Repository navigation
refactor: move the OpenAI files to the upstream layout - #370
Merged
eric8810 merged 12 commits intoOct 27, 2026
Merged
Conversation
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
cunninghamcard-bit
marked this pull request as ready for review
October 24, 2026 13:14
34 of 57 tasks
eric8810
approved these changes
Oct 25, 2026
eric8810
left a comment
Contributor
There was a problem hiding this comment.
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
Contributor
Author
Generated by Claude Code |
3 tasks done
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
approved these changes
Oct 27, 2026
eric8810
left a comment
Contributor
There was a problem hiding this comment.
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
changed the base branch from
test/port-the-upstream-openai-tests
to
master
October 27, 2026 11:00
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
把
src/openai/按@ai-sdk/openai4.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)上游同一条路:
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 改动(细节)
mod.rs的模块文档、mod、pub usemod.rs(模块声明、导出和给别家用的 crate 内路径)index.ts、internal/index.tsmod.rs的常量、设置、create_openai、openai、OpenAIProvider和实现;model.rs的ModelsListResponse、ModelEntry、list_models_onceprovider.rsopenai-provider.ts(list_models_once是 aimux 的模型发现,跟 provider 放一起,和 Google 一样)mod.rs的openai_failed_response_handler/openai_stream_errorerror.rs/stream_error.rsopenai-error.ts/openai-stream-error.tsconvert_common.rslanguage_model_capabilities.rs(原样)openai-language-model-capabilities.tsconvert.rs的normalize_json_schema、contains_lookaroundnormalize_json_schema.rsnormalize-openai-json-schema.tsmodel.rs;convert.rs的RequestBodyResult到build_request_body_with_chat_options(getArgs那组)chat/chat_language_model.rschat/openai-chat-language-model.ts(getResponseMetadata在这里内联,chat/get-response-metadata.ts指向它)options.rs;convert.rs的parse_option_fields、parse_chat_provider_options、openai_optionchat/chat_language_model_options.rschat/openai-chat-language-model-options.tsconvert.rs的提示词转换(convert_prompt_to_openai_messages_with_mode_fallible到convert_text_part_to_openai)chat/convert_to_chat_messages.rschat/convert-to-openai-chat-messages.ts(chat/openai-chat-prompt.ts的消息形状在 aimux 里是 JSON,指向这里)convert.rs的ToolWarning、PreparedTools、prepare_tools/parse_finish_reasonchat/chat_prepare_tools.rs/chat/map_finish_reason.rschat/openai-chat-prepare-tools.ts/chat/map-openai-finish-reason.tsmodel.rs的convert_usage/types.rschat/convert_chat_usage.rs/chat/chat_api.rschat/convert-openai-chat-usage.ts/chat/openai-chat-api.tscompletion.rscompletion/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.rsembedding/openai-embedding-api.ts/-model-options.ts/-model.tsfiles.rs的响应结构 / 选项 / 其余files/files_api.rs/files_options.rs/files.rsfiles/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.rsimage/openai-image-model-options.ts/-model.ts(响应在 aimux 里按 JSON 读,openai-image-api.ts指向image_model.rs)speech.rsspeech/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.rstranscription/openai-transcription-model-options.ts/-api.ts/-model.tsresponses/mod.rs的模型;responses/convert.rs的请求体那组;responses/responses_convert.rs;responses/provider_events.rsresponses/responses_language_model.rsresponses/openai-responses-language-model.ts(openai-responses-provider-metadata.ts只有类型,aimux 在这里写 JSON,指向它)responses/convert.rs的命名空间和openai_option/ 输入转换和 file id 前缀 / 工具准备 / usage / finish reasonresponses/responses_language_model_options.rs/convert_to_responses_input.rs/responses_prepare_tools.rs/convert_responses_usage.rs/map_responses_finish_reason.rsresponses/types.rsresponses/responses_api.rs(原样)responses/openai-responses-api.tsresponses/tool_args.rstool/*.ts的 input schema 集中在一处校验(layout.toml 记为aimux)tools.rs的 13 组参数类型和工厂函数 /OpenAITools、AzureOpenAITools、provider_tooltool/apply_patch.rs…tool/web_search_preview.rs/tools.rs(再导出tool/的全部公开项)tool/*.ts/openai-tools.tsdecision.rs、config.rsdecision.rs第一行注明 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 扩展留在原目录。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/导出)。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 那边的规则同样跳过厂商测试)。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,不经录制)。MockServer::start()。没有在请求途中丢客户端的用例(中途取消的转写用例用自己的TcpListenerWebSocket 服务器,不走池);lib 测试程序连跑 24 次,其中 8 次--test-threads=32,没有看到晚到的请求。openai()默认实例 lib 测试里没人用(stream/chat_tool_calls_tests.rs的Harness::openai()是同名的测试辅助函数)。CHANGELOG
CHANGELOG Unreleased 的 Breaking 末尾加了一条,列出本家变了的公开子模块路径和替代入口(RFC-0046 §4.5 第 2 条):
验证
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
Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW