Skip to content

RFC-0044: crate 拆分与依赖反转 - #279

Merged
eric8810 merged 15 commits into
masterfrom
claude/project-thread-7qaqe4
Oct 21, 2026
Merged

eric8810 merged 15 commits into
masterfrom
claude/project-thread-7qaqe4

Conversation

@cunninghamcard-bit

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

Copy link
Copy Markdown
Contributor

Summary

新增 rfc/0044-crate-layering-and-dependency-inversion.md,只有这一个文件,不改代码。

对齐文档第 2 章 D17 定了五层目标,但没有说怎么从现在的代码走过去。本文补上这部分:aimux-core 按职责拆进 aimux-provider、aimux-provider-utils、aimux、aimux-devtools;core 里直接调用的录制、session、trace、下载改成依赖反转;aimux-stream 并入 provider-utils。aimux-providers 内部的厂商目录和测试不在本文范围,见 RFC-0046(#294),本文的步骤不依赖它。

实施进度在 #328 跟踪。

一、体系现状(概览,master 5743a40a)

crate 依赖

aimux-ffi
 └ aimux-ops
    ├ aimux-providers ─┬ aimux-provider-utils ─┬ aimux-core
    │                  │                       └ aimux-stream
    │                  ├ aimux-stream
    │                  └ aimux-core
    ├ aimux-provider-utils
    └ aimux-core            (规格类型、运行时、录制、session、下载、重试全在这里)

一次文本生成从入口走到网络(右侧是所在 crate)

aimux_call                                         aimux-ffi/src/abi.rs:138               ffi
 └ dispatch::call → Dispatcher::call               aimux-ops/src/dispatch.rs:298 → :115   ops
   └ ops::text::generate                           aimux-ops/src/ops/text.rs:213          ops
     └ generate_text                               aimux-core/src/generate.rs:976         core
       ├ session_store() / resolve_session_id      aimux-core/src/generate.rs:1130-1131   core
       ├ recording::recorder() + RecordingContext  aimux-core/src/generate.rs:1101, :1153 core
       └ model.do_generate                         aimux-core/src/generate.rs:2294        core
         └ OpenAI do_generate → execute_generate   aimux-providers/src/openai/model.rs:166 → :221   providers
           └ HttpRequest::new(读录制上下文)       aimux-provider-utils/src/http.rs:168 → :126      provider-utils
           └ post_json_to_api(写录制)            aimux-provider-utils/src/http.rs:647 → :861      provider-utils
             └ reqwest

stream_text                                        aimux-core/src/generate.rs:1563        core
 └ model.do_stream                                 aimux-core/src/generate.rs:1693        core
   └ OpenAI do_stream → execute_stream             aimux-providers/src/openai/model.rs:184 → :376   providers
     └ create_event_source_response_handler        aimux-provider-utils/src/response_handler.rs:358 provider-utils
       └ aimux_stream::SseStream::new              aimux-provider-utils/src/response_handler.rs:389 stream

上游同一条路:generateText(ai)→ model.doGenerate(@ai-sdk/openai)→ postJsonToApi(provider-utils)→ fetch。规格类型在 @ai-sdk/provider,运行时不管录制和 session,devtools 从外面接入。

二、本 PR 改动(细节)

1. 录制:provider-utils 不再读写 core 的录制

现在:

generate_in_operation                              aimux-core/src/generate.rs:1062
 └ recording::recorder()                           aimux-core/src/generate.rs:1101   ← 全局 RECORDER(recording.rs:605)
 └ RecordingContext::scope(…)                      aimux-core/src/generate.rs:1153
   └ … OpenAI execute_generate                     aimux-providers/src/openai/model.rs:221
     └ config.http_request → HttpRequest::new      aimux-providers/src/openai/config.rs:180 → aimux-provider-utils/src/http.rs:168
       └ RecordingContext::current()               aimux-provider-utils/src/http.rs:126 → aimux-core/src/recording.rs:695
     └ post_json_to_api → record_exchange          aimux-provider-utils/src/http.rs:647 → :861 → aimux-core/src/recording.rs:568
(decide 同理:DecisionCallOptions 的 ExchangeContext 在 aimux-provider-utils/src/http.rs:130-140 读同一个 RecordingContext::current())

改成:

aimux::generate_text / decide
 └ 建立 DiagnosticScope(provider-utils,task-local,§4.2)
     { call_id, model_call: { seq, attempt, parent }, 交换计数器, observers }
     observers 是 scope 的构造参数,不放进 OperationSettings(它会序列化、写进录制,operation.rs:29、recording.rs:214)
   ├ retry 每次尝试递增 attempt;router、MoA 的子调用进子 scope,取新 seq
   └ model.do_generate → OpenAI → post_json_to_api
     └ Fetch 链:协议 fetch → 鉴权 fetch → 观察点(provider-utils)→ 用户或默认 fetch
                                           └ 从当前 scope 取关联,给交换编号 <seq>.<attempt>.<index>
                                           └ 交给 scope 里的 observers(取代全局 RECORDER;C3 到 C5 是 core 的 Recorder,init_recording 打开后由操作入口装上;C6 后是 aimux-devtools 的)

provider-utils 不再认识 RecordingContext。C3 就定下这一组关联,文本生成和 decide 两条路径(http.rs:118-128、:130-140)和写录制(:861-867)一起改,C3 到 C5 之间录制不丢调用关联。RFC-0048(#325)的 exchangeId 建在这上面。

上游没有 Fetch 层观察者:每个 telemetry 事件都带 callId(ai/src/generate-text/generate-text.ts:669 生成),executeLanguageModelCall(ai/src/telemetry/telemetry.ts:332-337)让模型调用跑在集成提供的上下文里;devtools 是 telemetry 集成加模型 middleware(devtools/src/integration.ts:113、devtools/src/middleware.ts:101)。Fetch 层录制是 aimux 扩展(RFC-0036 的 L0),已在 §7 登记。

2. session:运行时只传一个字符串

现在:

generate_text                                      aimux-core/src/generate.rs:976
 └ session::resolve_session_id(…)                  aimux-core/src/generate.rs:1130
 └ session::session_store()                        aimux-core/src/generate.rs:1131 → aimux-core/src/session.rs:333
   └ static SESSION_STORE                          aimux-core/src/session.rs:320

改成:

aimux::generate_text:settings.session_id 原样交给观测层
 └ aimux-devtools:推断、索引、与录制关联(无全局量)

上游 generateText 没有 session。去掉 AIMUX_SESSION_INFER 是公开行为变化,已在 §7 登记。

3. 下载:两份重定向循环合成一份

现在:

generate_video                                     aimux-core/src/video_model.rs:463
 └ create_download(None)                           aimux-core/src/video_model.rs:535 → aimux-core/src/download.rs:106
   └ download_inner                                aimux-core/src/download.rs:239
     └ for redirects in 0..=MAX_DOWNLOAD_REDIRECTS aimux-core/src/download.rs:244
       └ reqwest::Client::builder().no_proxy()     aimux-core/src/download.rs:259-260,UA aimux/<版本>(:266-269)

send_following_redirects                           aimux-provider-utils/src/http.rs:429
 └ validate_download_target(反向依赖 core)       aimux-provider-utils/src/http.rs:444 → aimux-core/src/download_guard.rs:101
 └ for redirect_count in 0..=MAX_REDIRECTS         aimux-provider-utils/src/http.rs:453(默认传输的代理,:458-466)

改成:

aimux::generate_video → options.download(接口类型在 aimux-provider)
 └ 默认实现 → aimux-provider-utils 的不可信 URL 下载(一份地址校验、一份逐跳重定向)
     └ 三个参数:连接策略(操作直连,保持 no_proxy / provider 走默认传输的代理,D26)
                 UA 来源(固定 aimux/<版本> / 请求自带)
                 错误映射(Other、InvalidArgument / ApiCall)

C4 是重构:各路径的代理、UA、错误变体保持现状(§4.3 对照表)。上游只有一份:ai/src/generate-video/generate-video.ts:387 → ai/src/util/download/download.ts:39 → provider-utils fetchUntrustedUrl,UA 是 ai-sdk/<版本>,失败抛 DownloadError;要不要照上游改是 §9 的待讨论项。

4. SSE:aimux-stream 并入 provider-utils

现在:

create_event_source_response_handler               aimux-provider-utils/src/response_handler.rs:358
 └ aimux_stream::SseStream::new                    aimux-provider-utils/src/response_handler.rs:389
   └ aimux-stream/src/sse.rs(约 120 行,包在第三方 sse-stream 外)

改成:

create_event_source_response_handler → provider-utils 内部的 SSE 解码 → sse-stream

上游:provider-utils parseJsonEventStream 直接用第三方 eventsource-parser。这是对 D17 的改动,已在 §7 登记。aimux-stream 0.5.0 已发布,删除前用当前代码发最后一个版本说明去向,不撤回旧版本。

5. 改完后的 crate 依赖

aimux-ffi → aimux-ops ─┬ aimux(运行时)──────┐
                       ├ aimux-providers ─────┤
                       └ aimux-devtools ──────┼ aimux-provider-utils → aimux-provider
                                              └(只往下依赖,不再有往上的边)

Provider 和 ProviderDiscovery 都在 aimux-provider(Provider::discovery() 返回 &dyn ProviderDiscovery);StreamPart::into_text_stream_part 改成 aimux 里的自由函数。

发布顺序:provider → provider-utils → aimux → providers → ops → ffi,C6 之后 devtools 排在 providers 和 ops 之间。C7 可以早于 C6,那时 providers 还依赖 aimux;aimux 不依赖 providers,所以这个顺序在 C6 前后都成立。

步骤

步骤 内容 前置
C0 aimux-stream 并入 provider-utils(删除前发最后一个版本) 无
C1 core 内部按层拆开混合文件 #268 合入
C2 新建 aimux-provider,先断三条往上的边 C1
C3 Fetch 观察点和 DiagnosticScope(含 decide、retry 的 attempt、组合模型的子 scope),provider-utils 不再依赖 core C2
C4 下载归一(行为保持现状,三个参数) C3
C5 session、trace 在调用层接入(等后续观测 RFC) C3、后续 RFC
C6 新建 aimux-devtools C5
C7 改名与发布顺序(aimux 先于 providers) C4

Type of change

  • Docs / RFC

Checklist

  • Updated relevant docs (rfc/)
  • Commit messages follow Conventional Commits

纯文档,cargo 检查不受影响。

Notes for reviewers

🤖 Generated with Claude Code

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
aimux-stream is a ~120-line adapter over sse-stream plus an unused
extract_lines; its only caller is provider-utils. Upstream keeps SSE
decoding in provider-utils over eventsource-parser. Registers the change
to alignment doc D17.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
RFC-0044 keeps the crate split and dependency inversion; the per-vendor
directory, test placement and cross-vendor reuse rules move to a
separate RFC-0046.

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
Fix the recording, session, download and trace call stacks against
master; assign the unassigned modules (decision, files and skills
models, math, util, prelude, replay mocks, rebuild_decision_provider);
name the three upward edges C2 must cut; add test ownership rules;
register the alignment-doc conflicts and list the open questions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
Record li's opinion that aimux-core keeps its name instead of the D17
rename to aimux; register the difference for the maintainer to decide.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
Contributor opinions go to PR comments, not the RFC text.

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

贡献者意见(li),供维护者决定:

  • aimux-core 不改名。RFC 现在按对齐文档 D17 写的是拆完后改名 aimux;我倾向保留 aimux-core 这个名字,作为对齐文档里的 aimux 层。这样 crates.io 不用换包名,也不会和命令行工具的二进制 aimux 重名。

Generated by Claude Code

@cunninghamcard-bit

Copy link
Copy Markdown
Contributor Author

有三个问题想先对齐。

  1. C3 要求 HTTP 层不再读 RecordingContext(§6 C3)。但现在 exchange 记在哪个调用下,靠的就是它。文本生成走 aimux-provider-utils/src/http.rs:118-128,decide 走 :130-140,写录制在 :861-867。§4 把"显式传入还是用作用域"留给了后续 RFC。C3 合入时用哪一种?两种都不用的话,C3 到 C5 之间录制会丢掉调用关联,这段需要登记。上游 telemetry 事件始终带 callId(packages/ai/src/telemetry/telemetry.ts:316-339),可以照这个在 C3 就定下来。C3 一行也应写明 decide 在范围内。
  2. §4.1 说不造事件接口,§6 说 录制 schema 3 与传输层回放(发布前,RFC-0041) #270 建在 C5、C6 的订阅接口上,§7 又说按上游 devtools 的方式以订阅接入。这三处需要统一成一种说法。
  3. RFC 正文 §2.3 对上游 devtools 的描述没问题。PR 描述却在录制一节把 devtools/src/middleware.ts:101 当成 Fetch 层观察点的上游对照。devToolsMiddleware 是模型 middleware,不是 Fetch 层观察者。Fetch 层录制是 RFC-0036 L0 的 aimux 扩展,建议登记到对齐文档 §5。另外,上游 devtools 在 NODE_ENV === 'production' 时直接抛错(middleware.ts:102-107、integration.ts:116-121),而 §7 写 ops 默认装上 devtools,这个差异也没有登记。

几处小问题:

  • 决策表缺 L7。
  • PR 标题和文件名还带"provider 目录布局"。
  • RFC-0046 还没有文件,正文 9 处引用它(:7、:11、:24、:149、:236、:253、:258、:259、:279),目前都没法核对。
  • 验收第 2 条"没有 static 可变全局"会挡住照上游做的全局 telemetry 注册(packages/ai/src/global.ts:36)。
  • 用 #[cfg(test)] 编译的 test_support,tests/ 下的集成测试看不到。

…bservation wording, register devtools differences

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
@cunninghamcard-bit cunninghamcard-bit changed the title RFC-0044: crate 拆分、依赖反转与 provider 目录布局 RFC-0044: crate 拆分与依赖反转 Oct 19, 2026

Copy link
Copy Markdown
Contributor Author

逐条处理如下,都在 d23cef1。

意见 处理 位置
1. C3 之后 exchange 靠什么归属调用;C3 到 C5 之间录制会不会丢关联;decide 是否在范围内 C3 就定下来:用对齐文档 D3、§3.5 已定的传输可见 scope DiagnosticScope(task-local,放在 provider-utils,带 call_id)。aimux 的操作在调用模型前建立它,观察点从当前 scope 取 call_id;流式 body 在发出时拿到关联。对应上游每个事件都带的 callId(generate-text.ts:669)和 executeLanguageModelCall(telemetry.ts:332-337)。C3 一行写明文本生成和 decide 两条路径(http.rs:118-128、:130-140)和写录制(:861-867)一起改,router、MoA、composite 同样建立 scope。这样 C3 到 C5 之间不丢关联,不需要另外登记 §1 L3、§4 表第一行、§6 C3
2. §4.1、§6、§7 三处说法不一致 统一成两层:传输层由本文定(Fetch 观察点加 DiagnosticScope,C3),录制和 #270 的传输回放建在它上面;调用层(模型调用开始与结束、session 归组、缓存审计)的接入方式留给后续 RFC,本文不造调用层事件接口。§6 改为“#270 建在 C3 的 Fetch 观察点和 C6 的 aimux-devtools 上”;§7 删掉“以订阅接入”,改为“接入方式由后续 RFC 定(§4.1)” §4.1、§6、§7
3. PR 描述把 devToolsMiddleware 当作 Fetch 层观察点的上游对照;devtools 生产环境抛错的差异没有登记 PR 描述改为:上游没有 Fetch 层观察者,devtools 是 telemetry 集成加模型 middleware,Fetch 层录制是 aimux 扩展(RFC-0036 L0)。§2.3 补了同样的说明和 NODE_ENV === 'production' 抛错(middleware.ts:102-107、integration.ts:116-121)。§7 登记两条,写入对齐文档 §5:录制在 Fetch 层;devtools 用于生产(录制、回放是产品功能,RFC-0023、RFC-0041,ops 默认装上) PR 描述、§2.3、§7
决策表缺 L7 原来的 L7(provider 目录)已移出本文,L8、L9 顺延为 L7、L8,C0 和 §7 的引用同步 §1、§6、§7
PR 标题和文件名还带“provider 目录布局” 文件改名为 rfc/0044-crate-layering-and-dependency-inversion.md,PR 标题改为“RFC-0044: crate 拆分与依赖反转” 文件名、PR 标题
RFC-0046 还没有文件,正文 9 处引用无法核对 9 处都去掉了。改为说明 aimux-providers 内部的目录和测试不在本文范围、另写 RFC(草稿,尚未提交),本文的步骤不依赖它;#273 一条直接写本文不加按厂商的 cargo feature :7、:11、L6、§2.4、§5、§6、§7
验收第 2 条会挡住照上游做的全局 telemetry 注册 改为:§4 列出的四个全局量不再存在;其余 static 可变全局进允许列表,每项注明对应的上游全局(如 telemetry-registry.ts:6、global.ts:54,按 fce9210 的行号);task-local 的操作设置和 DiagnosticScope 不算 §8 第 2 条
#[cfg(test)] 的 test_support 在 tests/ 下看不到 改为 #[cfg(any(test, feature = "test-support"))];本 crate 的集成测试经自引用的 dev 依赖开启这个 feature,下游 crate 在自己的 dev 依赖里开启,正常构建不带。自引用 dev 依赖在本机用一个小 crate 试过,tests/ 能用到 §3.3 第 4 条

Generated by Claude Code

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

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0116HPMoqaLfFr1TyqDq1hrW
Follows RFC-0046 section 5: each module directory has a tests/ child,
one Rust file per upstream test file; crate tests/ keeps only
cross-module scenarios.

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

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

Review

现状调用图基本准确,但步骤按文本走不通:

  • 阻塞 ProviderDiscovery 搬去 aimux-providers,但 Provider::discovery() 返回 &dyn ProviderDiscovery,会形成 aimux-provider -> aimux-providers 反向依赖;建议把 trait 留在 provider,或移除 Provider::discovery()。
  • 阻塞 StreamPart::into_text_stream_part 是 inherent impl;StreamPart 去 provider、TextStreamPart 去 aimux 后,这个 impl 无法跟着走,需要改成 aimux 中的自由函数/扩展 trait。
  • 重要 C3 的 DiagnosticScope 只有 call_id,录制需要 attempt/exchange index/observer route;与 #325 是同一缺口。
  • 重要 C4 统一下载会改变 proxy、UA、错误变体;当前 core 下载 no_proxy() 且带 aimux/<version> UA,需要明确 parity。
  • 重要 C7 依赖 C6,C6 依赖 C5,而 C5 等未写的观测 RFC;aimux-ops/src/manifest/controls.rs 还硬编码 14 处 aimux_core::...,重生成不会自动改成新 crate 名。
  • 重要 C0 删除已发布的 aimux-stream,没有 deprecation/最终版本方案。

Keep ProviderDiscovery beside Provider and turn into_text_stream_part
into a free function in aimux. Spell out what DiagnosticScope carries
(call id, seq/attempt/parent, exchange counter, observers) and the
download parity C4 keeps. Let the C7 rename follow C4 instead of the
devtools steps, note that #268 removed the generated aimux_core paths,
and plan a final aimux-stream release before C0 deletes it.

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

逐条处理如下,都在 adf6c61。左列是 @eric8810 的原话。

eric 的意见 核对 处理 位置
阻塞 ProviderDiscovery 搬去 aimux-providers,但 Provider::discovery() 返回 &dyn ProviderDiscovery,会形成 aimux-provider -> aimux-providers 反向依赖;建议把 trait 留在 provider,或移除 Provider::discovery() 属实(provider.rs:142、:152)。custom_provider、wrap_provider、ops 都调 discovery(),移除要改三处调用方 trait 和 Provider 一起留在 aimux-provider;custom_provider_test 随 custom_provider 去 aimux,不再去 ops §2.2、§3.1、§3.3 第 3 条
阻塞 StreamPart::into_text_stream_part 是 inherent impl;StreamPart 去 provider、TextStreamPart 去 aimux 后,这个 impl 无法跟着走,需要改成 aimux 中的自由函数/扩展 trait 属实(stream_part.rs:456-461,调用方 generate.rs:1903、ai_sdk_json_test.rs:488-502) 改成 aimux 里 stream_text 旁边的自由函数 §2.2
重要 C3 的 DiagnosticScope 只有 call_id,录制需要 attempt/exchange index/observer route;与 #325 是同一缺口 属实,RFC-0048 的 exchangeId 是 <seq>.<attempt>.<index> 新增 §4.2,定下 scope 的内容:call_id;model_call { seq, attempt, parent }(router、MoA 子 scope 取新 seq,retry 递增 attempt);每个 (seq, attempt) 内的交换计数器;observers(宿主经操作设置装上,取代全局 RECORDER)。C3 就由 retry 和组合模型设置这些值 §4 表第一行、§4.2、§6 C3
重要 C4 统一下载会改变 proxy、UA、错误变体;当前 core 下载 no_proxy() 且带 aimux/<version> UA,需要明确 parity 属实(download.rs:259-269;provider 下载走默认传输的代理,http.rs:458-466,错误是 ApiCall,http.rs:400-406) 新增 §4.3 对照表:C4 是重构,各路径的代理、UA、错误变体保持现状,不可信 URL 下载带一个连接策略参数;重定向循环和大小上限合成一份。照上游 download.ts 改 UA 和 DownloadError 列为 §9 待讨论 §4.3、§6 C4、§9
重要 C7 依赖 C6,C6 依赖 C5,而 C5 等未写的观测 RFC;aimux-ops/src/manifest/controls.rs 还硬编码 14 处 aimux_core::...,重生成不会自动改成新 crate 名 依赖链属实。controls.rs 那 14 处在基线 5743a40a 上有,#268 已删掉 controls.rs 和 schema/ops/type-*.json,master@c0622ea4 的 schema/ 里没有 aimux_core 路径;ops 里剩 30 处 TypeRef::of::<aimux_core::…> 是 Rust 路径 C7 前置改为 C4,不等观测 RFC;发布顺序先不含 devtools,C6 之后加入;C7 写明重生成后检查生成物不含 aimux_core,30 处 Rust 路径随改名一起改。(li 在本 PR 的贡献者意见是不改名,保留 aimux-core;若采纳,C7 只剩发布顺序) §6 C7 与其后一段
重要 C0 删除已发布的 aimux-stream,没有 deprecation/最终版本方案 属实,0.5.0 已发布 和 aimux-core 同样处理:删除前用当前代码发最后一个版本,README 和 crate 文档第一行写明已并入 aimux-provider-utils、不再维护,不撤回旧版本,CHANGELOG 记一条 §6 C0、§9

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.

复审(adf6c618)

之前 6 条基本都改到了:ProviderDiscovery 留在 provider、StreamPart 改自由函数、C3 scope 补齐、C4 parity、C7/C0 补方案。还有两个需要先改:

  • 重要 C7 的发布顺序仍不成立:C7 现在只需 C4,可以在 C6 前做;此时 providers 仍依赖 core,改名后 providers 会依赖未发布的 aimux,而发布顺序写的是 providers 在 aimux 前。把 C7 放回 C6 之后,或把顺序改成 provider → provider-utils → aimux → providers。
  • 重要 §4.2 说 observers 通过 OperationSettings 安装,但 OperationSettings 是 Serialize/Deserialize/Clone/Eq 且会写进录制,放不了 Arc<dyn Observer>。请明确载体(独立 task-local/scope 构造参数)和 C3–C5 期间用 core Recorder 做 observer 的过渡。
  • 次要 C4 的 parity 还需要 UA 和错误映射参数,单靠“连接策略参数”不够。
  • 次要 §4.3 引用 “RFC-0047 (#290)”,RFC-0047 是 #286,#290 是错误 cause 的实现 PR。
  • 提示 基线 5743a40a 与部分行号不匹配(stream_part.rs:456-461、generate.rs:1903 在声明的基线上是 492、1925)。

Publish order puts aimux before providers so C7 can land before C6; observers
ride on DiagnosticScope instead of OperationSettings, with core's Recorder as
the C3-C5 observer; C4's download takes connection, user-agent and error-mapping
parameters; RFC-0047 cited as #286; line references refreshed at 5743a40.

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

第二轮复审(review 5586872522)逐条处理,改动在 22a4e90。下表左列是 eric 的原话(摘要),每条都在 master@5743a40a 上对过代码。

eric 的意见 核对 处理
重要:C7 的发布顺序不成立。C7 只需 C4,可以在 C6 前做,那时 providers 仍依赖 core,改名后 providers 会依赖还没发布的 aimux,而发布顺序写的是 providers 在 aimux 前 属实。aimux-core/Cargo.toml 没有任何 aimux 依赖,providers 依赖 core 采用第二种改法:顺序改成 provider → provider-utils → aimux → providers → ops → ffi,C6 之后 devtools 排在 providers 和 ops 之间。C7 一行写明理由:C6 之前 providers 依赖 aimux,aimux 不依赖 providers,所以这个顺序在 C6 前后都成立。C7 仍只依赖 C4
重要:§4.2 说 observers 经 OperationSettings 安装,但 OperationSettings 是 Serialize/Deserialize/Clone/Eq,而且会写进录制,放不了 Arc<dyn Observer> 属实:derive 在 operation.rs:29,写进录制在 recording.rs:214 §4.2 写明载体是 DiagnosticScope 本身。它和 OperationSettings::current() 一样是 task-local,但是单独的一个值,宿主用它的构造参数装 observer。过渡期:C3 让 core 现在的 Recorder(全局 RECORDER,recording.rs:605)实现观察者接口;init_recording 打开录制后,操作入口把它放进本次 scope,HTTP 层不再读全局量。全局开关留到 C5 去掉,C6 把 Recorder 搬进 devtools
次要:C4 的 parity 还需要 UA 和错误映射参数,单靠“连接策略参数”不够 属实 §4.3 的三行改成三个参数:连接策略(直连 / 默认代理)、UA 来源(固定的 aimux/<版本> / 请求自带)、错误映射(Other、InvalidArgument / ApiCall)。§6 的 C4 同步改了
次要:§4.3 引用“RFC-0047 (#290)”,RFC-0047 是 #286 属实 改成“RFC-0047(#286,cause 的实现是 #290)”
提示:基线 5743a40a 与部分行号不匹配(stream_part.rs:456-461、generate.rs:1903) 属实 改成 stream_part.rs:487-492 和 generate.rs:1925。全文 file:line 又在基线上核对了一遍,另外改了三处:trace/store.rs:417(with_capacity)、trace/layer.rs:113(TraceLayer::new)、provider.rs:160(list_models)。§4.3 明写 c0622ea4 的那些行号在那个提交上是对的

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.

复审通过。C7 发布顺序、DiagnosticScope 的 observer 载体、C4 的 proxy/UA/错误映射参数、RFC 引用和基线行号都已修正。Approve。

@eric8810
eric8810 merged commit f209f8d into master Oct 21, 2026
14 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