stratus

Subagents

Delegate work to child agents as tool calls

Subagents let a parent agent delegate work to a child agent. The child runs as a tool call - the parent sends parameters, the child runs its own agent loop, and the result comes back as a tool message.

Defining a Subagent

subagent.ts
import { Agent, subagent } from "stratus-sdk/core";
import { z } from "zod";

const mathAgent = new Agent({
  name: "math",
  model,
  instructions: "You are a math expert. Solve the given problem.",
  tools: [calculate],
});

const mathSubagent = subagent({
  agent: mathAgent,
  inputSchema: z.object({
    problem: z.string().describe("The math problem to solve"),
  }),
  mapInput: (params) => params.problem, 
});

Using Subagents

Add subagents to a parent agent's subagents array. They appear as tools to the model:

parent.ts
const assistant = new Agent({
  name: "assistant",
  model,
  instructions: "Use the math subagent for math questions.",
  subagents: [mathSubagent], 
});

const result = await run(assistant, "What is 15 * 17?");
// The parent delegates to the math agent, which uses the calculate tool
console.log(result.output); // Contains "255"

Subagent Config

PropertyTypeDescription
agentAgentRequired. The child agent to delegate to
inputSchemaz.ZodTypeRequired. Zod schema for parameters the parent model passes
mapInput(params) => stringRequired. Convert parsed params to the child's user message
toolNamestringCustom tool name (default: run_{agent.name})
toolDescriptionstringCustom description for the model
mapContext(parentCtx) => childCtxMap the parent's context to the child's context type
maxTurnsnumberMax turns for the child run
modelModelOverride the child's model

Context Mapping

If the child agent has a different context type, use mapContext to transform it:

context-mapping.ts
const childSubagent = subagent({
  agent: childAgent, // Agent<{ apiKey: string }>
  inputSchema: z.object({ query: z.string() }),
  mapInput: (params) => params.query,
  mapContext: (parentCtx: { config: { key: string } }) => ({ 
    apiKey: parentCtx.config.key, 
  }), 
});

Error Handling

If the child agent throws an error, it's caught and returned as a tool message to the parent. This lets the parent recover gracefully rather than crashing the entire run.

// If the child fails, the parent sees a tool message like:
// "Error in sub-agent "math": Agent exceeded maximum turns (10)"

Subagents in Sessions

session-subagent.ts
const session = createSession({
  model,
  instructions: "Delegate math to the math subagent.",
  subagents: [mathSubagent], 
});

session.send("What is 2^10?");
for await (const event of session.stream()) {
  if (event.type === "content_delta") process.stdout.write(event.content);
}

Tracing

Subagent executions are recorded as "subagent" span type in traces:

tracing.ts
const { result, trace } = await withTrace("my_trace", () =>
  run(assistant, "What is 99 * 99?")
);

const subagentSpans = trace.spans
  .flatMap((s) => [s, ...s.children])
  .filter((s) => s.type === "subagent");

console.log(subagentSpans[0].name); // "subagent:math"

Subagents vs Handoffs

SubagentsHandoffs
Control flowParent keeps control; child result comes backControl transfers to the child permanently
Use caseDelegate a subtask, get the answer backRoute the conversation to a specialist
Message historyChild gets a fresh message historyChild inherits the full message history
ResultChild's output becomes a tool messageChild's output becomes the final output
Edit on GitHub

Last updated on

On this page