Repository navigation
[3/3] Error cause in ops and bindings - #293
Conversation
…entation Line numbers now refer to master 4220847 (#268 merged). The text follows what #289-#293 implement: TypeValidation is the cause of schema failures, transport messages drop the URL, and section 12 names the three PRs. The open questions in section 10 are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
…s in #276 The findings from implementing #289-#293 (TypeValidation, transport messages without the URL, the call-site count, the download error type) move to issue #276. Only the baseline and line numbers stay updated to master 4220847. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
The RFC is still open, so what #289-#293 found belongs in its text: TypeValidation as the cause of schema failures, transport and download messages without the URL, the 117 call sites, and reqwest::Error as the download error. Baseline and line numbers stay at master 4220847. Section 10's open questions are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
f64b656 to
096c31f
Compare
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
095464c to
e3a861b
Compare
096c31f to
2f4ccb4
Compare
eric8810
left a comment
There was a problem hiding this comment.
Review
envelope 四个域、C ABI、C++ NativeError、recording source→cause 都保持一致,未发现阻塞项。建议修:
- 重要
bindings/node/src/error.ts:28:嵌套 cause 直接复制 JSON,AI_JSONParseError/AI_TypeValidationError不是错误类,instanceof和 stack 都不成立,与 RFC-0047 §7 以及 Python/Java 的做法不一致。建议递归还原为对应错误类,或明确文档并补嵌套 AiMux 测试。 - 次要
aimux-ops/src/envelope.rs:362:BindingError/ProtocolError没有实现source(),Rust 的 source 链在 domain error 处断开,与docs/error-model.md的承诺不符。 - 次要
bindings/node/src/index.ts:58:客户端JSON.stringify失败构造的InvalidWireJson没有 cause。 - 提示 Node README 没补
error.cause;serde data 错误可能带调用方值,建议在 decode 处只保留类型/位置或做脱敏。
e3a861b to
b570ada
Compare
2f4ccb4 to
87fbf65
Compare
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
|
回复 @eric8810 的 review(左列是 eric 的原话):
本地:fmt、 Generated by Claude Code |
* 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>
87fbf65 to
fb67bbb
Compare
eric8810
left a comment
There was a problem hiding this comment.
评审:[3/3] Error cause in ops and bindings —— 批准
实现完整对齐 RFC-0047 §5/§7 与 §10 已采纳的第 2、3 项:recording 域 source→cause 对象化、binding/protocol 域带 serde 错误、四域同形且码与 Display 不变、Rust source() 链贯通(golden 实测);八绑定原生 cause 各按 §7 入口表落地(Node 不可枚举 attachCause + 递归、Python SourceError 链 + __cause__、Java 手写 ErrorCause 与生成 DTO 的分工、Go 链式 Unwrap + retry lastError、Swift/Flutter cause 属性),Retry 一律取最后尝试;C ABI 冻结(§5.2 ✓)、C++ 改抛 NativeError(code+JSON 断言)。
生成物只有 python.rs 的 contains_error 与 _error_payloads.py 需要同步且已同步,manifest 类型未变无需动向量——分层判断正确。
两点非阻塞:1) base 在 #290 的合并提交之前,#290 重做合并后请 rebase 本 PR;2) RFC §10 问题 5(错误 JSON 大小/脱敏边界)按 RFC 留待后续,PR 已如实登记。
fb67bbb to
1476f87
Compare
recording errors replace the `source` string with a SourceError chain, and BindingError::InvalidWireJson, ResultSerialization and ProtocolError::InvalidParams keep the serde error as the cause. The payload has a cause only when there is one; messages and error codes are unchanged. Part 3 of RFC-0047. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
aimux::check used to throw a std::runtime_error with only the message. NativeError still derives from it. The C ABI getters are unchanged. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
Node sets the standard error.cause; Python sets __cause__, restoring nested aimux errors as their exception classes and other causes as an aimux.SourceError chain. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
Java and Kotlin chain ErrorCause through getCause(); Go's Error and Cause implement Unwrap(). 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> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
1476f87 to
7690cae
Compare
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S2GJxE3fH7rQvAwXLg2f1C
7690cae to
7f5de6f
Compare
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
…h-the-ai-sdk master's error-cause change (#289/#290/#293) made InvalidResponseData a struct variant; closed_before_finishing now builds it with AiMuxError::invalid_response_data. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoxcKU4zBD64Lri3e4Lrq5
Requested by li · project thread
Summary
RFC-0047(#286)实现的第 3 步,也是最后一步:ops 错误信封的四个域都带上 cause,每种语言把它接成本语言原生的 cause。Node 的
error.cause、Python 的__cause__、Java 的getCause()、Go 的errors.Unwrap现在能一直走到Connection refused;重试错误的 cause 是最后一次尝试(AI SDK 的lastError);C++ 包装改抛带错误码和 JSON 的aimux::NativeError。错误码、名字和消息不变。叠在 #290(第 2 步:字符串变体)上,#290 叠在 #289 上。原型 #280 已关闭。
跨语言错误体系概览
基于 #290,整条栈在 master
e115e723上。同一个错误在 ops 边界投影成信封一次,各语言从信封还原,行号是开 PR 时的 master42208472(#268 合并后):#289、#290 之后 aimux 域的 payload 里已经有
cause,但其他三个域在构造时就把底层错误变成了文字,各语言也都不读cause:Python 只把Retry、ToolCallRepair的嵌套错误还原成异常,Java、Go、Node 的 cause 链是空的,C++ 连错误码都丢了。本 PR 的改动
ops 信封,
aimux-ops/src/envelope.rs:各语言(概览里最后一层):
调用方看到的(Python,
bindings/python/tests/test_ops_errors.py):黄金样例:
recording-init、recording-open-file、recording-spawn的source改为cause,binding-invalid-wire-json带 cause;新测试检查序列化失败的 cause 就是 serde 错误、没有底层错误时不输出 cause、binding 和 protocol 域的source()走到 serde 错误;Node、Python、Java、Go、Swift、Flutter 各有重试取最后一次尝试的测试,Node 另有嵌套 aimux 错误逐层还原成错误类的测试。文档:CHANGELOG Breaking,
docs/error-model.md的「错误原因」加上各语言入口、四个域和重试,各绑定 README 写明 cause 的入口。DTO 向量数(238)由 #289、#290 更新,本 PR 不再改。Type of change
Breaking:recording 域 payload 的
source改名cause且变为对象(RFC §10 问题 2,已采纳);BindingError::ResultSerialization、ProtocolError::InvalidParams改为结构体变体,InvalidWireJson多一个字段;各语言的原生 cause 从空变为有值;C++ 抛出的类型变为aimux::NativeError(仍继承std::runtime_error)。Checklist
cargo fmt --all -- --checkpassescargo clippy --workspace --all-targets -- -D warningspassescargo test --workspacepasses (cassette playback — no network/keys)README.md,docs/,rfc/,bindings/README.md)本地还跑了生成器
--check、Python 和 Node 的 DTO 向量(238 个)、Node facade 测试和tsc、Python 错误测试、JavaErrorCauseTest、Go 的 cause 测试、provider 边界检查;Swift、Flutter 的绑定测试由 CI 跑。Notes for reviewers
retryAfterMs)也改aimux-ops/src/envelope.rs,后合并的一个解决冲突(RFC §11.1)。CallbackFailure)仍不跨 ABI,RFC §5.3。