From d013f8c88e49f3abaf6cb96c82a0fa6db4bd401b Mon Sep 17 00:00:00 2001 From: iamlukethedev Date: Wed, 8 Apr 2026 19:38:51 -0500 Subject: [PATCH] fix(gateway): use control-ui identity for managed openclaw sessions. Present managed OpenClaw connections as control-ui sessions instead of webchat sessions so the upstream gateway preserves operator scopes for the Claw3D server proxy. Made-with: Cursor --- src/lib/gateway/GatewayClient.ts | 6 ++---- src/lib/gateway/openclaw/GatewayBrowserClient.ts | 15 +++++++++++++-- tests/unit/useGatewayConnection.test.ts | 8 ++++---- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/lib/gateway/GatewayClient.ts b/src/lib/gateway/GatewayClient.ts index eb8b241..511b575 100644 --- a/src/lib/gateway/GatewayClient.ts +++ b/src/lib/gateway/GatewayClient.ts @@ -119,7 +119,6 @@ const DEFAULT_CUSTOM_RUNTIME_URL = "http://localhost:7770"; const INITIAL_AUTO_CONNECT_DELAY_MS = 900; const INITIAL_CONNECT_RETRY_DELAY_MS = 1_200; const OPENCLAW_CONTROL_UI_CLIENT_ID = "openclaw-control-ui"; -const OPENCLAW_WEBCHAT_UI_CLIENT_ID = "webchat-ui"; const isAutoManagedAdapter = (adapterType: StudioGatewayAdapterType) => adapterType !== "custom"; @@ -128,12 +127,11 @@ export const resolveGatewayClientName = ( adapterType: StudioGatewayAdapterType, gatewayUrl: string ) => { + void gatewayUrl; if (adapterType !== "openclaw") { return OPENCLAW_CONTROL_UI_CLIENT_ID; } - return isLocalGatewayUrl(gatewayUrl) - ? OPENCLAW_CONTROL_UI_CLIENT_ID - : OPENCLAW_WEBCHAT_UI_CLIENT_ID; + return OPENCLAW_CONTROL_UI_CLIENT_ID; }; export const resolveGatewayDisableDeviceAuth = ( diff --git a/src/lib/gateway/openclaw/GatewayBrowserClient.ts b/src/lib/gateway/openclaw/GatewayBrowserClient.ts index 6c3c328..fd44722 100644 --- a/src/lib/gateway/openclaw/GatewayBrowserClient.ts +++ b/src/lib/gateway/openclaw/GatewayBrowserClient.ts @@ -27,8 +27,15 @@ const GATEWAY_CLIENT_NAMES = { const GATEWAY_CLIENT_MODES = { WEBCHAT: "webchat", + UI: "ui", } as const; +function resolveDefaultClientMode(clientName?: string): string { + return clientName === GATEWAY_CLIENT_NAMES.CONTROL_UI + ? GATEWAY_CLIENT_MODES.UI + : GATEWAY_CLIENT_MODES.WEBCHAT; +} + type CryptoLike = { randomUUID?: (() => string) | undefined; getRandomValues?: ((array: Uint8Array) => Uint8Array) | undefined; @@ -546,7 +553,9 @@ export class GatewayBrowserClient { const payload = buildDeviceAuthPayload({ deviceId: deviceIdentity.deviceId, clientId: this.opts.clientName ?? GATEWAY_CLIENT_NAMES.CONTROL_UI, - clientMode: this.opts.mode ?? GATEWAY_CLIENT_MODES.WEBCHAT, + clientMode: + this.opts.mode ?? + resolveDefaultClientMode(this.opts.clientName ?? GATEWAY_CLIENT_NAMES.CONTROL_UI), role, scopes, signedAtMs, @@ -569,7 +578,9 @@ export class GatewayBrowserClient { id: this.opts.clientName ?? GATEWAY_CLIENT_NAMES.CONTROL_UI, version: this.opts.clientVersion ?? "dev", platform: this.opts.platform ?? navigator.platform ?? "web", - mode: this.opts.mode ?? GATEWAY_CLIENT_MODES.WEBCHAT, + mode: + this.opts.mode ?? + resolveDefaultClientMode(this.opts.clientName ?? GATEWAY_CLIENT_NAMES.CONTROL_UI), instanceId: this.opts.instanceId, }, role, diff --git a/tests/unit/useGatewayConnection.test.ts b/tests/unit/useGatewayConnection.test.ts index 327b035..97abaf0 100644 --- a/tests/unit/useGatewayConnection.test.ts +++ b/tests/unit/useGatewayConnection.test.ts @@ -199,7 +199,7 @@ describe("useGatewayConnection", () => { expect(captured.clientName).toBe("openclaw-control-ui"); }); - it("uses_webchat_identity_for_remote_openclaw_connections", async () => { + it("uses_control_ui_identity_for_remote_openclaw_connections", async () => { const { useGatewayConnection, captured } = await setupAndImportHook(null); const coordinator = { loadSettings: async () => null, @@ -242,7 +242,7 @@ describe("useGatewayConnection", () => { expect(captured.url).toBe("ws://localhost:3000/api/gateway/ws"); }); expect(captured.authScopeKey).toBe("wss://pi5.myth-coho.ts.net"); - expect(captured.clientName).toBe("webchat-ui"); + expect(captured.clientName).toBe("openclaw-control-ui"); expect(captured.disableDeviceAuth).toBe(true); }); @@ -362,10 +362,10 @@ describe("useGatewayConnection", () => { expect(mod.resolveInitialGatewayConnectAttemptCount("openclaw", true)).toBe(1); }); - it("uses_webchat_client_id_only_for_remote_openclaw", async () => { + it("uses_control_ui_client_id_for_openclaw_connections", async () => { const mod = await import("@/lib/gateway/GatewayClient"); expect(mod.resolveGatewayClientName("openclaw", "wss://pi5.myth-coho.ts.net")).toBe( - "webchat-ui" + "openclaw-control-ui" ); expect(mod.resolveGatewayClientName("openclaw", "ws://localhost:18789")).toBe( "openclaw-control-ui"