Skip to content

fix(orchestration): scope assistant IDs by turn#42

Open
davidmashburn wants to merge 1 commit into
maria-rcks:mainfrom
davidmashburn:fix/cursor-resume-assistant-message-ids
Open

fix(orchestration): scope assistant IDs by turn#42
davidmashburn wants to merge 1 commit into
maria-rcks:mainfrom
davidmashburn:fix/cursor-resume-assistant-message-ids

Conversation

@davidmashburn

@davidmashburn davidmashburn commented Jul 16, 2026

Copy link
Copy Markdown

What changed

  • Centralize assistant message ID construction in a small helper.
  • Include the orchestration turn ID in assistant delta, completion, and checkpoint message IDs.
  • Add a regression test where a resumed Cursor session reuses assistant:session-1:segment:0 across two turns and verify both replies remain distinct.

Why

Cursor ACP can reuse assistant segment item IDs after a session resumes. Those IDs are persisted as message primary keys, so the second reply can update an older assistant row and appear above the latest user message instead of creating a new reply.

This is a focused port of the ID-collision fix from pingdotgg/t3code#3642. It intentionally ports the collision prevention only: turn-scoped IDs make the cross-turn projection merge unnecessary and avoid bringing over unrelated projection behavior.

Existing persisted IDs remain valid; newly ingested assistant events use the turn-scoped shape when a turn ID is available and preserve the legacy shape otherwise.

Verification

  • bun fmt
  • bun lint (passes with 9 pre-existing warnings)
  • bun typecheck
  • bun run --cwd apps/server test src/orchestration/assistantMessageIds.test.ts src/orchestration/Layers/ProviderRuntimeIngestion.test.ts (31 tests passed)

Made with Cursor

Summary by CodeRabbit

  • Bug Fixes

    • Fixed assistant messages being incorrectly combined when resumed sessions reuse the same underlying message identifier.
    • Assistant messages are now uniquely tracked per conversation turn across streaming responses, buffered updates, completions, and checkpoints.
    • Improved consistency of assistant message tracking and de-duplication during response ingestion.
  • Tests

    • Added coverage for resumed sessions, streaming updates, oversized responses, completion events, and checkpoint processing.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 14bc3073-0d5c-4938-adba-5ef3c80f3edc

📥 Commits

Reviewing files that changed from the base of the PR and between aeb4ce0 and 6d35183.

📒 Files selected for processing (4)
  • apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts
  • apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts
  • apps/server/src/orchestration/assistantMessageIds.test.ts
  • apps/server/src/orchestration/assistantMessageIds.ts

📝 Walkthrough

Walkthrough

Assistant message IDs now include the turn ID when available. Runtime ingestion uses centralized ID helpers across deltas, completions, and diff checkpoints, with tests covering resumed sessions that reuse item IDs.

Changes

Assistant message identity

Layer / File(s) Summary
Assistant message ID helpers
apps/server/src/orchestration/assistantMessageIds.ts, apps/server/src/orchestration/assistantMessageIds.test.ts
Adds base-key selection and optional turn-qualified MessageId generation, with fallback and legacy-format tests.
Runtime ingestion ID wiring
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts
Centralizes assistant ID creation for deltas, completions, and diff checkpoint placeholders.
Turn-scoped ingestion coverage
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts
Updates existing ID assertions and verifies distinct finalized replies when resumed turns reuse an item ID.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RuntimeEvent
  participant processRuntimeEvent
  participant assistantMessageIdForEvent
  participant AssistantMessage
  RuntimeEvent->>processRuntimeEvent: assistant delta or completion event
  processRuntimeEvent->>assistantMessageIdForEvent: derive base key and turn-scoped ID
  assistantMessageIdForEvent-->>processRuntimeEvent: MessageId
  processRuntimeEvent->>AssistantMessage: dispatch assistant update or completion
Loading

Suggested reviewers: maria-rcks

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: assistant IDs are now scoped by orchestration turn.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@davidmashburn

Copy link
Copy Markdown
Author

@maria-rcks — small Cursor reliability fix when you have a minute.

#42 prevents resumed Cursor sessions from reusing assistant message IDs across turns, which could make a new reply overwrite an older message and appear in the wrong place. The fix scopes assistant IDs by turn.

I verified it before reaching out:

  • The resumed-session regression fails on main and passes with this PR.
  • All 31 relevant orchestration tests pass.
  • The real T1 server and headless TUI launch successfully and render the project/composer interface.
  • Formatting, lint, and full typechecking pass.
  • Unrelated failures in the broader server/TUI suites reproduce unchanged on main.

This is a focused port of the fix from pingdotgg/t3code#3642, adapted to keep the t1code change small.

No pressure—just thought it might be useful here too. Thanks for all your work on t1code; I’m really enjoying the project!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant