refactor: apply repository naming contract

Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
Tianyi Cui
2026-08-13 00:36:22 +08:00
parent 101df7cf58
commit a2d0f7f411
3281 changed files with 21730 additions and 21592 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/examples/agent-spine-demo/README.md
README.md: 789715e53038f610d1e2db79cf56f9aabd681fac
README.zh.md: 7a861297d76d18d5e55539334ca8e7ee5ffef640
README.md: 2d48b65e5b5cf08d62bac8b07967965fe38bdd77
README.zh.md: 83df672b540649f58b112a08ba0792ca2cb72295

View File

@@ -18,13 +18,13 @@ Read this package for the whole plugin tree and its composition order.
@deepseek-ai/dsh-system-prompt prompt-section + tool-schema assembly
@deepseek-ai/dsh-tools registry + guarded pre/around/post/final-result pipeline
@deepseek-ai/dsh-skill skill provider registry
@deepseek-ai/dsh-skill-local local filesystem skill provider
@deepseek-ai/dsh-skill-filesystem local filesystem skill provider
@deepseek-ai/dsh-agent agent registry + initiator scope + agent/* events
@deepseek-ai/dsh-goal optional persisted same-session goal domain
@deepseek-ai/dsh-tool-goal optional model-facing goal controls
@deepseek-ai/dsh-goal-session optional same-session goal-round driver
@deepseek-ai/dsh-goal-round-driver optional same-session goal-round driver
@deepseek-ai/dsh-llm-retry provider-routed request retry policy
@deepseek-ai/dsh-tasks-local generic background-task registry
@deepseek-ai/dsh-jobs-local generic background-job registry
@deepseek-ai/dsh-invariants configurable invariant registry service
@deepseek-ai/dsh-session/invariant
@deepseek-ai/dsh-agent/invariant
@@ -32,9 +32,9 @@ Read this package for the whole plugin tree and its composition order.
@deepseek-ai/dsh-agent-loop/invariant
package-owned relational checks
@deepseek-ai/dsh-tool-bash the model-facing bash schema (unless toolBash=false)
@deepseek-ai/dsh-workspace-context AGENTS.md/CLAUDE.md workspace context loader
@deepseek-ai/dsh-agent-instructions AGENTS.md/CLAUDE.md workspace context loader
@deepseek-ai/dsh-tool-skill session-prefix skill catalog + model-facing loader schema
@deepseek-ai/dsh-tool-tasks task_output/task_list/task_kill schemas + completion notices
@deepseek-ai/dsh-tool-jobs job_output/job_list/job_kill schemas + completion notices
@deepseek-ai/dsh-agent-loop THE concrete loop (gets the forwarded `agents`)
(dsh-system-prompt gets the forwarded `persona`)
```
@@ -44,8 +44,8 @@ Read this package for the whole plugin tree and its composition order.
The spine is everything COMMON to every entry point. The swappable and entry-point-coupled pieces stay out, picked by whatever loads the bundle:
- **the LLM adapter** — the bundle ships the abstract `llm` service; the leaf registers a concrete adapter on `ctx.llm` (`llm-deepseek`, `llm-pi-ai`, `llm-replay`).
- **model-backed session-title providers** — the bundle mounts the fallback service with overridable example limits (5 words, 40 fallback bytes, 80 accepted-title bytes); a leaf may opt into exactly one first-message or all-messages LLM provider.
- **the bash executor** — the bundle ships `tool-bash` (the consumer schema); the leaf provides `ctx.bash` (`bash-local` or a sandboxed impl).
- **model-backed session-title providers** — the bundle mounts the fallback service with overridable example limits (5 words, 40 fallback bytes, 80 accepted-title bytes); a leaf may opt into exactly one first-prompt or all-messages LLM provider.
- **the bash executor** — the bundle ships `tool-bash` (the consumer schema); the leaf provides `ctx.shell` (`bash-local` or a sandboxed impl).
- **non-local skill providers** — the bundle ships the skill registry, the local filesystem provider, and the `skill` tool; deployments can add other providers such as embedded or remote catalogs as siblings.
- **entry point + per-app infrastructure** — headless, ACP, and JSON-RPC app packages own transport, stdout, and reload choices. `timer` stays in the spine because it is common and stdout-silent.
@@ -55,13 +55,13 @@ This applies the [Service Definition / Service provider / Consumer separation](.
```ts
import type { Config } from '@deepseek-ai/dsh-agent-spine-demo'
// { agents?, maxParallelToolCalls?, includeHarnessIdentity?, persona?, toolOrder?, tools?, dshHome?, sessionTitle?, skills?, workspaceContext, toolBash?, tasks?, toolTasks?, goals?, invariants? }
// { agents?, maxParallelToolCalls?, includeHarnessIdentity?, persona?, toolOrder?, tools?, dshHome?, sessionTitle?, skills?, workspaceContext, toolBash?, jobs?, toolJobs?, goals?, invariants? }
// workspaceContext requires { maxBytes } or false; the other owner schemas supply defaults.
```
The bundle forwards each field to the child that owns it. App packages supply any pre-created agents: headless and JSON-RPC compositions create `main`, while the ACP app creates agents on demand at `session/new`. Prompt, tool, title, skill, workspace-context, invariant, goal, and task settings retain the schemas and defaults documented by their owning packages; `tasks.maxConcurrentTasksPerOwner` configures the local provider independently of the model-facing `toolTasks` controls. `pickSpineConfig()` copies only fields owned by this bundle, and conflicting `dshHome` values fail during composition.
The bundle forwards each field to the child that owns it. App packages supply any pre-created agents: headless and JSON-RPC compositions create `main`, while the ACP app creates agents on demand at `session/new`. Prompt, tool, title, skill, agent-instructions, invariant, goal, and task settings retain the schemas and defaults documented by their owning packages; `jobs.maxConcurrentJobsPerOwner` configures the local provider independently of the model-facing `toolJobs` controls. `pickSpineConfig()` copies only fields owned by this bundle, and conflicting `dshHome` values fail during composition.
For example, `{ invariants: { enabled: true, package_allowlist: ['^@deepseek-ai/dsh-'], package_blocklist: ['agent-loop$'] } }` keeps the package-owned companions mounted but suppresses the blocked owner. Blocklist matches override allowlist matches; see [`dsh-invariants`](../../support/invariants/README.md) for regex and lifecycle rules.
For example, `{ invariants: { enabled: true, package_allowlist: ['^@deepseek-ai/dsh-'], package_blocklist: ['agent-loop$'] } }` keeps the package-owned companions mounted but suppresses the blocked owner. Blocklist matches override allowlist matches; see [`dsh-invariants`](../../runtime-diagnostics/invariants/README.md) for regex and lifecycle rules.
## Why a code bundle, not a shared YAML include

View File

@@ -18,13 +18,13 @@
@deepseek-ai/dsh-system-prompt prompt-section + tool-schema assembly
@deepseek-ai/dsh-tools registry + guarded pre/around/post/final-result pipeline
@deepseek-ai/dsh-skill skill provider registry
@deepseek-ai/dsh-skill-local local filesystem skill provider
@deepseek-ai/dsh-skill-filesystem local filesystem skill provider
@deepseek-ai/dsh-agent agent registry + initiator scope + agent/* events
@deepseek-ai/dsh-goal optional persisted same-session goal domain
@deepseek-ai/dsh-tool-goal optional model-facing goal controls
@deepseek-ai/dsh-goal-session optional same-session goal-round driver
@deepseek-ai/dsh-goal-round-driver optional same-session goal-round driver
@deepseek-ai/dsh-llm-retry provider-routed request retry policy
@deepseek-ai/dsh-tasks-local generic background-task registry
@deepseek-ai/dsh-jobs-local generic background-job registry
@deepseek-ai/dsh-invariants configurable invariant registry service
@deepseek-ai/dsh-session/invariant
@deepseek-ai/dsh-agent/invariant
@@ -32,9 +32,9 @@
@deepseek-ai/dsh-agent-loop/invariant
package-owned relational checks
@deepseek-ai/dsh-tool-bash the model-facing bash schema (unless toolBash=false)
@deepseek-ai/dsh-workspace-context AGENTS.md/CLAUDE.md workspace context loader
@deepseek-ai/dsh-agent-instructions AGENTS.md/CLAUDE.md workspace context loader
@deepseek-ai/dsh-tool-skill session-prefix skill catalog + model-facing loader schema
@deepseek-ai/dsh-tool-tasks task_output/task_list/task_kill schemas + completion notices
@deepseek-ai/dsh-tool-jobs job_output/job_list/job_kill schemas + completion notices
@deepseek-ai/dsh-agent-loop THE concrete loop (gets the forwarded `agents`)
(dsh-system-prompt gets the forwarded `persona`)
```
@@ -45,7 +45,7 @@
- **LLM(大语言模型)适配器**:组合包交付抽象 `llm` 服务;叶节点在 `ctx.llm` 上注册具体适配器(`llm-deepseek`、`llm-pi-ai`、`llm-replay`)。
- **基于模型的会话标题提供方**:组合包挂载带可覆盖示例限制的后备服务(5 个词、40 个后备字节、80 个可接受标题字节);叶节点可以恰好选用一个首消息或全消息 LLM 提供方。
- **bash 执行器**:组合包交付 `tool-bash`(消费方 schema);叶节点提供 `ctx.bash`(`bash-local` 或沙箱化实现)。
- **bash 执行器**:组合包交付 `tool-bash`(消费方 schema);叶节点提供 `ctx.shell`(`bash-local` 或沙箱化实现)。
- **非本地 skill 提供方**:组合包交付 skill 注册表、本地文件系统提供方和 `skill` 工具;部署可以把嵌入式目录或远程目录等其他提供方作为同级插件添加。
- **入口与各应用基础设施**:无头、ACP(Agent Client Protocol)和 JSON-RPC 应用包负责传输、stdout 与重新加载选择。`timer` 保留在主干中,因为它是共有组件且不写 stdout。
@@ -55,13 +55,13 @@
```ts
import type { Config } from '@deepseek-ai/dsh-agent-spine-demo'
// { agents?, maxParallelToolCalls?, includeHarnessIdentity?, persona?, toolOrder?, tools?, dshHome?, sessionTitle?, skills?, workspaceContext, toolBash?, tasks?, toolTasks?, goals?, invariants? }
// { agents?, maxParallelToolCalls?, includeHarnessIdentity?, persona?, toolOrder?, tools?, dshHome?, sessionTitle?, skills?, workspaceContext, toolBash?, jobs?, toolJobs?, goals?, invariants? }
// workspaceContext requires { maxBytes } or false; the other owner schemas supply defaults.
```
组合包将每个字段转发给拥有它的子节点。应用包提供预创建的 agent:无头和 JSON-RPC 组合会创建 `main`,ACP 应用则在 `session/new` 按需创建 agent。提示词、工具、标题、skill、工作区上下文、不变式、目标和任务设置沿用其所属包记录的 schema 与默认值;`tasks.maxConcurrentTasksPerOwner` 配置本地 Service provider,并与面向模型的 `toolTasks` 控制工具相互独立。`pickSpineConfig()` 只复制该组合包拥有的字段,`dshHome` 值冲突会在组合时失败。
组合包将每个字段转发给拥有它的子节点。应用包提供预创建的 agent:无头和 JSON-RPC 组合会创建 `main`,ACP 应用则在 `session/new` 按需创建 agent。提示词、工具、标题、skill、工作区上下文、不变式、目标和任务设置沿用其所属包记录的 schema 与默认值;`jobs.maxConcurrentJobsPerOwner` 配置本地 Service provider,并与面向模型的 `toolJobs` 控制工具相互独立。`pickSpineConfig()` 只复制该组合包拥有的字段,`dshHome` 值冲突会在组合时失败。
例如,`{ invariants: { enabled: true, package_allowlist: ['^@deepseek-ai/dsh-'], package_blocklist: ['agent-loop$'] } }` 会让包拥有的配套插件保持挂载,但抑制被阻止的拥有者。Blocklist 匹配优先于 allowlist 匹配;正则表达式与生命周期规则见 [`dsh-invariants`](../../support/invariants/README.md)。
例如,`{ invariants: { enabled: true, package_allowlist: ['^@deepseek-ai/dsh-'], package_blocklist: ['agent-loop$'] } }` 会让包拥有的配套插件保持挂载,但抑制被阻止的拥有者。Blocklist 匹配优先于 allowlist 匹配;正则表达式与生命周期规则见 [`dsh-invariants`](../../runtime-diagnostics/invariants/README.md)。
## 为何使用代码组合包,而非共享 YAML include

View File

@@ -36,42 +36,42 @@
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-goal": "workspace:^",
"@deepseek-ai/dsh-goal-session": "workspace:^",
"@deepseek-ai/dsh-goal-round-driver": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-paths": "workspace:^",
"@deepseek-ai/dsh-home-paths": "workspace:^",
"@deepseek-ai/dsh-llm-retry": "workspace:^",
"@deepseek-ai/dsh-scope": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-session-title": "workspace:^",
"@deepseek-ai/dsh-skill": "workspace:^",
"@deepseek-ai/dsh-skill-local": "workspace:^",
"@deepseek-ai/dsh-skill-filesystem": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-tasks-local": "workspace:^",
"@deepseek-ai/dsh-bash-env": "workspace:^",
"@deepseek-ai/dsh-jobs-local": "workspace:^",
"@deepseek-ai/dsh-shell-env": "workspace:^",
"@deepseek-ai/dsh-tool-bash": "workspace:^",
"@deepseek-ai/dsh-tool-goal": "workspace:^",
"@deepseek-ai/dsh-tool-skill": "workspace:^",
"@deepseek-ai/dsh-tool-tasks": "workspace:^",
"@deepseek-ai/dsh-tool-jobs": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-workspace-context": "workspace:^",
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
"@deepseek-ai/cordis": "workspace:^"
},
"devDependencies": {
"@deepseek-ai/cordis-plugin-timer": "workspace:^",
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-bash-env": "workspace:^",
"@deepseek-ai/dsh-shell-env": "workspace:^",
"@deepseek-ai/dsh-bash-local": "workspace:^",
"@deepseek-ai/dsh-bash-sandbox": "workspace:^",
"@deepseek-ai/dsh-fs-local": "workspace:^",
"@deepseek-ai/dsh-fs-policy": "workspace:^",
"@deepseek-ai/dsh-fs-observation-policy": "workspace:^",
"@deepseek-ai/dsh-fs-sandbox": "workspace:^",
"@deepseek-ai/dsh-goal": "workspace:^",
"@deepseek-ai/dsh-goal-session": "workspace:^",
"@deepseek-ai/dsh-goal-round-driver": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-paths": "workspace:^",
"@deepseek-ai/dsh-home-paths": "workspace:^",
"@deepseek-ai/dsh-llm-retry": "workspace:^",
"@deepseek-ai/dsh-subprocess-local": "workspace:^",
"@deepseek-ai/dsh-sandbox-local": "workspace:^",
@@ -80,17 +80,17 @@
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-session-title": "workspace:^",
"@deepseek-ai/dsh-skill": "workspace:^",
"@deepseek-ai/dsh-skill-local": "workspace:^",
"@deepseek-ai/dsh-skill-filesystem": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-tasks": "workspace:^",
"@deepseek-ai/dsh-tasks-local": "workspace:^",
"@deepseek-ai/dsh-jobs": "workspace:^",
"@deepseek-ai/dsh-jobs-local": "workspace:^",
"@deepseek-ai/dsh-tool-bash": "workspace:^",
"@deepseek-ai/dsh-tool-fs": "workspace:^",
"@deepseek-ai/dsh-tool-goal": "workspace:^",
"@deepseek-ai/dsh-tool-skill": "workspace:^",
"@deepseek-ai/dsh-tool-tasks": "workspace:^",
"@deepseek-ai/dsh-tool-jobs": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-workspace-context": "workspace:^",
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
"@deepseek-ai/node-addon-landlock-run": "workspace:*",
"@deepseek-ai/cordis": "workspace:^"
},

View File

@@ -1,7 +1,7 @@
/**
* Default executor-less, UI-less agent spine. It bundles the common services,
* background-task registry and controls, optional persisted goals, concrete loop, local skill and
* workspace-context providers, and model-facing bash/skill consumers;
* background-job registry and controls, optional persisted goals, concrete loop, local skill and
* agent-instructions providers, and model-facing shell/skill consumers;
* deployments still choose the LLM adapter, bash executor, and presentation.
* The plugin intentionally exposes named exports only because Loader default
* unwrapping would discard its `Config` schema (see docs/postmortem/0001).
@@ -11,31 +11,31 @@
import type { Context } from '@deepseek-ai/cordis'
import Timer from '@deepseek-ai/cordis-plugin-timer'
import z from '@deepseek-ai/schemastery'
import LlmService from '@deepseek-ai/dsh-llm'
import LlmRuntime from '@deepseek-ai/dsh-llm'
import SessionStore from '@deepseek-ai/dsh-session'
import SessionTitleService, { type Config as SessionTitleConfig } from '@deepseek-ai/dsh-session-title'
import SystemPrompt, { type Config as SystemPromptConfig } from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
import SkillService, { type Config as SkillRegistryConfig } from '@deepseek-ai/dsh-skill'
import * as SkillLocal from '@deepseek-ai/dsh-skill-local'
import ToolRuntime, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
import SkillRegistry, { type Config as SkillRegistryConfig } from '@deepseek-ai/dsh-skill'
import * as SkillFileSystem from '@deepseek-ai/dsh-skill-filesystem'
import AgentRegistry from '@deepseek-ai/dsh-agent'
import GoalService, { type Config as GoalDomainConfig } from '@deepseek-ai/dsh-goal'
import * as goalSession from '@deepseek-ai/dsh-goal-session'
import * as goalSession from '@deepseek-ai/dsh-goal-round-driver'
import * as toolGoal from '@deepseek-ai/dsh-tool-goal'
import LocalTaskService, { type Config as TasksConfig } from '@deepseek-ai/dsh-tasks-local'
import InvariantService, { type Config as InvariantConfig } from '@deepseek-ai/dsh-invariants'
import LocalJobRegistry, { type Config as JobsConfig } from '@deepseek-ai/dsh-jobs-local'
import InvariantRegistry, { type Config as InvariantConfig } from '@deepseek-ai/dsh-invariants'
import * as sessionInvariant from '@deepseek-ai/dsh-session/invariant'
import * as agentInvariant from '@deepseek-ai/dsh-agent/invariant'
import * as scopeInvariant from '@deepseek-ai/dsh-scope/invariant'
import * as agentLoopInvariant from '@deepseek-ai/dsh-agent-loop/invariant'
import * as toolBash from '@deepseek-ai/dsh-tool-bash'
import * as bashEnv from '@deepseek-ai/dsh-bash-env'
import * as workspaceContext from '@deepseek-ai/dsh-workspace-context'
import * as bashEnv from '@deepseek-ai/dsh-shell-env'
import * as workspaceContext from '@deepseek-ai/dsh-agent-instructions'
import * as toolSkill from '@deepseek-ai/dsh-tool-skill'
import * as toolTasks from '@deepseek-ai/dsh-tool-tasks'
import * as toolJobs from '@deepseek-ai/dsh-tool-jobs'
import AgentLoop, { type Config as AgentLoopConfig } from '@deepseek-ai/dsh-agent-loop'
import * as llmRetry from '@deepseek-ai/dsh-llm-retry'
import { resolveDshHome } from '@deepseek-ai/dsh-paths'
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
export const name = 'agent-spine-demo'
@@ -53,7 +53,7 @@ export interface SkillConfig {
/** Registry-level discovery cache settings. */
registry?: SkillRegistryConfig
/** Local filesystem skill provider settings. */
local?: SkillLocal.Config
filesystem?: SkillFileSystem.Config
/** Model-facing skill catalog and tool settings. */
tool?: toolSkill.Config
}
@@ -75,8 +75,8 @@ export interface GoalConfig {
* `dshHome` to bash environment and local skill discovery, `sessionTitle` to
* the fallback title service, `skills` to the
* skill registry/local provider/tool consumer, `workspaceContext` to the
* workspace-context loader, `tasks` to the process-local task provider, and
* `toolBash`/`toolTasks` to the model-facing tool plugins this bundle owns.
* agent-instructions loader, `jobs` to the process-local job provider, and
* `toolBash`/`toolJobs` to the model-facing tool plugins this bundle owns.
* Provider adapters own their `retryPolicy`; this bundle always mounts its
* executor.
* `goals` opts into and configures the persisted goal domain plus its model tool
@@ -115,10 +115,10 @@ export interface Config {
skills?: SkillConfig
/** Model-facing bash tool config, or false when another plugin owns `bash`. */
toolBash?: toolBash.Config | false
/** Process-local background-task admission config. */
tasks?: TasksConfig
/** Generic background-task controls; set false to keep the task service without model-facing task tools. */
toolTasks?: toolTasks.Config | false
/** Process-local background-job admission config. */
jobs?: JobsConfig
/** Generic background-job controls; set false to keep the job service without model-facing job tools. */
toolJobs?: toolJobs.Config | false
/** Global enablement and package-name filters for invariant companions. */
invariants?: InvariantConfig
/** Opt-in persisted same-session goal stack; set false or omit to leave it unmounted. */
@@ -128,8 +128,8 @@ export interface Config {
/** The skill config schema exported for app packages that forward `skills`. */
export const SkillConfigSchema: z<SkillConfig> = z.object({
enabled: z.boolean().default(true),
registry: SkillService.Config,
local: SkillLocal.Config,
registry: SkillRegistry.Config,
filesystem: SkillFileSystem.Config,
tool: toolSkill.Config,
})
@@ -141,11 +141,11 @@ export const SessionTitleConfigSchema: z<SessionTitleConfig> = SessionTitleServi
export const ToolBashConfigSchema: z<toolBash.Config | false> =
z.union([z.const(false), toolBash.Config])
/** The process-local task registry schema exported for app packages that forward `tasks`. */
export const TasksConfigSchema: z<TasksConfig> = LocalTaskService.Config
/** The process-local job registry schema exported for app packages that forward `jobs`. */
export const JobsConfigSchema: z<JobsConfig> = LocalJobRegistry.Config
/** The task-control-tool config schema exported for app packages that forward `toolTasks`. */
export const ToolTasksConfigSchema: z<toolTasks.Config> = toolTasks.Config
/** The job-control-tool config schema exported for app packages that forward `toolJobs`. */
export const ToolJobsConfigSchema: z<toolJobs.Config> = toolJobs.Config
/** The persisted-goal config schema exported for app packages that opt in. */
export const GoalConfigSchema: z<GoalConfig> = z.object({
@@ -158,17 +158,17 @@ export const Config = z.intersect([
AgentLoop.Config,
SystemPrompt.Config,
z.object({
tools: ToolRegistry.Config,
tools: ToolRuntime.Config,
dshHome: z.string(),
sessionTitle: SessionTitleConfigSchema,
skills: SkillConfigSchema,
workspaceContext: z.union([z.const(false), workspaceContext.Config]).required(),
toolBash: ToolBashConfigSchema,
tasks: TasksConfigSchema,
toolTasks: z.union([z.const(false), ToolTasksConfigSchema]),
invariants: InvariantService.Config,
jobs: JobsConfigSchema,
toolJobs: z.union([z.const(false), ToolJobsConfigSchema]),
invariants: InvariantRegistry.Config,
goals: z.union([z.const(false), GoalConfigSchema]),
}) as unknown as z<Pick<Config, 'tools' | 'dshHome' | 'sessionTitle' | 'skills' | 'workspaceContext' | 'toolBash' | 'tasks' | 'toolTasks' | 'invariants' | 'goals'>>,
}) as unknown as z<Pick<Config, 'tools' | 'dshHome' | 'sessionTitle' | 'skills' | 'workspaceContext' | 'toolBash' | 'jobs' | 'toolJobs' | 'invariants' | 'goals'>>,
]) as unknown as z<Config>
/**
@@ -188,8 +188,8 @@ export function pickSpineConfig(config: Omit<Config, 'agents'>): Omit<Config, 'a
workspaceContext: config.workspaceContext,
...config.skills !== undefined ? { skills: config.skills } : {},
...config.toolBash !== undefined ? { toolBash: config.toolBash } : {},
...config.tasks !== undefined ? { tasks: config.tasks } : {},
...config.toolTasks !== undefined ? { toolTasks: config.toolTasks } : {},
...config.jobs !== undefined ? { jobs: config.jobs } : {},
...config.toolJobs !== undefined ? { toolJobs: config.toolJobs } : {},
...config.invariants !== undefined ? { invariants: config.invariants } : {},
...config.goals !== undefined ? { goals: config.goals } : {},
}
@@ -206,15 +206,15 @@ export function pickSpineConfig(config: Omit<Config, 'agents'>): Omit<Config, 'a
* seams, then the loop that drives them.
*/
export function apply(ctx: Context, config: Config): void {
const nestedDshHome = config.skills?.local?.dshHome
const nestedDshHome = config.skills?.filesystem?.dshHome
if (config.dshHome !== undefined && nestedDshHome !== undefined
&& resolveDshHome(config.dshHome) !== resolveDshHome(nestedDshHome)) {
throw new Error('agent-spine-demo: dshHome and skills.local.dshHome must resolve to the same directory')
throw new Error('agent-spine-demo: dshHome and skills.filesystem.dshHome must resolve to the same directory')
}
const dshHome = resolveDshHome(config.dshHome ?? nestedDshHome)
ctx.plugin(Timer)
ctx.plugin(LlmService)
ctx.plugin(LlmRuntime)
ctx.plugin(SessionStore)
ctx.plugin(SessionTitleService, config.sessionTitle ?? EXAMPLE_SESSION_TITLE_CONFIG)
// Owner schemas resolve defaults; forward toolOrder only when explicitly set.
@@ -223,11 +223,11 @@ export function apply(ctx: Context, config: Config): void {
persona: config.persona ?? '',
...config.toolOrder !== undefined ? { toolOrder: config.toolOrder } : {},
})
ctx.plugin(ToolRegistry, config.tools ?? {})
ctx.plugin(ToolRuntime, config.tools ?? {})
const skillsEnabled = config.skills?.enabled ?? true
if (skillsEnabled) {
ctx.plugin(SkillService, config.skills?.registry ?? {})
ctx.plugin(SkillLocal, Object.assign({}, config.skills?.local, { dshHome }))
ctx.plugin(SkillRegistry, config.skills?.registry ?? {})
ctx.plugin(SkillFileSystem, Object.assign({}, config.skills?.filesystem, { dshHome }))
}
ctx.plugin(AgentRegistry)
ctx.plugin(llmRetry)
@@ -236,8 +236,8 @@ export function apply(ctx: Context, config: Config): void {
ctx.plugin(toolGoal, config.goals.tool ?? {})
ctx.plugin(goalSession)
}
ctx.plugin(LocalTaskService, config.tasks ?? {})
ctx.plugin(InvariantService, config.invariants ?? {})
ctx.plugin(LocalJobRegistry, config.jobs ?? {})
ctx.plugin(InvariantRegistry, config.invariants ?? {})
ctx.plugin(sessionInvariant)
ctx.plugin(agentInvariant)
ctx.plugin(scopeInvariant)
@@ -252,7 +252,7 @@ export function apply(ctx: Context, config: Config): void {
// Both plugins prepend session-prefix messages. Registration order is the
// rendered order, so workspace instructions must precede the skill catalog.
if (skillsEnabled) ctx.plugin(toolSkill, config.skills?.tool ?? {})
if (config.toolTasks !== false) ctx.plugin(toolTasks, config.toolTasks ?? {})
if (config.toolJobs !== false) ctx.plugin(toolJobs, config.toolJobs ?? {})
ctx.plugin(AgentLoop, {
agents: config.agents ?? [],
...config.maxParallelToolCalls !== undefined ? { maxParallelToolCalls: config.maxParallelToolCalls } : {},

View File

@@ -31,8 +31,8 @@ import * as agentLoopInvariant from '@deepseek-ai/dsh-agent-loop/invariant'
const testToolSignal = new AbortController().signal
declare module '@deepseek-ai/dsh-tasks' {
interface TaskKindMap {
declare module '@deepseek-ai/dsh-jobs' {
interface JobKindMap {
probe: 'probe'
}
}
@@ -69,7 +69,7 @@ async function mount(config: agentCore.Config, withBash = false): Promise<Contex
process.env.DSH_AGENTS_HOME = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-agents-'))
const ctx = new Context()
if (withBash) {
ctx.provide('bash', {
ctx.provide('shell', {
sandboxMode: undefined,
resolve() { throw new Error('composition test does not execute bash') },
run() { throw new Error('composition test does not execute bash') },
@@ -156,7 +156,7 @@ describe('dsh-agent-spine-demo bundle', () => {
expect(ctx.get('tools')).toBeDefined()
expect(ctx.get('skills')).toBeDefined()
expect(ctx.get('agents')).toBeDefined()
expect(ctx.get('tasks')).toBeDefined()
expect(ctx.get('jobs')).toBeDefined()
expect(ctx.get('invariants')).toBeDefined()
expect(ctx.get('agentLoop')).toBeDefined()
expect(ctx.get('goals')).toBeUndefined()
@@ -302,11 +302,11 @@ describe('dsh-agent-spine-demo bundle', () => {
it('forwards task admission config to the process-local provider', async () => {
const ctx = await mount({
tasks: { maxConcurrentTasksPerOwner: 1 },
jobs: { maxConcurrentJobsPerOwner: 1 },
workspaceContext: false,
})
let settle!: (outcome: { status: 'killed' }) => void
ctx.tasks.start({
ctx.jobs.start({
kind: 'probe',
label: 'hold configured slot',
run: () => ({
@@ -314,7 +314,7 @@ describe('dsh-agent-spine-demo bundle', () => {
done: new Promise((resolve) => { settle = resolve }),
}),
})
expect(() => ctx.tasks.start({
expect(() => ctx.jobs.start({
kind: 'probe',
label: 'blocked configured task',
run: () => ({ cancel: () => {}, done: Promise.resolve({ status: 'completed' }) }),
@@ -375,7 +375,7 @@ describe('dsh-agent-spine-demo bundle', () => {
const firstRequestText = adapter.requests[0]?.messages.map(messageText).join('\n')
expect(firstRequestText).toContain('hi')
expect(firstRequestText).toContain('bundled project rule')
expect(adapter.requests[0]?.system).toContain('You are an AI agent powered by the DeepSeek Harness SDK.')
expect(adapter.requests[0]?.system).toContain('You are an AI agent powered by DeepSeek Harness.')
expect(adapter.requests[0]?.system).not.toContain('bundled project rule')
await handle.dispose()
await ctx.fiber.dispose()
@@ -384,7 +384,7 @@ describe('dsh-agent-spine-demo bundle', () => {
}
})
it('forwards workspace-context config to the bundled loader', async () => {
it('forwards agent-instructions config to the bundled loader', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-agent-spine-demo-workspace-context-disabled-'))
try {
await mkdir(join(root, '.git'), { recursive: true })
@@ -425,7 +425,7 @@ describe('dsh-agent-spine-demo bundle', () => {
workspaceContext: false,
skills: {
registry: { collectCacheMaxEntries: 4 },
local: {
filesystem: {
dshHome: join(home, '.dsh'),
agentsHome: join(agentsHome, '.agents'),
customSkillDirs: [custom],
@@ -460,7 +460,7 @@ describe('dsh-agent-spine-demo bundle', () => {
const ctx = await mount({
workspaceContext: false,
skills: {
local: {
filesystem: {
dshHome: join(home, '.dsh'),
agentsHome: join(home, '.agents'),
watchStabilityThresholdMs: 20,
@@ -598,7 +598,7 @@ describe('dsh-agent-spine-demo bundle', () => {
const ctx = await mount({
dshHome: home,
workspaceContext: false,
skills: { local: { agentsHome } },
skills: { filesystem: { agentsHome } },
}, true)
expect((await ctx.skills.list()).map(skill => skill.name)).toEqual(['shared-skill'])
@@ -610,7 +610,7 @@ describe('dsh-agent-spine-demo bundle', () => {
name: 'bash',
arguments: { command: 'true' },
}
expect(ctx.bashEnv.collect(execution)).toMatchObject({ DSH_HOME: home, DSH_SHELL: '1' })
expect(ctx.shellEnv.collect(execution)).toMatchObject({ DSH_HOME: home, DSH_SHELL: '1' })
await ctx.fiber.dispose()
})
@@ -619,9 +619,9 @@ describe('dsh-agent-spine-demo bundle', () => {
agentCore.apply(new Context(), {
dshHome: '/global-dsh-home',
workspaceContext: false,
skills: { local: { dshHome: '/nested-dsh-home' } },
skills: { filesystem: { dshHome: '/nested-dsh-home' } },
})
}).toThrow('agent-spine-demo: dshHome and skills.local.dshHome must resolve to the same directory')
}).toThrow('agent-spine-demo: dshHome and skills.filesystem.dshHome must resolve to the same directory')
})
it('delivers workspace instructions ahead of the first-step skill catalog', async () => {
@@ -665,11 +665,11 @@ describe('dsh-agent-spine-demo bundle', () => {
}
})
it('forwards its bundled tool configs to tool-bash and tool-tasks', async () => {
it('forwards its bundled tool configs to tool-bash and tool-jobs', async () => {
const ctx = await mount({
workspaceContext: false,
toolBash: { enableRunInBackground: false },
toolTasks: { waitTimeoutMs: 7, maxWaitTimeoutMs: 11 },
toolJobs: { waitTimeoutMs: 7, maxWaitTimeoutMs: 11 },
}, true)
const bash = ctx.tools.schemas().find(tool => tool.name === 'bash')
@@ -677,17 +677,17 @@ describe('dsh-agent-spine-demo bundle', () => {
expect(Object.keys((bash!.parameters as { properties: Record<string, unknown> }).properties))
.not.toContain('run_in_background')
const id = ctx.tasks.start({
const id = ctx.jobs.start({
kind: 'probe',
label: 'config forwarding probe',
run: () => ({ cancel: () => {}, done: Promise.resolve({ status: 'completed' }) }),
})
const wait = vi.spyOn(ctx.tasks, 'wait')
const wait = vi.spyOn(ctx.jobs, 'wait')
await ctx.tools.execute({
signal: testToolSignal,
callId: CallId('task-config-forwarding'),
name: 'task_output',
arguments: { task_id: id, wait: true },
name: 'job_output',
arguments: { job_id: id, wait: true },
})
expect(wait).toHaveBeenCalledWith(id, 7, undefined, testToolSignal)
@@ -699,12 +699,12 @@ describe('dsh-agent-spine-demo bundle', () => {
workspaceContext: false,
skills: { enabled: false },
toolBash: { enableRunInBackground: false },
toolTasks: false,
toolJobs: false,
}, true)
expect(ctx.tools.schemas().map(tool => tool.name)).toEqual(['bash'])
expect(ctx.get('skills')).toBeUndefined()
expect(ctx.get('tasks')).toBeDefined()
expect(ctx.get('jobs')).toBeDefined()
await ctx.fiber.dispose()
})
@@ -716,7 +716,7 @@ describe('dsh-agent-spine-demo bundle', () => {
workspaceContext: false,
skills: { enabled: false },
toolBash: false,
toolTasks: false,
toolJobs: false,
}, true)
expect(ctx.tools.schemas()).toEqual([])
@@ -738,8 +738,8 @@ describe('dsh-agent-spine-demo bundle', () => {
workspaceContext: false as const,
skills: { enabled: false },
toolBash: { enableRunInBackground: false },
tasks: { maxConcurrentTasksPerOwner: 4 },
toolTasks: false as const,
jobs: { maxConcurrentJobsPerOwner: 4 },
toolJobs: false as const,
invariants: { enabled: false },
}
@@ -753,8 +753,8 @@ describe('dsh-agent-spine-demo bundle', () => {
workspaceContext: false,
skills: appConfig.skills,
toolBash: appConfig.toolBash,
tasks: appConfig.tasks,
toolTasks: appConfig.toolTasks,
jobs: appConfig.jobs,
toolJobs: appConfig.toolJobs,
invariants: appConfig.invariants,
})
expect(agentCore.pickSpineConfig({ workspaceContext: false })).toEqual({ workspaceContext: false })
@@ -773,7 +773,7 @@ describe('dsh-agent-spine-demo bundle', () => {
it('forwards toolOrder to the system-prompt assembly', async () => {
const ctx = await mount({ toolOrder: ['zulu', TOOL_ORDER_REST], workspaceContext: false })
// The bundle's own bash tools pend on the absent `ctx.bash` executor in
// The bundle's own bash tools pend on the absent `ctx.shell` executor in
// this providerless mount, so register two plain tools to order.
for (const name of ['alpha', 'zulu']) {
ctx.get('tools')!.register({
@@ -785,7 +785,7 @@ describe('dsh-agent-spine-demo bundle', () => {
})
}
const assembly = await ctx.get('systemPrompt')!.assemble()
expect(assembly.tools.map(tool => tool.name)).toEqual(['zulu', 'alpha', 'skill', 'task_kill', 'task_list', 'task_output'])
expect(assembly.tools.map(tool => tool.name)).toEqual(['zulu', 'alpha', 'job_kill', 'job_list', 'job_output', 'skill'])
await ctx.fiber.dispose()
})

View File

@@ -5,8 +5,8 @@ import { basename, join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import { SandboxBashExecutor } from '@deepseek-ai/dsh-bash-sandbox'
import LocalSubprocessService from '@deepseek-ai/dsh-subprocess-local'
import * as FsPolicy from '@deepseek-ai/dsh-fs-policy'
import LocalSubprocessRuntime from '@deepseek-ai/dsh-subprocess-local'
import * as FsPolicy from '@deepseek-ai/dsh-fs-observation-policy'
import SandboxedFileSystem from '@deepseek-ai/dsh-fs-sandbox'
import { CallId } from '@deepseek-ai/dsh-llm'
import { LocalSandboxProvider } from '@deepseek-ai/dsh-sandbox-local'
@@ -53,14 +53,14 @@ beforeEach(async () => {
ctx = new Context()
await ctx.plugin(LocalSandboxProvider, {})
await ctx.plugin(SandboxPolicyService, { mode: 'workspace-write', workspaceRoot: fallbackRoot })
await ctx.plugin(LocalSubprocessService)
await ctx.plugin(LocalSubprocessRuntime)
await ctx.plugin(SandboxBashExecutor, { cwd: fallbackRoot, timeoutMs: 30_000 })
await ctx.plugin(SandboxedFileSystem, { cwd: fallbackRoot })
await ctx.plugin(agentSpine, {
workspaceContext: false,
skills: { enabled: false },
toolBash: { enableRunInBackground: false },
toolTasks: false,
toolJobs: false,
})
await new Promise(resolve => setTimeout(resolve, 50))
await ctx.plugin(FsPolicy)

View File

@@ -39,7 +39,7 @@
"path": "../../skill/skill"
},
{
"path": "../../skill/skill-local"
"path": "../../skill/skill-filesystem"
},
{
"path": "../../skill/tool-skill"
@@ -54,10 +54,10 @@
"path": "../../goal/tool-goal"
},
{
"path": "../../goal/goal-session"
"path": "../../goal/goal-round-driver"
},
{
"path": "../../context/workspace-context"
"path": "../../context/agent-instructions"
},
{
"path": "../../core/agent-loop"
@@ -66,25 +66,25 @@
"path": "../../llm/llm-retry"
},
{
"path": "../../support/invariants"
"path": "../../runtime-diagnostics/invariants"
},
{
"path": "../../util/paths"
"path": "../../util/home-paths"
},
{
"path": "../../bash/bash-env"
"path": "../../shell/shell-env"
},
{
"path": "../../bash/tool-bash"
"path": "../../shell/tool-bash"
},
{
"path": "../../tasks/tasks"
"path": "../../jobs/jobs"
},
{
"path": "../../tasks/tasks-local"
"path": "../../jobs/jobs-local"
},
{
"path": "../../tasks/tool-tasks"
"path": "../../jobs/tool-jobs"
}
]
}