@deepseek-ai/dsh-subagent-dsh-sdk 0.1.1-rc.2 → 0.1.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/subagent/subagent-dsh-sdk/README.md
5
- README.md: 8d20b44dacd773345986e2a2fc0e6aca9470bf2c
6
- README.zh.md: 3937724c28a693e3e74cca2e1c3f1ae61766a14e
5
+ README.md: 59dc34f33a924c7cc67225a7337df2f8a3935f30
6
+ README.zh.md: 31da5276333f5ea6a90bd283639ceb495345075e
package/README.md CHANGED
@@ -1,50 +1,68 @@
1
+ ---
2
+ description: "The out-of-process SDK subagent backend for users and maintainers choosing a delegation provider, configuring a child Harness runtime command, or debugging remote child runs."
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-subagent-dsh-sdk
2
7
 
3
8
  English | [中文](README.zh.md)
4
9
 
5
- The SDK provider runs each subagent as a complete DeepSeek Harness runtime in a fresh subprocess, driven over stdio JSON-RPC through the [TypeScript SDK client](../../sdk/client/README.md). It is the second out-of-process backend beside [`subagent-acp`](../subagent-acp/README.md), differing in the wire and the child contract: the ACP backend drives any Agent Client Protocol agent; this backend drives specifically a harness SDK runtime (`dsh-jsonrpc-agent` bin or packaged executable), so the child is a full peer harness — own `cordis.yml`-decided composition, session persistence, model route, and tools.
10
+ ## Summary
6
11
 
7
- ## Start and ownership
12
+ `dsh-subagent-dsh-sdk` runs each delegated child as a complete DeepSeek Harness runtime in a fresh subprocess, driven over stdio JSON-RPC through the TypeScript SDK client. It is the second out-of-process backend beside the ACP provider, differing in the wire and the child contract: the child is a full peer harness with its own `cordis.yml`-decided composition, session persistence, model route, and tools. Each run spawns the child runtime (the resolved `@deepseek-ai/dsh` CLI under Node, or the configured `dshBin`), completes an `initialize` handshake with the configured provider and model route, submits the task, and reads the answer from the child's session events. The parent receives only the child's final assistant text or a safe error — no intermediate messages or tool traffic crosses the boundary. Choose it when the child should be a genuine Harness runtime, fully isolated from the parent harness.
8
13
 
9
- `start(request)` resolves the child's working directory, spawns the runtime through `DeepSeekHarness`, and completes the `initialize` handshake (with the configured `provider`/`model` route and optional `maxTokens` output cap) before it fulfills. Fulfillment therefore means the child runtime is ready and ownership has transferred to the caller. A spawn, handshake, or pre-publication cancellation failure rejects only after the subprocess has been reaped; a working-directory resolution failure rejects before anything is spawned.
14
+ ## Table of Contents
10
15
 
