Skip to content

Add Agent-scoped external Connector runtime - #3483

Merged
huangruiteng merged 6 commits into
mainfrom
codex/external-connector-runtime-20260822
Aug 22, 2026
Merged

Add Agent-scoped external Connector runtime#3483
huangruiteng merged 6 commits into
mainfrom
codex/external-connector-runtime-20260822

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • add the provider-neutral agent_external_connector_v0 binding for group-message and document-comment event sources
  • keep source, cursor, document anchor, reply-chain, exact provider identity, scopes, and repair URLs owner-local while exposing content-free status
  • make Agent-bound Lark Goal Topics persist and validate the generic Connector contract
  • add a bounded incremental async inbox with stable event dedupe, strict ordering, queue backpressure, restart-safe page cursors, and content-free failure/freshness projection
  • add a document-comment Provider boundary with typed permission requirements, exact registration-to-guidance binding, and publication readiness
  • require document comments to reference separately registered project material while remaining external_input_only
  • enforce permission evaluation → bounded Provider read → durable capture → Agent effect → Provider response/readback → ACK; no cursor advancement before settlement
  • require a committed working-session or domain effect and an event-bound verified response receipt before ACK
  • remove processed private event bodies after durable settlement while retaining content-free identities for replay deduplication

This implements the provider-neutral runtime, durable inbox, and synthetic document-comment Provider call boundary described by #3351. It does not ship a concrete external document adapter or any provider credentials.

Review refinement

Exact-head review found that the initial response proof was only a group of booleans: it was not bound to the current event and a provider writer was not required to echo the requested idempotency key. A stale verified receipt could therefore authorize a different event's ACK. The refined contract adds agent_external_event_response_receipt_v0, binds it to a content-free event digest, requires document providers to return the exact requested idempotency key, and converts provider-specific readback into that typed receipt at the adapter boundary. Negative coverage proves cross-event and mismatched-idempotency receipts fail closed.

Review also found that acknowledged event files retained owner-private bodies indefinitely. Settlement now commits cursor/ack state first and then removes the processed event file. The acknowledged content-free identity remains in cursor state, capture checks it before reaccepting an event, and replay can still advance a previously acknowledged page. Coverage proves both cleanup and replay behavior.

Architecture and TypeScript boundary

The Provider remains the external-effect adapter: credentials, raw payloads, provider API calls, exact scopes, and external response readback stay outside the kernel. The Connector module owns a new extension-domain binding, owner-local inbox, and provider-neutral receipt validation; it does not replace or duplicate an existing TypeScript Todo/quota/scheduler transition.

For the existing Lark live path, a completed persisted runtime Turn is adapted into the Connector's working_session_turn proof. The PR does not move a migrated TypeScript rule back into Python. Under the TypeScript migration RFC's payoff-phase rule, this new extension contract should not be translated leaf-by-leaf into TS until a complete operator-visible Connector transaction can cut over and delete the Python owner in the same bounded stage.

Future-facing boundary

The Provider call contract lives in a separate module instead of extending the durable inbox state module further. The binding normalizer is reused at caller boundaries, so concrete adapters can validate one authority contract without duplicating Connector state rules. A concrete document provider is intentionally outside this PR; the callback boundary and exact permission/receipt contract are the compatibility seam being reviewed here.

Validation

  • python -m pytest -q tests/extensions --disable-warnings --maxfail=1 — 429 passed
  • focused Connector runtime, Provider, and Lark routing/runtime tests — 66 passed
  • Ruff check and format check over the Connector runtime, Provider, Lark bridge, and focused tests — passed
  • loopx canary premerge --from-git-diff — 13/13 selected checks passed, including 8 extension/docs risk-profile smokes and the public-boundary scan
  • git diff --check and changed-file Python compile — passed

Merge decision

Runtime, permission, private-retention, and external-write behavior still requires an independent reviewer. This author-owned PR will not be self-merged; the exact-head review conclusion is published as a COMMENTED fallback because GitHub does not allow formal self-approval.

@huangruiteng
huangruiteng force-pushed the codex/external-connector-runtime-20260822 branch from fc3aad5 to ef1cacc Compare August 22, 2026 16:21
@huangruiteng huangruiteng changed the title Add Agent-scoped external Connector runtime contract Add Agent-scoped external Connector runtime Aug 22, 2026
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng force-pushed the codex/external-connector-runtime-20260822 branch from ef1cacc to 15089f2 Compare August 22, 2026 16:52
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

动机

现有 Lark Goal Topic 已能把一条外部消息送入 Goal,但“来源绑定到哪个 Agent/Session、哪些消息应捕获、走 live/queue/async 哪种 ingress、何时允许回复和 ACK”仍混在 provider-specific routing 中。文档评论等增量来源还需要 cursor、去重、顺序、backpressure 与权限修复合同。这个 PR 的目标不是增加一个名为 Connector 的空 capability,而是定义 provider-neutral 的调用方结果合同:一个外部事件源精确绑定一个 Agent,provider 保留凭证和原始 payload,LoopX 只接收规范化事件、owner-local 状态与 content-free projection。

