Skip to content

Chat request lifecycle

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

What happens when a user types in surface-app (or another chat client) instead of placing a call. Same agent config, no audio path.

The path

Browser / surface-app
  │ POST /api/conversations/:id/messages
  ▼
conversation-api          (HTTP :8080, gRPC :1234)
  │ start or resume conversation
  ▼
ai-orchestrator           (text-mode pipeline; no STT/TTS stages)
  │ LLM → tool calls
  ▼
agent-host                ←→ tools and integrations
  │ messages back via SSE
  ▼
surface-app               (renders A2UI components inline)

The reverse path is server-sent events from conversation-api to the surface, carrying:

  • Assistant text deltas.
  • Tool-call lifecycle frames.
  • A2UI component descriptors (rendered by multimodal-service on the client).
  • Conversation lifecycle events (start, end, transfer).

Per-hop responsibility

surface-app

Next.js front-end at apps/surface-app. For chat agents, opens a long-lived SSE connection to conversation-api and POSTs user messages over plain HTTP. Identity comes from the surface_session cookie.

Connects to conversation-api at CONVERSATION_API_URL. This must point at port 8080 (HTTP) — not 8000 (async-agent). Pointing at the wrong port silently breaks A2UI rendering via SSE reconnect storms; see the agent memory entry for surface-app-conversation-api-port.

conversation-api

Python FastAPI at apps/conversation-api. Owns the conversation lifecycle: creating sessions, persisting messages, brokering between chat clients and the orchestrator, recording transcripts and recordings.

Two surfaces:

  • HTTP :8080 — REST + SSE for surface clients.
  • gRPC :1234 — ai-orchestrator calls in to publish events and pull config.

ai-orchestrator (text mode)

Same service that runs voice pipelines. When the agent's agent_versions.config declares a chat subtype, the universal builder constructs a pipeline without STT or TTS stages. The LLM and tool stages are identical.

For agent_type=text_chat, A2UI is always-on with no permission prompts (see agent memory a2ui-chat-no-handshake).

agent-host

Same MCP tool server used by voice. The pipeline does not change.

State

Layer Where state lives Lifetime
Session conversation-api in-memory + Redis cache Session timeout
Transcript conversation_messages Forever
SSE connection conversation-api connection registry While the client is connected
Tool state agent-host Tool-defined

Where chat differs from voice

  • No media-proxy, asterisk, kamailio, ari-controller, or janus.
  • Latency budget is different: chat tolerates 1–2s LLM round-trips; voice does not.
  • Tools that emit audio are no-ops in chat mode.
  • A2UI is always-on for chat agents (no audio handshake to negotiate).
  • Recordings are the transcript itself, not an audio file.

See also