Skip to content

test(providers): add completePrompt signal/timeout tests for all 25 providers#712

Draft
easonLiangWorldedtech wants to merge 14 commits into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:feat/abort-signal-core/complete-prompt-abort
Draft

test(providers): add completePrompt signal/timeout tests for all 25 providers#712
easonLiangWorldedtech wants to merge 14 commits into
Zoo-Code-Org:mainfrom
easonLiangWorldedtech:feat/abort-signal-core/complete-prompt-abort

Conversation

@easonLiangWorldedtech

@easonLiangWorldedtech easonLiangWorldedtech commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR establishes the CompletePromptOptions contract and adds comprehensive test coverage across all 25 API providers, building on top of #701 (RequestConfigBuilder).

#701 introduced the RequestConfigBuilder for SDK-agnostic request configuration. This PR ensures every provider correctly passes abort signals and timeouts through completePrompt.

Scope & Strategy

Phase Focus Status
Phase 1 (This PR) Contract definition (CompletePromptOptions) + Test coverage + Basic signal/timeout forwarding ✅ In Progress
Phase 2 (Follow-up) Internal refactoring to fully leverage RequestConfigBuilder in provider implementations ⏳ Pending

This separation ensures each PR has a single focus: verifying the contract first, then optimizing the implementation.

Changes at a Glance

Metric Value
Files changed 56 files (+1,356 / -143 lines)
Provider test files 25 (all providers covered)
Shared test file 1 (complete-prompt-options.spec.ts)
New tests added 79 it()/test() cases
Provider impls updated 25 files

Test Coverage Breakdown

Each provider test file includes:

  • Signal abort — verifies abort signal is correctly passed through
  • TimeoutMs — verifies timeout is correctly forwarded
  • Backward compatible — works without options (no breaking changes)
  • Signal + Timeout merge — both together where applicable
Provider Tests Added Signal Timeout Backward Compat Merge
anthropic 3
anthropic-vertex 2
bedrock 2
deepseek 4
fireworks 3
gemini 2
gemini-handler 2
lite-llm 3
lmstudio 3
mimo 3
minimax 2
mistral 2
moonshot 2
native-ollama 2
openai-codex-native-tool-calls 2
openai-native 2
openai 4
opencode-go 2
openrouter 3
poe 2
requesty 3
sambanova 3
unbound 3
vercel-ai-gateway 3
vertex 2
vscode-lm 3
xai 2
zai 3
zoo-gateway 3

Shared test file: complete-prompt-options.spec.ts (4 tests) — validates common options behavior across all providers.

Files Changed

Test Files (26 files)

src/api/providers/__tests__/
├── complete-prompt-options.spec.ts    ← NEW: shared options validation
├── anthropic.spec.ts                  ← +70 lines
├── anthropic-vertex.spec.ts           ← +64 lines
├── bedrock.spec.ts                    ← +42 lines
├── deepseek.spec.ts                   ← +41 lines
├── openai.spec.ts                     ← +39 lines
├── vscode-lm.spec.ts                  ← +76 lines (most changes)
├── vercel-ai-gateway.spec.ts          ← +57 lines
├── requesty.spec.ts                   ← +59 lines
├── unbound.spec.ts                    ← +53 lines
└── ... and 14 more provider test files

Provider Implementations (25 files)

All providers updated to support completePrompt(prompt, options) where options includes:

  • signal?: AbortSignal — abort signal passthrough
  • timeoutMs?: number — per-call timeout control

Key files:

src/api/providers/
├── anthropic.ts                       ← +21 lines
├── opencode-go.ts                     ← +44/-8 lines (largest change)
├── vscode-lm.ts                       ← +30 lines
├── minimax.ts                         ← +19 lines
├── openai-native.ts                   ← +19 lines
├── mistral.ts                         ← +15 lines
├── xai.ts                             ← +15 lines
└── ... and 17 more provider files

Utilities (2 files)

src/utils/single-completion-handler.ts   ← TaskSemaphore integration
src/api/index.ts                          ← Re-exports updated

Relationship to other PRs

PR Status Role
#674 Merged ✅ Core plumbing: abortSignal in metadata + Task.ts wiring
#701 Open 🔗 RequestConfigBuilder — unified config construction (Phase 2 dependency)
This PR Open Phase 1: Contract definition + Test coverage

Review Guide

Quick Checklist for Reviewers

  1. Test correctness — Do the signal/timeout assertions properly verify behavior?
  2. Provider implementations — Are completePrompt changes consistent across all 25 files?
  3. Backward compatibility — Does every provider still work without options?
  4. Config builder integration — Is signal merging handled correctly in each provider?

Focus Areas (highest impact)

  • 🔍 opencode-go.ts — Largest diff (+44/-8), Anthropic format branch needs careful review
  • 🔍 vscode-lm.ts — CancellationTokenSource bridging logic
  • 🔍 anthropic.spec.ts — Most complex test file with timeout merge scenarios

What to Skip (low risk)

  • Boilerplate signal forwarding in providers that already had partial support
  • Test files for providers with minimal changes (2 tests each, standard pattern)

Test Plan

  • All provider tests include signal abort and timeout scenarios
  • CI checks pass

Summary by CodeRabbit

  • New Features
    • Prompt completion now accepts optional CompletePromptOptions (abortSignal, timeoutMs) and forwards them per request across supported providers.
    • Added RequestConfigBuilder and re-exported it for fluent, typed request configuration (including abort-signal merging).
  • Documentation
    • Documented RequestConfigBuilder, including usage patterns and signal-merging behavior.
  • Bug Fixes
    • Kept backward compatibility when completion is called without options.
  • Tests
    • Expanded unit coverage to validate the correct two-argument request shape and proper abort/timeout forwarding and combinations across providers.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e31f4910-6a1c-4dd1-a807-95c9da1da5da

📥 Commits

Reviewing files that changed from the base of the PR and between 387fe45 and aca3447.

📒 Files selected for processing (1)
  • src/api/providers/fetchers/__tests__/modelCache.spec.ts

📝 Walkthrough

Walkthrough

Adds CompletePromptOptions, threads it through completion entry points and provider handlers, introduces RequestConfigBuilder, and expands tests for signal, timeout, and no-options behavior.

Changes

completePrompt options propagation

Layer / File(s) Summary
Public contract and entry-point plumbing
src/api/index.ts, src/utils/single-completion-handler.ts, src/api/providers/fake-ai.ts, src/utils/__tests__/enhance-prompt.spec.ts, src/api/providers/__tests__/complete-prompt-options.spec.ts
Adds CompletePromptOptions, updates completion entry points to accept and forward it, and adjusts direct callers and type coverage.
RequestConfigBuilder utility and model cache
src/api/providers/config-builder/request-config-builder.ts, src/api/providers/index.ts, src/api/providers/config-builder/README.md, src/api/providers/fetchers/modelCache.ts, src/api/providers/fetchers/__tests__/modelCache.spec.ts
Introduces RequestConfigBuilder, its helper methods, the public re-export, documentation, and model cache helper coverage.
OpenAI-style request option forwarding
src/api/providers/base-openai-compatible-provider.ts, src/api/providers/openai.ts, src/api/providers/openrouter.ts, src/api/providers/requesty.ts, src/api/providers/lite-llm.ts, src/api/providers/lm-studio.ts, src/api/providers/unbound.ts, src/api/providers/vercel-ai-gateway.ts, src/api/providers/zoo-gateway.ts, src/api/providers/openai-native.ts, src/api/providers/openai-codex.ts, src/api/providers/opencode-go.ts, src/api/providers/xai.ts, src/api/providers/qwen-code.ts, and matching *.spec.ts files
Updates OpenAI-compatible handlers to build request options from signal and timeoutMs, and expands provider tests for two-argument calls and no-options behavior.
Specialized provider option passthrough
src/api/providers/anthropic.ts, src/api/providers/anthropic-vertex.ts, src/api/providers/bedrock.ts, src/api/providers/gemini.ts, src/api/providers/minimax.ts, src/api/providers/mistral.ts, src/api/providers/poe.ts, src/api/providers/native-ollama.ts, src/api/providers/openai-compatible.ts, src/api/providers/vscode-lm.ts, src/core/task/__tests__/Task.spec.ts, and matching *.spec.ts files
Updates the remaining handlers and task tests to accept options, forward supported values, or bridge cancellation through SDK-specific request paths.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related issues

