ai: shake-out fixes from first end-to-end search_kb run
Three problems surfaced when driving search_kb / read_chunk through a
real DeepSeek chat for the first time:
1. vite.config.ts: minisearch wasn't in `aliasedDeps`, so when
@crema/lexical-rag-ui imports it, Vite couldn't resolve the bare
specifier from the sibling lib's location. Added it next to the
other shared deps. tsconfig paths alone is not enough — the Vite
alias is what propagates resolution to sibling-lib code.
2. ai.tsx reindexKB: was using `toast.show?.()` which doesn't exist on
useToast()'s API. Optional chaining silently no-op'd, so the button
click ran the fetch but produced zero UI feedback (success or
failure). Switched to the actual API: toast.info / toast.success /
toast.error. Added a console.error in the catch arm so the
underlying exception is visible in DevTools when something does go
wrong.
3. ai.tsx MAX_TOOL_ITERATIONS: cap was 3, which is too tight for
agentic search→read→search loops on real questions. Bumped to 6.
More importantly, when the cap IS reached, the runner now
synthesises tool-error messages for each pending tool_call and
continues the chat — instead of silently dropping them, which left
the conversation with an assistant.tool_calls turn but no matching
tool messages. DeepSeek (and the OpenAI spec) reject that
conversation with 400 ("insufficient tool messages following
tool_calls"), poisoning the thread. Now the model gets a clean
"max iterations reached" signal and produces a final answer.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)]),
|
||||
|
||||
Reference in New Issue
Block a user