Skip to content

fix(ai-bedrock, ai-mistral): forward the caller's abort signal to the provider request - #1900

Open
ArVaViT wants to merge 2 commits into
TanStack:mainfrom
ArVaViT:fix/bedrock-mistral-abort-signal
Open

ArVaViT wants to merge 2 commits into
TanStack:mainfrom
ArVaViT:fix/bedrock-mistral-abort-signal

Conversation

@ArVaViT

@ArVaViT ArVaViT commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Aborting a chat() run on the Bedrock Converse adapter or the Mistral adapter now cancels the request to the provider, for both streaming and structured output.

🎯 Changes

  • BedrockConverseTextAdapter passes the caller's abort signal (options.request.signal) to client.send as the AWS SDK's abortSignal. This covers chatStream, structuredOutput and structuredOutputStream.
  • MistralTextAdapter sets the signal on the fetch of its raw stream and passes it to chat.complete for structured output. That call keeps the SDK's timeout (see Root cause).
  • Tests in packages/ai-bedrock/tests/converse/abort-signal-wire.test.ts and packages/ai-mistral/tests/abort-signal-wire.test.ts.
  • A patch changeset for @tanstack/ai-bedrock and one for @tanstack/ai-mistral.

Docs: no change. docs/chat/streaming.md already says that the AbortController given to chat() stops the model on the server. These two adapters now do that.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with pnpm run test:pr, or these tests do not apply to this pull request.
  • I fully understand the code in this pull request, including any code generated with AI assistance.
  • Docs: I updated docs/ for this change, or this change is not user-facing.
  • Changeset: I added a changeset (pnpm changeset), or this PR does not change a published package.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Root cause

Issue. abortController.abort() on a chat() run with the Bedrock Converse adapter or the Mistral adapter leaves the HTTP request open, and the provider keeps generating. In a 45 s run against a server that never answers, the Bedrock request and the Mistral stream stayed open. Mistral structured output closed only at the SDK's 30 s timeout.

Cause. The engine passes the caller's signal to the adapter as request.signal. BedrockConverseTextAdapter called client.send(command) with no options. MistralTextAdapter sent its raw stream fetch and client.chat.complete(params) without the signal.

Fix. Converse gives the signal to client.send as { abortSignal }. Mistral sets signal on the raw stream fetch and passes { signal } to chat.complete. The Mistral SDK applies its timeout (timeoutMs, 30 s by default) only to a request without a signal. So the structured output call combines the caller's signal and that timeout with AbortSignal.any. A call without a signal sends the same request as before.

Possible alternatives

Testing

Commands run

  • pnpm run test:pr passes.
  • @tanstack/ai-bedrock: 199 tests pass. @tanstack/ai-mistral: 115 tests pass. On main, 5 of the 6 new tests fail. The sixth makes sure that structured output with a signal still times out.
  • The E2E tests for the bedrock, bedrock-responses, mistral and vertex-mistral providers pass, with bedrock-converse-cache, bedrock-converse-truncated-tool-call and mistral-strict-tool-null-wire.
  • No new E2E spec, as in fix(ai-ollama): forward the caller's abort signal to the Ollama request #1708. The Converse adapter is the documented matrix gap in testing/e2e/README.md, and only two narrow specs drive it: bedrock-converse-cache.spec.ts through a fixed-stream mount, and bedrock-converse-truncated-tool-call.spec.ts through one aimock fixture. Also, aimock cannot show that the provider request closed.

Repro, written for this PR and not committed: a local server that never answers. Bedrock uses an HTTP/2 server, because the AWS SDK's default handler is NodeHttp2Handler. Mistral uses an HTTP/1.1 server. When the server gets the request, the test aborts and waits 1 s for the request to close. The mid-stream case aborts after the response headers.

On main (98055ca):

[bedrock stream] request stream STILL OPEN 1000 ms after abort
[bedrock structured output] request stream STILL OPEN 1000 ms after abort
[bedrock adapter.structuredOutput()] request stream STILL OPEN 1000 ms after abort
[bedrock mid-stream] STILL OPEN 1000 ms after abort
[mistral stream] connection STILL OPEN 1000 ms after abort
[mistral structured output] connection STILL OPEN 1000 ms after abort
[mistral mid-stream] STILL OPEN 1000 ms after abort

On this branch:

[bedrock stream] request stream closed 2 ms after abort
[bedrock structured output] request stream closed 0 ms after abort
[bedrock adapter.structuredOutput()] request stream closed 0 ms after abort
[bedrock mid-stream] closed 6 ms after abort
[mistral stream] connection closed 1 ms after abort
[mistral structured output] connection closed 0 ms after abort
[mistral mid-stream] closed 4 ms after abort

