diff --git a/src/agents/tools/nodes-tool-commands.ts b/src/agents/tools/nodes-tool-commands.ts index 5d615b530356..85de34c488b4 100644 --- a/src/agents/tools/nodes-tool-commands.ts +++ b/src/agents/tools/nodes-tool-commands.ts @@ -179,5 +179,7 @@ async function invokeNodeCommandPayload(params: { params: params.commandParams ?? {}, idempotencyKey: crypto.randomUUID(), }); - return raw?.payload ?? {}; + return raw && typeof raw === "object" && Object.hasOwn(raw, "payload") + ? raw.payload + : {}; } diff --git a/src/agents/tools/nodes-tool.test.ts b/src/agents/tools/nodes-tool.test.ts index 9c46e0ebd6ef..9a2cf4949da0 100644 --- a/src/agents/tools/nodes-tool.test.ts +++ b/src/agents/tools/nodes-tool.test.ts @@ -462,6 +462,19 @@ describe("createNodesTool screen_record duration guardrails", () => { }); }); + it("preserves explicit null location_get payloads from node.invoke", async () => { + gatewayMocks.callGatewayTool.mockResolvedValue({ payload: null }); + const tool = createNodesTool(); + + const result = await tool.execute("call-location-null", { + action: "location_get", + node: "macbook", + }); + + expect(result.details).toBeNull(); + expect(result.content).toEqual([{ type: "text", text: "null" }]); + }); + it("uses operator.pairing plus operator.admin to approve exec-capable node pair requests", async () => { mockNodePairApproveFlow({ requiredApproveScopes: ["operator.pairing", "operator.admin"],