Handoffs
Route conversations between specialized agents
Handoffs let one agent transfer a conversation to another agent mid-turn. This enables multi-agent architectures like triage → specialist routing.
Basic Handoff
Pass agents directly to handoffs. Stratus auto-generates a tool named transfer_to_{agent_name}:
import { Agent, run } from "@usestratus/sdk/core";
const mathAgent = new Agent({
name: "math",
model,
instructions: "You are a math expert. Solve math problems.",
});
const triageAgent = new Agent({
name: "triage",
model,
instructions: "Route the user to the right specialist.",
handoffs: [mathAgent],
});
const result = await run(triageAgent, "What is the integral of x^2?");
console.log(result.lastAgent.name); // "math"Custom Handoff Configuration
Use the handoff() function for more control:
import { handoff } from "@usestratus/sdk/core";
const agent = new Agent({
name: "triage",
model,
handoffs: [
handoff({
agent: mathAgent,
toolName: "escalate_to_math",
toolDescription: "Escalate complex math problems to the math specialist",
onHandoff: async (ctx) => {
console.log("Handing off to math agent");
await logHandoff(ctx, "math");
},
}),
],
});Handoff Config Options
| Property | Type | Description |
|---|---|---|
agent | Agent | Required. The target agent |
toolName | string | Custom tool name (default: transfer_to_{name}) |
toolDescription | string | Custom description for the model |
onHandoff | (ctx) => void | Callback that fires when the handoff executes |
inputType | z.ZodType | Zod schema for structured input the model sends with the handoff |
inputFilter | HandoffInputFilter | Transform conversation history passed to the target agent |
isEnabled | boolean | (ctx) => boolean | When false, the handoff is excluded from the model's tool list |
Structured Handoff Input
Use inputType to let the model send structured data with a handoff. The Zod schema becomes the tool's parameter schema:
import { handoff } from "@usestratus/sdk/core";
import { z } from "zod";
const agent = new Agent({
name: "triage",
model,
handoffs: [
handoff({
agent: mathAgent,
inputType: z.object({
problem: z.string().describe("The math problem to solve"),
difficulty: z.enum(["easy", "medium", "hard"]),
}),
}),
],
});Input Filter
Use inputFilter to transform the conversation history before it's passed to the target agent. This is useful for trimming irrelevant messages or redacting sensitive content:
handoff({
agent: specialistAgent,
inputFilter: ({ history, input }) => {
// Only pass user and assistant messages (drop tool messages)
return history.filter((m) => m.role === "user" || m.role === "assistant");
},
});The filter receives a HandoffInputData object:
interface HandoffInputData {
history: ChatMessage[]; // Full conversation history
input?: unknown; // Parsed input (if inputType is set)
}Conditional Handoffs (isEnabled)
Use isEnabled to dynamically include or exclude a handoff based on context:
handoff({
agent: adminAgent,
isEnabled: (ctx: AppContext) => ctx.isAdmin,
});When false, the handoff tool is not sent to the model. Same pattern as conditional tools.
How Handoffs Work
Registered as tool
The handoff is registered as a tool definition alongside the agent's other tools.
Model calls the tool
When the model decides to hand off, it calls the handoff tool.
Callback fires
Stratus executes onHandoff (if provided), then replaces the current agent with the target.
System prompt swaps
The system prompt is replaced with the new agent's instructions. The model loop continues.
Handoffs can be blocked by beforeHandoff hooks returning { decision: "deny" }. See Hooks - Permission Control.
Handoffs in Sessions
const session = createSession({
model,
instructions: "Route users to the right specialist.",
handoffs: [mathAgent, writingAgent],
});
session.send("Help me write a poem");
for await (const event of session.stream()) {
if (event.type === "content_delta") process.stdout.write(event.content);
}
const result = await session.result;
console.log(result.lastAgent.name); // "writing"Each stream() call starts from the session's configured agent. Handoffs within a turn don't persist to the next turn.
Multi-Agent Patterns
Triage Pattern
A triage agent routes to specialists based on the user's request:
const orderAgent = new Agent({
name: "orders",
model,
instructions: "Help with order lookups and status.",
tools: [lookupOrder],
handoffDescription: "Transfer for order status and tracking",
});
const refundAgent = new Agent({
name: "refunds",
model,
instructions: "Process refund requests.",
tools: [processRefund],
handoffDescription: "Transfer for refund processing",
});
const triage = new Agent({
name: "triage",
model,
instructions: "You are a customer support triage agent.",
handoffs: [orderAgent, refundAgent],
});Handoffs vs Subagents
Handoffs transfer control - the child takes over. Subagents delegate and return - the parent keeps control. See Subagents for the delegation pattern.
Last updated on