mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
The background-task change repeated its lifecycle design across implemented RFCs, package READMEs, JSDoc, test commentary, and model-visible schemas. That repetition obscured the contracts that maintainers must preserve and added avoidable prompt tokens. Rewrite the implemented RFCs around the current design, keep authorization, exact-owner cleanup, wait/abort ordering, producer quiescence, and teardown-failure guarantees at their owning surfaces, and remove peer surveys, review history, control-flow narration, and emphatic restatement. Shorten the task and subagent schema wording, synchronize the bilingual tool cookbook, and regenerate the config, service, RFC, tool, and replay snapshot derivatives. Runtime behavior is unchanged; test edits update prose-only assertions and descriptions.
639 lines
31 KiB
Markdown
639 lines
31 KiB
Markdown
<!-- Generated by scripts/gen-tool-catalog.ts — do not edit by hand.
|
|
Run `pnpm run gen-tool-catalog` to regenerate. -->
|
|
|
|
# Tool Schema Catalog
|
|
|
|
Every model-facing tool a shipped plugin contributes to `ctx.tools`: the `name`, `description`, and JSON-Schema `parameters` the model receives via the system-prompt assembly. It complements the cordis [events](cordis-catalog/events.md) & [services](cordis-catalog/services.md) catalogs (the wiring a plugin listens to and calls) and [core-data-structures/](core-data-structures/core.md) (the types those signatures move) — this page is the *tools* the agent is offered.
|
|
|
|
This file is GENERATED and verified fresh by `pnpm run verify-tool-catalog` (part of `doc-sync`) — do not edit it by hand. Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each tool plugin on a real context and reads `ctx.tools.schemas()`, because a tool schema is not statically knowable (runtime-spread enums, concatenated descriptions, config-driven names, raw-JSON-Schema MCP tools). A completeness guard globs `packages/*/tool-*` and fails if any package is missing from the generator's boot manifest, so a new tool cannot be silently undocumented. See [the tool-schema-catalog RFC](rfc/implemented/process/2026-07-02-tool-schema-catalog.md).
|
|
|
|
Scope: shipped product tools under `packages/*/tool-*`, each booted with its DEFAULT config. The registered tool NAME can be a load-time config (e.g. `tool-subagent`'s `toolName`), so a deployment may surface a package under a different or additional name — a per-package note records those shipped aliases where they exist. The `examples/` demo tools (e.g. `echo`) are excluded, matching the cordis catalog's packages-only scope.
|
|
|
|
## Tool Package Map
|
|
|
|
This table connects model-visible tool names to the plugin package and service seams behind them. Exact JSON Schemas follow in the package sections below.
|
|
|
|
| Tool package | Model-visible names | Requires | Writes / affects | Shipped aliases | Deployment note |
|
|
| --- | --- | --- | --- | --- | --- |
|
|
| `@deepseek-ai/dsh-tool-ask-user` | `ask_user_question` | `ctx.tools`, `ctx.userInteraction` | `tool/call`, `tool/result after a UI/provider answers the question` | - | ask_user_question pauses the tool call until the active UI provider returns a human answer. |
|
|
| `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`, `ctx.codeRuntime (execution time)`, `ctx.systemPrompt` | `tool/call`, `one tool/code-dispatch per bridged sub-call`, `tool/result` | - | Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode RFC). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated TypeScript SDK section, and a program calls them through serialized bindings that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
|
|
| `@deepseek-ai/dsh-tool-bash` | `bash` | `ctx.tools`, `ctx.bash`, `ctx.tasks at call time for run_in_background` | `tool/call`, `tool/result` | - | The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.tasks` runtime and is collected/stopped through the `task_*` tools from `@deepseek-ai/dsh-tool-tasks`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled. |
|
|
| `@deepseek-ai/dsh-tool-cordis` | `cordis_inspect`, `cordis_mount`, `cordis_unmount` | `ctx.tools` | `tool/call`, `tool/result`, `live plugin-tree mutations (mount/unmount)` | - | Ships in examples/cordis-agent only (a deliberate opt-in — mounted code gets the real ctx, see docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). Plugins the model mounts may register ADDITIONAL model-visible tools at runtime; the request-header ToolsDelta logs those tool-set changes. |
|
|
| `@deepseek-ai/dsh-tool-fs` | `edit`, `read`, `write` | `ctx.tools`, `ctx.fs`, `ctx.systemPrompt` | `tool/call`, `fs/write-intent or fs/edit-intent for mutations`, `fs/observed after successful file operations`, `tool/result` | - | The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin. |
|
|
| `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.tools`, `ctx.skills` | `tool/call`, `tool/result` | - | - |
|
|
| `@deepseek-ai/dsh-tool-subagent` | `subagent` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `examples/coding-agent/cordis.yml` and `examples/acp-agent/cordis.yml`. |
|
|
| `@deepseek-ai/dsh-tool-tasks` | `task_kill`, `task_list`, `task_output` | `ctx.tools`, `ctx.tasks`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `context/message via agent.inject() for background completion notices` | - | The kind-agnostic background-task control surface: a background bash command and a background subagent are read, listed, and killed through the same three tools. Loading the plugin attaches the control surface that arms producers' `ctx.tasks.start()`. |
|
|
| `@deepseek-ai/dsh-tool-todo` | `todo_write` | `ctx.tools`, `owning Agent session` | `tool/call`, `todo/write`, `tool/result` | - | todo_write is session-owned state; UIs render the latest todo/write event as a checklist or ACP plan. |
|
|
| `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`, `ctx.workflows`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents the script children)` | `tool/call`, `tool/result` | - | - |
|
|
| `@deepseek-ai/dsh-tool-web` | `web_fetch`, `web_search` | `ctx.tools`, `ctx.web`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. |
|
|
|
|
## `@deepseek-ai/dsh-tool-ask-user`
|
|
|
|
### `ask_user_question`
|
|
|
|
Ask the user a concise question when you need confirmation, a choice, or missing information before proceeding. Send one or more questions, each with a stable id that will be echoed in the answer.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"questions": {
|
|
"type": "array",
|
|
"description": "Questions to ask the user before continuing.",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"description": "Stable id for this question; echoed in the answer."
|
|
},
|
|
"question": {
|
|
"type": "string",
|
|
"description": "The specific question to ask the user."
|
|
},
|
|
"header": {
|
|
"type": "string",
|
|
"description": "Optional short heading for the question, such as \"Confirm\" or \"Choose Mode\"."
|
|
},
|
|
"options": {
|
|
"type": "array",
|
|
"description": "Optional choices to show the user. If you recommend one, put it first and append \"(Recommended)\" to that label.",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"label": {
|
|
"type": "string",
|
|
"description": "Short user-facing option label."
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"description": "One sentence explaining the tradeoff or impact."
|
|
}
|
|
},
|
|
"required": [
|
|
"label"
|
|
]
|
|
}
|
|
},
|
|
"multi_select": {
|
|
"type": "boolean",
|
|
"description": "Whether the user may select more than one option. Defaults to false."
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"question"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"questions"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/ui/tool-ask-user/src/index.ts`](../packages/ui/tool-ask-user/src/index.ts)
|
|
|
|
ask_user_question pauses the tool call until the active UI provider returns a human answer.
|
|
|
|
## `@deepseek-ai/dsh-tools`
|
|
|
|
### `run_code`
|
|
|
|
Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"code": {
|
|
"type": "string",
|
|
"description": "The program: the body of an async TypeScript function."
|
|
}
|
|
},
|
|
"required": [
|
|
"code"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/core/tools/src/code-mode.ts`](../packages/core/tools/src/code-mode.ts)
|
|
|
|
Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode RFC). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated TypeScript SDK section, and a program calls them through serialized bindings that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
|
|
|
|
## `@deepseek-ai/dsh-tool-bash`
|
|
|
|
### `bash`
|
|
|
|
Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"command": {
|
|
"type": "string",
|
|
"description": "The bash command to execute."
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"description": "Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: \"ls\" → \"List files in current directory\"; \"git status\" → \"Show working tree status\"; \"npm install\" → \"Install package dependencies\"."
|
|
},
|
|
"timeoutMs": {
|
|
"type": "number",
|
|
"description": "Timeout in milliseconds. The executor applies its configured default and cap, and kills the command on expiry."
|
|
},
|
|
"workdir": {
|
|
"type": "string",
|
|
"description": "Working directory for this command. Defaults to the session workspace; a relative path is resolved against it."
|
|
},
|
|
"run_in_background": {
|
|
"type": "boolean",
|
|
"description": "Run in the background and return a task id immediately (collect with task_output, stop with task_kill). No timeout applies."
|
|
}
|
|
},
|
|
"required": [
|
|
"command",
|
|
"description"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/bash/tool-bash/src/index.ts`](../packages/bash/tool-bash/src/index.ts)
|
|
|
|
The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.tasks` runtime and is collected/stopped through the `task_*` tools from `@deepseek-ai/dsh-tool-tasks`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled.
|
|
|
|
## `@deepseek-ai/dsh-tool-cordis`
|
|
|
|
### `cordis_inspect`
|
|
|
|
Inspect the live cordis runtime that is running THIS agent. Read-only. Sections: `services` (every provided ctx service and the plugin fiber that owns it), `plugins` (a flat list of the loaded plugins with their lifecycle states), `tools` (the model-facing tools currently registered, i.e. what you can call), `dynamic` (plugins you mounted via cordis_mount: id, name, state, provided services, awaited services), `api` (method signatures AND argument/return type shapes for every LIVE service — read this before writing plugin code that calls a service), `events` (every harness event with its dispatch mode and exact signature — pick listener targets here). Omit `what` to get all six sections.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"what": {
|
|
"type": "string",
|
|
"description": "Limit the report to one section. Omit for all sections.",
|
|
"enum": [
|
|
"services",
|
|
"plugins",
|
|
"tools",
|
|
"dynamic",
|
|
"api",
|
|
"events"
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cordis/src/index.ts)
|
|
|
|
### `cordis_mount`
|
|
|
|
Mount a NEW cordis plugin into the live runtime that is running THIS agent (self-modification). `code` runs as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, async execute(args) { … } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'boolean'|'object'|'array', required?: true, description?, enum?, items?, properties? }; a JSON-Schema-style { type: 'object', properties, required: […] } wrapper and type 'integer' are also accepted and normalized. A tool's `execute` MUST return an ARRAY of content blocks, e.g. `return [{ type: 'text', text: someString }]` — never a bare string. Mounts can COMPOSE: one plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically on unmount. Sandbox globals: `console` (tagged `[cordis:<id>]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned on unmount) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"code": {
|
|
"type": "string",
|
|
"description": "Body of an async JS function; must `return` the plugin to mount."
|
|
}
|
|
},
|
|
"required": [
|
|
"code"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cordis/src/index.ts)
|
|
|
|
### `cordis_unmount`
|
|
|
|
Dispose a plugin previously mounted with cordis_mount, by id. All its registrations (event listeners, tools, services) are cleaned up through the cordis effect lifecycle. Returns only after disposal has fully completed (quiescence, not just a request to stop).
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"description": "The dynamic mount id returned by cordis_mount (e.g. \"dyn-1\")."
|
|
}
|
|
},
|
|
"required": [
|
|
"id"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cordis/src/index.ts)
|
|
|
|
Ships in examples/cordis-agent only (a deliberate opt-in — mounted code gets the real ctx, see docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). Plugins the model mounts may register ADDITIONAL model-visible tools at runtime; the request-header ToolsDelta logs those tool-set changes.
|
|
|
|
## `@deepseek-ai/dsh-tool-fs`
|
|
|
|
### `edit`
|
|
|
|
Edit an existing UTF-8 text file by replacing literal text.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"file_path": {
|
|
"type": "string",
|
|
"description": "Path to edit, resolved by the filesystem backend."
|
|
},
|
|
"old_string": {
|
|
"type": "string",
|
|
"description": "Literal text to replace. Must match exactly."
|
|
},
|
|
"new_string": {
|
|
"type": "string",
|
|
"description": "Literal replacement text. Use an empty string to delete the match."
|
|
},
|
|
"replace_all": {
|
|
"type": "boolean",
|
|
"description": "Replace all matches. Defaults to false; when false, old_string must appear exactly once."
|
|
}
|
|
},
|
|
"required": [
|
|
"file_path",
|
|
"old_string",
|
|
"new_string"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/fs/tool-fs/src/index.ts`](../packages/fs/tool-fs/src/index.ts)
|
|
|
|
### `read`
|
|
|
|
Read a UTF-8 text file and return line-numbered content.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"file_path": {
|
|
"type": "string",
|
|
"description": "Path to read, resolved by the filesystem backend."
|
|
},
|
|
"offset": {
|
|
"type": "number",
|
|
"description": "1-based first line to return. Defaults to 1."
|
|
},
|
|
"limit": {
|
|
"type": "number",
|
|
"description": "Maximum number of lines to return. Defaults to 2000."
|
|
}
|
|
},
|
|
"required": [
|
|
"file_path"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/fs/tool-fs/src/index.ts`](../packages/fs/tool-fs/src/index.ts)
|
|
|
|
### `write`
|
|
|
|
Create or fully replace a UTF-8 text file.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"file_path": {
|
|
"type": "string",
|
|
"description": "Path to write, resolved by the filesystem backend."
|
|
},
|
|
"content": {
|
|
"type": "string",
|
|
"description": "Full UTF-8 text content to write."
|
|
}
|
|
},
|
|
"required": [
|
|
"file_path",
|
|
"content"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/fs/tool-fs/src/index.ts`](../packages/fs/tool-fs/src/index.ts)
|
|
|
|
The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin.
|
|
|
|
## `@deepseek-ai/dsh-tool-skill`
|
|
|
|
### `skill`
|
|
|
|
Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"description": "The exact skill name from the available skills list."
|
|
}
|
|
},
|
|
"required": [
|
|
"name"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/skill/tool-skill/src/index.ts`](../packages/skill/tool-skill/src/index.ts)
|
|
|
|
## `@deepseek-ai/dsh-tool-subagent`
|
|
|
|
### `subagent`
|
|
|
|
Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"description": {
|
|
"type": "string",
|
|
"description": "A short (3-5 word) description of the delegated task, for display."
|
|
},
|
|
"prompt": {
|
|
"type": "string",
|
|
"description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
|
|
},
|
|
"run_in_background": {
|
|
"type": "boolean",
|
|
"description": "Run as a background task and return its id; collect with task_output or stop with task_kill."
|
|
}
|
|
},
|
|
"required": [
|
|
"description",
|
|
"prompt"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/subagent/tool-subagent/src/index.ts`](../packages/subagent/tool-subagent/src/index.ts)
|
|
|
|
The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `examples/coding-agent/cordis.yml` and `examples/acp-agent/cordis.yml`.
|
|
|
|
## `@deepseek-ai/dsh-tool-tasks`
|
|
|
|
### `task_kill`
|
|
|
|
Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"task_id": {
|
|
"type": "string",
|
|
"description": "Task id returned by the tool that started the background work."
|
|
},
|
|
"reason": {
|
|
"type": "string",
|
|
"description": "Optional short reason, recorded in the log and forwarded to the task."
|
|
}
|
|
},
|
|
"required": [
|
|
"task_id"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/tasks/tool-tasks/src/index.ts`](../packages/tasks/tool-tasks/src/index.ts)
|
|
|
|
### `task_list`
|
|
|
|
List your background tasks (running and finished) with their ids, kinds, and statuses.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {}
|
|
}
|
|
```
|
|
|
|
Source: [`packages/tasks/tool-tasks/src/index.ts`](../packages/tasks/tool-tasks/src/index.ts)
|
|
|
|
### `task_output`
|
|
|
|
Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"task_id": {
|
|
"type": "string",
|
|
"description": "Task id returned by the tool that started the background work."
|
|
},
|
|
"wait": {
|
|
"type": "boolean",
|
|
"description": "Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive."
|
|
},
|
|
"timeout_ms": {
|
|
"type": "number",
|
|
"description": "Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum."
|
|
}
|
|
},
|
|
"required": [
|
|
"task_id"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/tasks/tool-tasks/src/index.ts`](../packages/tasks/tool-tasks/src/index.ts)
|
|
|
|
The kind-agnostic background-task control surface: a background bash command and a background subagent are read, listed, and killed through the same three tools. Loading the plugin attaches the control surface that arms producers' `ctx.tasks.start()`.
|
|
|
|
## `@deepseek-ai/dsh-tool-todo`
|
|
|
|
### `todo_write`
|
|
|
|
Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished).
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"todos": {
|
|
"type": "array",
|
|
"description": "The COMPLETE task list, replacing any previous list.",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"content": {
|
|
"type": "string",
|
|
"description": "What the task is — a short imperative line."
|
|
},
|
|
"status": {
|
|
"type": "string",
|
|
"description": "pending (not started) | in_progress (now) | completed (done).",
|
|
"enum": [
|
|
"pending",
|
|
"in_progress",
|
|
"completed"
|
|
]
|
|
}
|
|
},
|
|
"required": [
|
|
"content",
|
|
"status"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"todos"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/todo/tool-todo/src/index.ts`](../packages/todo/tool-todo/src/index.ts)
|
|
|
|
todo_write is session-owned state; UIs render the latest todo/write event as a checklist or ACP plan.
|
|
|
|
## `@deepseek-ai/dsh-tool-workflow`
|
|
|
|
### `workflow`
|
|
|
|
Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.
|
|
|
|
The workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.
|
|
|
|
Script-body hooks:
|
|
- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const — no oneOf/pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), `model` (override). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.
|
|
- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.
|
|
- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.
|
|
- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.
|
|
|
|
Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.
|
|
|
|
Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"script": {
|
|
"type": "string",
|
|
"description": "The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`)."
|
|
},
|
|
"meta": {
|
|
"type": "object",
|
|
"description": "The workflow identity block (plain JSON — never code).",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"description": "Short kebab-case workflow name."
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"description": "One-line description of what the workflow does."
|
|
},
|
|
"whenToUse": {
|
|
"type": "string",
|
|
"description": "Optional guidance on when this workflow applies."
|
|
},
|
|
"phases": {
|
|
"type": "array",
|
|
"description": "Optional phase declarations matched by phase() calls.",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"title": {
|
|
"type": "string",
|
|
"description": "The phase title phase() calls match by exact string."
|
|
},
|
|
"detail": {
|
|
"type": "string",
|
|
"description": "Optional one-line description of the phase."
|
|
},
|
|
"model": {
|
|
"type": "string",
|
|
"description": "Optional model override this phase is expected to use."
|
|
}
|
|
},
|
|
"required": [
|
|
"title"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"description"
|
|
]
|
|
},
|
|
"args": {
|
|
"type": "object",
|
|
"description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]})."
|
|
}
|
|
},
|
|
"required": [
|
|
"script",
|
|
"meta"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/workflow/tool-workflow/src/index.ts`](../packages/workflow/tool-workflow/src/index.ts)
|
|
|
|
## `@deepseek-ai/dsh-tool-web`
|
|
|
|
### `web_fetch`
|
|
|
|
Fetch the content of a specific HTTP(S) URL and return it decoded to text.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"url": {
|
|
"type": "string",
|
|
"description": "The HTTP(S) URL to fetch."
|
|
}
|
|
},
|
|
"required": [
|
|
"url"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/web/tool-web/src/index.ts`](../packages/web/tool-web/src/index.ts)
|
|
|
|
### `web_search`
|
|
|
|
Search the web for current information. Returns an optional summary answer and a list of source URLs.
|
|
|
|
```json
|
|
{
|
|
"type": "object",
|
|
"properties": {
|
|
"query": {
|
|
"type": "string",
|
|
"description": "The search query."
|
|
}
|
|
},
|
|
"required": [
|
|
"query"
|
|
]
|
|
}
|
|
```
|
|
|
|
Source: [`packages/web/tool-web/src/index.ts`](../packages/web/tool-web/src/index.ts)
|
|
|
|
web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps.
|