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/README.md
README.md: 0048d14ec49776f036d841bbc0579a6867e513bb
README.zh.md: 471548fd7c1814dae48c64175a1d585d1621329a
README.md: f36d906fd0145411aca0076d0d17a093a85067ff
README.zh.md: 483ae24e60fb404f951af938c4e8d1dc0567b3b8

View File

@@ -8,7 +8,7 @@ Pre-composed plugin bundles a thin leaf `cordis.yml` loads instead of assembling
|---|---|---|
| [`agent-spine-demo/`](agent-spine-demo/README.md) | `@deepseek-ai/dsh-agent-spine-demo` | Reusable agent-spine bundle |
| [`acp-demo/`](acp-demo/README.md) | `@deepseek-ai/dsh-acp-demo` | ACP automation application bundle |
| [`jsonrpc-demo/`](jsonrpc-demo/README.md) | `@deepseek-ai/dsh-jsonrpc-demo` | External-config JSON-RPC runtime |
| [`jsonrpc-demo/`](jsonrpc-demo/README.md) | `@deepseek-ai/dsh-sdk-jsonrpc-demo` | External-config JSON-RPC runtime |
`agent-spine-demo` is the shared bundle; `acp-demo` adds its automation entry point, while `jsonrpc-demo` boots a deployment-owned plugin tree. Product one-shot execution belongs to `dsh --profile headless`; no package in this directory provides it.

View File

@@ -8,7 +8,7 @@
|---|---|---|
| [`agent-spine-demo/`](agent-spine-demo/README.md) | `@deepseek-ai/dsh-agent-spine-demo` | 可复用的 agent-spine智能体主干组合包 |
| [`acp-demo/`](acp-demo/README.md) | `@deepseek-ai/dsh-acp-demo` | ACPAgent Client Protocol自动化应用组合包 |
| [`jsonrpc-demo/`](jsonrpc-demo/README.md) | `@deepseek-ai/dsh-jsonrpc-demo` | 外部配置 JSON-RPC 运行时 |
| [`jsonrpc-demo/`](jsonrpc-demo/README.md) | `@deepseek-ai/dsh-sdk-jsonrpc-demo` | 外部配置 JSON-RPC 运行时 |
`agent-spine-demo` 是共享组合包;`acp-demo` 添加自动化入口,`jsonrpc-demo` 则启动由部署方拥有的插件树。产品单次执行由 `dsh --profile headless` 提供;本目录没有任何包提供该功能。

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/acp-demo/README.md
README.md: c1a15a424d9d66b90bbec451e220198bfe0a45df
README.zh.md: 6928590f6483b95312400adc11b9f7b7112ece4a
README.md: 10ab91716a4e3c1395a41e2cb44cb46719d8e0f3
README.zh.md: 5b664c90331e800d70bd5993d6289b7f5a8b93b8

View File

@@ -34,8 +34,8 @@ The app does not install commands, user interaction, session navigation, configu
| `workspaceContext` | required | Workspace-instruction byte budget/config, or `false`. |
| `skills` | owner defaults | Skill registry, local provider, and model-facing skill tool. |
| `toolBash` | owner defaults | Model-facing bash tool config. |
| `tasks` | `{ maxConcurrentTasksPerOwner: 10 }` | Process-local per-owner active-task admission. |
| `toolTasks` | owner defaults | Generic background-task control config, or `false`. |
| `jobs` | `{ maxConcurrentJobsPerOwner: 10 }` | Process-local per-owner active-task admission. |
| `toolJobs` | owner defaults | Generic background-job control config, or `false`. |
| `goals` | owner defaults | Persisted same-session goal domain and model tools, or `false`. |
The shipped [`examples/acp-agent/cordis.yml`](../../../examples/acp-agent/cordis.yml) adds the DeepSeek adapter, sandboxed bash and filesystem providers, one-shot approval policy, compaction, subagents, workflows, hooks, and model-facing tools. The app supplies the derived session-query index, while the model-facing query consumer remains an explicit leaf opt-in. Snapshot overlays replace only nondeterministic providers or policy values.

