Recommended resources
The freely available resources this lesson will direct you to.
Welcome back. In our previous lesson, we established a robust system for dynamically loading an agent's instructions from a central Prompt Store. By decoupling prompts from code, we've made our agents more flexible and easier to manage. Now, with agents that can be configured with both tools and prompts on the fly, we are ready to assemble them into a functional hierarchy.
Today, we will implement one of the most powerful patterns in agentic design: the supervisor-worker hierarchy. You will learn how to create a "supervisor" agent that can delegate complex tasks to specialized "worker" agents. This is a foundational step toward building the sophisticated, multi-agent infrastructure that is central to your goal. We will focus on the core mechanism of delegation, which, as you'll see, leverages the Vercel AI SDK's tool-calling capabilities in a very elegant way.
1. The Supervisor-Worker Pattern
In any complex system, whether it's a software team or an AI application, a single entity trying to do everything becomes a bottleneck. The solution is delegation. In agentic systems, this is known as the supervisor-worker pattern (or orchestrator-worker). A supervisor agent acts as a coordinator, breaking down a high-level task and delegating sub-tasks to specialized worker agents.
This pattern is not just a theoretical concept; it's a practical approach to building scalable agent workflows.
Building AI Agent Workflows With Vercel's AI SDK
This article from Callstack provides an excellent, practical overview of various agentic workflows. We'll focus on the one that directly maps to our goal.
Please read the section on Orchestrator-Workers. Notice the analogy to a project team: a Tech Lead (supervisor) splits a feature request into tasks for a QA, Developer, and DevOps (workers). This is precisely the kind of separation of concerns we aim to achieve.
The primary motivations for adopting this hierarchical structure are compelling, especially for production-grade systems:
- Context Management: Worker agents can perform information-heavy tasks (like searching a codebase or the web) without flooding the supervisor's limited context window. The supervisor only needs to see the final, summarized result.
- Specialization & Isolation: You can equip worker agents with specific, powerful tools (e.g., database access, code execution) without giving those permissions to the main supervisor agent, enhancing security and reliability.
- Parallelism: Independent sub-tasks can be executed concurrently by multiple worker agents, significantly reducing overall task completion time.
The Vercel AI SDK documentation on subagents provides a concise summary of these benefits.
These official docs explain the rationale and mechanics of subagents.
Focus on the introduction and the tables in the sections When to Use Subagents and Why Use Subagents?. This reinforces the core principles behind the pattern.
2. The Implementation: Agents as Tools
The key insight for implementing this pattern in the Vercel AI SDK is both simple and powerful: a worker agent is exposed to its supervisor as a tool.
The supervisor doesn't need to know it's interacting with another complex agent; it just sees a tool with a specific input schema and an expected output. This abstraction is what makes the system so modular and extensible.
Let's break down how this works. Our primary building block will be the ToolLoopAgent, which you've likely encountered in your previous work with the AI SDK. It's Vercel's standard, production-ready implementation of an agent that can run in a loop, calling tools until it completes its task.

