diff --git a/src/agents/openclaw-tools.camera.test.ts b/src/agents/openclaw-tools.camera.test.ts index 96be774b297..b6d9e315656 100644 --- a/src/agents/openclaw-tools.camera.test.ts +++ b/src/agents/openclaw-tools.camera.test.ts @@ -174,6 +174,71 @@ describe("nodes notifications_list", () => { }); }); +describe("nodes device_status and device_info", () => { + it("invokes device.status and returns payload", async () => { + callGateway.mockImplementation(async ({ method, params }) => { + if (method === "node.list") { + return mockNodeList(["device.status", "device.info"]); + } + if (method === "node.invoke") { + expect(params).toMatchObject({ + nodeId: NODE_ID, + command: "device.status", + params: {}, + }); + return { + payload: { + battery: { state: "charging", lowPowerModeEnabled: false }, + }, + }; + } + return unexpectedGatewayMethod(method); + }); + + const result = await executeNodes({ + action: "device_status", + node: NODE_ID, + }); + + expect(result.content?.[0]).toMatchObject({ + type: "text", + text: expect.stringContaining('"battery"'), + }); + }); + + it("invokes device.info and returns payload", async () => { + callGateway.mockImplementation(async ({ method, params }) => { + if (method === "node.list") { + return mockNodeList(["device.status", "device.info"]); + } + if (method === "node.invoke") { + expect(params).toMatchObject({ + nodeId: NODE_ID, + command: "device.info", + params: {}, + }); + return { + payload: { + systemName: "Android", + appVersion: "1.0.0", + }, + }; + } + return unexpectedGatewayMethod(method); + }); + + const result = await executeNodes({ + action: "device_info", + node: NODE_ID, + }); + + expect(result.content?.[0]).toMatchObject({ + type: "text", + text: expect.stringContaining('"systemName"'), + }); + }); +}); + describe("nodes run", () => { it("passes invoke and command timeouts", async () => { callGateway.mockImplementation(async ({ method, params }) => { diff --git a/src/agents/tools/nodes-tool.ts b/src/agents/tools/nodes-tool.ts index 6b18e7d9782..a2f347e0e52 100644 --- a/src/agents/tools/nodes-tool.ts +++ b/src/agents/tools/nodes-tool.ts @@ -42,6 +42,8 @@ const NODES_TOOL_ACTIONS = [ "screen_record", "location_get", "notifications_list", + "device_status", + "device_info", "run", "invoke", ] as const; @@ -297,12 +299,23 @@ export function createNodesTool(options?: { const result: AgentToolResult = { content, details }; return await sanitizeToolResultImages(result, "nodes:camera_snap", imageSanitization); } - case "camera_list": { + case "camera_list": + case "notifications_list": + case "device_status": + case "device_info": { const node = readStringParam(params, "node", { required: true }); + const command = + action === "camera_list" + ? "camera.list" + : action === "notifications_list" + ? "notifications.list" + : action === "device_status" + ? "device.status" + : "device.info"; const payloadRaw = await invokeNodeCommandPayload({ gatewayOpts, node, - command: "camera.list", + command, }); const payload = payloadRaw && typeof payloadRaw === "object" && payloadRaw !== null ? payloadRaw : {}; @@ -430,15 +443,6 @@ export function createNodesTool(options?: { }); return jsonResult(payload); } - case "notifications_list": { - const node = readStringParam(params, "node", { required: true }); - const payload = await invokeNodeCommandPayload({ - gatewayOpts, - node, - command: "notifications.list", - }); - return jsonResult(payload); - } case "run": { const node = readStringParam(params, "node", { required: true }); const nodes = await listNodes(gatewayOpts);