尧图精选

DeepSeek Harness 事件面精简实践:移除无消费方的 skill 提供方事件(skill/provider-added / skill/provider-removed)

🕒 发布时间:2026/9/19 13:14:03 📁 来源:尧图网络
DeepSeek Harness 事件面精简实践移除无消费方的 skill 提供方事件skill/provider-added / skill/provider-removed【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness本指南以 DeepSeek Harness 仓库内已归档的 Agent Note.agents/notes/archived/simplification/2026-07-12-drop-unconsumed-skill-provider-events.zh.md为骨架完整还原这次面向无消费方事件的 API 精简决策从问题识别、决策内容、备选方案到后果影响。通过对照 skill 注册表源码、事件生产者/消费方矩阵 与 注册表测试你将掌握 skill 提供方注册、按需查找、缓存失效的完整运行契约理解skill/provider-added/skill/provider-removed为何被移除、subagent/provider-added与skills/change为何保留并学会在插件设计中判断何时该引入新事件、何时该保持按需拉取。背景skill 注册表与提供方模型DeepSeek Harness 的 skill技能能力由 packages/skill/skill 包承载其核心是SkillRegistry服务ctx.skills职责在 模块注释 中说得非常清楚具体提供方如deepseek-ai/dsh-skill-filesystem决定技能来自哪里该服务只负责合并提供方 catalog、为同名技能解析胜出者并向消费方暴露胜出的摘要与定义。从源码结构看整个体系围绕三类参与者展开提供方SkillProvider实现list()与get()两个方法 的同一进程插件。list()返回候选技能数组或{ candidates, complete }观察结果get()依据候选中的不透明locator加载完整技能正文。list()内部可以执行远程初始化、鉴权与发现且应响应options.signal的取消。运行时注册register()ctx.skills.register()接受一个SkillRegistration直接把技能定义注入调用方 scope 对应的 layer默认提供方标签为保留名runtime。消费方通过list()/snapshot()按需读取摘要目录或通过get()按名加载技能正文tool-skill等工具在操作边界处自行应用 model/user 调用策略。注册表是分层的SkillLayer使用ScopedLayers管理宿主行与仓库插件落在全局层由 agent preset 组合挂载的插件落在各自 preset 层读取时以全局层叠加查看 scope 的链同名技能就近者胜出rank只在同一层内决定优先级见 SkillRegistry 类注释。这一结构与 tools 注册表建立的模式一致。问题两个没有生产环境监听方的通知事件原 Agent Note 描述的问题很直接skill 注册表产出两个通知事件但没有生产环境的监听方。生成的生产者/消费方矩阵以及对事件名的精确搜索表明skill/provider-added与skill/provider-removed仅出现在声明、emit 站点、测试、生成的 catalog 和行文中。在仓库当前状态中精确搜索provider-added与provider-removed结果只命中 subagent 相关路径如 packages/subagent/tool-subagent/src/index.ts、packages/subagent/subagent/src/lifecycle.ts 等与文档行文skill 目录内已不存在这两个事件名——这与已移除的归档状态一致。关键论证是事件的存在价值在于有消费方。skill 发现是按需拉取模型提供方注册时同步清除已完成的 catalog 缓存源码中对应 invalidateCache()revision 1、清空collectCache随后发出唯一的宽泛失效通知skills/changecollect()中在await之后进行版本检查若revision ! this.revision说明发现期间发生了并发变更结果不会进入缓存collect() 实现至多重试MAX_COLLECT_ATTEMPTS 2次后返回cacheable: false的非权威结果消费方自行决定是否保留最后的可用状态。因此兄弟插件根本不需要监听提供方加入/移除来获知技能变化——下一次list()/get()调用天然会读取当前提供方映射并重新收集。与之形成对照的是活跃的subagent/provider-added消费方packages/subagent/tool-subagent/src/index.ts 通过ctx.on(subagent/provider-added, ...)在提供方加入时立即断言其配置并在运行时上下文里同时订阅subagent/provider-added/subagent/provider-removed第 573-576 行——它容忍兄弟并发加载是真实存在的生命周期消费方这也是 subagent 事件得以保留的原因。边界本提案不触碰的事件Agent Note 明确列出了范围外项仓库现状也与此一致tools/change与system-prompt/change既有简化决策将它们保留为面向实时工具与提示词 UI 的有意观测点且自引用的已挂载插件已在使用tools/change例如 tool-subagent 在组合 agent 时订阅tools/change。移除它们会破坏实时 UI 刷新链路。subagent/provider-added/subagent/provider-removed因为有tool-subagent这样的生产环境生命周期消费方属于有真实需求的通知。决策注册表不再声明和 emit 提供方成员变更事件决策本身干净利落可拆成两个层面行为层面skill 注册表不再声明与 emitskill/provider-added、skill/provider-removed。提供方的注册与 dispose 仍是effect 所有的直接状态变更——从源码看registerProvider() 通过this.layers.effect(...)在 layer 中插入/移除提供方并同步失效 catalogdispose 时registration undefined、undo()移除条目、lifecycle.abort()中止该注册的AbortController。查找与发现按需读取当前提供方映射表一切照旧。文档/目录层面生成式事件目录、API 目录与生产者/消费方矩阵不再包含已删除通知skill system Agent Note 与包文档改为通过由 effect 直接拥有的状态与 cache 失效契约来描述注册。值得注意的反面证据skill 注册表仍保留了一个事件skills/change它是未过滤的失效通知声明注释强调监听方失败会被隔离不能否决注册表变更。notifyChange() 的实现逐条 try/catch 并void Promise.resolve(...).catch(...)兜底正说明它只是尽力而为的提示刷新工作不应依赖它——这与按需拉取为主、推送仅为失效信号的整体设计一致。在 docs/event-producer-consumer.md 的生产者/消费方矩阵 中skills/change由skill包 emit当前没有矩阵内消费方同样是信号型而非契约型事件。事件目录也印证了移除结果矩阵中不再存在skill/provider-added、skill/provider-removed两行而agent/pre-step、fs/observed、skills/change等其他事件行保持完整。曾考虑的替代方案为未来插件保留通知Agent Note 记录了唯一的替代方案——为未来插件保留 skill 提供方通知第三方插件可能想观察提供方的可用性但直接提供方注册与按需查找才是扩展契约当前没有消费方需要推送信号。这个论证值得展开事件面的维护成本声明、目录、矩阵、测试是实打实的而未来可能有人用只是假设收益。仓库当前的扩展契约是两条明确的贡献路径ctx.skills.register()直接运行时注册与registerProvider()提供方注册外加skills/change这个失效信号。如果将来真的出现兄弟加载竞态正确的做法是像 subagent 注册表那样引入一个带有消费方实际所需的身份与就绪语义的专用通知——即按需补事件而不是预先铺事件。这也正是本提案与为将来留接口式设计的分水岭以实际消费方为准绳而不是以潜在需求为准绳。后果与测试验证Agent Note 列出的后果包括生成的事件矩阵中不再有skill/provider-added或skill/provider-removed的行skill 发现、直接运行时注册、提供方 effect 回滚/dispose、缓存失效与注册表查找清理全部保持不变监听方触发的回滚随事件一起消失tools/change、system-prompt/change以及已被消费的 subagent 提供方生命周期事件不受影响预发布消费方失去 skill 提供方观测点但仍保留两种贡献 skill 的方式直接运行时注册与提供方注册。测试侧的策略也随之改变通过提供方查找和收集到的输出来观察清理行为而非依赖生命周期通知。这在 packages/skill/skill/tests/skill.spec.ts 中有充分体现第 61 行起 的用例注册多个提供方、验证同名冲突的 first-wins 语义并通过disposeMemory()释放提供方后断言注册表清理行为第 713-725 行 验证registerProvider返回的 disposer 调用后提供方从查找结果中消失——即清理通过查找输出可观察而不是通过某个provider-removed事件回调。配套的 packages/skill/skill/src/invariant.ts 中还有一个有意思的佐证该包的不变量伴生插件没有注册任何运行时不变量注释给出的原因正是提供方/运行时映射与修订版缓存在注册表内部原子变更而注册表不再暴露独立变更事件或快照用于交叉校验——事件移除后连用不变量交叉校验事件面的前提都不存在了。经验总结什么时候该移除一个事件从这次精简中可以提炼出可复用的判断框架用数据说话对事件名做精确搜索并检查生成的生产者/消费方矩阵如 docs/event-producer-consumer.md。如果命中点只有声明、emit 站点、测试与行文而没有生产消费方该事件就值得质疑。确认消费路径是否为拉取式若数据读取本身是每次调用读取当前映射 版本检查防陈旧 同步失效缓存如SkillRegistry.collect()的模式推送通知往往冗余。区分契约事件与信号事件有真实消费方的事件是契约如subagent/provider-added之于tool-subagent纯失效提示是信号如skills/change可以保留但绝不能把刷新逻辑挂在它上面。移除后重新锚定测试把清理行为可观察迁移到查找结果与收集输出上而不是依赖生命周期回调。为未来留出正确的门如果未来出现真正需要推送语义的消费方按其实际所需的身份与就绪语义新增专用通知而不是恢复通用事件。结合 DeepSeek Harness 当前的 packages/skill 目录skill、skill-badge、skill-filesystem、tool-skill四个包与skills/change信号事件这次精简的最终形态是注册表只暴露按需拉取的读写契约与一个尽力而为的失效信号把所有通知语义留给确实存在消费方的事件——这正是事件驱动架构中少即是多的一次教科书式落地。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →