Skip to main content
The routing engine is a three-stage pipeline that picks one agent from a candidate set. It makes one decision, then hands off — it’s not an agentic loop. For several agents collaborating on one task, see multi-agent workflows.

When routing runs

This pipeline does not run on every chat message that omits an agent. Read this section before assuming what powers your unrouted chat traffic.
Chat requests go to POST /api/orchestrator/a2a. What happens depends on agent_id: The pipeline below is invoked in one place today: auto-assigning an agent to a MAF workflow step that doesn’t name one. Tuning it shapes MAF step assignment, not live chat routing. Full detail: where the pipeline actually runs.

The three stages

  1. Shortlist — ranks agents by semantic similarity between the query and each agent’s description, keeping the top candidates. Skipped for small fleets (ROUTER_SHORTLIST_THRESHOLD) or if the embedding provider is unavailable; either way every agent advances.
  2. Rerank — re-scores candidates using conversation context, so a follow-up is more likely to stay with the agent already handling the session. On failure, the shortlist order is kept.
  3. Select — an LLM makes the final call. On failure, the top-ranked candidate is chosen and the decision is marked fallback_used: true.
Every stage degrades gracefully — a query is never rejected because a routing sub-step had trouble. Decisions are logged asynchronously, off the response path.

Tuning

Environment variables on the control plane: These tune the engine’s own decision-making, separate from which model an agent calls once selected — see reusable LLM configs.

Inspecting decisions

GET /api/orchestrator/stats returns aggregated stats from this pipeline’s decisions — today, MAF step auto-assignments. One row per agent per day, newest and most-selected first, capped at 200 rows.
There’s no CLI command for this yet — call the route directly. To see which agent handled a live chat query, look at its session and trace instead: GET /api/observability/session/{id} and GET /api/observability/trace/{id}.

Reusable LLM configs

Separate from engine tuning, you can control which LLM an individual agent calls, through a per-user library of named configs:
A config carries a provider, model, optional fallback models, tuning (temperature, max tokens), and optionally your own API key. --pin locks an agent to one model — the engine still picks which agent answers, but that agent’s LLM calls stay fixed. nasiko model-registry ls / set manage a platform-wide strength-level→model table (level 1 strongest, level 3 smallest) that a smart-routing config can draw from. Changing it requires superuser. Full command set: nasiko llm-config --help.

LLM router dashboard

Configure providers and per-level models in the web app.

TokenOps

What your routing and model choices cost.

A2A agents and frameworks

What makes an agent discoverable and routable.

Orchestrator reference

Failure behavior and the flow guard.