Deep Agents
AgentOrchestratorRetrievalText2SQLToolbox

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_writer

The parent agent's system prompt includes a table of available specialists:

Agent NameAgent Description
researcherUse for researching topics and gathering information
writerUse 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:

FunctionUse CaseReturns
execute()Streaming responses for real-time UIStreamTextResult
generate()Non-streaming for pipelinesGenerateTextResult
swarm()UI-compatible stream with lifecycle hooksUIMessageStream
// 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