Skip to content

feat(sdk): add async subagent middleware for remote LangGraph servers #323

Merged
Colin Francis (colifran) merged 28 commits intomainfrom
colifran/async-subagents
Mar 20, 2026
Merged

feat(sdk): add async subagent middleware for remote LangGraph servers #323
Colin Francis (colifran) merged 28 commits intomainfrom
colifran/async-subagents

Conversation

@colifran
Copy link
Copy Markdown
Contributor

@colifran Colin Francis (colifran) commented Mar 18, 2026

Summary

Adds AsyncSubAgentMiddleware for launching background jobs on remote LangGraph deployments via the LangGraph SDK. This is the JS port of the Python AsyncSubAgentMiddleware.

The middleware provides five tools:

  • start_async_task — creates a thread + run on a remote server, returns a job ID immediately
  • check_async_task — fetches run status and extracts the result on completion
  • update_async_task — sends follow-up instructions by creating a new run on the same thread (with multitaskStrategy: "interrupt")
  • cancel_async_task — cancels a running job
  • list_async_tasks — lists all tracked jobs with live statuses fetched in parallel

Job state is persisted in the asyncSubAgentJobs state channel via a ReducedValue reducer, so jobs survive context compaction and summarization.

Integrated into createDeepAgent via the asyncSubagents parameter.

Tests

77 unit tests covering:

  • State reducer merge logic and immutability
  • ClientCache — caching, key deduplication, default x-auth-scheme header injection
  • All 5 tools — happy paths, unknown job IDs, SDK errors, graceful degradation (e.g. threads.getState failure on success still returns a result)
  • buildCheckResult — message content extraction, non-object fallback, empty messages fallback, error status
  • buildListTool — status filtering, terminal status SDK call skipping, live status updates, parallel fetching
  • createAsyncSubAgentMiddleware — validation (empty list, duplicate names), tool wiring, system prompt injection, independent instances

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 18, 2026

🦋 Changeset detected

Latest commit: e7e959d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
deepagents Minor
deepagents-acp Patch
@deepagents/evals Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 19, 2026

Open in StackBlitz

npm i https://pkg.pr.new/deepagents-acp@323
npm i https://pkg.pr.new/deepagents@323
npm i https://pkg.pr.new/@langchain/sandbox-standard-tests@323

commit: e7e959d

@colifran Colin Francis (colifran) marked this pull request as ready for review March 19, 2026 04:23
Copy link
Copy Markdown
Member

@hntrl Hunter Lovell (hntrl) left a comment

Choose a reason for hiding this comment

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

very nice!

