feat(sdk): add subagent conversation forking - #5714
Open
Thushanth Bengre (thushanth-bengre-langchain) wants to merge 16 commits into
Open
feat(sdk): add subagent conversation forking#5714Thushanth Bengre (thushanth-bengre-langchain) wants to merge 16 commits into
Thushanth Bengre (thushanth-bengre-langchain) wants to merge 16 commits into
Conversation
Member
|
Closes #4668 — with a shape difference worth noting:
Same underlying capability: forked subagent gets the parent's effective history (same summarization-cutoff logic as isolated subagents) plus the task description. Isolated-by-default is unchanged. Ninaad R. Rao (@NinaadRao) — if the per-call Unaffected related issues: #1359, #2440, #3838, #2512. (Also editing the PR description to include the |
Mason Daugherty (mdrxy)
requested changes
Aug 21, 2026
Mason Daugherty (mdrxy)
left a comment
Member
There was a problem hiding this comment.
- Forks probably shouldn't run prompt-producing middleware. Today a fork builds its middleware stack like any other subagent.
MemoryMiddleware,SkillsMiddleware, and any profile extras each append to the system prompt. But then_ForkSystemMessageMiddlewareruns last and replaces the whole thing with the captured parent message. So that work happens on every call and is thrown away every time. Since a fork's prompt is definitionally the parent's captured prompt, I think we can skip prompt-producing middleware at fork construction and set the captured message as the fork's static prompt? - A forked spec with
system_promptshould raise, not silently drop it. TheNeverannotation only helps typed users; at runtime_resolved_declarative_specfilters the key out, soForkedSubAgent(system_prompt="You are a SQL expert...")runs without complaint and the prompt is silently discarded (the kind of misroutingrequired mode="fork"seems to be designed to prevent). AValueErrorin_validate_subagent_mode(or a sibling validator) would make bad config loud. - Reject duplicate subagent names. The context leak Open SWE flagged is currently avoided only because
subagents_by_nameandsubagent_graphsboth happen to resolve duplicates last-write-wins. That agreement is incidental: aValueErroron duplicate names removes the whole class of bug instead of relying on two maps staying in lockstep.
Author
|
Thushanth Bengre (thushanth-bengre-langchain)
force-pushed
the
bengret/feat-subagent-forking
branch
from
August 25, 2026 19:52
e7daa52 to
ff41d48
Compare
Mason Daugherty (mdrxy)
approved these changes
Aug 27, 2026
Thushanth Bengre (thushanth-bengre-langchain)
force-pushed
the
bengret/feat-subagent-forking
branch
from
August 28, 2026 14:38
409bf96 to
01c42f9
Compare
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
Skip building Memory/Skills middleware for forks (their prompt contribution is always overwritten anyway), reject a ForkedSubAgent that sets system_prompt, reject duplicate subagent names, fold _PARENT_SYSTEM_MESSAGE_KEY into _EXCLUDED_STATE_KEYS, and narrow _is_forked_subagent with TypeIs to drop an unnecessary cast.
A fork's skills index would only feed a prompt fragment that gets discarded when the parent's captured system message overwrites it (same issue open-swe caught for system_prompt). Raise instead of silently dropping it, and document the constraint alongside system_prompt's.
…ompt Not needed for type safety -- ty rejects system_prompt on a forked spec either way, whether or not the field is declared. Runtime validation in _validate_subagent_mode already enforces this independently. Removing it also brings system_prompt in line with how skills is already handled (runtime-only, no type-level override), since skills can't get the same treatment -- it's declared on the shared _SubAgentBase, and TypedDict doesn't allow overriding an inherited field's type.
… and cache-parity
…im task-tool-mirror docstring
Thushanth Bengre (thushanth-bengre-langchain)
force-pushed
the
bengret/feat-subagent-forking
branch
from
August 28, 2026 18:15
01c42f9 to
5227e5c
Compare
5 tasks
Thushanth Bengre (thushanth-bengre-langchain)
added a commit
to langchain-ai/deepagentsjs
that referenced
this pull request
Aug 30, 2026
…fety fixes (#800) ## Summary This PR backports a set of fixes that landed later in Python `deepagents`'s equivalent feature (langchain-ai/deepagents#5714) ## What's included - **Dynamic system-message capture and replay** — a fork now gets the parent's actual composed system message (skills, memory, etc.), not a stale static copy, so the prompt cache can hit. - **Identity-preserving preamble** — tells a fork it's continuing a prior conversation, not receiving a fresh request. - **Recursion refusal** — a fork's task tool refuses re-delegation instead of recursing. - **Tool-description hint for the parent** — marks forked subagents in the task tool listing so the parent knows they don't need context restated. - **Memory-middleware parity fix** — forks no longer get memoryMiddleware mirrored in, matching Python. ## Testing - New unit tests: skills-injected system message replay into a fork, rejection of `skills` on a `ForkedSubAgent` at construction, a fork's own attempt to delegate again being refused rather than recursing, and `parentSystemMessageMiddleware` only being installed when a declarative fork is actually present. --------- Signed-off-by: Thushanth Bengre <thushanth.bengre@langchain.dev> Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>
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.
Closes #4668.
Adds
ForkedSubAgent, a subagent spec that inherits the parent's effective conversation history and exact system prompt instead of only seeing the task description — useful when a subagent is delegated deep into an investigation and shouldn't have to re-derive context the parent already gathered.mode="fork"is required rather than optional onForkedSubAgent, sinceSubAgent.system_promptis also optional — making both optional would let the two specs collapse into the same shape and get silently misrouted between forking and isolated behavior.Reconstructs history using the same summarization-cutoff logic as isolated subagents (now shared via a common helper), drops the parent's still-unresolved trailing tool-call message so the forked prefix matches what was actually cached, and mirrors in a fresh memory middleware instance when
memory=is configured. Experimental, flagged as such in the docstrings.Note: #4668 proposed a per-call
fork: boolflag on thetasktool; this implements the capability as a spec-levelForkedSubAgenttype instead. A per-call flag can be layered on as a follow-up if the tool-level ergonomics are wanted.