Repository navigation
refactor!: drop retryAfterMs from the error envelope - #349
Conversation
Retry's lastError as every binding's native cause, the Node and Java cause classes, an accurate security section with a size and redaction question, the full list of breaking changes, Swift's WireIndirect, and how RFC-0044, RFC-0048 and #349 meet this RFC. Q2 and Q3 are marked adopted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
eric8810
left a comment
There was a problem hiding this comment.
Review
核心/ops 和绑定侧都没有发现阻塞项:retryAfterMs、Ctx.now、Projected、retry_hint 删除完整;生成的 ErrorEnvelope、C 头文件和各语言绑定一致;core retry 和 provider poll 仍从 responseHeaders 读 hint。建议修:
- 重要 当前语言 API 指南仍宣传已删除的字段:
docs/api/c.md、node.md、python.md、go.md、java.md、kotlin.md、swift.md、flutter.md还有retryMs/retry_ms/aimux_error_retry_ms。这是 breaking PR,发布点会让用户照着旧文档写出不存在的调用;请更新,或在docs/API.md加显眼的 legacy banner 并开跟踪 issue。 - 次要 删除
ErrorEnvelope/002.json/002.expect.json后,DTO 的expect分支和显式 null 折叠(D16)没有向量;ErrorEnvelope/001删除后也没有 >2^53 整数向量,D13/D15 的 carve-out 变成未覆盖。建议换一个普通可选字段补expect向量,并在别的类型补一个 u64 边界向量,或删掉 carve-out。 - 次要
aimux-core/src/error.rs的新测试没有覆盖 Retry-in-Retry / 保留 attempt hint;补一个嵌套 aggregate。 - 次要
aimux-ffi/ABI-MIGRATION.md只写retry-after,应写优先retry-after-ms再retry-after。 - 提示 base
c0622ea4不是 head 的祖先(merge-base 是b91829af),当前 PR 显示冲突;合并前 rebase,避免把 #287/#283 的改动回退。
* docs(rfc): RFC-0047 error system and error cause Describes how aimux's error system differs from the AI SDK's, traces today's error paths from the public entry functions to the lines that drop the underlying error, and designs `cause` across the core, the transport layer, the ops envelope, the generated DTOs and every binding. The open questions in section 10 stay open. Line numbers refer to master 4220847, and the text includes what implementing #289, #290 and #293 found. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C * docs(rfc): answer the RFC-0047 review Retry's lastError as every binding's native cause, the Node and Java cause classes, an accurate security section with a size and redaction question, the full list of breaking changes, Swift's WireIndirect, and how RFC-0044, RFC-0048 and #349 meet this RFC. Q2 and Q3 are marked adopted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
eric8810
left a comment
There was a problem hiding this comment.
评审:drop retryAfterMs from the error envelope —— 批准(rebase 后合并)
规范出处核清:RFC-0047 §11.1 只是预案此变更,真正的决定在 issue #334 与 RFC-0039 §6——本 PR 正确修订了 RFC-0039(§6.1 示例与字段表、§6.2 重写为"信封没有派生 retry hint"、#166 C3 行同步)。
语义不丢:宿主直接读 error.responseHeaders(与上游 APICallError 一致);core 保留唯一解析器 retry_after_ms_from_headers(retry.rs/poll.rs 原样使用);§6.2 派生规则的 golden 向量(ms 优先/秒/HTTP-date/过去日期/大小写/溢出边界/优先级)整体迁入 error.rs 并新增"聚合错误不继承尝试 hint"的固化断言。删除的 1054 行主要是时钟穿线、投影缓存与生成物;顺带消除了 stream 终态用 UNIX_EPOCH 假时钟算 HTTP-date hint 的死语义。D13/D15 的大整数 carve-out 随 ErrorEnvelope/002 删除而休眠,已如实登记。
三个跟进项(非阻塞):
- 与 master 的 11 处冲突全部来自 [1/3] 的 digest/golden——rebase 后重跑 codegen 即可;与 #290/#293 谁后合谁解 envelope 冲突(RFC §11.1 已预案);
- D16 的 expect 路径现无向量覆盖,建议补一个其他类型的 expect 向量;
- docs/api/*.md 仍描述 0.5 的 retryMs(预先存在的过时),建议本 PR 或紧跟的 docs PR 收掉。
批准(rebase + codegen 重跑后合并)。
The ops error envelope is now {kind, code, message, error}. The derived
retryAfterMs duplicated error.responseHeaders and forced ops to carry a
clock (Ctx.now), a cached projection (OpsError::Projected),
Operation::start_with_clock and a re-export of the core header parser.
Upstream APICallError has no such field; hosts read responseHeaders, and
core still computes delays itself when it retries or polls.
Bindings regenerate their DTOs and drop the forwarding code; the
ErrorEnvelope vectors, RFC-0039 §6 and the implementation notes follow.
Closes #334
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
3b4c809 to
ff58c2d
Compare
eric8810
left a comment
There was a problem hiding this comment.
复审(rebased head ff58c2d)
之前的 rebase/冲突已解决,但先前指出的发布阻塞项仍在,暂不能合并:
- 重要 当前
docs/api/c.md、flutter.md、kotlin.md、node.md、python.md、swift.md仍宣传已删除的retryMs/retry_ms/aimux_error_retry_ms。这是 breaking PR 的发布点,用户会照着旧 API 写不存在的调用;请更新,或明确加 legacy banner + 跟踪 issue。 - 次要
contract-tests/dto只剩ErrorEnvelope/001.json;expect分支和显式 null 折叠(D16)没有向量,>2^53 的 D13/D15 carve-out 也不再有覆盖。建议用普通可选字段补expect向量,并在别的类型补 u64 边界向量,或删除 carve-out。 - 次要
aimux-ffi/ABI-MIGRATION.md:18只写retry-after,应写优先retry-after-ms再retry-after。 - 次要 新测试仍未覆盖 Retry-in-Retry / attempt hint 保留;建议补嵌套 aggregate。
之前的 APPROVED 是针对旧 head 的,当前 head 修完这些后我再复审。请求修改。
Brings in the error-cause series (#289, #290, #293). Conflicts: ops tests take master's `InvalidParams { .. }` without `unprojected()`; envelope.rs keeps `BindingError::result_serialization` without a clock; binding READMEs and Node error.ts keep the cause text without retryAfterMs. Bindings regenerated with aimux-codegen. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G5j9hYv7hDeYgMvvRu2F9T
Neither retry level has a hint of its own; the innermost attempt keeps retry-after-ms through nesting and a serde round trip. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G5j9hYv7hDeYgMvvRu2F9T
Python kept null on every optional field whose schema is nullable, so
it re-encoded {"output": null} where Rust and the other codecs omit the
key. Only JSON values and presence fields keep null now
(Ty::keeps_null replaces accepts_null).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G5j9hYv7hDeYgMvvRu2F9T
ModelLimits/002 (u64::MAX) and 003 (2^53+1) exercise the D13 and D15 carve-outs; 004 with 004.expect.json is an explicit null that folds to an omitted key (D16). They replace the two ErrorEnvelope vectors removed with retryAfterMs. The registrations and vector counts follow. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G5j9hYv7hDeYgMvvRu2F9T
docs/API.md and docs/api/{c,flutter,go,java,kotlin,node,python,swift}.md
still describe the 0.5 binding API, including the removed retry hint;
each now says so at the top and points to the binding README and #277.
ABI-MIGRATION reads retry-after-ms before retry-after.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G5j9hYv7hDeYgMvvRu2F9T
|
复审意见(
本地 1.99 的 fmt、clippy、workspace 测试、codegen Generated by Claude Code |
Requested by li · project thread
Summary
Before: an ops error envelope carried
retryAfterMsnext toerror.responseHeaders. To compute it once, ops threaded a clock through dispatch, frames and operations and cached the projected envelope.After: the envelope is
{kind, code, message, error}and depends only on the error. Hosts that need to wait readerror.responseHeaders(retry-after-ms, thenretry-after), as AI SDK users do; upstreamAPICallErrorhas no retry-hint field either.Merged with master
b69137e(the error-cause series #289/#290/#293); bindings regenerated.Overview: how a retry delay reaches each caller today (master
b69137e)This PR
Commits:
ff58c2drefactor!ErrorEnvelope.retry_after_ms,Ctx.now,OpsError::Projected/ProjectedError/project/project_with_clock/unprojected,Operation::start_with_clock,aimux-ops/src/retry_hint.rs; parser golden cases move intoaimux-core/src/error.rs; bindings drop their forwarding code; RFC-0039 §6.1/§6.2, implementation notes, alignment doc, READMEs, CHANGELOGb557c9bmergeInvalidParams { .. }withoutunprojected(), binding READMEs keep the cause text withoutretryAfterMs; codegen rerun862be4btestnested_retry_keeps_the_attempt_hint(aimux-core/src/error.rs): no hint at either retry level, the attempt keeps its own through nesting and serdeeea8e80fix(codegen)nullon an optional field, as Rust does (Ty::keeps_null,tools/aimux-codegen/src/model.rs); only JSON values and presence fields keep it. Found by the newexpectvector: Python re-encoded{"output": null}a5f967ftest(dto)ModelLimits/002(u64::MAX: D13, D15),003(2^53+1: D13, still checked in Java/Dart),004+004.expect.json(explicit null: D16); index, sources, D13/D15/D16 registrations and vector counts37ac2d1docsdocs/API.mdanddocs/api/{c,flutter,go,java,kotlin,node,python,swift}.md(they describe the whole 0.5 binding API; rewrite tracked in #277);ABI-MIGRATION.mdnamesretry-after-msbeforeretry-afterCloses #334
Type of change
Checklist
cargo fmt --all -- --checkpassescargo clippy --workspace --all-targets -- -D warningspasses (Rust 1.99)cargo test --workspacepassesAlso run locally after the merge:
cargo run -p aimux-codegen -- --check;scripts/check_provider_boundaries.sh;check_dto_vectors.py python node(240 vectors); Pythontest_dto_types.py. Go, Java, Dart and Swift vector runs are left to CI.Notes for reviewers
docs/api/describe the whole 0.5 API (status getters,retryMs, the old C exports), not only the retry hint, so this PR marks them legacy instead of patching a few lines; 文档对齐:ROADMAP、RFC 状态与 API 文档跟上 V4 和新 ABI #277 tracks the rewrite.