From f1db2592b398b5a49ec875c75c140a981542356f Mon Sep 17 00:00:00 2001 From: Jonathan Li <47408717+jonathanli12@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:44:59 -0700 Subject: [PATCH] fix(cursor): teach code-mode nested-helper contract in tool guidance Codex code mode advertises one freeform `exec` tool whose body is JavaScript evaluated in a V8 isolate; shell, edits, and MCP are nested `tools.(...)` helpers described inside that tool's description, invisible to a flat catalog scan. The Cursor guidance builder assumed a flat catalog and told the model to call a top-level `exec_command`, which does not exist on that turn. Routed models then burned turns rediscovering the contract from errors: empty output until `text()` is called, `require is not defined` because the isolate is not Node, and `apply_patch` rejected because it too is only nested. Detect code mode (freeform `exec` with no bare shell bridge) and emit the nested-helper contract instead. Turns that advertise a bare bridge are unchanged. --- src/adapters/cursor/tool-definitions.ts | 41 +++++++++++++++++++ tests/cursor-tool-definitions.test.ts | 54 +++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/src/adapters/cursor/tool-definitions.ts b/src/adapters/cursor/tool-definitions.ts index 48a18c2ebe..69a1d32536 100644 --- a/src/adapters/cursor/tool-definitions.ts +++ b/src/adapters/cursor/tool-definitions.ts @@ -191,6 +191,38 @@ export function isCursorWaitTool(tool: Pick): boo return isCursorResponsesProvider(tool.namespace) && tool.name === CODEX_WAIT_TOOL; } +/** + * True for Codex's unified-exec "code mode" tool: a freeform `exec` whose body is JavaScript + * evaluated in a V8 isolate, not a shell command string. + */ +export function isCursorCodeModeExecTool( + tool: Pick, +): boolean { + return isCursorResponsesProvider(tool.namespace) + && tool.name === CODEX_UNIFIED_EXEC_TOOL + && tool.freeform === true; +} + +/** + * Codex code mode advertises ONE freeform `exec` tool and no bare shell bridge. Shell, file + * edits, and MCP calls are reachable only as nested `tools.(...)` helpers described inside + * that tool's own description, so a flat catalog scan cannot see them. + * + * This matters because the shell-bridge guidance below is written for a flat catalog. Emitting + * "call \`exec_command\`" into a code-mode turn names a top-level tool that does not exist: the + * model calls it, gets nothing back, and burns turns rediscovering the real contract from error + * messages (empty output until \`text()\` is called, \`require is not defined\` because the isolate + * is not Node, \`apply_patch\` rejected because it too is only a nested helper here). + */ +export function cursorRequestUsesCodeMode( + tools: readonly Pick[] | undefined, + toolChoice?: OcxRequestOptions["toolChoice"], +): boolean { + const catalog = tools ?? []; + const visible = catalog.filter(tool => cursorToolAllowedByChoice(tool, toolChoice, catalog)); + return visible.some(isCursorCodeModeExecTool) && !visible.some(isBareCodexShellBridgeTool); +} + /** @deprecated Prefer isBareCodexShellBridgeTool; kept for older call sites/tests. */ function isBareCodexExecCommandTool(tool: Pick): boolean { return isBareCodexShellBridgeTool(tool); @@ -554,6 +586,7 @@ export function buildCursorToolGuidanceSystemNote( const listedNames = quotedNames(wireNames); const shellBridgeNames = wireNames.filter(isCodexShellBridgeToolName); const hasBareExec = shellBridgeNames.length > 0; + const codeMode = cursorRequestUsesCodeMode(tools, toolChoice); const shellBridgeLabel = quotedNames(shellBridgeNames.length > 0 ? shellBridgeNames : [...CODEX_SHELL_BRIDGE_TOOL_NAMES]); const hasApplyPatch = cursorRequestAdvertisesApplyPatch(tools, toolChoice); const structuredEditNames = tools @@ -572,6 +605,14 @@ export function buildCursorToolGuidanceSystemNote( unavailableNeighborNames.length > 0 ? `This turn does not expose neighboring-agent tool names ${quotedNames(unavailableNeighborNames)}; do not call or suggest them unless the catalog lists them.` : undefined, + // Code mode: the ONLY callable tool is freeform `exec`, and shell/edit/MCP live inside it as + // nested helpers. Without this the model probes for a top-level shell tool that is not there. + codeMode + ? `\`${CODEX_UNIFIED_EXEC_TOOL}\` is Codex code mode: its body is JavaScript evaluated in a V8 isolate, not a shell command and not Node. Shell, file edits, and MCP are nested helpers called INSIDE that body as \`await tools.(...)\`, for example \`await tools.exec_command({cmd: \"ls\"})\`. Read the tool description for the exact nested helpers this turn provides; they are not separate top-level tools, so do not call \`exec_command\`, \`shell_command\`, or \`apply_patch\` at the top level here.` + : undefined, + codeMode + ? "In code mode the isolate returns nothing on its own: call `text(...)` (or `notify(...)`) on any value you need to see, or the call completes with empty output. There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers." + : undefined, hasBareExec ? `${shellBridgeLabel} is the Codex Responses shell bridge for this turn, exposed through Cursor's tool protocol; it is not an external MCP server tool. \`shell_command\` and \`exec_command\` are aliases of the same bridge.` : undefined, diff --git a/tests/cursor-tool-definitions.test.ts b/tests/cursor-tool-definitions.test.ts index 2f2c644525..1e552f113f 100644 --- a/tests/cursor-tool-definitions.test.ts +++ b/tests/cursor-tool-definitions.test.ts @@ -9,6 +9,8 @@ import { buildCursorToolGuidanceSystemNote, CURSOR_EXEC_COMMAND_INPUT_SCHEMA, cursorRequestAdvertisesApplyPatch, + cursorRequestUsesCodeMode, + isCursorCodeModeExecTool, cursorToolArgNormalizeSchema, cursorToolInputSchema, cursorToolWireName, @@ -411,3 +413,55 @@ describe("Cursor tool definitions", () => { expect(allowedNote).not.toContain("`mcp__fs__read_file`"); }); }); + +describe("Cursor code mode tool guidance", () => { + const codeModeExec = (): OcxTool => ({ + name: "exec", + description: "Run JavaScript code to orchestrate tool calls. Nested tools are available on the global `tools` object.", + parameters: {}, + freeform: true, + }); + + test("detects code mode only when freeform exec has no bare shell bridge", () => { + expect(cursorRequestUsesCodeMode([codeModeExec()])).toBe(true); + expect(isCursorCodeModeExecTool(codeModeExec())).toBe(true); + + // A non-freeform `exec` is not code mode. + expect(cursorRequestUsesCodeMode([{ name: "exec", description: "Run", parameters: {} }])).toBe(false); + // A bare shell bridge alongside it means the flat-catalog guidance still applies. + expect(cursorRequestUsesCodeMode([codeModeExec(), { name: "exec_command", description: "Run", parameters: {} }])).toBe(false); + expect(cursorRequestUsesCodeMode([{ name: "exec_command", description: "Run", parameters: {} }])).toBe(false); + expect(cursorRequestUsesCodeMode(undefined)).toBe(false); + // Tool choice that hides exec also hides code mode. + expect(cursorRequestUsesCodeMode([codeModeExec(), { name: "read_file", namespace: "mcp__fs", description: "R", parameters: {} }], { name: "read_file" })).toBe(false); + }); + + test("teaches the nested-helper contract instead of a top-level shell bridge", () => { + const note = buildCursorToolGuidanceSystemNote([codeModeExec()]); + expect(note).toBeDefined(); + if (!note) throw new Error("Expected Cursor tool guidance note"); + + expect(note).toContain("is Codex code mode"); + expect(note).toContain("V8 isolate"); + expect(note).toContain("await tools.(...)"); + expect(note).toContain("await tools.exec_command({cmd: " + "\"" + "ls" + "\"" + "})"); + expect(note).toContain("text(...)"); + expect(note).toContain("There is no `require`"); + + // The flat-catalog shell-bridge guidance must NOT appear: naming a top-level + // `exec_command` in code mode sends the model after a tool that does not exist. + expect(note).not.toContain("is the Codex Responses shell bridge for this turn"); + expect(note).not.toContain("mcp_opencodex-responses_shell_command"); + expect(note).not.toContain("For file read/search/listing, use"); + }); + + test("keeps flat-catalog shell-bridge guidance when a bare bridge is advertised", () => { + const note = buildCursorToolGuidanceSystemNote([{ name: "exec_command", description: "Run", parameters: {} }]); + expect(note).toBeDefined(); + if (!note) throw new Error("Expected Cursor tool guidance note"); + + expect(note).toContain("is the Codex Responses shell bridge for this turn"); + expect(note).not.toContain("is Codex code mode"); + expect(note).not.toContain("V8 isolate"); + }); +});