Skip to content

fix(server): Claude completion notices preserve queued tools - #15653

Closed
StiensWout wants to merge 2 commits into
pingdotgg:mainfrom
StiensWout:t3code/claude-completion-notice-next
Closed

StiensWout wants to merge 2 commits into
pingdotgg:mainfrom
StiensWout:t3code/claude-completion-notice-next

Conversation

@StiensWout

Copy link
Copy Markdown
Contributor

Problem

An async delegated-task completion notice interrupts Claude with now priority, cancelling queued tool calls and producing a misleading user refusal.

Change

Carry the existing delegated-completion metadata into the Claude adapter and use next priority only for agent/server completion notices. User steering remains immediate, with the existing abort bookkeeping and Stop behavior preserved. Stamp the queued notice with its own prompt UUID so a late final reply stays attributed to the completion notice when a user turn is already queued.

Scope and approval

Fixes #15351. This is the server-only fix requested by Wout for that issue; there are no client or other-provider behavior changes.

Verification

The implementer passed 177 focused tests, six steering replay cases, targeted lint, formatting, and server typecheck. Both independent validators passed this exact commit; each reran the Claude adapter and steering integration tests, with 152 tests passing.

Live SDK/CLI checks on Claude Code 2.1.289 reproduced cancellation with now and verified that next preserves queued tools and the final reply. The stamped notice kept completion and queued-user replies separate, and Stop still worked. Live coverage is limited to that CLI version and direct SDK/Bash runs; MCP-specific behavior and older CLI versions were not verified.

Implemented for Wout by claude-opus-5-5 in Claude Code through T3 Code. PR prepared by gpt-6.1-sol in Codex through T3 Code.

StiensWout and others added 2 commits October 4, 2026 15:02
…ol calls

When an async delegated task finished, T3 steered the completion notice
into the running Claude turn with SDK priority "now". Claude ends the turn
to deliver a "now" message, so tool calls it had issued but not started
came back as "The user doesn't want to take this action right now. STOP".
The agent read that as an instruction from the user and stopped.

The Claude adapter now sends a server-created delegated completion with
priority "next". Claude reads it at the turn's next tool boundary and
every issued call still runs. A notice that lands during the final reply
gets a native turn of its own afterwards, which reaches the thread through
the existing continuation run. User steers, runtime-question answers and
agent-to-agent steers keep "now".

The steer input now carries the persisted message's delegatedCompletion so
the adapter can tell a notice from other steers. Only a "now" steer marks
the turn as expecting an abort result, so an abort after a notice still
ends the turn.

Fixes pingdotgg#15351

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…laude turn

A "next" completion notice that lands during the final reply is answered by
Claude in a turn of its own after the result. That turn echoed no prompt
uuid, so when T3 had already started a queued run, the adapter took the
notice's result for that run's own. The run ended on the notice's reply and
its real reply showed up on a continuation run.

The Claude adapter now stamps a "next" steer with a uuid derived from the
steered message. Claude echoes it on the notice's turn, so the existing
prompt-echo gate sends that output to a continuation run and leaves the
queued run to end on its own result. "now" steers stay unstamped.

Refs pingdotgg#15351

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 4, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This server-side fix changes Claude turn scheduling and reply attribution by propagating delegated-completion metadata into the adapter, affecting queued tool execution and continuation runs. The focused tests are extensive, but the runtime pipeline change is substantial enough to warrant human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 4, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (1)
docs/internals/effect-services.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 806f2891-887f-448b-879c-ca72aba6a3f1
📥 Commits

Reviewing files that changed from the base of the PR and between 4ee6bfd and cf9bdfa.

📒 Files selected for processing (5)
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
  • apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
  • apps/server/src/orchestration-v2/ProviderAdapter.ts
  • apps/server/src/orchestration-v2/ProviderTurnControlService.ts
  • apps/server/src/orchestration-v2/SteeringCompletion.integration.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Steering messages now carry delegated-completion metadata to the Claude adapter. The adapter uses that metadata to steer server-created completion notices with "next" priority while retaining "now" priority for other messages. Tests cover abort outcomes and notice replies across continuation runs.

Changes

