PM Makers
PM Makers

Agents

Multi-agent orchestration for AI SDK v5. Build intelligent workflows with specialized agents, automatic handoffs, and seamless coordination. Works with any AI provider. Includes built-in memory system for persistent context.

npm install @ai-sdk-tools/agents @ai-sdk-tools/memory ai zod

Why Multi-Agent Systems?

Complex tasks benefit from specialized expertise. Instead of a single model handling everything, break work into focused agents:

Customer Support

Triage → Technical Support → Billing

Content Pipeline

Research → Writing → Editing → Publishing

Code Development

Planning → Implementation → Testing → Documentation

Data Analysis

Collection → Processing → Visualization → Insights

•

Specialization

Each agent focuses on its domain with optimized instructions and tools

•

Context Preservation

Full conversation history maintained across handoffs

•

Provider Flexibility

Use different models for different tasks (GPT-4 for analysis, Claude for writing)

•

Programmatic Routing

Pattern matching and automatic agent selection

Built-in Memory System

Every agent includes a powerful memory system that maintains context across conversations. Memory is a required dependency that provides:

•

Working Memory

Persistent context that agents can read and update during conversations

•

Conversation History

Automatic message persistence and retrieval across chat sessions

•

Chat Management

Automatic title generation and chat organization

•

Flexible Scopes

Chat-level or user-level memory with multiple storage backends

import { Agent } from '@ai-sdk-tools/agents'
import { InMemoryProvider } from '@ai-sdk-tools/memory'
import { openai } from '@ai-sdk/openai'

const agent = new Agent({
  name: 'Assistant',
  model: openai('gpt-4o'),
  instructions: 'You are a helpful assistant.',
  memory: {
    provider: new InMemoryProvider(),
    workingMemory: {
      enabled: true,
      scope: 'chat', // or 'user'
    },
    history: {
      enabled: true,
      limit: 10,
    },
    chats: {
      enabled: true,
      generateTitle: true,
    }
  }
})

Learn more about memory configuration →

Quick Start

Basic: Single Agent

import { Agent } from '@ai-sdk-tools/agents'
import { openai } from '@ai-sdk/openai'

const agent = new Agent({
  name: 'Assistant',
  model: openai('gpt-4o'),
  instructions: 'You are a helpful assistant.',
})

// Generate response
const result = await agent.generate({
  prompt: 'What is 2+2?',
})

console.log(result.text) // "4"

Handoffs: Two Specialists

import { Agent } from '@ai-sdk-tools/agents'
import { openai } from '@ai-sdk/openai'

// Create specialized agents
const mathAgent = new Agent({
  name: 'Math Tutor',
  model: openai('gpt-4o'),
  instructions: 'You help with math problems. Show step-by-step solutions.',
})

const historyAgent = new Agent({
  name: 'History Tutor',
  model: openai('gpt-4o'),
  instructions: 'You help with history questions. Provide context and dates.',
})

// Create orchestrator with handoff capability
const orchestrator = new Agent({
  name: 'Triage',
  model: openai('gpt-4o'),
  instructions: 'Route questions to the appropriate specialist.',
  handoffs: [mathAgent, historyAgent],
})

// LLM decides which specialist to use
const result = await orchestrator.generate({
  prompt: 'What is the quadratic formula?',
})

console.log(`Handled by: ${result.finalAgent}`) // "Math Tutor"
console.log(`Handoffs: ${result.handoffs.length}`) // 1

Orchestration: Auto-Routing

Use programmatic routing for instant agent selection without LLM overhead:

const mathAgent = new Agent({
  name: 'Math Tutor',
  model: openai('gpt-4o'),
  instructions: 'You help with math problems.',
  matchOn: ['calculate', 'math', 'equation', /\d+\s*[\+\-\*\/]\s*\d+/],
})

const historyAgent = new Agent({
  name: 'History Tutor',
  model: openai('gpt-4o'),
  instructions: 'You help with history questions.',
  matchOn: ['history', 'war', 'civilization', /\d{4}/], // Years
})

