Skip to content

feat(sdk): add subagent conversation forking - #5714

Merged
Hunter Lovell (hntrl) merged 22 commits into
mainfrom
bengret/feat-subagent-forking
Sep 1, 2026
Merged

feat(sdk): add subagent conversation forking#5714
Hunter Lovell (hntrl) merged 22 commits into
mainfrom
bengret/feat-subagent-forking

Conversation

@thushanth-bengre-langchain

@thushanth-bengre-langchain Thushanth Bengre (thushanth-bengre-langchain) commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

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 on ForkedSubAgent, since SubAgent.system_prompt is 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: bool flag on the task tool; this implements the capability as a spec-level ForkedSubAgent type instead. A per-call flag can be layered on as a follow-up if the tool-level ergonomics are wanted.

@github-actions github-actions Bot added deepagents Related to the `deepagents` SDK / agent harness feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: M 200-499 LOC labels Aug 21, 2026

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 2 potential issues.

Open in WebView Open SWE trace

Comment thread libs/deepagents/deepagents/graph.py Outdated
Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
@github-actions github-actions Bot added size: L 500-999 LOC and removed size: M 200-499 LOC labels Aug 21, 2026

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 2 potential issues.

Open in WebView Open SWE trace

Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/deepagents/graph.py Outdated
Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/deepagents/graph.py
@mdrxy

Copy link
Copy Markdown
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 fork= flag itself matters beyond the capability, that can be layered on as a follow-up.

Unaffected related issues: #1359, #2440, #3838, #2512.

(Also editing the PR description to include the Closes #4668 line.)

@mdrxy Mason Daugherty (mdrxy) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 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 _ForkSystemMessageMiddleware runs 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_prompt should raise, not silently drop it. The Never annotation only helps typed users; at runtime _resolved_declarative_spec filters the key out, so ForkedSubAgent(system_prompt="You are a SQL expert...") runs without complaint and the prompt is silently discarded (the kind of misrouting required mode="fork" seems to be designed to prevent). A ValueError in _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_name and subagent_graphs both happen to resolve duplicates last-write-wins. That agreement is incidental: a ValueError on duplicate names removes the whole class of bug instead of relying on two maps staying in lockstep.

Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/tests/unit_tests/middleware/test_subagent_middleware_init.py Outdated

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

Open in WebView Open SWE trace

Comment thread libs/deepagents/deepagents/graph.py
@thushanth-bengre-langchain

Copy link
Copy Markdown
Contributor Author
  • 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 _ForkSystemMessageMiddleware runs 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_prompt should raise, not silently drop it. The Never annotation only helps typed users; at runtime _resolved_declarative_spec filters the key out, so ForkedSubAgent(system_prompt="You are a SQL expert...") runs without complaint and the prompt is silently discarded (the kind of misrouting required mode="fork" seems to be designed to prevent). A ValueError in _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_name and subagent_graphs both happen to resolve duplicates last-write-wins. That agreement is incidental: a ValueError on duplicate names removes the whole class of bug instead of relying on two maps staying in lockstep.
  • Fixed — forks now skip building MemoryMiddleware/SkillsMiddleware at construction instead of computing then discarding them.
  • Fixed — a forked spec with system_prompt set now raises ValueError in _validate_subagent_mode
  • Fixed — duplicate subagent names now raise ValueError before anything gets compiled

Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

Open in WebView Open SWE trace

Comment thread libs/deepagents/deepagents/middleware/subagents.py Outdated
Comment thread libs/deepagents/deepagents/middleware/summarization.py Outdated
@github-actions github-actions Bot added size: XL 1000+ LOC and removed size: L 500-999 LOC labels Aug 28, 2026
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>
…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.
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Aug 29, 2026
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>
Hunter Lovell (hntrl) and others added 5 commits August 31, 2026 20:27
Co-authored-by: Chester Curme <chester.curme@gmail.com>
…m_prompt` param (#6016)

Currently:
1. `system_prompt` is forbidden on `ForkedSubAgent` specs
2. `parent_system_prompt` is (usually) required to be passed into
SubAgentMiddleware for forked subagents

(In `create_deep_agent`, `parent_system_prompt` specifies the base
prompt that is not built by middleware.)

We can avoid introducing a new param by just allowing `system_prompt` on
forked subagent specs. So for forked subagents, `create_deep_agent`
appends (1) the parent agent system prompt, and (2) any `system_prompt`
found in the spec.

Once we do this, we can do away with `ForkedSubAgent` and just have
`["handoff", "fork"]` as allowed values for `mode` on SubAgent specs.

@open-swe open-swe Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open SWE Review found 1 potential issue.

Open in WebView Open SWE trace

Comment thread libs/deepagents/deepagents/middleware/subagents.py
@hntrl
Hunter Lovell (hntrl) merged commit 6b4427f into main Sep 1, 2026
103 checks passed
@hntrl
Hunter Lovell (hntrl) deleted the bengret/feat-subagent-forking branch September 1, 2026 17:24
Hunter Lovell (hntrl) pushed a commit that referenced this pull request Sep 1, 2026
> [!CAUTION]
> Merging this PR will automatically publish to **PyPI** and create a
**GitHub release**.

For the full release process, see
[`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md).

---

_Release notes preview: keep this section in sync with the package
`CHANGELOG.md`. Publish reads the merged CHANGELOG via `release.yml`,
not this PR description — keep them aligned anyway so the PR stays an
accurate historical record for reviewers and anyone returning later._

---


##
[0.7.12](deepagents==0.7.11...deepagents==0.7.12)
(2026-09-01)

### Features

- Added subagent conversation forking in the SDK
([#5714](#5714)).

### Bug Fixes

- Fixed glob sorting to tolerate missing `modified_at` values in the SDK
([#4376](#4376)).

_End release notes preview._

---

> [!NOTE]
> A **community contributors** list and a **Special thanks** section
(crediting the users who filed the issues this release's PRs closed) are
appended to the GitHub release notes automatically at publish time (see
[Release
Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline),
step 3).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: langchain-oss-automated-triage[bot] <248757908+langchain-oss-automated-triage[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deepagents Related to the `deepagents` SDK / agent harness dependencies Pull requests that update a dependency file feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: XL 1000+ LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add fork option to the task tool so subagents can inherit parent conversation history

4 participants