Native Subagent Handoff for Agent Trees (Transfer Events + Author Provenance)#532
Native Subagent Handoff for Agent Trees (Transfer Events + Author Provenance)#532victorbash400 wants to merge 2 commits intostrands-agents:mainfrom
Conversation
- disallow nested sub-agents (child subAgents now throw) - preserve resume-from-last-agent behavior for root entry - honor explicit child invoke/stream entry points - add regression tests for nested-tree rejection and explicit child entry - update README note for one-level tree support - run prettier fixes for transfer tool/test files
| } | ||
|
|
||
| child.parentAgent = this | ||
| ;(child as unknown as { messages: Message[] }).messages = this.messages |
There was a problem hiding this comment.
Issue: Casting workaround for readonly property is fragile
This casting (child as unknown as { messages: Message[] }).messages = this.messages circumvents TypeScript's readonly modifier. This pattern is error-prone and makes the shared timeline behavior implicit.
Suggestion: Consider making messages a private property with a public getter, or document this shared timeline behavior more explicitly in the class-level TSDoc. Alternatively, the child could hold a reference to the root agent rather than directly mutating its messages property.
| expect(() => new Agent({ name: 'root', model: new MockMessageModel(), subAgents: [childWithNested] })).toThrow( | ||
| 'Nested sub-agents are not supported' | ||
| ) | ||
| }) |
There was a problem hiding this comment.
Issue: Missing test coverage for transfer restriction options
Tests exist for the basic handoff flow but missing coverage for disallowTransferToParent and disallowTransferToPeers configuration options.
Suggestion: Add tests verifying:
- Child with
disallowTransferToParent: truecannot transfer back to parent - Child with
disallowTransferToPeers: truecannot transfer to siblings - The
MAX_CONSECUTIVE_TRANSFERSguard is triggered and handled correctly
| } from '../hooks/events.js' | ||
| import { createTransferToAgentTool } from '../tools/transfer-to-agent-tool.js' | ||
|
|
||
| const MAX_CONSECUTIVE_TRANSFERS = 8 |
There was a problem hiding this comment.
Issue: Magic number without configuration option
MAX_CONSECUTIVE_TRANSFERS = 8 is a hard-coded limit. Users might have valid use cases requiring more or fewer consecutive transfers.
Suggestion: Consider making this configurable via AgentConfig with a sensible default:
maxConsecutiveTransfers?: number // defaults to 8| this.fromAgentName = data.fromAgentName | ||
| this.toAgentName = data.toAgentName | ||
| } | ||
| } |
There was a problem hiding this comment.
Issue: AfterTransferEvent should override _shouldReverseCallbacks() for consistency
All other "After" events (AfterInvocationEvent, AfterToolCallEvent, AfterModelCallEvent, AfterToolsEvent) override _shouldReverseCallbacks() to return true for proper cleanup semantics. AfterTransferEvent should follow the same pattern.
Suggestion:
override _shouldReverseCallbacks(): boolean {
return true
}|
Issue: This PR introduces significant public API surface and should be labeled for API review Per the API Bar Raising guidelines, PRs that add new public classes/abstractions or primitives that customers will frequently use require the
Suggestion: Add the
|
| ``` | ||
|
|
||
| Notes: | ||
| - Agent names are required for agents in a sub-agent tree. |
There was a problem hiding this comment.
Issue: README example doesn't demonstrate all new configuration options
The documentation shows basic usage but doesn't cover disallowTransferToParent, disallowTransferToPeers, or the Message.author field that users can inspect.
Suggestion: Consider adding a brief note about these options:
// Example showing transfer restrictions
const mathAgent = new Agent({
name: 'math',
model,
systemPrompt: 'You are a math specialist.',
disallowTransferToParent: false, // default: can transfer back to parent
disallowTransferToPeers: false, // default: can transfer to sibling agents
})
// Accessing message author after handoff
for (const message of root.messages) {
console.log(`${message.author ?? 'unknown'}: ${message.content}`)
}
Review SummaryAssessment: Request Changes This PR introduces a well-designed sub-agent handoff system with clear tree-aware routing and lifecycle events. The overall architecture is solid and follows existing SDK patterns. Key Review Themes
The implementation is thoughtful and the shared timeline approach via message provenance is a clean solution. Looking forward to seeing this feature land with the suggested improvements! |
Description
This PR introduces native sub-agent handoff support to the SDK. It adds tree-aware routing (
name,subAgents,parentAgent,transfer restrictions), transfer lifecycle events (BeforeTransferEvent,AfterTransferEvent), and message author provenance (Message.author) so a shared timeline can preserve which agent produced each response. It also exports the new events from public entry points and documents usage in the README with a concrete handoff example.Transfer restrictions are configurable per agent: by default, transfers can target children, parent, and siblings;
disallowTransferToParentanddisallowTransferToPeersrestrict those routes when needed.Compatibility: this extends
AgentStreamEventwith additive variants and keeps existing single-agent behavior intact. Nested sub-agents are intentionally disallowed (one parent level with direct children only), with explicit validation errors.See README section
SubAgents and Handofffor a complete setup example and behavior notes.Related Issues
N/A
Documentation PR
N/A (README updated in this PR)
Type of Change
New feature
Testing
Added and updated unit tests in
src/agent/__tests__/subagents.test.tsto cover parent/child wiring, transfer events, invalid transfer handling, resume behavior, and nested sub-agent rejection. Ran full repo validation withnpm run check(lint, format, type-check, coverage, package tests).Validated end-to-end behavior in downstream app: GWEN, configured with local dependency
file:../sdk-typescript-with-subagents, exercising transfer and resume flows through live chat session logs.npm run checkChecklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.