十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

oh-my-openagent 实战:omo-senpi config-watch 重复加载崩溃修复与三通道 Live QA 验证

oh-my-openagent 实战:omo-senpi config-watch 重复加载崩溃修复与三通道 Live QA 验证 oh-my-openagent 实战omo-senpi config-watch 重复加载崩溃修复与三通道 Live QA 验证【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent导读本文基于 oh-my-openagent 仓库中omo-senpi-adapter/20260827-config-watch-standdown的 QA 证据文档完整还原一次真实线上缺陷的定位、修复与验证全过程当两个 omo 扩展实例在同一 senpi 进程中被重复加载时config-watch 组件的rebuildWatchers会陷入身份守卫identity-guard的互相回显最终以RangeError: Maximum call stack size exceeded栈溢出崩溃。文章将拆解修复代码的 deferral/coalescing 与 stand-down 设计并逐行讲解驱动真实 senpi 二进制的三通道隔离 QA 脚本读者可据此掌握修复前必先可复现、修复后必证不回归、全程不污染真实凭证的工程方法论。背景issue #7419 的崩溃机制本次变更PR #7420针对 issue #7419在 senpi 进程内同时加载了两个 omo 扩展实例例如 senpi settingspackages中配置的本地开发插件加上 omo launcher 通过--extension注入的捆绑扩展时senpi 引擎2026.8.26-2与崩溃报告完全同版本会发生RangeError: Maximum call stack size exceeded崩溃点位于rebuildWatchers的调用栈。其根因可从修复代码 config-watch/index.ts 的注释中还原senpi 的 config-watch 协议由一组事件构成config-watch:register、config-watch:ready、config-watch:reloaded、config-watch:rejected外加会话级session_shutdownsenpi 在每次 watcher 重建后都会发出 READY 事件——包括该组件自身注册引发的重建组件对 READY 的响应是重新注册re-register以保证 config-reload 主机重启清空注册表后 watch 仍能存活当两个活着的 omo 实例交替以不同 payload 身份注册时senpi 的注册表只保留最后一条注册且其重注册守卫比较的是 payload 身份identity于是两条实例会持续注册 → READY → 再注册地互相回显由于 READY 与 REGISTER 发生在同一条同步栈上直接同步重发注册会在拒绝是确定性场景下无限递归直到栈溢出——这正是RangeError的来源。修复设计延迟合并 被取代实例让位stand-down修复落在 config-watch/index.ts包含两个相互配合的机制机制一deferred/coalesced 的 READY 重注册原实现中READY → 同步重新 emit REGISTER的路径被改写为经 0ms 定时器合并的延迟发射scheduleEmitRegistrationconst scheduleEmitRegistration (): void { clearRetryTimer() retryTimer setTimeout(() { retryTimer undefined emitRegistration() }, 0) }关键细节与理由源码注释均有明确说明绝不从 senpi 事件派发内部发射 REGISTER因为rebuildWatchers与 REGISTER 同栈直接重发必然递归一个合并定时器同时服务 READY 重注册与拒绝重试两者动作完全相同合并后行为一致故意不调用unref()0ms 定时器本身是自排空的且dispose()会清理它而 unref 的一次性定时器在 Bun/Windows 下可能被无限期饿死——这是 senpi-compatibility CI 曾观测到的挂起根因。机制二superseded-instance stand-down身份守卫组件在收到同 idOMO_REGISTRATION_ID即omo的其他实例注册时判定自己已被取代输出警告并主动让位events.on(CONFIG_WATCH_REGISTER, (payload) { if (payload registration || payload emittingRegistration) return if (!isRecord(payload) || payload.id ! OMO_REGISTRATION_ID) return ctx.logger.warn( omo config-watch superseded by another omo extension instance; standing down, { hint: two omo extensions are loaded in this senpi process ...; remove one }, ) dispose() if (releasePrevious dispose) releasePrevious undefined })两个精妙的边界处理emittingRegistration标记组件自己发射的 payload 在发射期间被标记防止把自己的回显误判为外来实例因为同步拒绝会在自身 REGISTER 监听器看到原 payload 之前就换掉registration仅比对当前 registration 会误伤releasePrevious串行化register()入口先释放上一代订阅保证组件重复注册时不会叠加监听器。配套的拒绝重试预算REJECTED 事件例如目标路径覆盖了 senpi agent 目录这类确定性拒绝同样禁止同步重发改为按 payload 指纹targets 序列化限次重试const MAX_REJECTION_RETRIES 3同一指纹的拒绝最多重试 3 次且目标修复落地payload 变化会重置预算同时保留同一个 validator 实例使粘性诊断在修复前不被清空。这些常量与逻辑均可直接在上文源码中核对。三通道 Live QA用真实 senpi 二进制验证行为矩阵修复不能只停留在单元测试层面。证据目录 20260827-config-watch-standdown 下的驱动脚本 dual-load-qa.mjs 直接驱动仓库内的真实 senpi 二进制node_modules/.bin/senpiWindows 下为senpi.exe通过三个 lane 覆盖修复的完整行为矩阵Lane装载方式证明点lane1-single-load仅通过 settingspackages加载一次修复后插件修复不回归正常单实例生命周期全部组件注册成功、无注册失败、无让位警告lane2-dual-fixedpackages一份修复后插件 --extension第二份修复后副本重复加载优雅降级出现让位警告、会话正常完成、无注册失败lane3-dual-prefix两个位置都放修复前完整插件全部 bundle 取自修复提交父提交c45968dfc~1failing-first忠实复现 issue 报告的RangeError: Maximum call stack size exceeded证明rebuildWatchers身份守卫乒乓正是修复所针对的机制运行命令在仓库根目录node .omo/evidence/omo-senpi-adapter/20260827-config-watch-standdown/dual-load-qa.mjs关键设计修复前后 bundle 的纯单代隔离lane3 之所以可信在于它对插件树的处理不是简单混搭每个 lane 都通过cpSync完整复制 packages/omo-senpi/plugin 的全部生成插件树含omo-task.js及兄弟扩展、skills、stagedruntime/、manifest保证每个组件都会注册随后用git show revision:packages/omo-senpi/plugin/extensions/name从父提交c45968dfc~1提取全部六份生成的扩展 bundleomo.js、omo-task.js、omo-member.js、omo-memory-mcp.js、memory-run-supervisor.mjs、omo-init-deep-advisor.js整体覆盖上去这样崩溃扩展是纯粹的单一版本产物而非新旧混合的杂交体脚本还做了正反双向自检prefixBundle必须不含standing down确保取到的是真修复前代码fixedBundle必须含standing down确保当前树确实包含修复。修订号可用环境变量PREFIX_REVISION覆盖分支变基后适用。关键设计凭证隔离与未触碰断言每个 lane 都复用了 drive.mjs 导出的官方隔离 harnesscreateSandbox、seedSandbox、credentialDigest一次性SENPI_CODING_AGENT_DIR同时注入OMO_CODING_AGENT_DIR、PI_CODING_AGENT_DIR隔离的HOME/USERPROFILE/XDG_CONFIG_HOME/XDG_DATA_HOME/XDG_CACHE_HOME本地 mock provider--provider omo-mock --model mock-1PI_OFFLINE1无任何真实凭据不写auth.json每条 lane 以 120 秒超时运行真实 senpi 的-p打印模式-p --provider omo-mock --model mock-1 lane prompt由 mock 脚本输出* complete文本驱动会话收尾。隔离性本身是 verdict 的一部分驱动在运行前后对真实~/.senpi/agent与~/.omo/agent的auth.json、models.json、settings.json剔除易变时间戳、trust.json做credentialDigest比对任何一条 lane 触碰真实 agent 目录都会使整次运行判 FAILrealSenpiUntouched、realOmoAgentUntouched。沙箱根目录%TEMP%\omo-senpi-qa-*由finally块统一删除。关键设计断言粒度与 SKIP/FAIL 持久化声称健康生命周期的 lane 额外断言输出中不存在component registration failed行因此部分初始化的扩展不可能伪装成存活探针lane3 只 pinRangeError文本而非退出码——因为 senpi 即使从 uncaughtException 处理器退出也会返回 0二进制缺失时在任何 staging 之前就把SKIP写入final.json并清理.stage任何 setup/运行时异常浅克隆破坏 git bundle 提取、复制失败等都写入FAIL 原因并清理 stage避免遗留陈旧的 PASS四种路径均被实测强制 SKIPSENPI_BIN/nonexistent、强制 setup 失败PREFIX_REVISIONdeadbeef…、两次完整绿灯。结果final.json 与 lane 输出解读聚合结果持久化于 final.json三条 lane 全部 PASS且realSenpiUntouched: true、realOmoAgentUntouched: truelane1-single-loadexit 0无让位警告、无 RangeError、无组件注册失败lane1-single-load.output.txtlane2-dual-fixedexit 0输出包含omo config-watch superseded by another omo extension instance; standing down附 hint两种加载来源二选一无 RangeError、无注册失败lane2-dual-fixed.output.txtlane3-dual-prefix输出包含OmO exiting due to uncaughtException: RangeError: Maximum call stack size exceeded栈帧与 issue 报告一致lane3-dual-prefix.output.txt崩溃点在code-yeongyu/senpi/dist/core/event-bus.js的 Promise 回调中。三个 lane 放在一起恰好构成完整的对照实验正常单实例不受影响无回归、修复后双实例优雅降级修复生效、修复前双实例必崩机制属实。测试门禁Linux 全绿与 Windows 宿主差异的归因受支持环境Linux上的链式门禁修复同时通过了在 WSL Ubuntu 22.04.4 LTS CI 固定工具链bun1.4.0、nodev24.6.0下、针对本分支头874f807920d9347d75ce3925b7cfadfd1d6a39e0的完整门禁TOOLCHAIN: bun 1.4.0 / node v24.6.0 / Ubuntu 22.04.4 LTS HEAD: 874f807920d9347d75ce3925b7cfadfd1d6a39e0 bun run test:senpi - GATE_EXIT0 bun test packages/omo-senpi: 2404 pass / 7 skip / 0 fail (2411 tests, 321 files) resolve-evidence-dir contract: 10 pass / 0 fail完整逐字输出见同目录 linux-gate-test-senpi.logREADME 明确说明其存在。7 个 skip 是套件自身的 Windows-only 进程模式守卫。Windows 宿主运行如何把环境故障与代码缺陷分开初期的 Windows 宿主运行记录后被上面的 Linux 运行取代展示了严谨的归因方法bun test packages/omo-senpi/src/components/config-watch/36 pass / 0 fail含两个新增回归测试identity-guarded 同步回显宿主、READY 重注册的延迟/合并tsgo --noEmit -p packages/omo-senpi/tsconfig.jsoncleanresolve-evidence-dir.test.mjs10 pass / 0 failbun run test:senpi链式形式在该 Windows 宿主无法完成第一步build:lsp-daemon因 packages/lsp-daemon/scripts/build.mjs 中未加引号的process.execPathshell: true报C:\Program is not recognized另立 issue #7421与本变更无关门禁步骤因此被拆开单独执行bun test packages/omo-senpi2383 pass / 14 fail / 14 skip。14 个失败全部位于src/components/thread/receipts.test.ts、mailbox.test.ts签名一致为EPERM: operation not permitted, fsyncWindows 文件系统拒绝在%TEMP%中以只读 fd 执行fsyncSync在本机隔离环境对未修改的上游文件同样复现且无一触及 config-watch——由 Ubuntu 的senpi-compatibilityCI leg 作为最终仲裁。单元级回归测试的补充覆盖同样的机制在单元层面有 index.test.ts 覆盖共 368 行README 确认包含两个新增回归测试测试通过FakeEvents模拟事件总线记录注册、维护监听器集合以createPi()构造SenpiExtensionAPI的桩专门验证identity-guarded 同步回显自身发射被emittingRegistration标记豁免、外来同 id 注册触发 stand-downREADY 重注册的 deferral/coalescing多次 READY 只合并为一次延迟发射不再同步递归。FakeEvents.emit的实现先写入 registrations、再同步派发监听器正是为了在测试中复现REGISTER 与 READY 同栈的真实协议特征。对读者的可操作总结复现原始崩溃在同一 senpi 进程里以两个位置settingspackages--extension加载修复前的 omo 扩展即可触发RangeError: Maximum call stack size exceeded验证修复同一双加载方式换成修复后插件应看到omo config-watch superseded by another omo extension instance; standing down警告且会话正常完成运行官方 QA仓库根目录执行node .omo/evidence/omo-senpi-adapter/20260827-config-watch-standdown/dual-load-qa.mjs脚本自带沙箱隔离与真实 agent 目录保护无需任何真实凭据判定标准健康 lane 必须同时满足 exit 0、无component registration failed、无 RangeError聚合 PASS 还要求两条真实 agent 目录凭证摘要前后一致。结语本次 config-watch duplicate-load stand-down 修复的完整证据链展示了源码修复 单元回归 真实二进制三通道 QA 跨平台门禁归因的闭环lane3 先忠实复现崩溃证明机制成立lane2 证明修复让重复加载优雅降级lane1 证明单实例生命周期零回归而 Linux 全绿与 Windows 特定 EPERM 失败的归因则把环境故障与代码缺陷严格区分。对任何维护多扩展宿主进程如 senpi的团队这套可复现、可对照、可隔离、可归因的 QA 模式都值得直接借鉴。输出文章【免费下载链接】oh-my-openagentOmO: Just type mass ulw keyword with your prompt. Now you are the master of graph engineering.项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-openagent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表