Problem Statement
AgentTool wraps an agent as a tool for hierarchical composition, but the current implementation has significant limitations:
No streaming propagation
AgentTool.Execute() runs the child agent to completion and blocks until done. All streaming events — token deltas, tool execution progress, intermediate reasoning — are consumed silently. The parent agent (and ultimately the user) sees nothing until the child finishes.
In practice: invoke a sub-agent for a research task, wait 5 minutes with zero progress indication, then get a text blob back. This is the opposite of the real-time streaming experience the SDK otherwise provides.
Lossy I/O schema
- Input: Fixed to
{message: string}. The child agent receives raw JSON args as a text message. There's no way to pass structured data, files, or context that the child could use programmatically.
- Output: Fixed to
{result: string} containing only the last assistant message's text. Multi-part responses (tool results, reasoning traces, structured data), token usage from the child, and any artifacts produced are all lost.
No usage tracking propagation
Token usage from the child agent is not reported back to the parent. A parent agent can't make cost-aware decisions about sub-agent delegation.
Fresh session every time
Each invocation creates a completely isolated session. There's no way to share relevant context from the parent's conversation, and no way for the child to persist learning across multiple invocations.
Proposed Solution
Streaming tool interface
Add an optional streaming variant for tools that produce incremental output:
// StreamingTool extends Tool with streaming execution support.
type StreamingTool interface {
Tool
// ExecuteStream returns an iterator of progress events.
ExecuteStream(ctx context.Context, args json.RawMessage) iter.Seq2[ToolEvent, error]
}
// ToolEvent represents progress from a streaming tool.
type ToolEvent interface {
isToolEvent()
}
type ToolProgressEvent struct {
Message string // Human-readable progress update
Data json.RawMessage // Optional structured progress data
}
type ToolResultEvent struct {
Result json.RawMessage // Final result
}
AgentTool would implement StreamingTool, forwarding child agent events as ToolProgressEvent entries. The agent loop would emit these as they arrive, giving the parent (and consumer) real-time visibility.
Richer I/O for agent-as-tool
Input: Allow structured input that maps to the child agent's capabilities:
type AgentToolInput struct {
Message string `json:"message"` // Required: task description
Context json.RawMessage `json:"context,omitempty"` // Optional: structured context from parent
}
Output: Return richer results including usage and structured data:
type AgentToolResult struct {
Result string `json:"result"` // Text response (backward compatible)
Usage *llm.TokenUsage `json:"usage,omitempty"` // Token usage from child
Turns int `json:"turns"` // How many turns the child took
Artifacts json.RawMessage `json:"artifacts,omitempty"` // Any artifacts produced
}
Usage propagation
When AgentTool completes, it should report the child's cumulative token usage via the ToolCallInfo metadata, allowing the parent's interceptors (OTel, cost tracking) to account for sub-agent costs.
Optional context sharing
Allow configuring whether the child gets relevant context from the parent:
agenttool.New(childAgent,
agenttool.WithContextSharing(true), // Pass parent's recent messages as context
agenttool.WithSharedMessages(5), // Last 5 messages from parent session
)
Use Case Example
Research agent with streaming progress:
researcher := llmagent.New("researcher", "Research the given topic thoroughly", model,
llmagent.WithTools(webSearchRegistry),
)
// Parent agent delegates research
mainTools := tool.NewRegistry(tool.RegistryConfig{})
mainTools.Register(agenttool.New(researcher))
// During execution, the user sees:
// [sub-agent: researcher] Searching for "distributed consensus algorithms"...
// [sub-agent: researcher] Found 5 relevant papers, analyzing...
// [sub-agent: researcher] Querying second source for comparison...
// [sub-agent: researcher] Complete. Used 12,450 tokens across 4 turns.
// [main agent] Based on the research, here's a summary...
Why This Matters
- User experience: Waiting minutes with no progress indication is unacceptable for interactive applications. Users need to see that the agent is working and making progress, even when work is delegated to sub-agents.
- Observability: In production multi-agent systems, losing visibility into sub-agent execution makes debugging nearly impossible. Streaming events from children through to the consumer enables end-to-end tracing.
- Cost awareness: Without usage propagation, the parent agent can't make informed decisions about delegation cost. A parent that delegates to an expensive sub-agent 50 times has no way to track or limit the spend.
- Structured delegation: Complex agent systems need to pass structured context between agents, not just text messages. The current
{message: string} input means the parent must serialize everything to prose, and the child must parse it back — lossy and unreliable.
Problem Statement
AgentToolwraps an agent as a tool for hierarchical composition, but the current implementation has significant limitations:No streaming propagation
AgentTool.Execute()runs the child agent to completion and blocks until done. All streaming events — token deltas, tool execution progress, intermediate reasoning — are consumed silently. The parent agent (and ultimately the user) sees nothing until the child finishes.In practice: invoke a sub-agent for a research task, wait 5 minutes with zero progress indication, then get a text blob back. This is the opposite of the real-time streaming experience the SDK otherwise provides.
Lossy I/O schema
{message: string}. The child agent receives raw JSON args as a text message. There's no way to pass structured data, files, or context that the child could use programmatically.{result: string}containing only the last assistant message's text. Multi-part responses (tool results, reasoning traces, structured data), token usage from the child, and any artifacts produced are all lost.No usage tracking propagation
Token usage from the child agent is not reported back to the parent. A parent agent can't make cost-aware decisions about sub-agent delegation.
Fresh session every time
Each invocation creates a completely isolated session. There's no way to share relevant context from the parent's conversation, and no way for the child to persist learning across multiple invocations.
Proposed Solution
Streaming tool interface
Add an optional streaming variant for tools that produce incremental output:
AgentToolwould implementStreamingTool, forwarding child agent events asToolProgressEvententries. The agent loop would emit these as they arrive, giving the parent (and consumer) real-time visibility.Richer I/O for agent-as-tool
Input: Allow structured input that maps to the child agent's capabilities:
Output: Return richer results including usage and structured data:
Usage propagation
When
AgentToolcompletes, it should report the child's cumulative token usage via theToolCallInfometadata, allowing the parent's interceptors (OTel, cost tracking) to account for sub-agent costs.Optional context sharing
Allow configuring whether the child gets relevant context from the parent:
Use Case Example
Research agent with streaming progress:
Why This Matters
{message: string}input means the parent must serialize everything to prose, and the child must parse it back — lossy and unreliable.