Skip to content

refactor: move the OpenAI files to the upstream layout - #370

Merged
eric8810 merged 12 commits into
masterfrom
refactor/move-the-openai-files-to-the-upstream-layout
Oct 27, 2026
Merged

eric8810 merged 12 commits into
masterfrom
refactor/move-the-openai-files-to-the-upstream-layout

Conversation

@cunninghamcard-bit

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

Copy link
Copy Markdown
Contributor

Summary

把 src/openai/ 按 @ai-sdk/openai 4.0.83 一个文件对一个文件重排(RFC-0046 §4.2),照上游建 chat/、completion/、embedding/、files/、image/、responses/、speech/、transcription/、tool/ 子目录。九个老测试程序和三处内联测试并进厂商测试目录 src/openai/tests/(RFC-0046 §5)。函数体只改了路径和可见性。crate 根和 openai 模块根的再导出不变;有公开子模块路径变了,列在“公开路径”一节。测试数量和函数名前后一致(990 个,名字多重集相同)。叠在测试 PR #369 上(#369 叠在 fix PR #368 上)。实施进度在 #328 跟踪。

一、体系现状(概览,测试 PR #369 头 bdb657b5)

aimux_providers::openai::create_openai             src/openai/mod.rs:253
 └ OpenAIProvider                                   mod.rs:320 起
   ├ chat → OpenAIModel                             mod.rs:320 → model.rs:40
   │  ├ execute_generate / execute_stream           model.rs:221、:376
   │  ├ build_request_body_with_chat_options(getArgs)
   │  │                                             convert.rs:1091
   │  │  ├ parse_chat_options                       options.rs:12
   │  │  ├ get_model_capabilities                   convert_common.rs:103
   │  │  ├ convert_prompt_to_openai_messages_with_mode_fallible
   │  │  │                                          convert.rs:267
   │  │  ├ prepare_tools                            convert.rs:206
   │  │  └ normalize_json_schema                    convert.rs:27
   │  ├ OpenAIChatStream(Transformer)              model.rs:449
   │  ├ convert_usage                               model.rs:95
   │  ├ parse_finish_reason                         convert.rs:1211
   │  ├ openai_stream_error                         mod.rs:91
   │  └ openai_failed_response_handler              mod.rs:64
   ├ responses → OpenAIResponsesModel               mod.rs:355 → responses/mod.rs:58
   │  ├ build_responses_request_body_for(getArgs) responses/convert.rs:1925
   │  │  ├ ResponsesNamespace / ResponsesProfile    responses/convert.rs:45
   │  │  ├ convert_responses_input_with_conversation responses/convert.rs:150
   │  │  └ prepare_responses_tools_for              responses/convert.rs:984
   │  ├ build_responses_generate_result_with_tools  responses/responses_convert.rs:101
   │  ├ OpenAIResponsesStream(Transformer)         responses/responses_convert.rs:940
   │  │  └ provider_tool_content                    responses/provider_events.rs:11
   │  ├ convert_responses_usage                     responses/convert.rs:2241
   │  └ map_responses_finish_reason                 responses/convert.rs:2302
   ├ completion → OpenAICompletionModel             completion.rs:4(openai_compatible 的别名)
   ├ embedding → OpenAIEmbeddingModel               embedding.rs:24
   ├ image → OpenAIImageModel                       image.rs:65
   ├ speech → OpenAISpeechModel                     speech.rs:30
   ├ transcription → OpenAITranscriptionModel       transcription.rs:255
   ├ files → OpenAIFiles                            files.rs:94
   ├ decision → OpenAIDecisionModel                 decision.rs:30(aimux 扩展)
   └ tools → OpenAITools                            tools.rs:662(工厂函数和参数类型 tools.rs:1-660)
ProviderDiscovery::list_models → list_models_once   model.rs:716

上游同一条路:createOpenAI(openai-provider.ts)建 chat/ 下的 OpenAIChatLanguageModel(getArgs、doGenerate、doStream 和流的解析都在 openai-chat-language-model.ts)、responses/ 下的 OpenAIResponsesLanguageModel(同样,请求、生成、流和 provider 工具输出都在 openai-responses-language-model.ts)、completion/、embedding/、image/、speech/、transcription/、files/ 下各自的模型,tool/ 下每个 provider 工具一个文件,openai-tools.ts 把它们合成 openai.tools。aimux 把这些放在 19 个文件里,其中 convert.rs(提示词转换、工具准备、schema 规范化、getArgs、选项读取、finish reason)、model.rs(模型、执行、流、usage、模型列表)、responses/convert.rs(输入转换、工具准备、getArgs、usage、finish reason、命名空间)、responses/responses_convert.rs(生成结果和流的解析)、tools.rs(13 个工具)各跨了多个上游文件。

测试:#369 的新用例在 src/openai/tests/(openai:: 下 712 个);三处内联测试(convert.rs、model.rs 的 stream_tests、responses/convert.rs);老用例在九个独立测试程序里:tests/openai_decision_test.rs(13,另带 tests/common/replay.rs 的 3 个)、openai_embedding_test.rs(7)、openai_factory_test.rs(15)、openai_image_test.rs(23)、openai_speech_test.rs(8)、openai_transcription_test.rs(12)、openai_transcription_stream_test.rs(13)、openai_realtime_ws_replay_test.rs(3)、openai_upstream_e2e_test.rs(47)。

二、本 PR 改动(细节)

aimux_providers::openai::create_openai             src/openai/provider.rs:99                         ← openai-provider.ts
 └ OpenAIProvider
   ├ chat → OpenAIModel                             provider.rs:186 → chat/chat_language_model.rs:46  ← chat/openai-chat-language-model.ts
   │  ├ execute_generate / execute_stream           chat/chat_language_model.rs:158、:313
   │  ├ build_request_body_with_chat_options(getArgs)
   │  │                                             chat/chat_language_model.rs:995
   │  │  ├ parse_chat_options                       chat/chat_language_model_options.rs:11      ← chat/openai-chat-language-model-options.ts
   │  │  ├ get_model_capabilities                   language_model_capabilities.rs:103           ← openai-language-model-capabilities.ts
   │  │  ├ convert_prompt_to_openai_messages_with_mode_fallible
   │  │  │                                          chat/convert_to_chat_messages.rs:23          ← chat/convert-to-openai-chat-messages.ts
   │  │  ├ prepare_tools                            chat/chat_prepare_tools.rs:29                ← chat/openai-chat-prepare-tools.ts
   │  │  └ normalize_json_schema                    normalize_json_schema.rs:8                   ← normalize-openai-json-schema.ts
   │  ├ OpenAIChatStream(Transformer)              chat/chat_language_model.rs:387
   │  ├ ChatCompletionResponse 等                    chat/chat_api.rs:11                          ← chat/openai-chat-api.ts
   │  ├ convert_usage                               chat/convert_chat_usage.rs:20                ← chat/convert-openai-chat-usage.ts
   │  ├ parse_finish_reason                         chat/map_finish_reason.rs:7                  ← chat/map-openai-finish-reason.ts
   │  ├ openai_stream_error                         stream_error.rs:11                           ← openai-stream-error.ts
   │  └ openai_failed_response_handler              error.rs:6                                   ← openai-error.ts
   ├ responses → OpenAIResponsesModel               provider.rs:201 → responses/responses_language_model.rs:78
   │                                                ← responses/openai-responses-language-model.ts
   │  ├ build_responses_request_body_for(getArgs) responses/responses_language_model.rs:879
   │  │  ├ ResponsesNamespace / ResponsesProfile    responses/responses_language_model_options.rs:14
   │  │  │                                          ← responses/openai-responses-language-model-options.ts
   │  │  ├ convert_responses_input_with_conversation responses/convert_to_responses_input.rs:59
   │  │  │                                          ← responses/convert-to-openai-responses-input.ts
   │  │  └ prepare_responses_tools_for              responses/responses_prepare_tools.rs:30
   │  │                                             ← responses/openai-responses-prepare-tools.ts
   │  ├ build_responses_generate_result_with_tools  responses/responses_language_model.rs:1144
   │  ├ OpenAIResponsesStream(Transformer)         responses/responses_language_model.rs:1984
   │  │  └ provider_tool_content                    responses/responses_language_model.rs:3052
   │  ├ ResponsesUsage 等                            responses/responses_api.rs:24                ← responses/openai-responses-api.ts
   │  ├ convert_responses_usage                     responses/convert_responses_usage.rs:24      ← responses/convert-openai-responses-usage.ts
   │  └ map_responses_finish_reason                 responses/map_responses_finish_reason.rs:13  ← responses/map-openai-responses-finish-reason.ts
   ├ completion → OpenAICompletionModel             completion/completion_language_model.rs:5    ← completion/openai-completion-language-model.ts
   ├ embedding → OpenAIEmbeddingModel               embedding/embedding_model.rs:24              ← embedding/openai-embedding-model.ts
   ├ image → OpenAIImageModel                       image/image_model.rs:29                      ← image/openai-image-model.ts
   ├ speech → OpenAISpeechModel                     speech/speech_model.rs:30                    ← speech/openai-speech-model.ts
   ├ transcription → OpenAITranscriptionModel       transcription/transcription_model.rs:128     ← transcription/openai-transcription-model.ts
   ├ files → OpenAIFiles                            files/files.rs:43                            ← files/openai-files.ts
   ├ decision → OpenAIDecisionModel                 decision.rs:30(aimux 扩展,layout.toml 记为 aimux)
   └ tools → OpenAITools                            tools.rs:66                                  ← openai-tools.ts
      └ web_search、file_search、…                  tool/<name>.rs,一个上游工具一个文件       ← tool/*.ts
ProviderDiscovery::list_models → list_models_once   provider.rs:353
现在 搬到 上游
mod.rs 的模块文档、mod、pub use mod.rs(模块声明、导出和给别家用的 crate 内路径) index.ts、internal/index.ts
mod.rs 的常量、设置、create_openai、openai、OpenAIProvider 和实现;model.rs 的 ModelsListResponse、ModelEntry、list_models_once provider.rs openai-provider.ts(list_models_once 是 aimux 的模型发现,跟 provider 放一起,和 Google 一样)
mod.rs 的 openai_failed_response_handler / openai_stream_error error.rs / stream_error.rs openai-error.ts / openai-stream-error.ts
convert_common.rs language_model_capabilities.rs(原样) openai-language-model-capabilities.ts
convert.rs 的 normalize_json_schema、contains_lookaround normalize_json_schema.rs normalize-openai-json-schema.ts
model.rs;convert.rs 的 RequestBodyResult 到 build_request_body_with_chat_options(getArgs 那组) chat/chat_language_model.rs chat/openai-chat-language-model.ts(getResponseMetadata 在这里内联,chat/get-response-metadata.ts 指向它)
options.rs;convert.rs 的 parse_option_fields、parse_chat_provider_options、openai_option chat/chat_language_model_options.rs chat/openai-chat-language-model-options.ts
convert.rs 的提示词转换(convert_prompt_to_openai_messages_with_mode_fallible 到 convert_text_part_to_openai) chat/convert_to_chat_messages.rs chat/convert-to-openai-chat-messages.ts(chat/openai-chat-prompt.ts 的消息形状在 aimux 里是 JSON,指向这里)
convert.rs 的 ToolWarning、PreparedTools、prepare_tools / parse_finish_reason chat/chat_prepare_tools.rs / chat/map_finish_reason.rs chat/openai-chat-prepare-tools.ts / chat/map-openai-finish-reason.ts
model.rs 的 convert_usage / types.rs chat/convert_chat_usage.rs / chat/chat_api.rs chat/convert-openai-chat-usage.ts / chat/openai-chat-api.ts
completion.rs completion/completion_language_model.rs(原样) completion/openai-completion-language-model.ts(实现是 openai_compatible 的别名,completion/ 其余 6 个文件都指向它)
embedding.rs 的响应结构 / 选项 / 其余 embedding/embedding_api.rs / embedding_model_options.rs / embedding_model.rs embedding/openai-embedding-api.ts / -model-options.ts / -model.ts
files.rs 的响应结构 / 选项 / 其余 files/files_api.rs / files_options.rs / files.rs files/openai-files-api.ts / -options.ts / openai-files.ts(files/files.rs 和测试那边一样加 allow(clippy::module_inception, reason))
image.rs 的 DEFAULT_RESPONSE_FORMAT_PREFIXES、has_default_response_format、get_max_images_per_call、生成和编辑选项 / 其余 image/image_model_options.rs / image_model.rs image/openai-image-model-options.ts / -model.ts(响应在 aimux 里按 JSON 读,openai-image-api.ts 指向 image_model.rs)
speech.rs speech/speech_model.rs(原样) speech/openai-speech-model.ts(选项和 API 类型没有单独的内容,-api.ts、-model-options.ts 指向它)
transcription.rs 的选项 / 响应结构 / 其余 transcription/transcription_model_options.rs / transcription_api.rs / transcription_model.rs transcription/openai-transcription-model-options.ts / -api.ts / -model.ts
responses/mod.rs 的模型;responses/convert.rs 的请求体那组;responses/responses_convert.rs;responses/provider_events.rs responses/responses_language_model.rs responses/openai-responses-language-model.ts(openai-responses-provider-metadata.ts 只有类型,aimux 在这里写 JSON,指向它)
responses/convert.rs 的命名空间和 openai_option / 输入转换和 file id 前缀 / 工具准备 / usage / finish reason responses/responses_language_model_options.rs / convert_to_responses_input.rs / responses_prepare_tools.rs / convert_responses_usage.rs / map_responses_finish_reason.rs 同名上游文件
responses/types.rs responses/responses_api.rs(原样) responses/openai-responses-api.ts
responses/tool_args.rs 不动,第一行注明 aimux 扩展 aimux 独有:tool/*.ts 的 input schema 集中在一处校验(layout.toml 记为 aimux)
tools.rs 的 13 组参数类型和工厂函数 / OpenAITools、AzureOpenAITools、provider_tool tool/apply_patch.rs … tool/web_search_preview.rs / tools.rs(再导出 tool/ 的全部公开项) tool/*.ts / openai-tools.ts
decision.rs、config.rs 不动(decision.rs 第一行注明 aimux 扩展) aimux 独有 / openai-config.ts

和上游对应关系的偏差:files/openai-files.ts 落在 files/files.rs(和测试目录一样,保留 files 而不另起名);上游的 api / options 文件在 aimux 里没有单独内容时(image api、speech api 和 options、completion 的 6 个、chat prompt、responses provider metadata、chat get-response-metadata)不建空文件,layout.toml 指向含有那段内容的文件,和 Google 的 embedding options 一样;responses/tool_args.rs 和 decision.rs 作为 aimux 扩展留在原目录。

  • 公开路径(RFC-0046 §4.5,按 refactor: move the Mistral files to the upstream layout #297 / refactor: move the Cohere files to the upstream layout #298 / refactor: move the xAI files to the upstream layout #313 / refactor: move the Amazon Bedrock files to the upstream layout #359 / refactor: move the Anthropic files to the upstream layout #364 / refactor: move the Google files to the upstream layout #367 的做法只列出来):
    • openai::convert、openai::model、openai::responses::convert、openai::responses::responses_convert、openai::responses::types 不再公开。openai::model::OpenAIModel 用 openai::OpenAIModel(crate 根本来就导出)。
    • responses::convert 和 responses::types 里公开函数签名用到的类型放到 openai::responses 根:PreparedResponsesTools、parse_usage、ResponsesUsage、ResponsesInputTokensDetails、ResponsesOutputTokensDetails,和它原来就导出的 build_responses_request_body、convert_responses_usage、prepare_responses_tools 等放在一起,免得那些函数的参数和返回类型在外面叫不出名字。
    • convert 的 Chat Completions 辅助项(SystemMessageMode、ToolWarning、PreparedTools、prepare_tools、convert_prompt_to_openai_messages_with_mode_fallible、RequestBodyResult、build_request_body_with_warnings、parse_finish_reason)和 responses_convert 的共用解析(ResponsesEventStream、build_responses_generate_result、build_responses_event_stream)变成 crate 内部,没有公开的替代。
    • 没有任何调用方的 convert::build_request_body、responses_convert::build_header_list 删掉了(模块不公开后是死代码)。只有测试用的 build_request_body_with_warnings、build_responses_event_stream 现在是 #[cfg(test)] pub(crate)。
    • openai::completion、openai::decision、openai::embedding、openai::files、openai::image、openai::responses、openai::speech、openai::tools、openai::transcription 照旧公开,里面原有的公开项照旧(openai::tools::web_search 等经 tools.rs 的 pub use 从 tool/ 导出)。
  • crate 内的调用方不用改:别家用的 openai::convert::{tool_result_to_content, tool_result_content_value, parse_chat_provider_options, parse_option_fields}、openai::model::{list_models_once, chat_test_stream}、openai::options::{ChatOptionsParser, parse_chat_options} 由 mod.rs 里三个 pub(crate) mod 再导出接住;openai_failed_response_handler、openai_stream_error、API_KEY_ENV_VAR、DEFAULT_BASE_URL 由 pub(crate) use 导出;Codex 用的 openai::responses::responses_convert::{build_responses_generate_result, build_responses_event_stream_with_raw} 由 responses/mod.rs 的 pub(crate) mod responses_convert 接住;config、tools::AzureOpenAITools、responses::{ResponsesNamespace, ResponsesProfile, build_responses_request_body} 路径不变。别家的文件一个都没改。
  • 可见性:子目录的 mod.rs 把文件声明成 pub(super) mod,openai 下的兄弟目录和测试都能按完整路径用;拆开后要互相调用、或测试要用的项从私有改成 pub(crate)(子目录里)或 pub(super)(根目录里),被拆开的结构体字段同样(OpenAIEmbeddingResponse、OpenAIFilesResponse、OpenAITranscriptionOptions 等)。OpenAIChatStream 改成 pub(crate)(老的流测试用)。函数体里的 super::xxx 改成 crate::openai::<新路径>::xxx。
  • 测试:
    • 每个老程序并进对应上游文件的测试,放在末尾一个 older_* 模块里:openai_decision_test.rs → tests/evaluation.rs 的 older_decision;openai_embedding_test.rs → tests/embedding/embedding_model.rs 的 older_embedding;openai_factory_test.rs → tests/provider.rs 的 older_factory;openai_image_test.rs → tests/image/image_model.rs 的 older_image;openai_speech_test.rs → tests/speech/speech_model.rs 的 older_speech;openai_transcription_test.rs、openai_transcription_stream_test.rs、openai_realtime_ws_replay_test.rs → tests/transcription/transcription_model.rs 的 older_transcription、older_transcription_stream、older_realtime_ws_replay(后两个照旧 cfg(feature = "realtime"));openai_upstream_e2e_test.rs → tests/responses/responses_language_model.rs 的 older_upstream_e2e(47 个里大半是 Responses,和 Google 把 e2e 放进 language_model 一样)。
    • 内联测试:convert.rs 的进 tests/chat/convert_to_chat_messages.rs 的 older_convert,model.rs 的 stream_tests 进 tests/chat/chat_language_model.rs 的 older_stream,responses/convert.rs 的进 tests/responses/convert_to_responses_input.rs 的 older_responses_convert;use super::* 换成新模块的 glob 和原文件用到的 import。
    • 每节前一行注释写明原来的位置,老文件头的说明改成普通注释。mock_fetch 改用 crate::test_support::mock_fetch;决策测试用的 common::replay::mount_recording 改用 crate::test_support::replay(test_support/mod.rs 加一行 #[path] 引 tests/common/replay.rs,它的 3 个内联测试随之从决策程序搬进 lib,数量不变);aimux_providers:: 改成 crate::;include_str!("fixtures/…") 和 ../../contract-tests/… 改成按 CARGO_MANIFEST_DIR 算,fixture 文件留在原处(别的程序也用)。test: port the upstream OpenAI tests #369 测试里的 convert::、model::、types::、convert_common::、responses::convert::、responses::responses_convert:: import 改到新路径。断言都没改。
  • 留在 tests/ 的:tests/openai_output_round_trip_test.rs(还用 DeepSeek,跨厂商)、openai_compatible_*(另一个厂商)和其余跨厂商的测试程序。
  • layout.toml 的 [openai] 里 57 个 rust 字段改到新路径,末尾加两条 status = "aimux"(openai/decision.rs、openai/responses/tool_args.rs,带 reason)。
  • scripts/check_provider_boundaries.sh:rule 1 的放行正则里 openai/transcription\.rs 改成 openai/transcription/transcription_model\.rs;rule 4b("groq" / "deepseek" 字面量)加 --exclude-dir=tests,因为 older_decision 有一个用例建 DeepSeek preset 来确认它没有决策模型(anthropic 那边的规则同样跳过厂商测试)。
  • 合并了 test: port the upstream OpenAI tests #369 分支新的 41a66c7a(只改 bindings/python/tests/ops_fixtures.py),用 merge commit,没有改历史。

共享进程状态

老测试原来各是单独的测试程序,现在和 #369 的用例、别家的 lib 用例同在 lib 的一个测试程序里。

  • OPENAI_BASE_URL:test: port the upstream OpenAI tests #369 的 tests/provider.rs 有 4 个 #[serial] 用例设它,default_providers.rs 的一个 #[serial] 用例设成 "not a url"。用 OPENAI_BASE_URL="not a url" 跑整个 lib 测试程序,older_factory 的 12 个用例挂了:它的 settings() 不给 base_url,建 provider 时读环境变量。修法是改 setup:settings()(tests/provider.rs:353)和两个自己写设置的用例显式给 DEFAULT_BASE_URL(fixture 录的就是默认地址),加了注释。改后 OPENAI_BASE_URL="not a url"、OPENAI_BASE_URL="https://leak.example/v1" 下 990 个全过。
  • OPENAI_API_KEY:older_factory 的 missing_api_key_fails_the_call_not_the_factory、an_explicit_empty_key_is_sent_as_given 设它,本来就是 #[serial],测的正是读环境变量,保留。用 OPENAI_API_KEY="leak-key" 和 OPENAI_API_KEY="" 跑整个 lib 测试程序,990 个全过,没有别的用例依赖它。
  • 全局录制器:older_decision 里两个用例 recording::init_recording 装进程级的录制器,装着的时候本进程里每个 decide 调用都会被录进去。这 12 个调 decide 的用例原来是 #[serial],改成 #[serial(recording)],只在彼此之间串行,不再和环境变量的用例抢同一把锁;lib 里没有别的用例调 decide(test: port the upstream OpenAI tests #369 的 evaluation.rs 用 do_decide,不经录制)。
  • wiremock 池:并进来的老用例用 MockServer::start()。没有在请求途中丢客户端的用例(中途取消的转写用例用自己的 TcpListener WebSocket 服务器,不走池);lib 测试程序连跑 24 次,其中 8 次 --test-threads=32,没有看到晚到的请求。
  • 默认 transport:没有换进程默认 transport 的用例;openai() 默认实例 lib 测试里没人用(stream/chat_tool_calls_tests.rs 的 Harness::openai() 是同名的测试辅助函数)。

CHANGELOG

CHANGELOG Unreleased 的 Breaking 末尾加了一条,列出本家变了的公开子模块路径和替代入口(RFC-0046 §4.5 第 2 条):

- OpenAI's sub-modules follow the `@ai-sdk/openai` files (RFC-0046 §4.2):
  `openai::convert`, `openai::model`, `openai::responses::convert`,
  `openai::responses::responses_convert` and `openai::responses::types` are no
  longer public. `openai::model::OpenAIModel` is `openai::OpenAIModel`, as the
  crate root already exports it. The Responses types of `responses::convert`
  and `responses::types` are at `openai::responses`:
  `openai::responses::{PreparedResponsesTools, parse_usage, ResponsesUsage,
  ResponsesInputTokensDetails, ResponsesOutputTokensDetails}`, next to the
  functions it already exported. The Chat Completions helpers of `convert`
  (`SystemMessageMode`, `ToolWarning`, `PreparedTools`, `prepare_tools`,
  `convert_prompt_to_openai_messages_with_mode_fallible`, `RequestBodyResult`,
  `build_request_body_with_warnings`, `parse_finish_reason`) and the shared
  Responses parser of `responses_convert` (`ResponsesEventStream`,
  `build_responses_generate_result`, `build_responses_event_stream`) become
  crate-internal, with no public replacement; `build_request_body` and
  `build_header_list`, which nothing in the workspace called, are removed.
  `openai::completion`, `openai::decision`, `openai::embedding`,
  `openai::files`, `openai::image`, `openai::responses`, `openai::speech`,
  `openai::tools` and `openai::transcription` keep their paths.

验证

  • cargo test -p aimux-providers --all-features --lib 加原来九个 --test:前后都是 990 个测试(前 lib 846 + 144,后 lib 990),函数名多重集相同;openai:: 下 712 → 853,另 3 个是 test_support::replay 的内联测试。lib 测试程序连跑 24 次(8 次 32 线程,其余 4 到 12 线程),990 个全过。
  • cargo +1.99 clippy -p aimux-providers --lib --tests -- -D warnings、同样加 --all-features、RUSTDOCFLAGS="-D warnings" cargo +1.99 doc -p aimux-providers --no-deps、cargo fmt --all -- --check、bash scripts/check_provider_boundaries.sh、cargo +1.99 check --workspace --tests、cargo test -p aimux-providers(121 个测试程序,3116 过)通过。

Type of change

  • Refactor (no behavior change)

Checklist

  • Tests pass locally
  • Commit messages follow Conventional Commits

🤖 Generated with Claude Code

https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW

Split src/openai/ into one file per @ai-sdk/openai 4.0.83 source file
(RFC-0046 §4.2), with chat/, completion/, embedding/, files/, image/,
responses/, speech/, transcription/ and tool/ as upstream. Function bodies
only change paths and visibility; the crate-root and openai-root exports are
unchanged, and the sub-modules that were public are listed in the CHANGELOG.
The paths the other vendors import (convert, model, options,
responses::responses_convert) stay as crate-internal re-exports at the
openai root. The old tests/openai_*_test.rs programs and the inline tests
move into src/openai/tests/ with equal test names and counts.

The factory replays pass the default base URL explicitly, so they no longer
read OPENAI_BASE_URL while the env cases of the same binary set it; the
decision cases that call decide share a serial key, as two of them install
the process-wide recorder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 (1M context) <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.

OpenAI layout refactor:2453→2453 tests,move-only,公开 re-export 保留;建议把 boundary-script 的 tests 全局 exclusion 收窄到具体文件。Approve。

… deepseek

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

Copy link
Copy Markdown
Contributor Author
eric 的意见(原话) 处理
「建议把 boundary-script 的 tests 全局 exclusion 收窄到具体文件」 已改,e4535b1c:规则 4b 去掉 --exclude-dir=tests,只跳过两个文件:openai/tests/evaluation.rs(检查别的预设没有决策模型,写到 "deepseek")和 openai_compatible/tests/provider.rs(夹具录制时的服务商名是 groq)。#356 原来也加了 --exclude-dir=tests,写法不同,两个 PR 会在这几行冲突;#356 的 e41d394f 改成完全相同的几行。验证:边界脚本在两个分支都通过;在 openai_compatible/mod.rs 临时加一行 "groq" 时规则 4b 照样报出来。

Generated by Claude Code

The reasoning-delta case of openai_upstream_e2e_test.rs, which now rotates
the item id on later events, takes the same change in
src/openai/tests/responses/responses_language_model.rs, where the move put it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 (1M context) <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.

Verified the post-approval commits on this head: only additive tests/docs or tightened boundary checks; no weakening or behavior regression. Re-approving the current head.

…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
…sts' into refactor/move-the-openai-files-to-the-upstream-layout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
@eric8810
eric8810 changed the base branch from test/port-the-upstream-openai-tests to master October 27, 2026 11:00
@eric8810
eric8810 merged commit f70018a into master Oct 27, 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