View File

@@ -34,8 +34,8 @@ ACPAgent Client Protocol自动化服务器应用默认 agent智能
| `workspaceContext` | 必填 | 工作区指令字节预算/配置,或 `false`。 |
| `skills` | 拥有者默认值 | skill 注册表、本地提供方和面向模型的 skill 工具。 |
| `toolBash` | 拥有者默认值 | 面向模型的 bash 工具配置。 |
| `tasks` | `{ maxConcurrentTasksPerOwner: 10 }` | 进程内按 owner 限制活动任务的准入配置。 |
| `toolTasks` | 拥有者默认值 | 通用后台任务控制配置,或 `false`。 |
| `jobs` | `{ maxConcurrentJobsPerOwner: 10 }` | 进程内按 owner 限制活动任务的准入配置。 |
| `toolJobs` | 拥有者默认值 | 通用后台任务控制配置,或 `false`。 |
| `goals` | 拥有者默认值 | 持久化的同会话目标领域与模型工具,或 `false`。 |
已交付的 [`examples/acp-agent/cordis.yml`](../../../examples/acp-agent/cordis.yml) 添加 DeepSeek 适配器、沙箱化 bash 与文件系统提供方、一次性审批策略、压缩compaction、subagent、工作流、钩子以及面向模型的工具。应用提供派生会话查询索引而面向模型的查询消费方仍由叶节点显式选用。快照 overlay 只替换非确定性提供方或策略值。

View File

@@ -51,7 +51,7 @@
"@deepseek-ai/dsh-session-query": "workspace:^",
"@deepseek-ai/dsh-session-query-sqlite": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-workspace-context": "workspace:^",
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
"@deepseek-ai/cordis": "workspace:^",
"@deepseek-ai/schemastery": "workspace:^"
},
@@ -69,7 +69,7 @@
"@deepseek-ai/dsh-session-query-sqlite": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-workspace-context": "workspace:^",
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
"@deepseek-ai/cordis": "workspace:^",
"@deepseek-ai/schemastery": "workspace:^"
}

View File

