DeepSeek Harness 禁用插件后新建会话报 Unknown agent preset 怎么修

故障排查发布于 2026-10-20作者: DeepSeek Plugin 插件市场
DeepSeek HarnessDSHagent presetinjectCordis插件加载pending
DeepSeek Harness 禁用某插件后 preset 行永久 pending、新建会话报 Unknown agent preset;根因是 loader inject 没有可选依赖语义,给出三种修复路径。

「我只是禁用了一个不常用的插件,DSH 还能启动,但所有新会话都建不出来。」 这是 DeepSeek Harness(DSH)里很典型的一类连锁:被禁用的插件提供某个服务,preset 行又把这个服务写进了 inject,而 inject 在 Cordis 里是硬依赖——服务没了,preset 行不报错,只是永久 pending。宿主启动不依赖 preset,所以看起来一切正常;新建会话要解析 preset,才把问题暴露出来。

DeepSeek Harness 症状组合:能启动、不能新建会话

一句话结论:同时看到「preset 行 pending」「插件列表无报错」「新建会话报 Unknown agent preset」这三件事,就可以按本文处理。 单独出现任意一条,都可能是别的原因。

  • 插件列表里有一行或几行显示 pending (waiting for service: xxx)。
  • 宿主正常启动,旧会话甚至还能打开。
  • 新建会话时报 agent-preset/not-found: Unknown agent preset: standard。
  • 重新启用被禁用的插件后,症状立刻消失。

