-
Notifications
You must be signed in to change notification settings - Fork 1.2k
fix(cursor): stop grok-4.6 tool-result echo from poisoning later turns #4900
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,6 +13,27 @@ | |||||||||||||
| */ | ||||||||||||||
|
|
||||||||||||||
| const ECHO_MARKERS = ["[Tool Result]", "[Tool Error]", "[tool_result]"] as const; | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Drop a mid-message `[Tool Result]` / `[tool_result]` envelope from assistant | ||||||||||||||
| * history before Cursor root replay. The prefix sniffer retries echoes that | ||||||||||||||
| * start the turn; grok-4.6 often writes a real sentence first, so the echo | ||||||||||||||
| * already reached Codex and is persisted as assistant text. Replaying that | ||||||||||||||
| * block re-primes the next turn. Only whole-line markers count; inline mentions | ||||||||||||||
| * such as "the string [Tool Result] appeared" stay. | ||||||||||||||
| */ | ||||||||||||||
| export function stripAssistantEchoedToolEnvelope(text: string): string { | ||||||||||||||
| if (!text) return text; | ||||||||||||||
| const lines = text.split(/\r?\n/); | ||||||||||||||
| for (let i = 0; i < lines.length; i++) { | ||||||||||||||
| const probe = lines[i]!.replace(/^[ \t]*/, ""); | ||||||||||||||
| if ((ECHO_MARKERS as readonly string[]).includes(probe)) { | ||||||||||||||
| return lines.slice(0, i).join("\n").trimEnd(); | ||||||||||||||
|
Comment on lines
+29
to
+31
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: sed -n '1,155p' src/adapters/cursor/envelope-echo.ts
sed -n '185,225p' src/adapters/cursor/protobuf-request.ts
sed -n '400,490p' tests/providers/cursor/cursor-envelope-echo-retry.test.ts
rg -n -C 3 'stripAssistantEchoedToolEnvelope|ECHO_MARKERS|startsWith' src/adapters/cursor tests/providers/cursorRepository: lidge-jun/opencodex Length of output: 50375 🏁 Script executed: sed -n '140,180p' src/adapters/cursor/envelope-echo.ts
rg -n -C 8 'sawMidstreamEnvelopeEcho|findings\(\)|remintConversationId|assistantRootText|rootPromptMessagesJson' src/adapters/cursor/cursor.ts src/adapters/cursor/protobuf-request.ts src/adapters/cursor
sed -n '200,235p' src/adapters/cursor/protobuf-request.tsRepository: lidge-jun/opencodex Length of output: 34460 🏁 Script executed: sed -n '175,235p' src/adapters/cursor/envelope-echo.ts
rg -n -C 10 'sawMidstreamEnvelopeEcho|midstreamObserver|remintConversationId|findings\\(\\)' src/adaptersRepository: lidge-jun/opencodex Length of output: 16015 Normalize trailing whitespace before matching envelope markers.
Normalize both ends of the line while retaining exact equality. Add a focused regression test with trailing spaces. Proposed fix- const probe = lines[i]!.replace(/^[ \t]*/, "");
+ const probe = lines[i]!.trim();📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| return text; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| const MAX_SNIFF_BYTES = 40; | ||||||||||||||
| /** Mid-stream observer: max leading whitespace on a line before matching disarms. */ | ||||||||||||||
| const MAX_MIDSTREAM_LINE_INDENT = 128; | ||||||||||||||
|
|
@@ -59,15 +80,15 @@ export interface MidstreamEchoFinding { | |||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * Diagnostic-only mid-stream envelope-echo observer (devlog 260828 F1/F2). | ||||||||||||||
| * Mid-stream envelope-echo observer (devlog 260828 F1/F2). | ||||||||||||||
| * | ||||||||||||||
| * The prefix sniffer only watches the first ~40 bytes of a turn, but live | ||||||||||||||
| * probing caught grok-4.6 echoing "[Tool Result]" envelope blocks in the | ||||||||||||||
| * MIDDLE of an agent message — after legitimate leading text — one of them | ||||||||||||||
| * carrying a whitespace-spliced call-id ("fc_x mar-y" instead of "fc_x-y"). | ||||||||||||||
| * Deltas at that point have already reached the client, so this observer | ||||||||||||||
| * never throws and never withholds output: it records findings so the | ||||||||||||||
| * adapter can emit a structured diagnostic at turn end. Only fixed marker | ||||||||||||||
| * never throws and never withholds output. It records findings so the | ||||||||||||||
| * adapter can remint the conversation for the next turn. Only fixed marker | ||||||||||||||
| * enums, numeric offsets, and corruption booleans are retained — never | ||||||||||||||
| * content bytes. | ||||||||||||||
| */ | ||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🔎 Supported by static analysis
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 39375
🏁 Script executed:
Repository: lidge-jun/opencodex
Length of output: 42755
Do not remint compaction turns.
Compaction requests set
request.contextUsageStoreCheckpointstofalse, but this branch checks only_cursorIsolateConversation. Therefore, a compaction stream with an incomplete-tool error can invalidateinheritedCheckpointRefand callremintConversationId. When the request has a stable thread owner, that helper stores the replacement conversation for the parent thread.Exclude requests with
contextUsageStoreCheckpoints === falsehere. Add regression coverage for the thread override and inherited checkpoint.Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents