WebSocket

WebSocket

Một socket, mọi lệnh REST dưới dạng frame, kể cả sự kiện stream. Hợp với trình duyệt và client kết nối lâu dài.

Kết nối và xác thực

Endpoint: ws://127.0.0.1:8765/ws. Trình duyệt không đặt được header cho WebSocket, nên frame đầu tiên dùng để xác thực:

Các frame

→ { "type": "auth", "token": "<token>" }
← { "type": "ready", "protocol": "clarkcant.ws.v1" }

→ { "type": "request", "id": "1", "method": "POST", "path": "/conversations/<conversationId>/messages/stream", "body": { "text": "hi" } }
← { "type": "event", "id": "1", "event": "delta", "data": { "text": "…" } }
← …
← { "type": "response", "id": "1", "status": 200, "body": null }

→ { "type": "ping" }
← { "type": "pong" }
FrameChiềuCấu trúc
authclient → node{ type, token }, chỉ ở frame đầu
readynode → client{ type, protocol: "clarkcant.ws.v1" }
requestclient → node{ type, id, method, path, query?, body? }: bất kỳ route REST nào, trừ các quyết định của con người (403 PERSON_ONLY); id được trả lại đúng như gửi, chuỗi hoặc số; tham số query đặt trong query, không đặt trong path
eventnode → client{ type, id, event, data }: mỗi sự kiện SSE một frame, trên các route stream
responsenode → client{ type, id, status, body }: luôn là frame cuối của id đó; body là null sau một stream
ping / pongcả hai{ "type": "ping" } → { "type": "pong" }

Ví dụ

const ws = new WebSocket("ws://127.0.0.1:8765/ws");

// Browsers cannot set headers on a WebSocket, so the first frame authenticates.
ws.onopen = () => ws.send(JSON.stringify({ type: "auth", token: "<token>" }));

ws.onmessage = (message) => {
  const frame = JSON.parse(message.data);
  if (frame.type === "ready") {
    ws.send(JSON.stringify({
      type: "request",
      id: "1",
      method: "POST",
      path: "/conversations/<conversationId>/messages/stream",
      body: { text: "hi" },
    }));
  }
  if (frame.type === "event" && frame.event === "delta") console.log(frame.data.text);
  if (frame.type === "response") console.log("finished", frame.id, frame.status);
};

ws.onclose = (event) => { if (event.code === 4401) console.log("token missing, wrong or too late"); };

Đừng nhúng token vào trang công khai. Ai giữ token là điều khiển được Clark của bạn. Chỉ dùng từ máy của bạn hoặc sau lớp đăng nhập của riêng bạn.

Các socket khác

Node còn phục vụ /voice (phiên giọng nói) và /terminal (thẻ Terminal). Đây là socket của ứng dụng, không phải giao diện tích hợp công khai hay một phần của giao thức frame này.