Skip to content

refactor: share provider stream error - #384

Merged
eric8810 merged 10 commits into
masterfrom
refactor/share-provider-stream-error
Oct 29, 2026
Merged

eric8810 merged 10 commits into
masterfrom
refactor/share-provider-stream-error

Conversation

@cunninghamcard-bit

@cunninghamcard-bit cunninghamcard-bit commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

RFC-0046 R1 的第 6 个小 PR(清单见 #328):把 createProviderStreamError 放进 aimux-provider-utils,取代原来的 stream_error_api_call。12 个厂商的流内错误都由它构造,各家只留自己的状态码表。

Before:stream_error_api_call 只收消息、code、状态码和事件。是否可重试只能由状态码推出,原始数据只能等于事件本身,所以 Anthropic、DeepSeek、OpenAI、xAI 拿到错误后再改 is_retryable 和 data。Bedrock 没用它,自己拼 ApiCallError,请求体原样带进公开错误(data URL、长提示词都在),也没有响应体和响应头。

After:厂商把上游 ProviderStreamError 的几个字段(消息、code、状态码、是否可重试、原始数据)交给 create_provider_stream_error,不再事后改错误。Bedrock 也走它,请求体按其他厂商一样截断、脱敏,URL 去掉查询串和凭据,帧作为响应体,带上响应头。

一、体系现状(概览)

上游:

@ai-sdk/provider-utils 5.0.55
  create-provider-stream-error.ts
    createProviderStreamError({ message, type, code, statusCode, isRetryable, data }) → ProviderStreamError(带标记)
    isProviderStreamError(error)                 // AI SDK Core 据标记读出状态码和可重试
调用方(各家只留 getXxxStreamErrorMetadata 状态表)
  anthropic-language-model.ts:85
  amazon-bedrock-chat-language-model.ts:101
  deepseek-chat-language-model.ts:73
  groq-chat-language-model.ts:52
  huggingface-responses-language-model.ts
  open-responses-language-model.ts
  openai-stream-error.ts:29
  xai-responses-language-model.ts
  google interactions(aimux 未实现)

aimux(master b0450d4,9f9f5ab4 上相同):

aimux-provider-utils/src/response_handler.rs:295
  stream_error_api_call(message, provider_code, status_code, payload, url, body, headers) -> AiMuxError
    ├─ is_retryable = 状态码推出(不能传入)
    └─ data = payload(不能另给)
aimux-providers
  anthropic / deepseek / openai / xai   调用后再改 details.is_retryable、details.data
  google / groq / huggingface / mistral / open_responses / openai_compatible / codex   直接调用
  bedrock/chat_language_model.rs:574    手拼 ApiCallError,请求体未脱敏

二、本 PR 改动(细节)

aimux-provider-utils/src/create_provider_stream_error.rs
  :15  pub struct ProviderStreamError { message, provider_code, status_code, is_retryable: Option<bool>, data }
  :41  create_provider_stream_error(error, event, url, request_body_values, response_headers) -> AiMuxError
         event → response_body,并读 retry_after_ms / retry_after
         is_retryable: None → 按状态码;data 为 null → None;请求体与 URL 脱敏
aimux-provider-utils/src/response_handler.rs   删除 stream_error_api_call
aimux-provider-utils/src/lib.rs                pub mod + pub use(只有一个 `#[cfg(test)] mod tests;`)

aimux-providers/src/
  anthropic/language_model.rs:240        is_retryable、data(stream_error_data)直接传入
  deepseek/chat/chat_language_model.rs:122  额度用尽 → is_retryable: Some(false)
  openai/stream_error.rs:94              同上
  xai/error.rs:94                        同上
  google/error.rs:42、groq/chat_language_model.rs:80、mistral/error.rs:53
  huggingface/responses/responses_language_model.rs:119
  open_responses/responses/language_model.rs:339、:755
  openai/responses/responses_language_model.rs:2071
  openai_compatible/chat/chat_language_model.rs:463
  codex.rs:400
  bedrock/chat_language_model.rs:576     改用 create_provider_stream_error(行为修正)

ApiCallError 只有一个 code 字段,上游的 type 和 code 由各家选一个填进 provider_code,与改动前一致。

测试:

文件 用例 说明
provider-utils src/tests/create_provider_stream_error.rs 1 + 2 上游 1 条标 partial(没有单独的 type);isProviderStreamError 那条是 TS 专有;另 2 条非上游:可重试按状态码推出、事件作响应体并读出重试提示
bedrock tests/chat_language_model_event_stream.rs 1 新增:异常帧的错误里请求体被截断脱敏、帧作响应体;在 master 上失败
google tests/language_model.rs:8012 mod in_stream_error 1 新增(eric 评审):429 RESOURCE_EXHAUSTED 的流内错误
mistral tests/chat_language_model.rs:1483 mod in_stream_error 1 新增(eric 评审):rate_limit_error、status_code 429
codex codex.rs:650 1 新增(eric 评审):ChatGPT 账号模式的 response.failed

新增的 4 条都断言 message、status、provider_code、is_retryable、data、response_body 和 URL。其余厂商的已有用例原样通过。工作区测试 4380 → 4384(provider-utils 的 3 个另计)。

改动规模(对 master 9f9f5ab):

范围 文件 增 删
aimux-provider-utils 5 208 59
aimux-providers 16 323 95
合计(含 CHANGELOG) 22 549 154

公开 API 与行为

  • Breaking:aimux_provider_utils::stream_error_api_call 删除,改用 create_provider_stream_error 和 ProviderStreamError。
  • Added:create_provider_stream_error、ProviderStreamError。
  • Fixed:Bedrock 流内异常错误的请求体截断脱敏,带响应体和响应头。
  • CHANGELOG 的 Breaking、Added、Fixed 各一条。

检查

cargo fmt --check、scripts/check_provider_boundaries.sh、cargo +1.99 clippy(providers 与 provider-utils,-D warnings)、cargo check --workspace、cargo doc、全部测试均通过(基于 master 9f9f5ab)。

🤖 Generated with Claude Code

https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW

…der_stream_error

Ports createProviderStreamError from @ai-sdk/provider-utils 5.0.55:
the provider passes message, code, status, retryability and raw data as
a ProviderStreamError; an unset retryability still follows the status.
Ports the upstream test case that applies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…am_error

Each provider keeps its status table and passes retryability and data
in, instead of patching the built error afterwards. Errors are
unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
Bedrock built its exception-frame ApiCallError by hand, copying the
request body as sent. It now uses create_provider_stream_error, which
bounds and redacts it, sanitizes the URL and keeps the frame and the
response headers, as the other providers do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW

@eric8810 eric8810 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.

共享 helper 的语义和 13 个 call site 都核对通过,Bedrock 的有意变化也有测试。但当前不能合:

  1. 对 master 9f9f5ab 已 CONFLICTING:lib.rs、tests/mod.rs、CHANGELOG 三处冲突。注意 naively 解冲突会留下两个 #[cfg(test)] mod tests;,直接编译错;保留一个,并把 create_provider_stream_error 与 resolve_provider_reference 两个模块都列上。
  2. Google google/error.rs:42、Mistral mistral/error.rs:53、Codex codex.rs:400 没有 in-stream-error 断言;既然这次在集中 raw/data 形状,建议补上,至少 Google/Mistral。
  3. CI 16/16 是 base b0450d4 的,master 已前进,rebase 后要重跑。

Breaking removal 已记录,可接受。

…ider-stream-error

# Conflicts:
#	CHANGELOG.md
#	aimux-provider-utils/src/lib.rs
#	aimux-provider-utils/src/tests/mod.rs
…odex

Each test feeds one error event and checks the ApiCallError it becomes:
message, provider code, status, retryability, data and response body.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW

Copy link
Copy Markdown
Contributor Author

三条都处理了,新头 3c74f2e6。

eric 的意见 处理
1. 对 master 9f9f5ab 冲突(lib.rs、tests/mod.rs、CHANGELOG),注意别留两个 #[cfg(test)] mod tests; 合上 master(merge a4d3ff5)。lib.rs 只留一个 mod tests;,create_provider_stream_error 和 resolve_provider_reference 两个模块、两条 pub use 都在(aimux-provider-utils/src/lib.rs:15、:32、:47、:69)。tests/mod.rs、CHANGELOG 两边都保留。
2. Google google/error.rs:42、Mistral mistral/error.rs:53、Codex codex.rs:400 没有 in-stream-error 断言 3c74f2e 补了三条:Google google/tests/language_model.rs:8012 mod in_stream_error(429 RESOURCE_EXHAUSTED),Mistral mistral/tests/chat_language_model.rs:1483 mod in_stream_error(rate_limit_error,status_code 429),Codex codex.rs:650 subscription_response_failed_becomes_an_api_call_error(ChatGPT 账号模式的 response.failed)。每条断言 message、status、provider_code、is_retryable、data、response_body、URL 和流的最后一段。
3. CI 是 base b0450d4 的,要重跑 推送后 CI 在新头上重跑。本地 fmt、边界检查、cargo +1.99 clippy(providers 与 provider-utils)、workspace check、doc、全部测试通过,4384 个(多出的 3 个就是上面这三条)。

Generated by Claude Code

…ider-stream-error

# Conflicts:
#	aimux-provider-utils/src/tests/mod.rs

@eric8810 eric8810 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.

三项都补了:Google/Mistral/Codex 的 stream-error 断言在,duplicate mod tests 的问题也没复现。现在只差 rebase:head 基于 9f9f5ab,master 已是 ab00ae4,冲突只在 aimux-provider-utils/src/tests/mod.rs(保留 #380 三个模块 + mod create_provider_stream_error;)。rebase 后 CI 重跑即可。

Copy link
Copy Markdown
Contributor Author
eric 的意见 处理
合上新 master,CI 重跑 已合上 master 5cc14b1(含 #389–#391),提交 2e1d8c0。本地 fmt、边界检查、clippy、doc、providers 与 provider-utils 全部测试通过,CI 已重跑

Generated by Claude Code

@eric8810 eric8810 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.

冲突已解且无重复 mod tests;Google/Mistral/Codex 测试保持,helper 语义未变,16/16 CI 通过。Re-approve。

…ider-stream-error

# Conflicts:
#	CHANGELOG.md
#	aimux-provider-utils/src/lib.rs
#	aimux-provider-utils/src/tests/mod.rs

Copy link
Copy Markdown
Contributor Author
项 内容
这次推送 5fbeb71c:只合了 master 0bc182a9(#392 #393 #394 合入后),解决和它们的冲突
本 PR 改动 不变,和你批准时一样
本地检查 fmt、边界脚本、clippy -D warnings、workspace check、doc、providers 测试 4383 个全过

Generated by Claude Code

@eric8810 eric8810 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.

代码/tests 的 rebase 没问题,16/16 CI 也绿;但 CHANGELOG 的冲突解错了:CHANGELOG.md:1457 多插了一个 ### Fixed,导致四条 Added bullet(1464–1474)落在 Fixed 下面,真正的 ### Fixed 在 1476。删掉 1457–1458 的 heading/空行,把 Bedrock bullet 移到 1476 下面即可。

The master merge left a second Fixed heading inside Added, which moved
four Added bullets under it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW

Copy link
Copy Markdown
Contributor Author
eric 的意见 处理
CHANGELOG 冲突解错:Added 中间多了一个 ### Fixed,四条 Added 落到它下面 已改(1dfba34b):删掉多出的标题和空行,Bedrock 那条移到真正的 ### Fixed 下面第一条。Unreleased 下的标题顺序现在和 master 相同(Build、Breaking、Added、Fixed、Removed、RFCs、Changed);同一批合 master 的 #383 #385 #387 #388 也逐个核对过,只有这里错了

Generated by Claude Code

@eric8810 eric8810 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.

CHANGELOG 已修:只有一个 ### Fixed,Bedrock bullet 在 1470-1473;代码/tests 未变,16/16 CI 通过。Approve。

@eric8810
eric8810 merged commit 503825e into master Oct 29, 2026
16 checks passed
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