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
feat(api): abort signal support for unbound, vercel-ai-gateway, zoo-gateway - #1653
Wires the external abort signal and per-request timeout into the completePrompt (non-streaming) and createMessage (streaming) paths of the Unbound, Vercel AI Gateway, and Zoo Gateway providers. Stacks on the shared-util and opencode-go units of this split (resolveModelWithAbort in utils/abort-signal.ts).
Each provider:
createMessage: bridges metadata?.abortSignal (Bedrock pattern: pre-aborted guard, { once: true } listener, detached on completion so a task-scoped signal does not accumulate listeners) into a per-request AbortController; model resolution runs inside the shared resolveModelWithAbort cancellation scope (pre-aborted fast-fail before any catalog/SDK work, mid-resolution race). Aborted requests (pre-aborted, mid-resolution, mid-stream) normalize to the provider AbortError; non-abort failures propagate or wrap unchanged.
completePrompt: forwards abortSignal/ timeoutMs to the OpenAI SDK (timeoutMs <= 0 omits the SDK timeout option, since the SDK treats timeout: 0 as an immediate abort); aborted completions and APIConnectionTimeoutError normalize to the provider AbortError (series standard).
Zoo Gateway places the entry fast-fail before ensureAuthenticated() so a pre-aborted task surfaces the AbortError instead of an auth failure.
Tests:
Ported the reference abort/timeout completePrompt pass-through tests (signal, timeoutMs incl. 0, and no-options backward compatibility) for all three providers, plus normalization/identity tests for aborted and timed-out completions.
createMessage bridging tests per provider: pre-aborted signal -> rejects with the standardized AbortError before any request work (catalog and SDK both uncalled; unbound additionally asserts the SDK-level rejection identity since its error wrapper preserves main's behavior); abort mid-resolution -> settles on the standardized AbortError before the lookup is released, no late request; detach tests use the reference-identity pattern (the resolution race registers its own "abort" listener, so the bridge is the last registration).
Series and unit
Unit 3/3 of the #1295 split (content source: 62f596c5d); stacks on the shared-util and opencode-go units. Three sibling OpenAI-SDK gateway providers with an identical abort-wiring shape are kept as one unit to avoid tripling the review surface for mechanically identical changes (a+d soft-cap rationale per the split budget; the mutation gate is measured on the unit delta and is green).
Part of the abort-signal series (round 1). Builds on #674, #901, #1008. Addresses #404.
The model-resolution guard, the rejectOnAbort race, and the abort normalization now live once in the shared util (resolveModelWithAbort, unit 1/3) instead of being inlined per provider; all three providers call it and each spec exercises it end-to-end (pre-aborted -> catalog and SDK both uncalled; mid-resolution -> standardized AbortError before the lookup is released, no late request).
The createMessage catches use the wider isRequestAborted condition (aborted signal, DOM AbortError, SDK APIUserAbortError, exact "Request was aborted." message; name/message checks require a real Error instance).
The detach tests assert reference identity on the last "abort" registration, because the resolution race registers its own listener on the same external signal.
Evidence
vitest: 139/139 passing across the three gateway suites (134 changed executable lines, all covered)
Local Stryker mutation gate (unit delta vs own base): 185 valid mutants (≤400), 176 killed, 9 directive-ignored (the per-request bridge's unreachable pre-aborted branch per provider, with invariant-citing proofs), 0 Survived / 0 NoCoverage / 0 Timeout
Updated this round (2026-10-13)
Merged current upstream main into the branch to clear the dirty state. Conflicts: vercel-ai-gateway.ts/zoo-gateway.ts (imports only — main's model-cache fetcher imports plus this branch's abort-signal utility imports, both kept) and unbound.spec.ts (main's new "model catalog" describe block coexists with this branch's appended abort/cancellation suites — both kept).
Verification at this head: 535/535 green across the touched provider specs (unbound, vercel-ai-gateway, zoo-gateway, opencode-go); tsc --noEmit → 0 errors; per-file ESLint (--max-warnings=0) clean; prettier --check clean on touched files.
…utils
Extend src/api/providers/utils/abort-signal.ts with the abort-signal
series helpers used by the gateway providers:
- isRequestAborted(error, signal): wider abort detection - an aborted
signal, a DOM AbortError, the OpenAI/Anthropic SDK APIUserAbortError
(name check), or the exact SDK abort message "Request was aborted." -
trusting name/message only on real Error instances so a plain object
that merely looks like an abort propagates unchanged
- createAbortError(providerName): fresh error satisfying the Task.ts
abort contract (name "AbortError", message ending in "aborted")
- rejectOnAbort(pending, signal, providerName): settle a signal-less
async phase (model discovery) on the provider AbortError when the
signal fires first; the abort listener detaches when pending settles
- resolveModelWithAbort(fetchModel, signal, providerName): run model
resolution inside a cancellation scope - entry fast-fail for a
pre-aborted signal, the rejectOnAbort race while the lookup is
pending, and normalization of abort-flavored lookup failures; any
other resolution failure propagates unchanged
Includes direct unit tests for the resolveModelWithAbort cancellation
scope (pre-aborted fast-fail, no-signal pass-through, mid-resolution
race, abort normalization, non-abort propagation), the
isRequestAborted instanceof tightening tests, and the settle-guard
test utility.
Unit 1/3 of the Zoo-Code-Org#1295 split (content source: 62f596c).
Part of the abort-signal series (round 1). Builds on Zoo-Code-Org#674, Zoo-Code-Org#901, Zoo-Code-Org#1008.
Addresses Zoo-Code-Org#404.
- createMessage: bridge metadata.abortSignal to a per-request
AbortController (Bedrock pattern: pre-aborted guard, once-listener,
detached on completion so a task-scoped signal does not accumulate
listeners); model resolution runs inside the shared
resolveModelWithAbort cancellation scope (pre-aborted fast-fail,
mid-resolution race)
- aborted/timeout requests normalize to the provider AbortError on all
three wire formats (anthropic /v1/messages, responses /v1/responses,
openai chat completions), both pre-stream and mid-stream; non-abort
failures keep the wrapped "Opencode Go completion error:" identity
- completePrompt: forwards abortSignal/timeoutMs to all three SDK
paths (timeoutMs <= 0 omits the SDK timeout option, since the SDK
treats timeout: 0 as an immediate abort); aborted completions and
APIConnectionTimeoutError/APITimeoutError normalize to the provider
AbortError (series standard)
The two inner pre-stream guard mutants (the abort-normalization
condition and its provider-name literal) are documented as provably
equivalent with mutator-specific Stryker directives: createMessage's
outer catch applies the identical isRequestAborted check to the same
controller signal and re-standardizes, so the inner layer's only
unique behavior is the non-abort completion-error wrap (stays
kill-tested).
Unit 2/3 of the Zoo-Code-Org#1295 split (content source: 62f596c); stacks on the
shared-util unit.
Part of the abort-signal series (round 1). Builds on Zoo-Code-Org#674, Zoo-Code-Org#901, Zoo-Code-Org#1008.
Addresses Zoo-Code-Org#404.
…ateway
Each provider's createMessage bridges metadata.abortSignal to a
per-request AbortController (Bedrock pattern: pre-aborted guard,
{ once: true } listener, detached on completion so a task-scoped
signal does not accumulate listeners) and runs model resolution inside
the shared resolveModelWithAbort cancellation scope; aborted requests
(pre-aborted, mid-resolution, mid-stream) normalize to the provider
AbortError while non-abort failures propagate or wrap unchanged.
completePrompt forwards abortSignal/timeoutMs to the OpenAI SDK
(timeoutMs <= 0 omits the SDK timeout option); aborted completions and
APIConnectionTimeoutError normalize to the provider AbortError (series
standard).
Zoo Gateway places the entry fast-fail before ensureAuthenticated() so
a pre-aborted task surfaces the AbortError instead of an auth failure
(pinned by an unauthenticated pre-abort test).
Unit 3/3 of the Zoo-Code-Org#1295 split (content source: 62f596c); stacks on the
shared-util and opencode-go units. Three sibling OpenAI-SDK gateway
providers with an identical abort-wiring shape are kept as one unit to
avoid tripling the review surface for mechanically identical changes
(a+d soft-cap rationale per the split budget; the mutation gate is
measured on the unit delta and is green).
Part of the abort-signal series (round 1). Builds on Zoo-Code-Org#674, Zoo-Code-Org#901, Zoo-Code-Org#1008.
Addresses Zoo-Code-Org#404.
Reviewing files that changed from the base of the PR and between 76f0dc8 and 17975dd.
Files selected for processing: 4
src/api/providers/opencode-go.ts
src/api/providers/unbound.ts
src/api/providers/vercel-ai-gateway.ts
src/api/providers/zoo-gateway.ts
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
Recent review details
Context from checks skipped due to timeout: 16
GitHub Check: CodeRabbit
GitHub Check: platform-unit-test (windows-latest)
GitHub Check: mutation-diff
GitHub Check: extension-host-visual
GitHub Check: invisible-chars
GitHub Check: platform-unit-test (ubuntu-latest)
GitHub Check: webview-visual
GitHub Check: Build test VSIX
GitHub Check: check-translations
GitHub Check: compile
GitHub Check: knip
GitHub Check: theme-fixtures
GitHub Check: dependency-review
GitHub Check: e2e-mock
GitHub Check: Analyze (javascript-typescript)
GitHub Check: Zoo Code / resolve PRs to reconcile
Additional context used
Path-based instructions: 4
Treat model, provider, MCP, path, command, and tool data as untrusted.
CodeRabbit configuration file
Files:
src/api/providers/unbound.ts
src/api/providers/vercel-ai-gateway.ts
src/api/providers/zoo-gateway.ts
src/api/providers/opencode-go.ts
Check strict typing and exhaustive behavior across normal, boundary, error, cancellation, retry, and compatibility paths.
CodeRabbit configuration file
Files:
src/api/providers/unbound.ts
src/api/providers/vercel-ai-gateway.ts
src/api/providers/zoo-gateway.ts
src/api/providers/opencode-go.ts
Verify extension/webview contracts, cancellation and error propagation, VS Code lifecycle correctness, and behavior under retries and partial failure.
CodeRabbit configuration file
Files:
src/api/providers/unbound.ts
src/api/providers/vercel-ai-gateway.ts
src/api/providers/zoo-gateway.ts
src/api/providers/opencode-go.ts
Act as an adversarial second-opinion reviewer.
CodeRabbit configuration file
Files:
src/api/providers/unbound.ts
src/api/providers/vercel-ai-gateway.ts
src/api/providers/zoo-gateway.ts
src/api/providers/opencode-go.ts
Learnings: 1
Common learnings
Learnt from: easonLiangWorldedtech
Repo: Zoo-Code-Org/Zoo-Code PR: 1653
File: src/api/providers/unbound.ts:270-280
Timestamp: 2026-10-04T19:26:43.827Z
Learning: In src/api/providers/zoo-gateway.ts, ZooGatewayHandler.createMessage and ZooGatewayHandler.completePrompt must reject pre-aborted requests with the standardized provider AbortError before ensureAuthenticated runs. A resolveModelWithAbort check after authentication is not equivalent, because an authentication failure must not override cancellation. Regression tests should include a pre-aborted signal with an unauthenticated session.
Additional comments: 4
src/api/providers/opencode-go.ts: 1
44-51: LGTM!
Also applies to: 240-255, 258-279, 284-305, 309-344, 347-398
src/api/providers/unbound.ts: 1
32-39: LGTM!
Also applies to: 194-200, 203-261, 265-273
src/api/providers/vercel-ai-gateway.ts: 1
28-35: LGTM!
Also applies to: 123-129, 131-188, 192-200
src/api/providers/zoo-gateway.ts: 1
31-38: LGTM!
Also applies to: 258-264, 269-269, 329-330, 334-340, 344-351
📝 Summary
Summary by CodeRabbit
Bug Fixes
Canceled requests across OpenCode Go, Unbound, Vercel AI Gateway, and Zoo Gateway now return consistent abort errors, including when canceled before a request, during model lookup, or while streaming.
Prompt completions forward cancellation signals and apply positive timeout settings; zero timeouts are omitted. Timeout errors are reported consistently, while unrelated errors retain their existing behavior.
Streaming requests remove cancellation listeners when finished, helping prevent stale listeners after completion. Anthropic prompt completions also apply the configured maximum-token override.
Four provider handlers now resolve models with abort handling, forward cancellation signals to streaming and completion requests, and normalize recognized abort and timeout errors. Tests cover cancellation timing, listener cleanup, completion options, and stream-frame handling.
Changes: Provider cancellation and timeout handling
Layer / File(s)
Summary
Model resolution and streaming cancellation src/api/providers/opencode-go.ts, src/api/providers/unbound.ts, src/api/providers/vercel-ai-gateway.ts, src/api/providers/zoo-gateway.ts, src/api/providers/__tests__/*.spec.ts
Handlers resolve models with abort handling and bridge caller signals to streaming requests. They normalize recognized cancellations and remove listeners. Tests cover lookup and stream cancellation, listener cleanup, and stream-frame behavior.
Completion cancellation and timeout options src/api/providers/opencode-go.ts, src/api/providers/unbound.ts, src/api/providers/vercel-ai-gateway.ts, src/api/providers/zoo-gateway.ts, src/api/providers/__tests__/*.spec.ts
Completion requests forward abort signals and positive timeouts. They omit nonpositive timeouts and normalize recognized abort and timeout errors. Tests cover request options, cancellation, and calls without options.
sequenceDiagram
participant Caller
participant ProviderHandler
participant ModelResolver
participant ProviderSDK
ProviderHandler->>ModelResolver: Resolve model with caller signal
ModelResolver-->>ProviderHandler: Return model or abort error
ProviderHandler->>ProviderSDK: Start request with bridged signal
Caller->>ProviderSDK: Abort request signal
ProviderSDK-->>ProviderHandler: Return stream or abort error
Loading
Possibly related issues
Zoo-Code-Org/Zoo-Code#2202: Provider calls now settle when cancellation occurs during model resolution. This issue describes the separate behavior of aborting shared discovery after all waiters cancel.
Possibly related PRs
Zoo-Code-Org/Zoo-Code#1652: This PR adds the OpenCode Go request-path changes and listener-cleanup tests also present in this pull request.
Zoo-Code-Org/Zoo-Code#1293: This PR adds abort-bridge and timeout helpers that this pull request reports using across providers.
Zoo-Code-Org/Zoo-Code#1538: This PR adds cancellation during model discovery for Requesty, matching a request-cancellation behavior also covered here.
Merge Risk: Minimal · up to 17975
No actionable blocker is established; the change is mergeable after normal checks.
Security Architecture Review
Security architecture risk:🔵 Low · up to 07aeb
The reviewed paths retain existing authentication and request permissions while honoring cancellation. Remaining uncertainty concerns how quickly in-flight work stops when a consumer exits before a response arrives.
Retained concerns
No architecture-level concerns identified.
Security review details
Security Blast Radius
inferred — The added control affects requests subscribing to the caller's signal. Controllers and completion options are invocation-local rather than stored as handler-wide cancellation state. Reusing a signal can intentionally cancel multiple subscribing requests, but the inspected changes do not grant new credential or tool authority.
Trust Boundaries and Controls
observed — Caller cancellation becomes transport-control state: the shared helper checks the signal before initiating lookup, and provider request paths forward a caller signal or request-local controller signal. These controls do not alter credential selection or convert cancellation into permission to perform protected work.
Resilience and Maintainability Implications
inferred — Immediate resource release from iterator.return() alone while Zoo's initial SDK await is pending remains unverified. The pending-await structure predates this PR, while the PR adds an explicit external-signal cancellation route. This is a bounded cleanup uncertainty, not evidence of newly expanded authority or a verified security regression.
Pre-merge checks: 6 · 2
Failed checks: 2 warnings
Check name
Status
Explanation
Resolution
Regression Evidence
The prior regression finding remains. The changed providers omit SDK timeout unless hasUsableTimeout(timeoutMs) returns true (Unbound: unbound.ts:292; Vercel AI Gateway: vercel-ai-gateway.ts:227…
Add focused completePrompt tests with a negative timeoutMs and assert that the SDK options omit timeout for Unbound, Vercel AI Gateway, Zoo Gateway, and OpenCode Go's Anthropic, Responses, and Chat Completions paths. Where the test su…
Lifecycle Resource Cleanup
The changed Zoo Gateway cancellation path can leave catalog work running after cancellation and duplicate that work on restart. zoo-gateway.ts now wraps this.fetchModel() in `resolveModelWithAbort…
Thread the caller signal through RouterProvider.fetchModel, getModels/refreshModels, ZooGatewayHandler.fetchModels, and getZooGatewayModels into the Axios request. Preserve single-flight behavior for non-auth-scoped providers. For…
Passed checks: 6 passed
Check name
Status
Explanation
Title check
The title clearly summarizes the main change: abort-signal support for the Unbound, Vercel AI Gateway, and Zoo Gateway providers.
Description check
The description explains the implementation, identifies issue #404, and reports test procedures and results. It does not include the template’s completed pre-submission checklist or documentation-impa…
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.
Security Boundaries
The changed provider paths add abort-signal and timeout handling. They do not add secret or PII disclosure, execution of unvalidated input, or a bypass of approval or allowlist controls. The request c…
Persistence Integrity
The reviewed diff changes four provider implementations and their tests. The implementation changes add abort-signal and timeout handling to model lookup and API requests. No changed persistence path,…
Full details: Description check
Explanation
The description explains the implementation, identifies issue #404, and reports test procedures and results. It does not include the template’s completed pre-submission checklist or documentation-impact section, but the main required information is present.
Full details: Security Boundaries
Explanation
The changed provider paths add abort-signal and timeout handling. They do not add secret or PII disclosure, execution of unvalidated input, or a bypass of approval or allowlist controls. The request changes forward signals and usable timeout values to SDK calls. Existing Zoo Gateway authentication checks remain in place for non-aborted requests.
Full details: Persistence Integrity
Explanation
The reviewed diff changes four provider implementations and their tests. The implementation changes add abort-signal and timeout handling to model lookup and API requests. No changed persistence path, write operation, rollback behavior, or persisted default propagation appears in the diff, so the check’s failure conditions are not met.
Full details: Regression Evidence
Explanation
The prior regression finding remains. The changed providers omit SDK timeout unless hasUsableTimeout(timeoutMs) returns true (Unbound: unbound.ts:292; Vercel AI Gateway: vercel-ai-gateway.ts:227; Zoo Gateway: zoo-gateway.ts:374; OpenCode Go: opencode-go.ts:870, 920, 998). The focused completePrompt tests cover positive values and timeoutMs: 0, but none supplies a negative timeoutMs in these provider specs (unbound.spec.ts:406, 426; vercel-ai-gateway.spec.ts:869, 891; zoo-gateway.spec.ts:570, 586; opencode-go.spec.ts:1182, 1378, 2472 are the zero-value cases). The shared helper test covers -5, but it does not verify that each provider omits the SDK timeout. A provider could therefore forward a negative timeout without failing the provider-level tests.
Resolution
Add focused completePrompt tests with a negative timeoutMs and assert that the SDK options omit timeout for Unbound, Vercel AI Gateway, Zoo Gateway, and OpenCode Go's Anthropic, Responses, and Chat Completions paths. Where the test supplies an abort signal, also assert that the signal remains present in the SDK options.
Full details: Lifecycle Resource Cleanup
Explanation
The changed Zoo Gateway cancellation path can leave catalog work running after cancellation and duplicate that work on restart. zoo-gateway.ts now wraps this.fetchModel() in resolveModelWithAbort; rejectOnAbort settles the caller but explicitly leaves the underlying promise running (utils/abort-signal.ts:157-162). RouterProvider.fetchModel starts getModels and refreshModels without a signal (router-provider.ts:76-108). Zoo is auth-scoped, so both cache paths bypass single-flight and call fetchModelsFromProvider without a signal (modelCache.ts:210-236, 421-439). getZooGatewayModels then makes an Axios request with only a 15-second timeout (fetchers/zoo-gateway.ts:36-40). If cancellation occurs during lookup and a new handler starts, its separate modelFetchPromise can launch another catalog request while the first remains active. The new tests release their mocked lookup after asserting cancellation; they do not verify cancellation of the Axios request or prevent overlap.
Resolution
Thread the caller signal through RouterProvider.fetchModel, getModels/refreshModels, ZooGatewayHandler.fetchModels, and getZooGatewayModels into the Axios request. Preserve single-flight behavior for non-auth-scoped providers. For auth-scoped Zoo requests, cancel the catalog request when its last waiter aborts. Add a regression test that aborts a pending Zoo catalog lookup, starts a new handler, and verifies that the canceled lookup is released without overlapping the new request.
Finishing Touches
🧪 Generate unit tests (beta)
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.
ESLint
If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.
src/api/providers/opencode-go.ts
ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.
src/api/providers/unbound.ts
ESLint skipped: the matched ESLint configuration already failed (missing-dependency).
src/api/providers/vercel-ai-gateway.ts
ESLint skipped: the matched ESLint configuration already failed (missing-dependency).
1 others
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.
Thanks for contributing. This comment tracks the review sequence and the next action.
Current step: Awaiting fresh human maintainer or CODEOWNER approval.
Automated review is complete for the latest commit but does not replace human approval.
Review-state labels are managed by this workflow; do not edit them manually. community-approved is managed the same way — do not add or remove it manually. It signals a fresh community code approval for the current head as an advisory priority only; maintainer review is still required.
Conflicts were only in src/api/providers/utils/abort-signal.ts and its spec. Resolved
by keeping main's canonical helper: the branch carried a copy that lacked throwIfAborted
(main's fetchers import it, so the merge broke tsc) and the pre-aborted branch's
unhandled-rejection guard. The PR keeps only its own provider wiring.
Verified on the merged tree: tsc clean, eslint clean, prettier clean, 176 tests green
(abort-signal + unbound + vercel-ai-gateway + zoo-gateway specs).
Co-Authored-By: Claude <noreply@anthropic.com>
Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 8 minutes.
Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 3 minutes.
The CI lint gate (src: pnpm run lint) flags the six mock implementations
that abort internally and never read the request options: rename the
unused second parameter to _options to satisfy
@typescript-eslint/no-unused-vars. No behavior change; specs green.
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.
…sions
Merge follow-ups: the refreshed main lint rule requires hasUsableTimeout/toSdkTimeoutMs instead of forwarding timeoutMs directly (0 aborts immediately, negative/non-finite/fractional throw), applied to completePrompt in opencode-go, unbound, vercel-ai-gateway and zoo-gateway. Also removes Stryker disable comments (repo policy prohibits them; mutation gate rejects new directives) - the covered conditions are equivalent mutants documented on the PR: the pre-abort bridge branches are unreachable behind the entry guard plus rejectOnAbort race, and the inner abort-normalization throw is re-normalized by createMessage outer catch. Remaining 582 provider tests pass; tsc clean.
…roviders
Review follow-up: unbound, zoo-gateway, vercel-ai-gateway and opencode-go use bridgeExternalAbortSignal (pre-abort guard, once-only listener, dispose in finally) with a never-aborting fallback signal, replacing four copies of the inline bridge.
zoo-gateway.ts, unbound.ts, vercel-ai-gateway.ts and opencode-go.ts now use the shared bridgeExternalAbortSignal from utils/abort-signal.ts instead of four copies of the inline controller/listener/pre-abort block:
pre-aborted caller signals abort the request-local signal immediately;
the listener is { once: true } and is detached via the helper's dispose() in every format branch's finally (replacing the repeated removeEventListener calls);
a never-aborting fallback signal is kept when the caller supplies no external signal, preserving the previous always-signal behaviour for the SDK calls.
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.
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.
Wires the external abort signal and per-request timeout into the
completePrompt(non-streaming) andcreateMessage(streaming) paths of the Unbound, Vercel AI Gateway, and Zoo Gateway providers. Stacks on the shared-util and opencode-go units of this split (resolveModelWithAbortinutils/abort-signal.ts).Each provider:
createMessage: bridgesmetadata?.abortSignal(Bedrock pattern: pre-aborted guard,{ once: true }listener, detached on completion so a task-scoped signal does not accumulate listeners) into a per-requestAbortController; model resolution runs inside the sharedresolveModelWithAbortcancellation scope (pre-aborted fast-fail before any catalog/SDK work, mid-resolution race). Aborted requests (pre-aborted, mid-resolution, mid-stream) normalize to the provider AbortError; non-abort failures propagate or wrap unchanged.completePrompt: forwardsabortSignal/timeoutMsto the OpenAI SDK (timeoutMs <= 0omits the SDK timeout option, since the SDK treatstimeout: 0as an immediate abort); aborted completions andAPIConnectionTimeoutErrornormalize to the provider AbortError (series standard).Zoo Gateway places the entry fast-fail before
ensureAuthenticated()so a pre-aborted task surfaces the AbortError instead of an auth failure.Tests:
completePromptpass-through tests (signal, timeoutMs incl. 0, and no-options backward compatibility) for all three providers, plus normalization/identity tests for aborted and timed-out completions.createMessagebridging tests per provider: pre-aborted signal -> rejects with the standardized AbortError before any request work (catalog and SDK both uncalled; unbound additionally asserts the SDK-level rejection identity since its error wrapper preserves main's behavior); abort mid-resolution -> settles on the standardized AbortError before the lookup is released, no late request; detach tests use the reference-identity pattern (the resolution race registers its own "abort" listener, so the bridge is the last registration).Series and unit
Unit 3/3 of the #1295 split (content source:
62f596c5d); stacks on the shared-util and opencode-go units. Three sibling OpenAI-SDK gateway providers with an identical abort-wiring shape are kept as one unit to avoid tripling the review surface for mechanically identical changes (a+d soft-cap rationale per the split budget; the mutation gate is measured on the unit delta and is green).Part of the abort-signal series (round 1). Builds on #674, #901, #1008. Addresses #404.
Review response (maintainer review of #1295)
rejectOnAbortrace, and the abort normalization now live once in the shared util (resolveModelWithAbort, unit 1/3) instead of being inlined per provider; all three providers call it and each spec exercises it end-to-end (pre-aborted -> catalog and SDK both uncalled; mid-resolution -> standardized AbortError before the lookup is released, no late request).createMessagecatches use the widerisRequestAbortedcondition (aborted signal, DOM AbortError, SDK APIUserAbortError, exact "Request was aborted." message; name/message checks require a realErrorinstance).Evidence
Updated this round (2026-10-13)
Merged current upstream
maininto the branch to clear the dirty state. Conflicts:vercel-ai-gateway.ts/zoo-gateway.ts(imports only — main's model-cache fetcher imports plus this branch's abort-signal utility imports, both kept) andunbound.spec.ts(main's new "model catalog" describe block coexists with this branch's appended abort/cancellation suites — both kept).Verification at this head: 535/535 green across the touched provider specs (unbound, vercel-ai-gateway, zoo-gateway, opencode-go);
tsc --noEmit→ 0 errors; per-file ESLint (--max-warnings=0) clean;prettier --checkclean on touched files.