WebSocket
Full-duplex WebSocket protocol for per-session agents.
Connecting#
const ws = new WebSocket("ws://localhost:9002/ws")
// or: ws://localhost:9002/ws for standalone bridgeRegistration#
After connecting, register your agent:
{"type": "register", "name": "my-app.relay"}Response:
{"type": "registered", "name": "my-app.relay", "peer_id": "12D3KooW..."}The bridge spawns a full AgentNode for your session. It stays alive until you disconnect.
Client → Bridge messages#
| Type | Fields | Description |
|---|---|---|
register | name, relay? | Register agent identity |
send | to, message_type, payload, metadata? | Send direct message |
call | to, method, payload?, correlation_id? | RPC call |
call_response | correlation_id, success, payload?, error? | Respond to inbound RPC |
broadcast | topic, message_type, payload | Broadcast to topic |
subscribe | topic | Subscribe to pub/sub topic |
unsubscribe | topic | Unsubscribe from topic |
resolve | name | Resolve name to PeerId |
ping | — | Keepalive |
Bridge → Client messages#
| Type | Fields | Description |
|---|---|---|
registered | name, peer_id | Registration confirmed |
sent | to, message_id | Message sent |
call_result | correlation_id, success, payload, error | RPC response |
resolved | name, peer_id | Name resolution result |
message | from_name, from_peer_id, message_type, payload, metadata, timestamp_ms | Inbound message |
inbound_call | correlation_id, from_name, method, payload | Inbound RPC (respond with call_response) |
broadcast_message | topic, from_name, message_type, payload, metadata, timestamp_ms | Inbound broadcast |
subscribed | topic | Subscription confirmed |
error | code, message | Error |
pong | — | Keepalive response |
Example: JavaScript#
const ws = new WebSocket("ws://localhost:9002/ws")
ws.onopen = () => {
ws.send(JSON.stringify({ type: "register", name: "browser-agent.relay" }))
}
ws.onmessage = (event) => {
const msg = JSON.parse(event.data)
switch (msg.type) {
case "registered":
console.log(`connected as ${msg.name} (${msg.peer_id})`)
ws.send(JSON.stringify({
type: "subscribe",
topic: "updates.*"
}))
break
case "broadcast_message":
console.log(`[${msg.topic}] ${msg.from_name}: ${msg.payload}`)
break
case "inbound_call":
ws.send(JSON.stringify({
type: "call_response",
correlation_id: msg.correlation_id,
success: true,
payload: "handled"
}))
break
}
}Inbound RPC flow#
When another agent calls your WebSocket agent:
- Bridge receives the RPC via P2P
- Bridge sends
inbound_callto your WebSocket - You respond with
call_response(matchingcorrelation_id) - Bridge sends the P2P response back to the caller
Timeout: 30 seconds. If you don't respond, the caller gets a timeout error.
Session lifecycle#
- Client connects to
/ws - Client sends
register→ bridge spawnsAgentNode - Bridge installs message forwarder and RPC handler
- All messages route through the session's agent
- On disconnect →
AgentNodeis dropped, name expires