- {config.icon}
-
{config.displayName}
- {config.badge && (
-
- {config.badge}
-
+
+
+ {config.icon}
+ {config.displayName}
+ {config.badge && (
+
+ {config.badge}
+
+ )}
+ {localProviderStatus && (
+
+ )}
+
+ {localProviderStatus && localProviderStatus !== "connected" && (
+
)}
@@ -178,6 +207,32 @@ export function NonHyprProviderCard({
)}
)}
+ {config.links && (config.links.download || config.links.models) && (
+
+ )}
{!showBaseUrl && config.baseUrl && (
@@ -237,6 +292,32 @@ export function StyledStreamdown({
);
}
+function LocalProviderStatusBadge({
+ status,
+}: {
+ status: "connected" | "disconnected" | "checking";
+}) {
+ if (status === "checking") {
+ return ;
+ }
+
+ if (status === "connected") {
+ return (
+
+
+ Connected
+
+ );
+ }
+
+ return (
+
+
+ Not Running
+
+ );
+}
+
function useProvider(id: string) {
const providerRow = settings.UI.useRow("ai_providers", id, settings.STORE_ID);
const setProvider = settings.UI.useSetPartialRowCallback(
diff --git a/apps/desktop/src/components/settings/ai/shared/use-local-provider-status.ts b/apps/desktop/src/components/settings/ai/shared/use-local-provider-status.ts
new file mode 100644
index 0000000000..4ee573f6a1
--- /dev/null
+++ b/apps/desktop/src/components/settings/ai/shared/use-local-provider-status.ts
@@ -0,0 +1,71 @@
+import { useQuery } from "@tanstack/react-query";
+
+import * as settings from "../../../../store/tinybase/store/settings";
+import {
+ checkLMStudioConnection,
+ checkOllamaConnection,
+ type LocalProviderStatus,
+} from "./check-local-provider";
+
+const LOCAL_PROVIDERS = ["ollama", "lmstudio"] as const;
+type LocalProviderId = (typeof LOCAL_PROVIDERS)[number];
+
+const DEFAULT_OLLAMA_URL = "http://127.0.0.1:11434/v1";
+const DEFAULT_LMSTUDIO_URL = "http://127.0.0.1:1234/v1";
+
+function isLocalProvider(providerId: string): providerId is LocalProviderId {
+ return LOCAL_PROVIDERS.includes(providerId as LocalProviderId);
+}
+
+export function useLocalProviderStatus(providerId: string): {
+ status: LocalProviderStatus | null;
+ refetch: () => void;
+} {
+ const configuredProviders = settings.UI.useResultTable(
+ settings.QUERIES.llmProviders,
+ settings.STORE_ID,
+ );
+
+ const config = configuredProviders[providerId];
+
+ const defaultUrl =
+ providerId === "ollama"
+ ? DEFAULT_OLLAMA_URL
+ : providerId === "lmstudio"
+ ? DEFAULT_LMSTUDIO_URL
+ : "";
+
+ const baseUrl = String(config?.base_url || defaultUrl).trim();
+
+ const checkFn =
+ providerId === "ollama"
+ ? checkOllamaConnection
+ : providerId === "lmstudio"
+ ? checkLMStudioConnection
+ : null;
+
+ const query = useQuery({
+ enabled: isLocalProvider(providerId) && !!checkFn,
+ queryKey: ["local-provider-status", providerId, baseUrl],
+ queryFn: async () => {
+ if (!checkFn) return false;
+ return checkFn(baseUrl);
+ },
+ staleTime: 10_000,
+ refetchInterval: 15_000,
+ retry: false,
+ });
+
+ if (!isLocalProvider(providerId)) {
+ return { status: null, refetch: () => {} };
+ }
+
+ const status: LocalProviderStatus =
+ query.isLoading || query.isFetching
+ ? "checking"
+ : query.data
+ ? "connected"
+ : "disconnected";
+
+ return { status, refetch: () => void query.refetch() };
+}