Skip to content

fix(cursor): route native fallbacks through code mode - #1896

Draft
luvyoun0224-beep wants to merge 2 commits into
lidge-jun:devfrom
luvyoun0224-beep:agent/cursor-code-mode-native-fallback
Draft

fix(cursor): route native fallbacks through code mode#1896
luvyoun0224-beep wants to merge 2 commits into
lidge-jun:devfrom
luvyoun0224-beep:agent/cursor-code-mode-native-fallback

Conversation

@luvyoun0224-beep

@luvyoun0224-beep luvyoun0224-beep commented Aug 17, 2026

Copy link
Copy Markdown

Summary

  • Preserve Codex 0.147's real Responses Lite tool shape: the reserved functions namespace now flattens ordinary client functions and its nested freeform custom exec into top-level internal tools.
  • Detect those code-mode turns in the live Cursor transport and retain that mode in the native-exec context.
  • Replace misleading top-level shell_command / exec_command fallback instructions with the real code-mode contract: top-level exec, then nested tools.exec_command(...) or tools.apply_patch(...), with text(...) output.
  • Keep the existing flat-catalog guidance unchanged for non-code-mode requests and keep native local execution disabled by default.
  • Add regression coverage for the captured Codex 0.147 additional_tools shape, filesystem, shell, fetch, MCP-resource, mutation, and live-transport propagation paths.

This follows #1844. That change fixed system guidance, but two gaps remained: Codex 0.147 groups custom exec under the reserved functions namespace, which the parser dropped, and Cursor-native rejection responses still directed models to top-level tools that do not exist in code mode.

Verification

  • focused Cursor/native/parser/Responses Lite suites: 162 pass
  • all tests/cursor-*.test.ts files: 602 pass
  • bun run typecheck
  • bun run privacy:scan
  • git diff --check
  • bounded local live probe through Codex 0.147 + Cursor: the model successfully executed Get-Content package.json and read version 2.22.0; the following model continuation hit the account's Cursor resource limit, so the probe did not receive its requested final formatted line.
  • Full bun test was attempted on Windows; it stopped making progress during unrelated integration tests and was interrupted after more than 90 seconds without output.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed. (No user-facing configuration changed.)
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

AI assistance was used for implementation and test preparation; the resulting diff and verification output were reviewed locally.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@github-actions github-actions Bot added the bug Something isn't working label Aug 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c6872267-8b86-4413-a69a-e2be5f22bbe7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (0/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@lidge-jun

Copy link
Copy Markdown
Owner

Reviewed as the candidate canonical PR for the #1887/#1896 consolidation. Do not close #1887
as superseded yet
— one thing in it has to move here first, and it is not a nicety.

codeModeBridgeGuidance in this PR hardcodes the literal `exec` and the
mcp_opencodex-responses_* names whenever codeMode === true. That is a boolean, not a read
of what the request actually advertised. #1887 does the same job by asking the catalog:
cursorNativeExecUsesCodeModeBridge(catalog) checks hasAdvertisedName and returns
{kind:"none"} when exec is not advertised.

The reason this matters more than a style preference: #1895 exists specifically to remove
hardcoded tool names from the shared catalog nudge, on the grounds that hardcoding re-creates
per-provider drift. Landing this PR as canonical would re-introduce that defect one PR after
deleting it, in the same wave.

