@deepseek-ai/dsh-sdk-client 0.2.1-alpha.1 → 0.2.1-alpha.3

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
@@ -15,14 +15,14 @@
15
15
  en: d152484eb41ac6b4
16
16
  zh: 09388d293f9be9cb
17
17
  /deepseek-ai-dsh-sdk-client/use-this-package:
18
- en: 3c21c7ec64d17346
19
- zh: c6ba1b632b8a4d72
18
+ en: ff421f12a5db28a4
19
+ zh: 2ca9b71a3458b5e0
20
20
  /deepseek-ai-dsh-sdk-client/use-this-package/running-agent-turns-with-deepseekharness:
21
21
  en: 01c58dddd7e62de2
22
22
  zh: 6dbd46e244f3f135
23
23
  /deepseek-ai-dsh-sdk-client/use-this-package/lower-level-control-with-harnessclient:
24
- en: 8e7eb3a9b3f91404
25
- zh: 277a722586dcb549
24
+ en: 8778901987da6e59
25
+ zh: 3d09fe4b0b393a15
26
26
  /deepseek-ai-dsh-sdk-client/understand-the-implementation:
27
27
  en: 8773f50c51da85f0
28
28
  zh: 4649ebc69357deb0
package/README.md CHANGED
@@ -25,6 +25,10 @@ English | [中文](README.zh.md)
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
+ `await harness.resumeSession(savedId)` restores a persisted session from the configured `dshHome` and returns a `HarnessSession` ready for `run()`. Save the original session id and reuse its home and workspace. Restoration preserves conversation history and its directory, repairs an interrupted final turn, and sends no new input. Missing, unreadable, incompatible, or occupied sessions reject without creating a replacement. `session(id)` remains a lazy handle for an in-process session; it does not request persisted restoration. Shell, browser, and other external processes are not restored by this API.
29
+
30
+ `HarnessSession.getWorkingDirectory()` reads the effective directory; `setWorkingDirectory(path)` changes it and returns the validated absolute path. Either method creates an unknown Session without starting a model turn. Relative paths use the Session's current directory. Origin metadata, permissions, and existing processes remain unchanged. `HarnessClient` exposes the same methods with a leading `sessionId` argument.
31
+
28
32
  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
33
 
30
34
  ### Running agent turns with DeepSeekHarness
@@ -51,6 +55,8 @@ The subprocess starts lazily on first use and stays owned by the instance across
51
55
 
