Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/responses/code-mode-helper-compat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ export function compileCodeModeHelperInput(argumentsText: unknown, toolName: str
if (toolName === "write_stdin") {
return `const result = await tools.write_stdin(${JSON.stringify(args)});\ntext(result);`;
}
if (toolName === "view_image") {
let target = "";
if (isPlainObject(args)) {
if (typeof args.path === "string") target = ` for ${JSON.stringify(args.path)}`;
else if (typeof args.file_path === "string") target = ` for ${JSON.stringify(args.file_path)}`;
else if (typeof args.file === "string") target = ` for ${JSON.stringify(args.file)}`;
}
const msg = `Error: 'view_image' is not available in Code Mode${target}. Inspect files or visual assets programmatically using tools.exec_command or code.`;
return `text(${JSON.stringify(msg)});\n`;
}
return `const result = await tools.exec_command(${JSON.stringify(args)});\ntext(result);`;
}

Expand Down
1 change: 1 addition & 0 deletions src/types/tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const CODE_MODE_HELPER_TOOL_NAMES = [
...LEGACY_SHELL_BRIDGE_TOOL_NAMES,
"write_stdin",
"apply_patch",
"view_image",
] as const;

/**
Expand Down
12 changes: 12 additions & 0 deletions tests/responses/legacy-shell-compat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,16 @@ describe("code-mode helper compatibility", () => {
expect(received).toEqual(input === "[]" ? [] : input);
}
});

test("view_image emits a friendly code-mode error message via text()", async () => {
const source = compileCodeModeHelperInput(
JSON.stringify({ path: "/root/banner.png" }),
"view_image",
);
let output: unknown;
const run = new AsyncFunction("tools", "text", source);
await run({}, (value: unknown) => { output = value; });
expect(output).toContain("Error: 'view_image' is not available in Code Mode for \"/root/banner.png\"");
expect(output).toContain("tools.exec_command");
});
});
10 changes: 10 additions & 0 deletions tests/responses/responses-undeclared-tool-guard.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1640,6 +1640,16 @@ describe("undeclaredToolCallNameInResponse", () => {
expect(undeclaredToolCallNameInResponse(response, new Set())).toBe("write_stdin");
});

test("accepts view_image through a bare unified exec declaration", () => {
const response = {
output: [{ type: "function_call", name: "view_image" }],
};

expect(undeclaredToolCallNameInResponse(response, new Set(["exec"]))).toBeUndefined();
expect(undeclaredToolCallNameInResponse(response, new Set(["view_image"]))).toBeUndefined();
expect(undeclaredToolCallNameInResponse(response, new Set())).toBe("view_image");
});

test("never legacy-normalizes a namespaced shell bridge call", () => {
// A namespaced call (e.g. an MCP server advertising its own exec_command) must be
// matched by its full wire name only — never normalized to bare `exec`.
Expand Down
Loading