据讨论里的复现,vendor/cordis/src/registry.ts:71-88 的 Inject 归一化没有 required/optional 之分,写进 inject 的键一律当硬依赖;app-boot/src/index.ts:323/331 的 requiredIds 默认是空数组,:399-405 又先判 requiredIds 再排除 pending,所以最后只剩一条 warning(#10099)。preset 的常规配置可以对照 agent preset。

为什么 pending 不报错、却能让 DSH 新会话失败

一句话结论:Cordis 的 pending 是「等依赖」,不是「失败」;宿主启动不经过 preset 解析,新建会话才经过,所以故障被推迟到使用时才出现。

把链路拆开:

  • 插件 A 被禁用,它提供的服务 S 不存在。
  • preset 行的 inject 里有 S,于是该行不启动,停在 pending。
  • 宿主启动只加载基础 bundle,不要求 preset 行就绪,启动成功。
  • 新建会话要选一个 preset,发现 standard 未注册,报 agent-preset/not-found。

这也是为什么很多人以为是「会话数据坏了」,其实只是 preset 没起来。

DeepSeek Harness 的三种修复路径

一句话结论:马上要开会话就重新启用提供方,确实想禁用就 patch 掉 inject,长期维护就改 loader 语义。

修法一:重新启用提供服务的插件

这是最快恢复,但等于放弃禁用;适合你只是临时关掉、并不介意它继续运行的情况。

  1. 打开插件列表,找到处于 pending 的那一行,记下它等待的服务名;预期能看到一个具体服务名。
  2. 在列表里搜索提供该服务的插件,确认它当前是 disabled;预期能唯一对应到一个提供方。
  3. 重新启用该插件,等待状态变为 active;预期 pending 行随之启动。
  4. 新建一个会话;预期不再报 Unknown agent preset。
  5. 如果该插件本身启动失败,先修它,再谈禁用;预期提供方健康后两个症状一起消失。

修法二:把 preset 行的 inject 置空或改成可选

这是「既要禁用插件、又要能新建会话」的折中,适合 preset 并不真正依赖该服务的情况。 用 home 层 patch 覆盖,不动插件本体。

  1. 打开 ~/.dsh/profiles/<profile>/cordis.patch.yml;预期进入 profile 层而不是插件源码。
  2. 找到 preset 行对应的 id,确认它当前的 inject 列表;预期能看清每个硬依赖。
  3. 加一条同名 patch,把 inject 设为 null(顶层整替换,不是深度合并);预期整个键被替换。
  4. 重启 DSH;预期该行不再 pending。
  5. 新建会话验证;预期 preset 能解析,同时留意少了哪些工具。

这条修法会一并去掉该行所有注入依赖,包括它真正需要的服务,只适合 preset 行本身很薄的情况;patch 是整块替换,漏写其他字段可能把整行配置清空,改前要备份;后续插件升级改了行 id 时,patch 会失效。

修法三:改 loader,支持可选 inject 与超时降级

根治方向是让 inject 能表达 required/optional,并在依赖缺失时降级而不是永久 pending。 适合维护 fork 或提交上游。

  1. 在 vendor/cordis/src/registry.ts 的 Inject 归一化处,支持 { required: [...], optional: [...] } 形式;预期两类依赖可区分。
  2. 对 optional 依赖,不阻塞启动;读取时用 get() 并在缺失时返回 undefined;预期该行仍能启动。
  3. 在 app-boot/src/index.ts:399-405 的 pending 判定里,把「仅 optional 未就绪」的行视为可用;预期它变为 active。
  4. 给 pending 行补一条带服务名的 warning,而不是完全静默;预期日志能看出降级原因。
  5. 补测试:禁用提供方后,preset 行仍能启动并给出降级结果;预期测试稳定通过。

DSH 插件状态恢复后的验证与避坑

一句话结论:重启后看一次 pending 列表、建一个会话、再做一次禁用/启用往复,才能确认状态不是暂时正常。 验证步骤:

  1. 重启后看插件列表,确认目标行不再是 pending;预期状态为 active 或已按预期移除。
  2. 新建会话,发送一条会触发工具调用的消息;预期 preset 能解析、工具能执行。
  3. 打开旧会话;预期没有因为 patch 改动丢失原有工具。
  4. 再做一次「禁用 → 启用」往复;预期状态能正确切换,而不是残留 pending。

避坑要点:

  • 不要把 pending 当成无害:它意味着某个能力没有加载,长期会以「功能莫名消失」的形式出现。
  • requiredIds 默认为空是当前实现的特点,不要依赖启动失败来发现问题;需要自己监控 pending 列表。
  • patch 的优先级按文件顺序,后写的覆盖前写的;排查时先确认没有第二个 patch 把 inject 写回去。
  • 讨论里没有官方修复版本,0.2.1-rc.2 仍可复现;升级后以 release notes 为准,别把一个 DSH插件 的旧版 pending 当成新版行为。

DeepSeek Harness agent preset 常见问题

Q:DeepSeek Harness 禁用插件后新建会话报 Unknown agent preset,怎么恢复? A:DeepSeek Harness 报 Unknown agent preset,是因为 preset 行把被禁用插件提供的服务写进了 inject,而 inject 在 Cordis 里是硬依赖,服务缺失时该行停在 pending 而不报错。启动不需要 preset,所以 DSH 能起来;新建会话必须解析 preset,于是报未知预设。重新启用该插件,或把 preset 行的 inject 置空。

Q:DeepSeek Harness 插件列表 pending waiting for service,日志没报错,为什么? A:DeepSeek Harness 的 pending 表示插件的 inject 依赖尚未就绪,常见于被依赖的服务被禁用、版本不匹配或依赖行启动失败。与 failed 不同,pending 不阻塞宿主启动,所以最容易被忽略;看它依赖的服务名,再核对提供方。

Q:DeepSeek Harness 里 inject 和可选依赖有什么区别,为什么不能混写? A:DeepSeek Harness 的 inject 声明的是硬依赖,Cordis 会等它可用才启动本行;可选依赖应当用 get() 读取或声明为可选服务。把可选工具写进 inject,会在工具被禁用时让整行 pending,表现为「插件没坏但功能消失」。

Q:改 profile 的 inject: null 后 DeepSeek Harness 重启仍 pending,怎么办? A:DeepSeek Harness 重启仍 pending,先确认 patch 是整块替换而不是深度合并,inject: null 必须落在正确的行 id 上。再检查是否有第二个 patch 写回了 inject,patch 按顺序覆盖;最后清一次 profile 构建缓存再启动。

常见问题

DeepSeek Harness 禁用插件后新建会话报 Unknown agent preset,怎么恢复?

DeepSeek Harness 报 Unknown agent preset,是因为 preset 行把被禁用插件提供的服务写进了 inject,而 inject 在 Cordis 里是硬依赖,服务缺失时该行停在 pending 而不报错。启动不需要 preset,所以 DSH 能起来;新建会话必须解析 preset,于是报未知预设。重新启用该插件,或把 preset 行的 inject 置空。

DeepSeek Harness 插件列表 pending waiting for service,日志没报错,为什么?

DeepSeek Harness 的 pending 表示插件的 inject 依赖尚未就绪,常见于被依赖的服务被禁用、版本不匹配或依赖行启动失败。与 failed 不同,pending 不阻塞宿主启动,所以最容易被忽略;看它依赖的服务名,再核对提供方。

DeepSeek Harness 里 inject 和可选依赖有什么区别,为什么不能混写?

DeepSeek Harness 的 inject 声明的是硬依赖,Cordis 会等它可用才启动本行;可选依赖应当用 get() 读取或声明为可选服务。把可选工具写进 inject,会在工具被禁用时让整行 pending,表现为「插件没坏但功能消失」。

改 profile 的 inject: null 后 DeepSeek Harness 重启仍 pending,怎么办?

DeepSeek Harness 重启仍 pending,先确认 patch 是整块替换而不是深度合并,inject: null 必须落在正确的行 id 上。再检查是否有第二个 patch 写回了 inject,patch 按顺序覆盖;最后清一次 profile 构建缓存再启动。

相关术语

inject
inject 是 Cordis 插件声明依赖服务的方式,写进 inject 的服务名是硬依赖,未就绪时插件停在 pending 而不是报错。它适合必需服务,不适合可选能力。— https://github.com/deepseek-ai/deepseek-harness/discussions/10099
agent preset
agent preset 是 DeepSeek Harness 里一组预置的 agent 配置,包含模型、工具与 persona 等。新建会话时必须能解析出一个 preset,解析失败会报 agent-preset/not-found。— https://github.com/deepseek-ai/deepseek-harness/discussions/10099
pending
pending 是 Cordis 插件的等待状态,表示 inject 依赖尚未满足。与 failed 不同,pending 不阻塞宿主启动,因此经常表现为「服务能开、功能不可用」。— https://github.com/deepseek-ai/deepseek-harness/discussions/10099

来源