SNA

WebSocket プロトコル

Request/response op、push チャネル、再接続ルールを整理します。

WebSocket はライブチャネルです。push イベント (assistant delta、ツール 呼び出し、権限要求) と、HTTP API が露出するのと同じ制御 op を、 呼び出しごとの HTTP オーバーヘッドなしで運びます。

エンドポイント

ws://<host>:<port>/ws

クライアントは一度接続して、その単一接続上にすべてのセッションを 多重化します。

認証

WebSocket upgrade は保護された HTTP ルートと同じトークンを要求します。 Browser client は任意の upgrade header を設定できないため、TypeScript client はトークンを ws://<host>:<port>/ws?token=<authToken> として送ります。 Native client は upgrade request に Authorization: Bearer <authToken> または X-SNA-Token を使うこともできます。

サーバに origin allowlist がある場合、browser WebSocket 接続は許可された Origin から来る必要があります。トークン失敗は upgrade を 401 で閉じ、 origin 失敗は 403 で閉じます。

ワイヤ形

すべてのメッセージは type と payload を持つ JSON オブジェクトです。

// Client → server
{ "id": "rpc-7", "type": "agent.send", "payload": { "session": "abc", "message": "hi" } }

// Server → client (reply)
{ "id": "rpc-7", "type": "agent.send", "status": "ok", "data": { "queued": true } }

// Server → client (push, id なし)
{ "type": "agent.event", "data": { "session": "abc", "event": { "type": "assistant_delta", "delta": "Hello" } } }

id フィールドはクライアントが選ぶ相関トークンです。request/response ペアには付き、push メッセージには付きません。

制御 op

すべての HTTP ルートには対応する WS op があります:

WS typeHTTP 等価
agent.startPOST /agent/start
agent.sendPOST /agent/send
agent.interruptPOST /agent/interrupt
agent.set-modelPOST /agent/set-model
agent.set-permission-modePOST /agent/set-permission-mode
agent.restartPOST /agent/restart
agent.resumePOST /agent/resume
agent.killPOST /agent/kill
agent.run-oncePOST /agent/run-once
agent.completionPOST /agent/completion
agent.statusGET /agent/status
sessions.listGET /agent/sessions
sessions.createPOST /agent/sessions
sessions.updatePATCH /agent/sessions/:id
sessions.removeDELETE /agent/sessions/:id
permission.subscribe(push チャネル; HTTP 等価なし)
permission.respondPOST /agent/permission-respond

Push チャネル

2 つのチャネルは push 専用です:

  • agent.event: 購読中の全セッションが出す全 AgentEvent ごとに 発生します。agent.subscribe で購読し、agent.unsubscribe で解除します。
  • permission.request: どのセッションが permission_needed を emit しても発生します。permission.subscribe で購読します。

再接続

接続が切れたらクライアントは再接続して再購読する必要があります。切断中 にバッファされたイベントはセッションごとの ring buffer (デフォルト 1000 件) に残ります。新規 agent.subscribe?since=<cursor> を渡せば replay されます。

なぜ HTTP と WS の両方か

  • 順序と ACK には HTTP。 ミューテーションには推論しやすい request/response の契約が必要です。HTTP はこの契約を自然に提供します。
  • fanout には WS. 単一接続が N 個のセッションのイベント + 権限 要求を配ります。N 本の SSE ストリームを開くよりはるかに効率的です。

TypeScript クライアントはすべてのミューテーションに HTTP、push チャネルに WS を使います。片方だけでも動きます (http: true, ws: false は 短命スクリプト用; ws: true, http: false は HTTP が使えない クライアント用) が、実際のアプリでは両方使う構成が最も自然です。

目次