Claude steering flow

Layer / File(s) Summary
Pass delegated-completion metadata
apps/server/src/orchestration-v2/ProviderAdapter.ts, apps/server/src/orchestration-v2/ProviderTurnControlService.ts, apps/server/src/orchestration-v2/SteeringCompletion.integration.test.ts
The provider message schema includes delegatedCompletion, and the steering service passes it to the adapter when defined. Integration tests record and assert the metadata.
Select Claude steering priority
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts
Server-created agent messages with delegated completion receive "next" priority and a message-derived UUID. Other messages receive "now" priority. Only "now" steering marks the active turn as steered.
Verify abort and continuation behavior
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.test.ts
Tests cover steering priority, turn abort outcomes, and notice replies during continuations, including when a user turn is queued.

Priority: ➖ Normal

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

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant ProviderTurnControlService
  participant ClaudeAdapterV2
  participant ClaudeAgentSDK
  ProviderTurnControlService->>ClaudeAdapterV2: Pass delegatedCompletion when defined
  ClaudeAdapterV2->>ClaudeAgentSDK: Send delegated notice with next priority and UUID
  ClaudeAdapterV2->>ClaudeAgentSDK: Send other steer with now priority
Loading

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to cf9bd

Delegated-completion notices follow the queued steering path while user steering remains immediate. No identified issue prevents merging after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to cf9bd

The change is narrowly scoped to completion-notice scheduling and reply attribution. Existing ownership checks and Stop controls remain in place, and no new privilege escalation path was identified. Delivery-failure behavior and compatibility across runtime versions remain partially verified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The demonstrated exposure is execution ordering for tools in an existing active provider turn and attribution of its later completion response. The inspected sink requires a live query and the matching active turn; it does not establish broader tenant, credential, or infrastructure exposure.

Trust Boundaries and Controls

  • observed — The inspected path uses persisted message identity rather than accepting a caller-supplied priority. Completion ownership must match an open delivery before forwarding, dispatch constrains origin, and Claude independently qualifies agent/server notices. These checks support rejection of a metadata-only scheduling bypass; outer caller authentication was not inspected.

Resilience and Maintainability Implications

  • observed — Targeted tests exercise steering rejection and queued fallback, duplicate delivery acceptance, terminal interruption, and continuation cleanup. They support failure containment in those modeled states, but do not prove idempotent recovery after a native message is accepted and the offer subsequently reports failure.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the server-side fix: Claude completion notices preserve queued tools.
Description check ✅ Passed The description covers the problem, change, scope and approval, and verification. It reports test and live-check results and states the limits of live coverage.
Linked Issues check ✅ Passed Issue #15351 requires delegated-completion notices to reach Claude without canceling queued tool calls, while user steering remains immediate. ProviderAdapterV2TurnMessage and `ProviderTurnControlSe…
Out of Scope Changes check ✅ Passed The changes are limited to Claude server adapter logic, steering metadata propagation, and related adapter and integration tests. These changes support issue #15351. The reviewed changes show no clien…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@StiensWout

Copy link
Copy Markdown
Contributor Author

The docstring-coverage warning is not actionable for this fix. The changed scheduling rule is already explained immediately above claudeSteerPriority, the stable UUID and echo relationship is documented above claudePromptUuid, and the offer path explains why only immediate steering expects an abort. The schema field and metadata forwarding do not add undocumented service behavior. AGENTS.md asks for concise comments where they clarify behavior, not a blanket docstring quota; adding docstrings solely to meet an 80% threshold would duplicate the existing explanation. Leaving this warning without code changes.

gpt-6.1-sol via Codex in T3 Code, responding for Wout.

@juliusmarminge

Copy link
Copy Markdown
Member

Note

Grok responding on behalf of Julius.

Thanks for this, Wout. #15351 was fixed by #15892, which just merged to main and keeps Claude child-completion notices queued behind active tools (plus scheduled prompts). Since this PR only targeted #15351, I'm closing it as superseded. If you see a case that main still gets wrong, please open a new issue with the repro and we can pick it back up.

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

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Delegated-task notifications cancel queued Claude tool calls and tell the agent the user refused

2 participants