To see how these pieces connect, we will turn to the official documentation, which contains the canonical implementation pattern.
This section provides the fundamental code for creating and delegating to a subagent.
Study the code example under the heading Basic Subagent Without Streaming. This is the most important code snippet for this lesson. Analyze how researchSubagent is a standard ToolLoopAgent, and how researchTool wraps it, making it callable by mainAgent.
Let's dissect this pattern and adapt it for our infrastructure.
Step 1: Define the Worker Agent
First, we define our specialized worker. It's a standard ToolLoopAgent with its own instructions and a specific set of tools. For example, a research_agent might have tools for web search and reading documentation.
// /lib/agents/research-agent.ts
import { ToolLoopAgent } from 'ai';
import { openai } from '@ai-sdk/openai';
import { webSearchTool, readFileTool } from '@/lib/tools'; // Assume these are defined elsewhere
export const researchAgent = new ToolLoopAgent({
model: openai('gpt-4o'),
instructions:
'You are a world-class research analyst. You use the provided tools to find and synthesize information to answer the user request. Respond with a concise summary of your findings.',
tools: {
search: webSearchTool,
read: readFileTool,
},
});
Step 2: Create a Tool to Wrap the Worker
Next, we create a tool that the supervisor will use. The execute function of this tool is where the delegation happens: it invokes the worker agent.
// /lib/tools/delegation/create-research-tool.ts
import { tool } from 'ai';
import { z } from 'zod';
import { researchAgent } from '@/lib/agents/research-agent';
export const createResearchTool = () => {
return tool({
description: 'Delegates a research task to a specialized research agent. Use this for any task that requires finding, reading, or synthesizing information from external sources.',
inputSchema: z.object({
task: z.string().describe('The specific research question or task to be completed.'),
}),
execute: async ({ task }) => {
// Delegate the task to the researchAgent
const result = await researchAgent.generate({
prompt: task,
});
// Return the final text output from the worker
return result.text;
},
});
};
Note how the task from the tool's input is passed as the prompt to the researchAgent. The supervisor "talks" to the worker by calling this tool.
Step 3: Define the Supervisor Agent
Finally, the supervisor agent is another ToolLoopAgent, but its toolset includes the delegation tool we just created.
// /lib/agents/supervisor-agent.ts
import { ToolLoopAgent } from 'ai';
import { openai } from '@ai-sdk/openai';
import { createResearchTool } from '@/lib/tools/delegation/create-research-tool';
const researchTool = createResearchTool();
export const supervisorAgent = new ToolLoopAgent({
model: openai('gpt-4o'),
instructions:
'You are a supervisor. Your job is to analyze user requests and delegate sub-tasks to available worker agents. You do not perform tasks yourself; you only delegate.',
tools: {
research: researchTool,
// We could add more delegation tools here, e.g., codeWriterTool, etc.
},
});
When the supervisorAgent is given a prompt like "Research the current weather in San Francisco," its model will determine that the research tool is the best fit, call it with the task "current weather in San Francisco," and our researchAgent will execute the request.
3. Managing Context and Communication Flow
A critical aspect of this architecture is how context is managed. If the worker agent's entire thought process (all its tool calls and intermediate reasoning) were passed back to the supervisor, the supervisor's context window would quickly be exhausted.
Fortunately, subagent context is isolated by default.
This part of the documentation explains a key benefit of the subagent pattern.
Read the section Subagent Context is Isolated. Understand that each subagent invocation starts with a fresh context, and you should only pass history if absolutely necessary.
This isolation is a major advantage. The worker can use thousands of tokens to do its job, but the supervisor remains unaffected. However, this raises a question: how do we control what information is returned to the supervisor?
The toModelOutput function in the tool definition gives us precise control over the payload that is added back to the supervisor's message history. Instead of the worker's full output, we can pass back a concise summary.
This feature is essential for managing context in a production system.
Read the section Controlling What the Model Sees. Pay close attention to how the toModelOutput function is used to extract just the final text summary from the subagent's work, keeping the main agent's context clean.
Let's modify our researchTool to incorporate this. Imagine our researchAgent not only produces a final text summary but also returns structured data about its sources. The UI might need the full object, but the supervisor model only needs the text.
// /lib/tools/delegation/create-research-tool.ts (Enhanced)
import { tool, UIMessage } from 'ai';
import { z } from 'zod';
import { researchAgent } from '@/lib/agents/research-agent';
// Assume researchAgent now returns a structured object { text: string, sources: string[] }
// and we use stream/generate's `output` property to get it.
export const createResearchTool = () => {
return tool({
description: 'Delegates a research task...',
inputSchema: z.object({ task: z.string() }),
execute: async ({ task }) => {
// For simplicity, we'll imagine the result is a complex object.
// In a real implementation, you would use `researchAgent.stream` or `researchAgent.generate`
// with a schema to get a structured result.
const result = await researchAgent.generate({ prompt: task });
const structuredResult = {
summary: result.text,
sources: ['https://example.com/source1', 'https://example.com/source2'],
tokensUsed: result.usage.totalTokens
};
return structuredResult; // The full object is available in the message history for the UI
},
toModelOutput: ({ output: structuredResult }) => {
// This function determines what the SUPERVISOR'S model sees.
// We only pass the summary, not the extra metadata.
return {
type: 'text',
value: `Research complete. Summary: ${structuredResult.summary}`
};
},
});
};
This is an incredibly powerful technique for context management. The worker performs its detailed task, and the supervisor receives a clean, concise report, keeping it focused on its primary job: orchestration.
Conclusion
In this lesson, you have learned the fundamental pattern for implementing a supervisor-worker agent hierarchy using the Vercel AI SDK. By wrapping worker agents as tools, you can build modular, scalable, and secure multi-agent systems.
Key Takeaways:
- Delegation via Tools: The core mechanism for agent hierarchy is exposing worker agents to a supervisor as callable tools.
- The
ToolLoopAgent: This is the standard, production-ready building block for both supervisor and worker agents. - Context Isolation: Worker agents operate in an isolated context, preventing the supervisor's context window from becoming bloated with intermediate steps.
- Controlled Communication: The
toModelOutputfunction provides precise control over the information passed from a worker back to the supervisor's model, which is crucial for managing context and token usage.
You have now built the "plumbing" for delegation. However, simply providing the tool is not enough. The supervisor needs to be instructed on how, when, and why to use its worker agents effectively. In our next lesson, we will focus on designing and implementing "delegation prompts" that turn your supervisor from a simple tool user into an intelligent coordinator.