Round-trip the capability's whole state through the browser

The session store rebuilt the rag namespace from four known keys, so the
evidence record never survived a turn, let alone a reload from localStorage.
Compaction then ran with an empty ledger: earlier evidence was replaced by
receipts retaining nothing, while the citations already in citation_index kept
the UI looking correct.

The UI still names the fields it reads, but everything else in the namespace
passes through untouched, and seeding the namespace no longer replaces sibling
namespaces.
This commit is contained in:
Yiorgis Gozadinos 2026-08-13 15:20:02 +03:00
parent 771ac9c96c
commit 53bbf52697
No known key found for this signature in database
2 changed files with 7 additions and 1 deletions

View file

@ -321,6 +321,7 @@ function ChatContentInner({
const session = getSession(sessionId);
// Seed state for the capability; the backend replaces it after each run.
agent.setState({
...agent.state,
[AGUI_STATE_KEY]: normalizeRAGState(session?.ragState),
});
if (session && session.messages.length > 0) {

View file

@ -11,12 +11,16 @@ export interface Citation {
doc_item_refs?: string[];
}
// Matches RAGState from the backend capability.
// Matches RAGState from the backend capability. The fields named here are the
// ones this UI reads; the capability owns the rest of its namespace, including
// the evidence record that compaction builds its capsule from, so the state has
// to round-trip whole rather than be rebuilt from known keys.
export interface RAGState {
citation_index: Record<string, Citation>;
citations: string[];
document_filter: string | null;
searches: Record<string, unknown[]>;
[key: string]: unknown;
}
export interface StoredMessage {
@ -40,6 +44,7 @@ const ACTIVE_SESSION_KEY = "haiku.rag.activeSession";
export function normalizeRAGState(state?: Partial<RAGState>): RAGState {
return {
...state,
citation_index: state?.citation_index ?? {},
citations: state?.citations ?? [],
document_filter: state?.document_filter ?? null,