diff --git a/ui/src/ui/app-gateway.ts b/ui/src/ui/app-gateway.ts index b2355709c..438aa5d62 100644 --- a/ui/src/ui/app-gateway.ts +++ b/ui/src/ui/app-gateway.ts @@ -4,6 +4,7 @@ import { loadNodes } from "./controllers/nodes"; import { loadAgents } from "./controllers/agents"; import type { GatewayEventFrame, GatewayHelloOk } from "./gateway"; import { GatewayBrowserClient } from "./gateway"; +import { GATEWAY_CLIENT_NAMES } from "../../../src/gateway/protocol/client-info.js"; import type { EventLogEntry } from "./app-events"; import type { AgentsListResult, PresenceEntry, HealthSnapshot, StatusSummary } from "./types"; import type { Tab } from "./navigation"; @@ -116,11 +117,14 @@ export function connectGateway(host: GatewayHost) { host.execApprovalError = null; host.client?.stop(); + const clientName = + host.tab === "public-chat" ? GATEWAY_CLIENT_NAMES.WEBCHAT_UI : "moltbot-control-ui"; + host.client = new GatewayBrowserClient({ url: host.settings.gatewayUrl, token: host.settings.token.trim() ? host.settings.token : undefined, password: host.password.trim() ? host.password : undefined, - clientName: "moltbot-control-ui", + clientName, mode: "webchat", onHello: (hello) => { host.connected = true; diff --git a/ui/src/ui/gateway.ts b/ui/src/ui/gateway.ts index fc8dde08a..ab6a5ae66 100644 --- a/ui/src/ui/gateway.ts +++ b/ui/src/ui/gateway.ts @@ -53,6 +53,15 @@ export type GatewayBrowserClientOptions = { platform?: string; mode?: GatewayClientMode; instanceId?: string; + + /** + * Gateway role/scopes for this client. + * Control UI defaults to operator + admin scopes. + * Public WebChat will override this in a follow-up PR once the gateway enforces role allowlists. + */ + role?: string; + scopes?: string[]; + onHello?: (hello: GatewayHelloOk) => void; onEvent?: (evt: GatewayEventFrame) => void; onClose?: (info: { code: number; reason: string }) => void; @@ -132,8 +141,9 @@ export class GatewayBrowserClient { // Gateways may reject this unless gateway.controlUi.allowInsecureAuth is enabled. const isSecureContext = typeof crypto !== "undefined" && !!crypto.subtle; - const scopes = ["operator.admin", "operator.approvals", "operator.pairing"]; - const role = "operator"; + const scopes = + this.opts.scopes ?? ["operator.admin", "operator.approvals", "operator.pairing"]; + const role = this.opts.role ?? "operator"; let deviceIdentity: Awaited> | null = null; let canFallbackToShared = false; let authToken = this.opts.token;