Agents

Multi-Agent Workflows

Use Agent.asTool() to delegate work from one agent to specialist agents.

Use multiple agents when one coordinator should break a task into specialist work. In Anvia, the simplest pattern is to turn specialist agents into tools with agent.asTool(...), then attach those tools to a coordinator agent.

Build Specialist Agents

import { AgentBuilder } from "@anvia/core";

const supportAgent = new AgentBuilder("support", model)
  .name("Support Specialist")
  .description("Analyze customer impact and support next steps.")
  .instructions("Return concise support triage notes using only the provided facts.")
  .build();

const engineeringAgent = new AgentBuilder("engineering", model)
  .name("Engineering Specialist")
  .description("Analyze technical causes, diagnostics, and engineering next steps.")
  .instructions("Return concrete diagnostics and avoid unverified root-cause claims.")
  .build();

Specialist agents should have narrow instructions. Give each one a clear role and output shape.

Expose Agents as Tools

const coordinator = new AgentBuilder("coordinator", model)
  .name("Incident Coordinator")
  .instructions(
    [
      "Coordinate specialist agents through tools.",
      "Give each specialist a short task based only on the user request.",
      "Combine their findings into one concise incident brief.",
    ].join("\n"),
  )
  .tools([
    supportAgent.asTool({ name: "ask_support_agent" }),
    engineeringAgent.asTool({ name: "ask_engineering_agent" }),
  ])
  .defaultMaxTurns(4)
  .build();

asTool(...) creates a tool with one input field:

{ prompt: string }

When the coordinator calls the tool, Anvia prompts the specialist agent and returns the specialist's final text as the tool result.

By default, a specialist exposed with asTool(...) is opaque while it runs. The parent stream shows the parent tool_call and final tool_result, but not the child agent's intermediate turns.

Enable nested streaming when your UI should show specialist progress:

const coordinator = new AgentBuilder("coordinator", model)
  .tools([
    supportAgent.asTool({ name: "ask_support_agent", stream: true }),
    engineeringAgent.asTool({ name: "ask_engineering_agent", stream: true }),
  ])
  .build();

When the parent runs with .stream(), child agent events arrive as agent_tool_event values. The parent model still receives only the final specialist output as the normal tool result.

Nested progress is best-effort: the parent agent and child agent models must both support streaming. If nested streaming is unavailable, the agent-tool still behaves like a normal opaque asTool(...) call and returns the specialist's final output.

Add an event store when you need to replay or inspect nested child-agent progress after the run.

For memory boundaries in coordinator/specialist systems, see Multi-Agent Memory.

Run With Tool Concurrency

const response = await coordinator
  .prompt("Prepare an incident brief for a webhook retry failure.")
  .withToolConcurrency(2)
  .send();

console.log(response.output);

Use .withToolConcurrency(...) when independent specialist tools can run at the same time.

When to Use This Pattern

PatternUse it when
agent.asTool(...)A coordinator should decide which specialists to call during a prompt run and child progress can remain hidden
agent.asTool({ stream: true })A coordinator should decide which specialists to call and the caller should see child progress during streaming
Parallel pipelinesYou already know every branch should run
Studio multiple agentsYou want several agents available in one local UI

For runnable examples, see examples/cookbook/07_multi_agent/01-agent-as-tool.ts, examples/cookbook/07_multi_agent/03-streaming-agent-tools.ts, and examples/cookbook/07_multi_agent/04-agent-event-store.ts.