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-11 11:50:39 +08:00
import type { SubagentProvider , SubagentReportDelivery } 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-07-31 22:45:21 +08:00
import * as ToolSubagentReport from '@deepseek-ai/dsh-tool-subagent-report'
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-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' ,
source : 'packages/core/tools/src/code-mode.ts' ,
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).
toolsConfig : { mode : 'code' } ,
async mount() { } ,
note :
2026-07-31 19:09:52 +08:00
'Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` 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-24 18:23:42 +08:00
await ctx . plugin ( ToolSubagent , { provider : 'mock' , enableModelSelection : 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-02 03:16:17 +08:00
note :
2026-08-24 18:23:42 +08:00
'The registered delegation name is the load-time `toolName` config (default `subagent`); the schema above shows static model selection enabled for reference. Model selection defaults off. Web presets sample the default-off Models preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Explicit compositions may instead use static `enableModelSelection`. Each instance independently controls model selection, discovery ownership, and background behavior through `enableModelSelection`, `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 )
2026-08-06 22:28:32 +08:00
await ctx . plugin ( SessionProjectionRegistry )
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
} ,
2026-07-31 22:45:21 +08:00
{
pkg : '@deepseek-ai/dsh-tool-subagent-report' ,
dir : 'tool-subagent-report' ,
source : 'packages/subagent/tool-subagent-report/src/index.ts' ,
2026-08-11 11:50:39 +08:00
requires : [ 'ctx.subagents' , 'ctx.systemPrompt' , 'a live continuable in-process child Agent' ] ,
2026-07-31 22:45:21 +08:00
writes : [ 'tool/call' , 'tool/result' , 'a user-role message in the direct parent session' ] ,
async mount ( ctx ) {
await ctx . plugin ( AgentRegistry )
2026-08-13 00:36:22 +08:00
await ctx . plugin ( SubagentRuntime )
2026-08-11 11:50:39 +08:00
const { reportDelivery } = ToolSubagentReport . Config ( { } ) as { reportDelivery : SubagentReportDelivery }
2026-07-31 22:45:21 +08:00
await mountCatalogChildScope ( ctx , ( childCtx ) = > {
2026-08-11 11:50:39 +08:00
ToolSubagentReport . installReportTool ( childCtx , ctx , reportDelivery )
2026-07-31 22:45:21 +08:00
} )
} ,
scope : ctx = > catalogChildScopes . get ( ctx ) as Agent ,
note :
'Registered per continuable in-process child rather than globally, so this schema is visible only '
2026-08-11 11:50:39 +08:00
+ 'inside such a child and survives its global `toolFilter`. The same contribution installs the '
+ 'child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing '
+ '`send_message` tool is installed independently.' ,
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(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 {
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 ( )
}