const orchestrator = new Agent({
  name: 'Smart Router',
  model: openai('gpt-4o-mini'), // Efficient for routing
  instructions: 'Route to specialists. Fall back to handling general questions.',
  handoffs: [mathAgent, historyAgent],
})

// Automatically routes to mathAgent based on pattern match
const result = await orchestrator.generate({
  prompt: 'What is 15 * 23?',
})

Streaming with UI

For Next.js route handlers and real-time UI updates:

// app/api/chat/route.ts
import { Agent } from '@ai-sdk-tools/agents'
import { openai } from '@ai-sdk/openai'

const supportAgent = new Agent({
  name: 'Support',
  model: openai('gpt-4o'),
  instructions: 'Handle customer support inquiries.',
  handoffs: [technicalAgent, billingAgent],
})

export async function POST(req: Request) {
  const { messages } = await req.json()

  return supportAgent.toUIMessageStream({
    messages,
    maxRounds: 5, // Max handoffs
    maxSteps: 10, // Max tool calls per agent
    onEvent: async (event) => {
      if (event.type === 'agent-handoff') {
        console.log(`Handoff: ${event.from} → ${event.to}`)
      }
    },
  })
}

Tools and Context

Adding Tools

import { tool } from 'ai'
import { z } from 'zod'

const calculatorTool = tool({
  description: 'Perform calculations',
  parameters: z.object({
    expression: z.string(),
  }),
  execute: async ({ expression }) => {
    return eval(expression) // Use safe-eval in production
  },
})

const agent = new Agent({
  name: 'Calculator Agent',
  model: openai('gpt-4o'),
  instructions: 'Help with math using the calculator tool.',
  tools: {
    calculator: calculatorTool,
  },
  maxTurns: 20, // Max tool call iterations
})

Context-Aware Agents

Use typed context for team/user-specific behavior:

interface TeamContext {
  teamId: string
  userId: string
  preferences: Record<string, string>
}

const agent = new Agent<TeamContext>({
  name: 'Team Assistant',
  model: openai('gpt-4o'),
  instructions: (context) => {
    return `You are helping team ${context.teamId}. 
    User preferences: ${JSON.stringify(context.preferences)}`
  },
})

// Pass context when streaming
agent.toUIMessageStream({
  messages,
  context: {
    teamId: 'team-123',
    userId: 'user-456',
    preferences: { theme: 'dark', language: 'en' },
  },
})

Multi-Provider Setup

Use the best model for each task:

import { openai } from '@ai-sdk/openai'
import { anthropic } from '@ai-sdk/anthropic'
import { google } from '@ai-sdk/google'

const researchAgent = new Agent({
  name: 'Researcher',
  model: anthropic('claude-3-5-sonnet-20241022'), // Excellent reasoning
  instructions: 'Research topics thoroughly.',
})

const writerAgent = new Agent({
  name: 'Writer',
  model: openai('gpt-4o'), // Great at creative writing
  instructions: 'Create engaging content.',
})

const editorAgent = new Agent({
  name: 'Editor',
  model: google('gemini-1.5-pro'), // Strong at review
  instructions: 'Review and improve content.',
  handoffs: [writerAgent], // Can send back for rewrites
})

const pipeline = new Agent({
  name: 'Content Manager',
  model: openai('gpt-4o-mini'), // Efficient orchestrator
  instructions: 'Coordinate content creation.',
  handoffs: [researchAgent, writerAgent, editorAgent],
})

Guardrails

Control agent behavior with input/output validation:

