Skip to main content

WebSocket Protocol Reference

The chat uses a WebSocket connection at /ws/chat.

Connection

ws://localhost:8000/ws/chat?visitor_id=<uuid>&turnstile_token=<token>
ParameterRequiredDescription
visitor_idNoPersistent visitor identifier. Used to resume sessions. Defaults to "anonymous"
turnstile_tokenIf Turnstile enabledCloudflare 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

  1. Connect — Server verifies Turnstile (if enabled), creates or resumes a ChatSession, sends greeting
  2. Message exchange — Client sends messages, server responds with text + optional A2UI
  3. Rate limiting — After SESSION_MESSAGE_LIMIT messages, server responds with an error
  4. Disconnect — Session remains in DB for potential resumption via same visitor_id