Multi-Agent Orchestrator
This example demonstrates Heartbit’s orchestrator pattern. An orchestrator coordinates multiple specialized sub-agents — a researcher and a writer — that collaborate through delegation to produce a polished result.
Prerequisites
Section titled “Prerequisites”ANTHROPIC_API_KEYenvironment variable set with a valid API key
Running
Section titled “Running”export ANTHROPIC_API_KEY="sk-..."cargo run -p heartbit --example multi_agentSource
Section titled “Source”use std::sync::Arc;
use heartbit::{AnthropicProvider, Orchestrator};
#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> { let api_key = std::env::var("ANTHROPIC_API_KEY").expect("set ANTHROPIC_API_KEY environment variable"); let provider = Arc::new(AnthropicProvider::new(api_key, "claude-sonnet-4-20250514"));
let mut orchestrator = Orchestrator::builder(provider) .sub_agent( "researcher", "Finds facts and data on a topic", "You are a research assistant. Find key facts and return them as bullet points.", ) .sub_agent( "writer", "Writes polished prose from notes", "You are a writer. Turn bullet-point notes into a short, polished paragraph.", ) .max_turns(5) .max_tokens(4096) .build()?;
let output = orchestrator .run("Write a short paragraph about the Rust programming language.") .await?;
println!("{}", output.result); eprintln!( "[total tokens: {} in / {} out]", output.tokens_used.input_tokens, output.tokens_used.output_tokens );
Ok(())}Walkthrough
Section titled “Walkthrough”Orchestrator builder — Orchestrator::builder(provider) creates a builder that accepts sub-agent definitions. Each sub_agent() call takes three arguments:
- A name (used for delegation and logging)
- A description (tells the orchestrator what this agent is good at)
- A system prompt (shapes the sub-agent’s behavior)
Sub-agent roles — The orchestrator has a built-in delegate_task tool. When it receives a task, it decides which sub-agent to delegate to based on the descriptions:
researcher— finds facts and returns structured datawriter— transforms raw notes into polished prose
Execution flow — orchestrator.run("...") kicks off the orchestration loop:
- The orchestrator reads the user request
- It delegates to the researcher to gather facts
- It delegates to the writer with the researcher’s output
- It returns the final polished result
Token tracking — output.tokens_used accumulates tokens across all sub-agent calls, giving you total cost visibility.
Flat hierarchy — Heartbit enforces a flat agent hierarchy: the orchestrator spawns sub-agents, but sub-agents never spawn further agents. This keeps execution predictable and debuggable.
What to expect
Section titled “What to expect”The orchestrator coordinates both agents and returns a polished paragraph about Rust, followed by aggregate token usage:
Rust is a systems programming language focused on safety, speed, and concurrency...[total tokens: 1250 in / 380 out]