const agent = new Agent({
  name: 'Moderated Agent',
  model: openai('gpt-4o'),
  instructions: 'Answer questions helpfully.',
  inputGuardrails: [
    async (input) => {
      if (containsProfanity(input)) {
        return { 
          pass: false, 
          action: 'block',
          message: 'Input violates content policy',
        }
      }
      return { pass: true }
    },
  ],
  outputGuardrails: [
    async (output) => {
      if (containsSensitiveInfo(output)) {
        return { 
          pass: false, 
          action: 'modify',
          modifiedOutput: redactSensitiveInfo(output),
        }
      }
      return { pass: true }
    },
  ],
})

API Reference

Agent Constructor Options

name: string - Unique agent identifier
model: LanguageModel - AI SDK language model
instructions: string | ((context: TContext) => string) - System prompt
tools?: Record<string, Tool> - Available tools
handoffs?: Agent[] - Agents this agent can hand off to
maxTurns?: number - Maximum tool call iterations (default: 10)
temperature?: number - Model temperature
matchOn?: (string | RegExp)[] | ((message: string) => boolean) - Routing patterns
onEvent?: (event: AgentEvent) => void - Lifecycle event handler
inputGuardrails?: InputGuardrail[] - Pre-execution validation
outputGuardrails?: OutputGuardrail[] - Post-execution validation
permissions?: ToolPermissions - Tool access control

Methods

generate(options)

Generate response (non-streaming)

stream(options)

Stream response (AI SDK stream)

toUIMessageStream(options)

Stream as UI messages (Next.js route handler)

getHandoffs()

Get handoff agents

Event Types

• agent-start - Agent starts execution
• agent-step - Agent completes a step
• agent-finish - Agent finishes round
• agent-handoff - Agent hands off to another
• agent-complete - All execution complete
• agent-error - Error occurred

Integration with Other Packages

With @ai-sdk-tools/memory

Add persistent working memory and conversation history to agents:

import { DrizzleProvider } from '@ai-sdk-tools/memory'

const agent = new Agent({
  name: 'Assistant',
  model: openai('gpt-4o'),
  instructions: 'You are a helpful assistant.',
  memory: {
    provider: new DrizzleProvider(db),
    workingMemory: {
      enabled: true,
      scope: 'user', // or 'chat'
    },
    history: {
      enabled: true,
      limit: 10,
    },
    chats: {
      enabled: true,
      generateTitle: true,
    }
  },
})

// Agent automatically:
// - Loads working memory into system prompt
// - Injects updateWorkingMemory tool
// - Loads conversation history
// - Persists messages and generates titles

Learn more: Memory Documentation

With @ai-sdk-tools/cache

Cache expensive tool calls across agents:

import { cached } from '@ai-sdk-tools/cache'

const agent = new Agent({
  name: 'Data Agent',
  model: openai('gpt-4o'),
  instructions: 'Analyze data.',
  tools: {
    analyze: cached(expensiveAnalysisTool),
  },
})

With @ai-sdk-tools/artifacts

Stream structured artifacts from agents:

import { artifact } from '@ai-sdk-tools/artifacts'

const reportAgent = new Agent({
  name: 'Report Generator',
  model: openai('gpt-4o'),
  instructions: 'Generate structured reports.',
  tools: {
    createReport: tool({
      execute: async function* ({ title }) {
        const report = artifact.stream({ title, sections: [] })
        yield { text: 'Report complete', forceStop: true }
      },
    }),
  },
})

With @ai-sdk-tools/devtools

Debug agent execution in development:

import { AIDevTools } from '@ai-sdk-tools/devtools'

const agent = new Agent({
  name: 'Debug Agent',
  model: openai('gpt-4o'),
  instructions: 'Test agent.',
  onEvent: (event) => {
    console.log('[Agent Event]', event)
  },
})

// In your app
export default function App() {
  return (
    <>
      <YourChatInterface />
      <AIDevTools />
    </>
  )
}

Examples

Real-world implementations can be found in /apps/example/src/ai/agents/:

•

Triage Agent

Route customer questions to specialists

•

Financial Agent

Multi-step analysis with artifacts

•

Code Review

Analyze → Test → Document workflow

•

Multi-Provider

Use different models for different tasks