diff --git a/app/routes/ai.tsx b/app/routes/ai.tsx index 707ceeb..10e5b28 100644 --- a/app/routes/ai.tsx +++ b/app/routes/ai.tsx @@ -127,9 +127,10 @@ async function reindexKB( window.sessionStorage.getItem("arcadia_access_token")) || "dev" const url = `${baseUrl}/index/${encodeURIComponent(corpus)}/build` - toast.show?.({ - title: "Reindexing…", - description: `Rebuilding corpus '${corpus}'.`, + // Use useToast's actual API (see lib-notification-ui): tone helpers + // success/error/info/warning, plus generic toast({ title, description, tone }). + toast.info(`Reindexing '${corpus}'…`, { + description: `POST ${url}`, }) try { const res = await fetch(url, { @@ -140,16 +141,14 @@ async function reindexKB( throw new Error(`HTTP ${res.status}: ${await res.text()}`) } const out = (await res.json()) as { chunk_count: number; built_at: string } - toast.show?.({ - title: "Reindex complete", + toast.success("Reindex complete", { description: `${out.chunk_count} chunks indexed for '${corpus}'.`, }) } catch (err) { - toast.show?.({ - title: "Reindex failed", - description: err instanceof Error ? err.message : String(err), - tone: "error", - }) + const msg = err instanceof Error ? err.message : String(err) + // eslint-disable-next-line no-console + console.error("[reindexKB]", err) + toast.error("Reindex failed", { description: msg }) } } @@ -818,7 +817,7 @@ function ChatSurface({ } } }, [activeAgent, messages, isStreaming, agentHistory]) - const MAX_TOOL_ITERATIONS = 3 + const MAX_TOOL_ITERATIONS = 6 const [pendingConfirm, setPendingConfirm] = useState<{ /** Message index that emitted the write calls. */ afterIndex: number @@ -856,7 +855,27 @@ function ChatSurface({ toolIterationsRef.current = 0 return } - if (toolIterationsRef.current >= MAX_TOOL_ITERATIONS) return + if (toolIterationsRef.current >= MAX_TOOL_ITERATIONS) { + // Cap reached. Synthesize a tool-error response for each pending + // call so the conversation stays valid (every assistant tool_calls + // turn must be followed by tool messages — otherwise the next + // request to DeepSeek 400s on "insufficient tool messages"). Then + // continue the chat so the model writes a final answer with what + // it has, or apologizes for not finishing. + const cappedMessages = calls.map((c) => ({ + role: "tool" as const, + content: JSON.stringify({ + error: `MAX_TOOL_ITERATIONS (${MAX_TOOL_ITERATIONS}) reached — please answer with what you have so far.`, + }), + toolCallId: c.id, + name: c.name, + })) + void continueChat(cappedMessages, { + system: systemPrompt, + tools: getOpenAITools(), + }) + return + } toolIterationsRef.current += 1 void (async () => { const { reads, writes } = classifyCalls(calls) diff --git a/vite.config.ts b/vite.config.ts index b1fa382..6cd8ec8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -104,6 +104,7 @@ const aliasedDeps = [ "@tiptap/extension-link", "@tiptap/extension-placeholder", "@tiptap/extension-image", + "minisearch", ] const sharedDepAliases = Object.fromEntries( aliasedDeps.map((name) => [name, resolvePath(nodeModules, name)]),