Agent whose run() call lives inside a tool() execute function. The framework handles everything else: the orchestrator’s model decides when to call the tool, Vibes executes it, appends the result to history, and the run continues. Nesting is unlimited and usage aggregates automatically.
The agent-as-tool pattern
The fundamental building block is wrapping one agent’srun() call inside a tool(). The outer agent gets a tool it can call by name; the inner agent does focused work and returns a string. From the model’s perspective it’s just a tool call — there’s nothing special about the implementation.
(2)
tool() is the only glue needed. The specialist’s run() call is a plain async function call inside execute.(3)
result.output is a string here because searchSpecialist has no outputSchema. If the specialist returned a structured type, you’d get that instead.(4) The orchestrator’s system prompt is completely decoupled from the specialist’s. You can swap the specialist model, rewrite its prompt, or add tools to it without touching the orchestrator.
You don’t need to import any special multi-agent module. The only imports you need are
Agent, tool, and z — the same ones you use for any other agent.Why multi-agent instead of more tools?
Before adding a sub-agent, ask: can I solve this with another tool on the same agent? Use a sub-agent when:- The sub-task needs a different persona — a strict grader, a creative writer, a terse summarizer. Mixing prompts in one agent produces confused output.
- The sub-task needs different tools that should be invisible to the orchestrator. If the orchestrator doesn’t need to call
read_filedirectly, don’t clutter its tool list. - You want to reuse the same specialist from multiple orchestrators, keeping a single source of truth for its instructions and tools.
- The output of one stage is structured input for the next stage and you want that boundary enforced by a Zod schema.
Passing dependencies through the hierarchy
Dependencies flow through thedeps field on RunOptions. When your tools receive a RunContext, the ctx.deps field holds whatever you passed at run time. A sub-agent called inside a tool can receive its own deps at call time.
userId — good for least-privilege design.
Aggregating usage across the hierarchy
Token usage aggregates automatically.result.usage on the top-level run reflects the combined cost of the orchestrator plus every sub-agent call made during that run — you do not need to track sub-agent usage separately.
RunContext.usage object is shared within a run and sub-agents accumulate into the same counter through the tool’s ctx. Sub-agents started in separate agent.run() calls (outside of a tool context) maintain their own usage counters.
Structured output from sub-agents
Sub-agents can return structured data just like any agent. Declare anoutputSchema on the specialist, and the returned result.output is fully typed.
execute must return a string or plain object. Serializing the structured output lets the orchestrator see the full structure in its message history.
Common patterns
Orchestrator + specialists
One orchestrator agent with multiple specialist tools. The orchestrator routes tasks; specialists execute them. Good for open-ended tasks where the model should decide the order.
Pipeline
Agent A produces output that feeds directly into Agent B. Use message history (
messageHistory option) or tool chaining. Good when stages are deterministic and sequential.Dynamic routing
A router tool that calls different specialists based on task type. Implement with an
if/else in the tool’s execute — no special routing API required.Peer agents
Two agents that can each call the other as a tool. Useful for critique/review loops where one generates and one evaluates. Set
maxTurns carefully to bound recursion.Full example: research pipeline
Here’s a complete three-agent system: a search specialist, a summarizer, and an orchestrator that coordinates them.(2) The summarizer declares a Zod
outputSchema. The framework injects a final_result tool and validates the output automatically.(3)
JSON.stringify converts the structured output to a string so the orchestrator can read it in its message history.(4) The orchestrator coordinates and synthesizes, which benefits from a stronger model’s reasoning ability.
(5) With three tool calls in the plan,
maxTurns: 6 gives buffer for the model to think before and after each tool call.
Dynamic routing
When the right specialist depends on what the user asked, route inside the tool’sexecute function:
switch, Map lookups, database queries — whatever the routing logic requires.
Tools
Define tools and wrap any async function
Dependencies
Pass runtime deps through RunContext