+ {low
+ ? `Running low — top up at ${data?.provider ?? 'the node'} or AI will fall back to the keyless provider.`
+ : 'Pay-per-request AI, funded in sats via Routstr. Tops up when low.'}
+
+
+
+ );
+}
diff --git a/src/hooks/useSasquatchAiStatus.ts b/src/hooks/useSasquatchAiStatus.ts
new file mode 100644
index 0000000..9a9cf9e
--- /dev/null
+++ b/src/hooks/useSasquatchAiStatus.ts
@@ -0,0 +1,48 @@
+import { useQuery } from '@tanstack/react-query';
+import { Capacitor } from '@capacitor/core';
+import { useCurrentUser } from '@/hooks/useCurrentUser';
+import { PLATFORM_OWNER_PUBKEYS } from '@/hooks/useListingRestrictions';
+import { buildProAuthHeaders } from '@/lib/proAuth';
+
+/** Report shape from the proxy's owner-only `/api/ai/status`. */
+export interface SasquatchAiStatus {
+ configured: boolean;
+ balanceSats: number | null;
+ low: boolean;
+ provider?: string;
+}
+
+const AI_STATUS_URL = Capacitor.isNativePlatform()
+ ? 'https://skate-spots.org/api/ai/status'
+ : '/api/ai/status';
+
+/**
+ * Owner-only: the Sasquatch AI (upstream) account balance, so the operator can be
+ * nudged to top up before AI silently degrades to the keyless fallback. Polled
+ * every few minutes. Returns `undefined`/skips for non-owners.
+ */
+export function useSasquatchAiStatus() {
+ const { user } = useCurrentUser();
+ const isOwner = !!user?.pubkey && PLATFORM_OWNER_PUBKEYS.includes(user.pubkey);
+
+ return useQuery({
+ queryKey: ['sasquatch-ai-status', user?.pubkey],
+ enabled: isOwner,
+ refetchInterval: 5 * 60 * 1000,
+ staleTime: 60 * 1000,
+ queryFn: async () => {
+ const authHeaders = await buildProAuthHeaders({
+ pubkey: user!.pubkey,
+ signEvent: (e) => user!.signer.signEvent(e),
+ });
+ const res = await fetch(AI_STATUS_URL, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json', ...authHeaders },
+ body: '{}',
+ signal: AbortSignal.timeout(10000),
+ });
+ if (!res.ok) throw new Error(`AI status ${res.status}`);
+ return (await res.json()) as SasquatchAiStatus;
+ },
+ });
+}
diff --git a/src/lib/sasquatchBrain.ts b/src/lib/sasquatchBrain.ts
index bb6b7b7..e894d2f 100644
--- a/src/lib/sasquatchBrain.ts
+++ b/src/lib/sasquatchBrain.ts
@@ -19,20 +19,17 @@ const AI_PROXY_URL = Capacitor.isNativePlatform()
? 'https://skate-spots.org/api/ai'
: '/api/ai';
-// Models Sasquatch may request through the proxy, in preference order. These are
-// verified to work via Netlify's AI Gateway — which enforces a Zero-Data-
-// Retention policy, so not every OpenRouter model is routable (gemini/anthropic/
-// gpt-4o-mini are not). If one is rate-limited (429) we back off briefly then
-// move to the next; Pollinations is the keyless fallback.
-// Keep this list in sync with ALLOWED_MODELS in netlify/functions/ai.mjs.
+// Models Sasquatch requests through the proxy, in preference order. These are
+// the slugs served by our upstream (a Routstr node — see AGENTS.md), which are
+// OpenAI-style ids rather than OpenRouter's. If one is rate-limited (429) we back
+// off briefly then try the next; Pollinations is the keyless fallback.
+// The server is authoritative: keep this list in sync with `SASQUATCH_MODELS`
+// (and ALLOWED_MODELS in netlify/functions/ai.mjs) — but it's not fatal if they
+// drift, because the proxy substitutes its first allowed model.
export const PROXY_MODELS = [
- 'meta-llama/llama-3.3-70b-instruct',
- 'deepseek/deepseek-chat-v3-0324',
- 'x-ai/grok-4.5',
- 'moonshotai/kimi-k2',
- 'qwen/qwen-2.5-72b-instruct',
- 'mistralai/mistral-nemo',
- 'meta-llama/llama-3.1-8b-instruct',
+ 'gemini-3-6-flash',
+ 'z-ai-glm-5-3',
+ 'gemini-3-7-flash',
];
export type ChatTurn = { role: 'system' | 'user' | 'assistant'; content: string };
diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx
index e271fc8..e790c10 100644
--- a/src/pages/SettingsPage.tsx
+++ b/src/pages/SettingsPage.tsx
@@ -8,6 +8,7 @@ import { WalletModal } from '@/components/WalletModal';
import { SecuritySettings } from '@/components/SecuritySettings';
import { RelatrSettings } from '@/components/RelatrSettings';
import { CVMHealthCheck } from '@/components/CVMHealthCheck';
+import { SasquatchAiStatusCard } from '@/components/SasquatchAiStatusCard';
import { LanguageSelector } from '@/components/LanguageToggle';
import { DesktopNavManager } from '@/components/DesktopNavManager';
import { MyDataTab } from '@/components/MyDataTab';
@@ -586,8 +587,9 @@ function AdvancedScreen({ onBack }: { onBack: () => void }) {