mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 12:21:24 +00:00
refactor: remove bridge protocol
This commit is contained in:
@@ -113,7 +113,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
removeChatRun: context.removeChatRun,
|
||||
agentRunSeq: context.agentRunSeq,
|
||||
broadcast: context.broadcast,
|
||||
bridgeSendToSession: context.bridgeSendToSession,
|
||||
nodeSendToSession: context.nodeSendToSession,
|
||||
};
|
||||
|
||||
if (!runId) {
|
||||
@@ -250,7 +250,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
removeChatRun: context.removeChatRun,
|
||||
agentRunSeq: context.agentRunSeq,
|
||||
broadcast: context.broadcast,
|
||||
bridgeSendToSession: context.bridgeSendToSession,
|
||||
nodeSendToSession: context.nodeSendToSession,
|
||||
},
|
||||
{ sessionKey: p.sessionKey, stopReason: "stop" },
|
||||
);
|
||||
@@ -451,7 +451,7 @@ export const chatHandlers: GatewayRequestHandlers = {
|
||||
message: transcriptEntry.message,
|
||||
};
|
||||
context.broadcast("chat", chatPayload);
|
||||
context.bridgeSendToSession(p.sessionKey, "chat", chatPayload);
|
||||
context.nodeSendToSession(p.sessionKey, "chat", chatPayload);
|
||||
|
||||
respond(true, { ok: true, messageId });
|
||||
},
|
||||
|
||||
@@ -167,11 +167,6 @@ export const execApprovalsHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const bridge = context.bridge;
|
||||
if (!bridge) {
|
||||
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "bridge not running"));
|
||||
return;
|
||||
}
|
||||
const { nodeId } = params as { nodeId: string };
|
||||
const id = nodeId.trim();
|
||||
if (!id) {
|
||||
@@ -179,10 +174,10 @@ export const execApprovalsHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const res = await bridge.invoke({
|
||||
const res = await context.nodeRegistry.invoke({
|
||||
nodeId: id,
|
||||
command: "system.execApprovals.get",
|
||||
paramsJSON: "{}",
|
||||
params: {},
|
||||
});
|
||||
if (!res.ok) {
|
||||
respond(
|
||||
@@ -194,7 +189,7 @@ export const execApprovalsHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const payload = safeParseJson(res.payloadJSON ?? null);
|
||||
const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;
|
||||
respond(true, payload, undefined);
|
||||
});
|
||||
},
|
||||
@@ -210,11 +205,6 @@ export const execApprovalsHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const bridge = context.bridge;
|
||||
if (!bridge) {
|
||||
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "bridge not running"));
|
||||
return;
|
||||
}
|
||||
const { nodeId, file, baseHash } = params as {
|
||||
nodeId: string;
|
||||
file: ExecApprovalsFile;
|
||||
@@ -226,10 +216,10 @@ export const execApprovalsHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const res = await bridge.invoke({
|
||||
const res = await context.nodeRegistry.invoke({
|
||||
nodeId: id,
|
||||
command: "system.execApprovals.set",
|
||||
paramsJSON: JSON.stringify({ file, baseHash }),
|
||||
params: { file, baseHash },
|
||||
});
|
||||
if (!res.ok) {
|
||||
respond(
|
||||
|
||||
@@ -6,11 +6,14 @@ import {
|
||||
requestNodePairing,
|
||||
verifyNodeToken,
|
||||
} from "../../infra/node-pairing.js";
|
||||
import { listDevicePairing } from "../../infra/device-pairing.js";
|
||||
import {
|
||||
ErrorCodes,
|
||||
errorShape,
|
||||
validateNodeDescribeParams,
|
||||
validateNodeEventParams,
|
||||
validateNodeInvokeParams,
|
||||
validateNodeInvokeResultParams,
|
||||
validateNodeListParams,
|
||||
validateNodePairApproveParams,
|
||||
validateNodePairListParams,
|
||||
@@ -201,9 +204,29 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const list = await listNodePairing();
|
||||
const pairedById = new Map(list.paired.map((n) => [n.nodeId, n]));
|
||||
const connected = context.bridge?.listConnected?.() ?? [];
|
||||
const list = await listDevicePairing();
|
||||
const pairedById = new Map(
|
||||
list.paired
|
||||
.filter((entry) => entry.role === "node")
|
||||
.map((entry) => [
|
||||
entry.deviceId,
|
||||
{
|
||||
nodeId: entry.deviceId,
|
||||
displayName: entry.displayName,
|
||||
platform: entry.platform,
|
||||
version: undefined,
|
||||
coreVersion: undefined,
|
||||
uiVersion: undefined,
|
||||
deviceFamily: undefined,
|
||||
modelIdentifier: undefined,
|
||||
remoteIp: entry.remoteIp,
|
||||
caps: [],
|
||||
commands: [],
|
||||
permissions: undefined,
|
||||
},
|
||||
]),
|
||||
);
|
||||
const connected = context.nodeRegistry.listConnected();
|
||||
const connectedById = new Map(connected.map((n) => [n.nodeId, n]));
|
||||
const nodeIds = new Set<string>([...pairedById.keys(), ...connectedById.keys()]);
|
||||
|
||||
@@ -260,9 +283,9 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const list = await listNodePairing();
|
||||
const paired = list.paired.find((n) => n.nodeId === id);
|
||||
const connected = context.bridge?.listConnected?.() ?? [];
|
||||
const list = await listDevicePairing();
|
||||
const paired = list.paired.find((n) => n.deviceId === id && n.role === "node");
|
||||
const connected = context.nodeRegistry.listConnected();
|
||||
const live = connected.find((n) => n.nodeId === id);
|
||||
|
||||
if (!paired && !live) {
|
||||
@@ -270,8 +293,8 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
return;
|
||||
}
|
||||
|
||||
const caps = uniqueSortedStrings([...(live?.caps ?? paired?.caps ?? [])]);
|
||||
const commands = uniqueSortedStrings([...(live?.commands ?? paired?.commands ?? [])]);
|
||||
const caps = uniqueSortedStrings([...(live?.caps ?? [])]);
|
||||
const commands = uniqueSortedStrings([...(live?.commands ?? [])]);
|
||||
|
||||
respond(
|
||||
true,
|
||||
@@ -280,15 +303,15 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
nodeId: id,
|
||||
displayName: live?.displayName ?? paired?.displayName,
|
||||
platform: live?.platform ?? paired?.platform,
|
||||
version: live?.version ?? paired?.version,
|
||||
coreVersion: live?.coreVersion ?? paired?.coreVersion,
|
||||
uiVersion: live?.uiVersion ?? paired?.uiVersion,
|
||||
deviceFamily: live?.deviceFamily ?? paired?.deviceFamily,
|
||||
modelIdentifier: live?.modelIdentifier ?? paired?.modelIdentifier,
|
||||
version: live?.version,
|
||||
coreVersion: live?.coreVersion,
|
||||
uiVersion: live?.uiVersion,
|
||||
deviceFamily: live?.deviceFamily,
|
||||
modelIdentifier: live?.modelIdentifier,
|
||||
remoteIp: live?.remoteIp ?? paired?.remoteIp,
|
||||
caps,
|
||||
commands,
|
||||
permissions: live?.permissions ?? paired?.permissions,
|
||||
permissions: live?.permissions,
|
||||
paired: Boolean(paired),
|
||||
connected: Boolean(live),
|
||||
},
|
||||
@@ -305,11 +328,6 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
});
|
||||
return;
|
||||
}
|
||||
const bridge = context.bridge;
|
||||
if (!bridge) {
|
||||
respond(false, undefined, errorShape(ErrorCodes.UNAVAILABLE, "bridge not running"));
|
||||
return;
|
||||
}
|
||||
const p = params as {
|
||||
nodeId: string;
|
||||
command: string;
|
||||
@@ -329,12 +347,12 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
}
|
||||
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const paramsJSON = "params" in p && p.params !== undefined ? JSON.stringify(p.params) : null;
|
||||
const res = await bridge.invoke({
|
||||
const res = await context.nodeRegistry.invoke({
|
||||
nodeId,
|
||||
command,
|
||||
paramsJSON,
|
||||
params: p.params,
|
||||
timeoutMs: p.timeoutMs,
|
||||
idempotencyKey: p.idempotencyKey,
|
||||
});
|
||||
if (!res.ok) {
|
||||
respond(
|
||||
@@ -346,7 +364,7 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const payload = safeParseJson(res.payloadJSON ?? null);
|
||||
const payload = res.payloadJSON ? safeParseJson(res.payloadJSON) : res.payload;
|
||||
respond(
|
||||
true,
|
||||
{
|
||||
@@ -360,4 +378,85 @@ export const nodeHandlers: GatewayRequestHandlers = {
|
||||
);
|
||||
});
|
||||
},
|
||||
"node.invoke.result": async ({ params, respond, context }) => {
|
||||
if (!validateNodeInvokeResultParams(params)) {
|
||||
respondInvalidParams({
|
||||
respond,
|
||||
method: "node.invoke.result",
|
||||
validator: validateNodeInvokeResultParams,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const p = params as {
|
||||
id: string;
|
||||
nodeId: string;
|
||||
ok: boolean;
|
||||
payload?: unknown;
|
||||
payloadJSON?: string | null;
|
||||
error?: { code?: string; message?: string } | null;
|
||||
};
|
||||
const ok = context.nodeRegistry.handleInvokeResult({
|
||||
id: p.id,
|
||||
nodeId: p.nodeId,
|
||||
ok: p.ok,
|
||||
payload: p.payload,
|
||||
payloadJSON: p.payloadJSON ?? null,
|
||||
error: p.error ?? null,
|
||||
});
|
||||
if (!ok) {
|
||||
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "unknown invoke id"));
|
||||
return;
|
||||
}
|
||||
respond(true, { ok: true }, undefined);
|
||||
},
|
||||
"node.event": async ({ params, respond, context }) => {
|
||||
if (!validateNodeEventParams(params)) {
|
||||
respondInvalidParams({
|
||||
respond,
|
||||
method: "node.event",
|
||||
validator: validateNodeEventParams,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const p = params as { event: string; payload?: unknown; payloadJSON?: string | null };
|
||||
const payloadJSON =
|
||||
typeof p.payloadJSON === "string"
|
||||
? p.payloadJSON
|
||||
: p.payload !== undefined
|
||||
? JSON.stringify(p.payload)
|
||||
: null;
|
||||
await respondUnavailableOnThrow(respond, async () => {
|
||||
const { handleNodeEvent } = await import("../server-node-events.js");
|
||||
const nodeContext = {
|
||||
deps: context.deps,
|
||||
broadcast: context.broadcast,
|
||||
nodeSendToSession: context.nodeSendToSession,
|
||||
nodeSubscribe: context.nodeSubscribe,
|
||||
nodeUnsubscribe: context.nodeUnsubscribe,
|
||||
broadcastVoiceWakeChanged: context.broadcastVoiceWakeChanged,
|
||||
addChatRun: context.addChatRun,
|
||||
removeChatRun: context.removeChatRun,
|
||||
chatAbortControllers: context.chatAbortControllers,
|
||||
chatAbortedRuns: context.chatAbortedRuns,
|
||||
chatRunBuffers: context.chatRunBuffers,
|
||||
chatDeltaSentAt: context.chatDeltaSentAt,
|
||||
dedupe: context.dedupe,
|
||||
agentRunSeq: context.agentRunSeq,
|
||||
getHealthCache: context.getHealthCache,
|
||||
refreshHealthSnapshot: context.refreshHealthSnapshot,
|
||||
loadGatewayModelCatalog: context.loadGatewayModelCatalog,
|
||||
logGateway: { warn: context.logGateway.warn },
|
||||
};
|
||||
await handleNodeEvent(
|
||||
nodeContext,
|
||||
"node",
|
||||
{
|
||||
type: "event",
|
||||
event: p.event,
|
||||
payloadJSON,
|
||||
},
|
||||
);
|
||||
respond(true, { ok: true }, undefined);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,9 +2,9 @@ import type { ModelCatalogEntry } from "../../agents/model-catalog.js";
|
||||
import type { createDefaultDeps } from "../../cli/deps.js";
|
||||
import type { HealthSummary } from "../../commands/health.js";
|
||||
import type { CronService } from "../../cron/service.js";
|
||||
import type { startNodeBridgeServer } from "../../infra/bridge/server.js";
|
||||
import type { WizardSession } from "../../wizard/session.js";
|
||||
import type { ChatAbortControllerEntry } from "../chat-abort.js";
|
||||
import type { NodeRegistry } from "../node-registry.js";
|
||||
import type { ConnectParams, ErrorShape, RequestFrame } from "../protocol/index.js";
|
||||
import type { ChannelRuntimeSnapshot } from "../server-channels.js";
|
||||
import type { DedupeEntry } from "../server-shared.js";
|
||||
@@ -39,9 +39,13 @@ export type GatewayRequestContext = {
|
||||
stateVersion?: { presence?: number; health?: number };
|
||||
},
|
||||
) => void;
|
||||
bridge: Awaited<ReturnType<typeof startNodeBridgeServer>> | null;
|
||||
bridgeSendToSession: (sessionKey: string, event: string, payload: unknown) => void;
|
||||
nodeSendToSession: (sessionKey: string, event: string, payload: unknown) => void;
|
||||
nodeSendToAllSubscribed: (event: string, payload: unknown) => void;
|
||||
nodeSubscribe: (nodeId: string, sessionKey: string) => void;
|
||||
nodeUnsubscribe: (nodeId: string, sessionKey: string) => void;
|
||||
nodeUnsubscribeAll: (nodeId: string) => void;
|
||||
hasConnectedMobileNode: () => boolean;
|
||||
nodeRegistry: NodeRegistry;
|
||||
agentRunSeq: Map<string, number>;
|
||||
chatAbortControllers: Map<string, ChatAbortControllerEntry>;
|
||||
chatAbortedRuns: Map<string, number>;
|
||||
|
||||
Reference in New Issue
Block a user