From 8117a13dd646a7c043b48ab6c1093a4e9fb76f20 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Thu, 26 Feb 2026 11:35:05 +0530 Subject: [PATCH] fix(nodes): default camera snap to front high-quality image --- .../android/node/CameraCaptureManager.kt | 4 +-- src/agents/openclaw-tools.camera.test.ts | 35 +++++++++++++++++++ src/agents/tools/nodes-tool.ts | 6 ++-- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt b/apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt index 65bac915eff..aa038ad9a94 100644 --- a/apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt +++ b/apps/android/app/src/main/java/ai/openclaw/android/node/CameraCaptureManager.kt @@ -81,8 +81,8 @@ class CameraCaptureManager(private val context: Context) { ensureCameraPermission() val owner = lifecycleOwner ?: throw IllegalStateException("UNAVAILABLE: camera not ready") val facing = parseFacing(paramsJson) ?: "front" - val quality = (parseQuality(paramsJson) ?: 0.5).coerceIn(0.1, 1.0) - val maxWidth = parseMaxWidth(paramsJson) ?: 800 + val quality = (parseQuality(paramsJson) ?: 0.95).coerceIn(0.1, 1.0) + val maxWidth = parseMaxWidth(paramsJson) ?: 1600 val provider = context.cameraProvider() val capture = ImageCapture.Builder().build() diff --git a/src/agents/openclaw-tools.camera.test.ts b/src/agents/openclaw-tools.camera.test.ts index 3082c849609..6b1d2e35c33 100644 --- a/src/agents/openclaw-tools.camera.test.ts +++ b/src/agents/openclaw-tools.camera.test.ts @@ -43,6 +43,41 @@ beforeEach(() => { }); describe("nodes camera_snap", () => { + it("uses front/high-quality defaults when params are omitted", async () => { + callGateway.mockImplementation(async ({ method, params }) => { + if (method === "node.list") { + return mockNodeList(); + } + if (method === "node.invoke") { + expect(params).toMatchObject({ + command: "camera.snap", + params: { + facing: "front", + maxWidth: 1600, + quality: 0.95, + }, + }); + return { + payload: { + format: "jpg", + base64: "aGVsbG8=", + width: 1, + height: 1, + }, + }; + } + return unexpectedGatewayMethod(method); + }); + + const result = await executeNodes({ + action: "camera_snap", + node: NODE_ID, + }); + + const images = (result.content ?? []).filter((block) => block.type === "image"); + expect(images).toHaveLength(1); + }); + it("maps jpg payloads to image/jpeg", async () => { callGateway.mockImplementation(async ({ method }) => { if (method === "node.list") { diff --git a/src/agents/tools/nodes-tool.ts b/src/agents/tools/nodes-tool.ts index 4cfd84dc474..3006b9cfddc 100644 --- a/src/agents/tools/nodes-tool.ts +++ b/src/agents/tools/nodes-tool.ts @@ -186,7 +186,7 @@ export function createNodesTool(options?: { const node = readStringParam(params, "node", { required: true }); const nodeId = await resolveNodeId(gatewayOpts, node); const facingRaw = - typeof params.facing === "string" ? params.facing.toLowerCase() : "both"; + typeof params.facing === "string" ? params.facing.toLowerCase() : "front"; const facings: CameraFacing[] = facingRaw === "both" ? ["front", "back"] @@ -198,11 +198,11 @@ export function createNodesTool(options?: { const maxWidth = typeof params.maxWidth === "number" && Number.isFinite(params.maxWidth) ? params.maxWidth - : undefined; + : 1600; const quality = typeof params.quality === "number" && Number.isFinite(params.quality) ? params.quality - : undefined; + : 0.95; const delayMs = typeof params.delayMs === "number" && Number.isFinite(params.delayMs) ? params.delayMs