Possibly related PRs

Suggested labels

awaiting-review

Suggested reviewers

  • taltas
  • JamesRobert20
  • navedmerchant
  • hannesrudolph
  • edelauna

Poem

🐇 I hopped through prompts both near and far,
With signals tucked inside each jar,
A timeout blinked, a cancel sang,
The request paths chimed and softly rang,
Now completions travel with their star ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding completePrompt signal/timeout tests across providers.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
src/api/providers/openai-codex.ts (1)

1156-1227: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

timeoutMs is not enforced in this Codex request.

This completePrompt path only wires cancellation. options.timeoutMs is unused, so the non-streaming Codex request can outlive the caller's requested timeout even though the new API surface now exposes that option.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/openai-codex.ts` around lines 1156 - 1227, The
completePrompt flow in openai-codex.ts only forwards cancellation and ignores
options.timeoutMs, so the Codex request can run past the caller’s timeout.
Update completePrompt to enforce timeoutMs alongside the existing abort handling
by creating a timeout-driven abort signal/controller, merging it with the
current signals before the fetch call, and making sure the request is canceled
when the timeout elapses while preserving the existing mergedSignal and
abortController behavior.
src/api/providers/anthropic-vertex.ts (1)

273-302: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Forward or reject timeoutMs here too.

CompletePromptOptions.timeoutMs is unused in this path, so Vertex-backed Anthropic completions do not honor the new per-call timeout contract. That leaves completePrompt behavior inconsistent across providers.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/anthropic-vertex.ts` around lines 273 - 302, The Vertex
Anthropic path in completePrompt is ignoring CompletePromptOptions.timeoutMs, so
per-call timeouts are not honored. Update completePrompt in anthropic-vertex to
forward timeoutMs alongside the existing signal handling when calling
this.client.messages.create, matching the timeout behavior used by other
providers and keeping the CompletePromptOptions contract consistent.
src/api/providers/openai-native.ts (1)

1487-1563: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

The new timeout option is still dropped here.

completePrompt now honors caller abort signals, but options.timeoutMs never affects the responses.create call. That leaves OpenAI Native without the per-call timeout behavior this PR is adding elsewhere.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/openai-native.ts` around lines 1487 - 1563, The new
per-call timeout is not being applied in completePrompt, so the responses.create
request only respects abort signals and ignores options.timeoutMs. Update the
OpenAI Native path in completePrompt to wire the timeout into the request
lifecycle alongside the existing mergedSignal logic, using the same timeout
handling pattern added elsewhere in this provider. Make sure the fix is
localized to the completePrompt method and its requestOptions passed to
responses.create.
src/api/providers/gemini.ts (1)

579-599: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

timeoutMs is still dropped in completePrompt.

Only the abort signal is threaded into httpOptions. Callers that pass CompletePromptOptions.timeoutMs will not get the requested timeout behavior on Gemini requests.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/gemini.ts` around lines 579 - 599, The timeout handling in
completePrompt is incomplete because only options.signal is copied into
httpOptions, so CompletePromptOptions.timeoutMs is ignored. Update the Gemini
request setup in completePrompt to thread timeoutMs through the HTTP options
alongside signal, using the existing httpOpts/promptConfig flow so Gemini
requests honor caller-provided timeouts.
src/api/providers/native-ollama.ts (1)

347-378: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

This provider currently drops CompletePromptOptions entirely.

Accepting _options but ignoring both signal and timeoutMs means abort/timeout callers get no effect at all. Even if the Ollama client cannot cancel the transport, this method still needs caller-visible timeout/abort handling to match the new completePrompt contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/native-ollama.ts` around lines 347 - 378, The
completePrompt implementation in native-ollama ignores CompletePromptOptions, so
callers cannot abort or time out requests. Update completePrompt to honor the
options contract by using signal and timeoutMs from _options in the
native-ollama provider flow, and ensure the client.chat call in completePrompt
still returns promptly with a caller-visible abort/timeout error even if the
Ollama transport itself cannot be canceled.
src/api/providers/bedrock.ts (1)

799-844: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Propagate timeoutMs here as well.

This path forwards options.signal but silently ignores options.timeoutMs, so completePrompt falls back to the client default instead of honoring the caller's per-request timeout. That breaks the new cross-provider CompletePromptOptions contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/bedrock.ts` around lines 799 - 844, Propagate the
per-request timeout through `BedrockProvider.completePrompt` the same way
`options.signal` is already forwarded, since this method currently ignores
`options.timeoutMs` and falls back to the client default. Update the
`completePrompt` call path around `this.client.send` to include the timeout
handling expected by `CompletePromptOptions`, matching the behavior used
elsewhere in the provider so caller-supplied timeouts are honored consistently.
src/api/providers/vscode-lm.ts (1)

578-600: 🎯 Functional Correctness | 🔴 Critical

Move the catch back inside completePrompt.
The method closes before catch, so this block is invalid TypeScript syntax and will not parse.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/vscode-lm.ts` around lines 578 - 600, The `completePrompt`
method is missing its `catch` in the correct scope, which makes the TypeScript
invalid. Move the existing `catch(error: any)` block back inside
`completePrompt`, after the `try/finally` that uses `client.sendRequest` and
`tokenSource.dispose()`, so the method is syntactically complete and still
rethrows the wrapped `VSCode LM completion error`.
🧹 Nitpick comments (3)
src/api/providers/config-builder/README.md (1)

53-54: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Broken relative links to request-config-builder.ts.

This README lives in config-builder/ alongside request-config-builder.ts, so ../request-config-builder.ts:13 and :101 point one directory too high. Use ./request-config-builder.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/config-builder/README.md` around lines 53 - 54, The README
links to RequestConfigBuilder are using the wrong relative path and point one
directory too high. Update the markdown references in the config-builder README
so they point to the local request-config-builder.ts file from the same folder,
keeping the existing symbol references for RequestConfigBuilder and its methods
but changing the path target to the correct relative location.
src/api/providers/__tests__/poe.spec.ts (1)

328-340: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Backward-compat test doesn't actually verify signal is absent.

expect.objectContaining({ model, prompt }) only checks those keys are present and permits additional properties, so this assertion would still pass even if a signal were incorrectly forwarded. If the intent is to confirm no signal leaks through when options are omitted, assert the property is undefined explicitly.

♻️ Stronger assertion for signal absence
 			const result = await handler.completePrompt("test prompt")
 			expect(result).toBe("response")
 			expect(mockGenerateText).toHaveBeenCalledWith(
 				expect.objectContaining({
 					model: mockLanguageModel,
 					prompt: "test prompt",
 				}),
 			)
