From 86c4809a4081047f40026f69c1910a54a6039832 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Wed, 6 May 2026 03:04:20 -0700 Subject: [PATCH] test(gateway): skip opencode acp image probe by default --- src/gateway/gateway-acp-bind.live.test.ts | 86 +++++++++++++---------- src/gateway/live-agent-probes.test.ts | 8 +++ src/gateway/live-agent-probes.ts | 16 +++++ 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/src/gateway/gateway-acp-bind.live.test.ts b/src/gateway/gateway-acp-bind.live.test.ts index 14e9d7822ff..d656e6804a0 100644 --- a/src/gateway/gateway-acp-bind.live.test.ts +++ b/src/gateway/gateway-acp-bind.live.test.ts @@ -30,6 +30,7 @@ import { buildLiveCronProbeMessage, createLiveCronProbeSpec, runOpenClawCliJson, + shouldRunLiveImageProbe, } from "./live-agent-probes.js"; import { renderCatFacePngBase64 } from "./live-image-probe.js"; import { startGatewayServer } from "./server.js"; @@ -907,48 +908,57 @@ describeLive("gateway live (ACP bind)", () => { expect(boundHistory.matchedAssistantText).toContain(`ACP-BIND-MEMORY-${memoryNonce}`); logLiveStep("bound session transcript contains the final marker token"); - const markerAssistantCount = assistantTexts.length; - let imageHistory: Awaited> | null = null; - for (let attempt = 0; attempt < 2 && !imageHistory; attempt += 1) { - await sendChatAndWait({ - client, - sessionKey: originalSessionKey, - idempotencyKey: `idem-image-${attempt}-${randomUUID()}`, - message: - "What animal is drawn in the attached image? Reply with only the lowercase animal name.", - originatingChannel: "slack", - originatingTo: conversationId, - originatingAccountId: accountId, - attachments: [ - { - mimeType: "image/png", - fileName: `probe-${randomUUID()}.png`, - content: renderCatFacePngBase64(), - }, - ], - }); - logLiveStep(`image turn completed (attempt ${String(attempt + 1)})`); - - try { - imageHistory = await waitForAssistantTurn({ + if ( + shouldRunLiveImageProbe({ + agent: liveAgent, + override: process.env.OPENCLAW_LIVE_ACP_BIND_IMAGE_PROBE, + }) + ) { + const markerAssistantCount = assistantTexts.length; + let imageHistory: Awaited> | null = null; + for (let attempt = 0; attempt < 2 && !imageHistory; attempt += 1) { + await sendChatAndWait({ client, - sessionKey: spawnedSessionKey, - minAssistantCount: markerAssistantCount + 1, - timeoutMs: liveAgent === "claude" ? 60_000 : 45_000, + sessionKey: originalSessionKey, + idempotencyKey: `idem-image-${attempt}-${randomUUID()}`, + message: + "What animal is drawn in the attached image? Reply with only the lowercase animal name.", + originatingChannel: "slack", + originatingTo: conversationId, + originatingAccountId: accountId, + attachments: [ + { + mimeType: "image/png", + fileName: `probe-${randomUUID()}.png`, + content: renderCatFacePngBase64(), + }, + ], }); - } catch { - if (attempt === 1) { - logLiveStep( - "bound session image reply not observed; continuing to cron verification", - ); - break; + logLiveStep(`image turn completed (attempt ${String(attempt + 1)})`); + + try { + imageHistory = await waitForAssistantTurn({ + client, + sessionKey: spawnedSessionKey, + minAssistantCount: markerAssistantCount + 1, + timeoutMs: liveAgent === "claude" ? 60_000 : 45_000, + }); + } catch { + if (attempt === 1) { + logLiveStep( + "bound session image reply not observed; continuing to cron verification", + ); + break; + } + logLiveStep("bound session image reply not observed yet; retrying"); } - logLiveStep("bound session image reply not observed yet; retrying"); } - } - if (imageHistory) { - assertLiveImageProbeReply(imageHistory.lastAssistantText); - logLiveStep("bound session classified the probe image"); + if (imageHistory) { + assertLiveImageProbeReply(imageHistory.lastAssistantText); + logLiveStep("bound session classified the probe image"); + } + } else { + logLiveStep(`skipping image probe for ${liveAgent}`); } const requireCronMcpProbe = shouldRequireCronMcpProbe(); diff --git a/src/gateway/live-agent-probes.test.ts b/src/gateway/live-agent-probes.test.ts index ca7bcb8a928..ff26bb0659f 100644 --- a/src/gateway/live-agent-probes.test.ts +++ b/src/gateway/live-agent-probes.test.ts @@ -5,6 +5,7 @@ import { buildLiveCronProbeMessage, createLiveCronProbeSpec, isClaudeLikeLiveAgent, + shouldRunLiveImageProbe, } from "./live-agent-probes.js"; describe("live-agent-probes", () => { @@ -28,6 +29,13 @@ describe("live-agent-probes", () => { expect(() => assertLiveImageProbeReply("caterpillar")).toThrow("image probe expected 'cat'"); }); + it("skips the shared image probe for text-only live agents unless forced", () => { + expect(shouldRunLiveImageProbe({ agent: "claude" })).toBe(true); + expect(shouldRunLiveImageProbe({ agent: "opencode" })).toBe(false); + expect(shouldRunLiveImageProbe({ agent: "opencode", override: "1" })).toBe(true); + expect(shouldRunLiveImageProbe({ agent: "claude", override: "0" })).toBe(false); + }); + it("builds a retryable cron prompt with provider-specific fallback wording", () => { const spec = createLiveCronProbeSpec({ agentId: "codex", diff --git a/src/gateway/live-agent-probes.ts b/src/gateway/live-agent-probes.ts index ee627059752..550beba933e 100644 --- a/src/gateway/live-agent-probes.ts +++ b/src/gateway/live-agent-probes.ts @@ -38,6 +38,22 @@ export function assertLiveImageProbeReply(text: string): void { } } +export function shouldRunLiveImageProbe(params: { agent: string; override?: string }): boolean { + const override = params.override?.trim(); + if (override) { + switch (normalizeOptionalLowercaseString(override)) { + case "1": + case "on": + case "true": + case "yes": + return true; + default: + return false; + } + } + return normalizeOptionalLowercaseString(params.agent) !== "opencode"; +} + export function createLiveCronProbeSpec( params: { agentId?: string;