fix(ffi): constructors return JSON handle/error envelope, replacing aimux_last_error (issue #17) - #21
Merged
eric8810 merged 7 commits intoAug 3, 2026
Conversation
cunninghamcard-bit
force-pushed
the
explore/aimux-ffi-json-constructors
branch
from
August 3, 2026 12:07
85bde11 to
cc26ba6
Compare
Contributor
|
is this in draft or complete? |
Contributor
Author
|
是完整的,不是 draft——6 个绑定(Go/Java/Kotlin/Swift/Flutter/C)全部迁移完,#19 的 error_detail 回归测试也移植过来了(14 个通过,信封内容对齐:InvalidArgument/Json/UnknownProvider)。本地验证:Rust 测试、Go 真实 cgo 链接、C/C++ example 编译、swift build 都通过,另外用真实的 OpenAI 兼容 endpoint 走 Go 和 C 绑定跑了端到端(未知 provider 详情、invalid prompt_json 的 serde 详情、真实生成、流式)。Java/Kotlin/Flutter 是纯静态改动,以 CI 为准。 不过 #19 合入后这个 PR 现在有冲突,我 rebase 一下。rebase 之后这个 PR 的性质就变成:在 #19 的基础上进一步简化——删掉 aimux_last_error() 的线程局部机制,构造函数直接返回 JSON 信封,成功和失败在同一次调用的返回值里,没有第二次调用需要关联,各绑定也就不需要处理线程亲和(Go 不需要 LockOSThread,Kotlin 协程/虚拟线程接入时也没有坑)。#19 的测试会改写成信封版保留。rebase 完我在这里说一声。 |
cunninghamcard-bit
force-pushed
the
explore/aimux-ffi-json-constructors
branch
from
August 3, 2026 12:18
cc26ba6 to
5bb2a5a
Compare
Contributor
Author
Contributor
|
ci failed |
…imux_last_error (issue arcships#17) Follow-up simplification of arcships#19: instead of a bare u64 handle plus the aimux_last_error() thread-local side channel, every constructor returns the JSON envelope the rest of the ABI already uses: {"handle":<u64>} on success {"error":"...","error_type":"...","status_code":..} on failure Success and failure arrive in the same return value of the same call, so there is no second call to correlate — the entire last_error mechanism (LAST_ERROR TLS slot, begin_constructor, record_error/record_error_msg, the aimux_last_error symbol and its thread-affinity contract) is removed. No binding runtime needs thread pinning. Error envelopes are unchanged from arcships#19 (InvalidArgument for null / invalid-UTF-8 args, Json for config parse failures, UnknownProvider with the available-provider list), and Problem A's serde detail for prompt_json/config_json is preserved. error_detail_test.rs: the envelope-relevant cases from arcships#19 are kept and read the error from the constructor result; the TLS-semantics cases (clear-on-success, last-write-wins, read-once, thread-local isolation) have no counterpart — replaced with envelope-semantics tests (per-call error independence, 8-thread concurrent constructors, no pinning). cargo test -p aimux-ffi --release: 14 passed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parseHandleJSON reads the envelope, frees the C string, and surfaces the detailed error; a degenerate envelope with neither error nor handle is rejected. The takeLastError/callConstructor dispatch machinery and runtime.LockOSThread pinning from arcships#19 are removed — constructors are plain direct C calls, since the result is self-contained. Also removes stale StreamTextContext doc references (no such API); the per-call timeout (RFC-0016 H3) is the only interruption mechanism. go vet + go test ./... pass with a real cgo link; E2E against a live OpenAI-compatible endpoint verifies unknown-provider detail, prompt_json serde detail, real generate, and real streaming. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All JNA constructor declarations return Pointer; AimuxResult.extractHandle frees exactly once (try/finally), null-checks, and throws with the detailed engine error. The aimux_last_error declaration and constructorFailure helper from arcships#19 are removed. Static-only change; CI to verify. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same shape as the Java binding: Pointer? externs, extractHandle with free-in-finally, detailed errors surfaced. Static-only change; CI to verify. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
extractHandle copies the string, frees once, then throws AimuxError with the detailed message on the error envelope. swift build passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Constructor typedefs return Pointer<Utf8>; _extractHandle frees once and throws StateError with the detailed message. Static-only change; CI to verify (no dart SDK in the authoring environment). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
example.c / example.cpp parse the envelope and print the detailed engine error on constructor failure (replacing arcships#19's aimux_last_error read in example.c); example.cpp includes <stdexcept> for its throw sites. Both compile against the new header. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cunninghamcard-bit
force-pushed
the
explore/aimux-ffi-json-constructors
branch
from
August 3, 2026 12:22
5bb2a5a to
f747784
Compare
Contributor
Author
|
CI 绿了——之前挂的是新增测试文件的 rustfmt 格式问题,已修(折进了原 commit,历史不变)。现在全部 job 通过,包括我本地没法验证的 Java(JDK 8/11/17/21)。 |
cunninghamcard-bit
added a commit
to cunninghamcard-bit/aimux
that referenced
this pull request
Aug 4, 2026
… generator paths - aimux-ffi.h / AimuxFFI.java: remove aimux_last_error declaration and JNA binding — the symbol was removed in arcships#21 (constructors now return JSON envelopes); the header declared a function that no longer exists, and calling the JNA binding would fail at lookup. - scripts/gen_provider_names.py: Java/Kotlin outputs still targeted the old io.aimux / aimux packages; the checked-in files moved to ai.arcships.aimux for the Maven Central release. Running the generator would have recreated stale duplicate classes. Also emit gofmt-aligned Go consts so generator output matches the checked-in (gofmt-ed) file byte-for-byte. - ci: add a generator-drift step (run generator, git diff --exit-code) so checked-in ProviderName files can't silently diverge again. - docs/internal/phase4-audit.md: add a resolution-status section — P1-1/P1-2/ P2-3/P2-5 and the ffi-has-no-tests finding are resolved; P2-4/P2-6 remain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cunninghamcard-bit
added a commit
to cunninghamcard-bit/aimux
that referenced
this pull request
Aug 4, 2026
…ecls, stale header contracts arcships#21 replaced the thread-local last_error side channel with JSON handle/error envelopes; this cleans up everything it left behind: - aimux-ffi.h / AimuxFFI.java: remove the aimux_last_error declaration and JNA binding — the symbol no longer exists (undefined symbol for C callers, crash on first call via JNA). - aimux-ffi.h: align documented contracts with the post-arcships#21 implementation (verified against lib.rs line by line): three-key error envelope everywhere; Azure _with_base takes a REQUIRED base_url in place of resource_name; multimodal opts_json is required while generate/stream accept NULL; detailed invalid prompt_json/opts_json envelopes; _with_base NULL-means-default notes; embedding-onward envelope convention note; ignored opts_json/model_id params flagged; NULL-return and timeout semantics. - lib.rs: module/free_string docs now cover all char* returns, not just aimux_generate_text. - C/C++ examples: build commands gain the missing -I../../aimux-ffi. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cunninghamcard-bit
added a commit
to cunninghamcard-bit/aimux
that referenced
this pull request
Aug 4, 2026
…ecls, stale header contracts arcships#21 replaced the thread-local last_error side channel with JSON handle/error envelopes; this cleans up everything it left behind: - aimux-ffi.h / AimuxFFI.java: remove the aimux_last_error declaration and JNA binding — the symbol no longer exists (undefined symbol for C callers, crash on first call via JNA). - aimux-ffi.h: align documented contracts with the post-arcships#21 implementation (verified against lib.rs line by line): three-key error envelope everywhere; Azure _with_base takes a REQUIRED base_url in place of resource_name; multimodal opts_json is required while generate/stream accept NULL; detailed invalid prompt_json/opts_json envelopes; _with_base NULL-means-default notes; embedding-onward envelope convention note; ignored opts_json/model_id params flagged; NULL-return and timeout semantics. - lib.rs: module/free_string docs now cover all char* returns, not just aimux_generate_text. - C/C++ examples: build commands gain the missing -I../../aimux-ffi.
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
Follow-up simplification of #19: constructors return the JSON envelope the rest of the ABI already uses, instead of a bare
u64plus theaimux_last_error()side channel:Success and failure arrive in the same return value of the same call, so there is no second call to correlate — the entire last_error mechanism (TLS slot,
begin_constructor/record_error, theaimux_last_errorsymbol and its thread-affinity contract) is removed. No binding needs thread pinning (LockOSThreadgone in Go; nothing for Kotlin coroutines / virtual threads to get wrong when they adopt it). The convention matchesaimux_generate_text/aimux_embed, so bindings reuse their existing envelope parsers.Net −168 lines vs master (+1426/−1594) while extending coverage from 3 bindings to all 6.
Error envelopes are byte-identical to #19's (
InvalidArgument/Json/UnknownProvider, serde detail forprompt_json/config_json) — the only change is the retrieval mechanism.Cost: breaking C ABI change — 40+ constructor signatures change from
uint64_ttochar *(freed withaimux_free_string). 0.2.x is the cheapest moment this will ever be.Verification
cargo test -p aimux-ffi --release: 14 passed — fix(ffi): preserve detailed errors across the C ABI (issue #17) #19's error_detail regression cases kept (reading the error from the constructor result); the TLS-semantics cases have no counterpart and are replaced with envelope-semantics tests (per-call error independence, 8-thread concurrent constructors, no pinning)go vet+go test ./...with a real cgo link; C/C++ examples compile;swift buildpassesinvalid prompt_jsonserde detail, real generate, real streaming — all pass🤖 Generated with Claude Code