// agentLoop/earlyGuards.ts — P4-3 // Extracted from agentLoop.ts: navigator.onLine guard (S313) + token guard (S322). // Returns true if the loop should return early (guard triggered). // Uses raw `callbacks` (pre-onChunk-closure) to avoid dependency on render buffer. import { liveGuidanceStore } from "@/lib/liveGuidanceStore"; // S440 interface EarlyGuardCallbacks { onChunk?: (chunk: string) => void; onStatus?: (status: string) => void; } /** S313 + S322: pre-loop guards. Returns true → caller must return immediately. */ export function checkEarlyGuards(token: string, callbacks: EarlyGuardCallbacks): boolean { // S313-iOS: navigator.onLine guard — previene 30s timeout silenzioso su iPhone in tunnel/metro if (typeof navigator !== "undefined" && !navigator.onLine) { callbacks.onChunk?.("⚠️ Nessuna connessione internet. Riprova quando sei online."); callbacks.onStatus?.("📵 Offline — loop annullato"); try { liveGuidanceStore.clear(); } catch { /* non-blocking */ } // S440 return true; } // S322: Early token guard — risposta immediata se nessun provider configurato. // DEVE essere PRIMA di qualsiasi onStatus/taskStore call per evitare che l'utente // veda "Analisi richiesta…" per 30+ secondi prima di scoprire che manca il token. if (!token || !token.trim()) { const _noTokenMsg = `🔑 **Nessun token API configurato.**\n\nApri le **Impostazioni** (⚙️) e aggiungi uno di questi token gratuiti:\n\n` + `- **OpenRouter** → [openrouter.ai/keys](https://openrouter.ai/keys) — gratuito, 13+ modelli\n` + `- **Groq** → [console.groq.com/keys](https://console.groq.com/keys) — velocissimo, gratuito\n` + `- **Gemini** → [aistudio.google.com/apikey](https://aistudio.google.com/apikey) — Google, gratuito\n` + `- **HuggingFace** → [huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)`; callbacks.onChunk?.(_noTokenMsg); callbacks.onStatus?.("🔑 Token mancante"); try { liveGuidanceStore.clear(); } catch { /* non-blocking */ } // S440 return true; } return false; }