Skip to content

Voice request lifecycle

Status: Current | Last reviewed: 2026-05-28

What happens when a phone call hits TrueServe. Read this before universal pipeline builder.

The path

Caller / Carrier
  │ SIP INVITE
  ▼
kamailio                  (SIP routing, TLS termination)
  │ SIP INVITE rewritten
  ▼
asterisk                  (call control via PJSIP realtime)
  │ Stasis app handoff via ARI
  ▼
ari-controller-node       (decides what to do; binds the channel to media)
  │ Bridge channel to external media
  ▼
media-proxy (Go)          (decodes RTP, mixes, ducks; resamples)
  │ bidirectional gRPC audio
  ▼
ai-orchestrator (Python)  (Pipecat pipeline built from agent_versions.config)
  │ STT → LLM → TTS, plus tools
  ▼
agent-host (MCP tools)    ←→ external integrations (Salesforce, knowledge-engine, …)

The reverse path carries TTS audio back: ai-orchestrator → media-proxy → asterisk → kamailio → caller.

Per-hop responsibility

kamailio

Front-door SIP proxy. Handles TLS, registration, dial-plan rewriting, ACL. In Sentinel and city dev environments, kamailio is the only service exposed publicly on SIP ports. It forwards trusted calls to asterisk over UDP/TCP on the loopback (Vanguard) or pod network (cluster).

Config lives in charts/kamailio/ for cluster deploys and .devcontainer/configs/kamailio/ for Vanguard. Per-city TLS certs are baked into the container image during city rollout; see city-dev-environments.md.

asterisk

PBX with PJSIP realtime backed by the ps_* tables in Postgres. Asterisk is configured as a B2BUA: it accepts a leg from kamailio and dials a Stasis application that hands control to ari-controller-node over WebSocket on :8087.

The dialplan does very little logic. Everything beyond "answer and hand off" is in ari-controller.

ari-controller-node

A Node.js service that holds an ARI WebSocket open to asterisk. When a Stasis event arrives, it:

  1. Resolves the agent for this call (from dialed number → tenant → agent).
  2. Allocates a media-proxy session.
  3. Bridges the asterisk channel to media-proxy's external media (RTP).
  4. Tells ai-orchestrator to start a pipeline for this conversation.

For warm hand-off, ari-controller drives the consult: it spins up a second outbound channel, mixes the agents into a bridge, then unbridges on completion. See warm-handoff.md.

media-proxy

Go service that takes raw RTP from asterisk on one side and bidirectional gRPC audio frames from ai-orchestrator on the other. Handles:

  • Codec negotiation (G.711 µ-law, A-law, Opus).
  • Resampling between carrier rate (8 kHz / 16 kHz) and pipeline rate (24 kHz).
  • Mixing and ducking when multiple streams are active (translation TTS, underbed, hold music).

See audio-ducking.md.

ai-orchestrator

Python service running Pipecat. For each call it:

  1. Resolves the agent's config via resolve_agent_version() (sql-functions.md).
  2. Builds the pipeline through universal_builder.py, which selects a subtype builder (linear, S2S, translation, parallel-agent, etc.).
  3. Runs the pipeline: audio in → STT → LLM → tool calls (via agent-host) → TTS → audio out.
  4. Persists transcripts and events through conversation-api.

agent-host

MCP tool server that exposes the agent's tools (CRM lookups, knowledge search, custom Python, A2UI components) over the Model Context Protocol. ai-orchestrator dials agent-host as an MCP client; the LLM emits tool calls that flow back through.

agent-host runs the MCP streamable endpoint on :8003. See agent-host.md.

What carries the conversation state

Layer Where state lives Lifetime
SIP signaling asterisk channels Call duration
Media media-proxy in-memory session Call duration
Pipeline ai-orchestrator process memory Call duration
Transcript conversations + conversation_messages (Postgres) Forever
Recording conversation_recordings row + S3/GCS/MinIO blob Forever
Tool state agent-host worker, optionally in Redis for cross-pod consistency Tool-defined

If ai-orchestrator dies mid-call, the call drops. Persistent state is in the conversation tables; the live pipeline is intentionally ephemeral.

Where to look when it breaks

Symptom Read
No audio troubleshooting-voice.md, audio-ducking.md
Caller hears silence after greet media-proxy logs; check ai-orchestrator pipeline state
Translation cuts in/out troubleshooting-translation.md
Transfer fails warm-handoff.md
502 on register vanguard-nginx-ingress — Janus WS header strip

See also