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-orchestratorcalls 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.