+			expect(mockGenerateText.mock.calls[0][0]).not.toHaveProperty("signal")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/__tests__/poe.spec.ts` around lines 328 - 340, The
backward-compatibility test in PoeHandler.completePrompt currently only checks
for model and prompt, so it would still pass if signal is unintentionally
forwarded. Update the assertion in poe.spec.ts to explicitly verify that no
signal is present when completePrompt is called without options, using the
existing mockGenerateText expectation so the test fails if a signal leaks
through.
src/api/providers/fake-ai.ts (1)

78-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the new contract type-checked.

this.ai is already typed as FakeAI, so the as any cast just disables compile-time enforcement of the updated completePrompt(prompt, options) signature for test doubles. Calling this.ai.completePrompt(prompt, options) directly keeps that contract honest.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/fake-ai.ts` around lines 78 - 79, The
`FakeAI.completePrompt` implementation is bypassing the typed contract by
casting `this.ai` to `any`, which defeats compile-time checking of the new
`completePrompt(prompt, options)` signature. Update the `completePrompt` method
in `FakeAI` to call `this.ai.completePrompt(prompt, options)` directly so the
`FakeAI` type remains enforced for test doubles.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/__tests__/anthropic.spec.ts`:
- Around line 505-520: The `handler.completePrompt` merge test only checks that
`controller.signal` is forwarded, so it can still pass even if `timeoutMs` is
ignored. Tighten the test in `anthropic.spec.ts` by asserting the merged abort
behavior from `completePrompt`/`mockCreate`: verify the signal passed to
`mockCreate` is a distinct merged signal that aborts after the timeout window,
or that it aborts when the timeout elapses even without the controller being
aborted.

In `@src/api/providers/__tests__/native-ollama.spec.ts`:
- Around line 238-245: The native Ollama test currently only checks a partial
payload with objectContaining, so it can still pass if a signal property is
present. Harden the expectation in native-ollama.spec.ts around mockChat by
asserting the request payload does not include signal explicitly, using the
existing mockChat assertion block and the same model/messages/options fields as
anchors. Keep the current positive checks, but add a separate negative assertion
on the chat call argument so any forwarded signal option causes the test to
fail.

In `@src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts`:
- Around line 551-553: The test around the mock fetch call in
openai-codex-native-tool-calls.spec should assert the exact AbortSignal instance
instead of only checking that a signal property exists. Update the expectation
on mockFetch.mock.calls[0] so it verifies the passed request options contain the
same signal object that was provided to the API path, using the fetchCallArgs
variable and the surrounding test setup to compare identity rather than property
presence.

In `@src/api/providers/anthropic.ts`:
- Around line 401-416: The completePrompt method in anthropic.ts handles abort
signals but still ignores per-call timeoutMs, so update the client call path to
either pass the timeout through using the existing request options or explicitly
reject unsupported timeoutMs values. Use completePrompt and
this.client.messages.create as the main touchpoints, and make sure the behavior
matches the new CompletePromptOptions contract consistently with signal
handling.

In `@src/api/providers/base-openai-compatible-provider.ts`:
- Around line 229-238: Preserve explicit timeout values in the provider request
builder: the truthy check in base-openai-compatible-provider’s completePrompt
path drops timeoutMs = 0, so change the guard to forward any defined timeout
value while still omitting only undefined/null inputs. Apply the same fix
anywhere the PR added similar timeout propagation logic in other completePrompt
implementations, and verify RequestOptions.timeout is set from options.timeoutMs
even when it is zero.

In `@src/api/providers/config-builder/README.md`:
- Around line 200-230: The README documentation for `mergeAbortSignals` is
inconsistent with `request-config-builder.ts` and currently documents the
secondary-aborted bug. Update the behavior description to match the real
`mergeAbortSignals` contract: if `secondarySignal` is missing or already
aborted, the returned signal should reflect the correct abort state instead of
being described as `primarySignal` unchanged, and the primary-aborted branch
should be documented as returning the primary signal directly. Keep the table
and the `mergeAbortSignals` summary aligned with the implementation in
`request-config-builder.ts`.

In `@src/api/providers/config-builder/request-config-builder.ts`:
- Around line 119-134: The mergeAbortSignals method in RequestConfigBuilder is
returning the primary signal when secondarySignal is already aborted, which
breaks the “any aborted signal aborts the result” contract. Update
mergeAbortSignals so it returns an already-aborted signal whenever either
primarySignal or secondarySignal is aborted, and keep the listener-based merged
AbortController path only for the case where both signals are still active. Make
sure the fix is applied in mergeAbortSignals and preserves the existing abort
propagation behavior for both signals.

In `@src/api/providers/minimax.ts`:
- Around line 292-304: The completePrompt implementation in Minimax still
ignores timeoutMs, so the request can exceed the caller’s deadline. Update
completePrompt to honor CompletePromptOptions.timeoutMs in addition to signal by
wiring both into the client.messages.create call, using the existing options
handling in completePrompt and the MiniMax client request path so non-streaming
completions are aborted when the timeout is reached.

In `@src/api/providers/mistral.ts`:
- Around line 196-207: The completePrompt flow in mistral.ts is dropping the
caller’s timeout setting, so requests can outlive the deadline. Update the
Mistral provider’s completePrompt method to translate options.timeoutMs into a
request timeout/abort path and pass it through alongside the existing signal
handling when calling this.client.chat.complete. Make sure the timeout behavior
matches the contract used by other providers in the same completePrompt
implementation.

In `@src/api/providers/openai-compatible.ts`:
- Around line 200-208: The per-call timeout override is not being passed through
in completePrompt, so callers using options.timeoutMs still fall back to the
provider default. Update the completePrompt method in openai-compatible.ts to
forward the timeout override into the generateText call alongside
options.signal, using the existing CompletePromptOptions shape and the
getLanguageModel/getMaxOutputTokens flow.

In `@src/api/providers/opencode-go.ts`:
- Around line 491-509: The Anthropic-format path in completePrompt currently
ignores timeoutMs, unlike the OpenAI-format branch, so add timeout handling here
as well. Update the this.anthropicClient.messages.create call path to forward
options.timeoutMs when supported, or explicitly reject/fail fast in the
Anthropic branch if the timeout cannot be applied. Use the completePrompt method
and the anthropicClient.messages.create call site to locate the change.

In `@src/api/providers/poe.ts`:
- Around line 137-143: The Poe completePrompt implementation in completePrompt
currently forwards only options.signal, so CompletePromptOptions.timeoutMs is
being ignored. Update this method to apply the per-request timeout behavior as
well, using the same timeout/abort handling pattern used elsewhere in the
provider API, and ensure generateText receives both the signal and
timeout-derived abort control when options.timeoutMs is provided.

In `@src/api/providers/xai.ts`:
- Around line 145-156: The xAI request path in completePrompt still ignores the
per-request timeout option, so update the request setup in xai.ts to forward
options.timeoutMs along with options.signal when calling
this.client.responses.create. Use the completePrompt method and the
client.responses.create invocation as the integration point, and ensure the
timeout is translated into the request options in the same way the new API
contract expects.

---

Outside diff comments:
In `@src/api/providers/anthropic-vertex.ts`:
- Around line 273-302: The Vertex Anthropic path in completePrompt is ignoring
CompletePromptOptions.timeoutMs, so per-call timeouts are not honored. Update
completePrompt in anthropic-vertex to forward timeoutMs alongside the existing
signal handling when calling this.client.messages.create, matching the timeout
behavior used by other providers and keeping the CompletePromptOptions contract
consistent.

In `@src/api/providers/bedrock.ts`:
- Around line 799-844: Propagate the per-request timeout through
`BedrockProvider.completePrompt` the same way `options.signal` is already
forwarded, since this method currently ignores `options.timeoutMs` and falls
back to the client default. Update the `completePrompt` call path around
`this.client.send` to include the timeout handling expected by
`CompletePromptOptions`, matching the behavior used elsewhere in the provider so
caller-supplied timeouts are honored consistently.

In `@src/api/providers/gemini.ts`:
- Around line 579-599: The timeout handling in completePrompt is incomplete
because only options.signal is copied into httpOptions, so
CompletePromptOptions.timeoutMs is ignored. Update the Gemini request setup in
completePrompt to thread timeoutMs through the HTTP options alongside signal,
using the existing httpOpts/promptConfig flow so Gemini requests honor
caller-provided timeouts.

In `@src/api/providers/native-ollama.ts`:
- Around line 347-378: The completePrompt implementation in native-ollama
ignores CompletePromptOptions, so callers cannot abort or time out requests.
Update completePrompt to honor the options contract by using signal and
timeoutMs from _options in the native-ollama provider flow, and ensure the
client.chat call in completePrompt still returns promptly with a caller-visible
abort/timeout error even if the Ollama transport itself cannot be canceled.

In `@src/api/providers/openai-codex.ts`:
- Around line 1156-1227: The completePrompt flow in openai-codex.ts only
forwards cancellation and ignores options.timeoutMs, so the Codex request can
run past the caller’s timeout. Update completePrompt to enforce timeoutMs
alongside the existing abort handling by creating a timeout-driven abort
signal/controller, merging it with the current signals before the fetch call,
and making sure the request is canceled when the timeout elapses while
preserving the existing mergedSignal and abortController behavior.

In `@src/api/providers/openai-native.ts`:
- Around line 1487-1563: The new per-call timeout is not being applied in
completePrompt, so the responses.create request only respects abort signals and
ignores options.timeoutMs. Update the OpenAI Native path in completePrompt to
wire the timeout into the request lifecycle alongside the existing mergedSignal
logic, using the same timeout handling pattern added elsewhere in this provider.
Make sure the fix is localized to the completePrompt method and its
requestOptions passed to responses.create.

In `@src/api/providers/vscode-lm.ts`:
- Around line 578-600: The `completePrompt` method is missing its `catch` in the
correct scope, which makes the TypeScript invalid. Move the existing
`catch(error: any)` block back inside `completePrompt`, after the `try/finally`
that uses `client.sendRequest` and `tokenSource.dispose()`, so the method is
syntactically complete and still rethrows the wrapped `VSCode LM completion
error`.

---

Nitpick comments:
In `@src/api/providers/__tests__/poe.spec.ts`:
- Around line 328-340: The backward-compatibility test in
PoeHandler.completePrompt currently only checks for model and prompt, so it
would still pass if signal is unintentionally forwarded. Update the assertion in
poe.spec.ts to explicitly verify that no signal is present when completePrompt
is called without options, using the existing mockGenerateText expectation so
the test fails if a signal leaks through.

In `@src/api/providers/config-builder/README.md`:
- Around line 53-54: The README links to RequestConfigBuilder are using the
wrong relative path and point one directory too high. Update the markdown
references in the config-builder README so they point to the local
request-config-builder.ts file from the same folder, keeping the existing symbol
references for RequestConfigBuilder and its methods but changing the path target
to the correct relative location.

In `@src/api/providers/fake-ai.ts`:
- Around line 78-79: The `FakeAI.completePrompt` implementation is bypassing the
typed contract by casting `this.ai` to `any`, which defeats compile-time
checking of the new `completePrompt(prompt, options)` signature. Update the
`completePrompt` method in `FakeAI` to call `this.ai.completePrompt(prompt,
options)` directly so the `FakeAI` type remains enforced for test doubles.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a551a1e6-63c3-4248-b88e-d3db1412f58a

📥 Commits

Reviewing files that changed from the base of the PR and between e8acc6a and fe4adfc.

📒 Files selected for processing (60)
  • src/api/index.ts
  • src/api/providers/__tests__/anthropic-vertex.spec.ts
  • src/api/providers/__tests__/anthropic.spec.ts
  • src/api/providers/__tests__/bedrock.spec.ts
  • src/api/providers/__tests__/complete-prompt-options.spec.ts
  • src/api/providers/__tests__/deepseek.spec.ts
  • src/api/providers/__tests__/fireworks.spec.ts
  • src/api/providers/__tests__/gemini-handler.spec.ts
  • src/api/providers/__tests__/gemini.spec.ts
  • src/api/providers/__tests__/lite-llm.spec.ts
  • src/api/providers/__tests__/lmstudio.spec.ts
  • src/api/providers/__tests__/mimo.spec.ts
  • src/api/providers/__tests__/minimax.spec.ts
  • src/api/providers/__tests__/mistral.spec.ts
  • src/api/providers/__tests__/moonshot.spec.ts
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts
  • src/api/providers/__tests__/openai-native.spec.ts
  • src/api/providers/__tests__/openai.spec.ts
  • src/api/providers/__tests__/opencode-go.spec.ts
  • src/api/providers/__tests__/openrouter.spec.ts
  • src/api/providers/__tests__/poe.spec.ts
  • src/api/providers/__tests__/request-config-builder.spec.ts
  • src/api/providers/__tests__/requesty.spec.ts
  • src/api/providers/__tests__/sambanova.spec.ts
  • src/api/providers/__tests__/unbound.spec.ts
  • src/api/providers/__tests__/vercel-ai-gateway.spec.ts
  • src/api/providers/__tests__/vertex.spec.ts
  • src/api/providers/__tests__/vscode-lm.spec.ts
  • src/api/providers/__tests__/xai.spec.ts
  • src/api/providers/__tests__/zai.spec.ts
  • src/api/providers/__tests__/zoo-gateway.spec.ts
  • src/api/providers/anthropic-vertex.ts
  • src/api/providers/anthropic.ts
  • src/api/providers/base-openai-compatible-provider.ts
  • src/api/providers/bedrock.ts
  • src/api/providers/config-builder/README.md
  • src/api/providers/config-builder/request-config-builder.ts
  • src/api/providers/fake-ai.ts
  • src/api/providers/gemini.ts
  • src/api/providers/index.ts
  • src/api/providers/lite-llm.ts
  • src/api/providers/lm-studio.ts
  • src/api/providers/minimax.ts
  • src/api/providers/mistral.ts
  • src/api/providers/native-ollama.ts
  • src/api/providers/openai-codex.ts
  • src/api/providers/openai-compatible.ts
  • src/api/providers/openai-native.ts
  • src/api/providers/openai.ts
  • src/api/providers/opencode-go.ts
  • src/api/providers/openrouter.ts
  • src/api/providers/poe.ts
  • src/api/providers/requesty.ts
  • src/api/providers/unbound.ts
  • src/api/providers/vercel-ai-gateway.ts
  • src/api/providers/vscode-lm.ts
  • src/api/providers/xai.ts
  • src/api/providers/zoo-gateway.ts
  • src/utils/single-completion-handler.ts

Comment thread src/api/providers/__tests__/anthropic.spec.ts
Comment thread src/api/providers/__tests__/native-ollama.spec.ts
Comment thread src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts
Comment thread src/api/providers/anthropic.ts
Comment thread src/api/providers/base-openai-compatible-provider.ts Outdated
Comment thread src/api/providers/openai-compatible.ts Outdated
Comment thread src/api/providers/opencode-go.ts
Comment thread src/api/providers/poe.ts Outdated
Comment thread src/api/providers/vscode-lm.ts
Comment thread src/api/providers/xai.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/openai-compatible.ts`:
- Around line 210-217: The abort handling in the OpenAI-compatible provider
currently drops timeoutMs whenever options.signal is present, so merge both
inputs instead of choosing one. Update the logic in openai-compatible.ts around
generateOptions.abortSignal to combine options.signal and options.timeoutMs
using RequestConfigBuilder.mergeAbortSignals (or the same equivalent helper used
elsewhere), so the generated request keeps both cancellation sources active.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a07d2d67-353b-4eaa-9af5-b73e2665bcd2