@colifran Colin Francis (colifran) merged commit 2bebf30 into main Mar 20, 2026
15 checks passed
@colifran Colin Francis (colifran) deleted the colifran/async-subagents branch March 20, 2026 21:31
@github-actions github-actions bot mentioned this pull request Mar 20, 2026
Colin Francis (colifran) added a commit that referenced this pull request Mar 23, 2026
Colin Francis (colifran) added a commit that referenced this pull request Mar 23, 2026
…h servers (#323)" (#351)

* Revert "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)"

This reverts commit 2bebf30.

* regen lock
Colin Francis (colifran) added a commit that referenced this pull request Mar 23, 2026
Colin Francis (colifran) added a commit that referenced this pull request Mar 24, 2026
… LangGraph servers (#323)" (#351)" (#354)

* Revert "revert: "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)" (#351)"

This reverts commit 367e43a.

* use any backend protocol
Colin Francis (colifran) added a commit that referenced this pull request Mar 24, 2026
…#323)

* add langgraph sdk dep

* launch tool, check tool

* update tool and cancel tool

* update and cancel tool tests

* list async subagent jobs tool

* list subagent jobs tool and create middleware

* wire in async subagents

* create and use state schema, update message to messages

* tests

* AsyncSubagent -> AsyncSubAgent

* regen lock

* fix import

* bug fixes

* fix exports

* fix tool names

* fix check result bug

* adjust tool names and tests

* add createdAt, updatedAt, and checkAt fields

* changeset

* job->task

* SubAgent->subagent in docstrings

* update tool names

* use tool runtime

* update naming to match async task naming convention

* remove extra custom middleware added during merge conflicts

* launch_async_task->start_async_task

* buildLaunchTool->buildStartTool
Colin Francis (colifran) added a commit that referenced this pull request Mar 24, 2026
…h servers (#323)" (#351)

* Revert "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)"

This reverts commit 2bebf30.

* regen lock
Hunter Lovell (hntrl) pushed a commit that referenced this pull request Mar 24, 2026
… LangGraph servers (#323)" (#351)" (#354)

* Revert "revert: "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)" (#351)"

This reverts commit 367e43a.

* use any backend protocol
Hunter Lovell (hntrl) pushed a commit that referenced this pull request Apr 1, 2026
… LangGraph servers (#323)" (#351)" (#354)

* Revert "revert: "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)" (#351)"

This reverts commit 367e43a.

* use any backend protocol
Colin Francis (colifran) added a commit that referenced this pull request Apr 2, 2026
* Revert "revert: "feat(deepagents): support multimodal files for backends (#298)" (#352)" (#353)

This reverts commit 03ea1c9.

* revert: "revert: "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)" (#351)" (#354)

* Revert "revert: "feat(sdk): add async subagent middleware for remote LangGraph servers  (#323)" (#351)"

This reverts commit 367e43a.

* use any backend protocol

* Reapply "chore(deepagents): refactor backend method names - `lsInfo` -> `ls`, …" (#349) (#356)

This reverts commit 573479d.

* Reapply "chore(sdk): unify sync subagents and async subagents into a single pr…" (#348) (#355)

This reverts commit 96dc34c.

* chore: align alpha with main (#358)

* fix(deepagents): remove orphaned ToolMessages for Gemini compatibility (#335)

* fix(deepagents): remove orphaned ToolMessages for Gemini compatibility

* Fix ToolMessages for Gemini compatibility

---------

Co-authored-by: Christian Bromann <git@bromann.dev>

* fix(deepagents): throw on built-in tool collision (#330)

* add error

* Create big-horses-fail.md

* add config error class

* cr

---------

Co-authored-by: Christian Bromann <git@bromann.dev>

* fix(deepagents): use `crypto.randomUUID()` instead of uuid (#336)

* fix(deepagents): use crypto.randomUUID() instead of uuid

* update pnpm-lock

* Create grumpy-weeks-wave.md

* Update libs/deepagents/src/middleware/fs.int.test.ts

* feat(deepagent): add LangSmithSandbox (#324)

* feat(deepagent): add LangSmithSandbox

* Change deepagents version from patch to minor

* format

* fix tests

* format

* make it a patch

* cr

* cr

* fix

* cr

* chore: version packages (#321)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* regen lockfile

* fix langsmith tests so that they use backend protocol v2 methods

* format

---------

Co-authored-by: pawel-twardziak <pawel.twardziak.dev@gmail.com>
Co-authored-by: Christian Bromann <git@bromann.dev>
Co-authored-by: Maahir Sachdev <maahir.sachdev@langchain.dev>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* feat(deepagents): add completion notifier middleware for async subagents (#334)

Port of langchain-ai/deepagents#2119 to TypeScript. Adds a
createCompletionNotifierMiddleware that async subagents can use to
proactively notify their supervisor when they complete or error,
closing the gap where the supervisor only learns about completion
when someone calls check_async_task.

- New createCompletionNotifierMiddleware with afterAgent and
  wrapModelCall hooks
- Uses @langchain/langgraph-sdk Client to send runs.create() to the
  supervisor's thread
- Reads parent_thread_id from subagent state (injected by
  start_async_task)
- Derives task_id from runtime.configurable.thread_id
- Silently no-ops if parent context is missing
- Guards against duplicate notifications
- 22 unit tests covering all hooks, edge cases, and error paths

fix(deepagents): make url required in completion notifier (no ASGI in JS)

JS does not have ASGI transport like Python, so the url parameter
must be provided explicitly. Removed all ASGI references from docs
and the localhost fallback default.

fix(deepagents): throw on built-in tool collision (#330)

* add error

* Create big-horses-fail.md

* add config error class

* cr

---------

Co-authored-by: Christian Bromann <git@bromann.dev>

fix(deepagents): use `crypto.randomUUID()` instead of uuid (#336)

* fix(deepagents): use crypto.randomUUID() instead of uuid

* update pnpm-lock

* Create grumpy-weeks-wave.md

* Update libs/deepagents/src/middleware/fs.int.test.ts

feat(deepagent): add LangSmithSandbox (#324)

* feat(deepagent): add LangSmithSandbox

* Change deepagents version from patch to minor

* format

* fix tests

* format

* make it a patch

* cr

* cr

* fix

* cr

regen lockfile

linting

linting

add missing url property

chore: version packages (#321)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

changeset

regen lockfil

* chore: enter alpha pre-release

* chore: target alpha for releases

* chore: version packages (alpha) (#359)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* chore(deepagents): extend supported backend file types (#363)

* extend supported file types

* Create strong-tigers-share.md

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>

* chore(deepagents): implement async subagents + use stream example (#360)

* async subagents + use stream example

* fix lockfile

* format

* linting

* readme and linting

* format

* proactively send responses when subagents complete

* better examples

* feat(deepagents): rename completion notifier to completion callback and align with Python (#361)

* feat(deepagents): rename completion notifier to completion callback and align with Python PR

- Rename completion_notifier.ts -> completion_callback.ts to match Python's
  completion_callback.py naming
- Rename exports: createCompletionNotifierMiddleware -> createCompletionCallbackMiddleware,
  CompletionNotifierOptions -> CompletionCallbackOptions
- Rename state key: parent_thread_id -> callbackThreadId, option: parentGraphId -> callbackGraphId
- Make url optional (Python allows omitting for ASGI transport)
- Match Python's strict error behavior: throw on empty messages, non-AIMessage types,
  and missing callbackThreadId
- Add truncation suffix with task_id hint for long messages
- Use generic error message in wrapModelCall (don't leak error details)
- Remove duplicate notification guard (Python notifies on every error)
- Add extractCallbackContext to async_subagents.ts: injects callbackThreadId
  into subagent input state when launching via start_async_task
- Add tests for extractCallbackContext and callback context injection

* cr

* Rename completion notifier to completion callback

Renamed completion notifier to completion callback for consistency with Python.

* fix(sdk): `AsyncTask` `updatedAt` field doesn't update on task status changes (#400)

* update updatedAt field to change on any task update

* added changeset

* chore: set up self hosted async subagent example (#399)

* self hosted async subagent example

* with postgres

* formatting

* eslint disable no console

* fix dockerfile and readme

* Update examples/async-subagent-server/server.ts

Co-authored-by: Christian Bromann <git@bromann.dev>

---------

Co-authored-by: Christian Bromann <git@bromann.dev>

* chore(sdk): update async subagent middleware for agent protocol (#394)

* update async subagent middleware for agent protocol

* add changeset

* Update libs/deepagents/src/middleware/async_subagents.ts

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>

* Update libs/deepagents/src/middleware/async_subagents.ts

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>

* Update libs/deepagents/src/middleware/async_subagents.ts

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>

* differentiate agent protocol

---------

Co-authored-by: Hunter Lovell <40191806+hntrl@users.noreply.github.com>

* chore(repo): migrate linting and formatting to oxc tooling (#391)

* chore(repo): migrate linting and formatting to oxc tooling

* cr

* cr

* chore(lint): clean up console disables for oxlint

* cr

* Apply suggestions from code review

Co-authored-by: Christian Bromann <git@bromann.dev>

---------

Co-authored-by: Christian Bromann <git@bromann.dev>

* refactor(deepagents): clean up createDeepAgent middleware wiring (#392)

* refactor(deepagents): clean up createDeepAgent middleware wiring

* fix(deepagents): avoid duplicate HITL middleware on subagents

* add comments, remove iife

* Create ten-masks-flow.md

* fix(deepagents): align prompt templates with runtime behavior (#393)

* fix(deepagents): align prompt templates with runtime behavior

* chore: add changeset for prompt alignment fixes

* cr

* cr

* fix store backend and tests

* lint

* fix rests and resolveBackend

* lint

* fix failing tests

* revert adapt resolve backend

* fix resolve backend

* better variable name

* fix backend factory to return a maybe promise

* mark resolve backend as internal

* format

---------

Co-authored-by: Colin Francis <131073567+colifran@users.noreply.github.com>
Co-authored-by: pawel-twardziak <pawel.twardziak.dev@gmail.com>
Co-authored-by: Christian Bromann <git@bromann.dev>
Co-authored-by: Maahir Sachdev <maahir.sachdev@langchain.dev>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Colin Francis <colin.francis@langchain.dev>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants