Merge origin/master into codex/truncated-design
This commit is contained in:
@@ -1,36 +1,9 @@
|
||||
/**
|
||||
* Generate (and verify) the tool-schema catalog in docs/tool-catalog.md.
|
||||
*
|
||||
* The catalog is the MODEL-FACING TOOL reference: every tool a shipped plugin
|
||||
* contributes to `ctx.tools`, with the exact `name` / `description` / JSON-Schema
|
||||
* `parameters` the model receives via the system-prompt assembly. It complements
|
||||
* the cordis events/services catalog (the wiring a plugin author works against)
|
||||
* and the core-data-structures catalog (the vocabulary those signatures move):
|
||||
* this page is the TOOLS the agent is offered.
|
||||
*
|
||||
* `tsx scripts/gen-tool-catalog.ts` → write the catalog
|
||||
* `tsx scripts/gen-tool-catalog.ts --check` → exit 1 if the committed file
|
||||
* is stale (CI / pre-push gate)
|
||||
*
|
||||
* Why this generator BOOTS PLUGINS instead of parsing source (unlike its AST
|
||||
* sibling `gen-cordis-catalog.ts`): a tool's schema is not statically knowable.
|
||||
* `tool-todo` writes `enum: [...STATUSES]` (a runtime spread), descriptions are
|
||||
* built by string concatenation, `tool-subagent`'s tool name is `config.toolName`,
|
||||
* and an MCP plugin can register RAW JSON Schema without `defineTool` at all. The
|
||||
* faithful source of truth is therefore the SHIPPED schema: mount each tool
|
||||
* plugin on a real cordis Context and read `ctx.tools.schemas()` — exactly the
|
||||
* `ToolSchema[]` the model is sent. See
|
||||
* docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md.
|
||||
*
|
||||
* Booting sacrifices the AST pass's structural "nothing can be silently omitted"
|
||||
* property (there is no source declaration to enumerate), so a COMPLETENESS GUARD
|
||||
* restores it: the generator globs every `tool-*` package under `packages/` and
|
||||
* hard-errors if any such package is absent from the boot manifest below. A new
|
||||
* tool package fails the generator — and thus the freshness gate — until it is
|
||||
* registered here, mirroring how a new event appears in the cordis regenerate.
|
||||
*
|
||||
* Schema blocks use a plain ` ```json ` fence: doc-typecheck only extracts `ts*`
|
||||
* fences, so no BlockKind wiring is needed there.
|
||||
* Generate `docs/tool-catalog.md` from schemas collected by booting each tool
|
||||
* plugin. Runtime registration is the source of truth for computed schemas;
|
||||
* the manifest is checked against every on-disk `tool-*` package. `--check`
|
||||
* verifies the committed artifact. Rationale and ownership live in
|
||||
* `docs/rfc/implemented/process/2026-07-02-tool-schema-catalog.md`.
|
||||
*/
|
||||
|
||||
import { globSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
@@ -49,12 +22,14 @@ import SubagentService from '@deepseek-ai/dsh-subagent'
|
||||
import * as SubagentMock from '@deepseek-ai/dsh-subagent-mock'
|
||||
import SkillService from '@deepseek-ai/dsh-skill'
|
||||
import * as SkillLocal from '@deepseek-ai/dsh-skill-local'
|
||||
import TaskService from '@deepseek-ai/dsh-tasks'
|
||||
import * as ToolAskUser from '@deepseek-ai/dsh-tool-ask-user'
|
||||
import * as ToolBash from '@deepseek-ai/dsh-tool-bash'
|
||||
import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
|
||||
import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
|
||||
import * as ToolFsSearch from '@deepseek-ai/dsh-tool-fs-search'
|
||||
import * as ToolSkill from '@deepseek-ai/dsh-tool-skill'
|
||||
import * as ToolTasks from '@deepseek-ai/dsh-tool-tasks'
|
||||
import * as ToolTodo from '@deepseek-ai/dsh-tool-todo'
|
||||
import * as ToolSubagent from '@deepseek-ai/dsh-tool-subagent'
|
||||
import * as ToolWeb from '@deepseek-ai/dsh-tool-web'
|
||||
@@ -65,17 +40,9 @@ const root = resolve(import.meta.dirname, '..')
|
||||
const OUT = 'docs/tool-catalog.md'
|
||||
|
||||
/**
|
||||
* One tool-plugin package to boot. `mount` is a per-entry recipe (async): it
|
||||
* plugs the injected seams the plugin's `apply` reads (an executor for
|
||||
* `ctx.bash`, a provider for `ctx.subagents`) BEFORE the tool plugin itself.
|
||||
* `SystemPrompt` + `ToolRegistry` are mounted for every entry by the caller
|
||||
* (`ToolRegistry` injects `systemPrompt`), so `mount` only handles the extras.
|
||||
*
|
||||
* The recipe is irreducible policy — WHICH seams a given tool needs and with
|
||||
* WHAT config is not derivable from the package layout — so it stays a hand-
|
||||
* maintained closure. The `dir` field is what the completeness guard matches
|
||||
* against the on-disk `tool-*` package glob, so a NEW tool package cannot be
|
||||
* silently omitted (see the module doc).
|
||||
* Tool package plus its hand-maintained boot recipe. The caller mounts the
|
||||
* prompt and registry; each recipe supplies only package-specific seams and
|
||||
* config, while `dir` participates in the completeness check.
|
||||
*/
|
||||
interface ToolPackage {
|
||||
/** The npm package name, used as the catalog section heading. */
|
||||
@@ -147,14 +114,14 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
pkg: '@deepseek-ai/dsh-tool-bash',
|
||||
dir: 'tool-bash',
|
||||
source: 'packages/bash/tool-bash/src/index.ts',
|
||||
requires: ['ctx.tools', 'ctx.bash'],
|
||||
writes: ['tool/call', 'tool/result', 'context/message via agent.inject() for background completion notices'],
|
||||
requires: ['ctx.tools', 'ctx.bash', 'ctx.tasks at call time for run_in_background'],
|
||||
writes: ['tool/call', 'tool/result'],
|
||||
async mount(ctx) {
|
||||
await ctx.plugin(LocalBashExecutor)
|
||||
await ctx.plugin(ToolBash)
|
||||
},
|
||||
note:
|
||||
'The bash/bash_output/bash_kill tools are model-facing consumers of the bash executor seam.',
|
||||
'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.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-cordis',
|
||||
@@ -175,9 +142,8 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
requires: ['ctx.tools', 'ctx.fs', 'ctx.systemPrompt'],
|
||||
writes: ['tool/call', 'fs/write-intent or fs/edit-intent for mutations', 'fs/observed after successful file operations', 'tool/result'],
|
||||
async mount(ctx) {
|
||||
// The tool injects `fs`; boot the local backend to satisfy it. The schemas
|
||||
// do not depend on the policy plugin (an event gate that changes behavior,
|
||||
// not tool shape), so the bare provider is enough to harvest them.
|
||||
// The tool needs `fs`; the bare provider is sufficient because policy
|
||||
// changes behavior, not schema shape.
|
||||
await ctx.plugin(LocalFileSystem)
|
||||
await ctx.plugin(ToolFs)
|
||||
},
|
||||
@@ -232,6 +198,19 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
note:
|
||||
'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`.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-tasks',
|
||||
dir: 'tool-tasks',
|
||||
source: 'packages/tasks/tool-tasks/src/index.ts',
|
||||
requires: ['ctx.tools', 'ctx.tasks', 'ctx.systemPrompt'],
|
||||
writes: ['tool/call', 'tool/result', 'context/message via agent.inject() for background completion notices'],
|
||||
async mount(ctx) {
|
||||
await ctx.plugin(TaskService)
|
||||
await ctx.plugin(ToolTasks)
|
||||
},
|
||||
note:
|
||||
'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()`.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-todo',
|
||||
dir: 'tool-todo',
|
||||
@@ -267,10 +246,8 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
requires: ['ctx.tools', 'ctx.web', 'ctx.systemPrompt'],
|
||||
writes: ['tool/call', 'tool/result'],
|
||||
async mount(ctx) {
|
||||
// The tools inject `web`; boot the seam plus one search and one fetch
|
||||
// provider so both `web_search` and `web_fetch` register. The schemas do
|
||||
// not depend on which provider backs the seam (or on it being available),
|
||||
// so any registered provider is enough to harvest them.
|
||||
// Mount search and fetch providers so both tools register. Their schemas
|
||||
// do not depend on provider identity or availability.
|
||||
await ctx.plugin(WebService)
|
||||
await ctx.plugin(WebSearchExa)
|
||||
await ctx.plugin(WebFetchLocal)
|
||||
|
||||
Reference in New Issue
Block a user