改动思路

权责流为:Provider permission/read → agent_external_connector_event_v0 → owner-local ordered inbox → Agent/working-session durable effect → provider response + readback → event-bound response receipt → ACK/cursor commit。build_external_connector_binding() 用枚举和组合约束把 session、async inbox、cursor、response capability 的非法组合挡在入口;capture 以 expected cursor 做 CAS,先持久化事件且不提前推进 page cursor;settlement 只接受队头事件,并在 effect 和 response proof 均匹配当前 event 后提交 ACK。公共状态只暴露数量、freshness、lifecycle 与 capability,不暴露 source、cursor、正文、anchor、reply chain、scope 或 repair URL。

TypeScript RFC 方面,这里创建的是新的 extension-domain owner,并未重新实现已迁移的 Todo/quota/scheduler reducer,也没有增加逐 leaf 的 Python↔TS bridge chatter。Lark adapter 只把“已完成且持久化的 working-session Turn”转换成 Connector proof。以后若 Connector 形成完整 operator-visible transaction,应按 payoff-phase 原则整体迁入 TS 并删除 Python owner,而不是保留双语义实现。

具体改动

关键代码讲解

  • build_external_connector_binding() / project_external_connector_status():统一 group message 与 document comment 的 capture、ingress、response、lifecycle 和 capability shape,并隔离 owner-private refs。
  • capture_external_connector_events():校验精确 cursor、稳定 event id 去重、addressed filter、队列上限和 restart-safe sequence;只有没有未结算输入的页面才立即 checkpoint。
  • decide_external_event_ack() / build_external_event_response_receipt():effect receipt 必须绑定 raw event id;response receipt 使用 content-free event digest 和严格 boolean proof 绑定当前事件,杜绝跨事件复用旧 readback。
  • settle_external_connector_event():强制队头顺序;先原子提交 ACK/cursor,再删除已处理的私密 event body,同时保留 content-free id 用于 replay dedupe。
  • evaluate_external_connector_permissions() 与 document-comment provider boundary:exact scopes、provider identity、publication requirement、repair URL 均留在 owner-local guidance;公共 projection 只输出 readiness。response writer 必须回显本次 idempotency key。
  • Lark Goal Topic bridge:新 Agent-bound binding 持久化 generic Connector;legacy Goal-only binding 仍可读。实时回复在 ACK 前转换为 event-bound response proof。

对主干的风险

初审在旧 head 上发现两项 P1 级合同缺口,均已在当前 head 修复:一是任意带三个 true boolean 的历史 response receipt 可放行另一事件;二是 ACK 后私密正文永久保留,所谓 bounded inbox 只限制 pending、不限制历史内容。负例现在证明跨 event receipt、错误 idempotency key 和非 boolean proof 均 fail closed;正例证明 ACK 后正文文件删除且 acknowledged page replay 仍能推进 cursor。

剩余风险主要是规模和新公共合同:9 个文件、约 3k 行,document-comment 层目前是受测 callback compatibility seam,不包含具体 provider adapter 或凭证。它有明确 issue、文档、入口/失败合同与端到端 synthetic caller,但是否值得现在稳定为公开 seam,仍应由独立 reviewer 再做一次 scope-fit 判断。默认行为变化已披露:只有新 Agent-bound Connector route 增加 effect/readback ACK gate;legacy route 继续兼容。所有 machine-enforced obligation 均以 typed schema/enum/receipt 表达,没有用 prose “guidance” 替代强制检查。

exact head 5782a658b714c1f880e3c389e031039a532ad61e 的本地验证:extension suite 429 passed;focused Connector/Lark 66 passed;Ruff/format passed;premerge canary 13/13 passed,public-boundary scan clean。GitHub DCO、dependency review、builds、Linux pytest 均通过。Windows 首轮在 PR 未触及的 test_retry_safe_typed_write_recovers_after_unexpected_runtime_exit 重启路径偶发失败;仅重跑该 job 后 43/43 通过,未改 Connector 代码。最终 merge 仍需独立 reviewer approval。

我的整体评价

架构方向成立:provider 负责外部系统,Connector 负责规范化 binding/inbox/proof,核心 Goal/Todo 权威不被外部评论或群消息提升。refinement 把最危险的“看起来已验证、实际未绑定”和私密数据长期累积问题关掉了,且没有引入 TS/Python semantic twin。代码层面当前没有未修复 blocker;结论是“技术上可进入独立复核”,不是 author self-merge。由于 GitHub 禁止作者正式自批,本条使用 COMMENTED fallback;独立 reviewer 应重点复核 scope-fit、permission boundary 与 external-write idempotency。

English verdict: CODE-LEVEL APPROVAL AFTER REFINEMENT — exact-head local validation and remote checks are green (the unrelated Windows restart test passed on isolated rerun), but this author-owned runtime/permission change still requires independent approval before merge.

@huangruiteng
huangruiteng merged commit bf27af7 into main Aug 22, 2026
10 of 11 checks passed
@huangruiteng
huangruiteng deleted the codex/external-connector-runtime-20260822 branch August 22, 2026 17:32
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.

1 participant