Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Fix Cursor ACP thread rendering, thought output, and cancel delivery - #3669

Closed
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering
Closed

Fix Cursor ACP thread rendering, thought output, and cancel delivery#3669
taschaub wants to merge 3 commits into
pingdotgg:mainfrom
taschaub:fix-cursor-thread-rendering

Conversation

@taschaub

@taschaubtaschaub commented Jul 3, 2026

Copy link
Copy Markdown

What Changed

Four related bug fixes in the Cursor CLI (ACP) integration, found while dogfooding resumed and cancelled threads:

  1. Cancel never reached the agent.session/cancel was sent as a JSON-RPC request (with an id), but the ACP spec defines it as a notification. The Cursor CLI silently dropped the malformed message, so pausing a thread left the turn running. It is now sent as a proper notification.
  2. Resumed sessions rendered new output above the latest user message. ACP assistant segment item ids were stable across runtime restarts, so a resumed session appended new chunks to message items from earlier runs. Segment ids are now tagged with a per-runtime tag.
  3. Agent reasoning was invisible.agent_thought_chunk updates are now parsed into channel-aware segments and surfaced as expandable thinking rows in the work log (reusing the existing Codex task.progress thinking affordance).
  4. Race on turn completion. CursorAdapter now drains queued ACP session updates before emitting turn.completed, raced against the notification fiber so mid-turn teardown cannot hang.

Scope: server-side ACP runtime + Cursor adapter, plus a 2-line tone mapping in apps/web/src/session-logic.ts and a 4-line follow-through in GrokAdapter for the shared ingestion API. Unit tests added for each fix (AcpJsonRpcConnection, AcpRuntimeModel, AcpCoreRuntimeEvents, CursorAdapter), and the acp-mock-agent was extended to reproduce the resume/cancel scenarios.

Why

Cursor threads were unusable in three common flows: pausing a turn did nothing (the cancel was dropped by the CLI), resuming a session scrambled message order, and reasoning output was silently discarded. Each fix targets the root cause (spec-compliant notification, runtime-scoped segment identity, channel-aware segment parsing, deterministic drain before turn completion) rather than patching symptoms in the UI.

vp check and vp run typecheck pass.

UI Changes

No new UI. The visible effects are bug fixes: assistant output appears below the latest user message again on resumed Cursor threads, and Cursor reasoning shows up as the same expandable thinking rows already used for Codex. Happy to add before/after screenshots on request.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Open in Devin Review

Note

Fix Cursor ACP thread rendering, thought output, and cancel delivery

  • Adds support for ACP agent_thought_chunk events, segmenting thought and assistant channels separately in AcpSessionRuntime; thought segments accumulate text and emit it on completion as reasoning activities
  • Fixes outgoing JSON-RPC notifications in protocol.ts to omit the id field, preventing agents from rejecting cancel and other notifications as malformed requests
  • Adds a drain barrier in CursorAdapter.ts so content deltas and item completions are observed before turn.completed is emitted; suppresses turn.completed after session teardown
  • Persists completed reasoning items as reasoning activities with a truncated summary (max 120 chars) and capped detail (max 8000 chars) in ProviderRuntimeIngestion.ts
  • Assigns the thinking tone to reasoning activities in the work-log UI

Macroscope summarized 98a8e44.

- Send session/cancel as a spec-compliant JSON-RPC notification (no id);
the Cursor CLI dropped the malformed message so turns kept running
after pausing a thread.
- Tag ACP assistant segment item ids with a per-runtime tag so resumed
sessions stop appending new output to messages from earlier runs,
which pushed assistant text above the latest user message.
- Parse agent_thought_chunk into channel-aware segments and surface the
accumulated reasoning as expandable thinking rows in the work log.
- Drain queued ACP session updates before emitting turn.completed in
CursorAdapter (raced against the notification fiber to avoid hanging
on mid-turn teardown).
Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitaiBot commented Jul 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 54637cac-10bf-4e41-900a-e5d726d921dc

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
✨ 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.

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 3, 2026
Comment threadapps/server/src/provider/Layers/CursorAdapter.ts
Comment threadapps/server/src/provider/acp/AcpCoreRuntimeEvents.ts
@macroscopeapp

macroscopeappBot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

2 blocking correctness issues found. This PR introduces new thought/reasoning channel support across multiple system layers and includes concurrency fixes for session teardown. An unresolved high-severity comment identifies potential out-of-order event emission, and the scope extends beyond simple fixes to new streaming capability.

You can customize Macroscope's approvability policy. Learn more.

…ng deltas
- sendTurn's drain race also settles when stopSessionInternal interrupts
the notification fiber. Check ctx.stopped after the race and bail out
before mutating turn state or emitting turn.completed, so a torn-down
session can no longer produce events after session.exited. Covered by
extending the stop-during-pending-approval test.
- Document why reasoning_text content deltas are intentionally not
appended to the assistant message by ingestion: the full thought text
is accumulated in the runtime segment and persisted via item.completed,
and segments close on prompt settlement so cancelled turns keep their
reasoning.
Co-authored-by: Cursor <cursoragent@cursor.com>
@taschaub

Copy link
Copy Markdown
Author

Addressed both Macroscope findings in 98a8e44:

  • CursorAdapter.ts (High):sendTurn now checks ctx.stopped after the drain race and bails out before touching turn state or emitting turn.completed. A torn-down session can no longer emit events after session.exited. The existing stop-during-pending-approval test was extended to assert no turn.completed is published after teardown (it fails without the fix).
  • AcpCoreRuntimeEvents.ts (Medium): Intentional — documented at the emit site. reasoning_text deltas are deliberately not appended to the assistant message by ingestion (same treatment as the Codex/Claude/OpenCode reasoning deltas). The full thought text accumulates in the runtime segment and is delivered via item.completed (itemType reasoning), which ingestion persists as the expandable thinking row. Segments close on channel switches, tool calls, and prompt settlement including cancellation, so reasoning from an interrupted turn is not lost.

justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…utput, cancel delivery
Applies pingdotgg#3669 on top of the fork's #9 resume/recovery hardening.
Fixes: session/cancel sent as JSON-RPC notification (not request), runtime-unique
ACP segment item ids so resumed sessions render below the latest user message,
agent_thought_chunk parsed as expandable reasoning rows, and a turn-completion
drain race. Supersedes the reverted #10 turn-scoping.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
justingray0 added a commit to justingray0/t3code that referenced this pull request Jul 4, 2026
…ng-3669
Adopt upstream pingdotgg#3669: Cursor ACP thread rendering, thought output, cancel delivery
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

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

Labels

size:L100-499 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@taschaub@juliusmarminge