Four more things live only in #1887 and would be lost:

  1. native-exec-bridge.ts — the rewrite engine that translates denied native args into
    cat/ls/rg/curl with shell quoting. This PR has no equivalent.
  2. planNativeExecRewrite's finalize-vs-cancel ordering, with the documented failure mode:
    an immediate cancelCursorRun() sets expectedClose, scheduleClientToolFinalize becomes a
    no-op, turn 1 never emits done, the conversation id is dropped, and the rewritten result
    never comes back. That is expensive knowledge to rediscover.
  3. Three cursor-native-exec-policy.test.ts cases — rewrite, defer-while-sibling-open, and
    non-code-mode fallthrough.
  4. Windows PowerShell 5.1 guidance ([Bug] Cursor Auto repeats tool continuations on Windows PowerShell 5.1, causing excessive token usage #604): no cd /d, no heredocs, &&/|| are parser
    errors, one-retry cap. The guidance string here drops all of it.

Worth saying explicitly that these two PRs are not duplicates in kind. This one is
guidance — a denied op returns text asking the model to call exec itself, so it depends on
model compliance. #1887 is mechanical — it intercepts the denied frame and synthesizes a real
exec call, needing none. Guidance is the better default; the rewrite is the fallback for when
the model ignores it. Keeping both layers is the point of consolidating rather than choosing.

This PR is still draft, so nothing is blocked by this note. The parser fix here (flattening
Codex 0.147's reserved functions namespace so freeform custom children like code-mode exec
survive) is genuinely load-bearing and absent from #1887 — that, not scope, is the real case
for making this one canonical.

@lidge-jun

Copy link
Copy Markdown
Owner

Reviewed as the intended canonical of the #1887/#1896 pair, and it is the right choice — the
parser.ts fix here (flattening Codex 0.147's reserved functions namespace so freeform
custom children like code-mode exec survive) is load-bearing and absent from #1887.

But do not merge this and close #1887 as superseded, because one guard would be lost and
it is the one that matters most:

codeModeBridgeGuidance hardcodes the literal `exec` and the mcp_opencodex-responses_*
names whenever codeMode === true. #1887 instead derives them from the advertised catalog via
cursorNativeExecUsesCodeModeBridge, returning {kind:"none"} when the catalog does not
advertise exec.

That is the same defect #1895 was opened to remove — naming tools the turn may not actually
advertise. I have just fixed the shared-nudge version of it in #1951, which decides code mode
from freeform metadata rather than the name, precisely because a structured exec, or an
exec beside a visible shell bridge, is not code mode at all. Landing this as-is would
re-introduce that shape in the Cursor path one PR after deleting it from the shared one.

To become canonical, this needs #1887's:

  1. cursorNativeExecUsesCodeModeBridge catalog detection replacing the hardcoded names — the blocker
  2. the native-exec-bridge.ts rewrite engine, which synthesizes a real exec call instead of asking the model to make one
  3. planNativeExecRewrite's finalize-vs-cancel ordering and its documented failure mode
  4. the three cursor-native-exec-policy.test.ts cases
  5. the Windows PowerShell 5.1 guidance from [Bug] Cursor Auto repeats tool continuations on Windows PowerShell 5.1, causing excessive token usage #604

Items 1 and 2 are the substantive ones: guidance depends on model compliance, the rewrite does
not, so they are complementary layers rather than two takes on one fix.

Merge mechanics: this branch is currently clean against dev after #1900 landed (2b12521ee).

lidge-jun added a commit that referenced this pull request Aug 18, 2026
One merged, four carried, and one plan decision reversed. #1900 landed with its
three gates verified in the diff first - HTTPS-only non-loopback discovery, the
Bearer refused before any plain-HTTP request builder, and a clean EOF with open
tool calls emitting a typed error rather than done.

The reversal is #1887. The plan had it closed as superseded by #1896; it holds
the catalog-aware guard that decides the bridge from what the request actually
advertised, where #1896 hardcodes the names off a boolean. Closing it would have
re-introduced the defect #1895 exists to remove.

Also recording the process correction that held: WP6 faulted me for merging
#1902 before its CI could be judged, and #1900 was merged three minutes after
its run reported success rather than eight minutes before.
luvs01 pushed a commit to luvs01/opencodex that referenced this pull request Aug 18, 2026
I merged the train into a scratch worktree off origin/dev instead of predicting
conflicts, and the planned order fails twice.

lidge-jun#1887 conflicts only because lidge-jun#1896 exists - they are the duplicate pair this
plan already flagged, sharing five native-exec files plus live-transport.
Choosing lidge-jun#1896 as canonical and dropping lidge-jun#1887 makes the whole train clean.
lidge-jun#1896 also wins on scope: lidge-jun#1887 additionally drags in tool-definitions.ts and
two docs files that lidge-jun#1900 already touches.

lidge-jun#1903 is stale independently of the train. Merged alone onto current dev it
still conflicts in src/types.ts, so no resequencing fixes it - the branch needs
its author to rebase.

Recording the honest expectation up front: four of the five are drafts or
conflicting, so this work-phase should land lidge-jun#1900 and carry the rest with
reasons rather than pretending the order was the obstacle.
luvs01 pushed a commit to luvs01/opencodex that referenced this pull request Aug 18, 2026
The simulation reproduced exactly; my explanation of it did not.

I wrote that lidge-jun#1887 conflicts only because lidge-jun#1896 exists, naming the shared
native-exec files. In the sequence I actually ran, lidge-jun#1896 had not been merged
yet. Isolating it: lidge-jun#1887 alone is clean, and so is each of lidge-jun#1900, lidge-jun#1895 and
lidge-jun#1896 paired with it - the conflict needs lidge-jun#1900 and lidge-jun#1895 together, and it lands
in tool-definitions.ts, which is not a native-exec file and has nothing to do
with lidge-jun#1896. I presented dropping lidge-jun#1887 as evidence-driven when the evidence
pointed elsewhere.

The more serious one: closing lidge-jun#1887 as superseded would have deleted a guard
this plan calls critical. lidge-jun#1896's codeModeBridgeGuidance hardcodes exec and the
mcp_opencodex-responses names on a boolean; lidge-jun#1887 derives them from the
advertised catalog and returns none when exec is not advertised. That is the
plan's own no-hardcoded-exec matrix row, and it is the exact defect lidge-jun#1895 exists
to remove - so making lidge-jun#1896 canonical without migrating would re-introduce it
one PR after deleting it. Five items are now listed as migration prerequisites.

Also corrected: the scope comparison is a wash rather than a win for lidge-jun#1896, and
lidge-jun#1903 is a 32-file cross-cutting change rather than a rebase-and-merge item.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants