Merge worktree/schedule-explicit-at into worktree/schedule-fixed-rate
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
|
||||
import { globSync, readFileSync, writeFileSync } from 'node:fs'
|
||||
import { basename, resolve } from 'node:path'
|
||||
import { Context } from 'cordis'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import type { ToolSchema } from '@deepseek-ai/dsh-llm'
|
||||
import AgentRegistry from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
@@ -24,13 +24,15 @@ import * as BashEnvPlugin from '@deepseek-ai/dsh-bash-env'
|
||||
import { PwshLocalExecutor } from '@deepseek-ai/dsh-pwsh-local'
|
||||
import LocalSubprocessService from '@deepseek-ai/dsh-subprocess-local'
|
||||
import LocalFileSystem from '@deepseek-ai/dsh-fs-local'
|
||||
import { AttachmentStore } from '@deepseek-ai/dsh-attachment'
|
||||
import type { ImageAttachmentLimits, ImageAttachmentRef, SaveImageAttachment, StoredImageAttachment } from '@deepseek-ai/dsh-attachment'
|
||||
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
|
||||
import PlanModeService from '@deepseek-ai/dsh-plan-mode'
|
||||
import WebService from '@deepseek-ai/dsh-web'
|
||||
import * as WebSearchExa from '@deepseek-ai/dsh-web-search-exa'
|
||||
import * as WebFetchLocal from '@deepseek-ai/dsh-web-fetch-local'
|
||||
import SubagentService from '@deepseek-ai/dsh-subagent'
|
||||
import type { SubagentProvider } from '@deepseek-ai/dsh-subagent'
|
||||
import type { SubagentProvider, SubagentReportDelivery } from '@deepseek-ai/dsh-subagent'
|
||||
import * as ToolSubagentControl from '@deepseek-ai/dsh-tool-subagent-control'
|
||||
import * as ToolSubagentListAgents from '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
||||
import * as ToolSubagentReport from '@deepseek-ai/dsh-tool-subagent-report'
|
||||
@@ -61,6 +63,29 @@ import VmWorkflowEngine from '@deepseek-ai/dsh-workflow-workerthread'
|
||||
import * as ToolRalph from '@deepseek-ai/dsh-tool-ralph'
|
||||
import * as ToolWorkflow from '@deepseek-ai/dsh-tool-workflow'
|
||||
|
||||
/** 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,
|
||||
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'))
|
||||
}
|
||||
|
||||
override saveImage(_input: SaveImageAttachment): Promise<ImageAttachmentRef> {
|
||||
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'))
|
||||
}
|
||||
}
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const OUT = 'docs/tool-catalog.md'
|
||||
|
||||
@@ -121,7 +146,7 @@ interface ToolPackage {
|
||||
* name to its own source.
|
||||
*/
|
||||
source: string | Readonly<Record<string, string>>
|
||||
/** Services or owning runtime surfaces the package requires at execution time. */
|
||||
/** Services or owning runtimes the package requires at execution time. */
|
||||
requires: string[]
|
||||
/** Session events or other visible state the tools write or affect. */
|
||||
writes: string[]
|
||||
@@ -135,14 +160,14 @@ interface ToolPackage {
|
||||
/**
|
||||
* Config for the caller's `ToolRegistry` mount. The registry itself ships a
|
||||
* model-facing tool (`run_code`, registered under a non-native `mode`), so
|
||||
* ITS catalog entry boots the registry in the mode that surfaces it;
|
||||
* ITS catalog entry boots the registry in the mode that exposes it;
|
||||
* every other entry uses the default (native) registry.
|
||||
*/
|
||||
toolsConfig?: ToolsConfig
|
||||
/**
|
||||
* 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
|
||||
* load-time config (`tool-subagent`'s `toolName`), so one package may surface
|
||||
* load-time config (`tool-subagent`'s `toolName`), so one package may appear
|
||||
* under several names across deployments — the boot yields the package
|
||||
* DEFAULT, and this note records the shipped alternatives the model sees.
|
||||
*/
|
||||
@@ -225,7 +250,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
await ctx.plugin(ToolPwsh)
|
||||
},
|
||||
note:
|
||||
'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.bash`); it mirrors the bash tool call-for-call minus the sandbox surface — `run_in_background` runs register with the generic `ctx.tasks` runtime and are collected/stopped through the `task_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-bash-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\\...` paths and `$env:NAME` variables.',
|
||||
'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.bash`); it mirrors the bash tool call-for-call minus sandbox controls — `run_in_background` runs register with the generic `ctx.tasks` runtime and are collected/stopped through the `task_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-bash-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\\...` paths and `$env:NAME` variables.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-cordis',
|
||||
@@ -263,22 +288,24 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
await ctx.plugin(ToolStrReplaceEditor)
|
||||
},
|
||||
note:
|
||||
'Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal surface.',
|
||||
'Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal API.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-fs',
|
||||
dir: 'tool-fs',
|
||||
source: 'packages/fs/tool-fs/src/index.ts',
|
||||
requires: ['ctx.tools', 'ctx.fs', 'ctx.systemPrompt'],
|
||||
writes: ['tool/call', 'fs/write-intent or fs/edit-intent for mutations', 'fs/observed after read presence/absence or successful mutation', 'tool/result'],
|
||||
requires: ['ctx.tools', 'ctx.fs', 'ctx.systemPrompt', 'ctx.attachments (read_image registration)', 'ctx.llm + an image-capable route (read_image execution)'],
|
||||
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'],
|
||||
async mount(ctx) {
|
||||
// The tool needs `fs`; the bare provider is sufficient because policy
|
||||
// changes behavior, not schema shape.
|
||||
// changes behavior, not schema shape. The catalog seam marker opts into
|
||||
// the attachments-conditional read_image schema without attachment I/O.
|
||||
await ctx.plugin(LocalFileSystem)
|
||||
await ctx.plugin(CatalogAttachmentStore)
|
||||
await ctx.plugin(ToolFs)
|
||||
},
|
||||
note:
|
||||
'The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin.',
|
||||
'The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. `read_image` is not registered without `ctx.attachments`; its schema is route-independent, and execution refuses unless the exact routed model declares image input.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-fs-search',
|
||||
@@ -418,7 +445,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
await ctx.plugin(ToolSubagent, { provider: 'mock' })
|
||||
},
|
||||
note:
|
||||
'The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.',
|
||||
'The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance\'s description and `run_in_background` parameter follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable`, while `subagent_fork` stays `one-shot` — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-subagent-control',
|
||||
@@ -446,20 +473,22 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
pkg: '@deepseek-ai/dsh-tool-subagent-report',
|
||||
dir: 'tool-subagent-report',
|
||||
source: 'packages/subagent/tool-subagent-report/src/index.ts',
|
||||
requires: ['ctx.subagents', 'a live continuable in-process child Agent'],
|
||||
requires: ['ctx.subagents', 'ctx.systemPrompt', 'a live continuable in-process child Agent'],
|
||||
writes: ['tool/call', 'tool/result', 'a user-role message in the direct parent session'],
|
||||
async mount(ctx) {
|
||||
await ctx.plugin(AgentRegistry)
|
||||
await ctx.plugin(SubagentService)
|
||||
const { reportDelivery } = ToolSubagentReport.Config({}) as { reportDelivery: SubagentReportDelivery }
|
||||
await mountCatalogChildScope(ctx, (childCtx) => {
|
||||
ToolSubagentReport.installReportTool(childCtx, ctx, 'quiet')
|
||||
ToolSubagentReport.installReportTool(childCtx, ctx, reportDelivery)
|
||||
})
|
||||
},
|
||||
scope: ctx => catalogChildScopes.get(ctx) as Agent,
|
||||
note:
|
||||
'Registered per continuable in-process child rather than globally, so this schema is visible only '
|
||||
+ 'inside such a child and survives its global `toolFilter`. The parent-facing `send_message` tool '
|
||||
+ 'is installed independently.',
|
||||
+ '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.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-tasks',
|
||||
@@ -472,7 +501,7 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
await ctx.plugin(ToolTasks)
|
||||
},
|
||||
note:
|
||||
'The kind-agnostic background-task control surface: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the control surface that arms producers\' `ctx.tasks.start()`.',
|
||||
'The kind-agnostic background-task 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.tasks.start()`.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-todo',
|
||||
@@ -633,11 +662,11 @@ export function render(catalog: ToolCatalog): string {
|
||||
'',
|
||||
'# Tool Schema Catalog',
|
||||
'',
|
||||
'Every model-facing tool a shipped plugin contributes to `ctx.tools`: the `name`, `description`, and JSON-Schema `parameters` the model receives via the system-prompt assembly. It complements the [subsystem pages](subsystems/core.md) (the types plus each page\'s generated `cordis-surface` wiring region) — this page is the *tools* the agent is offered.',
|
||||
'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.',
|
||||
'',
|
||||
'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).',
|
||||
'',
|
||||
'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 surface a package under a different or additional name — a per-package note records those shipped aliases where they exist. The `examples/` demo tools (e.g. `echo`) are excluded, matching the cordis catalog\'s packages-only scope.',
|
||||
'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.',
|
||||
'',
|
||||
'## Tool Package Map',
|
||||
'',
|
||||
|
||||
Reference in New Issue
Block a user