WebSocket Protocol Reference
The chat uses a WebSocket connection at /ws/chat.
Connection
ws://localhost:8000/ws/chat?visitor_id=<uuid>&turnstile_token=<token>
| Parameter | Required | Description |
|---|---|---|
visitor_id | No | Persistent visitor identifier. Used to resume sessions. Defaults to "anonymous" |
turnstile_token | If Turnstile enabled | Cloudflare Turnstile verification token |
Server → Client messages
Greeting (on connect)
{
"type": "greeting",
"text": "Hey! How can I help?",
"quickActions": [
{"label": "About me", "action": "about"}
]
}
Response (to a user message)
{
"type": "response",
"text": "Here are your links:",
"a2ui": [
{"surfaceUpdate": {"surfaceId": "s1", "components": [...]}},
{"beginRendering": {"surfaceId": "s1", "root": "col1"}}
]
}
The a2ui field is optional — only present when the agent's tools rendered UI components.
Error
{
"type": "error",
"text": "Message limit reached for this session."
}
Client → Server messages
Text message
{"message": "What events do you have?"}
User action (from A2UI component interaction)
{
"userAction": {
"action": "rsvp",
"context": {"event_id": "abc-123"}
}
}
User actions are converted to natural-language descriptions for the agent:
[User clicked: rsvp. Context: {"event_id": "abc-123"}]
Session lifecycle
- Connect — Server verifies Turnstile (if enabled), creates or resumes a
ChatSession, sends greeting - Message exchange — Client sends messages, server responds with text + optional A2UI
- Rate limiting — After
SESSION_MESSAGE_LIMITmessages, server responds with an error - Disconnect — Session remains in DB for potential resumption via same
visitor_id