Manual test

  1. On main, copy packages/ai-bedrock/tests/converse/abort-signal-wire.test.ts and packages/ai-mistral/tests/abort-signal-wire.test.ts from this branch.
  2. Run pnpm --filter @tanstack/ai-bedrock test:lib abort-signal-wire. All 3 tests fail.
  3. Run pnpm --filter @tanstack/ai-mistral test:lib abort-signal-wire. The two abort tests fail. The timeout test passes, because main sends no signal.
  4. On this branch, run the same two commands. All tests pass.

How this PR makes testing easy

The two abort-signal-wire.test.ts files run the real SDK clients against a transport that never answers. Only the caller's signal can end the request.

Risk / rollback

Low. A call without a signal sends the same request as before. sendStream and send on BedrockConverseTextAdapter are protected and now take an optional signal. A subclass that overrides them still compiles, but it must pass the signal to client.send to keep the abort. To undo, revert this PR.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Aborting a chat now cancels in-flight streaming and structured-output requests for Bedrock and Mistral.
    • Mistral structured-output requests continue to respect configured timeouts when cancellation is enabled.

ArVaViT and others added 2 commits October 24, 2026 14:30
…quest

The Converse adapter called `client.send(command)` without the caller's
signal. Aborting a chat left the request to Bedrock open until Bedrock
answered. `chatStream`, `structuredOutput` and `structuredOutputStream`
now pass `request.signal` to `client.send` as the SDK's `abortSignal`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…uest

The adapter sent its raw stream fetch and its `chat.complete` call
without the caller's signal. Aborting a chat left the request to Mistral
open until Mistral answered. Both calls now carry `request.signal`.

The SDK drops its timeout (`timeoutMs`, 30 s by default) when a request
has a signal. The structured output call combines the two signals with
`AbortSignal.any`, so it still times out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f527e71

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@tanstack/ai-bedrock Patch
@tanstack/ai-mistral Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: TanStack/ai
  • Branch: main
  • File: .coderabbit.yaml
  • Commit: 98055ca
  • Layers: Repository YAML
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d7337c96-957c-403f-94de-2d4103357a8d
Commits

Reviewing files that changed from the base of the PR and between 98055ca and f527e71.

Files selected for processing: 6
  • .changeset/bedrock-converse-forward-abort-signal.md
  • .changeset/mistral-forward-abort-signal.md
  • packages/ai-bedrock/src/adapters/converse-text.ts
  • packages/ai-bedrock/tests/converse/abort-signal-wire.test.ts
  • packages/ai-mistral/src/adapters/text.ts
  • packages/ai-mistral/tests/abort-signal-wire.test.ts

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

Walkthrough

The Bedrock Converse and Mistral adapters now forward request abort signals to streaming and structured-output requests. Tests cover signal propagation for both adapters and timeout rejection for Mistral structured output.

Changes: Abort signal forwarding

Layer / File(s) Summary
Bedrock Converse signal forwarding
packages/ai-bedrock/src/adapters/converse-text.ts, packages/ai-bedrock/tests/converse/abort-signal-wire.test.ts, .changeset/bedrock-converse-forward-abort-signal.md
Bedrock Converse methods pass request signals to the AWS SDK for streaming and structured-output requests. Tests check propagation for streaming chat and structured output.
Mistral signal and timeout forwarding
packages/ai-mistral/src/adapters/text.ts, packages/ai-mistral/tests/abort-signal-wire.test.ts, .changeset/mistral-forward-abort-signal.md
Mistral streaming and structured-output requests receive the request signal. Structured output combines the signal with a timeout when applicable. Tests check abort propagation and timeout rejection.

Priority: Normal

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

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant BedrockConverseTextAdapter
  participant AWS SDK client
  Caller->>BedrockConverseTextAdapter: Send request with AbortSignal
  BedrockConverseTextAdapter->>AWS SDK client: Send Converse request with abortSignal
  Caller->>BedrockConverseTextAdapter: Abort request
  AWS SDK client-->>BedrockConverseTextAdapter: Reject aborted request
Loading
sequenceDiagram
  participant Caller
  participant MistralTextAdapter
  participant Mistral request
  Caller->>MistralTextAdapter: Send request with AbortSignal
  MistralTextAdapter->>Mistral request: Pass signal to fetch or chat.complete
  Caller->>MistralTextAdapter: Abort request
  Mistral request-->>MistralTextAdapter: Reject aborted request
Loading

Suggested reviewers: alemtuzlak

Merge Risk: Minimal · up to f527e

No actionable merge-blocking risk remains for abort-signal forwarding under the supported test workflows.

Pre-merge checks: Passed 5
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: forwarding caller abort signals to Bedrock and Mistral provider requests.
Description check Passed The description is complete and follows the repository template. It explains the change, root cause, alternatives, testing, release impact, documentation decision, and rollback risk.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 4 files. (2 skipped: 2 …
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 4 files. (2 skipped: 2 unsupported.)

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

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.

1 participant