draft: keyed subgraphs through send - #8819
Draft
Nuno Campos (nfcampos) wants to merge 4 commits into
Draft
Conversation
…as-is) Prototype for the "per-thread subgraph limitation" design item. Adds a `subgraph_key` configurable: when a subgraph is invoked with it, its checkpoint namespace becomes `<parent frames>|:key` instead of one derived from the invoking task id or the in-node call-order counter. Parallel invocations with distinct keys never share state; a later invocation with the same key continues that history. Works for both `checkpointer=None` and `checkpointer=True` subgraphs. Also: - nested loops only honour the parent's RESUMING flag when their latest checkpoint was written under the same parent checkpoint (same invocation) or has unfinished work; fixes a stateful subgraph ignoring new input when invoked from a resumed task - in-process guard: two concurrent loops on one addressable namespace raise instead of silently forking its history - `recast_checkpoint_ns(keep_keys=...)`, parent-command namespace and replay first-visit logic understand `:key` segments - exit-durability predicate treats keyed namespaces as addressable Tests in tests/test_subgraph_key.py document the intended semantics, including the two pre-existing bugs the design fixes (racy call-order counter on resume; RESUMING leak into a stateful subgraph's new turn). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DUNm3vKV4k9YP4wpvQcyUX
Revise the prototype after review: - `checkpointer=` stays meaningful with a key. A per-invocation subgraph gets `call:<task_id>|:key` (key scoped to the invoking task, fresh each turn); a checkpointer=True subgraph gets `call|:key` (key names an addressable memory a later invocation continues). - Drop the in-process concurrent-namespace guard. - The call-order counter is now per key within a task (unkeyed invocations keep one counter per task, unchanged), so two subgraphs invoked under one injected key are told apart while an explicit key elsewhere is untouched. - ToolNode gains `subgraph_key="tool_call_id" | "tool_name" | callable`, which sets the key on the config each tool runs with so graphs invoked inside tools are keyed without tool code. Default None keeps current behaviour. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DUNm3vKV4k9YP4wpvQcyUX
Two tool calls in one ToolNode batch that resolve to the same subgraph_key would run one subgraph memory concurrently and silently fork its history. The batch always executes in one process, so refuse it before any tool runs. Note this only covers batch mode: langchain's create_agent fans tool calls out with Send, one ToolNode call each, so the equivalent check there belongs in the edge that builds the Sends. Also test that checkpointer=True subgraphs run unpersisted under a parent without a checkpointer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DUNm3vKV4k9YP4wpvQcyUX
…hey invoke Revision 4. Move the harness-facing surface from ToolNode to Send, which is how create_agent and create_react_agent fan tool calls out: - `Send(node, arg, key=...)`: the task id derives from the key instead of the packet's position; two keyed packets for one node with the same key in one step raise InvalidUpdateError at task preparation (holds wherever tasks are prepared, no in-process assumption); the key is set as `subgraph_key` on the task's config so subgraphs invoked inside the task are keyed by it. - A key now names an addressable namespace (`<parent frames>|:key`) in either persistence mode. `checkpointer=` keeps its jobs: False disables, and without a key it decides per-task vs per-calling-node naming. - Send serialization round-trips the key; older readers drop it. - Back out the ToolNode `subgraph_key` argument and batch duplicate check. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DUNm3vKV4k9YP4wpvQcyUX
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.
https://claude.ai/code/artifact/befd728a-68be-470a-9bce-7efa2e25fd7f
langchain/deepagents should then be modified to pass this new send arg in tool calls