Skip to main content
The gateway handshake lets clients and servers agree on a protocol version, discover supported features, and recover from disconnects — all in one round trip.

Quick Start

1

Minimal hello

{
  "type": "hello",
  "agent_id": "assistant",
  "protocol_min": 1,
  "protocol_max": 1
}
2

Opt into capabilities

{
  "type": "hello",
  "agent_id": "assistant",
  "protocol_min": 1,
  "protocol_max": 1,
  "capabilities": ["streaming", "presence", "ack"]
}
3

Resume a session

{
  "type": "hello",
  "agent_id": "assistant",
  "protocol_min": 1,
  "protocol_max": 1,
  "session_id": "abc-123",
  "since": 42
}
After hello_ok, replayed events arrive as {"type": "replay", "event": …} before normal traffic resumes.

How It Works

Negotiated protocol version: min(client_max, GATEWAY_PROTOCOL_VERSION) where server version is 1 and minimum accepted client version is 1. Legacy joinjoined still works for existing clients. New clients should prefer hello.

HelloParams (client → server)

FieldTypeDefaultDescription
agent_idstrAgent to connect to
protocol_minintMinimum protocol version client supports
protocol_maxintMaximum protocol version client supports
capabilitiesList[str][]e.g. streaming, presence, ack
session_idOptional[str]NoneExisting session to resume
sinceOptional[int]NoneEvent cursor for replay
Legacy nested protocol: {min, max} is also accepted; missing values fall back to 1.

HelloResult (server → client, hello_ok)

FieldTypeDescription
protocolintNegotiated protocol version
featuresDict[str, List[str]]Supported methods and events
policyDict[str, int]max_payload, max_buffered_bytes, heartbeat_ms
session_idstrSession ID (new or resumed)
resumedboolTrue if an existing session was resumed
cursorintCurrent event cursor
Example success frame:
{
  "type": "hello_ok",
  "protocol": 1,
  "features": {"methods": ["message", "leave"], "events": ["message", "error", "token_stream"]},
  "policy": {"max_payload": 1048576, "max_buffered_bytes": 8388608, "heartbeat_ms": 30000},
  "session_id": "...",
  "resumed": false,
  "cursor": 0
}
Base methods: message, leave only (abort is not implemented). Base events: message, error.

HelloError (server → client, hello_error)

FieldTypeDescription
codeConnectErrorCodeStructured error code
messagestrHuman-readable explanation
next_actionOptional[str]Suggested next step

ConnectErrorCode

CodeMeaningTypical next_action
auth_requiredAuthentication required but missing
auth_unauthorizedInvalid credentials or wrong agent for sessionstart_new_session
protocol_unsupportedClient/server version mismatchupgrade_client or use_older_client
pairing_requiredClient must complete pairing firstpair_device
agent_not_foundUnknown agent_idcheck_agent_id

Capability Matrix

CapabilityEvents unlockedServer prerequisite
(none)message, error
streamingtoken_stream, tool_call_stream, stream_end
presencepresence_join, presence_leave, presence_updateserver has _presence_tracker
ackmessage_ack, message_nack, delivery_retryserver has _delivery_tracker
Events are advertised only if the client requested the matching capability.

Policy Limits

KeyDefaultDescription
max_payload1048576 (1 MB)Maximum message payload size
max_buffered_bytes8388608 (8 MB)Maximum buffered bytes per connection
heartbeat_ms30000Heartbeat interval (heartbeat_interval * 1000, default 30 s)
Clients should self-configure from the policy object in hello_ok.

Best Practices

Even when you only support version 1 today, send an explicit range so future servers can negotiate.
Requesting streaming without handling token_stream events wastes bandwidth and confuses clients.
Resume cleanly after disconnect and process replay envelopes before sending new messages.
Use structured ConnectErrorCode values for graceful UX instead of parsing free-text errors.

Gateway & Control Plane

Unified gateway architecture

Gateway Overview

WebSocket gateway features

Session Protocol

Session message format

Error Handling

Structured connection errors