52
56
  `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
57
 
58
+ Task-owning consumers can subscribe before `prompt()`, then call `request('session/wait', { sessionId })` and drain queued notifications with `tryNext()`. This waits for managed descendants and their root summary turns; `HarnessSession.run()` retains its next-idle interval. `validatedSessionEvent()` validates the event envelope and the assistant/turn fields consumed by SDK readers before they enter an output fold.
59
+
54
60
  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
61
 
56
62
  -----
package/README.zh.md CHANGED
@@ -25,6 +25,10 @@ kind: "package-library"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用本包
27
27
 
28
+ `await harness.resumeSession(savedId)` 从配置的 `dshHome` 恢复持久化会话,并返回可调用 `run()` 的 `HarnessSession`。请保存原会话 id,并沿用其 home 和工作区。恢复会保留对话历史及其目录、修复最后一个被中断的轮次,且不发送新输入。会话缺失、不可读、不兼容或被占用时,请求失败且不创建替代会话。`session(id)` 仍是当前进程内会话的惰性句柄,不会请求持久化恢复。此 API 不恢复 shell、浏览器或其他外部进程。
29
+
30
+ `HarnessSession.getWorkingDirectory()` 读取有效目录;`setWorkingDirectory(path)` 修改目录并返回校验后的绝对路径。两个方法都可创建未知 Session,而不启动模型轮次。相对路径以 Session 当前目录解析。起始目录元数据、权限与已有进程保持不变。`HarnessClient` 提供同名方法,并以 `sessionId` 作为首个参数。
31
+
28
32
  当 TypeScript 代码需要从另一进程驱动完整 Harness 运行时、且你能显式指名运行时可执行文件时,使用本客户端。常用路径极简:用启动规格构造 `DeepSeekHarness`,运行提示词,然后关闭它,使子进程总能被回收。
29
33
 
30
34
  ### 用 DeepSeekHarness 运行 agent 轮次
@@ -51,6 +55,8 @@ console.log(result.finalResponse)
51
55
 
52
56
  `HarnessClient` 是运行 API 之下的协议客户端:显式 `start()`、`initialize()`、`prompt()`、`request()` 与 `close()`,外加通知订阅。`prompt()` 在运行时接受排队消息后立即返回该消息的 id,绝不等待 agent 活动。`subscribe(filter?)` 返回 `NotificationSubscription`(可等待的 `next()`、非阻塞 `tryNext()`、异步迭代);`subscribeSessionTree(id)` 把范围限定到一个会话及从 `subagent.started` 血缘边发现的后代——运行时对上下文内每个会话都发通知,范围限定在客户端完成,与 Python SDK 完全一致。
53
57
 
58
+ 拥有完整任务的消费者可以先订阅,再调用 `prompt()`,随后调用 `request('session/wait', { sessionId })`,并通过 `tryNext()` 取完已排队的通知。这会等待受管理后代及其触发的根 Agent 摘要轮次;`HarnessSession.run()` 仍以首次空闲作为活动区间终点。`validatedSessionEvent()` 在事件进入输出折叠前,校验事件封装及 SDK 读取方使用的 assistant/turn 字段。
59
+
54
60
  本客户端为每种失败模式导出类型化错误:`JsonRpcResponseError`(协议错误响应,保留 code 与 data)、`RequestTimeoutError`(配置的时限已到)、`SdkProtocolError`(响应超出文档化协议)、`TransportClosedError`(运行时已消失——消息携带退出码与有界 stderr 尾部)。`close()` 先请求协议 `shutdown`(受 `shutdownTimeoutMs` 约束,默认 1000 毫秒),然后走 stdin-EOF → SIGTERM → SIGKILL 阶梯直到进程退出;幂等,已关闭的客户端拒绝复用。`HarnessClientOptions.env` 给定时整体替换子进程环境(`undefined` 原样继承父进程环境);凭据策略归调用方——`dsh-subprocess` 的 `scrubbedParentEnv` 是面向隔离启动的共享擦除基底。
55
61
 
56
62
  -----
package/lib/index.js CHANGED
@@ -441,6 +441,39 @@ var HarnessClient = class {
441
441
  return result.messageId;
442
442
  }
443
443
  /**
444
+ * Restore persisted history without sending a prompt; failures propagate without creating a session.
445
+ * @param sessionId - persisted identity in this runtime's configured persistence store.
446
+ * @returns after the session is ready for prompts.
447
+ */
448
+ async resumeSession(sessionId) {
449
+ await this.request("session/resume", { sessionId });
450
+ }
451
+ /**
452
+ * Read a Session's effective working directory, recovering it if missing.
453
+ * @param sessionId - target Session; an unknown id creates it.
454
+ * @returns the absolute effective directory.
455
+ */
456
+ getWorkingDirectory(sessionId) {
457
+ return this.workingDirectoryRequest("session/working-directory/get", { sessionId });
458
+ }
459
+ /**
460
+ * Change a Session's effective directory without changing origin or permissions.
461
+ * @param sessionId - target Session; an unknown id creates it.
462
+ * @param path - absolute or Session-current-directory-relative path.
463
+ * @returns the validated absolute directory.
464
+ */
465
+ setWorkingDirectory(sessionId, path) {
466
+ return this.workingDirectoryRequest("session/working-directory/set", {
467
+ sessionId,
468
+ path
469
+ });
470
+ }
471
+ async workingDirectoryRequest(method, params) {
472
+ const result = await this.request(method, params);
473
+ if (!isRecord(result) || typeof result.cwd !== "string") throw new SdkProtocolError(`${method} returned no working directory: ${JSON.stringify(result)}`);
474
+ return result.cwd;
475
+ }
476
+ /**
444
477
  * Send one JSON-RPC request and await its result.
445
478
  * @param method - the wire method name.
446
479
  * @param params - the params object; omitted params send `{}`.
@@ -682,7 +715,7 @@ var DeepSeekHarness = class {
682
715
  }
683
716
  /**
684
717
  * Open a session handle (no wire traffic; the runtime creates the session
685
- * on its first prompt).
718
+ * on its first prompt or working-directory operation).
686
719
  * @param sessionId - explicit id to reuse; omitted mints a fresh one.
687
720
  * @returns the session handle.
688
721
  */
@@ -690,6 +723,17 @@ var DeepSeekHarness = class {
690
723
  return new HarnessSession(this, sessionId ?? `session-${randomUUID().replaceAll("-", "")}`);
691
724
  }
692
725
  /**
726
+ * Start the runtime and restore a persisted session without sending input.
727
+ * The configured Harness home must contain its history; missing or occupied sessions reject.
728
+ * @param sessionId - exact persisted identity to continue.
729
+ * @returns a handle ready to run new prompts on the restored history.
730
+ */
731
+ async resumeSession(sessionId) {
732
+ await this.start();
733
+ await this.client.resumeSession(sessionId);
734
+ return new HarnessSession(this, sessionId);
735
+ }
736
+ /**
693
737
  * Run one prompt on a fresh (or named) session.
694
738
  * @param input - prompt text, or content blocks sent verbatim.
695
739
  * @param options - optional session id and per-notification observer.
@@ -730,6 +774,23 @@ var HarnessSession = class {
730
774
  this.id = id;
731
775
  }
732
776
  /**
777
+ * Read the effective directory and recover a missing directory to the Session origin.
778
+ * @returns the absolute directory used by new independent operations.
779
+ */
780
+ async getWorkingDirectory() {
781
+ await this.harness.start();
782
+ return this.harness.client.getWorkingDirectory(this.id);
783
+ }
784
+ /**
785
+ * Change the effective directory without moving existing processes or changing permissions.
786
+ * @param path - absolute or Session-current-directory-relative directory.
787
+ * @returns the validated absolute directory.
788
+ */
789
+ async setWorkingDirectory(path) {
790
+ await this.harness.start();
791
+ return this.harness.client.setWorkingDirectory(this.id, path);
792
+ }
793
+ /**
733
794
  * Queue one prompt, then observe the whole session through its next idle.
734
795
  * @param input - prompt text, or content blocks sent verbatim.
735
796
  * @param options - optional per-notification observer.
@@ -806,7 +867,11 @@ function validatedTurnEndReason(value) {
806
867
  }
807
868
  return value;
808
869
  }
809
- /** Validate the fields in a wire `session.event` envelope before returning the typed result. */
870
+ /**
871
+ * Validate the event envelope and assistant/turn fields consumed by SDK readers.
872
+ * @param value - the raw `session.event` event payload.
873
+ * @returns the event, or throws a protocol error for malformed consumed fields.
874
+ */
810
875
  function validatedSessionEvent(value) {
811
876
  if (!isRecord(value) || typeof value.type !== "string") throw new SdkProtocolError(`session.event carried no event envelope: ${JSON.stringify(value)}`);
812
877
  if (value.type === "assistant/message") {
@@ -841,4 +906,4 @@ function finalResponse(events) {
841
906
  return "";
842
907
  }
843
908
  //#endregion
844
- export { DeepSeekHarness, HarnessClient, HarnessSession, JsonRpcResponseError, RequestTimeoutError, SdkProtocolError, TransportClosedError };
909
+ export { DeepSeekHarness, HarnessClient, HarnessSession, JsonRpcResponseError, RequestTimeoutError, SdkProtocolError, TransportClosedError, validatedSessionEvent };
@@ -48,11 +48,18 @@ export declare class DeepSeekHarness implements AsyncDisposable {
48
48
  start(): Promise<void>;
49
49
  /**
50
50
  * Open a session handle (no wire traffic; the runtime creates the session
51
- * on its first prompt).
51
+ * on its first prompt or working-directory operation).
52
52
  * @param sessionId - explicit id to reuse; omitted mints a fresh one.
53
53
  * @returns the session handle.
54
54
  */
55
55
  session(sessionId?: string): HarnessSession;
56
+ /**
57
+ * Start the runtime and restore a persisted session without sending input.
58
+ * The configured Harness home must contain its history; missing or occupied sessions reject.
59
+ * @param sessionId - exact persisted identity to continue.
60
+ * @returns a handle ready to run new prompts on the restored history.
61
+ */
62
+ resumeSession(sessionId: string): Promise<HarnessSession>;
56
63
  /**
57
64
  * Run one prompt on a fresh (or named) session.
58
65
  * @param input - prompt text, or content blocks sent verbatim.
@@ -92,6 +99,17 @@ export declare class HarnessSession {
92
99
  * @param id - the wire session id this handle runs on.
93
100
  */
94
101
  constructor(harness: DeepSeekHarness, id: string);
102
+ /**
103
+ * Read the effective directory and recover a missing directory to the Session origin.
104
+ * @returns the absolute directory used by new independent operations.
105
+ */
106
+ getWorkingDirectory(): Promise<string>;
107
+ /**
108
+ * Change the effective directory without moving existing processes or changing permissions.
109
+ * @param path - absolute or Session-current-directory-relative directory.
110
+ * @returns the validated absolute directory.
111
+ */
112
+ setWorkingDirectory(path: string): Promise<string>;
95
113
  /**
96
114
  * Queue one prompt, then observe the whole session through its next idle.
97
115
  * @param input - prompt text, or content blocks sent verbatim.
@@ -107,6 +125,12 @@ export declare class HarnessSession {
107
125
  * @returns the content blocks to send.
108
126
  */
109
127
  export declare function normalizeInput(input: string | SdkPromptContentBlock[]): SdkPromptContentBlock[];
128
+ /**
129
+ * Validate the event envelope and assistant/turn fields consumed by SDK readers.
130
+ * @param value - the raw `session.event` event payload.
131
+ * @returns the event, or throws a protocol error for malformed consumed fields.
132
+ */
133
+ export declare function validatedSessionEvent(value: unknown): SessionEvent;
110
134
  /**
111
135
  * Extract the concatenated text of the last assistant message.
112
136
  * @param events - the activity interval's `session.event` payloads in wire order.
@@ -96,6 +96,26 @@ export declare class HarnessClient {
96
96
  * @returns the queued message id.
97
97
  */
98
98
  prompt(sessionId: string, contentBlocks: SdkPromptContentBlock[]): Promise<string>;
99
+ /**
100
+ * Restore persisted history without sending a prompt; failures propagate without creating a session.
101
+ * @param sessionId - persisted identity in this runtime's configured persistence store.
102
+ * @returns after the session is ready for prompts.
103
+ */
104
+ resumeSession(sessionId: string): Promise<void>;
105
+ /**
106
+ * Read a Session's effective working directory, recovering it if missing.
107
+ * @param sessionId - target Session; an unknown id creates it.
108
+ * @returns the absolute effective directory.
109
+ */
110
+ getWorkingDirectory(sessionId: string): Promise<string>;
111
+ /**
112
+ * Change a Session's effective directory without changing origin or permissions.
113
+ * @param sessionId - target Session; an unknown id creates it.
114
+ * @param path - absolute or Session-current-directory-relative path.
115
+ * @returns the validated absolute directory.
116
+ */
117
+ setWorkingDirectory(sessionId: string, path: string): Promise<string>;
118
+ private workingDirectoryRequest;
99
119
  /**
100
120
  * Send one JSON-RPC request and await its result.
101
121
  * @param method - the wire method name.
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * @module @deepseek-ai/dsh-sdk-client
10
10
  */
11
- export { DeepSeekHarness, HarnessSession } from './api.ts';
11
+ export { DeepSeekHarness, HarnessSession, validatedSessionEvent } from './api.ts';
12
12
  export type { RunOptions } from './api.ts';
13
13
  export { HarnessClient, RequestTimeoutError, SdkProtocolError, TransportClosedError, } from './client.ts';
14
14
  export type { NotificationSubscription } from './client.ts';
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.2.1-alpha.1",
4
+ "version": "0.2.1-alpha.3",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -26,18 +26,19 @@
26
26
  ],
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
- "@deepseek-ai/dsh": "0.2.1-alpha.1"
29
+ "@deepseek-ai/dsh": "0.2.1-alpha.3"
30
30
  },
31
31
  "peerDependencies": {
32
- "@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
33
- "@deepseek-ai/dsh-sdk-protocol": "0.2.1-alpha.1",
34
- "@deepseek-ai/dsh-session": "0.2.1-alpha.1",
35
- "@deepseek-ai/cordis": "~4.0.5-alpha.1"
32
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.3",
33
+ "@deepseek-ai/dsh-sdk-protocol": "0.2.1-alpha.3",
34
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.3",
35
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2"
36
36
  },
37
37
  "devDependencies": {
38
- "@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
39
- "@deepseek-ai/dsh-sdk-protocol": "0.2.1-alpha.1",
40
- "@deepseek-ai/dsh-session": "0.2.1-alpha.1",
41
- "@deepseek-ai/cordis": "~4.0.5-alpha.1"
38
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.3",
39
+ "@deepseek-ai/dsh-sdk-protocol": "0.2.1-alpha.3",
40
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.3",
41
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2",
42
+ "@deepseek-ai/dsh-experimental-translator": "0.2.1-alpha.3"
42
43
  }
43
44
  }