From a4250bad3008c8d0177e14d78b9b6e3c9b27fb09 Mon Sep 17 00:00:00 2001 From: Harivansh Rathi Date: Wed, 11 Mar 2026 14:26:18 -0400 Subject: [PATCH] fix: harden computer tool helper - remove the unimplemented accessibility observe mode from the public contract - refuse unmatched app_open requests instead of shelling out - add direct helper tests for both review findings Co-authored-by: Codex --- .../coding-agent/src/core/tools/computer.ts | 2 +- .../coding-agent/test/computer-tool.test.ts | 66 ++++++++++++++++++- 2 files changed, 65 insertions(+), 3 deletions(-) diff --git a/packages/coding-agent/src/core/tools/computer.ts b/packages/coding-agent/src/core/tools/computer.ts index 7cb9ac5..48c425f 100644 --- a/packages/coding-agent/src/core/tools/computer.ts +++ b/packages/coding-agent/src/core/tools/computer.ts @@ -30,7 +30,7 @@ const computerActions = [ "clipboard_write", ] as const; -const computerObservationModes = ["hybrid", "ocr", "accessibility"] as const; +const computerObservationModes = ["hybrid", "ocr"] as const; const DEFAULT_COMPUTER_COMMAND = process.env.COMPANION_AGENT_COMPUTER_COMMAND || "agent-computer"; diff --git a/packages/coding-agent/test/computer-tool.test.ts b/packages/coding-agent/test/computer-tool.test.ts index d1a3f49..5194d6b 100644 --- a/packages/coding-agent/test/computer-tool.test.ts +++ b/packages/coding-agent/test/computer-tool.test.ts @@ -1,6 +1,7 @@ -import { mkdtempSync, rmSync } from "node:fs"; +import { spawnSync } from "node:child_process"; +import { existsSync, mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; -import { join } from "node:path"; +import { join, resolve } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; import { parseArgs } from "../src/cli/args.js"; import { buildSystemPrompt } from "../src/core/system-prompt.js"; @@ -68,6 +69,13 @@ function createMockComputerOperations( }; } +function getAgentComputerScriptPath(): string { + return resolve( + process.cwd(), + "../../../../docker/companion/agent-computer.js", + ); +} + describe("computer tool", () => { const tempDirs: string[] = []; @@ -172,4 +180,58 @@ describe("computer tool", () => { "Prefer browser for websites and DOM-aware tasks. Switch to computer", ); }); + + it("rejects accessibility observe mode until a non-screenshot backend exists", () => { + const stateDir = createTempDir( + "coding-agent-computer-helper-accessibility-", + ); + const result = spawnSync( + process.execPath, + [ + "--no-warnings", + getAgentComputerScriptPath(), + "--state-dir", + stateDir, + "--input", + JSON.stringify({ + action: "observe", + mode: "accessibility", + }), + ], + { + encoding: "utf8", + }, + ); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain( + "backend_unavailable: accessibility observe mode is not implemented", + ); + }); + + it("refuses to shell out when app_open cannot match an installed app", () => { + const stateDir = createTempDir("coding-agent-computer-helper-app-open-"); + const markerPath = join(stateDir, "should-not-exist"); + const result = spawnSync( + process.execPath, + [ + "--no-warnings", + getAgentComputerScriptPath(), + "--state-dir", + stateDir, + "--input", + JSON.stringify({ + action: "app_open", + app: `definitely-not-an-installed-app && touch ${markerPath}`, + }), + ], + { + encoding: "utf8", + }, + ); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("app_not_found:"); + expect(existsSync(markerPath)).toBe(false); + }); });