You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Preserve cancellation across AI, MCP and telemetry integrations - #98
Cancellation could be mistaken for an ordinary failure when AI callbacks, MCP transports or telemetry hooks threw during cleanup. That could trigger retries, send error responses or continue recording after the operation had been canceled.
Preserve cancellation at the existing integration boundaries:
Keep AI failure observers and conversation persistence from replacing cancellation; preserve child-task ownership and completed-turn fallback behavior.
Stop MCP handshake retries and server error responses when cancellation is wrapped by cleanup, while still closing owned transports.
Propagate cancellation from OpenTelemetry, Sentry and Telescope callbacks without hiding genuine ordinary failures or skipping required cleanup.
Regression coverage checks direct and wrapped cancellation, callback failures, transport cleanup and ordinary-error behavior. Targeted source analysis and affected tests pass. The full suite and service matrices run in CI.
Summary by cubic
Cancellation was previously mistaken for an ordinary failure when AI callbacks, MCP transports, or telemetry hooks threw during cleanup. That could trigger retries, send error responses, or continue recording after the operation had been canceled.
Cancellation is now preserved at integration boundaries by using Coroutine::causedByCancellation and preferCancellation instead of referring to Swoole\Coroutine\CanceledException directly.
AI failure observers, step/tool reporters, and stream catch callbacks now run from finally, keeping the original cancellation alive even when reporting throws. Independently canceled concurrent tools and title generation surface as ChildCancellationException without discarding completed turns.
MCP handshake fallback no longer retries after cancellation, server handlers no longer convert cancellation into error responses or empty completions, and transport cleanup prefers cancellation while still closing owned sessions.
OpenTelemetry, Sentry, and Telescope fallback catches now rethrow cancellation chains before applying their ordinary-error handling, so canceled operations stop telemetry recording exactly where they should.
Regression tests cover direct and wrapped cancellation, throwing callbacks, transport cleanup, and ordinary-error behavior across the affected integrations.
Written for commit 9f7e35e. Summary will update on new commits.
Note
Preserve cancellation across AI, MCP and telemetry integrations
Replaces direct CanceledException type checks with Coroutine::causedByCancellation and Coroutine::preferCancellation across OpenTelemetry, Sentry, Telescope and MCP instrumentation, so cancellations wrapped in other exceptions propagate instead of being logged or converted to fallback values
Reworks AI failure-reporting paths (RememberConversation, GeneratesText, StreamsText, TextGenerationLoop, InvokesTools, Provider.dispatchingFailure, StreamableAgentResponse) to throw the original exception first and run reporting in finally, so a reporting failure retains the original as its previous exception
Cancellation-caused tool failures and title-generation failures are now stored as ChildCancellationException with the caught exception as previous
MCP Server.sendException and response handling now rethrow cancellation-caused exceptions instead of converting them to JSON-RPC errors; ClientManager and transport cleanup paths give cancellation precedence over other failures
Risk: behavioral change — places that previously swallowed or logged failures (e.g. JsonNormalizer.normalize, DumpWatcher::shouldRecordDump, Telescope Auth/cache lookups, Hub::startTransaction samplers) now rethrow any throwable whose cause chain contains a cancellation; non-cancellation failures keep prior behavior
Coroutine cancellation is now preserved across AI generation, tool execution, conversation storage, MCP requests, and telemetry integrations—even when wrapped by another exception.
Failure reporting and cleanup are less likely to obscure the original error or cancellation.
Completed conversation turns remain saved when title generation is canceled, and canceled operations are no longer silently treated as ordinary failures.
Tests
Expanded coverage for direct and wrapped cancellations, cleanup failures, and exception handling.
A failure-event factory or listener could replace an operation's cancellation with an ordinary exception, allowing retry() to run the canceled operation again.
Dispatch failure events from finally while the original exception is in flight. PHP retains that original cause if event construction or dispatch fails, without changing successful operations or optional-listener checks.
Validation: OperationEventsTest passes all 15 tests, including a throwing failure observer that must not cause a retry. Targeted source analysis and formatting pass.
Throwing agent, step or tool failure observers could erase the original cancellation. Separately, cancellation of one concurrent tool was exposed as cancellation of the still-active caller.
Run failure reporting from finally to retain the original exception chain. Mark independently canceled tool failures with the existing ChildCancellationException boundary, preserving sibling cancellation and joining before the caller receives the failure.
Validation: seven focused AgentEvents cases and all nine ConcurrentTools tests pass. Coverage includes prompt and stream failure reporting, middleware after generation, tool observers, ordinary tool failures and direct or wrapped child cancellation. Targeted source analysis and formatting pass.
A public stream catch callback that throws could hide cancellation from the failed producer, making an interrupted stream look like an ordinary failure.
Invoke the already-cleared callback list from finally while the producer exception remains in flight. Preserve callback execution context and once-only handling while retaining both failures through PHP's exception chain.
Validation: StreamableAgentResponseTest passes all nine tests, including throwing catch callbacks and repeated stream iteration. Targeted source analysis and formatting pass.
Conversation persistence failures could replace cancellation during generation or title work. Independently canceled title generation could also discard a completed caller turn.
Preserve cancellation through failed-turn recording and completed-turn persistence using finally. Mark independent title-child cancellation with ChildCancellationException and use the existing fallback title so the completed turn is stored. Cancellation of the caller still propagates after owned persistence.
Validation: 13 focused RememberConversation cases pass on SQLite, covering direct and wrapped title-child cancellation, failed-turn storage, caller title cancellation, and title cleanup. Targeted source analysis and formatting pass.
When an oversized remote attachment also failed during cancellation cleanup, the size-limit exception could replace the cancellation chain.
Use the shared cancellation predicate before replacing a transfer failure with the existing size-limit message. Ordinary oversized responses keep their current behavior; canceled transfers retain their original failure.
Validation: both direct and wrapped cancellation cases pass against the bounded loopback transfer fixture. Targeted source analysis and formatting pass.
MCP handlers and generators could convert cancellation carrying a cleanup failure into a protocol error, tool error or empty completion. Debug-mode rethrows concealed the server failure in tests.
Check cancellation at the shared server error boundary and the response-conversion and completion fallbacks. Rethrow the original failure while preserving ordinary error responses and the completion catch's original Exception breadth.
Validation: ServerTest passes 52 tests, CallToolTest 24 and CompletionCompleteTest 26. Regressions cover debug-disabled server handling, immediate and streamed tool failures, and direct or wrapped completion cancellation. Targeted source analysis and formatting pass.
A remembered legacy handshake could retry after wrapped cancellation, while fallback initialization could relabel cancellation as an additional handshake failure. Cleanup precedence also recognized only bare cancellation.
Use the existing cancellation predicate before handshake fallback or failure wrapping and preferCancellation when cleanup throws. Keep authorization errors, ordinary negotiation fallback and original exception identity unchanged.
Validation: HandshakeTest passes all 35 tests, including remembered-handshake cancellation, discovery timeout followed by cancellation, and cancellation during disconnect. Targeted source analysis and formatting pass.
Managed client teardown could suppress a ClientException carrying cancellation or retain an earlier ordinary failure instead of later cancellation.
Preserve cancellation at the client-error suppression boundary and use the shared precedence helper while still visiting every owned client. Ordinary client disconnect failures remain ignored as before.
Validation: ClientManagerTest passes all 38 tests, including direct, wrapped and transport-wrapped cancellation and verification that every client is visited once. Targeted source analysis and formatting pass.
Session termination treated cleanup-wrapped cancellation as an ignorable DELETE failure, and response cleanup selected cancellation only by its outer exception type.
Use the shared predicate for termination failures and the existing precedence helper for owned exchange cleanup. Session state is still reset and owned responses closed; active sibling consumers retain their transfer ownership.
Validation: HttpTransportTest passes all 45 tests, including direct and wrapped termination cancellation, response closure and idempotent disconnect. Targeted source analysis and formatting pass.
A failed stdio receive could hide cancellation raised through process-stop cleanup because teardown checked only the outer exception type.
Use preferCancellation when disconnect cleanup fails. Preserve the original primary failure for ordinary cleanup errors and retain existing process/input detachment before propagating cancellation.
Validation: three focused StdioTransport cases pass for direct disconnect, wrapped disconnect and wrapped cleanup after receive failure. Tests use a bounded process mock; targeted source analysis and formatting pass.
A cache-key resolver's cleanup failure could hide cancellation and allow completion telemetry to continue.
Use the shared cancellation predicate before logging an ordinary resolver error and omitting the key. Preserve ordinary resolver isolation and the existing metrics and tracing behavior.
Validation: CacheInstrumentationTest passes all eight tests, including direct and wrapped cancellation with no completion telemetry. Targeted source analysis and formatting pass.
Exception enrichment could continue through later callbacks after an enricher threw a cleanup error carrying cancellation.
Rethrow cancellation chains before logging and continuing past ordinary enricher failures. The original failure remains intact and later enrichers are not invoked for canceled work.
Validation: ExceptionInstrumentationTest passes all 12 tests. Regression cases cover direct and wrapped cancellation, later-callback suppression and no emitted record. Targeted source analysis and formatting pass.
A URL-template resolver could swallow cleanup-wrapped cancellation and proceed with a physical HTTP request.
Use the cancellation predicate at the resolver fallback boundary. Keep terminal error reporting unchanged so a genuine cleanup error remains observable while cancellation stops the request.
Validation: HttpClientInstrumentationTest passes all 13 tests. Both cancellation forms prevent the physical send; the wrapped cleanup failure retains its error span and duration metric. Targeted source analysis and formatting pass.
Redis query-text resolution could hide cancellation behind a cleanup error and emit misleading completion telemetry.
Recognize cancellation chains before applying the existing ordinary-error logging and omitted-query fallback. Leave normal command telemetry and resolver error isolation unchanged.
Validation: RedisInstrumentationTest passes all 11 tests, including direct and wrapped resolver cancellation with no completion telemetry. Targeted source analysis and formatting pass.
A user-context resolver's cleanup failure could be treated as an ordinary lookup error even when the operation was canceled.
Use the shared predicate before recording a resolver failure. Propagate the original cancellation chain and retain the existing ordinary-error fallback.
Validation: both UserContextResolverTest cases pass, exercising direct and wrapped cancellation from the configured resolver. Targeted source analysis and formatting pass.
Breadcrumb and sampling callbacks could replace cancellation with a cleanup failure, causing the Hub to log the error and continue.
Use the cancellation predicate before the existing callback-error fallback in breadcrumb, trace-sampler and profile-sampler handling. Keep configured sampling fallback and ordinary callback error logging unchanged.
Validation: HubTest passes all 14 tests with explicit direct and wrapped cancellation rows for each callback. Targeted source analysis and formatting pass.
Application accessors invoked by Sentry event handling can perform cancellable work. A cleanup exception carrying cancellation was ignored as an ordinary instrumentation failure.
Use the shared predicate at the event-dispatch catch, preserving ordinary failure isolation and the original cancellation exception chain.
Validation: AuthEventsTest passes all 12 tests, including direct and wrapped cancellation through a user email accessor. Targeted source analysis and formatting pass.
Tracing event dispatch ignored cleanup failures containing cancellation and could continue an interrupted operation.
Recognize cancellation chains at the existing event-handler catch. Ordinary instrumentation errors remain isolated from application execution.
Validation: tracing EventHandlerTest passes all nine tests, including direct and wrapped cancellation and ordinary instrumentation failure handling. Targeted source analysis and formatting pass.
User-defined tool schemas may perform cancellable work. Cleanup-wrapped cancellation was treated as an ignorable schema resolution failure.
Use the shared cancellation predicate before retaining the existing ordinary schema-error fallback. No schema invocation or successful tracing behavior changes.
Validation: the two focused AiIntegration cases pass, verifying that ordinary schema failures remain isolated while wrapped cancellation escapes tracing. Targeted source analysis and formatting pass.
Session-store resolution during cache tracing caught every failure, including cancellation raised by application bindings or cleanup.
Rethrow cancellation chains before the existing missing-session fallback. Preserve the reentry guard's cleanup and ordinary command tracing when session resolution fails normally.
Validation: both focused CacheIntegration cases pass for ordinary resolution failure and wrapped cancellation. Targeted source analysis and formatting pass.
An application serializer's cancellation could be replaced with Telescope's purged-value fallback.
Check the exception chain before purging serialization failures. Preserve ordinary malformed-value handling while allowing canceled application work to stop.
Validation: ExtractPropertiesTest passes all five tests, including a throwing serializer carrying cancellation and the existing ordinary-failure purge behavior. Targeted source analysis and formatting pass.
Loading monitored tags could hide cancellation and replace the existing tags with an empty list.
Rethrow cancellation before applying the ordinary storage-error fallback. Preserve existing tags when the load is interrupted and keep the empty fallback for ordinary failures.
Validation: the two cancellation/fallback rows and neighboring unique-tag storage test pass on SQLite. Targeted source analysis and formatting pass.
Recording-state cache lookups and application user accessors could swallow cancellation, enabling recording or queuing entries after the operation had stopped.
Recognize cancellation chains at both existing fallback catches. Preserve ordinary lookup-error behavior and the coroutine-local recording state.
Validation: six focused SQLite cases pass, covering pause lookup, user resolution, later recording after callback failures and command-start recording. Targeted source analysis and formatting pass.
Telescope could turn cancellation from a request or response body producer into a purged payload and continue recording.
Rethrow cancellation chains before the existing payload-error fallback. Preserve owned stream-position restoration and ordinary unreadable-payload handling.
Validation: request-body and cached-response cancellation cases and the neighboring raw payload test pass on SQLite. Targeted source analysis and formatting pass.
A canceled cache lookup for the dump-watcher flag was treated as an unavailable flag and delegated the dump as normal work.
Use the shared cancellation predicate before returning the existing false fallback. Ordinary cache failures still delegate; cancellation propagates without recording or delegation.
Validation: both focused DumpWatcher fallback cases pass on SQLite. The complete file also passed at the integration checkpoint. Targeted source analysis and formatting pass.
The requested audit of cancellation-sensitive callback, fallback and I/O catches is complete across the framework and integration groups.
Remove its completed task while retaining the separate proposal to investigate a focused PHPStan rule. The owner-approved Google SDK cause-loss limitation remains represented by its skipped regression and separate handoff.
Validation: checked the remaining todo entries and the final reviewed audit scope.
Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.
Walkthrough
The changes extend coroutine cancellation detection across AI, MCP, OpenTelemetry, Sentry, and Telescope. Failure callbacks and cleanup paths preserve cancellation-related exceptions, including wrapped cancellation. AI conversation handling also persists completed turns during independent title cancellation.
Changes: Coroutine cancellation handling
Layer / File(s)
Summary
AI failure reporting and cancellation docs/todo.md, src/ai/src/Files/*, src/ai/src/Gateway/*, src/ai/src/Providers/*, src/ai/src/Responses/*, tests/Ai/ConcurrentToolsTest.php, tests/Ai/Feature/AgentEventsTest.php, tests/Ai/Feature/Files/*, tests/Ai/Feature/OperationEventsTest.php, tests/Ai/Unit/Responses/*
AI failure callbacks now run while the original exception is rethrown. Concurrent tool cancellation is wrapped as a child cancellation. Cancellation checks cover wrapped exceptions, including when a URL download reaches its size limit.
Conversation cancellation and persistence src/ai/src/Middleware/RememberConversation.php, src/ai/src/Support/PendingConversationTitle.php, tests/Ai/Feature/RememberConversationTest.php
Conversation failure recording preserves the active exception. Title cancellation is handled separately, and persistence plus response updates run in a finally block. Tests cover title cancellation and storage failures.
MCP client, transport, and server paths use coroutine cancellation checks and exception-precedence helpers. Tests cover wrapped cancellation during initialization, requests, teardown, and response handling.
OpenTelemetry and Sentry cancellation src/opentelemetry/src/Instrumentation/*, src/opentelemetry/src/Support/*, src/sentry/src/*, tests/OpenTelemetry/*, tests/Sentry/*
Instrumentation and event handlers rethrow cancellation-caused exceptions while retaining existing handling for other failures. Tests cover direct and wrapped cancellation and selected telemetry behavior.
Serialization, storage, recording, and watcher paths rethrow cancellation-caused exceptions while retaining existing fallback behavior for other failures. Tests cover wrapped cancellation in these paths.
Caller cancellation remains preserved during title generation; no identified issue needs resolution before merging.
Pre-merge checks: 3 · 1 · 1
Failed checks: 1 warning · 1 inconclusive
Check name
Status
Explanation
Resolution
Description check
The description explains the problem, intended behavior, affected areas, and regression coverage. However, it omits the selected contribution type, linked issue or discussion, concrete failing and pas…
Select the applicable contribution type, link the relevant issue or discussion, identify the regression tests with their results before and after the fix, list the exact verification commands and results including the required composer fix …
Docstring Coverage
Docstring coverage is 63.51% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documenta…
Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed checks: 3 passed
Check name
Status
Explanation
Title check
The title clearly and concisely describes the main change: preserving cancellation across the affected AI, MCP, and telemetry integrations.
Linked Issues check
Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check
Check skipped because no linked issues were found for this pull request.
Full details: Description check
Explanation
The description explains the problem, intended behavior, affected areas, and regression coverage. However, it omits the selected contribution type, linked issue or discussion, concrete failing and passing regression-test results, verification commands and results, and completed submission checklist items.
Resolution
Select the applicable contribution type, link the relevant issue or discussion, identify the regression tests with their results before and after the fix, list the exact verification commands and results including the required composer fix run, and complete the before-submitting checklist.
Full details: Docstring Coverage
Explanation
Docstring coverage is 63.51% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 74 functions across 50 files. (9 skipped: 9 over the file limit.)
Resolution
Write docstrings for the functions missing them to satisfy the coverage threshold.
Finishing Touches
Generate docstrings
Commit to this branch
Create a new PR
Generate unit tests (beta)
Commit to this branch
Create a new PR
Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Warning
Some tools did not complete. Review the errors below.
PHPMD (3.0.0)
src/mcp/src/Client/Transport/HttpTransport.php
PHPMD could not process this file (exit code 3): Unexpected token: &, line: 54, col: 9, file: /src/mcp/src/Client/Transport/HttpTransport.php. #0 phar:///usr/bin/phpmd/vendor/pdepend/pdepend/src/Source/Language/PHP/AbstractPHPParser.php(8981): PDepend\Source\Parser\UnexpectedTokenException->__construct() #1 phar:///usr/bin/phpmd/vendor/pdepend/pdepend/src/Source/Language/PHP/AbstractPHPParser.php(8968): PDepend\Source\Language\PHP\AbstractPHPParser->getUnexpectedTokenExcepti...
src/mcp/src/Client/ClientManager.php
PHPMD could not process this file (exit code 3): Unexpected token: &, line: 33, col: 9, file: /src/mcp/src/Client/ClientManager.php. #0 phar:///usr/bin/phpmd/vendor/pdepend/pdepend/src/Source/Language/PHP/AbstractPHPParser.php(8981): PDepend\Source\Parser\UnexpectedTokenException->__construct() #1 phar:///usr/bin/phpmd/vendor/pdepend/pdepend/src/Source/Language/PHP/AbstractPHPParser.php(8968): PDepend\Source\Language\PHP\AbstractPHPParser->getUnexpectedTokenException() #2 ph...
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.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
Preserve cancellation across AI, MCP, and telemetry integrations
🐞 Bug fix🧪 Tests🕐 40+ Minutes
AI Description
• Preserve cancellation through AI failure observers, conversation storage, and independently
canceled child tasks.
• Prevent MCP retries and error responses after cancellation while retaining transport cleanup.
• Propagate cancellation from telemetry callbacks without changing ordinary-error fallbacks.
Diagram
graph TD
A["Integration operation"] --> B["Boundary catches"] --> C{"Cancellation cause?"}
C -->|Yes| D["Propagate failure"]
C -->|No| E["Ordinary fallback"]
B --> F["AI observers"] --> D
B --> G["MCP cleanup"] --> D
B --> H["Telemetry hooks"] --> C
Loading
High-Level Assessment
The following are alternative approaches to this PR:
1. Centralize integration exception handling
➕ Could reduce repeated cancellation checks across integrations.
➖ Would couple distinct fallback, cleanup, and child-ownership policies; risks changing ordinary-error behavior.
Recommendation: Keep the localized boundary fixes. They reuse the existing Coroutine cancellation helpers while preserving each integration's cleanup and ordinary-failure contract; a shared wrapper would obscure those differences.
Files changed (60) +1070 / -257
Bug fix (31) +268 / -171
UntrustedUrl.phpKeep transfer cancellation ahead of file-size errors+2/-2
Keep transfer cancellation ahead of file-size errors
• Recognizes cancellation wrapped by transfer cleanup so an oversized-download error cannot replace it.
TextGenerationLoop.phpPreserve generation failures and concurrent-tool ownership+28/-13
Preserve generation failures and concurrent-tool ownership
• Retains the original cause when step or tool failure observers throw. Marks cancellation originating in an independently running tool as child-owned before reporting it to the active caller.
RememberConversation.phpPreserve cancellation and completed conversation turns+56/-44
Preserve cancellation and completed conversation turns
• Keeps cancellation in the exception chain when failed-turn recording or storage fails. An independently canceled title falls back to a prompt-derived title without discarding the completed turn.
Provider.phpRetain operation failures through event dispatch+10/-7
Retain operation failures through event dispatch
• Constructs and dispatches optional failure events while the operation exception is in flight, preventing observer failures from hiding cancellation and enabling retries.
ClientManager.phpPrefer cancellation during client teardown+5/-6
Prefer cancellation during client teardown
• Keeps cancellation when selecting among disconnect failures, including wrapped failures. No longer suppresses a client exception caused by cancellation.
Protocol.phpStop handshake fallbacks after cancellation+12/-7
Stop handshake fallbacks after cancellation
• Avoids reconnecting or reporting a legacy handshake failure when an exception chain contains cancellation. Cleanup failure selection now uses the existing cancellation-preference helper.
CompletionComplete.phpDo not turn canceled completion into an empty result+6/-4
Do not turn canceled completion into an empty result
• Propagates completion failures caused by cancellation, including cleanup wrappers, while retaining the empty-result fallback for ordinary exceptions.
• Prevents session resolution cancellation from being treated as an unavailable session while preserving the existing cleanup and ordinary-error fallback.
ConcurrentToolsTest.phpCover concurrent child cancellation and sibling joining+23/-4
Cover concurrent child cancellation and sibling joining
• Extends tool-failure coverage to direct and wrapped child cancellation, checking ownership and that sibling tools finish before failure reaches the caller.
StdioTransportTest.phpCover cancellation during stdio disconnect and receive+21/-4
Cover cancellation during stdio disconnect and receive
• Exercises direct and wrapped process-stop cancellation, including disconnect triggered after a failed receive, while checking owned-state detachment.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
The PHPMD parse errors are its lack of support for PHP 8.4 by-reference property hooks. Both files pass the supported PHP runtime and source-analysis CI. No code change is needed. The docstring percentage is not a repository requirement, and the external-contributor checklist does not apply to this maintainer-directed change.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cancellation could be mistaken for an ordinary failure when AI callbacks, MCP transports or telemetry hooks threw during cleanup. That could trigger retries, send error responses or continue recording after the operation had been canceled.
Preserve cancellation at the existing integration boundaries:
Regression coverage checks direct and wrapped cancellation, callback failures, transport cleanup and ordinary-error behavior. Targeted source analysis and affected tests pass. The full suite and service matrices run in CI.
Summary by cubic
Cancellation was previously mistaken for an ordinary failure when AI callbacks, MCP transports, or telemetry hooks threw during cleanup. That could trigger retries, send error responses, or continue recording after the operation had been canceled.
Cancellation is now preserved at integration boundaries by using
Coroutine::causedByCancellationandpreferCancellationinstead of referring toSwoole\Coroutine\CanceledExceptiondirectly.finally, keeping the original cancellation alive even when reporting throws. Independently canceled concurrent tools and title generation surface asChildCancellationExceptionwithout discarding completed turns.Regression tests cover direct and wrapped cancellation, throwing callbacks, transport cleanup, and ordinary-error behavior across the affected integrations.
Written for commit 9f7e35e. Summary will update on new commits.
Note
Preserve cancellation across AI, MCP and telemetry integrations
CanceledExceptiontype checks withCoroutine::causedByCancellationandCoroutine::preferCancellationacross OpenTelemetry, Sentry, Telescope and MCP instrumentation, so cancellations wrapped in other exceptions propagate instead of being logged or converted to fallback valuesRememberConversation,GeneratesText,StreamsText,TextGenerationLoop,InvokesTools,Provider.dispatchingFailure,StreamableAgentResponse) to throw the original exception first and run reporting infinally, so a reporting failure retains the original as its previous exceptionChildCancellationExceptionwith the caught exception as previousServer.sendExceptionand response handling now rethrow cancellation-caused exceptions instead of converting them to JSON-RPC errors;ClientManagerand transport cleanup paths give cancellation precedence over other failuresJsonNormalizer.normalize,DumpWatcher::shouldRecordDump,TelescopeAuth/cache lookups,Hub::startTransactionsamplers) now rethrow any throwable whose cause chain contains a cancellation; non-cancellation failures keep prior behaviorMacroscope summarized 9f7e35e.
Summary by CodeRabbit