@@ -16,14 +16,14 @@ import { join } from 'node:path'
import z from '@deepseek-ai/schemastery'
import * as acp from '@deepseek-ai/dsh-acp'
import * as agentCore from '@deepseek-ai/dsh-agent-spine-demo'
import * as workspaceContext from '@deepseek-ai/dsh-workspace-context'
import ToolRegistry, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
import SessionPersistenceJsonl, {
import * as workspaceContext from '@deepseek-ai/dsh-agent-instructions'
import ToolRuntime, { type Config as ToolsConfig } from '@deepseek-ai/dsh-tools'
import JsonlSessionPersistence, {
JsonlCompressionSchema,
type JsonlCompression,
} from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as sessionCheckpointPolicy from '@deepseek-ai/dsh-session-checkpoint-policy'
import SessionQuerySqlite from '@deepseek-ai/dsh-session-query-sqlite'
import SqliteSessionQueryEngine from '@deepseek-ai/dsh-session-query-sqlite'
export const name = 'acp-demo'
const DEFAULT_PERSISTENCE_ROOT = './.sessions'
@@ -65,10 +65,10 @@ export interface Config {
skills?: agentCore.SkillConfig
/** Model-facing bash tool config forwarded through agent-core. */
toolBash?: NonNullable<agentCore.Config['toolBash']>
/** Process-local background-task admission config forwarded through agent-core. */
tasks?: NonNullable<agentCore.Config['tasks']>
/** Generic background-task controls forwarded through agent-core; set false to omit their tools. */
toolTasks?: NonNullable<agentCore.Config['toolTasks']>
/** Process-local background-job admission config forwarded through agent-core. */
jobs?: NonNullable<agentCore.Config['jobs']>
/** Generic background-job controls forwarded through agent-core; set false to omit their tools. */
toolJobs?: NonNullable<agentCore.Config['toolJobs']>
/** Persisted same-session goals; owner defaults enable them, or false disables the stack and tools. */
goals?: agentCore.GoalConfig | false
}
@@ -85,7 +85,7 @@ export const Config: z<Config> = z.object({
// order" (the owning dsh-system-prompt schema does the same), while
// schemastery's native [] default would read as an invalid configured list.
toolOrder: z.array(z.string()).default(undefined as unknown as string[]),
tools: ToolRegistry.Config,
tools: ToolRuntime.Config,
dshHome: z.string(),
sessionTitle: agentCore.SessionTitleConfigSchema,
persistenceRoot: z.string().default(DEFAULT_PERSISTENCE_ROOT),
@@ -94,8 +94,8 @@ export const Config: z<Config> = z.object({
workspaceContext: z.union([z.const(false), workspaceContext.Config]).required(),
skills: agentCore.SkillConfigSchema,
toolBash: agentCore.ToolBashConfigSchema,
tasks: agentCore.TasksConfigSchema,
toolTasks: z.union([z.const(false), agentCore.ToolTasksConfigSchema]),
jobs: agentCore.JobsConfigSchema,
toolJobs: z.union([z.const(false), agentCore.ToolJobsConfigSchema]),
goals: z.union([z.const(false), agentCore.GoalConfigSchema]),
})
/* jscpd:ignore-end */
@@ -120,7 +120,7 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
// Same rationale as the Config schema above: each entry point forwards its own
// persistence passthroughs rather than sharing a facade with stdio-demo.
/* jscpd:ignore-start */
const persistence = ctx.plugin(SessionPersistenceJsonl, {
const persistence = ctx.plugin(JsonlSessionPersistence, {
root: persistenceRoot,
...config.packChunks !== undefined ? { packChunks: config.packChunks } : {},
...(config.persistenceCompression === undefined ? {} : { compression: config.persistenceCompression }),
@@ -131,7 +131,7 @@ export async function apply(ctx: Context, config: Config): Promise<void> {
const checkpoint = ctx.plugin(sessionCheckpointPolicy)
await checkpoint
yield checkpoint.dispose
const query = ctx.plugin(SessionQuerySqlite, { path: join(persistenceRoot, 'session-query.db') })
const query = ctx.plugin(SqliteSessionQueryEngine, { path: join(persistenceRoot, 'session-query.db') })
await query
yield query.dispose
const transport = ctx.plugin(acp, { provider: config.provider, model: config.model })

View File

@@ -24,7 +24,7 @@ import * as acpAgent from '../src/index.ts'
async function mount(config: acpAgent.Config, withBash = false): Promise<Context> {
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') },
@@ -39,7 +39,7 @@ async function mount(config: acpAgent.Config, withBash = false): Promise<Context
async function isolatedSkillsConfig(catalogDescriptionMaxLength?: number): Promise<NonNullable<acpAgent.Config['skills']>> {
const home = await mkdtemp(join(tmpdir(), 'dsh-acp-demo-skills-'))
return {
local: { dshHome: join(home, '.dsh'), agentsHome: join(home, '.agents') },
filesystem: { dshHome: join(home, '.dsh'), agentsHome: join(home, '.agents') },
...catalogDescriptionMaxLength !== undefined ? { tool: { catalogDescriptionMaxLength } } : {},
}
}
@@ -96,10 +96,10 @@ describe('dsh-acp-demo composition', () => {
expect(ctx.get('sessions')).toBeDefined()
expect(ctx.get('sessionPersistence')).toBeDefined()
expect(ctx.get('sessionQuery')).toBeDefined()
expect(ctx.get('sessionReferences')).toBeUndefined()
expect(ctx.get('sessionReferenceResolver')).toBeUndefined()
expect((ctx.get('sessionPersistence') as unknown as { config: { compression?: string } }).config.compression).toBe('none')
expect(ctx.get('agentLoop')).toBeDefined()
expect(ctx.get('userInteraction')).toBeUndefined()
expect(ctx.get('userQuestions')).toBeUndefined()
expect(ctx.get('commands')).toBeUndefined()
expect(ctx.get('tools')?.get('ask_user_question')).toBeUndefined()
expect(ctx.get('goals')).toBeDefined()
@@ -163,7 +163,7 @@ describe('dsh-acp-demo composition', () => {
it('forwards skill config and dshHome into agent-spine-demo', async () => {
const skills = await isolatedSkillsConfig(6)
const ctx = await mount({ provider: 'mock', model: 'mock', persona: 'hi', dshHome: skills.local!.dshHome!, skills, workspaceContext: false })
const ctx = await mount({ provider: 'mock', model: 'mock', persona: 'hi', dshHome: skills.filesystem!.dshHome!, skills, workspaceContext: false })
ctx.skills.register({ name: 'acp-skill', description: 'ACP skill', source: 'runtime', content: 'body' })
expect(JSON.stringify(await composePrefix(ctx))).toContain('- `acp-skill`: ACP...')
await ctx.fiber.dispose()
@@ -186,12 +186,12 @@ describe('dsh-acp-demo composition', () => {
const ctx = await mount({
provider: 'mock',
model: 'mock',
tasks: { maxConcurrentTasksPerOwner: 1 },
jobs: { maxConcurrentJobsPerOwner: 1 },
skills: await isolatedSkillsConfig(),
workspaceContext: false,
})
let settle!: (outcome: { status: 'killed' }) => void
ctx.tasks.start({
ctx.jobs.start({
kind: 'bash',
label: 'hold configured slot',
run: () => ({
@@ -199,7 +199,7 @@ describe('dsh-acp-demo composition', () => {
done: new Promise((resolve) => { settle = resolve }),
}),
})
expect(() => ctx.tasks.start({
expect(() => ctx.jobs.start({
kind: 'bash',
label: 'blocked configured task',
run: () => ({ cancel: () => {}, done: Promise.resolve({ status: 'completed' }) }),
@@ -213,7 +213,7 @@ describe('dsh-acp-demo composition', () => {
model: 'mock',
workspaceContext: false,
toolBash: { enableRunInBackground: false },
toolTasks: { waitTimeoutMs: 7, maxWaitTimeoutMs: 11 },
toolJobs: { waitTimeoutMs: 7, maxWaitTimeoutMs: 11 },
skills: await isolatedSkillsConfig(),
}, true)
const bash = ctx.tools.schemas().find(tool => tool.name === 'bash')
@@ -235,7 +235,7 @@ describe('dsh-acp-demo composition', () => {
persistenceRoot: '/tmp/dsh-acp-demo-test-tool-order',
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({
@@ -252,10 +252,10 @@ describe('dsh-acp-demo composition', () => {
'alpha',
'create_goal',
'get_goal',
'job_kill',
'job_list',
'job_output',
'skill',
'task_kill',
'task_list',
'task_output',
'update_goal',
])
await ctx.fiber.dispose()

View File

@@ -32,11 +32,11 @@ const decompress = promisify(zstdDecompress)
const dshPackages = [
'examples/agent-spine-demo', 'core/agent', 'core/session', 'core/system-prompt',
'core/tools', 'core/agent-loop', 'llm/llm', 'bash/bash',
'bash/bash-local', 'bash/tool-bash', 'subprocess/subprocess', 'subprocess/subprocess-local', 'context/workspace-context', 'support/invariants', 'boot/app-boot',
'core/tools', 'core/agent-loop', 'llm/llm', 'shell/shell',
'shell/bash-local', 'shell/tool-bash', 'subprocess/subprocess', 'subprocess/subprocess-local', 'context/agent-instructions', 'runtime-diagnostics/invariants', 'boot/app-boot',
'session/session-persistence',
'session/session-checkpoint-policy', 'session/session-persistence-jsonl',
'acp/acp', 'examples/acp-demo', 'util/paths',
'acp/acp', 'examples/acp-demo', 'util/home-paths',
]
const vendorPackages = [
'cordis', 'loader', 'include', 'timer', 'hmr', 'logger-console',

View File

@@ -47,7 +47,7 @@ const CORDIS_YML = `
- id: tool-session-query
name: '@deepseek-ai/dsh-tool-session-query'
- id: timeout-policy
name: '@deepseek-ai/dsh-timeout-policy'
name: '@deepseek-ai/dsh-tool-call-timeout-policy'
- id: spill-local
name: '@deepseek-ai/dsh-spill-local'
- id: spill-policy

View File

@@ -36,7 +36,7 @@
"path": "../agent-spine-demo"
},
{
"path": "../../context/workspace-context"
"path": "../../context/agent-instructions"
},
{
"path": "../../session/session-checkpoint-policy"
@@ -45,7 +45,7 @@
"path": "../../session/session-persistence-jsonl"
},
{
"path": "../../support/invariants"
"path": "../../runtime-diagnostics/invariants"
}
]
}

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` 工具;部署可以把嵌入式目录或远程目录等其他提供方作为同级插件添加。
- **入口与各应用基础设施**无头、ACPAgent 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"
}
]
}

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/jsonrpc-demo/README.md
README.md: b2035b4caf2cadcbd5e93b27ac4aad2bdadcdb4d
README.zh.md: 40867d03c31cb44ed7b2cc20643b3838de294b92
README.md: 28060bd5a90445529a31d4b2bc34033c88fa452c
README.zh.md: c165c412fee303ebfa560657ce5c95799e91f60a

View File

@@ -1,4 +1,4 @@
# @deepseek-ai/dsh-jsonrpc-demo
# @deepseek-ai/dsh-sdk-jsonrpc-demo
English | [中文](README.zh.md)
@@ -8,7 +8,7 @@ Bin-only app that boots an external `cordis.yml`; its [`jsonrpc`](../../sdk/serv
The first non-empty channel wins: `$DSH_CORDIS_CONFIG`, then positional `argv[2]`. If neither names an existing file, the bin prints one-line usage to stderr and exits 1; there is no working-directory or built-in fallback. [`dsh-app-boot`](../../boot/app-boot/README.md) makes plugin load failures fatal. This protocol does not use `DSH_SNAPSHOT`.
A config without `dsh-jsonrpc` is valid and serves nothing; the bin does not designate a server plugin.
A config without `dsh-sdk-jsonrpc-server` is valid and serves nothing; the bin does not designate a server plugin.
## Exit lifecycle
@@ -28,6 +28,6 @@ No direct invalidation; the named consumer owns any request-prefix changes.
## Known Limitations and Deferred Work
- **The bin cannot prove that the config serves JSON-RPC** — a valid config with no `dsh-jsonrpc` entry boots successfully and serves nothing.
- **The bin cannot prove that the config serves JSON-RPC** — a valid config with no `dsh-sdk-jsonrpc-server` entry boots successfully and serves nothing.
- **No built-in or default config exists** — every launch must provide `DSH_CORDIS_CONFIG` or a positional path, and deployment owns the complete plugin tree and stdout discipline.
- **stdin EOF cuts off in-flight work** — client disappearance disposes the root immediately; callers that need orderly completion use the protocol-level `shutdown` request.

View File

@@ -1,4 +1,4 @@
# @deepseek-ai/dsh-jsonrpc-demo
# @deepseek-ai/dsh-sdk-jsonrpc-demo
[English](README.md) | 中文
@@ -8,7 +8,7 @@
第一个非空通道生效:先 `$DSH_CORDIS_CONFIG`,再位置参数 `argv[2]`。如果二者都没有指向现有文件bin 会向 stderr 打印单行用法并以 1 退出;没有工作目录回退或内置回退。[`dsh-app-boot`](../../boot/app-boot/README.md) 会使插件加载失败成为致命错误。此协议不使用 `DSH_SNAPSHOT`
不含 `dsh-jsonrpc` 的配置仍然有效只是不提供任何服务bin 不会指定服务器插件。
不含 `dsh-sdk-jsonrpc-server` 的配置仍然有效只是不提供任何服务bin 不会指定服务器插件。
## 退出生命周期
@@ -28,6 +28,6 @@ stdout 只承载 JSON-RPC 帧。bin 和启动守卫在 stderr 上输出诊断,
## 已知限制与暂缓事项
- **bin 无法证明配置提供 JSON-RPC 服务**:不含 `dsh-jsonrpc` 条目的有效配置也能成功启动,但不会提供任何服务。
- **bin 无法证明配置提供 JSON-RPC 服务**:不含 `dsh-sdk-jsonrpc-server` 条目的有效配置也能成功启动,但不会提供任何服务。
- **不存在内置或默认配置**:每次启动都必须提供 `DSH_CORDIS_CONFIG` 或位置路径;部署方负责完整的插件树和 stdout 纪律。
- **stdin EOF 会截断正在处理的工作**:客户端消失时立即释放根上下文;需要有序完成的调用方应使用协议级 `shutdown` 请求。

View File

@@ -1,5 +1,5 @@
{
"name": "@deepseek-ai/dsh-jsonrpc-demo",
"name": "@deepseek-ai/dsh-sdk-jsonrpc-demo",
"description": "Bin that boots an external Cordis config for the stdio JSON-RPC SDK runtime",
"version": "0.0.1-rc.2",
"publishConfig": {

View File

@@ -3,7 +3,7 @@
* Generic JSON-RPC agent bin. External configurations own their bare plugin
* packages; the packaged runtime uses `packaged-bin.ts` instead.
*
* @module @deepseek-ai/dsh-jsonrpc-demo/bin
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/bin
*/
import { runJsonrpcAgent } from './runner.ts'

View File

@@ -2,9 +2,9 @@
* Bin-only app package: its generic and packaged entries discover an external
* `cordis.yml` and own process exit. This module exports no composition plugin;
* the config chooses whether to load the
* {@link @deepseek-ai/dsh-jsonrpc} serving plugin.
* {@link @deepseek-ai/dsh-sdk-jsonrpc-server} serving plugin.
*
* @module @deepseek-ai/dsh-jsonrpc-demo
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo
*/
export {}

View File

@@ -1,16 +1,16 @@
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-jsonrpc-demo`.
* @module @deepseek-ai/dsh-jsonrpc-demo/invariant
* Package-owned invariant companion for `@deepseek-ai/dsh-sdk-jsonrpc-demo`.
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/invariant
*/
/* jscpd:ignore-start */
import type { Context } from '@deepseek-ai/cordis'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-jsonrpc-demo'
const PACKAGE_NAME = '@deepseek-ai/dsh-sdk-jsonrpc-demo'
/** Cordis companion plugin name. */
export const name = 'jsonrpc-demo-invariant'
export const name = 'sdk-jsonrpc-demo-invariant'
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']

View File

@@ -3,7 +3,7 @@
* Closed-runtime JSON-RPC agent bin. Bare plugins resolve from the installed
* runtime closure while relative plugins remain configuration-relative.
*
* @module @deepseek-ai/dsh-jsonrpc-demo/packaged-bin
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/packaged-bin
*/
import { runJsonrpcAgent } from './runner.ts'

View File

@@ -1,7 +1,7 @@
/**
* Shared process lifecycle for the generic and closed-runtime JSON-RPC bins.
*
* @module @deepseek-ai/dsh-jsonrpc-demo/runner
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/runner
*/
import { existsSync } from 'node:fs'

View File

@@ -18,7 +18,7 @@
"path": "../../boot/app-boot"
},
{
"path": "../../support/invariants"
"path": "../../runtime-diagnostics/invariants"
}
]
}