mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-22 22:41:13 +00:00
* feat(browser): add copilot security contracts * fix(gateway): expose verified client identity to handlers * feat(browser): add secure per-tab copilot panel Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * refactor(browser): separate copilot gateway hint custody * fix(browser): preserve legacy pairing parse shape * fix(browser): harden copilot lifecycle custody Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * fix(browser): enforce copilot lifecycle boundaries Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * style(browser): format copilot sources Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * fix(browser): preserve copilot consent revocation Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * refactor(browser): split copilot custody owners Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * test(browser): normalize websocket array buffers Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * chore(protocol): regenerate Swift gateway models Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * refactor(browser): model copilot runtime entrypoints Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * fix(browser): honor extension build boundaries Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * test(gateway): assert targeted chat delivery Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * test(gateway): cover targeted delivery calls Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * fix(browser): declare copilot build dependencies Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * fix(ci): clear browser copilot gate failures Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * test(ci): cover copilot lint exclusion Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * fix(browser): gate copilot on relay custody Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> * test(browser): bound copilot relay frames Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com> --------- Co-authored-by: Cameron Beeley <cameron.beeley@gmail.com>
67 lines
2.9 KiB
TypeScript
67 lines
2.9 KiB
TypeScript
// Gateway node session runtime factory.
|
|
// Creates node registry, subscription, and voice-wake fanout state.
|
|
import {
|
|
NodeRegistry,
|
|
type NodeRegistryOptions,
|
|
type SerializedEventPayload,
|
|
} from "./node-registry.js";
|
|
import type {
|
|
SessionEventSubscriberRegistry,
|
|
SessionMessageSubscriberRegistry,
|
|
} from "./server-chat-state.js";
|
|
import { createNodeSubscriptionManager } from "./server-node-subscriptions.js";
|
|
import { hasConnectedTalkNode } from "./server-talk-nodes.js";
|
|
|
|
// Node session runtime owns connected node registry state, session event
|
|
// subscriptions, and voice-wake fanout helpers for the gateway process.
|
|
/** Creates node registry/subscription runtime state for a gateway server. */
|
|
export function createGatewayNodeSessionRuntime(params: {
|
|
broadcast: (event: string, payload: unknown, opts?: { dropIfSlow?: boolean }) => void;
|
|
listRegisteredNodePluginToolCommands?: NodeRegistryOptions["listRegisteredNodePluginToolCommands"];
|
|
nodePluginToolsEnabled?: boolean;
|
|
nodeSkillsEnabled?: boolean;
|
|
sessionEventSubscribers: SessionEventSubscriberRegistry;
|
|
sessionMessageSubscribers: SessionMessageSubscriberRegistry;
|
|
}) {
|
|
const nodeRegistry = new NodeRegistry({
|
|
listRegisteredNodePluginToolCommands: params.listRegisteredNodePluginToolCommands,
|
|
nodePluginToolsEnabled: params.nodePluginToolsEnabled,
|
|
nodeSkillsEnabled: params.nodeSkillsEnabled,
|
|
});
|
|
const nodePresenceTimers = new Map<string, ReturnType<typeof setInterval>>();
|
|
const nodeSubscriptions = createNodeSubscriptionManager();
|
|
const sessionEventSubscribers = params.sessionEventSubscribers;
|
|
const sessionMessageSubscribers = params.sessionMessageSubscribers;
|
|
const nodeSendEvent = (opts: {
|
|
nodeId: string;
|
|
event: string;
|
|
payloadJSON?: SerializedEventPayload | null;
|
|
}) => {
|
|
nodeRegistry.sendEventRaw(opts.nodeId, opts.event, opts.payloadJSON ?? null);
|
|
};
|
|
// Session fanout goes through the subscription manager so node reconnects and
|
|
// explicit unsubscribes keep both node->session indexes in sync.
|
|
const nodeSendToSession = (sessionKey: string, event: string, payload: unknown) =>
|
|
nodeSubscriptions.sendToSession(sessionKey, event, payload, nodeSendEvent);
|
|
const nodeSendToAllSubscribed = (event: string, payload: unknown) =>
|
|
nodeSubscriptions.sendToAllSubscribed(event, payload, nodeSendEvent);
|
|
const broadcastVoiceWakeChanged = (triggers: string[]) => {
|
|
params.broadcast("voicewake.changed", { triggers }, { dropIfSlow: true });
|
|
};
|
|
const hasTalkNodeConnected = () => hasConnectedTalkNode(nodeRegistry);
|
|
|
|
return {
|
|
nodeRegistry,
|
|
nodePresenceTimers,
|
|
sessionEventSubscribers,
|
|
sessionMessageSubscribers,
|
|
nodeSendToSession,
|
|
nodeSendToAllSubscribed,
|
|
nodeSubscribe: nodeSubscriptions.subscribe,
|
|
nodeUnsubscribe: nodeSubscriptions.unsubscribe,
|
|
nodeUnsubscribeAll: nodeSubscriptions.unsubscribeAll,
|
|
broadcastVoiceWakeChanged,
|
|
hasTalkNodeConnected,
|
|
};
|
|
}
|