Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cognis.vasanth.xyz/llms.txt

Use this file to discover all available pages before exploring further.

Some problems are easier when you split them across specialized agents — a planner, a researcher, a writer, a critic. Cognis ships four orchestration strategies and a HandoffStrategy trait you can implement for your own. The orchestrator handles the boring parts (input routing, output capture, error propagation); you decide how the agents talk to each other.

What it is

let orch = MultiAgentOrchestrator::new(strategy)
    .add("name1", agent1)
    .add("name2", agent2);

let resp: AgentResponse = orch.run(input).await?;
strategy is a value (not a string or enum), which means each strategy is its own type with its own configuration knobs.

Pick a strategy

Each agent receives the previous agent’s output. Useful for pipelines where one specialist hands off to the next.
use cognis::{AgentBuilder, MultiAgentOrchestrator, Sequential};
use cognis_llm::Client;

let planner = AgentBuilder::new().with_llm(Client::from_env()?)
    .with_system_prompt("Break the request into 3 numbered steps.").build()?;

let executor = AgentBuilder::new().with_llm(Client::from_env()?)
    .with_system_prompt("Receive a numbered plan; reply with one paragraph.").build()?;

let orch = MultiAgentOrchestrator::new(Sequential)
    .add("planner", planner)
    .add("executor", executor);

let resp = orch.run("Help me prep for a 5-min team standup.").await?;
Source: examples/v2/08_ollama_multi_agent.rs.

How it works

  • Each strategy is a struct that implements HandoffStrategy. That trait has one required async method: run(&self, agents, input, bus) -> Result<AgentResponse>. The strategy decides everything that happens between the user’s input and the final response.
  • Agents inside the orchestrator are still Agents. Each runs its own loop with its own memory, tools, and middleware. The orchestrator only decides who runs next.
  • Errors propagate. If an agent inside the orchestrator returns Err, the orchestrator returns Err. Wrap a sub-agent’s client with with_fallback if you want graceful degradation.
  • The orchestrator returns an AgentResponse. Same shape as a single agent — drop-in callers don’t change.
  • Other strategies in the box. Beyond the four covered above, cognis::multi_agent also ships Hierarchical (manager → workers tree) and Consensus (quorum-based voting).

Custom handoff

Implement HandoffStrategy for full control:
use std::sync::Arc;
use async_trait::async_trait;
use tokio::sync::Mutex;
use cognis::multi_agent::{HandoffStrategy, MessageBus};
use cognis::{Agent, AgentResponse, Message, Result};

struct EscalateOnUnsure;

#[async_trait]
impl HandoffStrategy for EscalateOnUnsure {
    async fn run(
        &self,
        agents: &[(String, Arc<Mutex<Agent>>)],
        input: Message,
        bus: Arc<dyn MessageBus>,
    ) -> Result<AgentResponse> {
        // 1. Run a primary agent.
        // 2. If its reply is unsure, route to a senior agent.
        // 3. Return the chosen reply.
        todo!()
    }

    fn name(&self) -> &str { "EscalateOnUnsure" }
}
This is the right shape for domain-specific orchestrators — escalation chains, conditional handoffs, supervised exploration.

AgentBus and AgentEventBus

For looser coupling than orchestration — broadcast / subscribe between agents — Cognis has two pub/sub primitives:
  • AgentBus — generic typed pub/sub. Any T: Clone + Send + Sync + 'static can be a topic value.
  • AgentEventBus — pre-typed for AgentEvents emitted during the loop (request started, tool called, response produced, …).
use cognis::AgentBus;

let bus = AgentBus::new();
let mut sub = bus.subscribe::<MyEvent>("topic.events");
bus.publish("topic.events", MyEvent { /* … */ }).await?;
let ev = sub.recv().await?;
These don’t replace the orchestrator — they complement it. Orchestrators are for tightly coupled handoffs; buses are for fan-out signalling.

See also

Patterns → Multi-agent debate

A worked propose-critique-revise loop.

Patterns → Research assistant

Sequential planner → researcher → writer.

Middleware

SubagentMiddleware for inline subagent spawning from a single parent loop.