📥 Commits

Reviewing files that changed from the base of the PR and between d9536ad and 02aeaa6.

📒 Files selected for processing (17)
  • src/api/providers/__tests__/anthropic.spec.ts
  • src/api/providers/__tests__/bedrock.spec.ts
  • src/api/providers/__tests__/moonshot.spec.ts
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts
  • src/api/providers/__tests__/poe.spec.ts
  • src/api/providers/__tests__/request-config-builder.spec.ts
  • src/api/providers/anthropic.ts
  • src/api/providers/base-openai-compatible-provider.ts
  • src/api/providers/config-builder/request-config-builder.ts
  • src/api/providers/minimax.ts
  • src/api/providers/mistral.ts
  • src/api/providers/openai-compatible.ts
  • src/api/providers/opencode-go.ts
  • src/api/providers/poe.ts
  • src/api/providers/vscode-lm.ts
  • src/api/providers/xai.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • src/api/providers/minimax.ts
  • src/api/providers/poe.ts
  • src/api/providers/tests/moonshot.spec.ts
  • src/api/providers/tests/native-ollama.spec.ts
  • src/api/providers/tests/bedrock.spec.ts
  • src/api/providers/tests/poe.spec.ts
  • src/api/providers/base-openai-compatible-provider.ts
  • src/api/providers/opencode-go.ts
  • src/api/providers/vscode-lm.ts
  • src/api/providers/mistral.ts
  • src/api/providers/config-builder/request-config-builder.ts
  • src/api/providers/tests/request-config-builder.spec.ts

Comment thread src/api/providers/openai-compatible.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/api/providers/openai-compatible.ts (1)

211-232: 🩺 Stability & Availability | 🟠 Major

Handle pre-aborted signals and clear the merged timeout

