
oh-my-pi 任务子代理发现与选择机制深度解析Agent 定义、多源合并与执行期解析【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pioh-my-piOMP的 task 子系统负责把父会话的一次委托分解为可执行的子代理subagent任务它从内置定义、用户配置、项目配置、扩展包与 Claude 市场插件等多处来源发现 Agent 定义按既定优先级合并去重并在每次执行前重新解析出真正生效的 Agent。本文基于仓库中的权威文档 docs/task-agent-discovery.md结合 packages/coding-agent/src/task/ 下的真实源码系统讲解 Agent 定义的字段契约、发现与合并规则、查找与选择流程以及让一个 Agent可被发现但不可运行的各类执行期约束。读完本文你将掌握如何编写自定义 Agent 文件、如何用角色别名做模型路由、如何理解多来源冲突时的覆盖顺序以及如何通过设置项限制子代理的递归深度、禁用名单与 spawn 策略。实现文件总览以下是 task 子系统发现与选择机制涉及的核心文件原文档的src/task/...相对路径已换算为仓库根目录视角职责文件Agent 发现文件系统 插件 内置合并packages/coding-agent/src/task/discovery.ts内置 Agent 定义与解析packages/coding-agent/src/task/agents.tsAgent 定义、进度与结果类型packages/coding-agent/src/task/types.tstask 工具对外入口与 schemapackages/coding-agent/src/task/index.ts结构化子代理输出 schema 校验packages/coding-agent/src/task/structured-subagent.tsspawn 策略解析packages/coding-agent/src/task/spawn-policy.ts工作流命令的并行发现设施packages/coding-agent/src/task/commands.ts通用任务 Agent 的提示词packages/coding-agent/src/prompts/agents/task.mdtask 工具面向模型的提示词packages/coding-agent/src/prompts/tools/task.mdfrontmatter 解析与 Agent 字段解析packages/coding-agent/src/discovery/helpers.tsOMP 扩展包根目录列举packages/coding-agent/src/discovery/omp-extension-roots.ts设置项定义与默认值packages/coding-agent/src/config/settings-schema.ts子代理启动执行prewalk/advisor/readSummarize 落地packages/coding-agent/src/task/executor.tsAgent 定义形态AgentDefinition所有任务 Agent无论来自内置还是磁盘最终都归一化为AgentDefinition结构定义在 packages/coding-agent/src/task/types.ts必填name、description、systemPromptsystemPrompt 即 Markdown 文件中 frontmatter 之后的正文可选tools、spawns、带优先级的model列表、thinkingLevel、output、blocking、autoloadSkills、readSummarize、prewalk、advisorsourcebundled | user | project其中扩展包 Agent 会按其扩展根的层级被标记为 project 或 user 级可选filePath记录定义来源文件便于定位与排障。frontmatter 解析规则解析入口是parseAgentFields()packages/coding-agent/src/discovery/helpers.ts要点如下缺少name或description直接判为无效返回null调用方视作解析失败并跳过该文件tools接受 CSV 或数组两种写法一旦提供了toolsyield会被自动追加子代理结果回传所必需同时normalizeToolNames会把工具名规范化spawns接受*、CSV 或数组三种写法向后兼容规则若spawns缺失但tools中显式包含task则spawns自动推断为*output作为不透明 schema 数据直接透传不做结构校验read-summarize: false归一化为readSummarize会让子代理的read工具返回文件原文而非结构化摘要——runSubprocess以read.summarize.enabled: false覆盖子代理隔离设置见 packages/coding-agent/src/task/executor.ts内置scout默认关闭该特性字段缺省时默认为开启model接受单个选择器、CSV 或数组角色别名展开后按顺序逐个尝试thinking-level/thinking选择该 Agent 配置的思考档位blocking: true使父会话在异步任务执行开启时仍同步等待该 Agent 完成autoloadSkills列出要从父会话注入到子代理首次提示词之前的技能未知名称会被静默忽略prewalk: true让子代理先在其解析出的模型上启动并在第一次编辑/写入时交接给默认 prewalk 目标即smol角色DEFAULT_PREWALK_TARGET定义于 packages/coding-agent/src/config/model-resolver.ts字符串值如prewalk: smol或prewalk: openai/gpt-5-mini则指定自定义交接目标。该行为与会话级--prewalk完全一致。task.agentPrewalk设置记录Agent 名 →on/off/ 模型 pattern可在/agents中心的 prewalk 条带中按 Agent 配置会覆盖 frontmatter。解析发生在runSubprocesspackages/coding-agent/src/task/executor.ts。交接目标不可用时跳过而不是让 spawn 失败仅当解析出的目标与起始选择在模型钳制后身份与思考模式/档位完全一致时才跳过交接同模型的 effort 降级仍算真实交接会在首次编辑/写入时执行切换advisor: true为该 Agent 派生的会话配对 advisor使用advisor角色解析出的模型字符串值如advisor: deepseek/deepseek-v4-flash或advisor: smol:high指定显式 advisor 模型 pattern可带可选:level后缀写入派生会话的modelRoles.advisor。task.agentAdvisor设置记录在/agents中心的 advisor 条带配置覆盖 frontmatter。解析同样发生在runSubprocess子代理默认无 advisor生效的 opt-in 会持久化在session_init中以便冷恢复时还原。思考档位与 effort 上限当设置项task.enableEffort默认false见 packages/coding-agent/src/config/settings-schema.ts开启后task 工具暴露每项任务的粗粒度effortlo/med/hi该提示在启动时优先于 Agent 自身配置生效。OMP 把该提示映射为所选模型支持的最低 / 中间 / 最高思考档位再钳制到task.maxEffort默认max见 settings-schema.ts以下。这一上限会跨重试回退的模型切换保持。若所选模型没有任何 ≤ 上限的受支持档位spawn 失败不支持可控思考档位的模型则回退到其正常选择器。角色别名驱动的自定义 AgentOMP 从~/.omp/agent/agents/*.md用户级和.omp/agents/*.md项目级发现用户 Agent。在 frontmatter 中给 Agent 一个角色别名就可以按名字派发它。对于模型路由任务派发只设置agent并不直接设置 worker 模型。例如用户级文件~/.omp/agent/agents/reviewer.md--- name: reviewer description: Review a change for correctness. model: review --- Review the assigned change and report concrete findings.然后在~/.omp/agent/config.yml中设置角色映射modelRoles: review: openai/gpt-5.4:highreview通过modelRoles.review解析。每个modelRoles.role值保存一个具体模型选择器并可附加:high之类的思考后缀解析逻辑见 packages/coding-agent/src/config/model-resolver.ts。修改该映射会影响后续任务解析而无需改动 Agent 定义。任务/eval 预检会先重载当前全局、项目与显式 overlay 设置再重新发现 Agent因此会话运行期间新增的 Agent 文件与其角色别名会从同一份刷新后的配置状态中解析。派发时设置 Agent 名与任务即可{ context: Review the current change in this repository., tasks: [ { agent: reviewer, task: Report concrete correctness findings. } ] }/model的 Roles 视图可以分配并持久化自定义角色映射如review、fast、good。仅修改当前活动或默认会话的选择不会重映射这些角色——角色与具体模型是解耦的这正是角色别名设计的目的。监视运行中的 Agent 与 vibe_spawn 分层路由派发之后按AltA打开 Agent Hub详见 docs/agent-hub.md。其活动名册展示每个任务 Agent 的状态、当前活动、模型、运行时长与用量选中某个 Agent 即可阅读其 transcript 并直接操控parked已停驻到磁盘的 Agent 可以从同一视图恢复。vibe_spawn 的分层路由vibe_spawn把 CLI 的fast映射到内置sonic、good映射到内置task见 packages/coding-agent/src/vibe/runtime.ts 中fast: sonic、good: task的映射以及task.agentModelOverrides的读取。两者都会先经过task.agentModelOverrides再回退到内置 Agent 自身的模型默认值见 packages/coding-agent/src/task/agents.ts 中sonic携带model: smol、task携带model: task的 frontmatter。推荐的分层路由做法把别名留在task.agentModelOverrides具体选择器只放在modelRolestask: agentModelOverrides: sonic: fast_worker task: good_worker modelRoles: fast_worker: openai/gpt-5-mini good_worker: openai/gpt-5.4:highvibe_spawn的 CLI 参数仍是fast或good此后只需更新modelRoles即可更换 worker 模型无需改动任何 Agent 定义。内置 Agent构建期嵌入内置 Agent 在构建期通过 Bun 的{ type: text }文本导入嵌入二进制见 packages/coding-agent/src/task/agents.ts 的EMBEDDED_AGENT_DEFSscout、reviewer、security-reviewer直接来自各自的提示词文件task与sonic共享task.md正文外加注入的 frontmatter其中task的 frontmatter 声明spawns: *、model: task与thinkingLevel: AUTO_THINKINGsonic声明model: smol与中等思考档位没有内置 Agent 设置prewalk——通用taskAgent 的交接由task.prewalk设置默认关闭见 settings-schema.ts或按 Agent 通过/agents、task.agentPrewalk、用户 Agent frontmatter 打开。加载路径如下loadBundledAgents()用parseAgent(..., bundled, fatal)解析嵌入的 Markdown结果缓存在内存中的bundledAgentsCacheclearBundledAgentsCache()是仅供测试的缓存重置。由于内置解析使用level: fatal畸形内置 frontmatter 会直接抛错甚至可能让整个发现流程失败——这与用户/项目文件使用的warn级别形成鲜明对比。通用taskAgent 的系统提示词可以在 packages/coding-agent/src/prompts/agents/task.md 看到它强调hyperfocus 于分配任务、绝不偏离、优先窄范围查找grep/glob、除非明确要求绝不创建文档。文件系统与插件发现discoverAgents(cwd, home)packages/coding-agent/src/task/discovery.ts按序合并 OMP 原生根目录、OMP 扩展包、Claude 市场插件根目录的 Agent最后追加内置定义。.claude/agents、.codex/agents、.gemini/agents等跨 harness 的直接根目录被有意跳过——它们的 frontmatter schema 不是 OMP 任务 Agent 契约。源码中用TASK_AGENT_CONFIG_SOURCE .omp常量过滤原生配置目录列表确保只认 OMP 自己的契约。发现输入与优先级高优先级在前最近的项目.omp/agents目录来自findAllNearestProjectConfigDirs(agents, cwd)只取第一个.omp命中用户.omp/agents目录来自getConfigDirs(agents, { project: false })同样只取第一个.omp命中每个已启用 OMP 扩展包的extension-root/agents由listOmpExtensionRoots(...)返回顺序为CLI--extension根目录项目extensions:设置用户extensions:设置已安装的 npm/link 插件Claude 市场插件根目录listClaudePluginRoots(home, cwd)中带agents/子目录者仅在isProviderEnabled(claude-plugins)时参与项目作用域插件排在用户作用域之前源码中按 scope 排序project 优先内置 AgentloadBundledAgents()。OMP 扩展包表面在omp-plugins能力提供方被禁用时整体关闭市场根目录不会混入listOmpExtensionRoots只走独立的、受claude-plugins开关门控的路径。项目级扩展目录记录会作为projectAgentsDir随发现结果一并返回供 TUI 与工具展示项目 Agent 放在哪。合并与冲突规则按名字先到先得发现采用按精确agent.name先到先得first-wins的去重一个Setstring追踪已见过的名字各目录加载的 Agent 按目录顺序摊平仅当名字未见时才保留内置 Agent 用同一个 Set 过滤仅当仍未见时才追加。由此推导出的覆盖语义项目.omp覆盖用户.omp更早的扩展根目录覆盖更晚的扩展根目录、Claude 市场插件与内置 Agent一切非内置 Agent 覆盖同名内置 Agent名字匹配区分大小写Task与task是两个不同 Agent同一目录内Markdown 文件按文件名字典序读取后再去重源码中sort((a, b) a.name.localeCompare(b.name))。无效/缺失 Agent 文件的行为按目录处理loadAgentsFromDir目录不可读或不存在视为空readdir(...).catch(() [])不报错文件读取或解析失败记录 warning 日志并跳过该文件解析路径使用parseAgent(..., level: warn)。frontmatter 失败行为来自parseFrontmatterwarn级别的解析错误记录 warning解析器回退到简单的key: value行解析器若必填字段仍缺失parseAgentFields失败抛出的AgentParsingError被调用方捕获文件被跳过。净效果一个坏的自定义 Agent 文件不会中断其他文件的发现。此外parseAgentFields还保留了main与sub两个哨兵名自定义 Agent 不得使用这两个名字因为它们分别对应顶级会话与未命名子代理会话的agentName混用会破坏规则作用域。Agent 查找与选择查找是精确名字的线性搜索getAgent(agents, name)即agents.find(a a.name name)见 packages/coding-agent/src/task/discovery.ts无限制会话中省略agent字段默认取taskDEFAULT_SPAWN_AGENT见 packages/coding-agent/src/task/spawn-policy.ts受限的父级spawns列表中省略agent字段默认取列表第一个 Agent。resolveEffectiveSubagentPolicy()被 task 与 eval 后端子代理启动共用。在分配 artifacts 之前它依次原子地重载当前会话持久化的全局、项目与显式 overlay 设置同时保留运行时覆盖从父 spawn 策略解析省略或显式的 Agent 名执行深度、自身递归阻断、父 spawn 策略守卫用discoverAgents(session.cwd)重新发现 Agent 并精确查找检查task.disabledAgents解析 plan-mode 限制、输出 schema、模型策略与隔离策略。名字缺失时预检失败错误形如Unknown agent .... Available: ...不会启动任何子进程。描述时发现 vs 执行时发现TaskTool.create()在构建面向模型的工具描述时会按解析后的工作目录对发现结果做 memoize但执行时会重新发现 Agent。因此若会话中途 Agent 或扩展文件发生了变化运行时的 Agent 集合可能不同于较早描述时的集合阻塞行为也是在策略解析之后才确定而不是依据描述时刻的陈旧 Agent 对象。模型与结构化输出优先级任务派发的模型优先级task.agentModelOverrides[agentName]默认空记录见 settings-schema.tsAgent frontmatter 中带优先级的model列表父会话当前活动模型再回退到其配置/默认模型。前两类来源中的角色别名都会通过modelRoles展开。共享的 eval bridge 还可在设置覆盖之前提供调用局部模型覆盖task 的 wire schema 不暴露该字段。运行时输出 schema 的优先级task 项的显式outputSchemaAgent frontmatter 的output父会话的outputSchema。task 项的可选schemaMode覆盖父会话模式默认为permissive宽容模式保留重试预算耗尽后的覆盖strict则把任何无效最终载荷包括耗尽的 retry 覆盖都变为schema_violation失败结果。面向模型的 task 提示词packages/coding-agent/src/prompts/tools/task.md会标注只读 Agent如scout并警告不要把推理工作卸载给scout/sonic同时指导模型只把只读研究任务派给 scout、为每个 item 选择最具体的 Agent、并避免把agent字段显式传给 spawn 策略默认值。命令发现的并行基础设施src/task/commands.ts是工作流命令而非 Agent 定义的并行基础设施但遵循同样的整体模式见 packages/coding-agent/src/task/commands.ts 中discoverCommands先从能力提供方发现按名字先到先得去重仍未见的内置命令追加在后通过getCommand精确名字查找。在 packages/coding-agent/src/task/index.ts 中命令 helper 与 Agent 发现 helper 一并被重新导出Agent 发现本身在运行时并不依赖命令发现。发现之外的可达性约束一个 Agent 可以被发现却仍可能因执行期守卫而无法运行。禁用 Agent 设置resolveEffectiveSubagentPolicy()在解析出 Agent 后检查task.disabledAgents默认[]。被禁用的名字在预检时失败并在有可用替代时列出启用项。父级 spawn 策略解析器检查session.getSessionSpawns()来自父 Agent 的spawnsfrontmatter解析逻辑见 packages/coding-agent/src/task/spawn-policy.ts*true、null或缺省也等价→ 允许任意省略agent默认task或false→ 全部拒绝CSV 列表 → 只允许列出的名字省略agent默认取第一个名字。被拒绝时错误形如Cannot spawn .... Allowed: ...。自身递归阻断的环境守卫PI_BLOCKED_AGENT或内部请求覆盖会在发现之前就拒绝再次 spawn 同一个被阻断的 Agent。递归深度门控task.maxRecursionDepth默认2见 settings-schema.ts负值关闭上限。共享策略在当前任务深度已达上限时拒绝 spawn对应地types.ts中的canSpawnAtDepth(maxRecursionDepth, taskDepth)实现为maxRecursionDepth 0 || taskDepth maxRecursionDepth见 packages/coding-agent/src/task/types.ts。当子代触达上限时runSubprocess还会把task从它的工具列表中移除并把其 spawn 策略置空见 packages/coding-agent/src/task/executor.ts 中spawnsEnv与工具列表的组装逻辑。对于受限的 Agent 工具列表runSubprocess在声明了spawns且深度允许时自动补加task同时除非会话显式限制工具名否则保留宿主的hub协作工具。Plan mode 行为父级 plan mode 开启时resolveEffectiveSubagentPolicy()在启动子进程前构造effectiveAgent前置拼接 plan-mode 子代理系统提示词工具限制为read、grep、glob、web_search若 Agent 自身工具列表声明了ast_grep则额外允许清空子代 spawnsplan 阶段不允许再派生子代清除prewalk只读探索不应收到 prewalk 的计划/实现提示。plan mode 同时拒绝按 spawn 的隔离isolated、apply 与 merge 控制。同一个effectiveAgent同时用于子进程启动、模型/思考覆盖与输出 schema 选择。小结一份可执行的调试清单当某个 Agent 表现该出现却找不到或能找到却跑不起来时可以按本文脉络逐层排查文件位置用户级放~/.omp/agent/agents/项目级放.omp/agents/确认文件名以.md结尾且位于第一个.omp命中目录frontmatter 契约name与description必填且不能是main/subtools/spawns/model支持 CSV 或数组spawns缺失但含task工具时会推断为*冲突覆盖项目 用户 扩展根 市场插件 内置且同名精确匹配、区分大小写执行守卫依次检查task.disabledAgents、父spawns策略、PI_BLOCKED_AGENT、task.maxRecursionDepth与 plan mode 限制模型路由task.agentModelOverrides→ Agent frontmattermodel→ 父会话模型角色别名统一经modelRoles展开。这套定义 → 发现 → 合并 → 解析 → 守卫的完整链路正是 oh-my-pi 得以在 IDE 内稳定编排多 Agent 工作流的地基。【免费下载链接】oh-my-pi⌥ Coding agent with the IDE wired in项目地址: https://gitcode.com/GitHub_Trending/oh/oh-my-pi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考