Agent SDK

Orchestration

Patterns for coordinating single and multi-agent systems

Orchestration

Orchestration is how you coordinate agent execution — from a single agent handling everything, to specialized agents collaborating on complex tasks. The SDK supports five orchestration patterns, each with different trade-offs.

Start Simple

The golden rule of agent orchestration:

Start with a single agent. Add multi-agent structure only when you have a clear reason.

Most tasks don't need multi-agent systems. A single well-configured agent with good tools handles the majority of use cases. Add complexity only when you hit real limits.

Pattern 1: Single Agent

The simplest and most common pattern. One agent with tools and guardrails.

const agent = new Agent({
  name: 'assistant',
  model: claude('claude-sonnet-4-6'),
  instructions: 'You are a helpful assistant.',
  tools: [webSearch, calculator, fileReader],
})

const result = await Runner.run(agent, { messages })

When to use: 90% of cases. Use until you can articulate why you need more.

Pattern 2: Sequential Pipeline

Agents run in sequence, each transforming the output for the next:

import { Pipeline } from 'assistme-agent-sdk'

const pipeline = Pipeline.create([
  {
    agent: researcher,
    map: (input) => ({ messages: [{ role: 'user', content: `Research: ${input}` }] }),
  },
  {
    agent: writer,
    map: (researchResult) => ({
      messages: [{ role: 'user', content: `Write an article based on: ${researchResult.output}` }],
    }),
  },
  {
    agent: editor,
    map: (draft) => ({
      messages: [{ role: 'user', content: `Edit and polish: ${draft.output}` }],
    }),
  },
])

const result = await pipeline.run('Quantum computing advances in 2026')
// researcher → writer → editor → final polished article

When to use: Assembly-line processing where each step has a clear input/output contract.

Pattern 3: Parallel Execution

Run independent agents concurrently for lower latency:

import { Parallel } from 'assistme-agent-sdk'

const results = await Parallel.run([
  { agent: newsAgent, input: { messages: [{ role: 'user', content: 'Latest tech news' }] } },
  { agent: weatherAgent, input: { messages: [{ role: 'user', content: 'Weather in SF' }] } },
  { agent: stockAgent, input: { messages: [{ role: 'user', content: 'Market summary' }] } },
])

// All three run concurrently
// Total time ≈ slowest agent, not sum of all three
console.log(results.map(r => r.output))

Parallel with Aggregation

const briefing = await Parallel.run(
  [
    { agent: newsAgent, input: newsInput },
    { agent: weatherAgent, input: weatherInput },
    { agent: stockAgent, input: stockInput },
  ],
  {
    aggregate: async (results) => {
      // Combine results into a morning briefing
      return Runner.run(summaryAgent, {
        messages: [{
          role: 'user',
          content: `Create a morning briefing from:\n${results.map(r => r.output).join('\n---\n')}`,
        }],
      })
    },
  },
)

When to use: Independent subtasks that can run concurrently. Same total token cost, ~60% lower wall-clock time.

Pattern 4: Router

A routing agent classifies the input and dispatches to specialists:

import { Router } from 'assistme-agent-sdk'

const router = Router.create({
  model: claude('claude-haiku-4-5'), // Fast, cheap model for routing
  routes: [
    {
      agent: codeAgent,
      description: 'Questions about writing, debugging, or reviewing code',
    },
    {
      agent: dataAgent,
      description: 'Questions about data analysis, SQL, or statistics',
    },
    {
      agent: writingAgent,
      description: 'Writing tasks: emails, articles, summaries',
    },
    {
      agent: generalAgent,
      description: 'General knowledge questions and conversation',
    },
  ],
  fallback: generalAgent,
})

const result = await Router.run(router, { messages })

The router uses a lightweight model to classify the request, then dispatches to the appropriate specialist. The specialist gets a clean context without the routing overhead.

When to use: Mixed-complexity requests where different types benefit from specialized agents.

Pattern 5: Supervisor (Hierarchical)

A supervisor agent manages a team, delegating tasks and synthesizing results:

const supervisor = new Agent({
  name: 'supervisor',
  model: claude('claude-sonnet-4-6'),
  instructions: `You are a project manager. Break down complex requests into subtasks
and delegate them to your team. Synthesize the results into a coherent response.`,
  tools: [
    researcher.asTool({ name: 'research', description: 'Research a topic' }),
    coder.asTool({ name: 'write_code', description: 'Write or review code' }),
    analyst.asTool({ name: 'analyze_data', description: 'Analyze data or metrics' }),
  ],
})

const result = await Runner.run(supervisor, {
  messages: [{
    role: 'user',
    content: 'Build a dashboard showing our top 10 customers by revenue with trend charts',
  }],
})

The supervisor decides which agents to involve, what to delegate, and how to combine results. Each sub-agent runs in isolation with its own context window.

When to use: Complex tasks requiring coordination across different skill domains.

Comparing Patterns

PatternLatencyToken CostError RecoveryComplexity
Single AgentLowLowSimpleLowest
SequentialHighModerateModerateLow
ParallelLowSame totalGood (isolated)Low
RouterLowLow (cheap classifier)GoodModerate
SupervisorVariableHighestBestHighest

Combining Patterns

Real systems often combine patterns:

// Router → dispatches to specialists
// Each specialist may use parallel sub-agents
// Results flow through a sequential pipeline

const router = Router.create({
  routes: [
    {
      agent: new Agent({
        name: 'research-team',
        tools: [
          // Sub-agents run in parallel
          sourceA.asTool({ name: 'search_academic' }),
          sourceB.asTool({ name: 'search_news' }),
          sourceC.asTool({ name: 'search_patents' }),
        ],
      }),
      description: 'Research questions requiring multiple sources',
    },
  ],
})

Context Isolation

Each agent in a multi-agent system gets its own context window. This is critical for:

  1. Token efficiency — Sub-agents don't carry the parent's full context
  2. Focus — Agents perform better with relevant-only context
  3. Security — Agents can't see each other's tool results unless explicitly shared
// The researcher explores using 50,000 tokens internally
// But returns only a 2,000 token summary to the supervisor
const researcher = new Agent({
  name: 'researcher',
  model: claude('claude-sonnet-4-6'),
  instructions: 'Research thoroughly, then return a concise summary of findings.',
  tools: [webSearch, readUrl],
})

// The supervisor only sees the summary in its context
const supervisor = new Agent({
  name: 'supervisor',
  tools: [researcher.asTool({ name: 'research' })],
})

Best Practices

  1. Single agent first — Don't reach for multi-agent until single agent fails. The overhead of coordination often exceeds the benefit.

  2. Use the cheapest pattern that works — Router > Pipeline > Parallel > Supervisor in terms of simplicity.

  3. Isolate contexts — Never share full context between agents. Summarize and pass only what's needed.

  4. Use cheap models for routing — Haiku-class models are excellent routers. Don't waste Opus-class on classification.

  5. Set maxTurns on every agent — Especially sub-agents. A runaway sub-agent can blow up costs.

  6. Monitor token usage — Multi-agent systems can use tokens faster than expected. Track per-agent and total usage.