mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-03 09:13:30 +00:00
- docs: device.pair.update and the `permanent` option on approve in docs/04-gateway-protocol.md, docs/19-websocket-rpc.md and websocket-protocol.md; the paired-device TTL row in docs/09-security.md now mentions the admin opt-out. - store.ErrPairedDeviceNotFound: SetPairingPermanent wraps it in both stores. device.pair.update maps it to NOT_FOUND and any other store error to INTERNAL, so a DB failure no longer reads as "not found". - web UI: approve and make-permanent/set-expiry now toast the server error and reload the list in `finally`. A partially applied approve (paired, but the permanent write failed) shows up in the table instead of leaving the dialog dead-ended. - SQLite ListPaired: a stored expiry that fails to parse stays 0 (expires, date unknown) rather than being mistaken for permanent; the UI renders it as "--" instead of a 1970 date. Tests: gateway handler error mapping (NOT_FOUND / INTERNAL / OK), sentinel checks in the PG and SQLite store tests, SQLite unreadable-expiry case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2.7 KiB
2.7 KiB
WebSocket Protocol (v3)
Frame types: req (client request), res (server response), event (server push).
Authentication
The first request must be a connect handshake. Authentication supports three paths:
// Path 1: Token-based (admin role)
{"type": "req", "id": 1, "method": "connect", "params": {"token": "your-gateway-token", "user_id": "alice"}}
// Path 2: Browser pairing reconnect (operator role)
{"type": "req", "id": 1, "method": "connect", "params": {"sender_id": "previously-paired-id", "user_id": "alice"}}
// Path 3: No token — initiates browser pairing flow (returns pairing code)
{"type": "req", "id": 1, "method": "connect", "params": {"user_id": "alice"}}
Methods
| Method | Description |
|---|---|
connect |
Authentication handshake (must be first request) |
health |
Server health check |
status |
Server status and metadata |
chat.send |
Send a message to an agent |
chat.history |
Retrieve session history |
chat.abort |
Abort a running agent request |
agent |
Get agent info |
sessions.list |
List active sessions |
sessions.delete |
Delete a session |
sessions.label |
Label a session |
skills.list |
List available skills |
cron.list |
List scheduled jobs |
cron.create |
Create a cron job |
cron.delete |
Delete a cron job |
cron.toggle |
Enable/disable a cron job |
models.list |
List available AI models |
browser.pairing.status |
Poll pairing approval status |
device.pair.request |
Request device pairing |
device.pair.approve |
Approve a pairing code |
device.pair.list |
List pending and approved pairings |
device.pair.revoke |
Revoke a pairing |
device.pair.update |
Make a pairing permanent or restore the default TTL |
Events (server push)
| Event | Description |
|---|---|
chunk |
Streaming token from LLM (payload: {content}) |
tool.call |
Agent invoking a tool (payload: {name, id}) |
tool.result |
Tool execution result |
run.started |
Agent started processing |
run.completed |
Agent finished processing |
shutdown |
Server shutting down |
Frame Format
Request (client to server)
{
"type": "req",
"id": "unique-request-id",
"method": "chat.send",
"params": { ... }
}
Response (server to client)
{
"type": "res",
"id": "matching-request-id",
"ok": true,
"payload": { ... }
}
Error Response
{
"type": "res",
"id": "matching-request-id",
"ok": false,
"error": {
"code": "error_code",
"message": "Human-readable error message"
}
}
Event (server push)
{
"type": "event",
"event": "chunk",
"payload": { "content": "streaming text..." }
}