Replies: 1 comment
|
Strong +1 on the problem statement. Invoking the LLM (or even starting a full agent run) just to hydrate a thread on page load is the wrong tool. What we shipped (and how it relates to the protocol)We solved this with a dedicated out-of-band read, not
That endpoint is not part of the AG-UI core protocol. It is an application/transport convenience that happens to speak AG-UI message/state types. Clients therefore have two integration points (run stream + state read), which is exactly the downside you call out. We also expose a live On
|
Uh oh!
There was an error while loading. Please reload this page.
Summary
Add a
run_modefield toRunAgentInputwith a"sync"value that signals the backend to restore and emit session state (STATE_SNAPSHOT+MESSAGES_SNAPSHOT) without invoking the LLM. This enables session restoration on page load and explicit mid-session state refresh — both common operations that today have no first-class protocol support.Problem
When a user returns to an existing session (page reload, new tab, device switch), the frontend has a
threadIdbut no local state. To restore session state and message history, it currently has to trigger a full agent run. That is wasteful and incorrect: the LLM gets invoked on what is semantically a read operation, and users see a response they did not ask for.We worked around this in our own deployment by monkey-patching
ag-ui-adkto skip the LLM call when the last message is empty. That workaround is implicit, fragile, and invisible to anyone reading the call site. It should not be necessary.We have also seen developers implement a dedicated out-of-band endpoint (e.g.
GET /thread/{threadId}) as an alternative. That approach works but bypasses the existing protocol flow entirely — the client ends up with two separate integration points and the state has to be reconciled outside of the protocol. The protocol already has the right built-in mechanism for this:STATE_SNAPSHOTandMESSAGES_SNAPSHOT. What is missing is a way to invoke that mechanism without triggering an LLM call.We haven't found a first-class way to achieve this in the current protocol — if we've missed something, we'd welcome a pointer. If there genuinely isn't one, we'd like to propose adding it.
Proposed change
Add an optional
run_modefield toRunAgentInput:When
run_modeis"sync":threadIdSTATE_SNAPSHOTandMESSAGES_SNAPSHOTwith the current session contentsRUN_FINISHED— keeping the standardRUN_STARTED/RUN_FINISHEDenvelope so clients need no special transport handlingthreadId, responds with empty state (not an error)Precedent
The
resumefield added for interrupt/human-in-the-loop flows is the closest analogue — it also represents a "run" where the protocol semantics differ from a fresh LLM turn.run_mode: "sync"follows the same pattern of extendingRunAgentInputrather than adding a new message type.CopilotKit implications (out of scope for the protocol itself, noting for discussion)
For the feature to be ergonomic end-to-end, CopilotKit would benefit from:
autoSyncprop on<CopilotKit>(defaulttruewhenthreadIdis provided) — fires a sync run on mount and wheneverthreadIdchangessync()function from a hook for explicit calls (e.g. a "refresh" button)Raising here in case the maintainers want to coordinate. Happy to track this separately if preferred.
Open questions for maintainers
RunAgentInputthe right place, or would a separate input event type be preferable?RUN_STARTED/RUN_FINISHEDenvelope still wrap a sync response, or would a lighter-weight response shape make more sense?run_modethe right name, or does something likeintent: "sync" | "run"fit the protocol vocabulary better?All reactions