Skip to content

feat(adapters/langgraph): allow ManagerWorkers members and flow steps in a Swarm - #31

Open
spichen wants to merge 2 commits into
feat/managerworkers-adapterfrom
feat/swarm-composite-members
Open

spichen wants to merge 2 commits into
feat/managerworkers-adapterfrom
feat/swarm-composite-members

Conversation

@spichen

@spichen spichen commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Summary

Third of three PRs split out of #19. Base is feat/managerworkers-adapter (#30), which it depends on for the ManagerWorkers compiler.

Swarm was already supported in the LangGraph adapter — top-level, made of plain Agents. This closes three gaps, none of which needed the Swarm compiler to change shape.

ManagerWorkers as a Swarm member

A member had to be a plain Agent; anything else raised. A ManagerWorkers can decide a handoff too — its group manager is the LLM that emits the transfer tool call — so it's now accepted.

It can't use langgraph_swarm.create_handoff_tool: that tool's Command(graph=PARENT) lands on the ManagerWorkers graph, one level short of the Swarm, and is dropped. Instead the manager gets synthetic transfer_to_<sibling> tools, and the MW parent graph grows a __handoff__ node that re-emits the handoff upward.

Transcript validity is the subtle part: the MW graph exits via the PARENT command rather than its own END, so its internal messages don't merge into the shared Swarm conversation. The node therefore forwards the transfer AIMessage plus a ToolMessage answering every still-open tool call on it — including delegations emitted in the same turn — so the Swarm sees a well-formed call/result sequence. An orphan ToolMessage would 400 the next member's LLM.

A member that is neither an Agent nor a ManagerWorkers (a Flow, a nested Swarm) now raises NotImplementedError rather than ValueError — there's no single "decide-the-handoff" LLM to attach transfer tools to.

Swarm as a flow step

An AgentNode wrapping a Swarm raised TypeError from AgentNodeExecutor. It now compiles through the same composite-graph path as ManagerWorkers, with node inputs rendered into the first_agent prompt.

Swarm input/output inference

Swarm now infers its inputs/outputs from first_agent, so a flow AgentNode wrapping one exposes input ports and a DataFlowEdge into it resolves at load. Symmetric with the ManagerWorkers change in #30.

Note on the routing helper

_route_manager_to_worker_or_end gains the handoff branch and is renamed to _route_manager_to_worker_handoff_or_end. Handoff wins over delegation within a turn, since it transfers the whole conversation; same-turn delegations are answered-and-dropped by the handoff node.

Testing

tests/adapters/langgraph, tests/serialization, tests/validation with SKIP_LLM_TESTS=1, in a venv pinned to constraints/constraints.txt: identical results to the original unsplit #19 branch. black / isort / pyflakes clean on the changed files.

The tip of this branch is byte-identical to #19's head, so the three-way split is lossless.

⚠️ Same coverage gap as #30: all of flows/test_swarm_node.py is skipped under SKIP_LLM_TESTS=1 (the tests/adapters/conftest.py LLM guard fires on config construction), so the Swarm flow-step path is unverified in offline CI. Worth fixing separately.

🤖 Generated with Claude Code

@spichen
spichen force-pushed the feat/managerworkers-adapter branch from 3747193 to dba45e2 Compare July 25, 2026 11:31
@spichen
spichen force-pushed the feat/swarm-composite-members branch from d3a7fa0 to 51208b0 Compare July 25, 2026 11:31
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from dba45e2 to 34ad0ab Compare July 25, 2026 11:37
@spichen
spichen force-pushed the feat/swarm-composite-members branch from 51208b0 to c654f0d Compare July 25, 2026 11:37
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from 34ad0ab to 023ef14 Compare July 25, 2026 12:00
@spichen
spichen force-pushed the feat/swarm-composite-members branch from c654f0d to 522d8ec Compare July 25, 2026 12:00
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from 023ef14 to fa78d18 Compare July 25, 2026 15:30
@spichen
spichen force-pushed the feat/swarm-composite-members branch from 522d8ec to 5484422 Compare July 25, 2026 15:30
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from fa78d18 to 1aa5a54 Compare July 25, 2026 16:16
@spichen
spichen force-pushed the feat/swarm-composite-members branch from 5484422 to 8cc4093 Compare July 25, 2026 16:16
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from 1aa5a54 to ebf57be Compare July 25, 2026 16:48
@spichen
spichen force-pushed the feat/swarm-composite-members branch from 8cc4093 to 283e85e Compare July 25, 2026 16:48
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from ebf57be to e1a293b Compare July 25, 2026 16:55
@spichen
spichen force-pushed the feat/swarm-composite-members branch from 283e85e to 2fd96c7 Compare July 25, 2026 16:55
@spichen
spichen force-pushed the feat/managerworkers-adapter branch from e1a293b to c3ed319 Compare July 25, 2026 18:33
@spichen
spichen force-pushed the feat/swarm-composite-members branch from 2fd96c7 to d099217 Compare July 25, 2026 18:33
@cesarebernardis
cesarebernardis force-pushed the feat/managerworkers-adapter branch 2 times, most recently from 0a52773 to bf30c66 Compare August 25, 2026 13:44
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.

1 participant