Overview
Build intelligent multi-agent systems with composition, handoffs, and typed context flow
The @deepagents/agent package provides primitives for building multi-agent systems where specialized agents collaborate through handoffs. Rather than building monolithic agents that try to do everything, we compose systems from focused specialists that delegate to each other.
The Problem with Single Agents
When we build AI applications, we often start with a single agent that handles all tasks. This works initially, but as requirements grow, the agent becomes unwieldy:
- Context overload: The system prompt becomes massive, confusing the model
- Tool paralysis: Too many tools make selection unreliable
- Unclear failures: When something goes wrong, it's hard to trace why
- Prompt complexity: Instructions for different tasks conflict with each other
Multi-Agent Composition
DeepAgents solves this through composition. Instead of one agent with everything, we create specialists that each excel at one thing:
import { agent, instructions, execute } from '@deepagents/agent';
import { groq } from '@ai-sdk/groq';
// A specialist that researches topics
const researcher = agent({
name: 'Researcher',
model: groq('gpt-oss-20b'),
prompt: instructions({
purpose: ['You research topics thoroughly using web search.'],
routine: ['Search for relevant information', 'Summarize key findings'],
}),
tools: {
browserSearch: groq.tools.browserSearch({}),
},
handoffDescription: 'Use for researching topics and gathering information',
});
// A specialist that writes content
const writer = agent({
name: 'Writer',
model: groq('gpt-oss-20b'),
prompt: instructions({
purpose: ['You write clear, engaging content based on research.'],
routine: ['Structure the content logically', 'Write in a clear style'],
}),
handoffDescription: 'Use for writing and drafting content',
});
// A coordinator that delegates to specialists
const coordinator = agent({
name: 'Coordinator',
model: groq('gpt-oss-20b'),
prompt: instructions({
purpose: ['You coordinate research and writing tasks.'],
routine: [
'Understand the user request',
'Delegate research to the researcher',
'Delegate writing to the writer',
],
}),
handoffs: [researcher, writer],
});
// Execute the system
const stream = execute(coordinator, 'Write a blog post about AI agents', {});When the coordinator runs, it automatically gains access to transfer_to_researcher and transfer_to_writer tools. The model decides when to delegate based on the task at hand.
Key Concepts
Agents
An agent combines instructions, tools, and a model into a single unit:
const agent = agent({
name: string; // Unique identifier
model: AgentModel; // Language model from AI SDK
prompt: Instruction; // String, array, or function
tools?: ToolSet; // Available capabilities
handoffs?: Agent[]; // Agents to delegate to
output?: z.Schema; // Structured output schema
});Handoffs
Handoffs enable agent-to-agent delegation. When you add agents to the handoffs array, transfer tools are automatically generated:
handoffs: [researcher, writer]
// Creates: transfer_to_researcher, transfer_to_writerThe parent agent's system prompt includes a table of available specialists:
| Agent Name | Agent Description |
|---|---|
| researcher | Use for researching topics and gathering information |
| writer | Use for writing and drafting content |
Context Variables
Type-safe state flows through the entire execution chain:
type MyContext = {
userId: string;
findings: string[];
};
const researcher = agent<unknown, MyContext>({
prompt: (ctx) => `Research for user ${ctx.userId}...`,
// ...
});
execute(researcher, messages, { userId: '123', findings: [] });Structured Output
Agents can return typed data using Zod schemas:
const ReportSchema = z.object({
summary: z.string(),
findings: z.array(z.string()),
});
const analyst = agent({
output: ReportSchema,
// ...
});
const { experimental_output } = await generate(analyst, prompt, {});
// experimental_output is typed as { summary: string; findings: string[] }Execution Functions
Three ways to run agents:
| Function | Use Case | Returns |
|---|---|---|
execute() | Streaming responses for real-time UI | StreamTextResult |
generate() | Non-streaming for pipelines | GenerateTextResult |
swarm() | UI-compatible stream with lifecycle hooks | UIMessageStream |
// Streaming
const stream = execute(agent, 'Hello', context);
for await (const chunk of stream.textStream) {
process.stdout.write(chunk);
}
// Non-streaming
const { text, experimental_output } = await generate(agent, 'Hello', context);
// UI-compatible
const uiStream = swarm(agent, messages, context);Real-World Example
From the codebase, here's a research bot with three specialists:
// Planner decides what to search
const planner = agent({
name: 'PlannerAgent',
model: openai('gpt-4.1'),
output: WebSearchPlanSchema,
prompt: instructions({
purpose: ['Come up with web searches to answer the query.'],
routine: ['Output between 5 and 10 search terms.'],
}),
});
// Researcher executes searches
const research = agent({
name: 'ResearchAgent',
model: openai('gpt-4'),
prompt: instructions({
purpose: ['Search the web and summarize results.'],
routine: ['Capture main points succinctly.'],
}),
tools: {
web_search: openai.tools.webSearch({ searchContextSize: 'low' }),
},
});
// Writer synthesizes a report
const writer = agent({
name: 'WriterAgent',
model: openai('gpt-5'),
output: ReportDataSchema,
prompt: instructions({
purpose: ['Write a cohesive report from research.'],
routine: ['Create an outline', 'Generate the full report'],
}),
});
// Orchestrate the pipeline
const plan = await generate(planner, query, {});
const results = await Promise.all(
plan.experimental_output.searches.map((s) =>
execute(research, s.query, {}).text
)
);
const report = await generate(writer, JSON.stringify(results), {});When to Use This Package
Ideal for:
- Multi-step workflows requiring coordination
- Tasks needing different expertise (research, analysis, writing)
- Systems where specialists should have focused toolsets
- Applications requiring type-safe context flow
Consider alternatives when:
- A single prompt suffices
- You don't need agent coordination
- Simple function calling is enough
Next Steps
- Getting Started - Installation and first agent
- Anatomy of an Agent - Deep dive into agent configuration
- Handoffs - Agent-to-agent delegation patterns
- Tools - Equipping agents with capabilities