拆开 oh-my-openagent 的编排层:一次任务怎样选模型、派发和续跑 给一个导出接口增加 CSV 格式听起来是一件事。实际动手时可能要先找到现有导出链路确认字段与编码约定再改接口、补测试。如果这些工作交给几个代理真正需要设计的就不只是它们各自的提示词谁决定拆分谁拿到什么上下文结果回到哪里什么时候继续什么时候应该停下来这也是读oh-my-openagent源码时值得追的一条线。代理的名字很容易记住任务在它们之间怎样流动才更能说明编排层做了什么。2026-11-01 修订本文更新了项目版本边界删除无法对应固定版本的文件数、Hook 数和角色总数重新核对了任务派发与续跑逻辑。下文是源码分析没有在本次修订中运行项目也不提供速度或成本排名。先分清现在读的是哪一版仓库仍是code-yeongyu/oh-my-openagent。本次固定到提交13a25928c58ac7b481ac711e376d225899c74013避免把持续变化的开发分支当成不变的说明书。一个重要变化是当前 README 主推独立的omo命令运行在项目的 senpi 引擎上文档把这条路径称为 OmO Native。OpenCode 版与它有迁移和共存关系不能再把整个项目概括成“只运行在 OpenCode 上的插件”。README 与迁移说明下面选择OpenCode 1.x 适配路径追踪一次任务因为它能把旧文讨论的机制连接到具体代码。这个范围也有必要说清该提交为 OpenCode 2 提供的setup入口只完成插件注册并记录提示并没有运行同一套 V1 完整逻辑。看到相同项目名不代表不同宿主走的是相同执行链。实际入口一条消息不会自动走遍所有代理OpenCode 适配层的入口会组装管理器、工具和 Hook再把它们接到宿主接口上。plugin-interface.ts里可以直接看到消息处理、消息变换、系统提示变换、工具执行前后以及事件处理等入口。接口组装Hook 提供的是介入时机。某个 Hook 是否启用、这次事件是否满足条件还要看配置与具体处理函数。不能因为仓库里存在这些模块就画成每次请求必定经过全部环节的流水线。以 Sisyphus 主会话为例它可能直接处理小修改也可能调用task委派工作。task的参数把两个维度分开subagent_type点名一个专门角色。category按任务类别选择执行配置。工具声明要求二选一。代码接着分别进入角色解析或类别解析而不是把两者当作同一个名字的不同写法。task 工具用户提出具体需求主代理确定任务边界task 选择角色或类别解析模型与技能上下文创建或续接子会话结果交回主会话核验图 1按源码归纳的委派关系。它描述任务已经被决定委派后的路径不表示每个请求都必须创建子代理。还有一个容易混淆的地方**工具中的类别分支是在主代理已经给出类别参数之后执行的。**它不能证明系统对任何自然语言需求都能选出最合适的类别。任务怎样拆、何时需要顾问、一次该给多少上下文仍受到模型、提示和已有信息的影响。这一区分很重要。程序可以检查参数、限制工具、启动会话任务判断是否合理还需要看真实执行结果。Category 选配置执行角色不一定随之改变旧文把角色列成了一个固定团队却没有给出对应版本与注册口径。工作领域、任务类别和实际代理很容易因此混在一起让人以为每增加一种工作就得再加一个代理。实际的类别解析更值得看。category-resolver.ts会合并类别配置查询可用模型处理用户覆盖、提示追加与回退链这条路径最终返回的执行角色是Sisyphus-Junior。因此不同类别可以让同一个执行角色采用不同的模型和任务约束。类别解析拿前面的 CSV 导出来说可以先把“查清现有约定”和“按已确认约定实现”分开。前者的交付是证据与位置后者的交付才是代码和测试。是否值得拆成两个代理要看搜索范围与依赖如果只是一个文件里的局部修改拆分本身也有传递上下文的成本。Category 的价值在于把任务执行配置集中管理。它并不自动保证选到的模型更便宜、更准确回退之后有没有改变输出质量也需要单独观察。后台任务有独立会话但未必有独立工作区选择后台执行后executeBackgroundTask会把任务描述、提示、父会话、模型、技能和权限等信息交给BackgroundManager。管理器先建立pending任务并进入并发队列再在实际启动时创建子会话。后台派发这里有一段值得停下来看的逻辑子任务目录取input.cwd没有提供时使用父会话目录。也就是说新会话不等于自动获得隔离的文件副本。几个代理如果落在同一目录又同时改同一文件仍然需要处理写入冲突和集成问题。目录与会话创建这给实际使用带来的建议很具体并行检索可以按证据分工并行修改要先划清模块或工作区并明确谁负责整合。多开几个会话解决的是执行并行不能替代任务边界设计。工具限制也应按实际代码理解。共享限制表里Sisyphus-Junior的task被禁用后台启动还会合并角色限制和用户权限。它是一项具体的工具限制旧文直接写成“不能继续委托”过于笼统——同一启动逻辑里还存在call_omo_agent等能力是否能使用要继续看角色与宿主约束。角色限制、启动时的工具配置续跑不是“只要没做完就无限重试”旧文把 ULW、Boulder 与 TODO 续跑合并成了一种机制表达得太满。阅读时可以先把三个问题分开工作方式如何被提示计划状态怎样记录空闲之后是否应该再启动一轮。在这个提交中Boulder 包把状态路径定义为.omo/boulder.json承担计划跟踪所需的状态记录。todo-continuation-enforcer则有自己的空闲事件处理器检查当前会话是否需要继续。前者保存工作状态后者判断一次续跑机会职责有关联但并不相同。Boulder 路径、续跑判断否是是否收到 session.idle仍有未完成 TODO?结束或等待存在阻塞或停止条件?满足其他条件后注入继续提示图 2续跑条件的简化关系不是逐行控制流。源码还包含恢复、上下文限制、冷却和失败次数等检查。例如代码会在用户问题尚未回答、后台任务仍在运行、会话被取消或出现不可重试错误时跳过续跑并调用停滞检测决定是否还应继续。这个设计比“自动再发一句继续”复杂得多也说明自动化需要停止条件。假如 CSV 字段顺序还等人确认代理应该把这个决定交回来假如只是测试没跑完就应沿原任务继续验证。两种情形都叫“还没做完”处理方式却不能一样。评价编排最后还得回到交付这次重读后我更愿意用几项可观察的问题评价它任务是否被合理拆开角色和模型配置是否匹配子任务结果是否带证据修改是否正确整合失败时能否停在可恢复的位置。源码提供了这些问题的实现入口但没有替我们给出性能结论。我在另一篇 DSH Super-agent 分析里讨论过人工注意力成本这里也一样代理产出增加之后还要看审查、返工与协调是否一起增加。读多代理项目可以先挑一个具体任务沿着“谁决定、如何派发、结果去哪、何时停止”走一遍。比起记住角色总数这条链更容易迁移到自己的开发流程里。