Skip to content

Working with Sub-Agents

Sub-agents allow a parent agent to delegate subtasks to specialized child agents. Rather than handling every step itself, a parent agent can spawn a focused child agent with its own tools, persona, and iteration budget.

Two delegation modes exist:

  • Static sub-agents — configured at build time via .withAgentTool(). The sub-agent is always available as a named tool.
  • Dynamic sub-agents — spawned at runtime via the spawn-agent tool. The parent LLM decides when to spawn and what configuration to use.

Both modes run fully within the parent’s execution context. The child agent executes, produces a result, and that result is returned to the parent as a tool call observation.


Register a sub-agent as a named tool when its purpose is known at build time:

const agent = await ReactiveAgents.create()
.withProvider("anthropic")
.withAgentTool("data-analyst", {
name: "Data Analyst",
description: "Analyzes data and produces summaries",
provider: "anthropic",
maxIterations: 5,
tools: ["file-read", "web-search"],
persona: { role: "Data Analyst", instructions: "Focus on statistical patterns" },
})
.build();

The parent LLM can call data-analyst as a tool, passing a task description. The sub-agent executes with the configured tools and persona, then returns its result.

Use static sub-agents when:

  • The sub-agent’s purpose is fixed and known at build time
  • You want consistent, optimized behavior for a specific task type
  • You need tight control over which tools the sub-agent can access

Dynamic Sub-Agents (runtime via spawn-agent)

Section titled “Dynamic Sub-Agents (runtime via spawn-agent)”

Enable the spawn-agent tool to let the parent LLM create specialized agents on demand:

const agent = await ReactiveAgents.create()
.withProvider("anthropic")
.withDynamicSubAgents() // enables spawn-agent tool
.build();
// Parent LLM decides to spawn and configures at runtime

The parent LLM generates the sub-agent’s configuration (tools, persona, task) dynamically based on what the current task requires. This is useful when the type of sub-agent needed cannot be known in advance.

Use dynamic sub-agents when:

  • The sub-agent’s purpose depends on runtime task content
  • The parent needs to create differently-specialized agents for different subtasks
  • You want the parent to have full flexibility in delegation
QuestionAnswerMode
Is the sub-agent’s purpose known at build time?YesStatic (.withAgentTool())
Does the parent need to create agents dynamically?YesDynamic (.withDynamicSubAgents())
Do you need consistent, repeatable sub-agent behavior?YesStatic
Does the sub-agent’s role depend on the task at hand?YesDynamic

When a parent delegates to a sub-agent, the framework automatically forwards context to help the child agent understand the broader task:

  • Parent tool results — extracted from the parent’s recent tool results / working context (agents persist notes via the recall meta-tool)
  • Parent working memory — recent entries from the parent’s working memory store
  • Combined prefix — the above is composed into a systemPrompt prefix injected into the sub-agent, capped at 2000 characters (truncated oldest-first when over limit)

For the spawn-agent tool, the parent LLM can also pass:

  • tools — a whitelist of tool names the sub-agent is allowed to use
  • role, instructions, tone — persona steering applied to the spawned agent

Implementation reference: buildParentContextPrefix(), MAX_PARENT_CONTEXT_CHARS = 2000, and ALWAYS_INCLUDE_TOOLS in packages/tools/src/adapters/agent-tool-adapter.ts.


The current context forwarding mechanism has constraints to be aware of when designing sub-agent workflows:

  • 2000 character cap — forwarded context exceeding 2000 characters is truncated. Oldest entries are dropped first.
  • No full parent thread — sub-agents receive extracted tool results and a short forwarded slice, not the parent’s full message history or everything stored through recall.
  • No memory inheritance — sub-agents start with fresh memory. They do not inherit the parent’s episodic or semantic memory stores.
  • Sub-agents re-fetch data — if the parent fetched a URL or file, the sub-agent will re-fetch that resource unless the data is explicitly included in the forwarded context.

When context forwarding falls short, use these patterns:

  • Embed context in instructions — pass critical data directly in the instructions field of spawn-agent. The parent LLM can summarize key findings inline before delegating.
  • Keep sub-agent tasks narrow — design sub-agents for single-purpose tasks that do not require parent history. The less context a sub-agent needs, the less forwarding matters.
  • Use the tools whitelist — constrain the sub-agent to only the tools it needs. This reduces token usage and prevents the sub-agent from taking actions outside its scope.
  • Summarize before delegating — instruct the parent agent (via system prompt or persona) to produce a concise summary of relevant findings in its thought step before spawning a sub-agent.

Personas give sub-agents a defined role, background, and behavioral style. This is especially useful for specialized sub-agents where you want consistent behavior.

Configure a persona at build time with .withAgentTool():

const agent = await ReactiveAgents.create()
.withProvider("anthropic")
.withAgentTool("security-auditor", {
name: "Security Auditor",
description: "Reviews code for security vulnerabilities",
provider: "anthropic",
maxIterations: 6,
tools: ["file-read"],
persona: {
role: "Security Auditor",
background: "Expert in OWASP top 10 and common injection vulnerabilities",
instructions: "Flag any potential injection vulnerabilities. Be thorough and cite specific lines.",
tone: "formal",
},
})
.build();

When using dynamic sub-agents, the parent LLM generates persona parameters at runtime based on the task:

ParameterDescriptionExample value
roleThe sub-agent’s functional role"Data Analyst", "Code Reviewer"
instructionsTask-specific guidance for this invocation"Summarize the error patterns in this log"
toneBehavioral style"formal", "concise", "detailed"
backgroundDomain expertise context"Expert in distributed systems"

The parent LLM selects these values based on the subtask it is delegating. For example, a research agent might spawn a "Citation Verifier" sub-agent with instructions specific to the sources it found.


Sub-agent delegation adds overhead. Understand the costs before adopting this pattern:

  • Delegation overhead — delegate mode runs approximately 4x more expensive than a solo agent for simple tasks. Each delegation involves additional LLM calls for spawning and a full sub-agent execution cycle.
  • Small model limitations — models smaller than ~8B parameters often struggle with sub-agent tasks. They tend to hallucinate results or fail tool calls when operating as a sub-agent. Use capable models (7B+ instruction-tuned, or hosted providers) for sub-agent roles.
  • maxIterations for sub-agents — defaults to 3 when not set; the configured value is fully honored with no internal cap. Recommended range is 3–7: sub-agent tasks should be narrow and focused. A high iteration count on a sub-agent signals the task scope is too broad.
  • When not to use sub-agents:
    • Single-step lookups (one tool call is sufficient)
    • Tasks where the parent already has all required context
    • Cost-sensitive scenarios where the 4x overhead is not justified
    • Simple transformations or calculations that a tool handles directly