options.signal.addEventListener("abort", ...) won’t fire for an already-aborted signal, so the merged controller can miss immediate cancellation. The timeout also stays pending after generateText returns unless the external signal aborts. Add an options.signal.aborted guard and clean up the timer/listener in finally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/openai-compatible.ts` around lines 211 - 232, The
abort/timeout merge in openai-compatible.ts’s generateText flow does not handle
already-aborted signals and can leave the merged timeout pending after the
request completes. Update the logic around the options.signal / timeoutMs
handling to check options.signal.aborted before attaching the listener, and
ensure the merged controller’s timer and abort listener are always cleaned up in
a finally block after generateText. Keep the fix localized to the
generateOptions.abortSignal setup and the surrounding await
generateText(generateOptions) call.
🧹 Nitpick comments (1)
src/api/providers/__tests__/vscode-lm.spec.ts (1)

618-662: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen these timeout tests with cancellation-path assertions (not just call existence).

toHaveBeenCalled() alone won’t catch regressions where timeoutMs/merged signal wiring is ignored; assert the cancellation token/bridging side effects explicitly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/__tests__/vscode-lm.spec.ts` around lines 618 - 662, The
timeout-related tests in vscodelm.spec are only checking that completePrompt
calls sendRequest, which won’t detect regressions in the cancellation wiring.
Update the tests around completePrompt and the timeout/abort handling to assert
the actual cancellation-path side effects for timeoutMs and the combined signal
case, using the mocked sendRequest invocation and any timeout/abort bridging
behavior so the test verifies that the cancellation token is created and passed
through correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/api/providers/openai-compatible.ts`:
- Around line 211-232: The abort/timeout merge in openai-compatible.ts’s
generateText flow does not handle already-aborted signals and can leave the
merged timeout pending after the request completes. Update the logic around the
options.signal / timeoutMs handling to check options.signal.aborted before
attaching the listener, and ensure the merged controller’s timer and abort
listener are always cleaned up in a finally block after generateText. Keep the
fix localized to the generateOptions.abortSignal setup and the surrounding await
generateText(generateOptions) call.

---

Nitpick comments:
In `@src/api/providers/__tests__/vscode-lm.spec.ts`:
- Around line 618-662: The timeout-related tests in vscodelm.spec are only
checking that completePrompt calls sendRequest, which won’t detect regressions
in the cancellation wiring. Update the tests around completePrompt and the
timeout/abort handling to assert the actual cancellation-path side effects for
timeoutMs and the combined signal case, using the mocked sendRequest invocation
and any timeout/abort bridging behavior so the test verifies that the
cancellation token is created and passed through correctly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 76223aa0-26d4-4737-be03-b872b7252b71

📥 Commits

Reviewing files that changed from the base of the PR and between 02aeaa6 and 39c1247.

📒 Files selected for processing (12)
  • src/api/providers/__tests__/anthropic.spec.ts
  • src/api/providers/__tests__/gemini.spec.ts
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts
  • src/api/providers/__tests__/openai-native.spec.ts
  • src/api/providers/__tests__/opencode-go.spec.ts
  • src/api/providers/__tests__/vercel-ai-gateway.spec.ts
  • src/api/providers/__tests__/vscode-lm.spec.ts
  • src/api/providers/config-builder/README.md
  • src/api/providers/openai-compatible.ts
  • src/api/providers/poe.ts
  • src/api/providers/vercel-ai-gateway.ts
💤 Files with no reviewable changes (1)
  • src/api/providers/tests/openai-codex-native-tool-calls.spec.ts
✅ Files skipped from review due to trivial changes (1)
  • src/api/providers/config-builder/README.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/api/providers/poe.ts
  • src/api/providers/tests/vercel-ai-gateway.spec.ts
  • src/api/providers/tests/anthropic.spec.ts
  • src/api/providers/tests/opencode-go.spec.ts
  • src/api/providers/vercel-ai-gateway.ts
  • src/api/providers/tests/native-ollama.spec.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/__tests__/poe.spec.ts`:
- Around line 378-388: The assertion in PoeHandler completePrompt is
tautological because abortSignal is never an AbortController, so it does not
verify merged-signal behavior. Update the test in poe.spec.ts to compare
callArgs.abortSignal against the original controller.signal and assert they are
not the same object while still checking it is defined, using completePrompt and
mockGenerateText to confirm the handler creates a distinct merged AbortSignal
when both signal and timeoutMs are provided.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 930311e2-7b14-4203-8aca-aea1b3077ad6

📥 Commits

Reviewing files that changed from the base of the PR and between 39c1247 and 2b63906.

📒 Files selected for processing (5)
  • src/api/providers/__tests__/minimax.spec.ts
  • src/api/providers/__tests__/mistral.spec.ts
  • src/api/providers/__tests__/moonshot.spec.ts
  • src/api/providers/__tests__/poe.spec.ts
  • src/api/providers/__tests__/xai.spec.ts

Comment thread src/api/providers/__tests__/poe.spec.ts
@easonLiangWorldedtech easonLiangWorldedtech force-pushed the feat/abort-signal-core/complete-prompt-abort branch 2 times, most recently from d0d5d8f to 8fe2b1c Compare June 24, 2026 16:29
@edelauna

Copy link
Copy Markdown
Contributor

I'll review more in depth once #701 lands

@easonLiangWorldedtech easonLiangWorldedtech marked this pull request as draft June 26, 2026 15:14
@easonLiangWorldedtech easonLiangWorldedtech force-pushed the feat/abort-signal-core/complete-prompt-abort branch from 8fe2b1c to b33e17c Compare June 26, 2026 16:47
@easonLiangWorldedtech easonLiangWorldedtech marked this pull request as ready for review June 26, 2026 16:48
@easonLiangWorldedtech easonLiangWorldedtech marked this pull request as draft June 26, 2026 17:56
@easonLiangWorldedtech easonLiangWorldedtech marked this pull request as ready for review June 26, 2026 19:38
…nfiguration

Body: Implement generic request configuration builder with chainable methods (addAbortSignal, addHeaders, setOption), static factory methods (fromMetadata, mergeAbortSignals), and 40 unit tests.
…ls early-abort

- Fix README TOC: change #how-mergesignals-works to
  #how-mergeabortsignals-works to match the actual heading anchor
- Simplify mergeAbortSignals: return primarySignal directly when it's
  already aborted instead of creating a new AbortController
