15 KiB
description, kind
| description | kind |
|---|---|
| 面向工具作者与维护者的工具注册表与执行流水线说明,用于注册、限制、呈现或调试面向模型的工具。 | package-reference |
@deepseek-ai/dsh-tools
English | 中文
概述
使用 dsh-tools,工具插件注册 schema 与执行器,每次模型工具调用都经过一条受守卫的流水线——允许/拒绝/询问策略、单调守卫、环绕分发包装层、结果检查、由工具定义持有的内容终结,以及最终的仅观测通知。该包还控制工具向模型呈现的方式:mode 配置选择原生 Function Calling(函数调用)、Code Mode 或两者,单个 agent 可用 presentAs 为自己遮蔽该默认值。工具作者使用 defineTool 定义类型化参数与输出 schema、可选的协作式超时、并行安全分类与可选的 UI 呈现意图。把任何希望模型触达的能力做成注册表时请选择本包——schema 会自动流入提示词组装。
目录
使用本包
在任何 agent 调用工具的地方挂载 dsh-tools:它提供 ctx.tools,即每个工具插件注册进去、循环分发所经过的注册表。注册一个工具就足以让它可见——注册表会自动把其 schema 送入系统提示词组装。
注册工具
defineTool 构建类型化工具定义:面向模型的名称、描述与参数 schema、规范输出声明,以及只返回所声明 JSON 值的 execute 主体。模型参数在执行前被校验;无效输入变成普通错误结果。
import { readFile } from 'node:fs/promises'
import type { Context } from '@deepseek-ai/cordis'
import { defineTool } from '@deepseek-ai/dsh-tools'
declare const ctx: Context
ctx.tools.register(defineTool({
name: 'read_file',
description: 'Read a file from disk.',
parameters: {
path: { type: 'string', required: true, description: 'Absolute file path' },
offset: { type: 'number' },
limit: { type: 'number' },
},
output: {
schema: { type: 'string' },
render: (_args, value) => [{ type: 'text', text: value }],
},
async execute(args, exec) {
// args is typed: { path: string; offset?: number; limit?: number }
return readFile(args.path, { encoding: 'utf8', signal: exec.signal })
},
}))
统一 schema DSL 支持 string、number、integer、boolean、null、array、object、仅供作者使用的 json 与恰好匹配一个分支的 oneOf;InferValue 在 16 层容器内保留精确类型,之后加宽为 JsonValue。原始 JSON Schema(JsonSchemaNode)是与 subagent、工作流和 MCP 共享的协议级对应类型。
配置呈现模式
mode 配置决定模型看到什么:native(每个可见 schema)、code(只有 run_code 加一份生成 SDK)或 both。
- name: '@deepseek-ai/dsh-tools'
config:
mode: native
| 字段 | 默认值 | 含义 |
|---|---|---|
mode |
native |
可见工具向模型呈现的方式:native、code 或 both |
maxParallelSubCalls |
10 |
run_code 程序重叠子调用的并发上限;1 恢复严格串行分发 |
生成的配置目录是每个受支持字段的穷尽式真源。非原生模式要求已组合的 ctx.codeRuntime 且其语言有已注册的 SDK 渲染器;agent preset 通过 dsh-agent-tool-presentation 自行选择呈现方式,单个 agent 可用 presentAs(mode) 遮蔽默认值。
按 agent 限制工具
ctx.tools.restrict(filter) 对单个 agent 继承的全局工具应用允许或拒绝掩码;掩码取交集,作用域注册保持可见,限制在 dispose(资源释放)时解除。ctx.tools.get(name, scope) 按一个作用域的视角解析工具。需要匹配实际执行 definition 的 Host 本地 presenter 消费方会传入发起调用的 agent。ctx.tools.schemas(scope) 返回可见 schema(不含 execute 函数)。
对调用实施策略
ctx.tools.guard(guard) 在可扩展的 tools/pre-execute waterfall(瀑布式事件)之后注册单调同步守卫:返回的理由会拒绝调用,后续监听器无法把该拒绝重新变为允许。流水线事件给插件更多控制——tools/pre-execute 决定允许/拒绝/询问,tools/execute 为超时或重试包装分发,tools/post-execute 检查或替换结果,tools/result 观测冻结的最终结果。
Host 展示描述
工具可以为 Host 本地消费方保留纯函数 presentCall() 与 presentResult() 方法。内置 Web Client 不消费这些值,而是通过 tool.call.toolview 选择 renderer,并从原始调用参数、结果内容、失败状态与持久 metadata 派生 card props。Client 派生展示决策负责该 transport 拆分。
理解实现
实现细节——点击展开
本节解释该包如何实现上述行为;可观察约定已在使用本包中完整说明。
设计理念
注册表在作用域层中持有类型化 ToolDefinition,并在请求时把它们投影为面向模型的 ToolSchema 集合——output、execute、finalizeContent、timeoutMs 与呈现回调绝不会泄漏到协议上。每次调用都运行一条固定流水线:tools/pre-execute(可扩展的允许/拒绝/询问)→ 已注册单调守卫 → tools/execute(环绕分发包装层)→ tools/post-execute(检查/替换、附加上下文)→ 由定义持有的 finalizeContent → 仅观测的 tools/result 事件。只有 tools/execute 视图可以替换必填信号,注册表会在调用主体前重新融合调用方信号。
源码地图
| 文件 | 职责 |
|---|---|
src/index.ts |
插件入口:ToolRuntime 服务、配置、注册表、执行流水线 |
src/types.ts |
ToolDefinition、ToolExecution、ToolExecutionResult、守卫与决策类型 |
src/schema.ts |
defineTool DSL:ValueSchemaSpec、ParameterSchemaSpec、InferValue、InferArgs |
src/json-schema.ts |
强制执行的原始 JSON Schema 子集与校验 |
src/presentation.ts |
带 card 标签的 UI 呈现意图 |
src/code-mode.ts |
Code Mode:SDK 生成、run_code 分发桥接层、结算 |
src/ts-types.ts |
TypeScript SDK 类型渲染 |
src/py-types.ts |
Python SDK 类型渲染 |
src/invariant.ts |
不变式配套 |
执行与取消
每次类型化调用都会实体化并冻结解析后的参数、分配不透明关联 token,再运行策略与分发。取消采用协作式并等待完全停稳:每个工具主体都收到调用方拥有的 exec.signal 且必须观测它;调用主体前的取消为 ABORTED_BEFORE_DISPATCH,调用主体后的取消只能把成功结果替换为 ABORTED。拒绝、包装层失败、工具失败、后置策略失败与超时产生的 TOOL_TIMEOUT 仍保留更具体的结果。未知工具与抛出异常的工具都会变成结构化错误(UNKNOWN_TOOL),因此调用会失败而不会结束轮次。
Code Mode
在 code 或 both 下,注册表公开保留的 run_code 传输以及按所加载运行时语言生成的确定性 SDK。每个 SDK 绑定调用都会在日志中与外层调用关联,重新进入完整工具流水线,并通过复用原生并发约定的每次运行独有池调度。在纯 code 下,模型直呼其他任何可见工具都会在策略之前解析为 UNKNOWN_TOOL——通告面与可调用面保持一致。中间绑定值只存在于执行局部;只有外层 run_code 结果有硬大小上限。执行器塌缩 note 拥有该收束约定。
扩展点
工具插件调用 ctx.tools.register(),其 schema 会自动流入提示词组装。tools/pre-execute 是可重排的允许/拒绝/询问门禁;ctx.tools.guard() 在其后添加单调的拥有方策略;tools/execute 为超时、重试或指标包装规范化后的规范分发;tools/post-execute 可以替换内容或值、通过反馈阻止,或附加有序上下文;tools/result 观测不可变的最终结果。MCP 服务器发现工具后,用服务器的 schema 调用 ctx.tools.register()。
进一步探索
包级约定对大多数消费方已经足够;需要周边领域时再阅读以下页面。
- 工具子系统——完整流水线类型、schema DSL 与生成的服务 API。
- 生成工具目录——模型收到的已交付工具 schema。
- 工具执行流水线——可视化流水线。
- 添加工具实操手册——分步骤的工具编写指南。
- 协作式取消 Agent Note——完整取消约定。
- core 分组地图——core 各包如何组合。
模型体验
普通工具 schema
模型看到什么
在普通模式下,模型会看到每个可见定义的确切名称、描述与 JSON Schema;已交付定义记录在生成的工具目录中。agent 作用域的限制、遮蔽与扩展注册会改变该 agent 的最终工具集合。
Token 影响
每次请求的固定成本与可见定义成正比。隐藏工具的限制会为该 agent 移除其全部 schema 成本。
KV Cache 影响
只要可见定义及其顺序不变,前缀就保持稳定。注册、dispose 或作用域限制可能从第一个改变的 schema token 起使复用失效。
Code Mode schema 与系统提示词
模型看到什么
Code Mode 会公开生成的 run_code schema、下方 SDK 说明,以及按所加载运行时语言生成的精确 SDK 块。tools:sdk 段使用 first-party 顺序 5000。both 会同时公开普通 schema 与此 Code Mode API;在 code 下,提示词还会带上处于更早 first-party 顺序的 tools:code-only 规则,让模型先读到「可以调用哪些工具」再读「每个工具做什么」。
Code Mode SDK 说明
## Writing code for run_code
`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
- Independent read-only calls MAY overlap under `Promise.all` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with `await`.
- Emit results with `return` and/or `console.log(...)`. Only what you print or return is program output. A successful tool result containing an image is attached after the run so you can inspect it on the next step; every other intermediate result stays out of the conversation, so extract just what you need.
The available tools:
Token 影响
每次请求的固定成本与可见定义成正比。Code Mode 使用生成的 SDK 文本加一个传输 schema 取代最终工具 schema,但不承诺普遍减少成本。
KV Cache 影响
只要 Code Mode 选择、生成的 SDK、传输 schema 与可见工具集合不变,前缀就保持稳定。模式或筛选器变更可能从第一个改变的提示词或 schema token 起使复用失效。
工具调用历史与结果
模型看到什么
循环会保留模型发出的参数与注册表的最终内容。任何抛出异常或遭到拒绝的调用,都会转换为确切的 Error: <message>。Code Mode 只返回外层程序打印的行与呈现后的返回值;两者都为空时返回 (run_code completed with no output);失败时返回 Error: code run failed (<kind>): <message>,并根据是否存在已捕获内容,在其后附加 Captured output: 与捕获的行。内部分发事件只保留在日志中;成功且含图片的子结果会在外层结果之后作为带来源归属的上下文追加。
Token 影响
参数、结果与附加上下文取决于数据,并会重复发送直至压缩(compaction)。隐藏工具的限制还会在模型可以调用这些工具之前移除其 schema。
KV Cache 影响
仅追加;新的可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
已知限制与延期工作
这些限制说明注册表何时需要特别留意。它们是当前包约束,不是任务积压。
- 并发策略不是事件门禁:
executionMode()直接读取已解析的工具定义;插件只能在自身拥有的定义上声明分类器。 tools/pre-execute有意不允许改写exec.arguments:否则日志记录与呈现的参数会与实际运行内容失去同步;改写设计记录在拟议的 Agent Note中。- 调用方定义的 subagent 与工作流结构化输出仍要求对象根:这是消费方层面的守卫;共享 schema 词汇与工具输出支持任意 JSON 根。
- 定义中的
timeoutMs仅作声明之用:注册表绝不会强制执行截止时间;要强制执行,必须使用@deepseek-ai/dsh-tool-call-timeout-policy包装层。 - Code Mode 的 SDK 语言由当前加载的运行时决定,且呈现方式按 agent 而非按工具:
mode: code/both会拒绝组装提示词,除非ctx.codeRuntime.language有已注册的 SDK 渲染器;同一个 agent 内不能让一个工具仅使用 Native,而另一个仅使用 Code。 - Code Mode 中间值只存在于执行局部,且没有字节上限:它们无法从会话回放重建,并可能耗尽进程或 worker 内存;只有外层
run_code输出受 worker 可配置的硬上限约束。 - 每次运行都会获得全新的
run_code状态:MVP 不采用持久 REPL 风格内核,因为跨调用状态不会出现在日志中。
开发备注
维护者的工作上下文——点击展开
无。