DeepSeek Harness 取消传播设计:让 AbortSignal 穿越工具能力接缝(capability seam)
发布时间:2026/9/20 19:01:49 锦皓数字建站
`)
DeepSeek Harness 取消传播设计让 AbortSignal 穿越工具能力接缝capability seam【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness本篇设计指南以 DeepSeek Harness 仓库中的架构提案《Required cancellation through tool-reachable capability seams》为核心阐述一项尚处于proposed提案状态的设计在工具注册表已强制exec.signal的前提下如何进一步把取消能力以编译期强制的方式贯穿到工具体内所有可触达的异步能力接口杜绝跨层丢弃取消信号导致的悬空副作用。读者将理解问题产生的根源传递性缺口、精确的作用域边界、迁移策略、被否决的替代方案、验收标准与风险清单并能在自己的插件或能力实现中遵循同样的借用即传播、丢弃即编译失败的接口纪律。背景注册表边界的协作式取消已落地DeepSeek Harness 的一切皆插件架构中工具注册表ToolRuntime位于 packages/core/tools/src/index.ts负责工具的注册、策略流水线pre/around/post/result与派发。此前已实现并落地的架构决策《Cooperative tool cancellation at the registry boundary》见 .agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md确立了以下事实ToolExecutionInput.signal是必填的只读AbortSignal见 packages/core/tools/src/types.tsToolExecution.signal与ToolRunContext.signal随之成为必填只读字段defineTool()对exec.signal进行上下文类型推导所有注册的 TypeScript 工具无需强制类型转换即可观察或转发取消信号围绕派发的包装器around-dispatch wrapper拿到的是可变但必填的ToolDispatchExecution见 packages/core/tools/src/types.ts可以替换信号用于叠加 deadline但不能删除或置为undefined注册表导出TOOL_ABORTED与TOOL_ABORTED_BEFORE_DISPATCH两个取消码用于区分工具体已被调用、副作用可能已发生与调用从未进入工具体见 packages/core/tools/src/types.ts注册表信任这一类型化同进程契约不做运行时AbortSignal校验——运行时校验只保留在 parser/config、模型/工具 JSON、持久化/文件、worker、进程与 wire 等真正的非类型化边界。这套已实现契约的核心测试位于 packages/core/tools/tests/execution-signal-types.spec.ts用ts-expect-error断言缺少 signal 的ToolExecutionInput编译失败只读视图不可写around 视图可替换但不可删除/置空并用expectTypeOf钉死exec.signal的精确类型。行为层面的覆盖预中止短路、阶段跳过、调用者信号融合、静默排干等则在 packages/core/tools/tests/tools.spec.ts。问题工具体内的信号在下一个同进程调用处被悄悄丢弃注册表边界的强制只解决了工具体收到信号却没有解决工具体把信号传下去。提案指出的缺口具有传递性文件系统工具可能会调用路径解析与 I/OWeb 工具可能会调用某个 providerBash 工具可能会调用某个执行器复合工具composite tool可能会启动或等待任务task、子代理subagent或工作流workflow。这些从工具体内触达的异步能力接口当前许多仍接受可选的signal。于是出现一个尴尬的局面一个工具可以满足自己的类型签名因为exec.signal必填却在紧接着的同进程调用中把取消信号丢掉。TypeScript 无法证明拥有副作用的那条边界上取消仍然可用。提案明确指出不能简单粗暴地要求仓库里每一个异步函数都带signal有些操作不可从工具触达例如注册表内部的同步查询有些同步查询根本不等待、也不拥有进行中的工作显式分离detached的工作在完成所有权交接后已属于新的生命周期所有者不应继续绑定父调用者信号。因此需要一条精确的边界而不是一刀切。提案在工具可触达的异步能力接缝上强制要求 AbortSignal提案的核心主张对每一个从工具体可触达、且工具仍拥有或等待该操作的异步同进程能力操作要求提供一个AbortSignal。它可以按所属接缝seam的既有形态作为位置参数或必填的只读请求字段但遗漏必须导致 TypeScript 编译失败。配套约束包括每个直接调用者提供自己拥有的信号或从其自身的必填操作上下文中传播信号实现可以派生 child deadline 或取消作用域但派生信号在委托生命周期内必须保持与上游信号关联能力实现不得合成永不中止的信号、使用环境性的 async-local 取消也不得仅为重复类型化同进程契约而在运行时校验AbortSignal。这一约束的本质是把取消可用性从运行时习惯提升为编译期接口契约signal缺失即编译失败类型系统替你枚举出每一个遗漏传播的调用点。作用域边界哪些算范围内纳入范围in-scope的包括所有权转移前的启动操作、前台执行、读写、provider 请求、等待waits以及工具等待的清理/释放cleanup or disposal。排除范围out-of-scope的包括同步的注册表查找、可用性检查、schema 渲染、参数分类等不可能承载异步工作的操作显式分离所有权交接之后的工作——任务、工作流、worker 或子代理成功发布给新生命周期所有者后由该所有者的控制器管理分离生命周期但发起分离的启动操作在被交接提交handoff commits之前仍必须接收调用者信号之后任何等待已分离工作的工具调用也必须有自己本次调用的信号。此外当外部协议本身允许省略时parser、config、模型/工具 JSON、持久化/文件格式、worker、进程或 wire 输入可选的取消可以保留但所属边界在调用迁移后的能力接缝之前必须先把该输入解析为必填的同进程信号。仓库现状印证能力接缝的可选 signal 普遍存在提案指出的缺口并非假设而是当前仓库中大量存在的事实。以文件系统能力为例packages/fs/fs/src/index.ts 中Fs抽象类的多个核心操作目前都接受可选信号resolve(path, opts?)opts内signal?第 113-116 行附近stat(target, signal?)、lstat(path, opts?, signal?)第 165、181 行附近readText(target, signal?)、streamText(target, signal?)、listDir(target, signal?)第 189、200、221 行附近readBytes(target, signal: AbortSignal | undefined, maxBytes)第 212 行附近——注意此处的undefined联合类型。Shell 侧同样存在packages/shell/shell/src/types.ts中signal?: AbortSignal | undefined第 52、96 行附近packages/shell/bash-local/src/index.ts第 179 行附近与packages/shell/pwsh-local/src/index.ts第 225 行附近的底层执行器也把信号声明为可含undefined。对照之下仓库中已经有部分接缝提前执行了必填纪律packages/shell/tool-bash-persistent/src/index.ts第 50 行附近与packages/shell/tool-pwsh-persistent/src/index.ts第 53 行附近的会话获取接口get(owner, signal: AbortSignal)已经是必填信号。这恰好构成提案迁移目标形态的局部先例工具拥有的能力边界取消必须是必填的。从源码结构看这正是提案要消除的落差工具注册层已必填与底层能力层仍可选之间存在一整段工具体发起 → 能力调用的中间地带取消信号在其中是可静默丢失的。迁移策略先清单再按能力族成组迁移提案给出了明确的落地步骤而不是一次性大爆炸式改动建立清单inventory从每一个第一方ToolDefinition.execute()出发遍历它 await 的每一个能力调用登记工具体在所有权交接前可达的异步能力操作。成组迁移每次把一整个连贯的 Service Definition / Service Provider / Consumer 接缝一起改动连同其测试与生成的 API 文档。按能力族分批文件系统、shell/task、web/provider、workflow/subagent、code-runtime 等各自独立 PR保证每次改动可评审。不留兼容性后门在仓库的 pre-release 政策下迁移后的接口不保留可选兼容重载。一个值得注意的执行细节是把 typecheck 失败当作完整的调用者清单。必填参数一旦引入所有遗漏传播的调用点会同时暴露为编译错误这与提案风险部分大范围传递影响的处理方式互为表里——编译错误既是代价也是迁移的导航地图。被否决的替代方案为什么必须是类型契约提案系统性地比较了六种替代路线并逐一给出否决理由这组权衡本身对设计同类接口极具参考价值替代方案否决理由下游信号保持可选反正工具体已收到一个外层回调里有信号不等于传播是类型安全的每一个可选能力调用点仍合法地省略用 lint 规则或回调检查强制传播语法检查无法可靠识别所有权、派生信号、抽象层与正确的静默quiescent收敛把ToolRunContext传遍每个能力能力需要的是取消不是工具身份/代理状态/上下文延迟传大对象会把可复用服务耦合到工具注册表模糊窄接缝使用环境性的 async-local 信号隐式传播使所有权与分离交接难以审计、复杂化测试并可能让调用静默绑定到错误生命周期在能力实现里加默认或永不中止的信号默认值抹掉了缺少所有者这一事实而不是在编译期暴露它在本提案对应的已实现注册表改动里一次性迁移所有能力传递性接口变更跨越独立能力族分离提案可保留已落地的注册表决策让每条深层接缝带着聚焦的测试各自迁移核心结论可概括为一句话可用性availability是类型契约行为observation/forwarding仍是工具与能力的责任。类型系统能保证信号在边界上存在但无法保证实现真的观察并转发它——后者仍需集成测试在进程、worker、socket、provider 与任务边界上验证。验收标准如何证明迁移成功提案列出了七条可操作的验收标准可作为实现该设计时的检查清单清单映射了每个第一方工具体在所有权交接前可达的异步能力操作每个范围内能力接口都要求AbortSignal且编译期契约测试证明省略会失败接口、实现、直接消费者、测试助手、示例与生成的 API 引用一起迁移无兼容重载、无生产环境永不中止哨兵派生 deadline 与包装作用域保持与调用者信号关联集成测试证明取消能到达副作用所有者、被等待的工作能收敛到静默quiescence同步查询与显式分离的交接后工作保持在范围外歧义处的所有权转换有文档与测试运行时校验只加在真正的非类型化边界而非重复必填的 TypeScript 字段/参数每次连贯迁移后顶层 typecheck、覆盖率、快照、文档、模块图、构建、卫生、demo 与构建产物门禁全部通过。其中第 2、3 条可直接借鉴已落地的注册表契约测试模式在 packages/core/tools/tests/execution-signal-types.spec.ts 中ts-expect-error注解本身就是编译失败是预期行为的自动化断言。第 4 条强调行为验证不可被类型检查替代——这与仓库防御模式文档 docs/defensive-patterns.md 中Dispose must reach quiescence, not just request it清理必须等到工作真正收敛而非仅仅发出请求的既有规则一脉相承。风险清单大爆炸半径之外的五个陷阱提案坦诚地列出了五类主要风险对任何执行此类接口强化的团队都有普适警示意义大范围传递影响transitive blast radius一个必填参数可能同时暴露大量直接调用者。对策是按连贯能力族迁移并把 typecheck 失败当作完整调用者清单。分离工作分类错误过早排除启动操作会在发布被提交前就分离工作反过来永远要求父信号又可能让一个已完成的工具取消本该合法分离的工作。每个交接点都需要明确的提交点、新所有者、回滚行为与静默失败路径。信号所有权混淆能力如果存储了超出委托生命周期的借用信号就会把工作绑定到过期的调用者。接口与测试必须区分借用的操作信号与长生命周期服务拥有的控制器。机械合规但不协作mechanical compliance without cooperation必填参数只能证明可用不能证明被观察与转发。进程、worker、socket、provider 与任务边界的集成测试仍然必要。过度扩大同步或无关 API 的范围在不存在异步工作的地方要求取消只会增加噪声并稀释契约的信号强度。清单必须记录每个操作为何工具可触达且承载生命周期然后才改动它。与已实现注册表契约的关系需要明确的是本篇介绍的提案是独立于已落地的注册表取消契约的后续步骤。已实现决策在 .agents/notes/implemented/architecture/2026-07-19-cooperative-tool-cancellation.md 的Consequences一节明确写到下游能力接口保持不变直到关联的 proposed Agent Note 被接受并实现。也就是说当前仓库的注册表层ToolExecutionInput.signal必填已经生效而能力层fs、shell、web、workflow 等接缝的signal?仍等待本提案落地。这也解释了为何在现状下工具体内调用Fs.readText(target)不带 signal依然能编译通过——这正是提案要关闭的缺口。小结把借用即传播变成编译期纪律DeepSeek Harness 对取消的处理呈现出清晰的分层演进先让注册表边界上的信号必填已实现再让工具可触达的每个异步能力接缝上的信号必填本提案。后一步的价值在于把取消信号被丢弃这一运行时隐患转化为编译期错误同时用精确的作用域边界排除同步查询、分离后的工作、外部协议可选的边界避免过度设计。对插件与能力开发者而言这条设计的实践含义很直接只要你的异步操作会在某个工具体的生命周期内被等待就把AbortSignal设为必填参数并转发上游信号如果你的操作属于同步查询或已交接的分离工作才允许不接收信号。在此基础上再配合边界集成测试证明取消真实到达副作用所有者并等待被等待的工作收敛到静默——这正是 docs/defensive-patterns.md 中 quiescence 规则在接口层面的落地。【免费下载链接】deepseek-harnessDeepSeek Harness: Everything is a Plugin.项目地址: https://gitcode.com/gh_mirrors/de/deepseek-harness创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。