feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/ * *
2026-07-12 03:36:43 +08:00
* 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 `
2026-07-13 23:27:00 +08:00
* verifies the committed artifact . Rationale and ownership live in
2026-07-19 22:50:49 +08:00
* ` .agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md ` .
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
* /
import { globSync , readFileSync , writeFileSync } from 'node:fs'
import { basename , resolve } from 'node:path'
build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.
Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.
The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.
Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
2026-08-10 22:04:06 +08:00
import { Context } from '@deepseek-ai/cordis'
2026-08-24 18:23:42 +08:00
import LlmRuntime from '@deepseek-ai/dsh-llm'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
import type { ToolSchema } from '@deepseek-ai/dsh-llm'
2026-07-19 19:22:10 +08:00
import AgentRegistry from '@deepseek-ai/dsh-agent'
2026-07-31 22:45:21 +08:00
import type { Agent } from '@deepseek-ai/dsh-agent'
import { createScope } from '@deepseek-ai/dsh-scope'
import SessionStore , { SessionId } from '@deepseek-ai/dsh-session'
2026-08-06 22:28:32 +08:00
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
2026-08-13 00:36:22 +08:00
import SqliteSessionQueryEngine from '@deepseek-ai/dsh-session-query-sqlite'
2026-07-19 19:22:10 +08:00
import GoalService from '@deepseek-ai/dsh-goal'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
2026-08-13 00:36:22 +08:00
import ToolRuntime , { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
import LocalBashExecutor from '@deepseek-ai/dsh-bash-local'
2026-08-13 00:36:22 +08:00
import * as BashEnvPlugin from '@deepseek-ai/dsh-shell-env'
2026-08-01 18:48:17 +08:00
import { PwshLocalExecutor } from '@deepseek-ai/dsh-pwsh-local'
2026-08-13 00:36:22 +08:00
import LocalSubprocessRuntime from '@deepseek-ai/dsh-subprocess-local'
2026-07-02 09:30:04 +08:00
import LocalFileSystem from '@deepseek-ai/dsh-fs-local'
2026-08-10 15:09:07 +08:00
import { AttachmentStore } from '@deepseek-ai/dsh-attachment'
2026-08-21 13:19:50 +08:00
import type { ImageAttachmentLimits , ImageAttachmentRef , SaveImageAttachment , StoredImageAttachment } from '@deepseek-ai/dsh-attachment'
2026-08-13 00:36:22 +08:00
import UserQuestionService from '@deepseek-ai/dsh-user-questions'
import PlanModeController from '@deepseek-ai/dsh-plan-mode'
import WebRuntime from '@deepseek-ai/dsh-web'
2026-07-03 16:49:00 +08:00
import * as WebSearchExa from '@deepseek-ai/dsh-web-search-exa'
2026-08-13 00:36:22 +08:00
import * as WebFetchLocal from '@deepseek-ai/dsh-web-fetch-http'
import SubagentRuntime from '@deepseek-ai/dsh-subagent'
2026-08-28 01:04:46 +08:00
import type { SubagentProvider } from '@deepseek-ai/dsh-subagent'
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
import * as ToolSubagentControl from '@deepseek-ai/dsh-tool-subagent-control'
2026-07-26 02:32:34 +08:00
import * as ToolSubagentListAgents from '@deepseek-ai/dsh-tool-subagent-control/list-agents'
2026-08-13 00:36:22 +08:00
import SkillRegistry from '@deepseek-ai/dsh-skill'
import * as SkillFileSystem from '@deepseek-ai/dsh-skill-filesystem'
import LocalJobRegistry from '@deepseek-ai/dsh-jobs-local'
2026-07-03 11:57:07 +08:00
import * as ToolAskUser from '@deepseek-ai/dsh-tool-ask-user'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
import * as ToolBash from '@deepseek-ai/dsh-tool-bash'
2026-08-01 18:48:17 +08:00
import * as ToolPwsh from '@deepseek-ai/dsh-tool-pwsh'
2026-07-29 14:12:27 +08:00
import * as ToolBashPersistent from '@deepseek-ai/dsh-tool-bash-persistent'
2026-08-12 01:11:20 +08:00
import * as ToolPwshPersistent from '@deepseek-ai/dsh-tool-pwsh-persistent'
2026-08-12 23:51:31 +08:00
import CordisHostRunner from '@deepseek-ai/dsh-cordis-host-runner'
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
2026-07-02 09:30:04 +08:00
import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
2026-07-09 20:44:32 +08:00
import * as ToolFsSearch from '@deepseek-ai/dsh-tool-fs-search'
2026-07-29 14:12:27 +08:00
import * as ToolStrReplaceEditor from '@deepseek-ai/dsh-tool-str-replace-editor'
2026-08-13 00:36:22 +08:00
import TerminalSessionService from '@deepseek-ai/dsh-terminal'
import * as ToolPty from '@deepseek-ai/dsh-tool-terminal'
2026-07-19 19:22:10 +08:00
import * as ToolGoal from '@deepseek-ai/dsh-tool-goal'
2026-08-13 00:36:22 +08:00
import * as ToolSchedule from '@deepseek-ai/dsh-schedule'
feat(lsp): LSP capability seam, generic stdio provider, and lsp tool
Implements the LSP capability seam RFC as three packages: dsh-lsp (the
ctx.lsp interface — provider registry by branded id + exclusive extension
mapping, per-query order-independent selection, closed request/result
vocabulary, LspError taxonomy), dsh-lsp-local (a generic stdio language-server
provider — Content-Length JSON-RPC framing, per-(provider, workspace) process
single-flight, transient didOpen/query/didClose, an abortable per-instance
queue, UTF-16 negotiation, host-namespace source reads outside ctx.fs, and
bounded shutdown/kill teardown), and dsh-tool-lsp (the model-facing lsp tool —
four operations, one-based UTF-16 cursor conversion, workspace-grouped location
rendering, hover capping, a required session workspace, and a timeout budget).
Why: an agent had text search and file reads but no way to identify a program
symbol — follow an alias, connect an interface to implementations, or read an
inferred type — before changing code. Splitting model contract, seam, and local
subprocess behavior keeps the four semantic queries stable across future remote
or sandbox-native providers without leaking a JSON-RPC escape hatch.
2026-07-16 12:05:35 +08:00
import Lsp from '@deepseek-ai/dsh-lsp'
import * as ToolLsp from '@deepseek-ai/dsh-tool-lsp'
2026-07-03 12:26:58 +08:00
import * as ToolSkill from '@deepseek-ai/dsh-tool-skill'
2026-07-24 15:09:55 +08:00
import * as ToolSessionQuery from '@deepseek-ai/dsh-tool-session-query'
2026-08-13 00:36:22 +08:00
import * as ToolTasks from '@deepseek-ai/dsh-tool-jobs'
2026-08-19 22:22:59 +08:00
import type TeamService from '@deepseek-ai/dsh-experimental-agent-team'
import * as ToolTeam from '@deepseek-ai/dsh-experimental-tool-agent-team'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
import * as ToolTodo from '@deepseek-ai/dsh-tool-todo'
import * as ToolSubagent from '@deepseek-ai/dsh-tool-subagent'
2026-08-25 15:13:30 +08:00
import { registerListSubagentModels } from '../packages/subagent/tool-subagent/src/list-models.ts'
2026-07-03 16:49:00 +08:00
import * as ToolWeb from '@deepseek-ai/dsh-tool-web'
2026-08-13 00:36:22 +08:00
import VmWorkflowEngine from '@deepseek-ai/dsh-workflow-worker-thread'
2026-07-20 00:51:19 +08:00
import * as ToolRalph from '@deepseek-ai/dsh-tool-ralph'
workflow: dynamic workflows — script-driven multi-agent orchestration
A new capability family at packages/workflow/ in the bash seam shape,
modeled on Claude Code's dynamic workflows: the model writes a JavaScript
orchestration script (export const meta = {...} + plain-JS body), a runtime
executes it, and the script — not the conversation — holds the loop, the
branching, and the intermediate results.
- dsh-workflow (ctx.workflows): abstract WorkflowService + run vocabulary
(WorkflowRun whose result NEVER rejects) + observe-only workflow/* events
carrying data snapshots (id + meta, never the live run), per-listener
contained like subagent/*.
- dsh-workflow-vm: in-process node:vm engine. Meta extraction via a
string/comment-aware scanner (template interpolation rejected; literal
evaluated alone in an empty timed context; statement blanked line-
preservingly so stacks keep script line numbers). Hooks: agent(prompt,
{label, phase, schema, model}) over ctx.subagents, parallel(), pipeline()
(no cross-stage barrier), phase(), log(), args. Fatal-vs-null discipline:
hook misuse (unknown/deferred options, bad arguments, unsupported
schemas, tripped caps, seam start failures, cancellation) throws fatal
WorkflowErrors the combinators RE-THROW — never dissolved into the
per-item null reserved for child failures. Realm boundary: inbound values
materialized by descriptor walks that never invoke accessors (defineProperty
copies, __proto__-safe); outbound values rebuilt in-realm via the
context's own JSON.parse. Determinism bans (Date.now/Math.random/argless
new Date) kept so future resume support cannot break scripts. Caps and
timeouts are validated Config. Every hook promise carries a no-op
rejection consumer (app-boot exits on unhandled rejections).
- dsh-tool-workflow: the model-facing workflow tool, synchronous like
dsh-tool-subagent (start → await → try/finally dispose; abort bridged;
non-completed → isError). Generic render card titled by a textual
meta.name sniff. The tool description carries the authoring contract.
Wired into examples/{coding-agent,acp-agent} with explicit-ask-only
guidance. Coverage at every tier: unit (meta scanner, materializer incl.
counting-getter and __proto__ regressions, combinator semantics,
concurrency ceiling, caps, cancellation, no-unhandled-rejection abandon),
integration over the real spawn stack, with-key e2e (real two-phase run +
the tool through the registry pipeline), and a recorded ACP snapshot
scenario (workflow-run, 1 child session). RFC:
docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md (deferred
work explicitly listed). AGENTS.md budget 1575 → 1590 for the new group's
layout line.
2026-07-05 13:29:35 +08:00
import * as ToolWorkflow from '@deepseek-ai/dsh-tool-workflow'
2026-08-13 13:43:43 +08:00
import { githubSlug } from './verify-md-links.ts'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
2026-08-10 15:09:07 +08:00
/** Attachment seam marker that makes the attachments-conditional `read_image` schema harvestable. */
class CatalogAttachmentStore extends AttachmentStore {
readonly imageLimits : ImageAttachmentLimits = Object . freeze ( {
maxImageBytes : 1 ,
maxImagesPerMessage : 1 ,
maxMessageImageBytes : 1 ,
maxImagePixels : 1 ,
2026-08-17 20:49:08 +08:00
maxImageDimension : 1 ,
2026-08-10 15:09:07 +08:00
mediaTypes : Object.freeze ( [ 'image/png' ] as const ) ,
} )
override validateImage ( _input : SaveImageAttachment ) : Promise < void > {
return Promise . reject ( new Error ( 'gen-tool-catalog: attachment validation is unreachable during schema harvest' ) )
}
2026-08-21 13:19:50 +08:00
override saveImage ( _input : SaveImageAttachment ) : Promise < ImageAttachmentRef > {
2026-08-10 15:09:07 +08:00
return Promise . reject ( new Error ( 'gen-tool-catalog: attachment writes are unreachable during schema harvest' ) )
}
override readImage ( _ref : ImageAttachmentRef ) : Promise < StoredImageAttachment > {
return Promise . reject ( new Error ( 'gen-tool-catalog: attachment reads are unreachable during schema harvest' ) )
}
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
const root = resolve ( import . meta . dirname , '..' )
2026-07-06 22:26:06 +08:00
const OUT = 'docs/tool-catalog.md'
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
2026-07-19 17:20:49 +08:00
/ * *
* Register the descriptor needed to mount schema - producing consumers . Declares
* the full capability set of the shipped in - process providers so consumers
* mount under their shipped defaults ( tool - subagent ' s default numeric maxDepth
* requires ` depthLimit ` ) .
* /
2026-07-19 11:54:37 +08:00
function registerCatalogSubagentProvider ( ctx : Context , name : string ) : void {
const provider : SubagentProvider = {
name ,
2026-08-24 18:23:42 +08:00
capabilities : { agentOptions : true , outputSchema : true , depthLimit : true , toolFilter : true , persona : true } ,
2026-07-19 11:54:37 +08:00
inheritsParentContext : false ,
start : ( ) = > Promise . reject ( new Error ( 'tool-catalog provider cannot start a child' ) ) ,
2026-07-30 13:37:22 +08:00
// Declared so consumers configured for continuable background mode mount.
prepareContinuable : ( ) = > Promise . reject ( new Error ( 'tool-catalog provider cannot prepare a child' ) ) ,
2026-07-19 11:54:37 +08:00
}
ctx . subagents . registerProvider ( provider )
}
2026-07-31 22:45:21 +08:00
/** Minted child-scope keys for packages whose tools are never global. */
const catalogChildScopes = new WeakMap < Context , Agent > ( )
/ * *
* Install one scope - local tool package into an agent - like child scope for
* schema harvest , without starting a model , Agent loop , or persistence backend .
* @param ctx - catalog context owning the scope .
* @param mountScoped - package installer for the scoped context .
2026-08-05 19:00:02 +08:00
* @param key - agent - like scope key exposed to the package ' s scope selector .
* @param inject - services the package installer must await before mounting .
2026-07-31 22:45:21 +08:00
* /
async function mountCatalogChildScope (
ctx : Context ,
mountScoped : ( childCtx : Context ) = > void ,
2026-08-05 19:00:02 +08:00
key : Agent = { id : SessionId ( 'tool-catalog-child' ) } as Agent ,
inject : string [ ] = [ 'tools' , 'systemPrompt' , 'subagents' ] ,
2026-07-31 22:45:21 +08:00
) : Promise < void > {
await ctx . plugin ( Object . assign ( ( inner : Context ) = > {
mountScoped ( createScope ( inner , key ) . ctx )
2026-08-05 19:00:02 +08:00
} , { inject } ) )
2026-07-31 22:45:21 +08:00
catalogChildScopes . set ( ctx , key )
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/ * *
2026-07-13 23:27:00 +08:00
* 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 .
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
* /
2026-08-12 23:51:31 +08:00
export interface ToolPackage {
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/** The npm package name, used as the catalog section heading. */
pkg : string
/** The `packages/<group>/<dir>` leaf name — matched by the completeness guard. */
dir : string
2026-07-27 13:54:19 +08:00
/ * *
* Repo - relative implementation source linked per harvested tool . Packages
* whose tools share one plugin may use a string ; split plugins map each tool
* name to its own source .
* /
source : string | Readonly < Record < string , string > >
2026-07-24 19:54:25 +08:00
/** Services or owning runtimes the package requires at execution time. */
2026-07-05 01:25:58 +08:00
requires : string [ ]
/** Session events or other visible state the tools write or affect. */
writes : string [ ]
/** Additional model-visible names shipped by example/app config. */
shippedNames? : string [ ]
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/ * * P l u g t h e i n j e c t e d s e a m s + t h e t o o l p l u g i n o n t o a c o n t e x t t h a t a l r e a d y
* carries ` systemPrompt ` + ` tools ` . * /
mount : ( ctx : Context ) = > Promise < void >
2026-07-31 22:45:21 +08:00
/** Agent-like scope key whose tool view is catalogued instead of the global view. */
scope ? : ( ctx : Context ) = > Agent
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
/ * *
2026-08-13 00:36:22 +08:00
* Config for the caller ' s ` ToolRuntime ` mount . The registry itself ships a
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
* model - facing tool ( ` run_code ` , registered under a non - native ` mode ` ) , so
2026-07-24 19:54:25 +08:00
* ITS catalog entry boots the registry in the mode that exposes it ;
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
* every other entry uses the default ( native ) registry .
* /
toolsConfig? : ToolsConfig
2026-07-02 03:16:17 +08:00
/ * *
* A deployment note rendered after the package ' s tools , for a fact that
* booting the package alone cannot show . The registered tool NAME can be a
2026-07-24 19:54:25 +08:00
* load - time config ( ` tool-subagent ` ' s ` toolName ` ) , so one package may appear
2026-07-02 03:16:17 +08:00
* under several names across deployments — the boot yields the package
* DEFAULT , and this note records the shipped alternatives the model sees .
* /
note? : string
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
}
/ * *
* The boot manifest : every shipped tool package ( a ` tool-* ` leaf under
* ` packages/ ` ) . Ordered by package name ( the render order ) ; the completeness
* guard proves it is exhaustive against the on - disk glob .
* /
const TOOL_PACKAGES : ToolPackage [ ] = [
2026-07-03 11:57:07 +08:00
{
pkg : '@deepseek-ai/dsh-tool-ask-user' ,
dir : 'tool-ask-user' ,
refactor(packages): dissolve ui/ and rename sdk/ to scaffold/
git mv per the regrouping RFC: the five human-collaboration seams and
tui join packages/interaction/, app-boot becomes packages/boot/, and
jsonrpc joins the renamed scaffold/ (formerly sdk/) as its server half
beside client/protocol/create-sdk/helper/scripts/telemetry, whose
folders drop the legacy sdk- prefix. Three new group README triplets
replace the ui/ and sdk/ ones; tsconfig references/paths/globs,
knip keys, vitest globs, gate scripts, catalogs, docs, and the
lockfile follow. Adds the four settled FIXME rename markers
(dsh-sdk-server, dsh-sdk-telemetry, dsh-sdk-helper, dsh-sdk-scripts).
The scaffold folders diverge from their npm names until those renames
land, so tsconfig.base.json maps the three affected names explicitly
beside the group wildcard. Also repairs two pre-existing stale-path
classes the strengthened sweep surfaced: docs/web-styling.md's retired
web-ui host package and type-model spec fixture-literal joins.
app-boot's three Loader-composition specs time out at the default 5s
under full-suite parallel load on this filesystem (pre-existing;
pass isolated with --testTimeout=30000); interaction/scaffold/boot
suites otherwise green (687 passed).
2026-07-30 03:13:49 +08:00
source : 'packages/interaction/tool-ask-user/src/index.ts' ,
2026-08-13 00:36:22 +08:00
requires : [ 'ctx.tools' , 'ctx.userQuestions' ] ,
2026-07-05 17:05:33 +08:00
writes : [ 'tool/call' , 'tool/result after a UI/provider answers the question' ] ,
2026-07-03 11:57:07 +08:00
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( UserQuestionService )
2026-07-03 11:57:07 +08:00
await ctx . plugin ( ToolAskUser )
} ,
2026-07-05 17:05:33 +08:00
note :
'ask_user_question pauses the tool call until the active UI provider returns a human answer.' ,
2026-07-03 11:57:07 +08:00
} ,
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
{
pkg : '@deepseek-ai/dsh-tools' ,
dir : 'tools' ,
rename code-mode to ptc (PTC mode), except session-persistent vocabulary
Rename the tool-presentation transport from code-mode to ptc everywhere
that is not written into session logs: the mode config value becomes 'ptc',
the preset directory/id becomes ptc, the demo becomes demo:ptc, the
dispatch waterfall becomes tools/ptc-dispatch-log (types PtcDispatch*), the
prompt rule becomes tools:ptc-only, source/test files become ptc.ts etc.,
and prose says PTC mode / PTC 模式. The session-persistent vocabulary
(durable events tool/code-dispatch*, logged plugin name tools-code-mode,
sub-call id segment :code:) intentionally stays and moves in the stacked
persistence PR, which is blocked until the SESSION_FORMAT_VERSION v0→v1
migration lands with it. run_code, its code parameter, CodeSdkLanguage,
CodeRunFailedError, the dsh-code-runtime family, third-party codex names,
and frozen archived notes keep their names.
2026-08-25 20:46:42 +08:00
source : 'packages/core/tools/src/ptc.ts' ,
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
requires : [ 'ctx.tools' , 'ctx.codeRuntime (execution time)' , 'ctx.systemPrompt' ] ,
2026-07-26 10:33:48 +08:00
writes : [ 'tool/call' , 'one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call' , 'tool/result' ] ,
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
// The registry's OWN tool: run_code exists only under a non-native mode
// (the registry registers it in its constructor; the code runtime is read
// at assembly/execution time, so the schema harvest needs none mounted).
rename code-mode to ptc (PTC mode), except session-persistent vocabulary
Rename the tool-presentation transport from code-mode to ptc everywhere
that is not written into session logs: the mode config value becomes 'ptc',
the preset directory/id becomes ptc, the demo becomes demo:ptc, the
dispatch waterfall becomes tools/ptc-dispatch-log (types PtcDispatch*), the
prompt rule becomes tools:ptc-only, source/test files become ptc.ts etc.,
and prose says PTC mode / PTC 模式. The session-persistent vocabulary
(durable events tool/code-dispatch*, logged plugin name tools-code-mode,
sub-call id segment :code:) intentionally stays and moves in the stacked
persistence PR, which is blocked until the SESSION_FORMAT_VERSION v0→v1
migration lands with it. run_code, its code parameter, CodeSdkLanguage,
CodeRunFailedError, the dsh-code-runtime family, third-party codex names,
and frozen archived notes keep their names.
2026-08-25 20:46:42 +08:00
toolsConfig : { mode : 'ptc' } ,
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
async mount() { } ,
note :
rename code-mode to ptc (PTC mode), except session-persistent vocabulary
Rename the tool-presentation transport from code-mode to ptc everywhere
that is not written into session logs: the mode config value becomes 'ptc',
the preset directory/id becomes ptc, the demo becomes demo:ptc, the
dispatch waterfall becomes tools/ptc-dispatch-log (types PtcDispatch*), the
prompt rule becomes tools:ptc-only, source/test files become ptc.ts etc.,
and prose says PTC mode / PTC 模式. The session-persistent vocabulary
(durable events tool/code-dispatch*, logged plugin name tools-code-mode,
sub-call id segment :code:) intentionally stays and moves in the stacked
persistence PR, which is blocked until the SESSION_FORMAT_VERSION v0→v1
migration lands with it. run_code, its code parameter, CodeSdkLanguage,
CodeRunFailedError, the dsh-code-runtime family, third-party codex names,
and frozen archived notes keep their names.
2026-08-25 20:46:42 +08:00
'Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: ptc` / `mode: both` (see the PTC mode Agent Note). Under `ptc` it is the registry\'s only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime\'s language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.' ,
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge
The dsh-tools half of the Code Mode RFC (its fourth, final change): the
registry gains its first config — mode: native | code | both — and OWNS how
its tools reach the model. 'code' contributes exactly one wire tool,
run_code, plus a lazy tools:sdk prompt section declaring every other tool
as a generated TypeScript API (jsonSchemaToTs: total over the defineTool
subset, unknown degradation, lexicographic byte-identical rendering);
'both' ships both representations; 'native' is byte-for-byte the old
behavior. Non-native modes fail every assembly loudly without a
typescript-language ctx.codeRuntime.
run_code's dispatch bridge: JSON-normalizes each binding argument before
dispatch (what dispatches is what the tool/code-dispatch event logs — the
append can never fail on payload shape; BigInt/circulars reject that one
call), serializes all program tool calls through a per-run queue (even
Promise.all — no concurrency-safety metadata yet), routes every sub-call
through tools/pre-execute → tools/post-execute (a deny rejects the
program-side promise), drops sub-call additionalContext (no safe outlet
mid-run; pinned), owns a run-scoped abort that follows the outer signal in
and fires on settlement (in-flight sub-dispatch aborted, queued abandoned,
queue drained before returning), and converts a failed run into
CodeRunFailedError → a structured isError carrying kind + captured logs.
tool/code-dispatch joins SessionEventMap by declaration merging (log-only;
deriveMessages ignores it).
The composed surface: the tools config forwards through agent-core and
both app packages; examples/code-agent + demo:code run the worker runtime
under mode code (keyless boot smoke + a with-key e2e proving the collapsed
[run_code] header, the dispatch events, and the file the program wrote);
two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK
section, collapsed header, dispatch events, and result card — each its own
header-pinning class (the harness gains per-scenario config overlays and
per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the
RFC (moved to implemented/, restructured to decision-era headings) updated
in the same change.
2026-07-08 12:58:23 +08:00
} ,
feat(mode): exit_plan_mode + the ACP session-mode picker + scriptable review answers
Plan mode's stage 2 (RFC 2026-07-07-plan-mode). The exit tool: one
required plan argument (the durable log artifact), execute re-checks the
folded mode, then conducts the review over the user-interaction seam —
one single-select question (Approve / Keep planning) with free text open
— so an approval appends mode/set back to default in-turn and every
other outcome (keep-planning feedback verbatim, aborted, no provider)
returns the corrective isError with the mode unchanged. presentCall is a
generic card titled by the plan's first heading carrying the plan
markdown; over ACP the review rides the ask_user elicitation flow, in
the terminal the stdio prompt queue — no approval-seam dependency.
The ACP bridge maps the picker 1:1 onto ctx.modes (opportunistic, a
type-only peer edge): session/new + session/load advertise
availableModes/currentModeId, session/set_mode validates through set()
and echoes an optimistic current_mode_update (the pending mode IS the
selection; the logged mode/set lands at the boundary and, matching, is
not re-sent), and a session/event listener re-notifies on each logged
flip that differs from the last sent — the tool-driven exit updates the
picker. The feature matrix rows move from 'not modeled' to the
picker-to-modes / knobs-to-config-options division, with the ACP v2
removal direction recorded as a mechanical-migration risk.
The snapshot harness gains the setMode/setModeExpectError ops and a
scripted elicitationAnswers FIFO (cancel on exhaustion; a stray choice
string reaches the agent verbatim as a non-consenting custom answer, so
a scenario bug fails safe). The suite factory's header-pin requirement
now applies only to model-turn scenarios — a protocol-only suite has no
header content to anchor. examples/plan-acp-agent is the live
composition; its keyless modes-advertise scenario pins the wire surface
(advertisement, both set_mode round-trips, unknown-id rejection). The
recorded plan-mode approve/reject arc awaits a with-key recording
session; its texts are pinned at the unit tier meanwhile.
examples/AGENTS.md ceiling 653 → 680: the new example's required smoke
row does not fit the old budget.
2026-07-10 02:57:40 +08:00
{
2026-07-22 16:57:23 +08:00
pkg : '@deepseek-ai/dsh-plan-mode' ,
dir : 'plan-mode' ,
source : 'packages/plan/plan-mode/src/index.ts' ,
2026-08-13 00:36:22 +08:00
requires : [ 'ctx.tools' , 'ctx.systemPrompt' , 'ctx.userQuestions (execution time, opportunistic)' ] ,
2026-07-22 16:57:23 +08:00
writes : [ 'tool/call' , 'plan/mode inactive on an approved review' , 'tool/result' ] ,
feat(mode): exit_plan_mode + the ACP session-mode picker + scriptable review answers
Plan mode's stage 2 (RFC 2026-07-07-plan-mode). The exit tool: one
required plan argument (the durable log artifact), execute re-checks the
folded mode, then conducts the review over the user-interaction seam —
one single-select question (Approve / Keep planning) with free text open
— so an approval appends mode/set back to default in-turn and every
other outcome (keep-planning feedback verbatim, aborted, no provider)
returns the corrective isError with the mode unchanged. presentCall is a
generic card titled by the plan's first heading carrying the plan
markdown; over ACP the review rides the ask_user elicitation flow, in
the terminal the stdio prompt queue — no approval-seam dependency.
The ACP bridge maps the picker 1:1 onto ctx.modes (opportunistic, a
type-only peer edge): session/new + session/load advertise
availableModes/currentModeId, session/set_mode validates through set()
and echoes an optimistic current_mode_update (the pending mode IS the
selection; the logged mode/set lands at the boundary and, matching, is
not re-sent), and a session/event listener re-notifies on each logged
flip that differs from the last sent — the tool-driven exit updates the
picker. The feature matrix rows move from 'not modeled' to the
picker-to-modes / knobs-to-config-options division, with the ACP v2
removal direction recorded as a mechanical-migration risk.
The snapshot harness gains the setMode/setModeExpectError ops and a
scripted elicitationAnswers FIFO (cancel on exhaustion; a stray choice
string reaches the agent verbatim as a non-consenting custom answer, so
a scenario bug fails safe). The suite factory's header-pin requirement
now applies only to model-turn scenarios — a protocol-only suite has no
header content to anchor. examples/plan-acp-agent is the live
composition; its keyless modes-advertise scenario pins the wire surface
(advertisement, both set_mode round-trips, unknown-id rejection). The
recorded plan-mode approve/reject arc awaits a with-key recording
session; its texts are pinned at the unit tier meanwhile.
examples/AGENTS.md ceiling 653 → 680: the new example's required smoke
row does not fit the old budget.
2026-07-10 02:57:40 +08:00
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( PlanModeController , { section : 'Tool catalog schema harvest.' } )
feat(mode): exit_plan_mode + the ACP session-mode picker + scriptable review answers
Plan mode's stage 2 (RFC 2026-07-07-plan-mode). The exit tool: one
required plan argument (the durable log artifact), execute re-checks the
folded mode, then conducts the review over the user-interaction seam —
one single-select question (Approve / Keep planning) with free text open
— so an approval appends mode/set back to default in-turn and every
other outcome (keep-planning feedback verbatim, aborted, no provider)
returns the corrective isError with the mode unchanged. presentCall is a
generic card titled by the plan's first heading carrying the plan
markdown; over ACP the review rides the ask_user elicitation flow, in
the terminal the stdio prompt queue — no approval-seam dependency.
The ACP bridge maps the picker 1:1 onto ctx.modes (opportunistic, a
type-only peer edge): session/new + session/load advertise
availableModes/currentModeId, session/set_mode validates through set()
and echoes an optimistic current_mode_update (the pending mode IS the
selection; the logged mode/set lands at the boundary and, matching, is
not re-sent), and a session/event listener re-notifies on each logged
flip that differs from the last sent — the tool-driven exit updates the
picker. The feature matrix rows move from 'not modeled' to the
picker-to-modes / knobs-to-config-options division, with the ACP v2
removal direction recorded as a mechanical-migration risk.
The snapshot harness gains the setMode/setModeExpectError ops and a
scripted elicitationAnswers FIFO (cancel on exhaustion; a stray choice
string reaches the agent verbatim as a non-consenting custom answer, so
a scenario bug fails safe). The suite factory's header-pin requirement
now applies only to model-turn scenarios — a protocol-only suite has no
header content to anchor. examples/plan-acp-agent is the live
composition; its keyless modes-advertise scenario pins the wire surface
(advertisement, both set_mode round-trips, unknown-id rejection). The
recorded plan-mode approve/reject arc awaits a with-key recording
session; its texts are pinned at the unit tier meanwhile.
examples/AGENTS.md ceiling 653 → 680: the new example's required smoke
row does not fit the old budget.
2026-07-10 02:57:40 +08:00
} ,
note :
2026-08-13 00:36:22 +08:00
'exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary.' ,
feat(mode): exit_plan_mode + the ACP session-mode picker + scriptable review answers
Plan mode's stage 2 (RFC 2026-07-07-plan-mode). The exit tool: one
required plan argument (the durable log artifact), execute re-checks the
folded mode, then conducts the review over the user-interaction seam —
one single-select question (Approve / Keep planning) with free text open
— so an approval appends mode/set back to default in-turn and every
other outcome (keep-planning feedback verbatim, aborted, no provider)
returns the corrective isError with the mode unchanged. presentCall is a
generic card titled by the plan's first heading carrying the plan
markdown; over ACP the review rides the ask_user elicitation flow, in
the terminal the stdio prompt queue — no approval-seam dependency.
The ACP bridge maps the picker 1:1 onto ctx.modes (opportunistic, a
type-only peer edge): session/new + session/load advertise
availableModes/currentModeId, session/set_mode validates through set()
and echoes an optimistic current_mode_update (the pending mode IS the
selection; the logged mode/set lands at the boundary and, matching, is
not re-sent), and a session/event listener re-notifies on each logged
flip that differs from the last sent — the tool-driven exit updates the
picker. The feature matrix rows move from 'not modeled' to the
picker-to-modes / knobs-to-config-options division, with the ACP v2
removal direction recorded as a mechanical-migration risk.
The snapshot harness gains the setMode/setModeExpectError ops and a
scripted elicitationAnswers FIFO (cancel on exhaustion; a stray choice
string reaches the agent verbatim as a non-consenting custom answer, so
a scenario bug fails safe). The suite factory's header-pin requirement
now applies only to model-turn scenarios — a protocol-only suite has no
header content to anchor. examples/plan-acp-agent is the live
composition; its keyless modes-advertise scenario pins the wire surface
(advertisement, both set_mode round-trips, unknown-id rejection). The
recorded plan-mode approve/reject arc awaits a with-key recording
session; its texts are pinned at the unit tier meanwhile.
examples/AGENTS.md ceiling 653 → 680: the new example's required smoke
row does not fit the old budget.
2026-07-10 02:57:40 +08:00
} ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
{
pkg : '@deepseek-ai/dsh-tool-bash' ,
dir : 'tool-bash' ,
2026-08-13 00:36:22 +08:00
source : 'packages/shell/tool-bash/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.shell' , 'ctx.systemPrompt' , 'ctx.shellEnv' , 'ctx.jobs at call time for run_in_background' ] ,
feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
writes : [ 'tool/call' , 'tool/result' ] ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( LocalSubprocessRuntime )
2026-08-02 16:25:27 +08:00
await ctx . plugin ( BashEnvPlugin )
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
await ctx . plugin ( LocalBashExecutor )
await ctx . plugin ( ToolBash )
} ,
2026-07-05 01:25:58 +08:00
note :
2026-08-13 00:36:22 +08:00
'The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.jobs` runtime and is collected/stopped through the `job_*` tools from `@deepseek-ai/dsh-tool-jobs`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled.' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
} ,
2026-08-01 18:48:17 +08:00
{
pkg : '@deepseek-ai/dsh-tool-pwsh' ,
dir : 'tool-pwsh' ,
2026-08-13 00:36:22 +08:00
source : 'packages/shell/tool-pwsh/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.shell' , 'ctx.systemPrompt' , 'ctx.shellEnv' , 'ctx.jobs at call time for run_in_background' ] ,
2026-08-01 18:48:17 +08:00
writes : [ 'tool/call' , 'tool/result' ] ,
async mount ( ctx ) {
// The pwsh tool consumes the bash executor seam; the schema harvest
// mounts the pwsh-local implementation so the inject resolves without
// executing anything (registration never spawns a process).
2026-08-13 00:36:22 +08:00
await ctx . plugin ( LocalSubprocessRuntime )
2026-08-02 16:25:27 +08:00
await ctx . plugin ( BashEnvPlugin )
2026-08-01 18:48:17 +08:00
await ctx . plugin ( PwshLocalExecutor )
await ctx . plugin ( ToolPwsh )
} ,
note :
2026-08-13 00:36:22 +08:00
'The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as `@deepseek-ai/dsh-pwsh-local` backs `ctx.shell`); it mirrors the bash tool call-for-call minus sandbox controls — `run_in_background` runs register with the generic `ctx.jobs` runtime and are collected/stopped through the `job_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-shell-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\\...` paths and `$env:NAME` variables.' ,
2026-08-01 18:48:17 +08:00
} ,
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
{
pkg : '@deepseek-ai/dsh-tool-cordis' ,
dir : 'tool-cordis' ,
2026-08-13 00:36:22 +08:00
source : 'packages/extensions/tool-cordis/src/index.ts' ,
2026-08-12 23:51:31 +08:00
requires : [ 'ctx.tools' , 'ctx.dynamicCordisRunner' ] ,
writes : [ 'tool/call' , 'tool/result' , 'process-local dynamic package lifecycle' ] ,
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
async mount ( ctx ) {
2026-08-12 23:51:31 +08:00
await ctx . plugin ( CordisHostRunner )
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
await ctx . plugin ( ToolCordis )
} ,
note :
2026-08-12 23:51:31 +08:00
'Not in any shipped tree (a deliberate opt-in — dynamic package code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). The toolset injects `ctx.dynamicCordisRunner` from `@deepseek-ai/dsh-cordis-host-runner`, which owns the definition registry and the vm sandbox; a composition missing it never activates the tools. A running package may register ADDITIONAL model-visible tools until it is stopped, undefined, or DSH restarts; a full changed request header logs those tool-set changes.' ,
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
} ,
2026-07-29 14:12:27 +08:00
{
pkg : '@deepseek-ai/dsh-tool-bash-persistent' ,
dir : 'tool-bash-persistent' ,
2026-08-13 00:36:22 +08:00
source : 'packages/shell/tool-bash-persistent/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.terminals' , 'an owning Agent at execution time' ] ,
2026-07-29 14:12:27 +08:00
writes : [ 'tool/call' , 'PTY shell state' , 'tool/result' ] ,
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( TerminalSessionService )
2026-07-29 14:12:27 +08:00
await ctx . plugin ( ToolBashPersistent )
} ,
note :
'One owner-isolated persistent bash tool; deployment composition supplies the PTY backend and may override the model-facing environment description.' ,
} ,
2026-08-12 01:11:20 +08:00
{
pkg : '@deepseek-ai/dsh-tool-pwsh-persistent' ,
dir : 'tool-pwsh-persistent' ,
2026-08-13 09:52:56 +08:00
source : 'packages/shell/tool-pwsh-persistent/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.terminals' , 'an owning Agent at execution time' ] ,
2026-08-12 01:11:20 +08:00
writes : [ 'tool/call' , 'PTY shell state' , 'tool/result' ] ,
async mount ( ctx ) {
2026-08-13 09:52:56 +08:00
await ctx . plugin ( TerminalSessionService )
2026-08-12 01:11:20 +08:00
await ctx . plugin ( ToolPwshPersistent )
} ,
note :
'One owner-isolated persistent pwsh tool, the Windows counterpart of the persistent bash tool; deployment composition supplies a pwsh-dialect PTY backend and may override the model-facing environment description.' ,
} ,
2026-07-29 14:12:27 +08:00
{
pkg : '@deepseek-ai/dsh-tool-str-replace-editor' ,
dir : 'tool-str-replace-editor' ,
source : 'packages/fs/tool-str-replace-editor/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.fs' ] ,
2026-08-09 17:40:56 +08:00
writes : [ 'tool/call' , 'fs/observed after view presence/absence, edit absence, or successful mutation' , 'tool/result' ] ,
2026-07-29 14:12:27 +08:00
async mount ( ctx ) {
await ctx . plugin ( LocalFileSystem )
await ctx . plugin ( ToolStrReplaceEditor )
} ,
note :
2026-07-24 19:54:25 +08:00
'Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal API.' ,
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
} ,
2026-07-02 09:30:04 +08:00
{
pkg : '@deepseek-ai/dsh-tool-fs' ,
dir : 'tool-fs' ,
source : 'packages/fs/tool-fs/src/index.ts' ,
2026-08-20 18:19:23 +08:00
requires : [ 'ctx.tools' , 'ctx.fs' , 'ctx.systemPrompt' , 'ctx.attachments (image-tool registration)' , 'ctx.llm + an image-capable route (image-tool execution)' ] ,
2026-08-21 12:30:47 +08:00
writes : [ 'tool/call' , 'fs/write-intent or fs/edit-intent for mutations' , 'fs/observed after read presence/absence or successful file operation' , 'durable attachment (read_image)' , 'tool/result' ] ,
2026-07-02 09:30:04 +08:00
async mount ( ctx ) {
2026-07-13 23:27:00 +08:00
// The tool needs `fs`; the bare provider is sufficient because policy
2026-08-10 15:09:07 +08:00
// changes behavior, not schema shape. The catalog seam marker opts into
2026-08-21 12:30:47 +08:00
// the attachments-conditional image schema without attachment I/O.
2026-07-02 09:30:04 +08:00
await ctx . plugin ( LocalFileSystem )
2026-08-10 15:09:07 +08:00
await ctx . plugin ( CatalogAttachmentStore )
2026-07-02 09:30:04 +08:00
await ctx . plugin ( ToolFs )
} ,
note :
2026-08-21 12:30:47 +08:00
'The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-observation-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The image tool is not registered without `ctx.attachments`; its schema is route-independent, and execution refuses unless the exact routed model declares image input.' ,
2026-07-02 09:30:04 +08:00
} ,
2026-07-09 20:44:32 +08:00
{
pkg : '@deepseek-ai/dsh-tool-fs-search' ,
dir : 'tool-fs-search' ,
source : 'packages/fs/tool-fs-search/src/index.ts' ,
2026-08-01 18:04:38 +08:00
requires : [ 'ctx.tools' , 'ctx.subprocess' , 'ctx.systemPrompt' ] ,
2026-07-09 20:44:32 +08:00
writes : [ 'tool/call' , 'tool/result' ] ,
async mount ( ctx ) {
2026-08-01 18:04:38 +08:00
// The tools inject `subprocess` (search spawns the packaged ripgrep
// binary through the seam, not ctx.fs); registration itself never
// spawns, so the real local service is inert here. `ctx.spillStore` is
// optional (read via ctx.get) and does not affect the schemas, so no
// spill backend is mounted.
2026-08-13 00:36:22 +08:00
await ctx . plugin ( LocalSubprocessRuntime )
2026-07-30 21:14:03 +08:00
await ctx . plugin ( ToolFsSearch , { sampleOverCapGlobResults : true } )
2026-07-09 20:44:32 +08:00
} ,
note :
2026-08-13 00:36:22 +08:00
'glob and grep are unconditional discovery tools that spawn the packaged ripgrep binary (`@vscode/ripgrep`) through ctx.subprocess as ordinary foreground calls (never background jobs) — no host `rg` install and no shell layer. The catalog uses `sampleOverCapGlobResults: true`; deployments must choose that behavior explicitly. Capped results save the complete formatted list through the optional ctx.spillStore backend; returned locators are follow-up-readable/searchable when the backend exposes local paths in co-located deployments.' ,
2026-07-09 20:44:32 +08:00
} ,
2026-07-21 16:01:00 +08:00
{
2026-08-13 00:36:22 +08:00
pkg : '@deepseek-ai/dsh-tool-terminal' ,
dir : 'tool-terminal' ,
source : 'packages/terminal/tool-terminal/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.terminals' , 'ctx.systemPrompt' , 'ctx.jobs at call time for run_in_background' ] ,
2026-07-21 16:01:00 +08:00
writes : [ 'tool/call' , 'tool/result' ] ,
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( TerminalSessionService )
2026-07-21 16:01:00 +08:00
await ctx . plugin ( ToolPty )
} ,
note :
2026-08-13 00:36:22 +08:00
'The six terminal tools are opt-in and complement one-shot shell/filesystem tools. `terminal_send(run_in_background: true)` registers with `ctx.jobs`; TUI, named key sequences, BEL, resize, auto-start, and cross-agent sharing are absent from the schema.' ,
2026-07-21 16:01:00 +08:00
} ,
2026-07-19 19:22:10 +08:00
{
pkg : '@deepseek-ai/dsh-tool-goal' ,
dir : 'tool-goal' ,
source : 'packages/goal/tool-goal/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.agents' , 'ctx.goals' , 'ctx.systemPrompt' , 'a calling Agent in an authorized open turn' ] ,
2026-07-31 22:52:18 +08:00
writes : [ 'tool/call' , 'goal/change for mutations' , 'tool/result' ] ,
2026-07-19 19:22:10 +08:00
async mount ( ctx ) {
await ctx . plugin ( AgentRegistry )
await ctx . plugin ( GoalService )
await ctx . plugin ( ToolGoal )
} ,
note :
'create, edit, pause, and resume require direct-human root authority; complete and blocked also accept the exact current goal round. The default blocked lower bound is three admitted rounds.' ,
} ,
2026-08-05 19:00:02 +08:00
{
2026-08-13 00:36:22 +08:00
pkg : '@deepseek-ai/dsh-schedule' ,
dir : 'schedule' ,
source : 'packages/schedule/schedule/src/tools.ts' ,
2026-08-05 19:00:02 +08:00
requires : [ 'ctx.tools' , 'ctx.sessions' , 'Session persistence' , 'a future live root Agent' ] ,
writes : [ 'tool/call' , 'schedule/change create or delete' , 'tool/result' ] ,
async mount ( ctx ) {
await ctx . plugin ( SessionStore )
const session = ctx . sessions . create ( SessionId ( 'tool-catalog-schedule' ) )
const agent = { id : session.id , session } as Agent
await mountCatalogChildScope ( ctx , ( childCtx ) = > {
ToolSchedule . registerScheduleTools ( ctx , childCtx , agent , ( ) = > { } )
} , agent , [ 'tools' , 'systemPrompt' ] )
} ,
scope : ctx = > catalogChildScopes . get ( ctx ) as Agent ,
note :
'Registered only inside live root Agent scopes created after the opt-in Schedule plugin loads. '
2026-08-09 17:04:48 +08:00
+ 'Version 1 accepts after_seconds, explicit absolute at, and bounded fixed-rate every_seconds, '
+ 'and discloses session-local delivery; '
2026-08-05 19:00:02 +08:00
+ 'management reads and mutations require the shared Session persistence barrier.' ,
} ,
feat(lsp): LSP capability seam, generic stdio provider, and lsp tool
Implements the LSP capability seam RFC as three packages: dsh-lsp (the
ctx.lsp interface — provider registry by branded id + exclusive extension
mapping, per-query order-independent selection, closed request/result
vocabulary, LspError taxonomy), dsh-lsp-local (a generic stdio language-server
provider — Content-Length JSON-RPC framing, per-(provider, workspace) process
single-flight, transient didOpen/query/didClose, an abortable per-instance
queue, UTF-16 negotiation, host-namespace source reads outside ctx.fs, and
bounded shutdown/kill teardown), and dsh-tool-lsp (the model-facing lsp tool —
four operations, one-based UTF-16 cursor conversion, workspace-grouped location
rendering, hover capping, a required session workspace, and a timeout budget).
Why: an agent had text search and file reads but no way to identify a program
symbol — follow an alias, connect an interface to implementations, or read an
inferred type — before changing code. Splitting model contract, seam, and local
subprocess behavior keeps the four semantic queries stable across future remote
or sandbox-native providers without leaking a JSON-RPC escape hatch.
2026-07-16 12:05:35 +08:00
{
pkg : '@deepseek-ai/dsh-tool-lsp' ,
dir : 'tool-lsp' ,
source : 'packages/lsp/tool-lsp/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.lsp' , 'ctx.systemPrompt' ] ,
writes : [ 'tool/call' , 'tool/result' ] ,
async mount ( ctx ) {
// The tool registers from the seam alone; the schema does not depend on any provider.
await ctx . plugin ( Lsp )
await ctx . plugin ( ToolLsp )
} ,
note :
2026-08-13 00:36:22 +08:00
'The lsp tool keeps provider selection and language-server subprocesses behind ctx.lsp, so its model-visible schema stays stable across providers. Requires a registered provider (e.g. `@deepseek-ai/dsh-lsp-stdio`) at runtime; without one, a query returns the structured `LSP_UNAVAILABLE` error rather than changing the schema.' ,
feat(lsp): LSP capability seam, generic stdio provider, and lsp tool
Implements the LSP capability seam RFC as three packages: dsh-lsp (the
ctx.lsp interface — provider registry by branded id + exclusive extension
mapping, per-query order-independent selection, closed request/result
vocabulary, LspError taxonomy), dsh-lsp-local (a generic stdio language-server
provider — Content-Length JSON-RPC framing, per-(provider, workspace) process
single-flight, transient didOpen/query/didClose, an abortable per-instance
queue, UTF-16 negotiation, host-namespace source reads outside ctx.fs, and
bounded shutdown/kill teardown), and dsh-tool-lsp (the model-facing lsp tool —
four operations, one-based UTF-16 cursor conversion, workspace-grouped location
rendering, hover capping, a required session workspace, and a timeout budget).
Why: an agent had text search and file reads but no way to identify a program
symbol — follow an alias, connect an interface to implementations, or read an
inferred type — before changing code. Splitting model contract, seam, and local
subprocess behavior keeps the four semantic queries stable across future remote
or sandbox-native providers without leaking a JSON-RPC escape hatch.
2026-07-16 12:05:35 +08:00
} ,
2026-07-20 00:51:19 +08:00
{
pkg : '@deepseek-ai/dsh-tool-ralph' ,
dir : 'tool-ralph' ,
source : 'packages/workflow/tool-ralph/src/index.ts' ,
2026-08-13 00:36:22 +08:00
requires : [ 'ctx.tools' , 'ctx.workflowEngine' , 'ctx.subagents' , 'ctx.systemPrompt' , 'a calling Agent (exec.agent parents every fresh round)' ] ,
2026-07-20 00:51:19 +08:00
writes : [ 'tool/call' , 'tool/result' , 'workflow and child session events during execution' ] ,
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SubagentRuntime )
2026-07-20 00:51:19 +08:00
registerCatalogSubagentProvider ( ctx , 'mock' )
await ctx . plugin ( VmWorkflowEngine , { provider : 'mock' } )
await ctx . plugin ( ToolRalph , { subagentProvider : 'mock' } )
} ,
note :
'A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap.' ,
} ,
2026-07-03 12:26:58 +08:00
{
pkg : '@deepseek-ai/dsh-tool-skill' ,
dir : 'tool-skill' ,
2026-07-10 14:19:06 +08:00
source : 'packages/skill/tool-skill/src/index.ts' ,
2026-07-27 16:50:56 +08:00
requires : [ 'ctx.tools' , 'ctx.agents' , 'ctx.skills' ] ,
writes : [ 'tool/call' , 'tool/result' , 'user/message replacement catalogs via agent.inject()' ] ,
2026-07-03 12:26:58 +08:00
async mount ( ctx ) {
2026-07-27 16:50:56 +08:00
await ctx . plugin ( AgentRegistry )
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SkillRegistry )
await ctx . plugin ( SkillFileSystem , {
2026-07-03 12:26:58 +08:00
dshHome : resolve ( root , '.tmp/tool-catalog/.dsh' ) ,
agentsHome : resolve ( root , '.tmp/tool-catalog/.agents' ) ,
} )
await ctx . plugin ( ToolSkill )
} ,
} ,
2026-07-24 15:09:55 +08:00
{
pkg : '@deepseek-ai/dsh-tool-session-query' ,
dir : 'tool-session-query' ,
source : 'packages/session-query/tool-session-query/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.systemPrompt' , 'ctx.sessionQuery' , 'a calling Agent for workspace authority' ] ,
writes : [ 'tool/call' , 'tool/result' ] ,
async mount ( ctx ) {
await ctx . plugin ( SessionStore )
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SqliteSessionQueryEngine , { path : ':memory:' } )
2026-07-24 15:09:55 +08:00
await ctx . plugin ( ToolSessionQuery )
} ,
note :
2026-07-25 18:14:36 +08:00
'The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies.' ,
2026-07-24 15:09:55 +08:00
} ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
{
pkg : '@deepseek-ai/dsh-tool-subagent' ,
dir : 'tool-subagent' ,
2026-08-24 18:23:42 +08:00
source : {
list_subagent_models : 'packages/subagent/tool-subagent/src/list-models.ts' ,
subagent : 'packages/subagent/tool-subagent/src/index.ts' ,
} ,
requires : [ 'ctx.tools' , 'ctx.subagents' , 'ctx.systemPrompt' , 'ctx.llm for model discovery and selected-route validation' ] ,
2026-07-05 01:25:58 +08:00
writes : [ 'tool/call' , 'tool/result' , 'child session events through the chosen provider' ] ,
shippedNames : [ 'subagent' , 'subagent_fork' ] ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SubagentRuntime )
2026-08-24 18:23:42 +08:00
await ctx . plugin ( LlmRuntime )
2026-07-19 11:54:37 +08:00
registerCatalogSubagentProvider ( ctx , 'mock' )
2026-08-25 15:13:30 +08:00
await ctx . plugin ( ToolSubagent , { provider : 'mock' } )
registerListSubagentModels ( ctx , { routes : [ { provider : 'mock' , model : 'mock' } ] } )
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
} ,
2026-07-02 03:16:17 +08:00
note :
2026-08-25 15:13:30 +08:00
'The registered delegation name is the load-time `toolName` config (default `subagent`); the default schema above has model selection off, while the discovery schema is shown as the fixed companion available in an enabled Session. Web presets sample the Plugins preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Each instance independently controls whether it reads model-selection settings and its background behavior through `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`.' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
} ,
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
{
pkg : '@deepseek-ai/dsh-tool-subagent-control' ,
dir : 'tool-subagent-control' ,
2026-07-27 13:54:19 +08:00
source : {
2026-08-06 13:46:55 +08:00
interrupt_agent : 'packages/subagent/tool-subagent-control/src/index.ts' ,
2026-07-27 13:54:19 +08:00
list_agents : 'packages/subagent/tool-subagent-control/src/list-agents.ts' ,
send_message : 'packages/subagent/tool-subagent-control/src/index.ts' ,
} ,
2026-08-06 13:46:55 +08:00
requires : [ 'ctx.tools' , 'ctx.subagents' , 'ctx.agents and ctx.sessionProjections (list_agents only)' ] ,
2026-07-27 00:00:14 +08:00
writes : [ 'tool/call' , 'tool/result' , 'child session events through ctx.subagents' ] ,
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SubagentRuntime )
await ctx . plugin ( LocalJobRegistry )
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
await ctx . plugin ( AgentRegistry )
2026-07-26 02:32:34 +08:00
await ctx . plugin ( SessionStore )
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
await ctx . plugin ( ToolSubagentControl )
2026-07-26 02:32:34 +08:00
await ctx . plugin ( ToolSubagentListAgents )
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
} ,
note :
2026-08-06 13:46:55 +08:00
'The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` and `interrupt_agent` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows use the sessionProjections and live Agent registries).' ,
feat(subagent): continuable background subagents
Implement the continuable background subagents RFC: a durable child
session with a series of Task-backed activations, each disposing its
run before the Task settles.
- dsh-subagent: rename SubagentRun.sendMessage to strict steer, drop
run-level resume, add SubagentProvider.resume dispatch via
SubagentService.resume, the continuation start field, and the
versioned model-hidden subagent/descriptor session event.
- dsh-subagent-inprocess/-spawn/-fork: publish the control-allocated
child id, append the descriptor inside the initial turn, implement
cold resume from the child's own transcript under the live parent
scope, and strict running-only steer.
- dsh-subagent-control (new): SubagentControlService owning stable
child ids, descriptor snapshot/fold/authorization, Task-backed
activation with settle-then-dispose ordering, the process-local
active-run association, and steer-or-resume sendMessage routing.
- dsh-tool-subagent: background route branches on the provider's
resume capability (continuable via the control service; one-shot
task for ACP), returning both child and task ids.
- dsh-tool-subagent-control (new): the globally named send_message
tool rendering steered/started routes.
Keyless coverage spans Task ownership and disposal ordering, running
delivery, cold follow-up, descriptor rejection and rollback, known-id
reconstruction, kill during lookup, admission races, and a new
subagent-continuable ACP snapshot scenario.
2026-07-23 17:07:38 +08:00
} ,
feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
{
2026-08-13 00:36:22 +08:00
pkg : '@deepseek-ai/dsh-tool-jobs' ,
dir : 'tool-jobs' ,
source : 'packages/jobs/tool-jobs/src/index.ts' ,
requires : [ 'ctx.tools' , 'ctx.jobs' , 'ctx.systemPrompt' ] ,
2026-07-23 19:15:45 +08:00
writes : [ 'tool/call' , 'tool/result' , 'user/message via agent.inject() for background completion notices' ] ,
feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
async mount ( ctx ) {
2026-08-13 00:36:22 +08:00
await ctx . plugin ( LocalJobRegistry )
feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
await ctx . plugin ( ToolTasks )
} ,
note :
2026-08-13 00:36:22 +08:00
'The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers\' `ctx.jobs.start()`.' ,
feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
} ,
2026-08-14 12:48:53 +08:00
{
2026-08-19 22:22:59 +08:00
pkg : '@deepseek-ai/dsh-experimental-tool-agent-team' ,
dir : 'tool-agent-team' ,
source : 'packages/experimental/tool-agent-team/src/index.ts' ,
2026-08-19 22:28:18 +08:00
requires : [ 'ctx.tools' , 'ctx.systemPrompt' , 'ctx.agentTeams' , 'an exact live Team member Agent' ] ,
2026-08-14 12:48:53 +08:00
writes : [ 'tool/call' , 'team/member' , 'team/message/queued' , 'team/message/delivered' , 'team/task' , 'tool/result' ] ,
async mount ( ctx ) {
await ctx . plugin ( AgentRegistry )
await ctx . plugin ( SessionStore )
const session = ctx . sessions . create ( SessionId ( 'tool-catalog-team-lead' ) )
let agent ! : Agent
const membership = {
get root() { return agent } ,
id : session.id ,
role : 'lead' as const ,
name : 'lead' ,
}
2026-08-19 22:28:18 +08:00
ctx . provide ( 'agentTeams' , {
2026-08-14 12:48:53 +08:00
tryMembership : ( candidate : Agent ) = > candidate === agent ? membership : undefined ,
membership : ( ) = > membership ,
} as unknown as TeamService )
await ctx . plugin ( Object . assign ( ( inner : Context ) = > {
agent = {
id : session.id ,
session ,
options : { } ,
status : 'idle' ,
} as unknown as Agent
Object . assign ( agent , { ctx : createScope ( inner , agent ) . ctx } )
inner . agents . register ( agent )
2026-08-19 22:28:18 +08:00
} , { inject : [ 'tools' , 'systemPrompt' , 'agents' , 'agentTeams' ] } ) )
2026-08-14 12:48:53 +08:00
await ctx . plugin ( ToolTeam )
catalogChildScopes . set ( ctx , agent )
} ,
scope : ctx = > catalogChildScopes . get ( ctx ) as Agent ,
note :
'All ten tools are scoped to implicit Team Leads and durable teammates. The shipped dsh-base bundle keeps the package disabled; the documented Agent Teams profile patch enables it while disabling the legacy continuable-child control names.' ,
} ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
{
pkg : '@deepseek-ai/dsh-tool-todo' ,
dir : 'tool-todo' ,
source : 'packages/todo/tool-todo/src/index.ts' ,
2026-07-05 01:25:58 +08:00
requires : [ 'ctx.tools' , 'owning Agent session' ] ,
writes : [ 'tool/call' , 'todo/write' , 'tool/result' ] ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
async mount ( ctx ) {
2026-07-29 16:44:13 +08:00
await ctx . plugin ( ToolTodo , { allowParallelInProgress : true } )
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
} ,
2026-07-05 01:25:58 +08:00
note :
2026-08-06 12:13:28 +08:00
'todo_write is session-owned state; UIs render the latest todo/write event as a checklist. `allowParallelInProgress` is required with no default, so the catalog states its choice: `true`, whose description invites several `in_progress` items. A deployment choosing `false` receives the same tool with a description asking for exactly one active task.' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
} ,
workflow: dynamic workflows — script-driven multi-agent orchestration
A new capability family at packages/workflow/ in the bash seam shape,
modeled on Claude Code's dynamic workflows: the model writes a JavaScript
orchestration script (export const meta = {...} + plain-JS body), a runtime
executes it, and the script — not the conversation — holds the loop, the
branching, and the intermediate results.
- dsh-workflow (ctx.workflows): abstract WorkflowService + run vocabulary
(WorkflowRun whose result NEVER rejects) + observe-only workflow/* events
carrying data snapshots (id + meta, never the live run), per-listener
contained like subagent/*.
- dsh-workflow-vm: in-process node:vm engine. Meta extraction via a
string/comment-aware scanner (template interpolation rejected; literal
evaluated alone in an empty timed context; statement blanked line-
preservingly so stacks keep script line numbers). Hooks: agent(prompt,
{label, phase, schema, model}) over ctx.subagents, parallel(), pipeline()
(no cross-stage barrier), phase(), log(), args. Fatal-vs-null discipline:
hook misuse (unknown/deferred options, bad arguments, unsupported
schemas, tripped caps, seam start failures, cancellation) throws fatal
WorkflowErrors the combinators RE-THROW — never dissolved into the
per-item null reserved for child failures. Realm boundary: inbound values
materialized by descriptor walks that never invoke accessors (defineProperty
copies, __proto__-safe); outbound values rebuilt in-realm via the
context's own JSON.parse. Determinism bans (Date.now/Math.random/argless
new Date) kept so future resume support cannot break scripts. Caps and
timeouts are validated Config. Every hook promise carries a no-op
rejection consumer (app-boot exits on unhandled rejections).
- dsh-tool-workflow: the model-facing workflow tool, synchronous like
dsh-tool-subagent (start → await → try/finally dispose; abort bridged;
non-completed → isError). Generic render card titled by a textual
meta.name sniff. The tool description carries the authoring contract.
Wired into examples/{coding-agent,acp-agent} with explicit-ask-only
guidance. Coverage at every tier: unit (meta scanner, materializer incl.
counting-getter and __proto__ regressions, combinator semantics,
concurrency ceiling, caps, cancellation, no-unhandled-rejection abandon),
integration over the real spawn stack, with-key e2e (real two-phase run +
the tool through the registry pipeline), and a recorded ACP snapshot
scenario (workflow-run, 1 child session). RFC:
docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md (deferred
work explicitly listed). AGENTS.md budget 1575 → 1590 for the new group's
layout line.
2026-07-05 13:29:35 +08:00
{
pkg : '@deepseek-ai/dsh-tool-workflow' ,
dir : 'tool-workflow' ,
source : 'packages/workflow/tool-workflow/src/index.ts' ,
2026-08-13 00:36:22 +08:00
requires : [ 'ctx.tools' , 'ctx.workflowEngine' , 'ctx.systemPrompt' , 'a calling Agent (exec.agent parents the script children)' ] ,
2026-07-06 03:14:07 +08:00
writes : [ 'tool/call' , 'tool/result' ] ,
workflow: dynamic workflows — script-driven multi-agent orchestration
A new capability family at packages/workflow/ in the bash seam shape,
modeled on Claude Code's dynamic workflows: the model writes a JavaScript
orchestration script (export const meta = {...} + plain-JS body), a runtime
executes it, and the script — not the conversation — holds the loop, the
branching, and the intermediate results.
- dsh-workflow (ctx.workflows): abstract WorkflowService + run vocabulary
(WorkflowRun whose result NEVER rejects) + observe-only workflow/* events
carrying data snapshots (id + meta, never the live run), per-listener
contained like subagent/*.
- dsh-workflow-vm: in-process node:vm engine. Meta extraction via a
string/comment-aware scanner (template interpolation rejected; literal
evaluated alone in an empty timed context; statement blanked line-
preservingly so stacks keep script line numbers). Hooks: agent(prompt,
{label, phase, schema, model}) over ctx.subagents, parallel(), pipeline()
(no cross-stage barrier), phase(), log(), args. Fatal-vs-null discipline:
hook misuse (unknown/deferred options, bad arguments, unsupported
schemas, tripped caps, seam start failures, cancellation) throws fatal
WorkflowErrors the combinators RE-THROW — never dissolved into the
per-item null reserved for child failures. Realm boundary: inbound values
materialized by descriptor walks that never invoke accessors (defineProperty
copies, __proto__-safe); outbound values rebuilt in-realm via the
context's own JSON.parse. Determinism bans (Date.now/Math.random/argless
new Date) kept so future resume support cannot break scripts. Caps and
timeouts are validated Config. Every hook promise carries a no-op
rejection consumer (app-boot exits on unhandled rejections).
- dsh-tool-workflow: the model-facing workflow tool, synchronous like
dsh-tool-subagent (start → await → try/finally dispose; abort bridged;
non-completed → isError). Generic render card titled by a textual
meta.name sniff. The tool description carries the authoring contract.
Wired into examples/{coding-agent,acp-agent} with explicit-ask-only
guidance. Coverage at every tier: unit (meta scanner, materializer incl.
counting-getter and __proto__ regressions, combinator semantics,
concurrency ceiling, caps, cancellation, no-unhandled-rejection abandon),
integration over the real spawn stack, with-key e2e (real two-phase run +
the tool through the registry pipeline), and a recorded ACP snapshot
scenario (workflow-run, 1 child session). RFC:
docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md (deferred
work explicitly listed). AGENTS.md budget 1575 → 1590 for the new group's
layout line.
2026-07-05 13:29:35 +08:00
async mount ( ctx ) {
// The tool injects `workflows`; boot the vm engine over a scripted
// subagent provider to satisfy it. The schema does not depend on which
// provider backs the engine.
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SubagentRuntime )
2026-07-19 11:54:37 +08:00
registerCatalogSubagentProvider ( ctx , 'mock' )
workflow: dynamic workflows — script-driven multi-agent orchestration
A new capability family at packages/workflow/ in the bash seam shape,
modeled on Claude Code's dynamic workflows: the model writes a JavaScript
orchestration script (export const meta = {...} + plain-JS body), a runtime
executes it, and the script — not the conversation — holds the loop, the
branching, and the intermediate results.
- dsh-workflow (ctx.workflows): abstract WorkflowService + run vocabulary
(WorkflowRun whose result NEVER rejects) + observe-only workflow/* events
carrying data snapshots (id + meta, never the live run), per-listener
contained like subagent/*.
- dsh-workflow-vm: in-process node:vm engine. Meta extraction via a
string/comment-aware scanner (template interpolation rejected; literal
evaluated alone in an empty timed context; statement blanked line-
preservingly so stacks keep script line numbers). Hooks: agent(prompt,
{label, phase, schema, model}) over ctx.subagents, parallel(), pipeline()
(no cross-stage barrier), phase(), log(), args. Fatal-vs-null discipline:
hook misuse (unknown/deferred options, bad arguments, unsupported
schemas, tripped caps, seam start failures, cancellation) throws fatal
WorkflowErrors the combinators RE-THROW — never dissolved into the
per-item null reserved for child failures. Realm boundary: inbound values
materialized by descriptor walks that never invoke accessors (defineProperty
copies, __proto__-safe); outbound values rebuilt in-realm via the
context's own JSON.parse. Determinism bans (Date.now/Math.random/argless
new Date) kept so future resume support cannot break scripts. Caps and
timeouts are validated Config. Every hook promise carries a no-op
rejection consumer (app-boot exits on unhandled rejections).
- dsh-tool-workflow: the model-facing workflow tool, synchronous like
dsh-tool-subagent (start → await → try/finally dispose; abort bridged;
non-completed → isError). Generic render card titled by a textual
meta.name sniff. The tool description carries the authoring contract.
Wired into examples/{coding-agent,acp-agent} with explicit-ask-only
guidance. Coverage at every tier: unit (meta scanner, materializer incl.
counting-getter and __proto__ regressions, combinator semantics,
concurrency ceiling, caps, cancellation, no-unhandled-rejection abandon),
integration over the real spawn stack, with-key e2e (real two-phase run +
the tool through the registry pipeline), and a recorded ACP snapshot
scenario (workflow-run, 1 child session). RFC:
docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md (deferred
work explicitly listed). AGENTS.md budget 1575 → 1590 for the new group's
layout line.
2026-07-05 13:29:35 +08:00
await ctx . plugin ( VmWorkflowEngine , { provider : 'mock' } )
await ctx . plugin ( ToolWorkflow )
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
} ,
} ,
2026-07-03 16:49:00 +08:00
{
pkg : '@deepseek-ai/dsh-tool-web' ,
dir : 'tool-web' ,
source : 'packages/web/tool-web/src/index.ts' ,
2026-07-05 01:25:58 +08:00
requires : [ 'ctx.tools' , 'ctx.web' , 'ctx.systemPrompt' ] ,
writes : [ 'tool/call' , 'tool/result' ] ,
2026-07-03 16:49:00 +08:00
async mount ( ctx ) {
2026-07-13 23:27:00 +08:00
// Mount search and fetch providers so both tools register. Their schemas
// do not depend on provider identity or availability.
2026-08-13 00:36:22 +08:00
await ctx . plugin ( WebRuntime )
2026-07-03 16:49:00 +08:00
await ctx . plugin ( WebSearchExa )
await ctx . plugin ( WebFetchLocal )
await ctx . plugin ( ToolWeb )
} ,
2026-07-05 01:25:58 +08:00
note :
'web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps.' ,
2026-07-03 16:49:00 +08:00
} ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
]
/** One package's contribution to the catalog: its schemas plus attribution. */
interface CatalogPackage {
pkg : string
2026-07-27 13:54:19 +08:00
sources : Readonly < Record < string , string > >
2026-07-05 01:25:58 +08:00
requires : string [ ]
writes : string [ ]
shippedNames? : string [ ]
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
schemas : ToolSchema [ ]
2026-07-02 03:16:17 +08:00
/** A deployment note (see {@link ToolPackage.note}), rendered after the tools. */
note? : string
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
}
/** The whole catalog: one entry per booted tool package, in manifest order. */
export type ToolCatalog = CatalogPackage [ ]
/ * *
* Assert the boot manifest covers every shipped tool package on disk ( a
* ` tool-* ` leaf under ` packages/ ` ) .
* Booting has no source declaration to enumerate , so this glob restores the
* "a new tool cannot be silently undocumented" guarantee : an unlisted package
* fails the generator ( and the freshness gate ) until it is added to
* { @link TOOL_PACKAGES } . Exported for a direct negative test .
*
* ` scanRoot ` defaults to the repo root ; a test may point it at a fixture tree .
* /
export function assertManifestComplete ( packages : ToolPackage [ ] = TOOL_PACKAGES , scanRoot : string = root ) : void {
const onDisk = globSync ( 'packages/*/tool-*' , { cwd : scanRoot } ) . map ( p = > basename ( p ) ) . sort ( )
const listed = new Set ( packages . map ( p = > p . dir ) )
const missing = onDisk . filter ( dir = > ! listed . has ( dir ) )
if ( missing . length > 0 ) {
throw new Error (
` gen-tool-catalog: ${ missing . length } tool package(s) not in the boot manifest: ${ missing . join ( ', ' ) } . `
+ 'Add each to TOOL_PACKAGES in scripts/gen-tool-catalog.ts so its schema is catalogued.' ,
)
}
}
2026-08-12 23:51:31 +08:00
/ * *
* Assert one manifest entry actually registered a tool .
*
* A tool package that boots without registering anything is a broken boot , not
* an empty catalog section . The usual cause is an ` inject ` the entry ' s ` mount `
* does not satisfy : cordis leaves the plugin PENDING , every step here still
2026-08-22 13:10:23 +08:00
* succeeds , and the generator writes a catalog missing that package ' s tools .
* The freshness gate stays green because regeneration reproduces the omission .
* { @link assertManifestComplete } cannot see this : the
2026-08-12 23:51:31 +08:00
* package IS listed , it just contributed nothing .
* @param entry - the manifest entry that was booted .
* @param harvested - how many schemas its boot registered .
* @throws when the boot registered no tool at all .
* /
export function assertToolsHarvested ( entry : ToolPackage , harvested : number ) : void {
if ( harvested > 0 ) return
throw new Error (
` gen-tool-catalog: ${ entry . pkg } booted without registering a single tool. `
+ 'Its plugin is most likely PENDING on a service this manifest entry does not mount — '
+ ` compare the plugin's inject with mount() and requires: ${ entry . requires . join ( ', ' ) } . ` ,
)
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/ * *
* Boot each tool package on a fresh Context and harvest its model - facing
* schemas . A fresh Context per package keeps attribution clean ( each entry ' s
* schemas come from exactly that package ) and isolates a boot failure to its
* own entry . Disposed after harvest so no executor / provider outlives the run .
* /
export async function collectToolCatalog ( packages : ToolPackage [ ] = TOOL_PACKAGES ) : Promise < ToolCatalog > {
assertManifestComplete ( packages )
const catalog : ToolCatalog = [ ]
for ( const entry of packages ) {
const ctx = new Context ( )
2026-07-02 03:16:17 +08:00
// Dispose in `finally` so a throw from `mount`/`schemas()` after earlier
// plugins mounted still tears the context down (no leaked executor/provider
// fiber) — the repo's "dispose must reach quiescence" rule.
try {
2026-08-19 13:57:58 +08:00
await ctx . plugin ( SessionProjectionRegistry )
2026-07-02 03:16:17 +08:00
await ctx . plugin ( SystemPrompt )
2026-08-13 00:36:22 +08:00
await ctx . plugin ( ToolRuntime , entry . toolsConfig ? ? { } )
2026-07-02 03:16:17 +08:00
await entry . mount ( ctx )
2026-07-31 22:45:21 +08:00
const schemas = ctx . tools . schemas ( entry . scope ? . ( ctx ) ) . sort ( ( a , b ) = > a . name . localeCompare ( b . name ) )
2026-08-12 23:51:31 +08:00
assertToolsHarvested ( entry , schemas . length )
2026-07-05 01:25:58 +08:00
catalog . push ( {
pkg : entry.pkg ,
2026-07-27 13:54:19 +08:00
sources : Object.fromEntries ( schemas . map ( schema = > [
schema . name ,
toolSource ( entry , schema . name ) ,
] ) ) ,
2026-07-05 01:25:58 +08:00
requires : entry.requires ,
writes : entry.writes ,
schemas ,
. . . entry . shippedNames !== undefined ? { shippedNames : entry.shippedNames } : { } ,
. . . entry . note !== undefined ? { note : entry.note } : { } ,
} )
2026-07-02 03:16:17 +08:00
} finally {
await ctx . fiber . dispose ( )
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
}
return catalog
}
2026-07-27 13:54:19 +08:00
/** Resolve one harvested tool to the plugin source that registered it. */
function toolSource ( entry : ToolPackage , toolName : string ) : string {
if ( typeof entry . source === 'string' ) return entry . source
const source = entry . source [ toolName ]
if ( source === undefined ) {
throw new Error (
` gen-tool-catalog: ${ entry . pkg } has no source mapping for harvested tool ${ toolName } ` ,
)
}
return source
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/** Render one tool's entry: name, description, JSON-Schema parameters, source. */
function renderTool ( schema : ToolSchema , source : string ) : string [ ] {
const out = [ ` ### \` ${ schema . name } \` ` , '' ]
if ( schema . description ) out . push ( schema . description , '' )
out . push ( '```json' , JSON . stringify ( schema . parameters , null , 2 ) , '```' , '' )
2026-07-06 22:26:06 +08:00
out . push ( ` Source: [ \` ${ source } \` ](../ ${ source } ) ` , '' )
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
return out
}
2026-07-05 01:25:58 +08:00
function codeList ( values : string [ ] | undefined ) : string {
return values ? . length ? values . map ( value = > ` \` ${ value } \` ` ) . join ( ', ' ) : '-'
}
function tableCell ( value : string | undefined ) : string {
return value ? value . replace ( /\|/g , '\\|' ) . replace ( /\n/g , '<br>' ) : '-'
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
/** Render the full catalog (pure, deterministic given the manifest-ordered input). */
export function render ( catalog : ToolCatalog ) : string {
const lines : string [ ] = [
'<!-- Generated by scripts/gen-tool-catalog.ts — do not edit by hand.' ,
' Run `pnpm run gen-tool-catalog` to regenerate. -->' ,
'' ,
'# Tool Schema Catalog' ,
'' ,
2026-07-24 19:54:25 +08:00
'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 [subsystem pages](subsystems/core.md) (the types plus each page\'s generated Cordis API region) — this page is the *tools* the agent is offered.' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
'' ,
2026-07-19 22:50:49 +08:00
'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 Agent Note](../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md).' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
'' ,
2026-07-24 19:54:25 +08:00
'Scope: shipped product tools under `packages/*/tool-*`, each booted with its DEFAULT config, except where a Config field is REQUIRED with no default — there the generator must choose, and the per-package note records which branch this page shows. The registered tool NAME can be a load-time config (e.g. `tool-subagent`\'s `toolName`), so a deployment may expose 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.' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
'' ,
2026-07-05 01:25:58 +08:00
'## 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 |' ,
'| --- | --- | --- | --- | --- | --- |' ,
. . . catalog . map ( entry = > ` | \` ${ entry . pkg } \` | ${ codeList ( entry . schemas . map ( schema = > schema . name ) ) } | ${ codeList ( entry . requires ) } | ${ codeList ( entry . writes ) } | ${ codeList ( entry . shippedNames ) } | ${ tableCell ( entry . note ) } | ` ) ,
'' ,
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
]
for ( const entry of catalog ) {
2026-08-13 13:43:43 +08:00
lines . push ( ` <a id=" ${ githubSlug ( entry . pkg ) } "></a> ` , '' , ` ## \` ${ entry . pkg } \` ` , '' )
2026-07-27 13:54:19 +08:00
for ( const schema of entry . schemas ) {
// Collection validated that every harvested schema has a source.
2026-07-31 22:45:21 +08:00
const source = entry . sources [ schema . name ] as string
lines . push ( . . . renderTool ( schema , source ) )
2026-07-27 13:54:19 +08:00
}
2026-07-02 03:16:17 +08:00
if ( entry . note ) lines . push ( entry . note , '' )
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
}
return lines . join ( '\n' )
}
/ * * C L I e n t r y : d e f a u l t w r i t e s t h e c a t a l o g , ` - - c h e c k ` f a i l s i f t h e c o m m i t t e d c o p y
* is stale . Guarded behind an entry - point check so importing this module for
* tests neither regenerates the committed file nor calls process . exit . * /
async function main ( ) : Promise < void > {
const content = render ( await collectToolCatalog ( ) )
if ( process . argv . includes ( '--check' ) ) {
let committed : string | null = null
try {
committed = readFileSync ( resolve ( root , OUT ) , 'utf8' )
} catch {
// Only ENOENT (not yet generated) is expected; a present-but-unreadable
// file is not a state this repo produces. Either way the remedy is the
// same — regenerate — so treat a read failure as "stale".
committed = null
}
if ( committed === content ) {
console . log ( ` gen-tool-catalog: ${ OUT } is up to date. ` )
process . exit ( 0 )
}
console . error ( ` gen-tool-catalog: ${ OUT } is stale. Run \` pnpm run gen-tool-catalog \` and commit ${ OUT } . ` )
2026-08-07 16:53:58 +08:00
const committedLines = committed ? . split ( '\n' ) ? ? [ ]
const generatedLines = content . split ( '\n' )
const lineCount = Math . max ( committedLines . length , generatedLines . length )
for ( let index = 0 ; index < lineCount ; index += 1 ) {
if ( committedLines [ index ] === generatedLines [ index ] ) continue
console . error ( ` gen-tool-catalog: first difference at line ${ index + 1 } ` )
console . error ( ` committed: ${ JSON . stringify ( committedLines [ index ] ) } ` )
console . error ( ` generated: ${ JSON . stringify ( generatedLines [ index ] ) } ` )
break
}
feat(docs): generate a tool-schema catalog by booting the tool plugins
Add docs/tool-catalog/tools.md, a generated reference of every model-facing
tool a shipped `packages/*/tool-*` plugin contributes (name, description,
JSON-Schema parameters) — the third generated catalog alongside the cordis
events/services and core-data-structures catalogs.
Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each
tool plugin on a real cordis Context and reads `ctx.tools.schemas()`, because a
tool schema is not statically knowable: `todo_write` builds its enum with a
runtime spread, descriptions are string-concatenated, `subagent`'s name is
config-driven, and MCP tools register raw JSON Schema without `defineTool`. A
completeness guard globs the on-disk `tool-*` packages and fails if any is
absent from the boot manifest, restoring the "nothing silently omitted"
property booting would otherwise lose. `verify-tool-catalog` runs inside
`doc-sync`, so the artifact cannot drift.
The boot-over-AST decision and the discovered-inventory / hand-written-recipe
split are recorded in a process RFC.
2026-07-02 02:20:24 +08:00
process . exit ( 1 )
}
writeFileSync ( resolve ( root , OUT ) , content )
console . log ( ` gen-tool-catalog: wrote ${ OUT } . ` )
}
if ( process . argv [ 1 ] && import . meta . filename === resolve ( process . argv [ 1 ] ) ) {
await main ( )
}