-
-
Notifications
You must be signed in to change notification settings - Fork 0
WebSocket Protocol
The WebSocket connection provides real-time bidirectional communication between clients and the Cass backend. It handles chat messages, status updates, tool execution, and audio delivery.
ws://localhost:8000/ws
Two authentication methods:
Query Parameter (preferred):
ws://localhost:8000/ws?token=<jwt_access_token>
First Message:
{
"type": "auth",
"token": "<jwt_access_token>"
}Localhost Bypass:
Connections from 127.0.0.1, ::1, or localhost automatically use DEFAULT_LOCALHOST_USER_ID if ALLOW_LOCALHOST_BYPASS=true (default).
On successful connection:
{
"type": "connected",
"message": "Cass vessel connected",
"sdk_mode": true,
"user_id": "user-uuid-here",
"timestamp": "2025-12-09T10:00:00"
}Send a message to Cass:
{
"type": "chat",
"message": "Hello Cass!",
"conversation_id": "conv-uuid",
"image": "base64-encoded-data",
"image_media_type": "image/png"
}| Field | Required | Description |
|---|---|---|
| message | Yes | The user's message text |
| conversation_id | No | Conversation to continue (creates new if omitted) |
| image | No | Base64-encoded image data |
| image_media_type | No | MIME type (e.g., "image/png") |
Authenticate after connection:
{
"type": "auth",
"token": "jwt_token_here"
}Trigger onboarding introduction:
{
"type": "onboarding_intro",
"user_id": "user-uuid",
"profile": {
"display_name": "Name",
"relationship": "researcher"
}
}Trigger collaborative demo:
{
"type": "onboarding_demo",
"user_id": "user-uuid",
"message": "optional response",
"profile": {
"relationship": "researcher",
"background": {"context": "..."},
"communication": {"style": "..."}
}
}Connection established:
{
"type": "connected",
"message": "Cass vessel connected",
"sdk_mode": true,
"user_id": "user-uuid",
"timestamp": "2025-12-09T10:00:00"
}Authentication successful:
{
"type": "auth_success",
"user_id": "user-uuid"
}Authentication failed:
{
"type": "auth_error",
"message": "Invalid token"
}Status update during processing:
{
"type": "thinking",
"status": "Retrieving memories...",
"memories": {
"summaries_count": 3,
"details_count": 5,
"project_docs_count": 2,
"user_context_count": 4,
"wiki_pages_count": 1,
"has_context": true
},
"timestamp": "2025-12-09T10:00:01"
}Status messages progress through:
- "Retrieving memories..."
- "Generating response (Claude/OpenAI/local model)..."
- "Using tool: [tool_name]..." (if tools used)
Cass's response:
{
"type": "response",
"text": "Hello! <gesture:wave>",
"animations": [
{"type": "gesture", "name": "wave", "position": 7}
],
"input_tokens": 1500,
"output_tokens": 150,
"provider": "anthropic",
"model": "claude-sonnet-4-20250514",
"conversation_id": "conv-uuid",
"timestamp": "2025-12-09T10:00:02"
}| Field | Description |
|---|---|
| text | Response text with gesture/emote tags |
| animations | Parsed gesture/emote data |
| input_tokens | Tokens used for input |
| output_tokens | Tokens generated |
| provider | "anthropic", "openai", or "local" |
| model | Specific model used |
| conversation_id | ID of the conversation |
TTS audio available:
{
"type": "audio",
"url": "/audio/abc123.wav",
"timestamp": "2025-12-09T10:00:03"
}System message:
{
"type": "system",
"message": "Memory summarization complete",
"timestamp": "2025-12-09T10:00:04"
}Conversation title changed:
{
"type": "title_update",
"conversation_id": "conv-uuid",
"title": "New conversation title",
"timestamp": "2025-12-09T10:00:05"
}Debug information (development):
{
"type": "debug",
"message": "[Tool Loop #1] stop_reason=tool_use, tools=['recall_journal']",
"timestamp": "2025-12-09T10:00:06"
}Error occurred:
{
"type": "error",
"message": "Failed to generate response",
"timestamp": "2025-12-09T10:00:07"
}Client Server
| |
|-- chat (message) ------------>|
| |
|<-- thinking (memories) -------|
|<-- thinking (generating) -----|
| |
|<-- response -----------------|
|<-- audio (optional) ----------|
Client Server
| |
|-- chat (message) ------------>|
| |
|<-- thinking (memories) -------|
|<-- thinking (generating) -----|
|<-- thinking (using tool) -----|
|<-- debug (tool loop) ---------|
|<-- thinking (continuing) -----|
| |
|<-- response -----------------|
When Cass uses tools, the server loops:
- LLM returns
stop_reason: "tool_use" - Server executes requested tool(s)
- Server sends tool results back to LLM
- LLM generates next response (may use more tools)
- Repeat until
stop_reason: "end_turn"
For each chat message, the server builds context:
- Hierarchical Memory - Summaries and recent details
- User Context - Profile and observations for the user
- Project Context - Documents if conversation is in a project
- Self-Model - Cass's self-observations
- Wiki Context - Auto-injected relevant wiki pages
Context is formatted and prepended to the conversation.
The server maintains active connections:
class ConnectionManager:
active_connections: List[WebSocket]
connection_users: Dict[WebSocket, str] # websocket -> user_idOn WebSocketDisconnect, the connection is removed:
except WebSocketDisconnect:
manager.disconnect(websocket)The WebSocket supports multiple LLM providers:
| Provider | Variable | Description |
|---|---|---|
anthropic |
Claude | Anthropic Claude models |
openai |
OpenAI | OpenAI GPT models |
local |
Ollama | Local Ollama models |
Provider is selected via:
-
/llmTUI command -
Ctrl+OTUI shortcut - API endpoint
Response includes provider and model fields.
Images can be sent with messages:
{
"type": "chat",
"message": "What's in this image?",
"image": "base64-encoded-image-data",
"image_media_type": "image/png"
}The image is passed to the LLM for multimodal understanding.
Errors are sent as error type messages:
{
"type": "error",
"message": "Detailed error message"
}Common errors:
- Authentication failures
- LLM API errors
- Tool execution failures
- User not found
-
backend/main_sdk.py:4799-5830- WebSocket endpoint -
backend/main_sdk.py:4799-4830- ConnectionManager class -
tui-frontend/tui.py- TUI WebSocket client -
backend/auth.py- Token handling