Files
hermes-agent/web/src/lib/gatewayClient.ts
Brooklyn Nicholson e9b95dfd19 fix(docker): include apps/shared in dashboard image build
The shared websocket package is a web file: dependency but was excluded
by .dockerignore and never copied into the Docker build context. Also fix
tsc -b errors: expose buildWsUrl on api and drop the GatewayClient state
getter that conflicted with the shared base class.
2026-06-28 21:43:56 -05:00

62 lines
1.9 KiB
TypeScript

/**
* Browser WebSocket client for the tui_gateway JSON-RPC protocol.
*
* Speaks the exact same newline-delimited JSON-RPC dialect that the Ink TUI
* drives over stdio. The server-side transport abstraction
* (tui_gateway/transport.py + ws.py) routes the same dispatcher's writes
* onto either stdout or a WebSocket depending on how the client connected.
*
* const gw = new GatewayClient()
* await gw.connect()
* const { session_id } = await gw.request<{ session_id: string }>("session.create")
* gw.on("message.delta", (ev) => console.log(ev.payload?.text))
* await gw.request("prompt.submit", { session_id, text: "hi" })
*/
import {
JsonRpcGatewayClient,
buildHermesWebSocketUrl,
type ConnectionState,
type GatewayEvent,
type GatewayEventName,
} from "@hermes/shared";
import { HERMES_BASE_PATH, buildWsAuthParam } from "@/lib/api";
export type { ConnectionState, GatewayEvent, GatewayEventName };
export class GatewayClient extends JsonRpcGatewayClient {
constructor() {
super({
closedErrorMessage: "WebSocket closed",
connectErrorMessage: "WebSocket connection failed",
notConnectedErrorMessage: "gateway not connected",
requestIdPrefix: "w",
});
}
async connect(token?: string): Promise<void> {
if (this.connectionState === "open" || this.connectionState === "connecting") {
return;
}
// Gated mode: legacy ``?token=`` is rejected by ``_ws_auth_ok``; the SPA
// must fetch a single-use ticket. Explicit ``token`` keeps the test-only
// override path.
const authParam = token ? (["token", token] as const) : await buildWsAuthParam();
if (!authParam[1]) {
throw new Error(
"Session token not available — page must be served by the Hermes dashboard server",
);
}
await super.connect(
buildHermesWebSocketUrl({
authParam,
basePath: HERMES_BASE_PATH,
path: "/api/ws",
}),
);
}
}