Repository navigation
fix(cursor): bridge native TodoWrite completions - #8432
diegosouzapw merged 2 commits into
Conversation
|
Thanks for this — really thorough work, both on the protobuf reverse-engineering and on the fail-closed safety semantics (exact-set merge proof, priority-history recovery, duplicate/malformed rejection). I re-ran the full validation locally on a fresh checkout of your branch: 91/91 on the three focused suites and 219/219 on the full One thing is blocking merge right now that CI is also flagging: this PR's own diff pushes The other two red checks are not on you — "No new ESLint warnings" is the known pre-existing stale-suppression drift in |
53dd71b to
576f6d0
Compare
|
Addressed in Using the same
Post-extraction validation on the rebased head:
The full |
c9be34a
into
cheaper-inference:release/v3.8.49
Summary
InteractionUpdate.tool_call_completed -> ToolCall.todo_write.todowritetool call so OpenCode can update its own Todo state.merge=trueonly when its unique content set exactly matches structured history; reject partial/new/ambiguous merges fail-closed.role: "tool"request resumes from full history.Related Issues
Validation
npx tsx --test tests/unit/cursor*.test.ts(219/219)npm run lint— four pre-existing@typescript-eslint/no-explicit-anyerrors remain in unchangedtests/unit/claude-to-openai-think-close-5123.test.ts; targeted ESLint and Prettier checks on all six changed files passAdditional validation:
npm run typecheck:coregit diff --checkfinish_reason: "tool_calls", completetodowriteJSONfinish_reason: "tool_calls", usage,[DONE]merge=truepayload bridges totodowritewithfinish_reason: "tool_calls"todowrite,finish_reason: "tool_calls", and[DONE]nativeTodoWrite.ts: host 1505/1521 lines, leaf 111/800 lines by CI counting semanticsTests Added Or Updated
tests/unit/cursor-agent-protobuf.test.tstests/unit/cursor-builtin-tool-bridge.test.tstests/unit/cursor-agent-tool-calls.test.tsCoverage Notes
The production changes are covered at three layers:
decodeAgentServerMessage;processFrame-> emitted tool-call state and cold-resume lifecycle.A sanitized real Cursor capture was also replayed outside the committed test fixtures. It contains all four observed statuses (
pending,in_progress,completed,cancelled) and is intentionally not committed because raw captures can contain prompt/account metadata.Reviewer Notes
Wire semantics
TodoWrite differs from the shell/read path fixed by #8171: there is no
ExecServerMessageto reject. Cursor reports the complete structured action inside a tool-call completion interaction update. The decoder keeps the existing generictool_call_completeddelta for compatibility and additionally emitsnative_todo_writewhen the nested message is complete and recognized.Fail-closed rules
tool_choicefiltering happens before TodoWrite matching.merge: trueis accepted only when its unique content set exactly equals the latest structured TodoWrite history, proving that the payload can safely replace the full list.role: "assistant"tool calls.tool_choicefail closed.Lifecycle
The native TodoWrite is already completed inside Cursor and has no open ExecMcp result channel. The bridge therefore emits an external OpenAI tool call, sets
requiresColdResume, and closes the native h2 session. The nextrole: "tool"request uses the existing full-history cold path rather than attempting an invalid inline result.