@deepseek-ai/dsh-sdk-client 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 +2 -2
- package/README.md +101 -15
- package/README.zh.md +103 -17
- package/lib/index.js +158 -30
- package/lib/types/api.d.ts +20 -13
- package/lib/types/client.d.ts +11 -7
- package/lib/types/index.d.ts +5 -5
- package/lib/types/launch.d.ts +58 -0
- package/lib/types/types.d.ts +22 -13
- package/package.json +14 -11
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/sdk/client/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
5
|
+
README.md: 176bddad402a21fd5cdc92aa0316a0716053dbfb
|
|
6
|
+
README.zh.md: c650dd7fa9498c30c32bc66141ab023354dc70c7
|
package/README.md
CHANGED
|
@@ -1,49 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "The TypeScript SDK client for callers that spawn a DeepSeek Harness runtime subprocess and drive agent turns over stdio JSON-RPC: the DeepSeekHarness run API and the lower-level HarnessClient."
|
|
3
|
+
kind: "package-library"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-sdk-client
|
|
2
7
|
|
|
3
8
|
English | [中文](README.zh.md)
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## Summary
|
|
11
|
+
|
|
12
|
+
`dsh-sdk-client` lets TypeScript programs drive a DeepSeek Harness runtime as a subprocess over stdio JSON-RPC. With `DeepSeekHarness` you can spawn the runtime, open sessions, send prompts, and collect the final response plus the event and notification streams; `HarnessClient` gives explicit control over the protocol layer. It is the design twin of the [Python SDK](../../../python/README.md), which shares the same runtime peer and protocol. The launch spec is explicit — callers may name the runtime executable via `dshBin`, omitted resolves the same-version `@deepseek-ai/dsh` package's bin, and the client constructs the arguments — so this client suits repository-adjacent TypeScript consumers such as the SDK subagent backend and automation that know which runtime they are launching. It is a pure library: it registers nothing on a Cordis context, and the runtime it spawns is a complete harness whose composition its own `cordis.yml` decides.
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
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)
|
|
6
22
|
|
|
7
|
-
|
|
23
|
+
-----
|
|
8
24
|
|
|
9
|
-
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## Use this package
|
|
27
|
+
|
|
28
|
+
Use this client when TypeScript code must drive a complete Harness runtime from another process and you can name the runtime executable explicitly. The common path is minimal: construct a `DeepSeekHarness` with a launch spec, run prompts, and close it so the child process is always reaped.
|
|
29
|
+
|
|
30
|
+
### Running agent turns with DeepSeekHarness
|
|
10
31
|
|
|
11
32
|
```ts
|
|
12
33
|
import { DeepSeekHarness } from '@deepseek-ai/dsh-sdk-client'
|
|
34
|
+
import { ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
|
13
35
|
|
|
14
36
|
await using harness = new DeepSeekHarness({
|
|
15
|
-
|
|
37
|
+
profile: 'sdk',
|
|
38
|
+
patches: ['./automation.cordis.yml'],
|
|
16
39
|
provider: 'deepseek-official',
|
|
17
40
|
model: 'deepseek-v4-flash',
|
|
41
|
+
reasoningEffort: ReasoningEffortId('max'),
|
|
18
42
|
maxTokens: 49_152,
|
|
19
43
|
})
|
|
20
44
|
const result = await harness.run('say hi')
|
|
21
45
|
console.log(result.finalResponse)
|
|
22
46
|
```
|
|
23
47
|
|
|
24
|
-
The subprocess starts lazily on first use and stays owned by the instance across `run()` calls; `close()` (or `await using`)
|
|
48
|
+
The subprocess starts lazily on first use and stays owned by the instance across `run()` calls; call `close()` (or use `await using`) so the child is always reaped. `start()` memoizes the bounded `initialize` handshake, which carries the workspace cwd, provider/model route, optional adapter-owned `reasoningEffort`, and optional positive `maxTokens` output cap. The server validates that exact route before it accepts prompts; an omitted effort preserves the model's default. `initializeTimeoutMs` defaults to 10 seconds, and its diagnostic names the selected profile with the retained stderr tail. `run(input, { sessionId?, onNotification? })` accepts text or `SdkPromptContentBlock[]`; an inline raster block carries canonical base64 plus `mimeType` and becomes a durable attachment inside the runtime. The call owns one activity interval: it queues the prompt, waits until its message id appears in a durable inbox receipt, then collects through the next whole-agent `idle`. It returns `RunResult { sessionId, finalResponse, events, notifications }`, where `finalResponse` is the last committed root-session assistant text in that interval — not a response causally assigned to the prompt, because steering, injected context, and other queued work may contribute before idle. `session(id?)` opens a named or fresh session handle. When a failed handshake is cleaned up successfully, the instance installs a fresh client so a later call retries with a new process until terminal `close()`; if initialization and cleanup both fail, `start()` returns an ordered `AggregateError` and retains the failed client instead of spawning beside a process whose exit is unproved. `maxTokens` caps each root-agent request output and is inherited by in-process descendants; compaction plugins own their separate summary limits.
|
|
49
|
+
|
|
50
|
+
### Lower-level control with HarnessClient
|
|
51
|
+
|
|
52
|
+
`HarnessClient` is the protocol client under the run API: explicit `start()`, `initialize()`, `prompt()`, `request()`, and `close()`, plus notification subscriptions. `prompt()` returns the queued message id as soon as the runtime accepts it and never waits for agent activity. `subscribe(filter?)` returns a `NotificationSubscription` (awaitable `next()`, non-blocking `tryNext()`, async iteration); `subscribeSessionTree(id)` scopes to one session and the descendants discovered from `subagent.started` lineage edges — the runtime notifies for every session in its context, and scoping is client-side, exactly like the Python SDK.
|
|
53
|
+
|
|
54
|
+
The client exports typed errors for every failure mode: `JsonRpcResponseError` (a wire error response, code and data preserved), `RequestTimeoutError` (a configured bound elapsed), `SdkProtocolError` (a response outside the documented protocol), and `TransportClosedError` (the runtime is gone — the message carries the exit code and a bounded stderr tail). `close()` requests protocol `shutdown` (bounded by `shutdownTimeoutMs`, default 1000 ms), then walks a stdin-EOF → SIGTERM → SIGKILL ladder until the process has exited; it is idempotent, and a closed client refuses reuse. `HarnessClientOptions.env` replaces the child environment entirely when given (`undefined` inherits the parent's); callers own credential policy — `scrubbedParentEnv` from `dsh-subprocess` is the shared scrub base for isolation-minded launches.
|
|
55
|
+
|
|
56
|
+
-----
|
|
57
|
+
|
|
58
|
+
<a id="understand-the-implementation"></a>
|
|
59
|
+
## Understand the implementation
|
|
60
|
+
|
|
61
|
+
<details>
|
|
62
|
+
<summary>Implementation internals — click to expand</summary>
|
|
63
|
+
|
|
64
|
+
This section explains the design behind the client; the observable behavior is fully covered in [Use this package](#use-this-package).
|
|
65
|
+
|
|
66
|
+
### Design concept
|
|
67
|
+
|
|
68
|
+
The client is two layers over one wire: `DeepSeekHarness` (owned runs) over `HarnessClient` (the protocol client), mirroring the Python SDK's layering. It runs outside any harness context, so it spawns the runtime directly rather than through the `dsh-subprocess` service — the seam's documented exception for SDK-managed transports — and its teardown ladder lives in this package. The runtime notifies for every session in its context; session-tree scoping is a client-side filter over `subagent.started` lineage edges.
|
|
25
69
|
|
|
26
|
-
|
|
70
|
+
### Source map
|
|
27
71
|
|
|
28
|
-
|
|
72
|
+
| File | Role |
|
|
73
|
+
|---|---|
|
|
74
|
+
| [`src/api.ts`](src/api.ts) | `DeepSeekHarness` + `HarnessSession`: owned runs, receipt-to-idle collection, `finalResponse` |
|
|
75
|
+
| [`src/client.ts`](src/client.ts) | `HarnessClient`: spawn, handshake, requests, subscription fan-out, typed errors |
|
|
76
|
+
| [`src/dispose.ts`](src/dispose.ts) | Private teardown ladder: stdin EOF → SIGTERM → SIGKILL to actual exit |
|
|
77
|
+
| [`src/types.ts`](src/types.ts) | Launch and timeout options, notification shapes, `RunResult` |
|
|
78
|
+
| [`src/index.ts`](src/index.ts) | Consumer interface: the two client layers and caller-facing types |
|
|
79
|
+
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion (no runtime invariant — the peer is a separate runtime process) |
|
|
29
80
|
|
|
30
|
-
|
|
81
|
+
### Owned activity flow
|
|
31
82
|
|
|
32
|
-
|
|
83
|
+
A run subscribes to the session tree, queues the prompt, waits until the prompt's message id appears in a durable `agent/inbox/spliced` receipt, then collects notifications until the whole agent reports `idle`. `finalResponse` is derived from the last `assistant/message` in the collected events. Transport loss, timeout, and protocol violations reject the run; model outcomes remain observable in the event stream without being attributed to one input.
|
|
33
84
|
|
|
34
|
-
|
|
85
|
+
### Errors and teardown
|
|
35
86
|
|
|
87
|
+
Every failure mode maps to one exported error class — a wire error response, an elapsed request bound, a response outside the documented protocol, or a dead runtime — so callers branch on failure type; the four classes are exported from [src/index.ts](src/index.ts). Teardown is a private, idempotent escalation (stdin EOF → SIGTERM → SIGKILL) in [src/dispose.ts](src/dispose.ts) that ends only at actual process exit.
|
|
88
|
+
|
|
89
|
+
</details>
|
|
90
|
+
|
|
91
|
+
-----
|
|
92
|
+
|
|
93
|
+
<a id="further-exploration"></a>
|
|
94
|
+
## Further Exploration
|
|
95
|
+
|
|
96
|
+
Read these pages when the client contract is not enough. They move from the wire protocol to the serving plugin and the applications that use this client.
|
|
97
|
+
|
|
98
|
+
- [SDK wire protocol](../protocol/README.md) — the JSON-RPC methods and payload shapes this client speaks.
|
|
99
|
+
- [JSON-RPC serving plugin](../server/README.md) — the runtime plugin that serves this client.
|
|
100
|
+
- [Python SDK](../../../python/README.md) — the design twin that shares the same runtime peer and protocol.
|
|
101
|
+
- [SDK subagent backend](../../subagent/subagent-dsh-sdk/README.md) — a harness-internal consumer of this client.
|
|
102
|
+
- [SDK application bundle](../../bundle/sdk-app/README.md) — the `dsh --profile sdk` runtime application this client launches.
|
|
103
|
+
|
|
104
|
+
-----
|
|
105
|
+
|
|
106
|
+
<a id="model-experience"></a>
|
|
36
107
|
## Model Experience
|
|
37
108
|
|
|
38
|
-
None, as this is a client-process library;
|
|
109
|
+
None, as this is a client-process library; model-facing behavior lives in the spawned runtime's composed plugins.
|
|
39
110
|
|
|
40
111
|
#### KV Cache effect
|
|
41
112
|
|
|
42
|
-
None
|
|
113
|
+
None in the client process. Profile, patch, provider, model, and history choices determine cache reuse in the child.
|
|
43
114
|
|
|
44
115
|
## Known Limitations and Deferred Work
|
|
45
116
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
117
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
These limits define when the client is a poor fit or needs special care. They are current package constraints, not a comparison with other SDK clients or a task backlog.
|
|
121
|
+
|
|
122
|
+
- **No bundled-runtime resolution** — the client resolves the same-version `@deepseek-ai/dsh` package (or a caller-provided `dshBin`); packaged-executable discovery stays Python-side until a TypeScript distribution consumer exists.
|
|
123
|
+
- **No mid-turn cancel** — the wire has no prompt-cancel method; abandoning a turn means closing the runtime (see the [protocol limitations](../protocol/README.md#known-limitations-and-deferred-work)).
|
|
124
|
+
- **No per-prompt result** — low-level `prompt()` returns only an enqueue receipt; high-level `run()` owns receipt-to-idle collection, and abandoning it means closing the runtime.
|
|
49
125
|
- **Client→server notifications and server→client requests are unimplemented** on both wire ends; the transport carries them for future approval flows.
|
|
126
|
+
|
|
127
|
+
<a id="dev-note"></a>
|
|
128
|
+
### Dev Note
|
|
129
|
+
|
|
130
|
+
<details>
|
|
131
|
+
<summary>Working context for maintainers — click to expand</summary>
|
|
132
|
+
|
|
133
|
+
This Dev Note is working context for maintainers and is explicitly non-authoritative — shipped behavior and limits live in the sections above and in the code. The launch spec is intentionally fully explicit: no bundled-runtime resolution is planned for TypeScript until a distribution consumer exists. Keep the dispose ladder and the error vocabulary in sync with the Python client, which drives the same runtime. No other unresolved design questions are recorded.
|
|
134
|
+
|
|
135
|
+
</details>
|
package/README.zh.md
CHANGED
|
@@ -1,49 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "面向以子进程方式启动 DeepSeek Harness 运行时、并通过 stdio JSON-RPC 驱动 agent 轮次的调用方的 TypeScript SDK 客户端:DeepSeekHarness 运行 API 与低层 HarnessClient。"
|
|
3
|
+
kind: "package-library"
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# @deepseek-ai/dsh-sdk-client
|
|
2
7
|
|
|
3
8
|
[English](README.md) | 中文
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
## 概述
|
|
11
|
+
|
|
12
|
+
`dsh-sdk-client` 让 TypeScript 程序以子进程方式、通过 stdio JSON-RPC 驱动 DeepSeek Harness 运行时。使用 `DeepSeekHarness` 你可以启动运行时、打开会话、发送提示词,并收集最终响应以及事件与通知流;`HarnessClient` 提供对协议层的显式控制。它是 [Python SDK](../../../python/README.zh.md) 的设计孪生,共享同一个运行时对端与协议。启动说明是显式的——调用方可通过 `dshBin` 指定运行时可执行文件,省略时解析同版本 `@deepseek-ai/dsh` 包的 bin,参数由客户端构造——因此本客户端适合仓库近旁的 TypeScript 消费方,如 SDK subagent 后端和知道自己要启动哪个运行时的自动化。它是纯库:不在任何 Cordis 上下文注册,而且它启动的运行时是一个完整 harness,其组成由自己的 `cordis.yml` 决定。
|
|
13
|
+
|
|
14
|
+
## 目录
|
|
15
|
+
|
|
16
|
+
- [使用本包](#use-this-package)
|
|
17
|
+
- [理解实现](#understand-the-implementation)
|
|
18
|
+
- [进一步探索](#further-exploration)
|
|
19
|
+
- [模型体验](#model-experience)
|
|
20
|
+
- [已知限制与延期工作](#known-limitations-and-deferred-work)
|
|
21
|
+
- [开发备注](#dev-note)
|
|
6
22
|
|
|
7
|
-
|
|
23
|
+
-----
|
|
8
24
|
|
|
9
|
-
|
|
25
|
+
<a id="use-this-package"></a>
|
|
26
|
+
## 使用本包
|
|
27
|
+
|
|
28
|
+
当 TypeScript 代码需要从另一进程驱动完整 Harness 运行时、且你能显式指名运行时可执行文件时,使用本客户端。常用路径极简:用启动规格构造 `DeepSeekHarness`,运行提示词,然后关闭它,使子进程总能被回收。
|
|
29
|
+
|
|
30
|
+
### 用 DeepSeekHarness 运行 agent 轮次
|
|
10
31
|
|
|
11
32
|
```ts
|
|
12
33
|
import { DeepSeekHarness } from '@deepseek-ai/dsh-sdk-client'
|
|
34
|
+
import { ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
|
13
35
|
|
|
14
36
|
await using harness = new DeepSeekHarness({
|
|
15
|
-
|
|
37
|
+
profile: 'sdk',
|
|
38
|
+
patches: ['./automation.cordis.yml'],
|
|
16
39
|
provider: 'deepseek-official',
|
|
17
40
|
model: 'deepseek-v4-flash',
|
|
41
|
+
reasoningEffort: ReasoningEffortId('max'),
|
|
18
42
|
maxTokens: 49_152,
|
|
19
43
|
})
|
|
20
44
|
const result = await harness.run('say hi')
|
|
21
45
|
console.log(result.finalResponse)
|
|
22
46
|
```
|
|
23
47
|
|
|
24
|
-
子进程在首次使用时惰性启动,并在多次 `run()`
|
|
48
|
+
子进程在首次使用时惰性启动,并在多次 `run()` 调用之间持续归实例所有;请调用 `close()`(或使用 `await using`),子进程才总能被回收。`start()` 会记忆化有界的 `initialize` 握手,其中包含工作区 cwd、提供方/模型路由、可选且由适配器持有的 `reasoningEffort`,以及可选的正整数 `maxTokens` 输出上限。服务器会在接受提示词前校验该确切路由;省略推理强度时保留模型自身的默认值。`initializeTimeoutMs` 默认 10 秒,诊断会写明所选 profile 并附带保留的 stderr 尾部。`run(input, { sessionId?, onNotification? })` 接受文本或 `SdkPromptContentBlock[]`;内联栅格图像块携带规范 base64 与 `mimeType`,并在运行时内变成持久附件。该调用拥有一个活动区间:它将提示词排入队列,等待其消息 id 出现在持久入队回执中,然后持续收集到整个 agent 下一次进入 `idle`。它返回 `RunResult { sessionId, finalResponse, events, notifications }`,其中 `finalResponse` 是该区间内根会话最后提交的助手文本——并非因果上归属于该提示词的响应,因为 steering(中途引导)、注入的上下文和其他排队工作都可能在 idle 前参与其中。`session(id?)` 打开具名或全新的会话句柄。握手失败且清理成功时,实例会换入全新客户端,使后续调用用新进程重试,直到终结性的 `close()`;如果初始化和清理均失败,`start()` 会返回保留两个原因的有序 `AggregateError`,并继续保留失败的客户端,避免在原进程退出尚未得到证明时启动另一个进程。`maxTokens` 限制每个根 agent 请求的输出量,并由进程内后代继承;压缩(compaction)插件单独持有摘要上限。
|
|
49
|
+
|
|
50
|
+
### 用 HarnessClient 做低层控制
|
|
51
|
+
|
|
52
|
+
`HarnessClient` 是运行 API 之下的协议客户端:显式 `start()`、`initialize()`、`prompt()`、`request()` 与 `close()`,外加通知订阅。`prompt()` 在运行时接受排队消息后立即返回该消息的 id,绝不等待 agent 活动。`subscribe(filter?)` 返回 `NotificationSubscription`(可等待的 `next()`、非阻塞 `tryNext()`、异步迭代);`subscribeSessionTree(id)` 把范围限定到一个会话及从 `subagent.started` 血缘边发现的后代——运行时对上下文内每个会话都发通知,范围限定在客户端完成,与 Python SDK 完全一致。
|
|
53
|
+
|
|
54
|
+
本客户端为每种失败模式导出类型化错误:`JsonRpcResponseError`(协议错误响应,保留 code 与 data)、`RequestTimeoutError`(配置的时限已到)、`SdkProtocolError`(响应超出文档化协议)、`TransportClosedError`(运行时已消失——消息携带退出码与有界 stderr 尾部)。`close()` 先请求协议 `shutdown`(受 `shutdownTimeoutMs` 约束,默认 1000 毫秒),然后走 stdin-EOF → SIGTERM → SIGKILL 阶梯直到进程退出;幂等,已关闭的客户端拒绝复用。`HarnessClientOptions.env` 给定时整体替换子进程环境(`undefined` 原样继承父进程环境);凭据策略归调用方——`dsh-subprocess` 的 `scrubbedParentEnv` 是面向隔离启动的共享擦除基底。
|
|
55
|
+
|
|
56
|
+
-----
|
|
57
|
+
|
|
58
|
+
<a id="understand-the-implementation"></a>
|
|
59
|
+
## 理解实现
|
|
60
|
+
|
|
61
|
+
<details>
|
|
62
|
+
<summary>实现细节——点击展开</summary>
|
|
63
|
+
|
|
64
|
+
本节解释客户端背后的设计;可观察行为已在[使用本包](#use-this-package)中完整说明。
|
|
65
|
+
|
|
66
|
+
### 设计理念
|
|
67
|
+
|
|
68
|
+
客户端是同一协议上的两层:`DeepSeekHarness`(自有运行)叠加在 `HarnessClient`(协议客户端)之上,与 Python SDK 的分层一致。它运行在任何 harness 上下文之外,因此直接 spawn 运行时而非经由 `dsh-subprocess` 服务——即该 seam 记录的 SDK 托管传输例外——其关闭阶梯也位于本包。运行时对上下文内每个会话都发通知;会话树范围限定是客户端对 `subagent.started` 血缘边的过滤。
|
|
25
69
|
|
|
26
|
-
|
|
70
|
+
### 源码地图
|
|
27
71
|
|
|
28
|
-
|
|
72
|
+
| 文件 | 职责 |
|
|
73
|
+
|---|---|
|
|
74
|
+
| [`src/api.ts`](src/api.ts) | `DeepSeekHarness` + `HarnessSession`:自有运行、回收到 idle 的收集、`finalResponse` |
|
|
75
|
+
| [`src/client.ts`](src/client.ts) | `HarnessClient`:spawn、握手、请求、订阅扇出、类型化错误 |
|
|
76
|
+
| [`src/dispose.ts`](src/dispose.ts) | 私有关闭阶梯:stdin EOF → SIGTERM → SIGKILL 直到真正退出 |
|
|
77
|
+
| [`src/types.ts`](src/types.ts) | 启动与超时选项、通知结构、`RunResult` |
|
|
78
|
+
| [`src/index.ts`](src/index.ts) | 消费方接口:两层客户端与面向调用方的类型 |
|
|
79
|
+
| [`src/invariant.ts`](src/invariant.ts) | 不变式配套插件(无运行时不变式——对端是独立运行时进程) |
|
|
29
80
|
|
|
30
|
-
|
|
81
|
+
### 自有活动流程
|
|
31
82
|
|
|
32
|
-
|
|
83
|
+
一次运行会订阅会话树、把提示词排入队列,等待提示词的消息 id 出现在持久的 `agent/inbox/spliced` 回执中,然后持续收集通知,直到整个 agent 报告 `idle`。`finalResponse` 从收集到的事件中最后一条 `assistant/message` 派生。传输丢失、超时与协议违例会使本次运行被拒绝;模型结果仍可在事件流中观察,但不会归属于某一输入。
|
|
33
84
|
|
|
34
|
-
|
|
85
|
+
### 错误与关闭
|
|
35
86
|
|
|
87
|
+
每种失败模式都映射到一个导出的错误类——协议错误响应、请求时限已到、响应超出文档化协议、运行时死亡——调用方可以按失败类型分支处理;这四个类从 [src/index.ts](src/index.ts) 导出。关闭采用私有的幂等阶梯(stdin EOF → SIGTERM → SIGKILL),位于 [src/dispose.ts](src/dispose.ts),只在进程真正退出时结束。
|
|
88
|
+
|
|
89
|
+
</details>
|
|
90
|
+
|
|
91
|
+
-----
|
|
92
|
+
|
|
93
|
+
<a id="further-exploration"></a>
|
|
94
|
+
## 进一步探索
|
|
95
|
+
|
|
96
|
+
当客户端约定不够用时阅读以下页面。它们从协议格式进入服务插件与使用本客户端的应用。
|
|
97
|
+
|
|
98
|
+
- [SDK 协议格式](../protocol/README.zh.md) — 本客户端所说的 JSON-RPC 方法与载荷结构。
|
|
99
|
+
- [JSON-RPC 服务插件](../server/README.zh.md) — 服务本客户端的运行时插件。
|
|
100
|
+
- [Python SDK](../../../python/README.zh.md) — 共享同一运行时对端与协议的设计孪生。
|
|
101
|
+
- [SDK subagent 后端](../../subagent/subagent-dsh-sdk/README.zh.md) — harness 内部消费本客户端的例子。
|
|
102
|
+
- [SDK 应用组合包](../../bundle/sdk-app/README.zh.md) — 本客户端启动的 `dsh --profile sdk` 运行时应用。
|
|
103
|
+
|
|
104
|
+
-----
|
|
105
|
+
|
|
106
|
+
<a id="model-experience"></a>
|
|
36
107
|
## 模型体验
|
|
37
108
|
|
|
38
|
-
|
|
109
|
+
无,因为这是客户端进程库;模型可见行为存在于所 spawn 运行时组合的插件中。
|
|
39
110
|
|
|
40
111
|
#### KV Cache 影响
|
|
41
112
|
|
|
42
|
-
|
|
113
|
+
client 进程中无影响。子进程的 profile、patch、provider、model 与历史决定缓存复用。
|
|
114
|
+
|
|
115
|
+
## 已知限制与延期工作
|
|
116
|
+
|
|
117
|
+
<a id="known-limitations-and-deferred-work"></a>
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
这些限制说明本客户端何时不合适或需要特别注意。它们是当前包约束,不是与其他 SDK 客户端的对比或任务积压。
|
|
121
|
+
|
|
122
|
+
- **无捆绑运行时解析**——客户端解析同版本 `@deepseek-ai/dsh` 包(或调用方提供的 `dshBin`);打包可执行文件的发现留在 Python 侧,直到出现 TypeScript 发行版消费方。
|
|
123
|
+
- **无轮次中取消**——协议层没有提示词取消方法;放弃轮次意味着关闭运行时(见[协议限制](../protocol/README.zh.md#known-limitations-and-deferred-work))。
|
|
124
|
+
- **没有逐提示词结果**——低层 `prompt()` 只返回入队回执;高层 `run()` 负责从回收到 idle 的收集,放弃该过程意味着关闭运行时。
|
|
125
|
+
- **客户端→服务端通知与服务端→客户端请求**在协议两端都未实现;传输层为未来审批流程保留了承载能力。
|
|
126
|
+
|
|
127
|
+
<a id="dev-note"></a>
|
|
128
|
+
### 开发备注
|
|
129
|
+
|
|
130
|
+
<details>
|
|
131
|
+
<summary>维护者的工作上下文——点击展开</summary>
|
|
43
132
|
|
|
44
|
-
|
|
133
|
+
本开发备注是维护者的工作上下文,明确不具权威性——已交付的行为与限制见上文各节与代码。启动规格有意保持完全显式:在出现 TypeScript 发行版消费方之前,不计划做捆绑运行时解析。请让关闭阶梯与错误词汇与驱动同一运行时的 Python 客户端保持同步。没有记录其他未解决的开放设计问题。
|
|
45
134
|
|
|
46
|
-
|
|
47
|
-
- **无轮次中取消**——协议层没有提示词取消方法;放弃轮次意味着关闭运行时(见协议的 [已知限制](../protocol/README.zh.md))。
|
|
48
|
-
- **没有逐提示词结果或取消**——低层 `prompt()` 只返回入队回执;高层 `run()` 负责从回执收集到 idle,放弃该过程意味着关闭运行时。
|
|
49
|
-
- **客户端→服务端通知与服务端→客户端请求**在协议两端都未实现;传输层为未来审批流保留了承载能力。
|
|
135
|
+
</details>
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { resolve } from "node:path";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { JsonRpcLineTransport, JsonRpcResponseError, JsonRpcResponseError as JsonRpcResponseError$1 } from "@deepseek-ai/dsh-sdk-protocol";
|
|
5
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
5
7
|
//#region lib/types/dispose.js
|
|
6
8
|
/**
|
|
7
9
|
* Private teardown ladder for the runtime subprocess: stdin EOF (cooperative
|
|
@@ -96,6 +98,97 @@ async function disposeRuntimeProcess(child, graces, platform = process.platform)
|
|
|
96
98
|
}
|
|
97
99
|
await forceTerminateWithin(child, graces.disposeGraceMs);
|
|
98
100
|
}
|
|
101
|
+
/** Read a package manifest from one resolved package.json URL. */
|
|
102
|
+
function manifest(url) {
|
|
103
|
+
return JSON.parse(readFileSync(fileURLToPath(url), "utf8"));
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve and version-check a dsh executable from package manifests.
|
|
107
|
+
* @param dshManifestUrl - resolved URL of the dsh package manifest.
|
|
108
|
+
* @param clientManifestUrl - resolved URL of the SDK client manifest.
|
|
109
|
+
* @returns the absolute dsh executable path.
|
|
110
|
+
*/
|
|
111
|
+
function resolveDshBinFromManifests(dshManifestUrl, clientManifestUrl) {
|
|
112
|
+
const dshManifest = manifest(dshManifestUrl);
|
|
113
|
+
const clientManifest = manifest(clientManifestUrl);
|
|
114
|
+
if (typeof dshManifest.version !== "string" || dshManifest.version !== clientManifest.version) throw new Error(`dsh SDK client ${String(clientManifest.version)} requires the same dsh version, got ${String(dshManifest.version)}`);
|
|
115
|
+
const bin = typeof dshManifest.bin === "object" && dshManifest.bin !== null ? dshManifest.bin.dsh : dshManifest.bin;
|
|
116
|
+
if (typeof bin !== "string" || bin === "") throw new Error("@deepseek-ai/dsh declares no dsh executable");
|
|
117
|
+
return resolve(dirname(fileURLToPath(dshManifestUrl)), bin);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Resolve the Node launch for one same-version dsh package.
|
|
121
|
+
* @param dshManifestUrl - resolved URL of the dsh package manifest.
|
|
122
|
+
* @param clientManifestUrl - resolved URL of the SDK client manifest.
|
|
123
|
+
* @param sourceLoaderUrl - optional absolute tsx loader URL for deterministic tests.
|
|
124
|
+
* @returns built output, or the source entry plus its compatibility patch and tsx environment.
|
|
125
|
+
*/
|
|
126
|
+
function resolveDshNodeLaunchFromManifests(dshManifestUrl, clientManifestUrl, sourceLoaderUrl) {
|
|
127
|
+
const bin = resolveDshBinFromManifests(dshManifestUrl, clientManifestUrl);
|
|
128
|
+
if (existsSync(bin)) return {
|
|
129
|
+
nodeArgs: [bin],
|
|
130
|
+
patches: [],
|
|
131
|
+
environment: {}
|
|
132
|
+
};
|
|
133
|
+
const packageDir = dirname(fileURLToPath(dshManifestUrl));
|
|
134
|
+
const sourceBin = resolve(packageDir, "src/bin.ts");
|
|
135
|
+
const sourcePatch = resolve(packageDir, "src/sdk-source.cordis.patch.yml");
|
|
136
|
+
const sourceTsconfig = resolve(packageDir, "tsconfig.json");
|
|
137
|
+
if (!existsSync(sourceBin) || !existsSync(sourcePatch) || !existsSync(sourceTsconfig)) throw new Error(`@deepseek-ai/dsh is missing its built executable ${bin} and complete source launch files ${sourceBin}, ${sourcePatch}, ${sourceTsconfig}`);
|
|
138
|
+
return {
|
|
139
|
+
nodeArgs: [
|
|
140
|
+
"--import",
|
|
141
|
+
sourceLoaderUrl ?? import.meta.resolve("tsx/esm"),
|
|
142
|
+
sourceBin
|
|
143
|
+
],
|
|
144
|
+
patches: [sourcePatch],
|
|
145
|
+
environment: { TSX_TSCONFIG_PATH: sourceTsconfig }
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Resolve the installed dsh package to a built or source Node launch.
|
|
150
|
+
* @returns the launch descriptor for the current checkout or installed package.
|
|
151
|
+
*/
|
|
152
|
+
function installedDshNodeLaunch() {
|
|
153
|
+
return resolveDshNodeLaunchFromManifests(import.meta.resolve("@deepseek-ai/dsh/package.json"), new URL("../package.json", import.meta.url).href);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Resolve caller-relative filesystem inputs and construct canonical dsh argv.
|
|
157
|
+
* @param options - public SDK launch options.
|
|
158
|
+
* @param callerCwd - parent-process directory used for lexical resolution.
|
|
159
|
+
* @returns one generic subprocess spec for the JSON-RPC transport.
|
|
160
|
+
*/
|
|
161
|
+
function resolveDshLaunch(options = {}, callerCwd = process.cwd()) {
|
|
162
|
+
const profile = options.profile ?? "sdk";
|
|
163
|
+
const dshLaunch = options.dshBin === void 0 ? installedDshNodeLaunch() : {
|
|
164
|
+
nodeArgs: [resolve(callerCwd, options.dshBin)],
|
|
165
|
+
patches: [],
|
|
166
|
+
environment: {}
|
|
167
|
+
};
|
|
168
|
+
const patches = [...dshLaunch.patches, ...(options.patches ?? []).map((path) => resolve(callerCwd, path))];
|
|
169
|
+
const dshHome = options.dshHome === void 0 ? void 0 : resolve(callerCwd, options.dshHome);
|
|
170
|
+
return {
|
|
171
|
+
command: process.execPath,
|
|
172
|
+
args: [
|
|
173
|
+
...dshLaunch.nodeArgs,
|
|
174
|
+
"--profile",
|
|
175
|
+
profile,
|
|
176
|
+
...patches.flatMap((path) => ["--patch", path])
|
|
177
|
+
],
|
|
178
|
+
...options.processCwd === void 0 ? {} : { cwd: resolve(callerCwd, options.processCwd) },
|
|
179
|
+
environment: () => ({
|
|
180
|
+
...options.env ?? process.env,
|
|
181
|
+
...dshLaunch.environment,
|
|
182
|
+
...dshHome === void 0 ? {} : { DSH_HOME: dshHome }
|
|
183
|
+
}),
|
|
184
|
+
description: `dsh profile ${JSON.stringify(profile)}`,
|
|
185
|
+
initializeTimeoutMs: options.initializeTimeoutMs ?? 1e4,
|
|
186
|
+
...options.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: options.requestTimeoutMs },
|
|
187
|
+
...options.shutdownTimeoutMs === void 0 ? {} : { shutdownTimeoutMs: options.shutdownTimeoutMs },
|
|
188
|
+
...options.disposeEofGraceMs === void 0 ? {} : { disposeEofGraceMs: options.disposeEofGraceMs },
|
|
189
|
+
...options.disposeGraceMs === void 0 ? {} : { disposeGraceMs: options.disposeGraceMs }
|
|
190
|
+
};
|
|
191
|
+
}
|
|
99
192
|
//#endregion
|
|
100
193
|
//#region lib/types/client.js
|
|
101
194
|
/**
|
|
@@ -197,7 +290,7 @@ var NotificationSubscriptionImpl = class {
|
|
|
197
290
|
* Deliver one notification to a waiter or the queue when the filter
|
|
198
291
|
* matches. A throwing filter fails only THIS subscription (detached, the
|
|
199
292
|
* throw becomes its terminal error) — it never disturbs sibling
|
|
200
|
-
* subscriptions or the transport's read loop
|
|
293
|
+
* subscriptions or the transport's read loop.
|
|
201
294
|
* @param notification - the wire notification to deliver.
|
|
202
295
|
*/
|
|
203
296
|
push(notification) {
|
|
@@ -233,7 +326,9 @@ var NotificationSubscriptionImpl = class {
|
|
|
233
326
|
* runtime is closed.
|
|
234
327
|
*/
|
|
235
328
|
var HarnessClient = class {
|
|
329
|
+
/** Original public dsh launch and timeout options for this client. */
|
|
236
330
|
options;
|
|
331
|
+
runtime;
|
|
237
332
|
child;
|
|
238
333
|
transport;
|
|
239
334
|
stderrTail = [];
|
|
@@ -244,9 +339,9 @@ var HarnessClient = class {
|
|
|
244
339
|
spawnError;
|
|
245
340
|
streamsSettled = Promise.resolve();
|
|
246
341
|
closeTask;
|
|
247
|
-
|
|
248
|
-
constructor(options) {
|
|
342
|
+
constructor(options = {}, runtime) {
|
|
249
343
|
this.options = options;
|
|
344
|
+
this.runtime = runtime ?? resolveDshLaunch(options);
|
|
250
345
|
}
|
|
251
346
|
/**
|
|
252
347
|
* Spawn the runtime subprocess and start reading frames. Idempotent while
|
|
@@ -255,9 +350,9 @@ var HarnessClient = class {
|
|
|
255
350
|
start() {
|
|
256
351
|
if (this.closeTask !== void 0) throw new TransportClosedError("DeepSeek Harness runtime client is closed");
|
|
257
352
|
if (this.child !== void 0) return;
|
|
258
|
-
const child = spawn(this.
|
|
259
|
-
cwd: this.
|
|
260
|
-
env: this.
|
|
353
|
+
const child = spawn(this.runtime.command, this.runtime.args, {
|
|
354
|
+
cwd: this.runtime.cwd,
|
|
355
|
+
env: this.runtime.environment(),
|
|
261
356
|
stdio: [
|
|
262
357
|
"pipe",
|
|
263
358
|
"pipe",
|
|
@@ -323,7 +418,7 @@ var HarnessClient = class {
|
|
|
323
418
|
* @returns the runtime's wire identity.
|
|
324
419
|
*/
|
|
325
420
|
async initialize(params) {
|
|
326
|
-
const result = await this.request("initialize", { ...params });
|
|
421
|
+
const result = await this.request("initialize", { ...params }, this.runtime.initializeTimeoutMs);
|
|
327
422
|
if (!isRecord(result) || !isRecord(result.serverInfo) || typeof result.serverInfo.name !== "string" || typeof result.serverInfo.version !== "string") throw new SdkProtocolError(`initialize returned no server identity: ${JSON.stringify(result)}`);
|
|
328
423
|
return { serverInfo: {
|
|
329
424
|
name: result.serverInfo.name,
|
|
@@ -363,12 +458,13 @@ var HarnessClient = class {
|
|
|
363
458
|
const transport = this.transport;
|
|
364
459
|
/* v8 ignore next -- start() either sets the transport or throws */
|
|
365
460
|
if (transport === void 0) throw new TransportClosedError("DeepSeek Harness runtime is not running");
|
|
366
|
-
const timeout = timeoutMs ?? this.
|
|
461
|
+
const timeout = timeoutMs ?? this.runtime.requestTimeoutMs;
|
|
367
462
|
try {
|
|
368
463
|
if (timeout === void 0) return await transport.request(method, params ?? {});
|
|
369
464
|
const abandon = new AbortController();
|
|
370
465
|
const timer = setTimeout(() => {
|
|
371
|
-
|
|
466
|
+
const stderr = this.stderrTail.length === 0 ? "" : `; stderr tail:\n${this.stderrTail.join("\n")}`;
|
|
467
|
+
abandon.abort(new RequestTimeoutError(`${method} timed out after ${timeout}ms waiting for ${this.runtime.description}${stderr}`));
|
|
372
468
|
}, timeout);
|
|
373
469
|
try {
|
|
374
470
|
return await transport.request(method, params ?? {}, abandon.signal);
|
|
@@ -407,8 +503,8 @@ var HarnessClient = class {
|
|
|
407
503
|
}
|
|
408
504
|
/**
|
|
409
505
|
* Subscribe to one session and the descendants discovered from
|
|
410
|
-
* `subagent.started` lineage edges
|
|
411
|
-
* in its context
|
|
506
|
+
* `subagent.started` lineage edges. The runtime notifies for every session
|
|
507
|
+
* in its context, so this client applies the scope.
|
|
412
508
|
* @param sessionId - the root session id.
|
|
413
509
|
* @returns the filtered subscription handle.
|
|
414
510
|
*/
|
|
@@ -438,13 +534,13 @@ var HarnessClient = class {
|
|
|
438
534
|
const child = this.child;
|
|
439
535
|
if (child === void 0) return;
|
|
440
536
|
try {
|
|
441
|
-
await this.request("shutdown", void 0, this.
|
|
537
|
+
await this.request("shutdown", void 0, this.runtime.shutdownTimeoutMs ?? 1e3);
|
|
442
538
|
} catch (error) {
|
|
443
539
|
this.appendStderr([`shutdown request failed: ${errorMessage(error)}`]);
|
|
444
540
|
}
|
|
445
541
|
await disposeRuntimeProcess(child, {
|
|
446
|
-
disposeEofGraceMs: this.
|
|
447
|
-
disposeGraceMs: this.
|
|
542
|
+
disposeEofGraceMs: this.runtime.disposeEofGraceMs ?? 6e3,
|
|
543
|
+
disposeGraceMs: this.runtime.disposeGraceMs ?? 3e3
|
|
448
544
|
});
|
|
449
545
|
this.transport?.close();
|
|
450
546
|
this.failSubscriptions(this.closedError("DeepSeek Harness runtime closed"));
|
|
@@ -486,7 +582,7 @@ var HarnessClient = class {
|
|
|
486
582
|
})]);
|
|
487
583
|
}
|
|
488
584
|
closedError(reason) {
|
|
489
|
-
const parts = [reason];
|
|
585
|
+
const parts = [`${this.runtime.description}: ${reason}`];
|
|
490
586
|
if (this.spawnError !== void 0) parts.push(`spawn error: ${this.spawnError.message}`);
|
|
491
587
|
if (this.exitCode !== void 0) parts.push(`exit code: ${String(this.exitCode)}`);
|
|
492
588
|
if (this.stderrTail.length > 0) parts.push(`stderr tail:\n${this.stderrTail.join("\n")}`);
|
|
@@ -512,7 +608,6 @@ function errorMessage(error) {
|
|
|
512
608
|
* High-level run API over {@link HarnessClient}: `DeepSeekHarness` owns one
|
|
513
609
|
* runtime subprocess across many sessions; `HarnessSession.run` sends a
|
|
514
610
|
* prompt and settles when the whole agent next becomes idle.
|
|
515
|
-
* Mirrors the Python SDK's `DeepSeekHarness`/`Session` pair.
|
|
516
611
|
*
|
|
517
612
|
* @module @deepseek-ai/dsh-sdk-client/api
|
|
518
613
|
*/
|
|
@@ -524,26 +619,28 @@ function errorMessage(error) {
|
|
|
524
619
|
*/
|
|
525
620
|
var DeepSeekHarness = class {
|
|
526
621
|
clientInstance;
|
|
527
|
-
|
|
622
|
+
createClient;
|
|
528
623
|
cwd;
|
|
529
624
|
provider;
|
|
530
625
|
model;
|
|
626
|
+
reasoningEffort;
|
|
531
627
|
maxTokens;
|
|
532
628
|
initialized;
|
|
533
629
|
closed = false;
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
this.
|
|
537
|
-
this.
|
|
538
|
-
this.cwd = resolve(options.cwd ?? options.launch.cwd ?? process.cwd());
|
|
630
|
+
constructor(options = {}, clientFactory) {
|
|
631
|
+
this.createClient = clientFactory ?? (() => new HarnessClient(options));
|
|
632
|
+
this.clientInstance = this.createClient();
|
|
633
|
+
this.cwd = resolve(options.cwd ?? options.processCwd ?? process.cwd());
|
|
539
634
|
this.provider = options.provider ?? "deepseek-official";
|
|
540
635
|
this.model = options.model ?? "deepseek-v4-flash";
|
|
636
|
+
this.reasoningEffort = options.reasoningEffort;
|
|
541
637
|
this.maxTokens = options.maxTokens;
|
|
542
638
|
}
|
|
543
639
|
/**
|
|
544
640
|
* The underlying JSON-RPC client (exposed for low-level access). A failed
|
|
545
|
-
* handshake
|
|
546
|
-
*
|
|
641
|
+
* handshake swaps in a fresh instance only after cleanup proves the runtime
|
|
642
|
+
* exited; cleanup failure retains this client, so do not cache it across a
|
|
643
|
+
* failed {@link start}.
|
|
547
644
|
* @returns the client currently owning the runtime subprocess.
|
|
548
645
|
*/
|
|
549
646
|
get client() {
|
|
@@ -551,9 +648,12 @@ var DeepSeekHarness = class {
|
|
|
551
648
|
}
|
|
552
649
|
/**
|
|
553
650
|
* Start the subprocess and perform the `initialize` handshake once. On
|
|
554
|
-
* failure
|
|
555
|
-
* (`HarnessClient.close` is permanent), so a later call retries
|
|
556
|
-
* subprocess
|
|
651
|
+
* failure, successful SDK-owned cleanup reaps the runtime and installs a
|
|
652
|
+
* fresh client (`HarnessClient.close` is permanent), so a later call retries
|
|
653
|
+
* with a new subprocess unless {@link close} already ended this harness. If
|
|
654
|
+
* cleanup also fails, rejects with an `AggregateError` whose ordered errors
|
|
655
|
+
* preserve both causes and retains the failed client rather than spawning
|
|
656
|
+
* alongside a process whose exit was not proved.
|
|
557
657
|
* @returns settlement of the (memoized) handshake.
|
|
558
658
|
*/
|
|
559
659
|
start() {
|
|
@@ -564,12 +664,17 @@ var DeepSeekHarness = class {
|
|
|
564
664
|
cwd: this.cwd,
|
|
565
665
|
provider: this.provider,
|
|
566
666
|
model: this.model,
|
|
667
|
+
...this.reasoningEffort === void 0 ? {} : { reasoningEffort: this.reasoningEffort },
|
|
567
668
|
...this.maxTokens === void 0 ? {} : { maxTokens: this.maxTokens }
|
|
568
669
|
});
|
|
569
670
|
} catch (error) {
|
|
570
671
|
this.initialized = void 0;
|
|
571
|
-
|
|
572
|
-
|
|
672
|
+
try {
|
|
673
|
+
await this.clientInstance.close();
|
|
674
|
+
} catch (cleanupError) {
|
|
675
|
+
throw new AggregateError([error, cleanupError], "DeepSeek Harness initialization and cleanup failed");
|
|
676
|
+
}
|
|
677
|
+
if (!this.closed) this.clientInstance = this.createClient();
|
|
573
678
|
throw error;
|
|
574
679
|
}
|
|
575
680
|
})();
|
|
@@ -683,6 +788,24 @@ function normalizeInput(input) {
|
|
|
683
788
|
text: input
|
|
684
789
|
}] : input;
|
|
685
790
|
}
|
|
791
|
+
/** Validate the provider-read fields of one wire turn-end reason. */
|
|
792
|
+
function validatedTurnEndReason(value) {
|
|
793
|
+
if (!isRecord(value) || typeof value.kind !== "string") throw new SdkProtocolError(`turn/end carried no reason envelope: ${JSON.stringify(value)}`);
|
|
794
|
+
if (value.kind === "aborted") {
|
|
795
|
+
if (!isRecord(value.reason) || typeof value.reason.kind !== "string") throw new SdkProtocolError(`turn/end carried a malformed aborted reason: ${JSON.stringify(value)}`);
|
|
796
|
+
switch (value.reason.kind) {
|
|
797
|
+
case "user":
|
|
798
|
+
case "parent":
|
|
799
|
+
case "disposed":
|
|
800
|
+
case "legacy": break;
|
|
801
|
+
case "hook":
|
|
802
|
+
if (typeof value.reason.reason !== "string") throw new SdkProtocolError(`turn/end carried a malformed hook abort reason: ${JSON.stringify(value)}`);
|
|
803
|
+
break;
|
|
804
|
+
default: throw new SdkProtocolError(`turn/end carried an unknown abort reason: ${JSON.stringify(value)}`);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
return value;
|
|
808
|
+
}
|
|
686
809
|
/** Validate the fields in a wire `session.event` envelope before returning the typed result. */
|
|
687
810
|
function validatedSessionEvent(value) {
|
|
688
811
|
if (!isRecord(value) || typeof value.type !== "string") throw new SdkProtocolError(`session.event carried no event envelope: ${JSON.stringify(value)}`);
|
|
@@ -691,6 +814,11 @@ function validatedSessionEvent(value) {
|
|
|
691
814
|
const content = isRecord(message) ? message.content : void 0;
|
|
692
815
|
if (!Array.isArray(content) || !content.every((block) => isRecord(block) && typeof block.type === "string")) throw new SdkProtocolError(`assistant/message event carried malformed content: ${JSON.stringify(value)}`);
|
|
693
816
|
}
|
|
817
|
+
if (value.type === "turn/end") {
|
|
818
|
+
const data = isRecord(value.data) ? value.data : void 0;
|
|
819
|
+
if (data === void 0) throw new SdkProtocolError(`turn/end event carried malformed data: ${JSON.stringify(value)}`);
|
|
820
|
+
validatedTurnEndReason(data.reason);
|
|
821
|
+
}
|
|
694
822
|
return value;
|
|
695
823
|
}
|
|
696
824
|
/** Whether a raw session event is the durable enqueue receipt for `messageId`. */
|
package/lib/types/api.d.ts
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
* High-level run API over {@link HarnessClient}: `DeepSeekHarness` owns one
|
|
3
3
|
* runtime subprocess across many sessions; `HarnessSession.run` sends a
|
|
4
4
|
* prompt and settles when the whole agent next becomes idle.
|
|
5
|
-
* Mirrors the Python SDK's `DeepSeekHarness`/`Session` pair.
|
|
6
5
|
*
|
|
7
6
|
* @module @deepseek-ai/dsh-sdk-client/api
|
|
8
7
|
*/
|
|
9
8
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
10
9
|
import { HarnessClient } from './client.ts';
|
|
11
|
-
import type {
|
|
10
|
+
import type { RuntimeProcessOptions } from './launch.ts';
|
|
11
|
+
import type { DeepSeekHarnessOptions, HarnessNotification, RunResult, SdkPromptContentBlock } from './types.ts';
|
|
12
12
|
/**
|
|
13
13
|
* Reusable SDK for running DeepSeek Harness agent turns in a runtime
|
|
14
14
|
* subprocess. The subprocess starts lazily on first use and stays owned by
|
|
@@ -17,27 +17,32 @@ import type { ContentBlock, DeepSeekHarnessOptions, HarnessNotification, RunResu
|
|
|
17
17
|
*/
|
|
18
18
|
export declare class DeepSeekHarness implements AsyncDisposable {
|
|
19
19
|
private clientInstance;
|
|
20
|
-
private readonly
|
|
20
|
+
private readonly createClient;
|
|
21
21
|
private readonly cwd;
|
|
22
22
|
private readonly provider;
|
|
23
23
|
private readonly model;
|
|
24
|
+
private readonly reasoningEffort;
|
|
24
25
|
private readonly maxTokens;
|
|
25
26
|
private initialized;
|
|
26
27
|
private closed;
|
|
27
|
-
/** @param options -
|
|
28
|
-
constructor(options
|
|
28
|
+
/** @param options - dsh launch configuration plus the session route, effort, and output cap. */
|
|
29
|
+
constructor(options?: DeepSeekHarnessOptions);
|
|
29
30
|
/**
|
|
30
31
|
* The underlying JSON-RPC client (exposed for low-level access). A failed
|
|
31
|
-
* handshake
|
|
32
|
-
*
|
|
32
|
+
* handshake swaps in a fresh instance only after cleanup proves the runtime
|
|
33
|
+
* exited; cleanup failure retains this client, so do not cache it across a
|
|
34
|
+
* failed {@link start}.
|
|
33
35
|
* @returns the client currently owning the runtime subprocess.
|
|
34
36
|
*/
|
|
35
37
|
get client(): HarnessClient;
|
|
36
38
|
/**
|
|
37
39
|
* Start the subprocess and perform the `initialize` handshake once. On
|
|
38
|
-
* failure
|
|
39
|
-
* (`HarnessClient.close` is permanent), so a later call retries
|
|
40
|
-
* subprocess
|
|
40
|
+
* failure, successful SDK-owned cleanup reaps the runtime and installs a
|
|
41
|
+
* fresh client (`HarnessClient.close` is permanent), so a later call retries
|
|
42
|
+
* with a new subprocess unless {@link close} already ended this harness. If
|
|
43
|
+
* cleanup also fails, rejects with an `AggregateError` whose ordered errors
|
|
44
|
+
* preserve both causes and retains the failed client rather than spawning
|
|
45
|
+
* alongside a process whose exit was not proved.
|
|
41
46
|
* @returns settlement of the (memoized) handshake.
|
|
42
47
|
*/
|
|
43
48
|
start(): Promise<void>;
|
|
@@ -54,7 +59,7 @@ export declare class DeepSeekHarness implements AsyncDisposable {
|
|
|
54
59
|
* @param options - optional session id and per-notification observer.
|
|
55
60
|
* @returns the owned activity interval.
|
|
56
61
|
*/
|
|
57
|
-
run(input: string |
|
|
62
|
+
run(input: string | SdkPromptContentBlock[], options?: RunOptions): Promise<RunResult>;
|
|
58
63
|
/**
|
|
59
64
|
* Shut down and reap the runtime subprocess. Idempotent and terminal —
|
|
60
65
|
* a closed harness no longer retries a failed handshake.
|
|
@@ -67,6 +72,8 @@ export declare class DeepSeekHarness implements AsyncDisposable {
|
|
|
67
72
|
*/
|
|
68
73
|
[Symbol.asyncDispose](): Promise<void>;
|
|
69
74
|
}
|
|
75
|
+
/** Construct the high-level API against a generic process for package-local fake-runtime tests. */
|
|
76
|
+
export declare function createProcessDeepSeekHarness(runtime: RuntimeProcessOptions, options?: DeepSeekHarnessOptions): DeepSeekHarness;
|
|
70
77
|
/** Per-run options: target session and streaming observer. */
|
|
71
78
|
export interface RunOptions {
|
|
72
79
|
/** Session id to run on; omitted mints a fresh session per call. */
|
|
@@ -92,14 +99,14 @@ export declare class HarnessSession {
|
|
|
92
99
|
* @returns the owned activity interval; rejects on transport loss, timeout,
|
|
93
100
|
* or a protocol error.
|
|
94
101
|
*/
|
|
95
|
-
run(input: string |
|
|
102
|
+
run(input: string | SdkPromptContentBlock[], options?: Pick<RunOptions, 'onNotification'>): Promise<RunResult>;
|
|
96
103
|
}
|
|
97
104
|
/**
|
|
98
105
|
* Normalize run input: a string becomes one text block; blocks pass verbatim.
|
|
99
106
|
* @param input - prompt text or content blocks.
|
|
100
107
|
* @returns the content blocks to send.
|
|
101
108
|
*/
|
|
102
|
-
export declare function normalizeInput(input: string |
|
|
109
|
+
export declare function normalizeInput(input: string | SdkPromptContentBlock[]): SdkPromptContentBlock[];
|
|
103
110
|
/**
|
|
104
111
|
* Extract the concatenated text of the last assistant message.
|
|
105
112
|
* @param events - the activity interval's `session.event` payloads in wire order.
|
package/lib/types/client.d.ts
CHANGED
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
*
|
|
12
12
|
* @module @deepseek-ai/dsh-sdk-client/client
|
|
13
13
|
*/
|
|
14
|
-
import { type InitializeParams, type InitializeResult } from '@deepseek-ai/dsh-sdk-protocol';
|
|
15
|
-
import type
|
|
14
|
+
import { type InitializeParams, type InitializeResult, type SdkPromptContentBlock } from '@deepseek-ai/dsh-sdk-protocol';
|
|
15
|
+
import { type RuntimeProcessOptions } from './launch.ts';
|
|
16
16
|
import type { HarnessClientOptions, HarnessNotification, NotificationFilter } from './types.ts';
|
|
17
17
|
/**
|
|
18
18
|
* The runtime subprocess is gone or unusable: it exited, its stdio closed, or
|
|
@@ -63,7 +63,9 @@ export interface NotificationSubscription extends AsyncIterable<HarnessNotificat
|
|
|
63
63
|
* runtime is closed.
|
|
64
64
|
*/
|
|
65
65
|
export declare class HarnessClient {
|
|
66
|
+
/** Original public dsh launch and timeout options for this client. */
|
|
66
67
|
readonly options: HarnessClientOptions;
|
|
68
|
+
private readonly runtime;
|
|
67
69
|
private child;
|
|
68
70
|
private transport;
|
|
69
71
|
private readonly stderrTail;
|
|
@@ -74,8 +76,8 @@ export declare class HarnessClient {
|
|
|
74
76
|
private spawnError;
|
|
75
77
|
private streamsSettled;
|
|
76
78
|
private closeTask;
|
|
77
|
-
/** @param options -
|
|
78
|
-
constructor(options
|
|
79
|
+
/** @param options - dsh profile, patch, home, process, environment, and timeout options. */
|
|
80
|
+
constructor(options?: HarnessClientOptions);
|
|
79
81
|
/**
|
|
80
82
|
* Spawn the runtime subprocess and start reading frames. Idempotent while
|
|
81
83
|
* the process is live; rejects reuse after {@link close}.
|
|
@@ -93,7 +95,7 @@ export declare class HarnessClient {
|
|
|
93
95
|
* @param contentBlocks - the user message, sent verbatim.
|
|
94
96
|
* @returns the queued message id.
|
|
95
97
|
*/
|
|
96
|
-
prompt(sessionId: string, contentBlocks:
|
|
98
|
+
prompt(sessionId: string, contentBlocks: SdkPromptContentBlock[]): Promise<string>;
|
|
97
99
|
/**
|
|
98
100
|
* Send one JSON-RPC request and await its result.
|
|
99
101
|
* @param method - the wire method name.
|
|
@@ -114,8 +116,8 @@ export declare class HarnessClient {
|
|
|
114
116
|
subscribe(filter?: NotificationFilter): NotificationSubscription;
|
|
115
117
|
/**
|
|
116
118
|
* Subscribe to one session and the descendants discovered from
|
|
117
|
-
* `subagent.started` lineage edges
|
|
118
|
-
* in its context
|
|
119
|
+
* `subagent.started` lineage edges. The runtime notifies for every session
|
|
120
|
+
* in its context, so this client applies the scope.
|
|
119
121
|
* @param sessionId - the root session id.
|
|
120
122
|
* @returns the filtered subscription handle.
|
|
121
123
|
*/
|
|
@@ -136,6 +138,8 @@ export declare class HarnessClient {
|
|
|
136
138
|
private settleStreams;
|
|
137
139
|
private closedError;
|
|
138
140
|
}
|
|
141
|
+
/** Construct the transport against a generic process for package-local fake-runtime tests. */
|
|
142
|
+
export declare function createProcessHarnessClient(options: RuntimeProcessOptions): HarnessClient;
|
|
139
143
|
/**
|
|
140
144
|
* Whether `value` is a plain JSON object (the wire-boundary shape probe).
|
|
141
145
|
* @param value - the wire value to probe.
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TypeScript client SDK for the DeepSeek Harness runtime: spawn the
|
|
3
|
-
* `dsh
|
|
4
|
-
* stdio JSON-RPC. `DeepSeekHarness` is the high-level run API;
|
|
3
|
+
* same-version `dsh --profile sdk` runtime as a subprocess and drive agent
|
|
4
|
+
* turns over stdio JSON-RPC. `DeepSeekHarness` is the high-level run API;
|
|
5
5
|
* `HarnessClient` is the lower-level protocol client. A pure library — it
|
|
6
|
-
* registers nothing on a Cordis context;
|
|
7
|
-
*
|
|
6
|
+
* registers nothing on a Cordis context; named profiles and ordered patch
|
|
7
|
+
* files customize the runtime process it spawns.
|
|
8
8
|
*
|
|
9
9
|
* @module @deepseek-ai/dsh-sdk-client
|
|
10
10
|
*/
|
|
@@ -13,5 +13,5 @@ export type { RunOptions } from './api.ts';
|
|
|
13
13
|
export { HarnessClient, RequestTimeoutError, SdkProtocolError, TransportClosedError, } from './client.ts';
|
|
14
14
|
export type { NotificationSubscription } from './client.ts';
|
|
15
15
|
export { JsonRpcResponseError } from '@deepseek-ai/dsh-sdk-protocol';
|
|
16
|
-
export type { ContentBlock, DeepSeekHarnessOptions, HarnessClientOptions, HarnessNotification, NotificationFilter, RunResult, } from './types.ts';
|
|
16
|
+
export type { ContentBlock, SdkPromptContentBlock, DeepSeekHarnessOptions, HarnessClientOptions, HarnessNotification, NotificationFilter, RunResult, } from './types.ts';
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the public SDK launch configuration to one dsh subprocess.
|
|
3
|
+
* @module @deepseek-ai/dsh-sdk-client/launch
|
|
4
|
+
*/
|
|
5
|
+
import type { HarnessClientOptions } from './types.ts';
|
|
6
|
+
/** Default bound for a profile to answer the SDK initialize handshake. */
|
|
7
|
+
export declare const DEFAULT_INITIALIZE_TIMEOUT_MS = 10000;
|
|
8
|
+
/** Internal generic process launch used by the transport and fake-runtime tests. */
|
|
9
|
+
export interface RuntimeProcessOptions {
|
|
10
|
+
command: string;
|
|
11
|
+
args: string[];
|
|
12
|
+
cwd?: string;
|
|
13
|
+
/** Materialize the complete child environment when the client starts its subprocess. */
|
|
14
|
+
environment: () => NodeJS.ProcessEnv;
|
|
15
|
+
description: string;
|
|
16
|
+
initializeTimeoutMs: number;
|
|
17
|
+
requestTimeoutMs?: number;
|
|
18
|
+
shutdownTimeoutMs?: number;
|
|
19
|
+
disposeEofGraceMs?: number;
|
|
20
|
+
disposeGraceMs?: number;
|
|
21
|
+
}
|
|
22
|
+
/** Node argv plus internal profile patches required by one resolved dsh entry. */
|
|
23
|
+
export interface DshNodeLaunch {
|
|
24
|
+
/** Arguments before the profile selector. */
|
|
25
|
+
nodeArgs: string[];
|
|
26
|
+
/** Internal patches applied below caller-supplied patches. */
|
|
27
|
+
patches: string[];
|
|
28
|
+
/** Environment values required by the resolved entry mode. */
|
|
29
|
+
environment: NodeJS.ProcessEnv;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve and version-check a dsh executable from package manifests.
|
|
33
|
+
* @param dshManifestUrl - resolved URL of the dsh package manifest.
|
|
34
|
+
* @param clientManifestUrl - resolved URL of the SDK client manifest.
|
|
35
|
+
* @returns the absolute dsh executable path.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveDshBinFromManifests(dshManifestUrl: string, clientManifestUrl: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve and version-check the built dsh executable installed with this SDK.
|
|
40
|
+
* @returns the absolute built executable path, whether or not it exists in a source checkout.
|
|
41
|
+
*/
|
|
42
|
+
export declare function installedDshBin(): string;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the Node launch for one same-version dsh package.
|
|
45
|
+
* @param dshManifestUrl - resolved URL of the dsh package manifest.
|
|
46
|
+
* @param clientManifestUrl - resolved URL of the SDK client manifest.
|
|
47
|
+
* @param sourceLoaderUrl - optional absolute tsx loader URL for deterministic tests.
|
|
48
|
+
* @returns built output, or the source entry plus its compatibility patch and tsx environment.
|
|
49
|
+
*/
|
|
50
|
+
export declare function resolveDshNodeLaunchFromManifests(dshManifestUrl: string, clientManifestUrl: string, sourceLoaderUrl?: string): DshNodeLaunch;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve caller-relative filesystem inputs and construct canonical dsh argv.
|
|
53
|
+
* @param options - public SDK launch options.
|
|
54
|
+
* @param callerCwd - parent-process directory used for lexical resolution.
|
|
55
|
+
* @returns one generic subprocess spec for the JSON-RPC transport.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveDshLaunch(options?: HarnessClientOptions, callerCwd?: string): RuntimeProcessOptions;
|
|
58
|
+
//# sourceMappingURL=launch.d.ts.map
|
package/lib/types/types.d.ts
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* @module @deepseek-ai/dsh-sdk-client/types
|
|
6
6
|
*/
|
|
7
|
-
import type { ContentBlock } from '@deepseek-ai/dsh-llm';
|
|
7
|
+
import type { ContentBlock, ReasoningEffortId } from '@deepseek-ai/dsh-llm';
|
|
8
|
+
import type { SdkPromptContentBlock } from '@deepseek-ai/dsh-sdk-protocol';
|
|
8
9
|
import type { SessionEvent } from '@deepseek-ai/dsh-session';
|
|
9
10
|
/** One server-to-client notification as received off the wire. */
|
|
10
11
|
export interface HarnessNotification {
|
|
@@ -17,19 +18,26 @@ export interface HarnessNotification {
|
|
|
17
18
|
export type NotificationFilter = (notification: HarnessNotification) => boolean;
|
|
18
19
|
/** Launch and timeout options for {@link HarnessClient}. */
|
|
19
20
|
export interface HarnessClientOptions {
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
|
|
21
|
+
/** Absolute or caller-relative dsh CLI module; omitted resolves this package's same-version dependency. */
|
|
22
|
+
dshBin?: string;
|
|
23
|
+
/** Named profile serving the SDK protocol (default `sdk`). */
|
|
24
|
+
profile?: string;
|
|
25
|
+
/** Ordered per-launch profile patches; relative paths resolve before spawn. */
|
|
26
|
+
patches?: string[];
|
|
27
|
+
/** Explicit Harness home for this child; relative paths resolve before spawn. */
|
|
28
|
+
dshHome?: string;
|
|
29
|
+
/** Working directory for the dsh process itself. */
|
|
30
|
+
processCwd?: string;
|
|
26
31
|
/**
|
|
27
|
-
* The complete child environment
|
|
28
|
-
*
|
|
32
|
+
* The complete child environment, read when {@link HarnessClient.start}
|
|
33
|
+
* spawns. `undefined` reads the parent env at that time; passing an object
|
|
34
|
+
* reads that object at spawn and replaces the parent environment entirely, so callers own
|
|
29
35
|
* credential policy (see `scrubbedParentEnv` in `@deepseek-ai/dsh-subprocess`
|
|
30
36
|
* for the shared scrub-then-merge base).
|
|
31
37
|
*/
|
|
32
38
|
env?: NodeJS.ProcessEnv;
|
|
39
|
+
/** Bound (ms) on the initial profile handshake (default 10000). */
|
|
40
|
+
initializeTimeoutMs?: number;
|
|
33
41
|
/** Per-request timeout (ms); `undefined` waits indefinitely (a turn can legitimately run long). */
|
|
34
42
|
requestTimeoutMs?: number;
|
|
35
43
|
/** Bound (ms) on the protocol `shutdown` exchange inside `close()` (default 1000). */
|
|
@@ -40,15 +48,15 @@ export interface HarnessClientOptions {
|
|
|
40
48
|
disposeGraceMs?: number;
|
|
41
49
|
}
|
|
42
50
|
/** Options for the high-level {@link DeepSeekHarness} wrapper. */
|
|
43
|
-
export interface DeepSeekHarnessOptions {
|
|
44
|
-
/**
|
|
45
|
-
launch: HarnessClientOptions;
|
|
46
|
-
/** Workspace cwd recorded on every SDK-created session (default: the launch cwd, else `process.cwd()`). */
|
|
51
|
+
export interface DeepSeekHarnessOptions extends HarnessClientOptions {
|
|
52
|
+
/** Workspace cwd recorded on every SDK-created session (default: the process cwd, else `process.cwd()`). */
|
|
47
53
|
cwd?: string;
|
|
48
54
|
/** Provider route for SDK-created agents (default `deepseek-official`). */
|
|
49
55
|
provider?: string;
|
|
50
56
|
/** Model for SDK-created agents (default `deepseek-v4-flash`). */
|
|
51
57
|
model?: string;
|
|
58
|
+
/** Adapter-owned reasoning effort for the selected provider/model route. */
|
|
59
|
+
reasoningEffort?: ReasoningEffortId;
|
|
52
60
|
/** Maximum output tokens for each conversation-model request. */
|
|
53
61
|
maxTokens?: number;
|
|
54
62
|
}
|
|
@@ -65,4 +73,5 @@ export interface RunResult {
|
|
|
65
73
|
}
|
|
66
74
|
/** Re-exported content-block alias so SDK callers need no extra import. */
|
|
67
75
|
export type { ContentBlock };
|
|
76
|
+
export type { SdkPromptContentBlock };
|
|
68
77
|
//# sourceMappingURL=types.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-sdk-client",
|
|
3
3
|
"description": "TypeScript client SDK for driving a DeepSeek Harness runtime subprocess over stdio JSON-RPC: the DeepSeekHarness high-level turns API and the lower-level HarnessClient",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.2-alpha.2",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -30,18 +30,21 @@
|
|
|
30
30
|
"lib/types/**/*.d.ts"
|
|
31
31
|
],
|
|
32
32
|
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@deepseek-ai/dsh": "0.1.2-alpha.2"
|
|
35
|
+
},
|
|
33
36
|
"peerDependencies": {
|
|
34
|
-
"@deepseek-ai/dsh-invariants": "^0.1.
|
|
35
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
36
|
-
"@deepseek-ai/dsh-sdk-protocol": "^0.1.
|
|
37
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
38
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
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-protocol": "^0.1.2-alpha.2",
|
|
40
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
|
|
41
|
+
"@deepseek-ai/cordis": "^4.0.2"
|
|
39
42
|
},
|
|
40
43
|
"devDependencies": {
|
|
41
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
42
|
-
"@deepseek-ai/dsh-
|
|
43
|
-
"@deepseek-ai/dsh-
|
|
44
|
-
"@deepseek-ai/
|
|
45
|
-
"@deepseek-ai/
|
|
44
|
+
"@deepseek-ai/dsh-llm": "^0.1.2-alpha.2",
|
|
45
|
+
"@deepseek-ai/dsh-sdk-protocol": "^0.1.2-alpha.2",
|
|
46
|
+
"@deepseek-ai/dsh-session": "^0.1.2-alpha.2",
|
|
47
|
+
"@deepseek-ai/cordis": "^4.0.2",
|
|
48
|
+
"@deepseek-ai/dsh-invariants": "^0.1.2-alpha.2"
|
|
46
49
|
}
|
|
47
50
|
}
|