
OmO / senpi-task 的 Agent 感知解析与持久化从 resolveAgent 到任务记录回读的完整实现拆解【免费下载链接】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-openagentOmO仓库中senpi-task包的 Agent 解析链路以.omo/evidence/omo-senpi-adapter/20260719-curated-agents/task-4.md的验证记录为骨架深入resolveAgent的模型解析优先级、内置回退链、工具规则过滤、persona 组装以及解析结果经parseTaskRecord持久化回读的完整闭环。读完本文你将掌握 Agent 定义如何被解析成可执行的任务记录、resolved_model.source: agent在解析与持久化两侧的校验方式以及如何用测试与变异验证守住这条链路。一、Task 4 验证了什么一条从解析到回读的闭环2026-07-19 的 curated-agents 任务分九个子任务落地。Task 4agent-aware resolution and persistence验证的是整个 Agent 解析与持久化链路的核心覆盖以下行为面resolveAgent的回退解析fallback resolution直接模型优先级direct model precedence即model字段优先于models列表有序模型备选ordered model alternatives即models[]数组的先后顺序即尝试顺序禁用与未知 Agentdisabled and unknown agents的报错形态注册表不可用unavailable registries时的降级返回显式模型 persona 解析explicit-model persona resolution即配置了modelOverride时直接携带 persona 返回工具规则过滤tool-rule filtering即tools/disallowedTools派生 allowlist 与 denylistresolved_model.source: agent这一来源标记在解析产物中的正确落位。同时验证了持久化侧一个全新的RecordStore实例能够通过parseTaskRecord从磁盘重新读取 agent 来源的任务记录未知目标渲染unknown-target rendering会同时携带活跃的 Agent 名册与类别名册curated 名称会被 team-member 校验拒绝。从源码结构看这一任务还完成了职责抽取注册表解析被抽到独立的 agent-model-registry.ts使 resolve-agent.ts 保持在 176 行的克制体量——解析逻辑与注册表解析逻辑从此各司其职。二、resolveAgent解析入口与三种返回形态resolveAgent定义在 resolve-agent.ts签名接收四个参数请求的 Agent 名、Agent 定义表、模型注册表端口可为空、以及可选的ResolveAgentOptions含modelOverride与omoConfig。解析结果是一个可判别联合discriminated unionResolvedAgentResult解析成功携带agent、model形如provider/modelId、persona 字段、运行时模型链requested_model/fallback_models/resolved_model与availableAgents名册AgentNotFoundResultAgent 不存在或disable: true返回not_found与活跃名册AgentModelUnavailableResult注册表缺失或没有任何候选模型可用返回model_unavailable、attemptedModel与活跃名册。三种形态都附带availableAgents按名称排序的未禁用 Agent 列表这正是 Task 4 所验证的未知目标渲染同时携带活跃名册的产物来源——渲染层拿到not_found结果时可以直接展示当前可用的 Agent 名单。解析主流程的优先级resolve-agent.ts 的执行顺序值得逐一拆解名册过滤先过滤disable true的定义得到活跃 Agent 排序名册目标定义缺失或被禁用则直接返回not_foundmodelOverride 短路若调用方显式传入modelOverride直接返回resolved模型即该覆盖值并携带完整 persona这就是显式模型 persona 解析这为上层调用提供了一条绕过整个注册表解析的快速通道注册表缺失降级registry undefined时无法做任何解析此时尽力推算一个attemptedModel依次尝试definition.model、models[0]、类别默认模型、内置回退链头返回model_unavailable直接候选解析由 agent-model-entry.ts 的agentModelCandidates将model与有序的models[]合并为候选序列model永远排在最前这正是直接模型优先级的实现基础逐个经findExactAgentModel精确查找并要求命中结果同时出现在可用模型集中类别解析若定义带categories走 resolve-agent-categories.ts 的resolveAgentCategoryModel第一个能解析成功的类别即提供模型内置回退链若以上都未命中且可用模型集可解析调用delegate-core的resolveModelForDelegateTask在AGENT_FALLBACK_CHAINS上做回退选择。注意 Task 4 明确记录了一个边界No category lookup occurs insideresolveAgent——类别解析由第 5 步单独调用完成resolveAgent自身不内嵌类别查找planner 兼容性属于 Task 7 的范畴。从代码看确实如此类别解析被隔离在独立的resolveAgentCategoryModel函数中保持单一职责。三、注册表解析抽取agent-model-registry.tsTask 4 的关键重构是注册表解析抽取。文件 agent-model-registry.ts 承担三类职责findExactAgentModel把候选字符串如openai/gpt-5.6-luna-fast按provider/modelId拆分再与注册表find结果比对。拆分要求/存在且首尾均非空注册表对象必须同时提供字符串型的自有数据属性provider与id且与期望值一致才返回。parseAvailableAgentModels把registry.getAvailable()的数组规整为provider/modelId排序列表非数组返回undefined。resolveAgent中这一解析结果被用作凭据门——注释明确说明注册表的find从完整目录作答即使本机没有该模型的凭据也能命中因此每个候选都必须同时出现在凭据过滤后的可用集里否则子进程会在第一次调用时失败。把models[]与内置回退链的候选都门禁在可用集上才能让回退真正接管。安全性设计parseRegistryModel会拒绝任何带有密钥类字段名的模型对象——SECRET_LIKE_MODEL_FIELD_NAMES集合覆盖accesstoken、apikey、auth、authorization、bearertoken、clientsecret、password、privatekey、privatetoken、secret、secretkey、token等名称匹配时先剔除所有非字母数字字符再小写归一。这一边界镜像自category/resolver.ts的注册表解析保证 Agent 解析与类别解析遵循相同的安全约束避免模型对象中的敏感字段被当作合法模型数据泄入任务记录。// agent-model-registry.ts 的核心形态略去注释后的骨架 export function findExactAgentModel(candidate, registry) { const expected parseModel(candidate) // provider/modelId 拆分 return expected undefined ? undefined : parseRegistryModel(registry.find(expected.provider, expected.modelId), expected) } export function parseAvailableAgentModels(models) { if (!Array.isArray(models)) return undefined return models .map((model) parseRegistryModel(model)) .filter((model) model ! undefined) .map((model) ${model.provider}/${model.modelId}) .sort() }四、内置回退链与工具规则过滤内置回退链builtin/fallback-chains.ts 中的AGENT_FALLBACK_CHAINS为 curated Agent 提供手抄镜像的回退链。链以 Agent 名为键当前包含explore8 级、librarian8 级、plan-consultant3 级、plan-reviewer6 级。每个 rung 声明一组有序 provider 与模型可带variant例如 explore 链头是openai-codex/gpt-5.6-luna-fast (variant: low)随后依次是 deepseek、qwen、minimax、claude、nano 等备选。两个值得注意的 senpi-only 差异源码注释明确记载每个claude-*rung 都由claude-sdk-oauth打头——senpi 的 Claude 订阅通道优先级高于计量制的opencode通道任何 rung 都不列出openai计量 API-key 通道只保留openai-codex。而 ulw 评审类 Agent 刻意不在此表中——它们通过定义上的categories字段解析模型这正好呼应了 Task 4 中类别查找不属于 resolveAgent的边界划分。回退链的防漂移手段是独立字面量表测试见 fallback-chains.test.ts测试文件显式禁止导入oh-my-opencode/model-core对每个链的 provider 列表、模型、variant、数组位置做逐字转录断言。Task 1 的变异验证证明仅改链长无法检测到的条目漂移会被字面量表测试抓出。工具规则过滤agent-tool-policy.ts 的agentToolPolicy是persona、计划、任务记录与内核工具授权读取同一派生结果的唯一事实源。规则是只有字面模式不含空格、不含*才算工具面规则glob 或带空格命令规则属于按次调用的权限规则。派生逻辑为toolAllowlist 字面规则中allow: true的模式列表toolRuleDenylist 字面规则中allow: false的模式列表toolDenylistdisallowedTools与toolRuleDenylist的并集。纯拒绝式定义会得到空 allowlist——这是最严格的形态且绝不能解读为无策略。Task 4 的测试矩阵中包含 tool-rule filtering 用例如 resolve-agent.test.ts 验证disallowedTools以toolDenylist随 persona 传递、未配置时不得强制注入 denylist。persona 组装agentPersona随后把agentType、prompt作为instructions、工具策略、executionMode仅接受in-process/process、allowedSubagents、maxDepth合并进结果——这正是 Task 2/3 所验证的 curated 只读 bash 替代机制赖以生效的通道。五、持久化回读parseTaskRecord 与 source: agent解析结果不仅要被运行时消费还要落盘。Task 4 验证了一个关键场景全新的RecordStore实例通过parseTaskRecord从磁盘重读 agent 来源的记录。record-parse.ts 的parseTaskRecord从 JSON 记录中读取status、updated_at、agent_type、tool_allow、tool_deny、resolved_model等字段并强制team_role若存在则必须为member——这正是 Task 4 中curated 名称被 team-member 校验拒绝的落点之一解析层直接拒绝非法团队角色且解析失败即抛错而非静默降级。resolved_model的解析在 record-blocks-parse.ts 的readResolvedModel中完成其中readResolvedModelSource只接受三个合法来源值switch (source) { case category: case explicit: case agent: return source default: throw new Error(resolved_model.source must be ${RESOLVED_MODEL_SOURCES.join( or )}) }agent是 Agent 解析路径独有的来源标记。在解析侧resolve-agent.ts 的resolvedAgent助手构造resolved_model时固定写入source: agent并携带provider、model_id、displayprovider/modelId以及可选的variant/reasoning_effort/reasoning三元组reasoning取reasoningEffort ?? variant。变异验证是最有说服力的证据Task 4 明确记录临时把记录解析器中的case agent分支删掉fresh-store 的磁盘回读往返测试立即失败恢复后整套测试重新变绿。这证明source: agent不是装饰性字段——持久化回读真正依赖它来正确重建 Agent 来源的模型记录。该边界同时被parseOptionalResolvedModel/parseOptionalResolvedModelArray对应requested_model/fallback_models复用解析出的运行时模型链得以无损还原。六、测试证据与验证纪律Task 4 的验证结果记录在案聚焦运行resolve-agent.test.ts得到7 通过 / 0 失败完整包门禁覆盖了 record-store、task execution 与 member-validator 用例变异验证case agent删除 → 回读往返失败恢复 → 全绿。从当前仓库看resolve-agent.test.ts 的测试矩阵与 Task 4 的描述一一对应disallowedTools随 persona 传递、直接模型优先级model胜于models、禁用 Agent 被隐藏为not_found、未知 Agent 返回排序名册、注册表无匹配时返回model_unavailable而不抛异常等。测试中catalogRegistry特意复刻了线上 senpi 注册表形态——find从完整目录作答、getAvailable只返回本机有凭据的模型——使凭据门行为得到真实形态的覆盖。这些测试跨越了 Task 4 主张的六个消费边界模型model、persona、工具策略tool-policy、持久化persistence、错误上报error-reporting、团队资格team-eligibility这正是为什么足够的判据。七、边界与后续任务Task 4 明确声明了两个省略项resolveAgent内部不进行类别查找planner 兼容性保留给 Task 7同时从 Task 1–3 的边界可见运行时安装激活、只读 bash 替代等由 Task 9 的 live child 与 Task 2/3 的在进程装配测试分别兜底。理解这条边界才能在阅读 resolve-agent.ts 时把直接解析与类别路由两条模型通道正确分开。附阅读路径速览解析入口与三种返回形态resolve-agent.ts注册表解析抽取与密钥字段防护agent-model-registry.ts候选模型合并与调优默认值agent-model-entry.ts内置回退链与防漂移字面量表fallback-chains.ts、fallback-chains.test.ts工具规则单一事实源agent-tool-policy.ts持久化解析与source枚举校验record-parse.ts、record-blocks-parse.ts聚焦测试矩阵resolve-agent.test.ts验证记录原文task-4.md【免费下载链接】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),仅供参考