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
This commit is contained in:
iamlukethedev
2026-04-08 19:38:51 -05:00
committed by iamlukethedev
parent e9d59ace84
commit d013f8c88e
3 changed files with 19 additions and 10 deletions
+2 -4
View File
@@ -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 = (
@@ -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,
+4 -4
View File
@@ -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"