Skip to content

WebSocket Protocol

The chat widget communicates with the Durable Object via WebSocket.

Connection

GET /ws/:sessionId
Upgrade: websocket

The worker proxies the upgrade request to the Durable Object identified by sessionId.

Message Types

Client → Server (WSClientMessage)

typescript
type WSClientMessage =
  | { type: 'message'; text: string }       // Regular chat message
  | { type: 'quick_reply'; text: string }    // Quick reply button tap
  | { type: 'escalate'; name: string; email: string }  // Switch to live mode

Server → Client (WSServerMessage)

typescript
type WSServerMessage =
  | { type: 'message'; sender: 'visitor' | 'anshul'; text: string; timestamp: number }
  | { type: 'bot_message'; text: string; quickReplies?: string[] }
  | { type: 'session_started'; sessionId: string; mode: 'bot' | 'live' }
  | { type: 'session_ended'; reason: 'timeout' | 'closed' }
  | { type: 'request_info' }
  | { type: 'typing' }
  | { type: 'message_limit'; message: string }
  | { type: 'away'; message: string }
  | { type: 'error'; message: string }

Session Modes

Bot Mode

  1. On WebSocket connect, server sends session_started with mode: 'bot'
  2. Server sends bot_message with the knowledge base greeting
  3. Client sends message or quick_reply — server responds with bot_message
  4. Bot responses may include quickReplies array for suggested follow-ups
  5. Session times out after 10 minutes of inactivity

Live Mode

  1. Client sends escalate with name and email
  2. A Slack thread is created for the session
  3. Server switches mode to live
  4. Client message → posted to Slack thread
  5. Slack replies → relayed to client as message with sender: 'anshul'
  6. Session times out after 30 minutes of inactivity

Rate Limits

ConstraintValue
Per-message rate limit2 seconds between messages
Max message length2000 characters
Message limitEnforced via message_count in storage

Messages exceeding 2000 characters receive an error response before any processing.

Timeouts and Alarms

The Durable Object uses Cloudflare alarms for timeout management:

TimeoutDurationBehavior
Bot inactivity10 minutesSends session_ended with reason timeout
Live inactivity30 minutesSends session_ended with reason timeout
Away indicator5 minutesSends away message if Anshul hasn't replied

State Machine

         ┌───────────────────────┐
         │      CONNECTED        │
         │  mode: 'bot'          │
         │  (Gemini answers)     │
         └───────────┬───────────┘
                     │ escalate

         ┌───────────────────────┐
         │      CONNECTED        │
         │  mode: 'live'         │
         │  (Slack relay)        │
         └───────────┬───────────┘
                     │ timeout / close

         ┌───────────────────────┐
         │       ENDED           │
         │  session_ended sent   │
         └───────────────────────┘

Storage Keys (Durable Object)

KeyTypePurpose
session_stateSessionStateVisitor info, mode, Slack thread
last_visitor_messagenumberTimestamp for inactivity tracking
last_anshul_replynumberTimestamp for away indicator
last_unmatched_textstringLast bot question to forward on escalation
session_idstringSession identifier
conversation_historyConversationHistoryAI conversation context
message_countnumberTotal messages in session