diff --git a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte
index a4baa40bf9..be09f2fdd7 100644
--- a/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte
+++ b/tools/ui/src/lib/components/app/chat/ChatForm/ChatFormActions/ChatFormActionModels.svelte
@@ -1,5 +1,6 @@
-{#if hasError}
+{#if hasError || isLoadingModel}
{#if isLoadingModel}
diff --git a/tools/ui/src/lib/hooks/use-backend-availability.svelte.ts b/tools/ui/src/lib/hooks/use-backend-availability.svelte.ts
new file mode 100644
index 0000000000..c78284c2d5
--- /dev/null
+++ b/tools/ui/src/lib/hooks/use-backend-availability.svelte.ts
@@ -0,0 +1,38 @@
+/**
+ * Backend availability for connection error states.
+ *
+ * The server error banner and the offline affordances should only appear when
+ * no backend can serve requests. The active backend failing is not enough:
+ * with an external backend configured, the UI stays usable.
+ */
+
+import { LOCAL_BACKEND_ID } from '$lib/constants';
+import { backendsModelsStore, backendsStore, serverStore } from '$lib/stores';
+
+export interface BackendAvailability {
+ readonly hasAvailableBackend: boolean;
+ readonly isOffline: boolean;
+}
+
+export function useBackendAvailability(): BackendAvailability {
+ const hasAvailableBackend = $derived.by(() => {
+ // no connection error at all: nothing to report
+ if (!serverStore.error) return true;
+
+ // the local server failed, but an external backend may still be usable
+ return backendsStore.enabled.some(
+ (backend) =>
+ backend.id !== LOCAL_BACKEND_ID && backendsModelsStore.get(backend.id).error === null
+ );
+ });
+
+ return {
+ get hasAvailableBackend() {
+ return hasAvailableBackend;
+ },
+
+ get isOffline() {
+ return !hasAvailableBackend;
+ }
+ };
+}