…onfigBuilder (Zoo-Code-Org#615)

- Add default empty object parameter to addHeaders() so calling with
  undefined no longer throws TypeError from Object.keys(undefined)
- Reorder mergeAbortSignals to check primarySignal.aborted before
  allocating AbortController, preventing unnecessary controller creation
…roviders

- anthropic.spec.ts: timeout trigger test + signal instance verification

- native-ollama.spec.ts: explicit assertion no second arg passed (no signal forwarding)

- openai-codex-native-tool-calls.spec.ts: removed weak toHaveProperty(signal) assertion

- vercel-ai-gateway.spec.ts: temperature test uses correct undefined second arg

fix: add timeoutMs forwarding to completePrompt methods

- vercel-ai-gateway.ts: use Object.keys(createOptions).length > 0 check instead of truthy check

- poe.ts: merge signal and timeoutMs properly with combined abort logic

- config-builder/README.md: update documentation for mergeAbortSignals behavior

test: add timeoutMs coverage for poe, moonshot, minimax, mistral, xai providers

- poe.spec.ts: signal+timeoutMs merge, timeoutMs only, timeoutMs=0 cases

- moonshot.spec.ts: same timeoutMs tests for openai-compatible pattern

- minimax.spec.ts: signal+timeoutMs, timeoutMs only, truthy check behavior

- mistral.spec.ts: same timeoutMs coverage

- xai.spec.ts: signal+timeoutMs, timeoutMs only, truthy check behavior

test: add timeoutMs coverage for anthropic-vertex, base-openai-compatible, bedrock, openai-native

- anthropic-vertex.spec.ts: signal passing test (no timeoutMs support)

- base-openai-compatible-provider-timeout.spec.ts: completePrompt with signal+timeoutMs, timeoutMs only, truthy check behavior

- bedrock.spec.ts: timeoutMs coverage for adaptive thinking path

- openai-native.spec.ts: signal and timeoutMs merging tests

test: add signal+timeoutMs merge tests for fireworks, lite-llm, lmstudio

- fireworks.spec.ts: added merge signal and timeoutMs together test

- lite-llm.spec.ts: added same combined signal+timeoutMs test

- lmstudio.spec.ts: aligned with same abort signal pattern

fix: replace tautological assertion in poe.spec.ts

- poe.spec.ts: completePrompt should prefer signal over timeoutMs test now asserts abortSignal is a distinct AbortSignal from controller.signal instead of always-true instanceof check

test: add missing error catch and timeout cleanup tests

- vscode-lm.spec.ts: added 'should handle errors in completePrompt' test

- poe.spec.ts: added 'completePrompt should clear timeout when user signal aborts' test

- opencode-go.spec.ts: added OpenAI path completePrompt tests (signal, timeoutMs, merged)
@easonLiangWorldedtech easonLiangWorldedtech force-pushed the feat/abort-signal-core/complete-prompt-abort branch from 5f2900d to 8b83fda Compare June 26, 2026 19:41
@easonLiangWorldedtech

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/api/providers/fetchers/__tests__/modelCache.spec.ts (1)

474-485: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Strengthen writeModels assertion to verify serialization/path.

Since safeWriteJson is mocked, resolves.toBeUndefined() passes almost unconditionally and doesn't exercise the function's actual contract: building the ${router}_models.json filename and forwarding the data payload. Assert the mock was called with the expected filename and data.

♻️ Suggested stronger assertion
 		await expect(writeModels("openrouter", mockModels)).resolves.toBeUndefined()
+		expect(safeWriteJson).toHaveBeenCalledWith(
+			expect.stringContaining("openrouter_models.json"),
+			mockModels,
+		)

As per coding guidelines: "Use package-local unit tests for ... serialization, request construction ...".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/fetchers/__tests__/modelCache.spec.ts` around lines 474 -
485, The writeModels test only checks for a resolved promise, which is too weak
because safeWriteJson is mocked. Update the writeModels spec to assert the mock
receives the expected ${router}_models.json filename and the same model payload,
so the test verifies serialization/path construction instead of just completion.
Use the writeModels and safeWriteJson symbols in
src/api/providers/fetchers/__tests__/modelCache.spec.ts to locate the assertion.

Source: Coding guidelines

src/api/providers/qwen-code.ts (1)

330-330: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer a top-level named import over an inline import(...) type.

Other OpenAI-compatible providers import CompletePromptOptions from ../index directly; the inline import("../index").CompletePromptOptions here is inconsistent and harder to read. Consider importing it normally.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/qwen-code.ts` at line 330, The completePrompt method in
qwen-code.ts uses an inline import type for CompletePromptOptions, which is
inconsistent with the other OpenAI-compatible providers. Update the provider
module to use a top-level named import from ../index and reference
CompletePromptOptions directly in completePrompt so the signature matches the
rest of the codebase and is easier to read.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/__tests__/lmstudio.spec.ts`:
- Around line 174-182: Add a package-local unit test in the lmstudio spec to
cover the zero-timeout path, since LmStudioHandler.completePrompt currently
relies on a truthy check and may drop timeoutMs: 0 instead of forwarding it.
Extend the existing timeout forwarding test in completePrompt to call the
handler with { timeoutMs: 0 } and assert that mockCreate receives { timeout: 0
}, so the regression is caught alongside the current nonzero timeout case.

In `@src/api/providers/__tests__/poe.spec.ts`:
- Around line 390-401: The test name in PoeHandler’s completePrompt suite does
not match the behavior it verifies, since it never aborts the AbortController
and therefore does not cover timeout cleanup. Update the test in poe.spec.ts to
actually trigger controller.abort(), then assert the merged abortSignal behavior
and that the timeout is cleared or the signal is aborted as intended. Use the
existing completePrompt and mockGenerateText setup to keep the check focused on
the abort/timeout path.

In `@src/api/providers/opencode-go.ts`:
- Around line 498-500: The timeout override in opencode-go is using a truthy
check, so a caller-supplied timeoutMs of 0 is ignored and the SDK default is
used instead. Update the option handling in the relevant request-building paths
(the timeout assignment near the current requestOptions logic and the second
provider path mentioned in the review) to check for explicit presence of
timeoutMs rather than truthiness, so zero is treated as an intentional value and
applied by both code paths.

In `@src/api/providers/poe.ts`:
- Around line 144-166: The merged abort handling in `generateText` setup leaks
the timeout and misses already-aborted input signals. Update the `abortSignal +
timeoutMs` branch in `src/api/providers/poe.ts` so the timeout is always cleared
in a `finally` after `generateText(generateOptions)` completes, and ensure a
pre-aborted `options.abortSignal` immediately aborts the merged controller
before the request starts. Use the existing
`RequestConfigBuilder.mergeAbortSignals` behavior as the reference for the
correct merging semantics.

In `@src/api/providers/qwen-code.ts`:
- Around line 341-353: The timeout guard in the Qwen code provider currently
uses a truthy check, which drops an explicit timeoutMs value of 0 and diverges
from the base provider behavior. Update the fetchOptions setup in qwen-code.ts
to gate timeout assignment with an explicit undefined check, matching the logic
used by the base OpenAI-compatible provider and keeping
callApiWithRetry/client.chat.completions.create behavior consistent.

---

Nitpick comments:
In `@src/api/providers/fetchers/__tests__/modelCache.spec.ts`:
- Around line 474-485: The writeModels test only checks for a resolved promise,
which is too weak because safeWriteJson is mocked. Update the writeModels spec
to assert the mock receives the expected ${router}_models.json filename and the
same model payload, so the test verifies serialization/path construction instead
of just completion. Use the writeModels and safeWriteJson symbols in
src/api/providers/fetchers/__tests__/modelCache.spec.ts to locate the assertion.

In `@src/api/providers/qwen-code.ts`:
- Line 330: The completePrompt method in qwen-code.ts uses an inline import type
for CompletePromptOptions, which is inconsistent with the other
OpenAI-compatible providers. Update the provider module to use a top-level named
import from ../index and reference CompletePromptOptions directly in
completePrompt so the signature matches the rest of the codebase and is easier
to read.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d58847bd-768c-4020-a9cf-a6bcdc19e811

📥 Commits

Reviewing files that changed from the base of the PR and between 39c1247 and 6c2154f.

📒 Files selected for processing (68)
  • src/api/index.ts
  • src/api/providers/__tests__/anthropic-vertex.spec.ts
  • src/api/providers/__tests__/anthropic.spec.ts
  • src/api/providers/__tests__/base-openai-compatible-provider-timeout.spec.ts
  • src/api/providers/__tests__/bedrock.spec.ts
  • src/api/providers/__tests__/complete-prompt-options.spec.ts
  • src/api/providers/__tests__/deepseek.spec.ts
  • src/api/providers/__tests__/fireworks.spec.ts
  • src/api/providers/__tests__/gemini-handler.spec.ts
  • src/api/providers/__tests__/gemini.spec.ts
  • src/api/providers/__tests__/lite-llm.spec.ts
  • src/api/providers/__tests__/lmstudio-native-tools.spec.ts
  • src/api/providers/__tests__/lmstudio.spec.ts
  • src/api/providers/__tests__/mimo.spec.ts
  • src/api/providers/__tests__/minimax.spec.ts
  • src/api/providers/__tests__/mistral.spec.ts
  • src/api/providers/__tests__/moonshot.spec.ts
  • src/api/providers/__tests__/native-ollama.spec.ts
  • src/api/providers/__tests__/openai-codex-native-tool-calls.spec.ts
  • src/api/providers/__tests__/openai-native.spec.ts
  • src/api/providers/__tests__/openai.spec.ts
  • src/api/providers/__tests__/opencode-go.spec.ts
  • src/api/providers/__tests__/openrouter.spec.ts
  • src/api/providers/__tests__/poe.spec.ts
  • src/api/providers/__tests__/qwen-code-native-tools.spec.ts
  • src/api/providers/__tests__/request-config-builder.spec.ts
  • src/api/providers/__tests__/requesty.spec.ts
  • src/api/providers/__tests__/sambanova.spec.ts
  • src/api/providers/__tests__/unbound.spec.ts
  • src/api/providers/__tests__/vercel-ai-gateway.spec.ts
  • src/api/providers/__tests__/vertex.spec.ts
  • src/api/providers/__tests__/vscode-lm.spec.ts
  • src/api/providers/__tests__/xai.spec.ts
  • src/api/providers/__tests__/zai.spec.ts
  • src/api/providers/__tests__/zoo-gateway.spec.ts
  • src/api/providers/anthropic-vertex.ts
  • src/api/providers/anthropic.ts
  • src/api/providers/base-openai-compatible-provider.ts
  • src/api/providers/bedrock.ts
  • src/api/providers/config-builder/README.md
  • src/api/providers/config-builder/request-config-builder.ts
  • src/api/providers/fake-ai.ts
  • src/api/providers/fetchers/__tests__/modelCache.spec.ts
  • src/api/providers/fetchers/modelCache.ts
  • src/api/providers/gemini.ts
  • src/api/providers/index.ts
  • src/api/providers/lite-llm.ts
  • src/api/providers/lm-studio.ts
  • src/api/providers/minimax.ts
  • src/api/providers/mistral.ts
  • src/api/providers/native-ollama.ts
  • src/api/providers/openai-codex.ts
  • src/api/providers/openai-compatible.ts
  • src/api/providers/openai-native.ts
  • src/api/providers/openai.ts
  • src/api/providers/opencode-go.ts
  • src/api/providers/openrouter.ts
  • src/api/providers/poe.ts
  • src/api/providers/qwen-code.ts
  • src/api/providers/requesty.ts
  • src/api/providers/unbound.ts
  • src/api/providers/vercel-ai-gateway.ts
  • src/api/providers/vscode-lm.ts
  • src/api/providers/xai.ts
  • src/api/providers/zoo-gateway.ts
  • src/core/task/__tests__/Task.spec.ts
  • src/utils/__tests__/enhance-prompt.spec.ts
  • src/utils/single-completion-handler.ts
✅ Files skipped from review due to trivial changes (2)
  • src/api/providers/index.ts
  • src/api/providers/config-builder/README.md
🚧 Files skipped from review as they are similar to previous changes (48)
  • src/utils/tests/enhance-prompt.spec.ts
  • src/api/providers/tests/sambanova.spec.ts
  • src/utils/single-completion-handler.ts
  • src/api/providers/tests/gemini-handler.spec.ts
  • src/api/providers/openrouter.ts
  • src/api/providers/lm-studio.ts
  • src/api/providers/tests/complete-prompt-options.spec.ts
  • src/api/providers/xai.ts
  • src/api/providers/anthropic-vertex.ts
  • src/api/providers/mistral.ts
  • src/api/providers/gemini.ts
  • src/api/providers/lite-llm.ts
  • src/api/providers/tests/zai.spec.ts
  • src/api/providers/tests/openai.spec.ts
  • src/api/providers/base-openai-compatible-provider.ts
  • src/api/providers/tests/openrouter.spec.ts
  • src/api/providers/tests/unbound.spec.ts
  • src/api/providers/openai-codex.ts
  • src/api/providers/zoo-gateway.ts
  • src/api/providers/fake-ai.ts
  • src/api/providers/bedrock.ts
  • src/api/providers/tests/minimax.spec.ts
  • src/api/providers/unbound.ts
  • src/api/providers/tests/mistral.spec.ts
  • src/api/providers/tests/zoo-gateway.spec.ts
  • src/api/providers/requesty.ts
  • src/api/providers/tests/anthropic.spec.ts
  • src/api/providers/native-ollama.ts
  • src/api/providers/vscode-lm.ts
  • src/api/providers/vercel-ai-gateway.ts
  • src/api/providers/tests/requesty.spec.ts
  • src/api/providers/anthropic.ts
  • src/api/providers/tests/gemini.spec.ts
  • src/api/providers/tests/vertex.spec.ts
  • src/api/providers/tests/xai.spec.ts
  • src/api/providers/tests/openai-codex-native-tool-calls.spec.ts
  • src/api/providers/openai.ts
  • src/api/providers/tests/deepseek.spec.ts
  • src/api/providers/openai-native.ts
  • src/api/providers/config-builder/request-config-builder.ts
  • src/api/providers/tests/native-ollama.spec.ts
  • src/api/providers/tests/mimo.spec.ts
  • src/api/providers/openai-compatible.ts
  • src/api/providers/tests/vercel-ai-gateway.spec.ts
  • src/api/providers/tests/openai-native.spec.ts
  • src/api/providers/minimax.ts
  • src/api/providers/tests/moonshot.spec.ts
  • src/api/providers/tests/request-config-builder.spec.ts

Comment thread src/api/providers/__tests__/lmstudio.spec.ts
Comment thread src/api/providers/__tests__/poe.spec.ts
Comment thread src/api/providers/opencode-go.ts Outdated
Comment thread src/api/providers/poe.ts
Comment thread src/api/providers/qwen-code.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/api/providers/vscode-lm.ts (1)

572-576: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

timeoutMs: 0 is still ignored here.

Line 574 uses a truthy guard, so completePrompt(..., { timeoutMs: 0 }) never cancels. The other providers in this PR moved to defined checks specifically to preserve 0, so this breaks the shared CompletePromptOptions contract.

🛠️ Proposed fix
-		if (options?.timeoutMs && options.timeoutMs > 0) {
-			timeoutTimeout = setTimeout(() => tokenSource.cancel(), options.timeoutMs)
+		if (options?.timeoutMs !== undefined && options.timeoutMs >= 0) {
+			if (options.timeoutMs === 0) {
+				tokenSource.cancel()
+			} else {
+				timeoutTimeout = setTimeout(() => tokenSource.cancel(), options.timeoutMs)
+			}
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/vscode-lm.ts` around lines 572 - 576, The timeout handling
in completePrompt still ignores timeoutMs = 0 because it uses a truthy check
before creating the cancellation timer. Update the guard in the vscode-lm
provider’s completePrompt flow to check for a defined timeoutMs value instead of
truthiness, while still only scheduling the timer when the value is non-negative
as intended. Keep the fix aligned with the shared CompletePromptOptions behavior
used by the other provider implementations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api/providers/bedrock.ts`:
- Around line 842-875: The request options builder in bedrock.ts does not abort
immediately when timeoutMs is 0 without a caller-provided signal, and the
timeout timer created for the merged AbortSignal is not cleaned up after
client.send finishes. Update the sendOptions/AbortController logic to ensure
timeoutMs: 0 always produces an already-aborted signal even when
options.abortSignal is absent, and refactor the timeout path in the send() call
so any setTimeout handle is cleared once the request resolves or rejects. Use
the existing sendOptions builder and this.client.send flow as the place to fix
it.

In `@src/api/providers/openai-codex.ts`:
- Around line 1165-1168: The request-local timeout in openai-codex’s fetch flow
is left pending when the request finishes early, so it can later abort an
already completed controller. Update the timeout handling around the
`options.timeoutMs` / `timeoutId` logic in `fetch` to always clear the timer in
the `finally` block, and make sure the `localAbortController` is only aborted by
an active request timeout.

---

Outside diff comments:
In `@src/api/providers/vscode-lm.ts`:
- Around line 572-576: The timeout handling in completePrompt still ignores
timeoutMs = 0 because it uses a truthy check before creating the cancellation
timer. Update the guard in the vscode-lm provider’s completePrompt flow to check
for a defined timeoutMs value instead of truthiness, while still only scheduling
the timer when the value is non-negative as intended. Keep the fix aligned with
the shared CompletePromptOptions behavior used by the other provider
implementations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e204c493-54e6-434e-994f-c36ad6de967a

📥 Commits

Reviewing files that changed from the base of the PR and between dcdce75 and 387fe45.

📒 Files selected for processing (29)
  • src/api/providers/__tests__/anthropic-vertex.spec.ts
  • src/api/providers/__tests__/anthropic.spec.ts
  • src/api/providers/__tests__/bedrock.spec.ts
  • src/api/providers/__tests__/gemini-handler.spec.ts
  • src/api/providers/__tests__/gemini.spec.ts
  • src/api/providers/__tests__/minimax.spec.ts
  • src/api/providers/__tests__/mistral.spec.ts
  • src/api/providers/__tests__/moonshot.spec.ts
  • src/api/providers/__tests__/request-config-builder.spec.ts
  • src/api/providers/__tests__/vertex.spec.ts
  • src/api/providers/__tests__/xai.spec.ts
  • src/api/providers/anthropic-vertex.ts
  • src/api/providers/bedrock.ts
  • src/api/providers/config-builder/README.md
  • src/api/providers/fetchers/__tests__/modelCache.spec.ts
  • src/api/providers/gemini.ts
  • src/api/providers/lite-llm.ts
  • src/api/providers/minimax.ts
  • src/api/providers/mistral.ts
  • src/api/providers/openai-codex.ts
  • src/api/providers/openai-compatible.ts
  • src/api/providers/openai.ts
  • src/api/providers/openrouter.ts
  • src/api/providers/requesty.ts
  • src/api/providers/unbound.ts
  • src/api/providers/vercel-ai-gateway.ts
  • src/api/providers/vscode-lm.ts
  • src/api/providers/xai.ts
  • src/api/providers/zoo-gateway.ts
✅ Files skipped from review due to trivial changes (1)
  • src/api/providers/config-builder/README.md
🚧 Files skipped from review as they are similar to previous changes (17)
  • src/api/providers/tests/vertex.spec.ts
  • src/api/providers/unbound.ts
  • src/api/providers/minimax.ts
  • src/api/providers/openrouter.ts
  • src/api/providers/anthropic-vertex.ts
  • src/api/providers/openai.ts
  • src/api/providers/zoo-gateway.ts
  • src/api/providers/tests/bedrock.spec.ts
  • src/api/providers/xai.ts
  • src/api/providers/lite-llm.ts
  • src/api/providers/mistral.ts
  • src/api/providers/tests/gemini-handler.spec.ts
  • src/api/providers/tests/moonshot.spec.ts
  • src/api/providers/vercel-ai-gateway.ts
  • src/api/providers/fetchers/tests/modelCache.spec.ts
  • src/api/providers/requesty.ts
  • src/api/providers/tests/request-config-builder.spec.ts

Comment on lines +842 to +875
// Build request options with abortSignal and/or timeoutMs
const sendOptions: { abortSignal?: AbortSignal } | undefined = (() => {
let signal: AbortSignal | undefined = options?.abortSignal
if (options?.timeoutMs !== undefined) {
if (signal) {
// When both are provided, create a merged signal that aborts when either fires
const controller = new AbortController()
if (signal.aborted) {
controller.abort()
} else if (options.timeoutMs > 0) {
const timeoutId = setTimeout(() => controller.abort(), options.timeoutMs)
signal.addEventListener(
"abort",
() => {
clearTimeout(timeoutId)
controller.abort()
},
{ once: true },
)
} else {
// timeoutMs is 0, abort immediately
controller.abort()
}
signal = controller.signal
} else if (options.timeoutMs !== undefined) {
if (options.timeoutMs > 0) {
signal = AbortSignal.timeout(options.timeoutMs)
}
}
}
return signal ? { abortSignal: signal } : undefined
})()

const response = await this.client.send(command, sendOptions)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Handle timeoutMs: 0 without a caller signal and clear merged timeout timers.

Line 866 leaves signal unset for { timeoutMs: 0 }, so the Bedrock request runs instead of aborting immediately. Also, the timer created on Line 852 is not cleared when client.send completes before the timeout.

Proposed fix
 async completePrompt(prompt: string, options?: import("../index").CompletePromptOptions): Promise<string> {
+	let timeoutId: ReturnType<typeof setTimeout> | undefined
 	try {
 		const modelConfig = this.getModel()
@@
-							const timeoutId = setTimeout(() => controller.abort(), options.timeoutMs)
+							timeoutId = setTimeout(() => controller.abort(), options.timeoutMs)
@@
 					} else if (options.timeoutMs !== undefined) {
 						if (options.timeoutMs > 0) {
 							signal = AbortSignal.timeout(options.timeoutMs)
+						} else {
+							const controller = new AbortController()
+							controller.abort()
+							signal = controller.signal
 						}
 					}
@@
 			throw enhancedError
+		} finally {
+			if (timeoutId !== undefined) {
+				clearTimeout(timeoutId)
+			}
 		}
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Build request options with abortSignal and/or timeoutMs
const sendOptions: { abortSignal?: AbortSignal } | undefined = (() => {
let signal: AbortSignal | undefined = options?.abortSignal
if (options?.timeoutMs !== undefined) {
if (signal) {
// When both are provided, create a merged signal that aborts when either fires
const controller = new AbortController()
if (signal.aborted) {
controller.abort()
} else if (options.timeoutMs > 0) {
const timeoutId = setTimeout(() => controller.abort(), options.timeoutMs)
signal.addEventListener(
"abort",
() => {
clearTimeout(timeoutId)
controller.abort()
},
{ once: true },
)
} else {
// timeoutMs is 0, abort immediately
controller.abort()
}
signal = controller.signal
} else if (options.timeoutMs !== undefined) {
if (options.timeoutMs > 0) {
signal = AbortSignal.timeout(options.timeoutMs)
}
}
}
return signal ? { abortSignal: signal } : undefined
})()
const response = await this.client.send(command, sendOptions)
let timeoutId: ReturnType<typeof setTimeout> | undefined
// Build request options with abortSignal and/or timeoutMs
const sendOptions: { abortSignal?: AbortSignal } | undefined = (() => {
let signal: AbortSignal | undefined = options?.abortSignal
if (options?.timeoutMs !== undefined) {
if (signal) {
// When both are provided, create a merged signal that aborts when either fires
const controller = new AbortController()
if (signal.aborted) {
controller.abort()
} else if (options.timeoutMs > 0) {
timeoutId = setTimeout(() => controller.abort(), options.timeoutMs)
signal.addEventListener(
"abort",
() => {
clearTimeout(timeoutId)
controller.abort()
},
{ once: true },
)
} else {
// timeoutMs is 0, abort immediately
controller.abort()
}
signal = controller.signal
} else if (options.timeoutMs !== undefined) {
if (options.timeoutMs > 0) {
signal = AbortSignal.timeout(options.timeoutMs)
} else {
const controller = new AbortController()
controller.abort()
signal = controller.signal
}
}
}
return signal ? { abortSignal: signal } : undefined
})()
const response = await this.client.send(command, sendOptions)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/bedrock.ts` around lines 842 - 875, The request options
builder in bedrock.ts does not abort immediately when timeoutMs is 0 without a
caller-provided signal, and the timeout timer created for the merged AbortSignal
is not cleaned up after client.send finishes. Update the
sendOptions/AbortController logic to ensure timeoutMs: 0 always produces an
already-aborted signal even when options.abortSignal is absent, and refactor the
timeout path in the send() call so any setTimeout handle is cleared once the
request resolves or rejects. Use the existing sendOptions builder and
this.client.send flow as the place to fix it.

Comment on lines +1165 to +1168
if (options.timeoutMs !== undefined) {
if (options.timeoutMs > 0) {
timeoutId = setTimeout(() => localAbortController?.abort(), options.timeoutMs)
} else {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Clear the request-local timeout in finally.

If fetch completes before timeoutMs, the timer from Line 1167 remains pending and later aborts a completed request controller.

Proposed fix
 		} finally {
+			if (timeoutId !== undefined) {
+				clearTimeout(timeoutId)
+			}
 			this.abortController = undefined
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (options.timeoutMs !== undefined) {
if (options.timeoutMs > 0) {
timeoutId = setTimeout(() => localAbortController?.abort(), options.timeoutMs)
} else {
} finally {
if (timeoutId !== undefined) {
clearTimeout(timeoutId)
}
this.abortController = undefined
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api/providers/openai-codex.ts` around lines 1165 - 1168, The
request-local timeout in openai-codex’s fetch flow is left pending when the
request finishes early, so it can later abort an already completed controller.
Update the timeout handling around the `options.timeoutMs` / `timeoutId` logic
in `fetch` to always clear the timer in the `finally` block, and make sure the
`localAbortController` is only aborted by an active request timeout.

@edelauna

Copy link
Copy Markdown
Contributor

I'm going to convert this PR to draft while we wait for a fix to #615 to land.

@edelauna edelauna marked this pull request as draft June 29, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants