Skip to content

RFC-0039: ops、FFI 与八种绑定契约 - #209

Merged
eric8810 merged 1 commit into
masterfrom
docs/rfc-0039-ops-bindings-contract
Oct 15, 2026
Merged

eric8810 merged 1 commit into
masterfrom
docs/rfc-0039-ops-bindings-contract

Conversation

@eric8810

@eric8810 eric8810 commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

覆盖 C1–C4、D1–D8、op/handle、错误、流生命周期、版本、stdio 和冻结条件。

状态与依赖

以 #200 已记录的一次性切换/全语言宿主回调后置为目标;类型和 provider 合同分别依赖 RFC-0042/0040,stdio 作为后续独立能力。

本 PR 属于完整 roadmap RFC 批次。整批已完成节点覆盖与跨文档契约复核,再按主题分别提交 Draft。各 PR 均独立基于 master,不叠加其他未合并文档。设计齐备不表示运行时实现或验收已完成。

验证

  • 文档编号、代码围栏、相对链接、空白检查通过
  • 本 PR 仅修改 rfc/0039-ops-bindings-contract.md
  • 本地未运行构建、运行时测试、性能实测或真实 provider 探测;CI 状态以本 PR 当前 head 的检查结果为准

同批设计(均独立基于 master)

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

注:文中“V4 层”的代码位置,以及未注明 master 的 aimux 路径和行号,均以 #256 的提交 65ca6be 为准(#249–#256 按顺序叠放,这个提交包含全部各层):https://github.com/arcships/aimux/tree/65ca6be74515374ea89eb4f25717b4ac42ca2911

"kind": "aimux",
"code": 11,
"message": "API call failed",
"error": {"type": "api-call", "message": "rate limited", "statusCode": 429},

@cunninghamcard-bit cunninghamcard-bit Oct 13, 2026 •

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.

§6.1 有三处想先和你确认(错误 JSON 形状的统一我们决定暂缓,放到新 ABI 那几层一起做):

  1. 判别字段:示例用 "error": {"type": "api-call", ...}(第 290 行),上游 AI SDK 的错误以 name 区分,例如 "AI_APICallError"(@ai-sdk/provider@4.0.19 src/errors/api-call-error.ts:3;ai@7.0.122 src/util/retry-error.ts:3),master 上的错误 JSON 还是 0.5 的形状({"ApiCall": {...}},aimux-core/tests/error_value_golden_test.rs:35),V4 的公共 JSON 那一层([8/8] refactor!: public JSON equals the AI SDK JSON #256)改成了按上游的 name 区分(https://github.com/arcships/aimux/blob/65ca6be74515374ea89eb4f25717b4ac42ca2911/aimux-core/tests/error_value_golden_test.rs#L36)。信封里的 error 最终用 name 还是 type?第 296 行说完整联合归 RFC-0042,但 RFC-0042: V4 类型边界与统一生成 #212 没有错误联合这一节,也想确认由哪份 RFC 定义。
  2. “HTTP 状态只在实际观察到响应时提供”(第 301 行):上游对 200 响应中的流内 error 帧会推断状态码,OpenAI 把 rate_limit 推成 429、authentication 推成 401,其余默认 500(@ai-sdk/openai@4.0.80 src/openai-stream-error.ts:192、:235-260);ai 的 StreamProviderError.statusCode 也注明是可推断的“HTTP-equivalent”(ai@7.0.122 src/error/stream-provider-error.ts:23-27,overloaded → 503)。我们按上游移植了 OpenAI 这段(aimux-providers/src/openai/mod.rs 的 openai_stream_error)。建议区分“观察到的状态”和“由错误帧推断的状态”,并确认 TokenExpired 可以带它来源的 401(aimux-core/src/error.rs 的 status_code)。
  3. 码值:第 299 行写“保留 AiMux 1–17,新增由 manifest 分配”,但 manifest 还没有,V4 层里已在 17 之后加了 18 NoOutputGenerated、19 LoadApiKey、20 LoadSetting(aimux-ffi/src/lib.rs:452、:457-458)。能否把这三个登记进来,或说明由 manifest 接管?


### 5.3 有界背压

当前切换默认预算:音频输入最多 64 项且最多 8 MiB;输出 data 队列最多 256 项且最多 8 MiB;单个事件/音频块最大 1 MiB;先达到任何限制即背压。Node/Python 可保留更小的 64 项桥接队列,但总字节上限与终结规则一致。允许显式降低限额,不允许“无限”配置。

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.

§5.3 的“单个事件/音频块最大 1 MiB”和“超大单项在分配前返回 ResourceLimit”(第 273、275 行)会把一个已经修掉的缺陷带回 FFI 层。#200 的影响面地图把旧 SSE 单事件 1 MiB 上限列为 as:STREAM-1:Gemini 流式图片、Responses 的 response.completed 等合法事件超过 1 MiB,本应成功的请求因此失败(docs/aisdk-architecture-impact-map.md:558);master 上的 #213 已按上游去掉了 SSE 上限(aimux-stream/src/sse.rs:19;上游 parseJsonEventStream 不设 maxBufferSize,@ai-sdk/provider-utils@5.0.51 src/parse-json-event-stream.ts:20)。这类数据在 FFI 流里是单个 data 事件:file part 的内容内联在事件里(aimux-core/src/result.rs 的 GeneratedFile),includeRawChunks 下的 raw 事件也是整块原始事件,按 1 MiB 上限会以 ResourceLimit 失败。
建议:单事件不设固定 1 MiB 上限,改为按字节计的队列背压(总字节上限可以保留);如果一定要有单事件上限,至少高于录制 fixture 中最大的事件并留出余量,数值仍交给 RFC-0038 核定。

| `auth.codexRefresh` | G | 既有 refresh 输入;不记录 token、不自动重试 | call → token 结果;不得进入通用日志 |
| `handle.drop` | 所有非零 kind;0/未知值也可 | 无 | 幂等;先移除 registry,再取消/回收 |

这里的 provider/transport/devtools 生命周期 op 是 #200 对现有行为的显式对象化,不授权本期实现 descriptor 中尚未具备的 skills、Evaluation、Batch、SpeechTranslation 等能力。方法列在 descriptor 中但不属于 current capability 集时,返回 `UnsupportedFunctionality`,不能返回伪造的成功空值。

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.

§3.1 的句柄种类(第 115 行)、§3.2 的合法矩阵(第 126-178 行)和 §1.2 的能力保留清单(第 72 行)都没有 Decision,第 180 行还把 Evaluation 列为“不授权本期实现”的能力。你起草时的基线 72a37b5 还没有它;之后 master 合入了 #221、#226(RFC-0037、RFC-0038 decision),C ABI 已有 Decision 句柄和 aimux_provider_decision_model、aimux_decision_capabilities、aimux_decide、aimux_decide_with_abort(master aimux-ffi/src/lib.rs:107、:2849、:2911、:2928、:2938),七个绑定都有对应封装(例如 bindings/go/decision.go)。
它就是上游的实验性 evaluate:@ai-sdk/provider 4.0.19 里叫 EvaluationModelV4(src/evaluation-model/v4/),4.0.22 改名为 DecisionModelV4 / doDecide(src/decision-model/v4/decision-model-v4.ts:6-17),NoSuchModelError 的 modelType 也改为 decisionModel(4.0.22 src/errors/no-such-model-error.ts:19-21)。按 §0.1 第 9 条和 §11.2,新 ABI 删除旧导出时,如果没有对应的新 op,这项能力会丢失。
建议:§3.1 加 Decision 句柄(由 provider.model 的 decisionModel 方法产生;与上游一样是 Provider 上的扩展,不进入稳定的 ProviderV4 接口);§3.2 加 decision.decide(Decision;Abort 可选;call → decision 结果)和 decision.capabilities(Decision;无参数;call → 能力摘要,不联网);§1.2 加 decision;第 180 行删去 Evaluation,或写成“Evaluation 已以 Decision 的名义由 RFC-0037/0038 实现”;第 56、72 行的“八模态”届时是九种模型句柄。

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

方向同意,可以合并。之前的行内评论供参考,不阻塞合并。


Generated by Claude Code

@cunninghamcard-bit
cunninghamcard-bit marked this pull request as ready for review October 15, 2026 03:47
@eric8810
eric8810 merged commit 9c8e412 into master Oct 15, 2026
24 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.

2 participants