CopilotKit / CopilotKit/CopilotKit
[v2] Message view freezes mid-run in long multi-tool runs (LangGraphAgent); state updates flow but UI stops re-rendering
Open
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 37.4k
- Forks
- 4.6k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 444
Description
Environment
@copilotkit/react-core/react-ui/runtime: 1.64.2 (all v2 imports)- Agent:
LangGraphAgent(LangGraph dev server,stream_mode=['events','values','updates','messages-tuple']) - LLM: DeepSeek (reasoning model) via OpenAI-compatible API
- Next.js 16 + React 19, production build
Symptom
In long multi-tool runs (e.g. query tool → long reasoning → file-generation tool → final answer), the chat view stops re-rendering mid-run while the run is still executing:
- The last visible content is typically the assistant text right before a tool call.
- The run completes successfully server-side (verified in traces and server logs).
- The client keeps receiving and processing events — we instrumented
agent.subscribe({ onEvent })and events (STATE_SNAPSHOT,RAW, …) keep flowing after the UI freezes. - No console errors.
- After the freeze, nothing brings the content back — waiting past run completion does not help. Only starting a new run flushes the accumulated content into view.
What we verified (elimination)
- Server SSE stream is complete and well-formed (replayed the run: all ~2000 events valid JSON,
RUN_FINISHEDpresent). - Component renderers are fine in isolation (SSR smoke tests with the exact tool payloads).
- Not throttling-related: we don't set
throttleMs/defaultThrottleMs, so the unthrottled path is used. - A "reconcile watchdog" subscriber that returns
{ messages: [...messages] }(fresh array reference) ononRunFinishedEvent(outcomesuccess) /onRunFailed/onRunErrorEventdoes not unfreeze the view — suggesting the blockage is deeper than theMemoizedAssistantMessagereference comparison. - Two empirical red lines we hit while experimenting (both reproduce reliably):
- Returning a
messagesmutation from a subscriber while the run is paused on an interrupt breaks interrupt UI (the choice card fromuseInterruptnever renders). - Returning periodic
messagesmutations during an active run corrupts in-flight streaming (the view freezes almost immediately).
- Returning a
Repro characteristics
- Intermittent for short runs; near-deterministic for long runs (multiple tool calls + 20–60s reasoning + a tool whose arguments are a large JSON payload, ~10–20 KB streamed as
TOOL_CALL_ARGSdeltas). - Freeze point in our logs consistently lands right after a
generate_file-like tool call's result, or right after an assistant message that carries both visible text and tool calls. - Our integration details that may matter: assistant messages from DeepSeek carry
contentas an array of parts (reasoning_content+text); heavySTATE_SNAPSHOTtraffic (500+ per run) from LangGraphvaluesstream mode.
Happy to provide
- Full client-side event log (
window.__evtsprobe) vs. server SSE comparison for a frozen run - Langfuse trace showing the run completing successfully
- A minimal repro if you can point us at a reference LangGraph + v2 setup
Ask
- Is this a known class of issue in v2's message reconciliation (memoized message view vs. in-place state mutation)?
- Is there a supported way to force the message view to re-sync from
agent.messagesafter a run? (Our subscriber mutation does not achieve this.) - Guidance on the two red lines above — are subscriber
messagesmutations during interrupts / mid-run supposed to be safe?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the long multi-tool run and trace agent.subscribe({ onEvent }), agent.messages, and the MemoizedAssistantMessage and useInterrupt paths. Compare the event flow after TOOL_CALL_ARGS, STATE_SNAPSHOT, and RUN_FINISHED with the rendered message state. Done means the message view continues updating through long runs without breaking interrupt UI or streaming reconciliation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 42/100