Skip to content

Commit f85806b

Browse files
committed
fix: filter gateway node list locally
1 parent cb4fc58 commit f85806b

2 files changed

Lines changed: 36 additions & 4 deletions

File tree

src/gateway/server-plugins.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,29 @@ describe("loadGatewayPlugins", () => {
526526
expect(typeof subagent?.getSession).toBe("function");
527527
});
528528

529+
test("filters connected plugin nodes locally without sending unsupported node.list params", async () => {
530+
loadOpenClawPlugins.mockReturnValue(createRegistry([]));
531+
loadGatewayStartupPluginsForTest();
532+
serverPluginsModule.setFallbackGatewayContext(createTestContext("nodes-list-filter"));
533+
handleGatewayRequest.mockImplementationOnce(async (opts: HandleGatewayRequestOptions) => {
534+
expect(opts.req.method).toBe("node.list");
535+
opts.respond(true, {
536+
nodes: [
537+
{ nodeId: "connected", connected: true },
538+
{ nodeId: "offline", connected: false },
539+
],
540+
});
541+
});
542+
543+
const runtime = runtimeModule.createPluginRuntime({
544+
allowGatewaySubagentBinding: true,
545+
});
546+
const result = await runtime.nodes.list({ connected: true });
547+
548+
expect(getLastDispatchedParams()).toEqual({});
549+
expect(result.nodes).toEqual([{ nodeId: "connected", connected: true }]);
550+
});
551+
529552
test("forwards provider and model overrides when the request scope is authorized", async () => {
530553
const serverPlugins = serverPluginsModule;
531554
const runtime = await createSubagentRuntime(serverPlugins);

src/gateway/server-plugins.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,20 @@ export function createGatewaySubagentRuntime(): PluginRuntime["subagent"] {
388388
export function createGatewayNodesRuntime(): PluginRuntime["nodes"] {
389389
return {
390390
async list(params) {
391-
const payload = await dispatchGatewayMethod<{ nodes?: unknown[] }>("node.list", {
392-
...(params?.connected === true && { connected: true }),
393-
});
391+
const payload = await dispatchGatewayMethod<{ nodes?: unknown[] }>("node.list", {});
394392
const nodes = Array.isArray(payload?.nodes) ? payload.nodes : [];
395-
return { nodes: nodes as Awaited<ReturnType<PluginRuntime["nodes"]["list"]>>["nodes"] };
393+
const filteredNodes =
394+
params?.connected === true
395+
? nodes.filter(
396+
(node) =>
397+
node !== null &&
398+
typeof node === "object" &&
399+
(node as { connected?: unknown }).connected === true,
400+
)
401+
: nodes;
402+
return {
403+
nodes: filteredNodes as Awaited<ReturnType<PluginRuntime["nodes"]["list"]>>["nodes"],
404+
};
396405
},
397406
async invoke(params) {
398407
const payload = await dispatchGatewayMethod<unknown>("node.invoke", {

0 commit comments

Comments
 (0)