fix(ego-reader): keep native source tools usable with owned spaces - #5770
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=xhigh
Request changes conclusion (author-owned PR; GitHub blocks formal self-review)
Exact head: aeb19ba
动机
配置 Ego 正文与图片工具的原生 MCP host 操作者。
固定浏览器空间过期后,仍可恢复的原生会话无法再读取来源;auto 入口试图自动创建与恢复专属页面,但两个真实 host 实际复用了同一空间。
单个 host 的过期恢复、正文和图片读取成功;多个 host 的专属空间承诺失败,退出或导航可能干扰另一 host。
本次只评审浏览器 transport;不认证来源内容真实性、Bot 下游交付、账户授权或默认启用。
每进程隔离尚未成立;SIGTERM 已清理浏览器空间,但进程仍等待 stdin EOF;原生 Bot 下游交付仍由其 owner 独立验收。
本次 SIGTERM 实验确认浏览器空间关闭,但 stdin 仍打开时 Python 进程 35 秒后仍存活,EOF 后退出。真正阻断批准的是下面已复现的跨进程共享空间。作者后来更正原生会话的下游交付尚未验收;正文和图片读取与最终频道交付须分别判断。这个更正不改变已复现的 transport 反例。
改动思路
原生 stdio MCP 沿用正文和图片两个工具,显式环境配置决定 executable、origin 与页面;Python 适配器不拥有模型会话、账户或发布权限。新 _OwnedSpace 仅记录一个进程内的空间句柄,首次合法 auto 调用时请求 Ego 创建/复用空间,confirmed missing 时最多恢复一次。URL、exact-resource fence、输出限额和本进程读锁复用现有实现。
最小设计应在这个现有 owner 内使用稳定的每进程唯一创建标识。独立进程内的锁和句柄不能使浏览器资源自动独立:Ego 的实际 taskSpace(name) API 是“reuse or create”。固定名称因此是资源共享键,而不是排他创建证明。无需添加浏览器管理服务或新的权限机制。
具体改动
四个路径均已完整读取:ego_source_reader.py 增加惰性空间、总 deadline、missing-space 恢复及 shutdown;pyproject.toml 增加可选 mcp==1.28.1 extra;集成文档提供 auto、数字空间、关闭和 rollback;测试增加模拟空间和 stdio 入口。
规格:docs/integrations/ego-source-reader.md,spec_revision 8251ec80e0c327d28d13a1fd64e3f343a2aa3c0e。本次修改后的文档只作披露,以下依据修改前的契约:
Operator setup is explicit:not_met。旧契约要求每个 MCP process 保留独立页面,不与另一进程共享;真实两个 host 返回同一个空间。Redirects and Page races fail closed:implemented。origin 预检查与规范化 exact URL fence 保留,生成脚本的拒绝路径通过。Calls within one process reject concurrent reads:implemented。本进程锁和正文/图片限额通过;这不证明跨进程隔离。Release qualification must separately verify:deferred。本次资格化真实 MCP/browser transport;原 Bot 身份、频道交付和 workspace grant 的最终验收由原 owner 负责。
关键代码讲解
loopx/extensions/ego_source_reader.py:88_OwnedSpace.resolve:记录 creation attempt,拒绝不确定创建的盲重试;但第 100 行所有进程都调用taskSpace('LoopX public-source reader'),真实 API 会复用既有同名空间。loopx/extensions/ego_source_reader.py:117_OwnedSpace.close:只检查记住的 id 当前是否 agent-owned;agent-owned 不等于这个 MCP 进程排他创建,可能关闭另一个 host 使用的页面。loopx/extensions/ego_source_reader.py:318_read:origin/配置先于创建,锁与总 30 秒 deadline 共用于创建、读取和一次 confirmed-missing 恢复;这些单进程路径通过。loopx/extensions/ego_source_reader.py:388main:保持原工具 schema,通过 finally 关闭空间并安装 SIGTERM handler。真实 signal 实验空间已关闭,但进程等待 stdin EOF 的退出限制应补充或修复。
对主干的风险
[P1] 每个 host 必须使用唯一而稳定的空间标识。 在真实安装的 Ego 上启动两个独立 stdio MCP host,均设置 auto 和同一合法 origin;两个进程分别成功读取正文,却读回同一个 TaskSpace id。一个 host 的导航会改变另一个 host 的页面,退出 cleanup 也会影响另一个 host。新测试给模拟 factory 预设不同 id,所以 87 项测试全绿仍能遗漏这个缺陷。修复应为每个进程生成一次唯一 name/nonce,在它的后续读、恢复和 shutdown 中保持自己的生命周期;用真实两个 host 验证不同空间、交错正文/图片调用与单方退出后另一方仍可工作。
独立证据:head 87 项、source-asserted base 75 项测试通过;真实 MCP 单 host 的非法 origin 拒绝、空间主动关闭后的恢复、正文、实际 PNG content 和 EOF cleanup 通过。数字空间的 base/head 正文及 PNG 元数据/摘要完全一致,并且 adapter 没有关闭显式保留空间。并行固定空间探针最初使用同名测试空间而相互干扰,改为独立测试名称后通过;这也促使本次验证真实 factory 的复用行为。SIGTERM 两次记录保留:stdin 打开时 35 秒未退出,但第二次明确观察到空间已关闭,EOF 后 exit 0,因此不能把它描述为“浏览器未清理”。
Ruff、mypy、diff、development advisory 后的全树 semantic smoke 通过。最初误写了 semantic 脚本路径,只产生 missing-file 失败;改用仓库现有脚本后通过,没有改测试范围或标准。不获取、轮询或等待 CI。
语义与 CI 对齐
这是局部 provider 生命周期,不新增泛用状态词汇。auto 的每进程 scope 必须由真实 factory identity 实现;目前 own 的排他语义与实际共享资源不符。missing-space 的文本 regex 只位于 provider 解码边界,不是 generic Goal/Todo 分类规则;今后 provider 提供 typed error 时应直接采用。
我的整体评价
REQUEST_CHANGES。problem_context 的交付判断为 not_yet_proven:单 host 恢复有价值,但每进程隔离的关键验收失败。long_horizon 与 user_experience 均受跨 host 导航/退出干扰,未能保留现有独立页面边界。显式 numeric 路径和关闭 auto 是当前可回退路径。
代码规模适合现有可选 adapter;未来变更审查要求的有界改进就是修正稳定唯一创建键,并验证真实两进程,不需要新的生命周期框架。修复后需重新审查新 head,保留 numeric parity、origin/URL/user-control/总预算和退出负例。未认证真实 Bot 下游材料、账户权限、安装全局发布或模型行为;批准、旧 review closeout 和 merge 权限仍分别判断。
English verdict: REQUEST_CHANGES - aeb19ba. Two real native MCP processes reuse the same named Ego TaskSpace, defeating per-process isolation and cleanup ownership. Single-host recovery/text/image/EOF and numeric base/head parity pass; use a stable unique process identity and validate real concurrent hosts. CI was not consulted.
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
|
Fixed the exact-head review finding in 89a8f8b: each MCP host generates one UUID nonce for its named Ego TaskSpace and retains that identity throughout confirmed-missing recovery. The unit factory now models real name-based reuse instead of assigning distinct ids unconditionally. Real native MCP validation on the installed browser: two independent stdio hosts resolve distinct spaces and names, each reads the same full rendered source and actual PNG content; after one exits, the survivor successfully reads another PNG. Both owned spaces are confirmed absent after EOF cleanup. The first validation harness used incorrectly nested AnyIO contexts and failed during teardown; the corrected two-task harness passed and the failed attempt is retained privately. SIGTERM cleanup/EOF exit limitations are explicitly disclosed in the integration document. All 87 adapter tests, Ruff, focused mypy, development semantic advisory and risk-based premerge pass. No CI status is used as evidence. This qualifies browser transport isolation, not native Bot final-channel delivery; the independently tracked Lark edit-quota repair still needs actual channel readback. Please re-review the new exact head. |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; gpt-6.1-sol; OpenAI; runtime_reported; reasoning_effort=xhigh
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Exact head: 89a8f8b
动机
配置正文与图片读取工具的原生 MCP host 操作者。
旧的固定页面过期后不能继续读取;上一版自动恢复又让两个 host 共用同一页面。现在每个 host 使用稳定的独立名称,关闭一个后另一个仍能读图。
两个真实 reader 进程分别创建不同页面,过期后只恢复自己的页面,正文与实际 PNG 读取成功。
本次资格化浏览器读取与隔离,不证明来源真实性、模型理解、原 Bot 最终投递或稳定版本发布。
SIGTERM 清理后仍可能等待 stdin EOF;下游原 Bot 的最终频道投递与正式安装资格由其既有 owner 独立验收。
改动思路
Existing specialized Python Ego extension owns ephemeral transport only; browser owns TaskSpace lifecycle。真实路径为 Explicit MCP configuration -> main/read_public_url/read_public_image -> _read -> _OwnedSpace.resolve -> installed Ego TaskSpace/Page; main finally -> _OwnedSpace.close。复用现有provider owner和调用者授权,避免第二个sender、worker或泛用Python决策源;return读回、用户采纳、模型收益与Goal验收分别判断。
具体改动
新 head 的唯一稳定 UUID 改动修复上一版固定 factory 名称冲突。Ego 的 named factory 仍可能复用同名资源,因此名称必须按进程独立而在同一 host 的恢复中保持稳定。此次真实两进程、关闭一方后幸存者读取、另一方过期后同名恢复证明该条件,不以模拟返回不同 id 当作隔离证据。完整四路径包括既有 URL/正文/图片 guards、可选 mcp extra、文档和测试;复用上一 exact-head 的不变图像/URL契约证据前,已核验 base、依赖、主分支和调用路径没有改变,并重跑87测试与真实入口。旧 P1 已由当前证据解决,历史 review/inline 仍保留审计。
单 host / numeric compatibility 的 scope、全文、digest、尺寸、PNG 像素存在和 configured 页面保留状态在不可变 base/head 完整比较相等。SIGTERM 可完成页面清理,但 stdio 仍可能等待 stdin EOF;既有真实失败/退出观察被新文档如实披露,不声称修好了进程退出。强杀无清理保证,用户接管/其它浏览器错误不恢复。
规格:docs/integrations/ego-source-reader.md,spec_revision 8251ec80e0c327d28d13a1fd64e3f343a2aa3c0e,在当前diff前读取该不可变版本;本PR对文档的补充不是独立证明。
Operator setup is explicit:implemented。Reserve a Page per MCP process; never share it with another process. 87 exact-head tests; unchanged immutable base75 evidence revalidated against source pins; real installed Ego/native MCP two-host isolation, survivor PNG, confirmed-expiry recovery and own EOF cleanup; fresh numeric base/head full structured text/image/error parity; diff/Ruff/scoped mypy/advisory then full semantic smoke pass.Redirects and Page races fail closed:implemented。Authorize origins before navigation and reject changed exact URL before extraction. 87 exact-head tests; unchanged immutable base75 evidence revalidated against source pins; real installed Ego/native MCP two-host isolation, survivor PNG, confirmed-expiry recovery and own EOF cleanup; fresh numeric base/head full structured text/image/error parity; diff/Ruff/scoped mypy/advisory then full semantic smoke pass.Calls within one process reject concurrent reads:implemented。Reject concurrent same-process reads and preserve bounded text/images. 87 exact-head tests; unchanged immutable base75 evidence revalidated against source pins; real installed Ego/native MCP two-host isolation, survivor PNG, confirmed-expiry recovery and own EOF cleanup; fresh numeric base/head full structured text/image/error parity; diff/Ruff/scoped mypy/advisory then full semantic smoke pass.Release qualification must separately verify:deferred。Original native Bot tool call, visible return, preserved identity and grants are separate qualification. SIGTERM 清理后仍可能等待 stdin EOF;下游原 Bot 的最终频道投递与正式安装资格由其既有 owner 独立验收。
关键代码讲解
loopx/extensions/ego_source_reader.py:62ReaderConfig.from_environment:Explicit origin/executable/numeric or auto configuration; no availability activation。loopx/extensions/ego_source_reader.py:84_OwnedSpace.__init__:Generate one stable UUID name per process, reused after confirmed expiry。loopx/extensions/ego_source_reader.py:92_OwnedSpace.resolve:Resolve that unique named factory; ambiguous creation cannot blindly retry。loopx/extensions/ego_source_reader.py:321_read:Validate origin before creation; local lock and one total deadline; recover confirmed missing only。loopx/extensions/ego_source_reader.py:392main:Expose narrow read tools; finally close only own created still-agent space; SIGTERM EOF limit documented。
对主干的风险
Unconfigured/unauthorized/invalid URL rejects before creation; ambiguous creation or user-control/browser failure does not create a replacement; one host cannot close another unique space。最大风险是把不确定写入或资源身份当作可安全重复;当前证据沿生产入口核验effect与持久readback,而非只看返回ok。
87 exact-head tests; unchanged immutable base75 evidence revalidated against source pins; real installed Ego/native MCP two-host isolation, survivor PNG, confirmed-expiry recovery and own EOF cleanup; fresh numeric base/head full structured text/image/error parity; diff/Ruff/scoped mypy/advisory then full semantic smoke pass.
上一head固定名称的真实两进程失败仍保留;新head相同边界的真实进程证据覆盖它。此前 SIGTERM 等待stdin EOF观察保留,文档限制并不被计为修复进程退出。 不查询、轮询或等待CI。没有模型效果/延迟测量,也不把外部owner声明当作自己的生产验收。
语义与 CI 对齐
Default-off 由显式MCP配置保持;import、安装或工具发现不创建页面。Numeric关闭路径完整parity、origin拒绝和actual多host隔离分别验证。 Provider专有词汇留在extension;机器限制与操作建议明确区分,不新增泛用must_attempt_work义务。
我的整体评价
APPROVE,交付判断为 justified_increment。long_horizon improved:两个真实 reader 进程分别创建不同页面,过期后只恢复自己的页面,正文与实际 PNG 读取成功。 user_experience improved:旧的固定页面过期后不能继续读取;上一版自动恢复又让两个 host 共用同一页面。现在每个 host 使用稳定的独立名称,关闭一个后另一个仍能读图。 沿原入口恢复,不要求重输问题或重建会话;必要原source授权仍保留。剩余边界:SIGTERM 清理后仍可能等待 stdin EOF;下游原 Bot 的最终频道投递与正式安装资格由其既有 owner 独立验收。
有界未来重构:已将稳定unique identity放入既有生命周期owner;无需新增resource manager。 未发现当前阻塞。该 exact-head 结论与平台aggregate、closeout、requiredchecks和维护者merge授权分开。同作者GitHub账户只能以COMMENTED公开approval结论,不能宣称formal APPROVED;历史COMMENTED讨论保留,真正有效的阻塞review另由当前closeout与权限契约处理。
English verdict: APPROVE - 89a8f8b. 两个真实 reader 进程分别创建不同页面,过期后只恢复自己的页面,正文与实际 PNG 读取成功。 87 exact-head tests; unchanged immutable base75 evidence revalidated against source pins; real installed Ego/native MCP two-host isolation, survivor PNG, confirmed-expiry recovery and own EOF cleanup; fresh numeric base/head full structured text/image/error parity; diff/Ruff/scoped mypy/advisory then full semantic smoke pass. SIGTERM 清理后仍可能等待 stdin EOF;下游原 Bot 的最终频道投递与正式安装资格由其既有 owner 独立验收。 CI was not consulted. Exact-head evidence qualifies this bounded provider increment, not broader release or Goal acceptance.
A configured fixed Ego TaskSpace can expire while a native Chat Session remains resumable. Public-source tools then stop working even though the installed browser is healthy. This adds opt-in
LOOPX_EGO_READ_TASK_SPACE="auto": each MCP host lazily creates and reuses its own space, replaces it only after a confirmed missing-space error, and finishes only its own still-agent-owned space on shutdown. Existing numeric-space configuration remains supported.The existing read-only URL/image tools retain origin checks, exact-URL fences, bounded pixels and the per-process read lock. Creation and recovery share the same 30-second request budget; ambiguous creation and user-control stops do not create replacement spaces. The optional
ego-source-readerdependency extra and setup guide make installation explicit without adding a CLI owner or changing host permissions.Validation: 87 focused tests passed, including concurrent stdio hosts, EOF cleanup, text/image reuse, stderr receipts, timeout budgeting and negative URL/ownership cases; Ruff and mypy passed. Standard premerge passed all 11 selected checks plus direct checks. Its first run lacked root npm dev dependencies; installing the existing lockfile dependencies resolved that setup failure. CI was not fetched or used as evidence.
Local native-path acceptance: the original resumable Bot Session invoked the MCP text reader, consumed actual rendered images, and completed one previously blocked material request. Independent readback verified intake, ranking receipts/projections and preserved existing material membership/content. Core completed, but the final streaming-message edit is still blocked by a provider readback mismatch in the existing delivery path; that separate defect is under repair. A Core terminal event is not channel-delivery evidence. The workspace sandbox and original Session were preserved. This does not qualify every downstream workflow or source. No private configuration, account binding, conversation text or browser content is included.