refactor(bindings,ffi)!: 稳定跨语言错误模型 - #158
Open
cunninghamcard-bit wants to merge 7 commits into
Open
Conversation
cunninghamcard-bit
marked this pull request as draft
August 19, 2026 03:49
cunninghamcard-bit
force-pushed
the
feat/error-model-bindings-ffi
branch
6 times, most recently
from
August 19, 2026 08:23
d6ada6c to
1ba57b8
Compare
Node and Python now project each core error variant into a real runtime exception class instead of rebuilding a generic metadata object. Node registers the canonical JavaScript constructors with napi-rs and Rust instantiates them in the owning environment. Synchronous throws, promise rejections, streams and workers therefore preserve instanceof. Python raises the matching PyO3 exception class. Variant payload lives only on the class that owns it: APICallError carries provider-call details, TokenExpiredError carries its defined 401 status, and the registry errors carry their identifiers. AimuxError has no compatibility code, status or retryable fields, and the serialized errorValue/error_value companion is removed. RecordingError remains a second family, unrelated to AimuxError, for recorder construction and flush failures. Binding-layer failures keep the native framework behavior: napi-rs Error statuses in Node and ValueError or RuntimeError in Python.
Every fallible C function now returns aimux_error_t *: NULL on success with the result in a trailing out-parameter, or one owned error on failure, released exactly once with aimux_error_free(). The caller-allocated AimuxError struct, aimux_error_clear, error_value and mixed sentinel polarities are removed. One code space identifies the source. AiMuxError uses 1–13: Other takes the retired UNKNOWN slot at 1, codes 2–13 retain their existing values, and the old Other value 14 is retired. RecordingError uses 100–105 and C-boundary failures use 200–206. A non-NULL error never reports code 0. aimux_error_message() works for every code. Detail getters read only the payload owned by that variant and return NULL, -1 or 0 otherwise. The error is a Box transferred directly to the caller, not a registry handle or a JSON projection. Router and MoA constructors reject every dead member handle instead of silently changing the composite. The C and C++ examples use the same ownership and result convention.
The Go binding reads the new ABI: every call gets an `aimux_error_t *`, NULL means success, the result arrives through an out-parameter, and the error is freed once. `error.go` rebuilds the separate types from the code range — the `AimuxError` hierarchy for 1–13, a distinct `RecordingError` for 100–105, and a plain Go error for the C boundary's own 200–206, which callers should never have to branch on. The arcships#157 lifecycle model is unchanged: atomic handle owners, Close that never waits for an in-flight C call. Only the ABI call sites and the error decoder move.
Both JVM bindings follow the new ABI: an opaque error pointer per call, freed once, with the payload read through the getters. `AimuxCError` is gone — the code range now decides the type: `AimuxException` and its subclasses for 1–13, a separate `RecordingException` / `RecordingErrorCode` for 100–105, and the language's own `IllegalStateException` / `IllegalArgumentException` for the C boundary's 200–206.
Swift and Flutter follow the new ABI the same way: one opaque error pointer per call, freed once, payload through the getters, and the code range rebuilding the separate types — the engine hierarchy for 1–13, a distinct recording error for 100–105, and the language's own invariant error for the C boundary's 200–206.
Rewrites the error sections for C, Go, Java, Kotlin, Swift, Flutter, Node and Python: the return convention, the code ranges and which type each range becomes in that language.
cunninghamcard-bit
force-pushed
the
feat/error-model-bindings-ffi
branch
from
August 19, 2026 17:06
1ba57b8 to
8b4e885
Compare
cunninghamcard-bit
marked this pull request as ready for review
August 19, 2026 17:35
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.
Refs #95
本次改动
本 PR 确定跨语言错误处理的稳定形态:
instanceof、isinstance。aimux_error_t *:NULL表示成功,失败对象由调用方释放一次。1..13、100..105、200..206。RecordingError保持独立;绑定错误不冒充核心错误。兼容性
已有名称、错误码、所有权和调用约定保持稳定;以后通过新增错误类型、可选字段或 getter 扩展。破坏这些约定需要主版本变更。
完整说明见
docs/error-model.md。参考
参考了 AI SDK、libsignal FFI、Node-API/napi-rs、PyO3 和 openai-go;只借鉴错误处理范式,不照抄其结构。