11
- The working directory resolves exactly like the ACP backend, through the seam's shared out-of-process helpers ([`dsh-subagent`](../subagent/README.md)): the configured `cwd` override when set (validated once at load), else the delegating parent session's cwd — never the server process's own cwd. The resolved path becomes the child process cwd and the workspace cwd of its SDK session.
16
+ - [Use this package](#use-this-package)
17
+ - [Understand the implementation](#understand-the-implementation)
18
+ - [Further Exploration](#further-exploration)
19
+ - [Model Experience](#model-experience)
20
+ - [Known Limitations and Deferred Work](#known-limitations-and-deferred-work)
21
+ - [Dev Note](#dev-note)
12
22
 
13
- The returned run id is minted in the parent namespace; the child runtime's session id exists only inside the child process. After publication the provider owns one SDK activity and reads the child's answer from its session events: the last complete non-empty `assistant/message` (an empty-content message that records usage is skipped), or the accumulated `text-delta` stream when no such message exists. Partial output remains available after cancellation or an error.
23
+ -----
14
24
 
15
- `dispose()` is idempotent: it settles the result locally as `aborted` (there is no wire-level prompt cancel), then closes the runtime — a bounded protocol `shutdown` request followed by the shared stdin-EOF → SIGTERM → SIGKILL ladder to actual exit.
25
+ <a id="use-this-package"></a>
26
+ ## Use this package
16
27
 
17
- ## Stop-reason mapping
28
+ Mount this provider when a delegation should run as a complete Harness runtime in its own process. The common path is explicit: mount the seam, mount this provider, and give it a command that starts an SDK runtime with its own `cordis.yml`.
18
29
 
19
- The SDK client returns an owned child activity rather than a prompt result. The provider reads the last durable `turn/end` inside that activity and maps it into the seam vocabulary: `completed` → `completed`, `max-tokens` → `max-tokens`, `aborted` → `aborted`; everything else — `error`, `interrupted`, `disposed`, a future variant, or an activity with no turn — maps to `error`, so an unclean stop is never reported as success. Transport-level failures after publication flatten to `stopReason: 'error'` through the `onError` diagnostic sink (wired to `ctx.logger.warn`); the seam contract forbids `result` rejecting.
30
+ ### When to choose it
20
31
 
21
- ## Capabilities and context
32
+ Choose this backend when the child must be a full harness peer — its own composition, session persistence, model route, and tools — rather than an agent that shares the parent's process. Choose an in-process backend when the child must share the parent's composition or honor parent-enforced non-route capabilities: this provider accepts agent route options but rejects structured output, depth caps, tool filters, and personas rather than silently omitting them.
22
33
 
23
- The provider advertises no start-time capabilities (`outputSchema`/`depthLimit`/`toolFilter`/`persona` all false) and `inheritsParentContext: false`: the child is a fresh runtime in another process, and the only parent-derived input is the workspace cwd. `dsh-tool-subagent` deployments over this provider set `maxDepth: 'provider-managed'` — the child harness owns its own recursion budget.
34
+ The provider advertises `agentOptions: true`, with `outputSchema`/`depthLimit`/`toolFilter`/`persona` false, and `inheritsParentContext: false`. Its immutable `agentRouteDefaults` publish the configured provider/model baseline to `dsh-tool-subagent` before model overrides and exact-route preflight; `start()` independently applies the same configuration defaults for direct callers and `maxTokens`. Agent route values cross the SDK wire as an explicit whitelist; the child remains a fresh runtime in another process, and the only value derived from the parent agent itself is the workspace cwd. `dsh-tool-subagent` deployments over this provider set `maxDepth: 'provider-managed'` — the child harness owns its own recursion budget.
24
35
 
25
- ## Configuration
36
+ ### Configuration
26
37
 
27
- | Key | Default | Meaning |
38
+ | Field | Default | Meaning |
28
39
  |---|---|---|
29
- | `providerName` | `dsh-sdk` | Registry name on `ctx.subagents`. |
30
- | `command` | required | Executable spawned per run (the child runtime bin or packaged exe). |
31
- | `args` | `[]` | Command arguments (typically the child's `cordis.yml` path). |
32
- | `cwd` | parent session cwd | Working-directory override; same validation as [`subagent-acp`](../subagent-acp/README.md). |
33
- | `provider` | `deepseek-official` | Provider route sent in the child's `initialize`. |
34
- | `model` | `deepseek-v4-flash` | Model sent in the child's `initialize`. |
35
- | `maxTokens` | adapter/provider route default | Per-request output-token cap sent in the child's `initialize`; it applies to the child root agent and its in-process descendants. |
36
- | `env` | `{}` | Explicit child environment layered over a credential-scrubbed parent environment (e.g. the child's own `DEEPSEEK_API_KEY`, or `DSH_CORDIS_CONFIG`). |
37
- | `shutdownTimeoutMs` | `1000` | Bound on the protocol `shutdown` exchange during dispose. |
38
- | `disposeEofGraceMs` | `6000` | Grace after stdin EOF before platform termination. |
39
- | `disposeGraceMs` | `3000` | Exit-confirmation grace after termination; POSIX also waits this long after SIGTERM before SIGKILL. |
40
+ | `providerName` | `dsh-sdk` | Registry name on `ctx.subagents` |
41
+ | `dshBin` | SDK dependency | Explicit dsh CLI module, resolved and checked at plugin load; omission uses the SDK dependency |
42
+ | `profile` | `sdk` | Named child profile |
43
+ | `patches` | `[]` | Ordered per-launch profile patch files, resolved and checked at plugin load |
44
+ | `dshHome` | required | Absolute isolated Harness home for every nested child process |
45
+ | `cwd` | parent session cwd | Working-directory override for the child process and its SDK session |
46
+ | `provider` | `deepseek-official` | Provider route sent in the child's `initialize` |
47
+ | `model` | `deepseek-v4-flash` | Model sent in the child's `initialize` |
48
+ | `maxTokens` | adapter/provider route default | Per-request output-token cap sent in the child's `initialize` |
49
+ | `env` | `{}` | Explicit child environment layered over the credential-scrubbed parent environment |
50
+ | `shutdownTimeoutMs` | `1000` | Bound on the protocol `shutdown` exchange during dispose |
51
+ | `disposeEofGraceMs` | `6000` | Grace after stdin EOF before platform termination |
52
+ | `disposeGraceMs` | `3000` | Exit-confirmation grace after termination |
53
+
54
+ The generated [configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-subagent-dsh-sdk) is the exhaustive source for every accepted field and its JSDoc.
55
+
56
+ Request `agentOptions` override `provider`, `model`, and `maxTokens` independently. `reasoningEffort` has no provider-instance default: an omitted request leaves it absent so the selected child model resolves its own default. The model-facing subagent tool can select provider/model/reasoning per call; `maxTokens` remains deployment-controlled through tool config or this provider's default.
40
57
 
41
58
  ```yaml
42
59
  - id: subagent-dsh-sdk
43
60
  name: '@deepseek-ai/dsh-subagent-dsh-sdk'
44
61
  config:
45
62
  providerName: dsh-sdk
46
- command: node
47
- args: ['./packages/examples/jsonrpc-demo/lib/bin.js', './examples/jsonrpc-agent/cordis.yml']
63
+ profile: sdk
64
+ patches: ['./profiles/research-child.cordis.yml']
65
+ dshHome: !!js dshHomePath('children')
48
66
  maxTokens: 49152
49
67
  env:
50
68
  DEEPSEEK_API_KEY: !!js process.env.DEEPSEEK_API_KEY
@@ -53,19 +71,74 @@ The provider advertises no start-time capabilities (`outputSchema`/`depthLimit`/
53
71
  config: { provider: dsh-sdk, toolName: subagent, maxDepth: 'provider-managed' }
54
72
  ```
55
73
 
56
- ## Process boundary
74
+ ### What you get
75
+
76
+ A successful run returns the child's final assistant text (or accumulated partial text after cancellation) as result output. The child's model route, tools, and session come from the child runtime itself — the parent supplies the task, working directory, and `initialize` route. The child's last durable `turn/end` maps into the seam vocabulary: `completed` and `max-tokens` pass through, `blocked` becomes `refusal`, and an unexpected or missing terminal becomes `error`. An `aborted` result stays aborted; only a child-side `disposed` cause adds a `child-disposed` diagnostic.
77
+
78
+ ### Failure and recovery
79
+
80
+ An already-aborted request fails before path resolution or spawn. A route, spawn, handshake, or pre-publication cancellation failure ordinarily rejects only after the subprocess is reaped. If initialization and cleanup both fail, the ordered safe facts preserve both failures without claiming quiescence. A child runtime that fails after publication settles through the run rather than rejecting it; partial output stays separate from the safe diagnostic. Diagnostics expose only the provider plus `initialize`, `session-run`, or `shutdown` stage and a fixed category. They never copy SDK messages, stderr, paths, task content, environment values, credentials, or protocol payloads.
81
+
82
+ -----
83
+
84
+ <a id="understand-the-implementation"></a>
85
+ ## Understand the implementation
86
+
87
+ <details>
88
+ <summary>Implementation internals — click to expand</summary>
89
+
90
+ This section explains how the backend drives a child Harness runtime and where the observable behavior comes from; the full contract lives in [Use this package](#use-this-package).
91
+
92
+ ### Design concept
93
+
94
+ - **Full harness peer.** Each child is a complete Harness runtime in its own process — own composition, session, model route, and tools; only the resolved working directory and the `initialize` route cross from the parent.
95
+ - **One runtime per run.** Every run spawns a fresh runtime process; there is no pooling.
96
+ - **The JSON-RPC wire is the serialization boundary.** Same-process subagent values are not defensively cloned; the protocol is where hostile input is validated.
97
+
98
+ ### Source map
99
+
100
+ | File | Role |
101
+ |---|---|
102
+ | [`src/index.ts`](src/index.ts) | Plugin entry: config schema, provider registration |
103
+ | [`src/run.ts`](src/run.ts) | The SDK run lifecycle, answer extraction, and stop-reason mapping |
104
+
105
+ ### Run flow
106
+
107
+ A start resolves the child's working directory and one process-wide SDK route before spawning. Each declared `request.agentOptions` field (`provider`, `model`, `reasoningEffort`, or `maxTokens`) overrides the matching provider-instance default; omission preserves the configured provider/model and optional cap, while reasoning effort remains absent unless the request supplies it. The provider spawns the runtime through the SDK client and completes the `initialize` handshake, including exact-model and effort validation, before it fulfills. A route, spawn, handshake, or pre-publication cancellation failure rejects only after the subprocess is reaped; a working-directory resolution failure rejects before spawning. After publication the provider owns one SDK activity and reads the child's answer from its session events: the last complete non-empty `assistant/message` (an empty-content message that records usage is skipped), or the accumulated `text-delta` stream when no such message exists. Disposal is idempotent: it settles the result locally as `aborted`, sends a bounded protocol `shutdown` request, then escalates through stdin EOF → SIGTERM → SIGKILL to actual exit.
108
+
109
+ ### Stop-reason mapping
57
110
 
58
- The child environment is the [`dsh-subprocess`](../../subprocess/README.md) seam's `scrubbedParentEnv()` base — ambient credential-shaped and `DSH_*` names dropped — with explicit `config.env` values merged after the scrub. The child is spawned by the SDK client rather than through `ctx.subprocess` (the subprocess README's documented exception for SDK-managed transports), which is why this backend applies the scrub itself. The JSON-RPC wire is the real serialization boundary.
111
+ The child's last `turn/end` reason maps into the shared stop-reason vocabulary in [`src/run.ts`](src/run.ts).
59
112
 
60
- The package has no default export. Cordis loader unwrapping would otherwise hide the named `inject` metadata; see [postmortem 0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.md).
113
+ ### Process boundary
61
114
 
115
+ The child environment is the subprocess seam's credential-scrubbed parent environment with explicit `config.env` values merged after the scrub. The child is spawned by the SDK client rather than through `ctx.subprocess` — the documented exception for SDK-managed transports — which is why this backend applies the scrub itself.
116
+
117
+ </details>
118
+
119
+ -----
120
+
121
+ <a id="further-exploration"></a>
122
+ ## Further Exploration
123
+
124
+ Read these pages when the package-level contract is not enough. They move from this backend to the seam it plugs into and the SDK it drives.
125
+
126
+ - [Subagent subsystem](../../../docs/subsystems/subagent.md) — the service contract, provider contract, and terminal result semantics.
127
+ - [dsh-subagent seam](../subagent/README.md) — the registry and start API this provider registers on.
128
+ - [ACP subagent backend](../subagent-acp/README.md) — the sibling out-of-process provider over the Agent Client Protocol.
129
+ - [TypeScript SDK client](../../sdk/client/README.md) — the stdio JSON-RPC client this backend drives the child through.
130
+ - [Generated configuration catalog](../../../docs/config-catalog.md#deepseek-aidsh-subagent-dsh-sdk) — every accepted config field and its source declaration.
131
+
132
+ -----
133
+
134
+ <a id="model-experience"></a>
62
135
  ## Model Experience
63
136
 
64
137
  ### Child-agent request
65
138
 
66
139
  #### What the model sees
67
140
 
68
- The child runtime's model receives the standalone task as its user message plus that runtime's own configured system prompt, tools, and fresh session. It receives no parent conversation. This provider advertises no optional start-time capabilities, so the local service rejects requests for persona, tool filtering, depth enforcement, or structured output instead of silently omitting them.
141
+ The child runtime's model receives the standalone task as its user message plus that runtime's own configured system prompt, tools, and fresh session. It receives no parent conversation. A parent tool call may choose the child provider, model, and reasoning effort for this run; the selected route and any deployment-owned output cap are fixed for the new child process. Persona, tool filtering, depth enforcement, and structured output remain unsupported and are rejected instead of silently omitted.
69
142
 
70
143
  #### Token effect
71
144
 
@@ -79,7 +152,7 @@ Independent of the parent request cache. Each SDK child can reuse only prefixes
79
152
 
80
153
  #### What the model sees
81
154
 
82
- Through `dsh-tool-subagent`, the parent receives only the child's final assistant text (or accumulated partial text) or that consumer's exact stop-reason error, not intermediate messages or tool traffic.
155
+ Through `dsh-tool-subagent`, the parent receives only the child's final assistant text (or accumulated partial text) or that consumer's exact stop-reason error, not intermediate messages or tool traffic. A diagnostic-bearing non-completed result presents the safe diagnostic before separately preserved partial assistant output; startup and shutdown errors expose the same fixed facts without raw SDK text.
83
156
 
84
157
  #### Token effect
85
158
 
@@ -91,7 +164,25 @@ Append-only; newly visible content follows the reusable request prefix and does
91
164
 
92
165
  ## Known Limitations and Deferred Work
93
166
 
167
+ <a id="known-limitations-and-deferred-work"></a>
168
+
169
+
170
+ These limits define when this backend is a poor fit or needs special operational care. They are current package constraints, not a general SDK comparison or a task backlog.
171
+
94
172
  - **A fresh runtime process per run** — no pooling; a harness runtime boots a full plugin tree, so per-run spawn cost is higher than the ACP backend's typical child.
95
- - **No optional start-time capabilities** — the parent cannot enforce `outputSchema`, depth, tool filters, or persona inside the child process; configure the child's own `cordis.yml` instead.
96
- - **The child's transcript stays in the child's own session root** — the parent log records only the delegation tool call/result (the seam's child-isolation rule); the streamed `session.event` channel is consumed for output extraction, not bridged into the parent log.
97
- - **Local child processes only** — the resolved cwd is a local path; a remote runtime would need its own backend.
173
+ - **No non-route start-time capabilities** — the parent can select the child agent route but cannot enforce `outputSchema`, depth, tool filters, or persona inside the child process; configure the selected child profile and its ordered patches instead.
174
+ - **The child's transcript stays in the child's own session root** — the parent log records only the delegation tool call and result; the streamed `session.event` channel is consumed for output extraction, not bridged into the parent log.
175
+ - **Local child processes only** — the resolved working directory is a local path; a remote runtime would need its own backend.
176
+
177
+ <a id="dev-note"></a>
178
+ ### Dev Note
179
+
180
+ <details>
181
+ <summary>Working context for maintainers — click to expand</summary>
182
+
183
+ This Dev Note is working context for maintainers: open questions and undecided directions. It is explicitly non-authoritative — shipped behavior and limits live in the sections above and in the package code.
184
+
185
+ - **Spawn cost** — the full plugin tree per run is the price of full isolation; pooling would change that trade-off.
186
+ - **Remote runtimes** — a remote runtime would need its own backend and workspace mapping.
187
+
188
+ </details>
package/README.zh.md CHANGED
@@ -1,50 +1,68 @@
1
+ ---
2
+ description: "面向用户与维护者的进程外 SDK subagent 后端,用于选择委派提供方、配置子 Harness 运行时命令或排查远程子 agent 运行问题。"
3
+ kind: "package-reference"
4
+ ---
5
+
1
6
  # @deepseek-ai/dsh-subagent-dsh-sdk
2
7
 
3
8
  [English](README.md) | 中文
4
9
 
5
- SDK 提供方会在全新的子进程中把每个 subagent 作为完整的 DeepSeek Harness 运行时运行,并经由 [TypeScript SDK 客户端](../../sdk/client/README.zh.md) 通过 stdio JSON-RPC 驱动。它是 [`subagent-acp`](../subagent-acp/README.zh.md) 之外的第二个进程外后端,差异在协议格式(wire format)和子进程约定:ACP(Agent Client Protocol)后端能驱动任何 Agent Client Protocol agent(智能体);本后端专门驱动 harness SDK 运行时(`dsh-jsonrpc-agent` bin 或打包后的可执行文件),因此子进程是一个完整的对等 harness,拥有由 `cordis.yml` 决定的组合、会话持久化、模型路由和工具。
10
+ ## 概述
6
11
 
7
- ## 启动与所有权
12
+ `dsh-subagent-dsh-sdk` 在全新的子进程中把每个被委派的子 agent(智能体)作为完整的 DeepSeek Harness 运行时运行,并经由 TypeScript SDK 客户端通过 stdio JSON-RPC 驱动。它是 ACP 提供方之外的第二个进程外后端,差异在协议格式(wire format)与子进程约定:子进程是完整的对等 harness,拥有由 `cordis.yml` 决定的组合、会话持久化、模型路由与工具。每次运行都会 spawn 子运行时(Node 下解析出的 `@deepseek-ai/dsh` CLI,或配置的 `dshBin`),以配置的提供方与模型路由完成 `initialize` 握手、提交任务,并从子进程的会话事件中读取答案。父级只收到子进程最终的 assistant 文本或安全错误——中间消息与工具流量不会跨越边界。当子进程应该是与父 harness 完全隔离的真实 Harness 运行时时,选择它。
8
13
 
9
- `start(request)` 先解析子进程工作目录,通过 `DeepSeekHarness` spawn 运行时,并在履行前完成 `initialize` 握手(携带配置的 `provider`/`model` 路由及可选的 `maxTokens` 输出上限)。因此,履行意味着子运行时已就绪、所有权已移交给调用方。spawn、握手或发布前取消失败时,只会在子进程被回收后拒绝;工作目录解析失败则会在尚未 spawn 任何内容时拒绝。
14
+ ## 目录
10
15
 
11
- 工作目录的解析与 ACP 后端完全一致,并使用 seam 共享的进程外辅助工具([`dsh-subagent`](../subagent/README.zh.md)):设置了 `cwd` 覆盖值时使用该值(加载时校验一次),否则使用发起委派的父会话 cwd,绝不使用服务器进程自身的 cwd。解析出的路径同时成为子进程 cwd 和其 SDK 会话的工作区 cwd。
16
+ - [使用本包](#use-this-package)
17
+ - [理解实现](#understand-the-implementation)
18
+ - [进一步探索](#further-exploration)
19
+ - [模型体验](#model-experience)
20
+ - [已知限制与延期工作](#known-limitations-and-deferred-work)
21
+ - [开发备注](#dev-note)
12
22
 
13
- 返回的 run id 在父级命名空间中生成;子运行时的会话 id 只存在于子进程内部。发布后,提供方拥有一段 SDK 活动,并从子会话事件中读取答案:最后一条完整且非空的 `assistant/message`(记录 usage 的空内容消息会被跳过);若没有这类消息,则取累积的 `text-delta` 流。取消或发生错误后,部分输出仍然可用。
23
+ -----
14
24
 
15
- `dispose()`(资源释放)是幂等的:先在本地把结果确定为 `aborted`(协议层面没有提示词取消机制),再关闭运行时,即先发出一次有界的协议 `shutdown` 请求,随后通过共享的 stdin-EOF → SIGTERM → SIGKILL 阶梯使进程实际退出。
25
+ <a id="use-this-package"></a>
26
+ ## 使用本包
16
27
 
17
- ## 停止原因映射
28
+ 当委派应以完整 Harness 运行时在独立进程中运行时,挂载本提供方。常用路径是显式的:挂载 seam、挂载本提供方,并给出一个启动带有自身 `cordis.yml` 的 SDK 运行时的命令。
18
29
 
19
- SDK 客户端返回自有子活动,而不是提示词结果。提供方读取该活动内最后一个已持久化的 `turn/end`,并将其映射为 seam 词汇:`completed` → `completed`,`max-tokens` → `max-tokens`,`aborted` → `aborted`;其余情况,包括 `error`、`interrupted`、`disposed`、未来变体或不含轮次的活动,均映射为 `error`,因此非正常停止绝不会报告为成功。发布后的传输层失败会通过 `onError` 诊断接收器(连接到 `ctx.logger.warn`)压平为 `stopReason: 'error'`;seam 约定禁止 `result` 被拒绝。
30
+ ### 何时选择
20
31
 
21
- ## 能力与上下文
32
+ 当子进程必须是完整的 harness 对等体——拥有自己的组合、会话持久化、模型路由与工具——而不是共享父进程的 agent 时,选择此后端。当子进程必须共享父级组合或遵守父级强制的非路由能力时,请选择进程内后端:本提供方接受 agent 路由选项,但会拒绝结构化输出、深度上限、工具过滤或 persona,而不是静默省略。
22
33
 
23
- Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilter`/`persona` 全为 false),且 `inheritsParentContext: false`:子进程是另一进程里的全新运行时,唯一来自父方的输入是工作区 cwd。基于本 provider 的 `dsh-tool-subagent` 部署应设置 `maxDepth: 'provider-managed'`——子 harness 拥有自己的递归预算。
34
+ 提供方声明 `agentOptions: true`,同时保持 `outputSchema`/`depthLimit`/`toolFilter`/`persona` 为 false,并且 `inheritsParentContext: false`。不可变的 `agentRouteDefaults` 会在模型覆盖与确切路由预检前,把配置的 provider/model 基线公开给 `dsh-tool-subagent`;`start()` 则为直接调用方与 `maxTokens` 独立应用同一份配置默认值。Agent 路由值通过显式白名单跨越 SDK 协议;子进程仍是另一进程里的全新运行时,唯一从父 agent 本身派生的值是工作区 cwd。基于本提供方的 `dsh-tool-subagent` 部署应设置 `maxDepth: 'provider-managed'`——子 harness 拥有自己的递归预算。
24
35
 
25
- ## 配置
36
+ ### 配置
26
37
 
27
- | 键 | 默认 | 含义 |
38
+ | 字段 | 默认值 | 含义 |
28
39
  |---|---|---|
29
- | `providerName` | `dsh-sdk` | `ctx.subagents` 上的注册名。 |
30
- | `command` | 必填 | 每次运行时 spawn 的可执行文件(子运行时 bin 或打包后的可执行文件)。 |
31
- | `args` | `[]` | 命令参数(通常是子进程的 `cordis.yml` 路径)。 |
32
- | `cwd` | 父会话 cwd | 工作目录覆盖;校验规则与 [`subagent-acp`](../subagent-acp/README.zh.md) 相同。 |
33
- | `provider` | `deepseek-official` | 写入子进程 `initialize` 的提供方路由。 |
34
- | `model` | `deepseek-v4-flash` | 写入子进程 `initialize` 的模型。 |
35
- | `maxTokens` | 适配器/提供方路由默认值 | 写入子进程 `initialize` 的单次请求输出 token 上限;对子运行时的根 agent 及其进程内后代生效。 |
36
- | `env` | `{}` | 在凭据擦除后的父环境之上叠加的显式子环境(例如子进程自己的 `DEEPSEEK_API_KEY`,或 `DSH_CORDIS_CONFIG`)。 |
37
- | `shutdownTimeoutMs` | `1000` | dispose 期间协议 `shutdown` 交换的时限。 |
38
- | `disposeEofGraceMs` | `6000` | stdin EOF 之后、平台终止之前的宽限。 |
39
- | `disposeGraceMs` | `3000` | 终止后的退出确认窗口;POSIX 在 SIGTERM 之后、SIGKILL 之前也等待同样时长。 |
40
+ | `providerName` | `dsh-sdk` | `ctx.subagents` 上的注册表名称 |
41
+ | `dshBin` | SDK 依赖 | 显式 dsh CLI 模块,在插件加载时解析并校验;省略则使用 SDK 依赖 |
42
+ | `profile` | `sdk` | 子进程命名的 profile |
43
+ | `patches` | `[]` | 每次启动的有序 profile patch 文件,在插件加载时解析并校验 |
44
+ | `dshHome` | 必填 | 每个嵌套子进程的绝对隔离 Harness home |
45
+ | `cwd` | 父会话 cwd | 子进程及其 SDK 会话的工作目录覆盖值 |
46
+ | `provider` | `deepseek-official` | 写入子进程 `initialize` 的提供方路由 |
47
+ | `model` | `deepseek-v4-flash` | 写入子进程 `initialize` 的模型 |
48
+ | `maxTokens` | 适配器/提供方路由默认值 | 写入子进程 `initialize` 的单次请求输出 token 上限 |
49
+ | `env` | `{}` | 叠加在已清理凭据的父环境之上的显式子环境 |
50
+ | `shutdownTimeoutMs` | `1000` | dispose 期间协议 `shutdown` 交换的时限 |
51
+ | `disposeEofGraceMs` | `6000` | stdin EOF 之后、平台终止之前的宽限 |
52
+ | `disposeGraceMs` | `3000` | 终止后的退出确认宽限 |
53
+
54
+ 生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-subagent-dsh-sdk)是每个受支持字段及其 JSDoc 的穷尽式真源。
55
+
56
+ 请求 `agentOptions` 会分别覆盖 `provider`、`model` 与 `maxTokens`。`reasoningEffort` 没有提供方实例默认值:请求省略时保持缺省,由所选子模型解析自身默认值。面向模型的 subagent 工具可在每次调用时选择提供方/模型/推理强度;`maxTokens` 仍由工具配置或本提供方默认值在部署侧控制。
40
57
 
41
58
  ```yaml
42
59
  - id: subagent-dsh-sdk
43
60
  name: '@deepseek-ai/dsh-subagent-dsh-sdk'
44
61
  config:
45
62
  providerName: dsh-sdk
46
- command: node
47
- args: ['./packages/examples/jsonrpc-demo/lib/bin.js', './examples/jsonrpc-agent/cordis.yml']
63
+ profile: sdk
64
+ patches: ['./profiles/research-child.cordis.yml']
65
+ dshHome: !!js dshHomePath('children')
48
66
  maxTokens: 49152
49
67
  env:
50
68
  DEEPSEEK_API_KEY: !!js process.env.DEEPSEEK_API_KEY
@@ -53,19 +71,74 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
53
71
  config: { provider: dsh-sdk, toolName: subagent, maxDepth: 'provider-managed' }
54
72
  ```
55
73
 
56
- ## 进程边界
74
+ ### 你会得到什么
75
+
76
+ 成功的运行会把子进程最终的 assistant 文本(或取消后累积的部分文本)作为结果输出返回。子进程的模型路由、工具与会话来自子运行时自身——父级提供任务、工作目录与 `initialize` 路由。子进程最后一个持久化 `turn/end` 会映射进 seam 词汇:`completed` 与 `max-tokens` 原样通过,`blocked` 变为 `refusal`,意外终态或缺少终态变为 `error`。`aborted` 结果保持中止;只有子进程侧 `disposed` 原因会附加 `child-disposed` 诊断。
77
+
78
+ ### 失败与恢复
79
+
80
+ 已取消的请求会在路径解析或 spawn 之前失败。路由、spawn、握手或发布前取消失败通常只在子进程被回收后拒绝;如果初始化与清理均失败,有序安全事实会保留两项失败,而不会宣称已完全停稳。子运行时在发布后失败时会通过运行本身结算,而不是拒绝;部分输出与安全诊断保持分离。诊断只公开提供方、`initialize`、`session-run` 或 `shutdown` 阶段,以及固定类别。SDK 消息、stderr、路径、任务内容、环境值、凭据和协议载荷绝不会复制到诊断中。
81
+
82
+ -----
83
+
84
+ <a id="understand-the-implementation"></a>
85
+ ## 理解实现
86
+
87
+ <details>
88
+ <summary>实现细节——点击展开</summary>
89
+
90
+ 本节解释后端如何驱动子 Harness 运行时,以及可观察行为从何而来;完整约定见[使用本包](#use-this-package)。
91
+
92
+ ### 设计理念
93
+
94
+ - **完整 harness 对等体。** 每个子进程都是独立进程中的完整 Harness 运行时——拥有自己的组合、会话、模型路由与工具;只有解析后的工作目录与 `initialize` 路由从父级跨越。
95
+ - **每次运行一个运行时。** 每次运行都 spawn 全新运行时进程;没有进程池。
96
+ - **JSON-RPC 协议格式是序列化边界。** 同进程 subagent 值不会为防御目的克隆;协议才是校验不可信输入的地方。
97
+
98
+ ### 源码地图
99
+
100
+ | 文件 | 职责 |
101
+ |---|---|
102
+ | [`src/index.ts`](src/index.ts) | 插件入口:config schema、提供方注册 |
103
+ | [`src/run.ts`](src/run.ts) | SDK 运行生命周期、答案提取与停止原因映射 |
104
+
105
+ ### 运行流程
106
+
107
+ 一次启动会在 spawn 前解析子进程工作目录与一条进程级 SDK 路由。`request.agentOptions` 中每个已声明字段(`provider`、`model`、`reasoningEffort` 或 `maxTokens`)都会覆盖对应的提供方实例默认值;省略时保留已配置的提供方/模型与可选上限,而推理强度只有在请求提供时才会出现。随后,提供方通过 SDK 客户端 spawn 运行时,并在履行前完成 `initialize` 握手,其中包括确切模型与推理强度校验。路由、spawn、握手或发布前取消失败时,只会在子进程被回收后拒绝;工作目录解析失败则会在尚未 spawn 任何内容时拒绝。发布后,提供方拥有一段 SDK 活动,并从子会话事件中读取答案:最后一条完整且非空的 `assistant/message`(记录 usage 的空内容消息会被跳过);若没有这类消息,则取累积的 `text-delta` 流。dispose(资源释放)是幂等的:先在本地把结果确定为 `aborted`,发出有界的协议 `shutdown` 请求,再经 stdin EOF → SIGTERM → SIGKILL 升级到实际退出。
108
+
109
+ ### 停止原因映射
57
110
 
58
- 子进程环境以 [`dsh-subprocess`](../../subprocess/README.zh.md) seam 的 `scrubbedParentEnv()` 为基础,先移除疑似凭据和名称为 `DSH_*` 的环境变量,再合并显式 `config.env` 值。子进程由 SDK 客户端 spawn,而不是经由 `ctx.subprocess` spawn(这是 subprocess README 中记录的 SDK 托管传输例外),因此本后端会自行执行环境清理。JSON-RPC 协议格式才是真正的序列化边界。
111
+ 子进程最后一个 `turn/end` 的原因会映射进共享的停止原因词汇,实现见 [`src/run.ts`](src/run.ts)。
59
112
 
60
- 本包没有默认导出。否则 Cordis loader 解包会隐藏具名 `inject` 元数据;见[事故复盘(postmortem)0001](../../../docs/postmortem/0001-acp-default-export-drops-inject.zh.md)。
113
+ ### 进程边界
61
114
 
115
+ 子进程环境以子进程 seam 的已清理凭据父环境为基础,并在清除之后合并显式 `config.env` 值。子进程由 SDK 客户端 spawn,而不是经由 `ctx.subprocess`——这是 SDK 托管传输的文档化例外——因此本后端会自行执行环境清理。
116
+
117
+ </details>
118
+
119
+ -----
120
+
121
+ <a id="further-exploration"></a>
122
+ ## 进一步探索
123
+
124
+ 当包级约定不够用时阅读以下页面。它们从本后端逐步进入它接入的 seam 与它驱动的 SDK。
125
+
126
+ - [Subagent 子系统](../../../docs/subsystems/subagent.zh.md)——服务约定、提供方约定与终态结果语义。
127
+ - [dsh-subagent seam](../subagent/README.zh.md)——本提供方注册于其上的注册表与启动 API。
128
+ - [ACP subagent 后端](../subagent-acp/README.zh.md)——经 Agent Client Protocol 的兄弟进程外提供方。
129
+ - [TypeScript SDK 客户端](../../sdk/client/README.zh.md)——本后端用以驱动子进程的 stdio JSON-RPC 客户端。
130
+ - [生成配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-subagent-dsh-sdk)——每个受支持配置字段及其源声明。
131
+
132
+ -----
133
+
134
+ <a id="model-experience"></a>
62
135
  ## 模型体验
63
136
 
64
137
  ### 子 agent 请求
65
138
 
66
- #### 模型看到的内容
139
+ #### 模型看到什么
67
140
 
68
- 子运行时的模型会收到作为用户消息的独立任务,以及该运行时自身配置的系统提示词、工具和全新会话。它不会收到父级对话。本提供方不声明可选的启动时能力,因此本地服务会拒绝要求 persona、工具过滤、深度强制或结构化输出的请求,而不是静默省略这些要求。
141
+ 子运行时的模型会收到作为用户消息的独立任务,以及该运行时自身配置的系统提示词、工具和全新会话。它不会收到父级对话。父级工具调用可以为本次运行选择子级提供方、模型与推理强度;所选路由和部署持有的可选输出上限会固定到这个新子进程。persona、工具过滤、深度强制与结构化输出仍不受支持,并会被拒绝而不是静默省略。
69
142
 
70
143
  #### Token 影响
71
144
 
@@ -77,9 +150,9 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
77
150
 
78
151
  ### 父级工具结果(间接)
79
152
 
80
- #### 模型看到的内容
153
+ #### 模型看到什么
81
154
 
82
- 经由 `dsh-tool-subagent`,父级只会收到子运行时最终的 assistant 文本(或累积的部分文本),或该消费方给出的精确停止原因错误;不会收到中间消息或工具流量。
155
+ 经由 `dsh-tool-subagent`,父级只会收到子运行时最终的 assistant 文本(或累积的部分文本),或该消费方给出的精确停止原因错误;不会收到中间消息或工具流量。带诊断的非完成结果会先呈现安全诊断,再单独呈现保留的部分 assistant 输出;启动与 shutdown 错误使用同一固定事实,不公开原始 SDK 文本。
83
156
 
84
157
  #### Token 影响
85
158
 
@@ -89,9 +162,27 @@ Provider 不宣告任何启动期能力(`outputSchema`/`depthLimit`/`toolFilte
89
162
 
90
163
  仅追加;新增可见内容位于可复用请求前缀之后,不会使现有 KV Cache 条目失效。
91
164
 
92
- ## 已知限制与暂缓事项
165
+ ## 已知限制与延期工作
166
+
167
+ <a id="known-limitations-and-deferred-work"></a>
168
+
169
+
170
+ 这些限制说明本后端何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是通用 SDK 对比或任务积压。
171
+
172
+ - **每次运行都使用全新的运行时进程**——不使用进程池;harness 运行时需要启动完整的插件树,因此每次运行的 spawn 成本高于 ACP 后端通常使用的子进程。
173
+ - **不支持路由之外的启动时能力**——父级可以选择子 agent 路由,但无法在子进程内强制执行 `outputSchema`、深度限制、工具过滤或 persona;应改为配置所选子 profile 及其有序 patch。
174
+ - **子进程的 transcript(文本记录)保留在其自身的会话根目录中**——父级日志只记录委派工具调用与结果;流式会话事件通道只用于提取输出,不会桥接到父级日志中。
175
+ - **仅支持本地子进程**——解析出的工作目录是本地路径;远程运行时需要独立的后端。
176
+
177
+ <a id="dev-note"></a>
178
+ ### 开发备注
179
+
180
+ <details>
181
+ <summary>维护者的工作上下文——点击展开</summary>
182
+
183
+ 本开发备注是维护者的工作上下文:开放问题与尚未决定的探索方向。它明确不具权威性——已交付的行为与限制以上文和包代码为准。
184
+
185
+ - **Spawn 成本**——每次运行加载完整插件树是彻底隔离的代价;池化会改变这一权衡。
186
+ - **远程运行时**——远程运行时需要独立的后端与工作区映射。
93
187
 
94
- - **每次运行都使用全新的运行时进程**:不使用进程池;harness 运行时需要启动完整的插件树,因此每次运行的 spawn 成本高于 ACP 后端通常使用的子进程。
95
- - **不支持可选的启动时能力**:父级无法在子进程内强制执行 `outputSchema`、深度限制、工具过滤或 persona;应改为配置子进程自身的 `cordis.yml`。
96
- - **子进程的 transcript(文本记录)保留在其自身的会话根目录中**:父级日志只记录委派工具调用/结果(seam 的子级隔离规则);流式 `session.event` 通道只用于提取输出,不会桥接到父级日志中。
97
- - **仅支持本地子进程**:解析出的 cwd 是本地路径;远程运行时需要独立的后端。
188
+ </details>
package/lib/index.js CHANGED
@@ -1,19 +1,20 @@
1
+ import { statSync } from "node:fs";
2
+ import { isAbsolute, resolve } from "node:path";
1
3
  import z from "@deepseek-ai/schemastery";
2
4
  import { AssistantOutputFold, NO_START_CAPABILITIES, assertPositiveFinite, resolveChildCwd, settleRunResult, subprocessRunHandle, validateConfiguredCwd } from "@deepseek-ai/dsh-subagent";
3
5
  import { randomUUID } from "node:crypto";
4
- import { DeepSeekHarness } from "@deepseek-ai/dsh-sdk-client";
5
- import { SessionId } from "@deepseek-ai/dsh-session";
6
+ import { brandString } from "@deepseek-ai/dsh-brand";
7
+ import { DeepSeekHarness, JsonRpcResponseError, SdkProtocolError, TransportClosedError } from "@deepseek-ai/dsh-sdk-client";
6
8
  import { scrubbedParentEnv } from "@deepseek-ai/dsh-subprocess";
7
9
  //#region lib/types/run.js
8
10
  /**
9
11
  * Fresh-process SDK subagent client. Drives one child DeepSeek Harness
10
12
  * runtime over stdio JSON-RPC through `@deepseek-ai/dsh-sdk-client` and owns
11
- * cancellation and quiescent disposal. Structure mirrors the ACP backend
12
- * (`@deepseek-ai/dsh-subagent-acp`): publish after the child handshake,
13
- * flatten child failures into stop reasons, tear down to quiescence. The
14
- * child is spawned BY the SDK client rather than through `ctx.subprocess` —
15
- * the subprocess seam's documented exception for SDK-managed transports —
16
- * so this driver applies the seam's shared env scrub itself.
13
+ * cancellation and quiescent disposal. It publishes after the child
14
+ * handshake, maps child failures to stop reasons, and tears down to
15
+ * quiescence. The SDK client spawns the child rather than using
16
+ * `ctx.subprocess` — the subprocess seam's documented exception for
17
+ * SDK-managed transports — so this driver applies the seam's shared env scrub.
17
18
  *
18
19
  * @module @deepseek-ai/dsh-subagent-dsh-sdk/run
19
20
  */
@@ -23,19 +24,88 @@ const DEFAULT_DISPOSE_EOF_GRACE_MS = 6e3;
23
24
  const DEFAULT_DISPOSE_GRACE_MS = 3e3;
24
25
  /** Default bound on the protocol `shutdown` exchange during dispose. */
25
26
  const DEFAULT_SHUTDOWN_TIMEOUT_MS = 1e3;
27
+ /** Fixed safe failure text derived only from provider-owned structured facts. */
28
+ function failureDiagnostic(facts) {
29
+ return `Subagent failure (${[
30
+ "provider: DSH SDK",
31
+ `stage: ${facts.stage}`,
32
+ `category: ${facts.category}`
33
+ ].join("; ")})`;
34
+ }
35
+ var SdkRunFailure = class extends Error {
36
+ facts;
37
+ constructor(facts, cause) {
38
+ super(`subagent-dsh-sdk: ${failureDiagnostic(facts)}`, { cause });
39
+ this.facts = facts;
40
+ this.name = "SdkRunFailure";
41
+ }
42
+ };
43
+ /** Runtime constructor seam replaced only by package-local fake-runtime tests. */
44
+ const internals = { createHarness: (options) => new DeepSeekHarness(options) };
26
45
  /**
27
- * Map a child turn-end reason to a harness {@link SubagentStopReason}.
46
+ * Hide a pre-spawn workspace/configuration failure behind fixed safe facts.
47
+ * @param cause - original Host failure retained on the Error cause chain.
48
+ * @returns an Error whose message contains only the fixed DSH SDK failure line.
49
+ */
50
+ function sdkConfigurationFailure(cause) {
51
+ return new SdkRunFailure({
52
+ stage: "initialize",
53
+ category: "configuration"
54
+ }, cause);
55
+ }
56
+ /** Classify one SDK rejection without reading its message or stderr tail. */
57
+ function sdkFailure(error, stage) {
58
+ return new SdkRunFailure(error instanceof TransportClosedError ? {
59
+ stage,
60
+ category: "transport"
61
+ } : error instanceof SdkProtocolError || error instanceof JsonRpcResponseError ? {
62
+ stage,
63
+ category: "protocol"
64
+ } : {
65
+ stage,
66
+ category: "unknown"
67
+ }, error);
68
+ }
69
+ /**
70
+ * Map one child terminal reason to its complete shared result outcome.
28
71
  * @param reason - the owned child run's final durable turn reason, or
29
72
  * `undefined` when it settled without running a turn.
30
- * @returns the harness equivalent; an absent or unknown reason maps to
31
- * `error`, so an unclean stop is never reported as `completed`.
73
+ * @returns the shared stop reason and any additional safe diagnostic.
32
74
  */
33
- function sdkStopReason(reason) {
75
+ function sdkChildOutcome(reason) {
34
76
  switch (reason?.kind) {
35
- case "completed": return "completed";
36
- case "max-tokens": return "max-tokens";
37
- case "aborted": return "aborted";
38
- default: return "error";
77
+ case "completed": return { stopReason: "completed" };
78
+ case "max-tokens": return { stopReason: "max-tokens" };
79
+ case "aborted": return reason.reason.kind === "disposed" ? {
80
+ stopReason: "aborted",
81
+ diagnostic: failureDiagnostic({
82
+ stage: "session-run",
83
+ category: "child-disposed"
84
+ })
85
+ } : { stopReason: "aborted" };
86
+ case "blocked": return { stopReason: "refusal" };
87
+ case "error": return {
88
+ stopReason: "error",
89
+ diagnostic: failureDiagnostic({
90
+ stage: "session-run",
91
+ category: "child-error"
92
+ })
93
+ };
94
+ case "interrupted": return { stopReason: "error" };
95
+ case void 0: return {
96
+ stopReason: "error",
97
+ diagnostic: failureDiagnostic({
98
+ stage: "session-run",
99
+ category: "missing-terminal"
100
+ })
101
+ };
102
+ default: return {
103
+ stopReason: "error",
104
+ diagnostic: failureDiagnostic({
105
+ stage: "session-run",
106
+ category: "child-unknown"
107
+ })
108
+ };
39
109
  }
40
110
  }
41
111
  /** Normalize an unknown thrown value to an Error (the catch binding is `unknown`). */
@@ -43,34 +113,62 @@ function toError(value) {
43
113
  /* v8 ignore next */
44
114
  return value instanceof Error ? value : new Error(String(value));
45
115
  }
116
+ /** Report an original Host failure without letting the observation sink replace it. */
117
+ function reportFailure(spec, error) {
118
+ try {
119
+ spec.onError?.(toError(error), "error");
120
+ } catch {}
121
+ }
122
+ /** Map an SDK-owned failed-start aggregate into safe initialize/shutdown lines. */
123
+ function sdkStartupFailure(spec, error) {
124
+ if (!(error instanceof AggregateError) || error.errors.length < 2) {
125
+ reportFailure(spec, error);
126
+ return sdkFailure(error, "initialize");
127
+ }
128
+ const initializeError = error.errors[0];
129
+ const cleanupError = error.errors[1];
130
+ reportFailure(spec, initializeError);
131
+ reportFailure(spec, cleanupError);
132
+ const initializeFailure = sdkFailure(initializeError, "initialize");
133
+ const cleanupFailure = new SdkRunFailure({
134
+ stage: "shutdown",
135
+ category: "unknown"
136
+ }, cleanupError);
137
+ return new AggregateError([initializeFailure, cleanupFailure], `${initializeFailure.message}; ${cleanupFailure.message}`);
138
+ }
46
139
  /**
47
140
  * Start and publish one SDK runtime child after its `initialize` handshake.
48
- * Child failures resolve through the run result; startup failures reject
49
- * after process reap. Disposal shuts the runtime down and reaps it.
141
+ * Child failures resolve through the run result. Startup rejects with fixed
142
+ * safe facts after SDK-owned cleanup; successful cleanup proves process reap.
143
+ * Cleanup failure preserves initialize plus shutdown for an ordinary failure,
144
+ * or shutdown alone after cancellation, without claiming quiescence. Disposal
145
+ * shuts the runtime down and reaps it.
50
146
  * @param request - the start request; its signal is the cancellation channel.
51
- * @param spec - the resolved spawn spec: command/args/cwd, the child's
52
- * provider/model route, env, timeouts, and the optional error sink.
147
+ * @param spec - the resolved spawn spec: profile/patches/home/cwd, the child's
148
+ * provider/model/reasoning route, output cap, env, timeouts, and the optional
149
+ * error sink.
53
150
  * @returns the ready run handle for the child subprocess.
54
151
  */
55
152
  async function startSdkRun(request, spec) {
56
153
  if (request.signal.aborted) throw new Error("subagent request was aborted before the SDK child started");
57
- const id = SessionId(randomUUID());
58
- const harness = new DeepSeekHarness({
59
- launch: {
60
- command: spec.command,
61
- args: spec.args,
62
- cwd: spec.cwd,
63
- env: {
64
- ...scrubbedParentEnv(),
65
- ...spec.env
66
- },
67
- shutdownTimeoutMs: spec.shutdownTimeoutMs,
68
- disposeEofGraceMs: spec.disposeEofGraceMs,
69
- disposeGraceMs: spec.disposeGraceMs
154
+ const id = brandString(randomUUID());
155
+ const harness = internals.createHarness({
156
+ ...spec.dshBin === void 0 ? {} : { dshBin: spec.dshBin },
157
+ profile: spec.profile,
158
+ patches: spec.patches,
159
+ dshHome: spec.dshHome,
160
+ processCwd: spec.cwd,
161
+ env: {
162
+ ...scrubbedParentEnv(),
163
+ ...spec.env
70
164
  },
165
+ shutdownTimeoutMs: spec.shutdownTimeoutMs,
166
+ disposeEofGraceMs: spec.disposeEofGraceMs,
167
+ disposeGraceMs: spec.disposeGraceMs,
71
168
  cwd: spec.cwd,
72
169
  provider: spec.provider,
73
170
  model: spec.model,
171
+ ...spec.reasoningEffort === void 0 ? {} : { reasoningEffort: spec.reasoningEffort },
74
172
  ...spec.maxTokens === void 0 ? {} : { maxTokens: spec.maxTokens }
75
173
  });
76
174
  const flags = { cancelled: false };
@@ -87,17 +185,27 @@ async function startSdkRun(request, spec) {
87
185
  requestCancel();
88
186
  };
89
187
  request.signal.addEventListener("abort", onAbort, { once: true });
188
+ const cancelledStartup = /* @__PURE__ */ new Error("subagent cancelled before the SDK child initialized");
90
189
  try {
91
190
  await Promise.race([harness.start(), cancelSettled.then(() => {
92
- throw new Error("subagent cancelled before the SDK child initialized");
191
+ throw cancelledStartup;
93
192
  })]);
94
193
  /* v8 ignore next */
95
- if (flags.cancelled) throw new Error("subagent cancelled before the SDK child initialized");
194
+ if (flags.cancelled) throw cancelledStartup;
96
195
  } catch (error) {
97
196
  request.signal.removeEventListener("abort", onAbort);
98
- await harness.close();
99
- if (flags.cancelled) throw new Error("subagent request was aborted before the SDK child started");
100
- throw toError(error);
197
+ if (error !== cancelledStartup) throw sdkStartupFailure(spec, error);
198
+ try {
199
+ await harness.close();
200
+ } catch (cleanupError) {
201
+ reportFailure(spec, cleanupError);
202
+ const cleanupFailure = new SdkRunFailure({
203
+ stage: "shutdown",
204
+ category: "unknown"
205
+ }, cleanupError);
206
+ throw new AggregateError([cleanupFailure], cleanupFailure.message);
207
+ }
208
+ throw new Error("subagent request was aborted before the SDK child started");
101
209
  }
102
210
  const childSessionId = `session-${randomUUID().replaceAll("-", "")}`;
103
211
  const fold = new AssistantOutputFold();
@@ -106,22 +214,41 @@ async function startSdkRun(request, spec) {
106
214
  fold.push(notification.params.event);
107
215
  };
108
216
  const collectOutput = () => fold.collect() ?? [];
217
+ const teardown = async () => {
218
+ try {
219
+ await harness.close();
220
+ } catch (error) {
221
+ reportFailure(spec, error);
222
+ throw new SdkRunFailure({
223
+ stage: "shutdown",
224
+ category: "unknown"
225
+ }, error);
226
+ }
227
+ };
228
+ let diagnostic;
109
229
  return subprocessRunHandle({
110
230
  id,
111
231
  result: settleRunResult({
112
232
  attempt: async () => {
113
- const turn = await Promise.race([harness.session(childSessionId).run(request.prompt, { onNotification: observe }), cancelSettled.then(() => "cancelled")]);
114
- if (turn === "cancelled") return {
115
- output: collectOutput(),
116
- stopReason: "aborted"
117
- };
118
- const lastEnd = turn.events.findLast((event) => event.type === "turn/end");
119
- return {
120
- output: collectOutput(),
121
- stopReason: sdkStopReason(lastEnd?.data.reason)
122
- };
233
+ try {
234
+ const turn = await Promise.race([harness.session(childSessionId).run(request.prompt, { onNotification: observe }), cancelSettled.then(() => "cancelled")]);
235
+ if (turn === "cancelled") return {
236
+ output: collectOutput(),
237
+ stopReason: "aborted"
238
+ };
239
+ const outcome = sdkChildOutcome(turn.events.findLast((event) => event.type === "turn/end")?.data.reason);
240
+ diagnostic = outcome.diagnostic;
241
+ return {
242
+ output: collectOutput(),
243
+ ...outcome
244
+ };
245
+ } catch (error) {
246
+ diagnostic = failureDiagnostic(sdkFailure(error, "session-run").facts);
247
+ throw error;
248
+ }
123
249
  },
124
250
  collectOutput,
251
+ collectDiagnostic: () => diagnostic,
125
252
  cancelled: () => flags.cancelled,
126
253
  onError: spec.onError,
127
254
  signal: request.signal,
@@ -130,18 +257,19 @@ async function startSdkRun(request, spec) {
130
257
  signal: request.signal,
131
258
  onAbort,
132
259
  requestCancel,
133
- teardown: () => harness.close()
260
+ teardown
134
261
  });
135
262
  }
136
263
  //#endregion
137
264
  //#region lib/types/index.js
138
265
  /**
139
266
  * Out-of-process SDK subagent backend. Each child is a complete DeepSeek
140
- * Harness runtime in its own process — own `cordis.yml`-decided composition,
267
+ * Harness runtime in its own process — own named profile and patch composition,
141
268
  * session, model route, and tools — driven over stdio JSON-RPC through the
142
- * TypeScript SDK client, so it shares no Cordis context and advertises no
143
- * parent-enforced start capabilities; the ONE thing it reads off
144
- * `request.parent` is the session's workspace cwd. This plugin uses named
269
+ * TypeScript SDK client, so it shares no Cordis context. It accepts the
270
+ * provider/model/reasoning/maxTokens subset of `agentOptions`; other start
271
+ * features remain unsupported. The ONE thing it reads off `request.parent`
272
+ * is the session's workspace cwd. This plugin uses named
145
273
  * exports only; a default would hide its loader metadata (see
146
274
  * `docs/postmortem/0001-acp-default-export-drops-inject.md`).
147
275
  * @module @deepseek-ai/dsh-subagent-dsh-sdk
@@ -150,8 +278,10 @@ const name = "subagent-dsh-sdk";
150
278
  const inject = ["subagents"];
151
279
  const Config = z.object({
152
280
  providerName: z.string().default("dsh-sdk"),
153
- command: z.string().required(),
154
- args: z.array(z.string()).default([]),
281
+ dshBin: z.string(),
282
+ profile: z.string().default("sdk"),
283
+ patches: z.array(z.string()).default([]),
284
+ dshHome: z.string().required(),
155
285
  cwd: z.string(),
156
286
  provider: z.string().default("deepseek-official"),
157
287
  model: z.string().default("deepseek-v4-flash"),
@@ -161,30 +291,68 @@ const Config = z.object({
161
291
  disposeEofGraceMs: z.number().default(DEFAULT_DISPOSE_EOF_GRACE_MS),
162
292
  disposeGraceMs: z.number().default(DEFAULT_DISPOSE_GRACE_MS)
163
293
  });
294
+ /** Resolve one configured runtime file against the harness launch directory and require a regular file. */
295
+ function resolveConfiguredFile(field, value) {
296
+ const path = resolve(value);
297
+ try {
298
+ if (statSync(path).isFile()) return path;
299
+ } catch {}
300
+ throw new TypeError(`subagent-dsh-sdk ${field} must name an existing file: ${path}`);
301
+ }
302
+ /** DSH SDK can apply Agent route options while the other start features remain child-owned. */
303
+ const SDK_START_CAPABILITIES = Object.freeze({
304
+ ...NO_START_CAPABILITIES,
305
+ agentOptions: true
306
+ });
307
+ /** Merge the request's supported route fields over this provider instance's defaults. */
308
+ function resolveSdkRoute(config, requested) {
309
+ const maxTokens = requested?.maxTokens ?? config.maxTokens;
310
+ return {
311
+ provider: requested?.provider ?? config.provider,
312
+ model: requested?.model ?? config.model,
313
+ ...requested?.reasoningEffort === void 0 ? {} : { reasoningEffort: requested.reasoningEffort },
314
+ ...maxTokens === void 0 ? {} : { maxTokens }
315
+ };
316
+ }
164
317
  /**
165
- * The SDK provider. Advertises NO start-time capabilities: an out-of-process
166
- * child cannot honor `outputSchema`/`maxDepth`/`toolFilter`/`persona` (the
167
- * service rejects a request needing any of them before `start` runs).
318
+ * The SDK provider. It resolves Agent route options into the child runtime's
319
+ * process-wide handshake; output schema, depth, tool filter, and persona stay
320
+ * unsupported because their ownership does not cross this process boundary.
168
321
  */
169
322
  var SdkSubagentProvider = class {
170
323
  name;
171
324
  ctx;
172
325
  config;
173
- capabilities = NO_START_CAPABILITIES;
326
+ capabilities = SDK_START_CAPABILITIES;
327
+ agentRouteDefaults;
174
328
  inheritsParentContext = false;
175
329
  constructor(name, ctx, config) {
176
330
  this.name = name;
177
331
  this.ctx = ctx;
178
332
  this.config = config;
333
+ this.agentRouteDefaults = Object.freeze({
334
+ provider: config.provider,
335
+ model: config.model
336
+ });
179
337
  }
180
338
  start(request) {
339
+ if (request.signal.aborted) throw new Error("subagent request was aborted before the SDK child started");
340
+ let cwd;
341
+ try {
342
+ cwd = resolveChildCwd("subagent-dsh-sdk", this.config.cwd, request.parent.session.header.cwd);
343
+ } catch (error) {
344
+ const failure = sdkConfigurationFailure(error);
345
+ this.ctx.logger.warn(`subagent-dsh-sdk "${this.name}": child start failed: %o`, error);
346
+ throw failure;
347
+ }
348
+ const route = resolveSdkRoute(this.config, request.agentOptions);
181
349
  return startSdkRun(request, {
182
- command: this.config.command,
183
- args: this.config.args,
184
- cwd: resolveChildCwd("subagent-dsh-sdk", this.config.cwd, request.parent.session.header.cwd),
185
- provider: this.config.provider,
186
- model: this.config.model,
187
- ...this.config.maxTokens === void 0 ? {} : { maxTokens: this.config.maxTokens },
350
+ ...this.config.dshBin === void 0 ? {} : { dshBin: this.config.dshBin },
351
+ profile: this.config.profile,
352
+ patches: this.config.patches,
353
+ dshHome: this.config.dshHome,
354
+ cwd,
355
+ ...route,
188
356
  env: this.config.env,
189
357
  shutdownTimeoutMs: this.config.shutdownTimeoutMs,
190
358
  disposeEofGraceMs: this.config.disposeEofGraceMs,
@@ -201,9 +369,15 @@ function apply(ctx, config) {
201
369
  assertPositiveFinite("subagent-dsh-sdk", "disposeEofGraceMs", resolved.disposeEofGraceMs);
202
370
  assertPositiveFinite("subagent-dsh-sdk", "disposeGraceMs", resolved.disposeGraceMs);
203
371
  if (resolved.maxTokens !== void 0 && (!Number.isSafeInteger(resolved.maxTokens) || resolved.maxTokens <= 0)) throw new TypeError("subagent-dsh-sdk maxTokens must be a positive safe integer");
204
- const configuredCwd = validateConfiguredCwd("subagent-dsh-sdk", resolved.cwd);
205
- const validated = configuredCwd === void 0 ? resolved : {
372
+ if (!isAbsolute(resolved.dshHome)) throw new TypeError("subagent-dsh-sdk dshHome must be an absolute path");
373
+ const launchPaths = {
206
374
  ...resolved,
375
+ patches: resolved.patches.map((path, index) => resolveConfiguredFile(`patches[${String(index)}]`, path)),
376
+ ...resolved.dshBin === void 0 ? {} : { dshBin: resolveConfiguredFile("dshBin", resolved.dshBin) }
377
+ };
378
+ const configuredCwd = validateConfiguredCwd("subagent-dsh-sdk", resolved.cwd);
379
+ const validated = configuredCwd === void 0 ? launchPaths : {
380
+ ...launchPaths,
207
381
  cwd: configuredCwd
208
382
  };
209
383
  ctx.subagents.registerProvider(new SdkSubagentProvider(validated.providerName, ctx, validated));
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Out-of-process SDK subagent backend. Each child is a complete DeepSeek
3
- * Harness runtime in its own process — own `cordis.yml`-decided composition,
3
+ * Harness runtime in its own process — own named profile and patch composition,
4
4
  * session, model route, and tools — driven over stdio JSON-RPC through the
5
- * TypeScript SDK client, so it shares no Cordis context and advertises no
6
- * parent-enforced start capabilities; the ONE thing it reads off
7
- * `request.parent` is the session's workspace cwd. This plugin uses named
5
+ * TypeScript SDK client, so it shares no Cordis context. It accepts the
6
+ * provider/model/reasoning/maxTokens subset of `agentOptions`; other start
7
+ * features remain unsupported. The ONE thing it reads off `request.parent`
8
+ * is the session's workspace cwd. This plugin uses named
8
9
  * exports only; a default would hide its loader metadata (see
9
10
  * `docs/postmortem/0001-acp-default-export-drops-inject.md`).
10
11
  * @module @deepseek-ai/dsh-subagent-dsh-sdk
@@ -17,10 +18,14 @@ export declare const inject: string[];
17
18
  export interface Config {
18
19
  /** Provider name on `ctx.subagents` (default `dsh-sdk`). */
19
20
  providerName: string;
20
- /** The executable to spawn for each run (the child runtime bin or packaged exe). */
21
- command: string;
22
- /** Arguments passed to {@link command} (typically the child's `cordis.yml` path). */
23
- args: string[];
21
+ /** Explicit dsh CLI module, resolved and checked at plugin load; omission uses the SDK dependency. */
22
+ dshBin?: string;
23
+ /** Named child profile (default `sdk`). */
24
+ profile: string;
25
+ /** Ordered per-launch profile patch files, resolved and checked at plugin load. */
26
+ patches: string[];
27
+ /** Absolute isolated Harness home for every nested child process. */
28
+ dshHome: string;
24
29
  /**
25
30
  * Working directory override for the child process and its SDK session
26
31
  * workspace. Must be non-empty; a relative path resolves against the
@@ -38,8 +43,7 @@ export interface Config {
38
43
  maxTokens?: number;
39
44
  /**
40
45
  * Extra environment variables for the child process — e.g. the child
41
- * runtime's own `DEEPSEEK_API_KEY`, or `DSH_CORDIS_CONFIG` naming its
42
- * config. Forwarded on top of a credential-scrubbed copy of the parent
46
+ * runtime's own `DEEPSEEK_API_KEY`. Forwarded on top of a credential-scrubbed copy of the parent
43
47
  * env, so an explicit key here reaches the child while ambient secrets do
44
48
  * not leak implicitly.
45
49
  */
@@ -1,23 +1,28 @@
1
1
  /**
2
2
  * Fresh-process SDK subagent client. Drives one child DeepSeek Harness
3
3
  * runtime over stdio JSON-RPC through `@deepseek-ai/dsh-sdk-client` and owns
4
- * cancellation and quiescent disposal. Structure mirrors the ACP backend
5
- * (`@deepseek-ai/dsh-subagent-acp`): publish after the child handshake,
6
- * flatten child failures into stop reasons, tear down to quiescence. The
7
- * child is spawned BY the SDK client rather than through `ctx.subprocess` —
8
- * the subprocess seam's documented exception for SDK-managed transports —
9
- * so this driver applies the seam's shared env scrub itself.
4
+ * cancellation and quiescent disposal. It publishes after the child
5
+ * handshake, maps child failures to stop reasons, and tears down to
6
+ * quiescence. The SDK client spawns the child rather than using
7
+ * `ctx.subprocess` — the subprocess seam's documented exception for
8
+ * SDK-managed transports — so this driver applies the seam's shared env scrub.
10
9
  *
11
10
  * @module @deepseek-ai/dsh-subagent-dsh-sdk/run
12
11
  */
13
- import { type TurnEndReason } from '@deepseek-ai/dsh-session';
14
- import type { SubagentRun, SubagentStartRequest, SubagentStopReason } from '@deepseek-ai/dsh-subagent';
12
+ import { DeepSeekHarness, type DeepSeekHarnessOptions } from '@deepseek-ai/dsh-sdk-client';
13
+ import type { ReasoningEffortId } from '@deepseek-ai/dsh-llm';
14
+ import type { TurnEndReason } from '@deepseek-ai/dsh-session';
15
+ import type { SubagentResult, SubagentRun, SubagentStartRequest, SubagentStopReason } from '@deepseek-ai/dsh-subagent';
15
16
  /** Resolved spawn spec for an SDK runtime child process (no defaults — see Config). */
16
17
  export interface SdkRunSpec {
17
- /** The executable to spawn (the child runtime — a `dsh-jsonrpc-agent` bin or packaged exe). */
18
- command: string;
19
- /** Arguments passed to {@link command} (typically the child's `cordis.yml` path). */
20
- args: string[];
18
+ /** Explicit dsh CLI module; omission resolves the SDK client's same-version dependency. */
19
+ dshBin?: string;
20
+ /** Named child profile. */
21
+ profile: string;
22
+ /** Ordered per-launch profile patch files. */
23
+ patches: string[];
24
+ /** Absolute isolated Harness home for the nested runtime. */
25
+ dshHome: string;
21
26
  /**
22
27
  * Absolute working directory for the child process AND the workspace cwd
23
28
  * of its SDK session. The provider resolves it before this spec exists:
@@ -28,11 +33,13 @@ export interface SdkRunSpec {
28
33
  provider: string;
29
34
  /** Model the child runtime initializes with. */
30
35
  model: string;
36
+ /** Optional adapter-owned reasoning effort sent in the child runtime's initialize handshake. */
37
+ reasoningEffort?: ReasoningEffortId;
31
38
  /** Optional per-request output-token cap sent in the child runtime's initialize handshake. */
32
39
  maxTokens?: number;
33
40
  /**
34
41
  * Extra environment variables to ADD for the child (e.g. the child
35
- * runtime's own `DEEPSEEK_API_KEY`, or `DSH_CORDIS_CONFIG`). Merged after
42
+ * runtime's own `DEEPSEEK_API_KEY`). Merged after
36
43
  * the seam's `scrubbedParentEnv()` base, so an explicit credential or
37
44
  * current `DSH_*` fact survives while ambient namesakes never leak.
38
45
  */
@@ -44,10 +51,9 @@ export interface SdkRunSpec {
44
51
  /** Termination confirmation window (ms), including forced exit on every platform. */
45
52
  disposeGraceMs: number;
46
53
  /**
47
- * Sink for a child-level failure that the run flattened into a stop reason
48
- * (the seam contract forbids `result` rejecting). A throw from the sink
49
- * itself is contained. Optional — omitted in unit tests that assert the
50
- * stop reason directly.
54
+ * Host sink for startup, published-run, or shutdown failures. Model-visible
55
+ * text uses fixed safe facts, while this callback retains the original Error.
56
+ * A throw from the sink itself is contained.
51
57
  */
52
58
  onError?: (error: Error, stopReason: SubagentStopReason) => void;
53
59
  }
@@ -57,21 +63,34 @@ export declare const DEFAULT_DISPOSE_EOF_GRACE_MS = 6000;
57
63
  export declare const DEFAULT_DISPOSE_GRACE_MS = 3000;
58
64
  /** Default bound on the protocol `shutdown` exchange during dispose. */
59
65
  export declare const DEFAULT_SHUTDOWN_TIMEOUT_MS = 1000;
66
+ /** Runtime constructor seam replaced only by package-local fake-runtime tests. */
67
+ export declare const internals: {
68
+ createHarness(options: DeepSeekHarnessOptions): DeepSeekHarness;
69
+ };
60
70
  /**
61
- * Map a child turn-end reason to a harness {@link SubagentStopReason}.
71
+ * Hide a pre-spawn workspace/configuration failure behind fixed safe facts.
72
+ * @param cause - original Host failure retained on the Error cause chain.
73
+ * @returns an Error whose message contains only the fixed DSH SDK failure line.
74
+ */
75
+ export declare function sdkConfigurationFailure(cause: unknown): Error;
76
+ /**
77
+ * Map one child terminal reason to its complete shared result outcome.
62
78
  * @param reason - the owned child run's final durable turn reason, or
63
79
  * `undefined` when it settled without running a turn.
64
- * @returns the harness equivalent; an absent or unknown reason maps to
65
- * `error`, so an unclean stop is never reported as `completed`.
80
+ * @returns the shared stop reason and any additional safe diagnostic.
66
81
  */
67
- export declare function sdkStopReason(reason: TurnEndReason | undefined): SubagentStopReason;
82
+ export declare function sdkChildOutcome(reason: TurnEndReason | undefined): Pick<SubagentResult, 'stopReason' | 'diagnostic'>;
68
83
  /**
69
84
  * Start and publish one SDK runtime child after its `initialize` handshake.
70
- * Child failures resolve through the run result; startup failures reject
71
- * after process reap. Disposal shuts the runtime down and reaps it.
85
+ * Child failures resolve through the run result. Startup rejects with fixed
86
+ * safe facts after SDK-owned cleanup; successful cleanup proves process reap.
87
+ * Cleanup failure preserves initialize plus shutdown for an ordinary failure,
88
+ * or shutdown alone after cancellation, without claiming quiescence. Disposal
89
+ * shuts the runtime down and reaps it.
72
90
  * @param request - the start request; its signal is the cancellation channel.
73
- * @param spec - the resolved spawn spec: command/args/cwd, the child's
74
- * provider/model route, env, timeouts, and the optional error sink.
91
+ * @param spec - the resolved spawn spec: profile/patches/home/cwd, the child's
92
+ * provider/model/reasoning route, output cap, env, timeouts, and the optional
93
+ * error sink.
75
94
  * @returns the ready run handle for the child subprocess.
76
95
  */
77
96
  export declare function startSdkRun(request: SubagentStartRequest, spec: SdkRunSpec): Promise<SubagentRun>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-subagent-dsh-sdk",
3
3
  "description": "Out-of-process SDK subagent backend: drives a child DeepSeek Harness runtime subprocess over stdio JSON-RPC through the TypeScript SDK client",
4
- "version": "0.1.1-rc.2",
4
+ "version": "0.1.2-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -32,29 +32,40 @@
32
32
  ],
33
33
  "license": "MIT",
34
34
  "peerDependencies": {
35
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
36
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
37
- "@deepseek-ai/dsh-sdk-client": "^0.1.1-rc.2",
38
- "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
39
- "@deepseek-ai/dsh-subagent": "^0.1.1-rc.2",
40
- "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2",
41
- "@deepseek-ai/cordis": "^4.0.1",
42
- "@deepseek-ai/dsh-agent": "^0.1.1-rc.2"
35
+ "@deepseek-ai/cordis": "^4.0.2",
36
+ "@deepseek-ai/dsh-agent": "^0.1.2-alpha.2",
37
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
38
+ "@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
39
+ "@deepseek-ai/dsh-sdk-client": "^0.1.2-alpha.2",
40
+ "@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
41
+ "@deepseek-ai/dsh-subprocess": "^0.1.2-alpha.2",
42
+ "@deepseek-ai/dsh-subagent": "^0.1.2-alpha.2"
43
43
  },
44
44
  "dependencies": {
45
- "@deepseek-ai/schemastery": "^3.18.1"
45
+ "@deepseek-ai/dsh-brand": "^0.1.2-alpha.2",
46
+ "@deepseek-ai/schemastery": "^3.18.2"
46
47
  },
47
48
  "devDependencies": {
48
- "@deepseek-ai/cordis-plugin-loader": "^1.0.2",
49
- "@deepseek-ai/dsh-agent": "^0.1.1-rc.2",
50
- "@deepseek-ai/dsh-llm": "^0.1.1-rc.2",
51
- "@deepseek-ai/dsh-loader-smoke": "^0.1.1-rc.2",
52
- "@deepseek-ai/dsh-invariants": "^0.1.1-rc.2",
53
- "@deepseek-ai/dsh-sdk-protocol": "^0.1.1-rc.2",
54
- "@deepseek-ai/dsh-sdk-client": "^0.1.1-rc.2",
55
- "@deepseek-ai/dsh-subagent": "^0.1.1-rc.2",
56
- "@deepseek-ai/cordis": "^4.0.1",
57
- "@deepseek-ai/dsh-session": "^0.1.1-rc.2",
58
- "@deepseek-ai/dsh-subprocess": "^0.1.1-rc.2"
49
+ "@deepseek-ai/cordis": "^4.0.2",
50
+ "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
51
+ "@deepseek-ai/dsh-agent": "^0.1.2-alpha.2",
52
+ "@deepseek-ai/dsh-agent-instructions": "^0.1.2-alpha.2",
53
+ "@deepseek-ai/dsh-agent-spine-demo": "^0.1.2-alpha.2",
54
+ "@deepseek-ai/dsh-app-boot": "^0.1.2-alpha.2",
55
+ "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2",
56
+ "@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
57
+ "@deepseek-ai/dsh-llm-deepseek": "^0.1.2-alpha.2",
58
+ "@deepseek-ai/dsh-loader-smoke": "^0.1.2-alpha.2",
59
+ "@deepseek-ai/dsh-sdk-client": "^0.1.2-alpha.2",
60
+ "@deepseek-ai/dsh-sdk-protocol": "^0.1.2-alpha.2",
61
+ "@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
62
+ "@deepseek-ai/dsh-session-checkpoint-policy": "^0.1.2-alpha.2",
63
+ "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.2-alpha.2",
64
+ "@deepseek-ai/dsh-session-projection": "^0.1.2-alpha.2",
65
+ "@deepseek-ai/dsh-skill-filesystem": "^0.1.2-alpha.2",
66
+ "@deepseek-ai/dsh-subagent": "^0.1.2-alpha.2",
67
+ "@deepseek-ai/dsh-subprocess": "^0.1.2-alpha.2",
68
+ "@deepseek-ai/dsh-system-prompt": "^0.1.2-alpha.2",
69
+ "@deepseek-ai/dsh-tool-subagent": "^0.1.2-alpha.2"
59
70
  }
60
71
  }