fix(sdk): fetch subagent history#2191
Open
Christian Bromann (christian-bromann) wants to merge 4 commits intomainfrom
Open
fix(sdk): fetch subagent history#2191Christian Bromann (christian-bromann) wants to merge 4 commits intomainfrom
Christian Bromann (christian-bromann) wants to merge 4 commits intomainfrom
Conversation
|
81dd95c to
ee56388
Compare
@langchain/langgraph-checkpoint
@langchain/langgraph-checkpoint-mongodb
@langchain/langgraph-checkpoint-postgres
@langchain/langgraph-checkpoint-redis
@langchain/langgraph-checkpoint-sqlite
@langchain/langgraph-checkpoint-validation
create-langgraph
@langchain/langgraph-api
@langchain/langgraph-cli
@langchain/langgraph
@langchain/langgraph-cua
@langchain/langgraph-supervisor
@langchain/langgraph-swarm
@langchain/langgraph-ui
@langchain/langgraph-sdk
@langchain/angular
@langchain/react
@langchain/svelte
@langchain/vue
commit: |
36790fc to
02d8549
Compare
02d8549 to
59204fe
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Restores subagent conversation history (messages, tool calls) after page reload in deep-agent UIs. Previously, reloading a page that had completed a deep-agent run would correctly show the subagent pipeline cards (researcher, data-analyst, content-writer), but each card would be empty — no internal messages or tool calls visible, even though the same content was visible during the live stream.
Problem
Three separate issues combined to cause the failure:
1. Wrong source for messages in
buildExecutionSubagentManager.buildExecutionalways calledgetMessagesForSubagent(base.id), which reads from the live-streaming message chunk buffer. For subagents reconstructed after a page reload this buffer is empty, so it returned[]and unconditionally overwrotebase.messages— even afterupdateSubagentFromSubgraphStatehad successfully populated it from the checkpoint.2. Subgraph
getStateHistorythrew instead of falling backWhen the SDK queried
POST /threads/{id}/historywithcheckpoint_ns: "tools:{uuid}", LangGraph'sgetStateHistorytried to find a statically-registered Pregel subgraph named"tools". Tool-call subgraphs are created dynamically at runtime (not registered statically), so it threw"Subgraph with namespace 'tools' not found". The fix makesgetStateHistory(andgetState) fall back to direct checkpointer access when no static subgraph matches the namespace — consistent with how tool-call subgraphs actually store their checkpoints.3. AbortController / React Strict Mode cleanup race
The
useEffectthat callsfetchSubagentHistoryhad no cleanup function. In React Strict Mode (and when reactive dependencies likeisLoadingtoggle), effects re-run immediately — meaning a secondfetchSubagentHistorycall would start before the first completed. By adding anAbortControllerreturned from the cleanup, the previous in-flight HTTP request is cancelled on re-run. Crucially, the abort check was placed only on the HTTP request itself: if the fetch already completed before cleanup, the result is still applied (cancellation only prevents the network round-trip, not the state update of a completed response).Changes
libs/sdk/src/ui/subagents.tsbuildExecution: Fall back tobase.messageswhen the streaming message manager is empty. This ensures checkpoint-restored messages are visible in the UI.updateSubagentFromSubgraphState: New method that accepts restored messages from a subgraph checkpoint and sets them on the base, guarded against overwriting live streaming data.libs/sdk/src/ui/manager.tsfetchSubagentHistory: Newasyncmethod onStreamManager. AfterreconstructSubagents, fetches each subagent's checkpoint history using the UUID-basedcheckpoint_nsstored in the tool message'sadditional_kwargs.subgraph_checkpoint_ns. Accepts anAbortSignalto cancel in-flight requests when effects re-run.libs/langgraph-core/src/pregel/index.tsgetState/getStateHistory: When no static subgraph matches the namespace (e.g. dynamically-created tool-call subgraphs), fall back to direct checkpointer access instead of throwing. This makes subgraph history fetchable via the existing/threads/{id}/historyendpoint.Framework SDKs (React, Vue, Angular, Svelte)
All four framework hooks now:
fetchSubagentHistoryafterreconstructSubagents, passing theclient.threadsand anAbortSignal.sdk-react,sdk/react)useEffectcleanup return valuesdk-vue)watchonCleanupparametersdk-angular)effectonCleanupparametersdk-svelte)fetchControllervariable, aborted inonDestroyHow it works end-to-end
During a live stream (no change): subagent messages flow through SSE events with a namespaced
checkpoint_ns(e.g.tools:a1b2c3d4-...). Deepagents stores this namespace in the taskToolMessage'sadditional_kwargs.subgraph_checkpoint_ns. The streaming message buffer populatesbuildExecutionas before.After page reload:
subgraph_checkpoint_ns.reconstructSubagentscreates subagent stubs from the main thread's messages (tool call args, final result, status).fetchSubagentHistoryuses the storedcheckpoint_nsto callPOST /threads/{id}/historywith{ checkpoint: { checkpoint_ns: "tools:{uuid}" }, limit: 1 }for each subagent.updateSubagentFromSubgraphStatesets these on the base object.buildExecutionpicks them up via thebase.messagesfallback, populating the UI.Requires companion change in deepagents
The
subgraph_checkpoint_nsfield in each taskToolMessagerequires a matching change in the deepagents library: thetasktool capturesconfig.configurable.checkpoint_ns(the UUID-based namespace injected by LangGraph'salgo.ts) and stores it inreturnCommandWithStateUpdate. See deepagentsjs PR #312.