dsh-plugin-dev-kb 1.1.0 → 1.3.0
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/CHANGELOG.md +16 -0
- package/README.en.md +14 -8
- package/README.md +14 -8
- package/docs/banner.svg +25 -0
- package/kb/INDEX.md +6 -2
- package/kb/README.md +4 -4
- package/kb/extra/AGENTS.md +2 -2
- package/kb/extra/cookbook/adding-a-session-format-version.md +109 -0
- package/kb/extra/cookbook/adding-a-session-format-version.zh.md +109 -0
- package/kb/extra/cookbook/adding-a-vendored-package.md +1 -1
- package/kb/extra/cookbook/adding-a-vendored-package.zh.md +1 -1
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +1 -1
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +1 -1
- package/kb/extra/deepseek-llm-api-wire-extensions.md +2 -2
- package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +2 -2
- package/kb/extra/development.md +13 -3
- package/kb/extra/development.zh.md +13 -3
- package/kb/extra/event-producer-consumer.md +33 -31
- package/kb/extra/event-producer-consumer.zh.md +34 -32
- package/kb/extra/i18n/README.md +2 -1
- package/kb/extra/i18n/README.zh.md +3 -2
- package/kb/extra/i18n/translation-prompt.md +1 -1
- package/kb/extra/module-graph.md +62 -24
- package/kb/extra/module-graph.zh.md +62 -24
- package/kb/extra/rescope.md +1 -1
- package/kb/extra/rescope.zh.md +1 -1
- package/kb/extra/session-format-status.md +47 -0
- package/kb/extra/session-format-status.zh.md +47 -0
- package/kb/extra/subsystems/agent-team.md +1 -1
- package/kb/extra/subsystems/agent-team.zh.md +1 -1
- package/kb/extra/subsystems/feedback.md +164 -30
- package/kb/extra/subsystems/feedback.zh.md +164 -30
- package/kb/extra/testing.md +4 -3
- package/kb/extra/testing.zh.md +4 -3
- package/kb/extra/web-styling.md +1 -0
- package/kb/extra/web-styling.zh.md +1 -0
- package/kb/meta/search-index.json +151 -103
- package/kb/meta/site-pages.txt +188 -184
- package/kb/meta/source.json +5 -5
- package/kb/meta/topics.md +2 -2
- package/kb/site/develop/basic/publish.md +1 -1
- package/kb/site/en/develop/basic/publish.md +1 -1
- package/kb/site/en/guide/providers.md +1 -1
- package/kb/site/en/guide/python-sdk.md +19 -3
- package/kb/site/en/reference/agent-lifecycle.md +12 -5
- package/kb/site/en/reference/capability-seams.md +10 -3
- package/kb/site/en/reference/config-catalog.md +173 -42
- package/kb/site/en/reference/cookbook/adding-a-tool.md +1 -1
- package/kb/site/en/reference/cookbook/extension-cookbook.md +1 -1
- package/kb/site/en/reference/index.md +18 -8
- package/kb/site/en/reference/persistence-catalog.md +121 -48
- package/kb/site/en/reference/subsystems/approval.md +1 -1
- package/kb/site/en/reference/subsystems/client-modules.md +9 -0
- package/kb/site/en/reference/subsystems/client-resources.md +94 -0
- package/kb/site/en/reference/subsystems/compaction.md +1 -1
- package/kb/site/en/reference/subsystems/core.md +79 -16
- package/kb/site/en/reference/subsystems/filesystem.md +15 -0
- package/kb/site/en/reference/subsystems/goal.md +37 -1
- package/kb/site/en/reference/subsystems/index.md +2 -0
- package/kb/site/en/reference/subsystems/invariants.md +1 -1
- package/kb/site/en/reference/subsystems/llm-streaming.md +20 -10
- package/kb/site/en/reference/subsystems/lsp.md +1 -1
- package/kb/site/en/reference/subsystems/persistence.md +36 -15
- package/kb/site/en/reference/subsystems/schedule.md +1 -1
- package/kb/site/en/reference/subsystems/scope.md +1 -1
- package/kb/site/en/reference/subsystems/session-reference.md +4 -0
- package/kb/site/en/reference/subsystems/session-telemetry.md +22 -6
- package/kb/site/en/reference/subsystems/session.md +64 -42
- package/kb/site/en/reference/subsystems/shell.md +9 -6
- package/kb/site/en/reference/subsystems/sidebar-right.md +151 -0
- package/kb/site/en/reference/subsystems/slots.md +41 -33
- package/kb/site/en/reference/subsystems/spill.md +13 -6
- package/kb/site/en/reference/subsystems/subagent.md +20 -13
- package/kb/site/en/reference/subsystems/subprocess.md +25 -26
- package/kb/site/en/reference/subsystems/system-prompt.md +3 -1
- package/kb/site/en/reference/subsystems/token-meter.md +2 -1
- package/kb/site/en/reference/subsystems/tools.md +5 -5
- package/kb/site/en/reference/subsystems/workspace.md +80 -1
- package/kb/site/en/reference/tool-catalog.md +46 -2
- package/kb/site/en/reference/tool-execution-pipeline.md +2 -2
- package/kb/site/guide/providers.md +1 -1
- package/kb/site/guide/python-sdk.md +19 -3
- package/kb/site/reference/agent-lifecycle.md +12 -5
- package/kb/site/reference/capability-seams.md +10 -3
- package/kb/site/reference/config-catalog.md +173 -42
- package/kb/site/reference/cookbook/adding-a-tool.md +1 -1
- package/kb/site/reference/cookbook/extension-cookbook.md +1 -1
- package/kb/site/reference/index.md +18 -8
- package/kb/site/reference/persistence-catalog.md +127 -54
- package/kb/site/reference/subsystems/approval.md +1 -1
- package/kb/site/reference/subsystems/client-modules.md +9 -0
- package/kb/site/reference/subsystems/client-resources.md +94 -0
- package/kb/site/reference/subsystems/compaction.md +1 -1
- package/kb/site/reference/subsystems/core.md +79 -16
- package/kb/site/reference/subsystems/filesystem.md +15 -0
- package/kb/site/reference/subsystems/goal.md +37 -1
- package/kb/site/reference/subsystems/index.md +14 -12
- package/kb/site/reference/subsystems/invariants.md +1 -1
- package/kb/site/reference/subsystems/llm-streaming.md +20 -10
- package/kb/site/reference/subsystems/lsp.md +1 -1
- package/kb/site/reference/subsystems/persistence.md +36 -15
- package/kb/site/reference/subsystems/schedule.md +1 -1
- package/kb/site/reference/subsystems/scope.md +1 -1
- package/kb/site/reference/subsystems/session-reference.md +4 -0
- package/kb/site/reference/subsystems/session-telemetry.md +22 -6
- package/kb/site/reference/subsystems/session.md +64 -42
- package/kb/site/reference/subsystems/shell.md +9 -6
- package/kb/site/reference/subsystems/sidebar-right.md +151 -0
- package/kb/site/reference/subsystems/slots.md +41 -33
- package/kb/site/reference/subsystems/spill.md +13 -6
- package/kb/site/reference/subsystems/subagent.md +20 -13
- package/kb/site/reference/subsystems/subprocess.md +25 -26
- package/kb/site/reference/subsystems/system-prompt.md +3 -1
- package/kb/site/reference/subsystems/token-meter.md +2 -1
- package/kb/site/reference/subsystems/tools.md +5 -5
- package/kb/site/reference/subsystems/workspace.md +80 -1
- package/kb/site/reference/tool-catalog.md +46 -2
- package/kb/site/reference/tool-execution-pipeline.md +2 -2
- package/lib/index.js +25 -44
- package/package.json +3 -2
- package/skills/dsh-plugin-dev-kb.md +3 -3
|
@@ -11,7 +11,20 @@ outline: [2,3]
|
|
|
11
11
|
|
|
12
12
|
## `SessionHandle`——通向已存储会话的一条打开通道
|
|
13
13
|
|
|
14
|
-
每一次日志读写都经由句柄流动,绝不经由按 id
|
|
14
|
+
每一次日志读写都经由句柄流动,绝不经由按 id 寻址的服务方法:句柄是跨进程写租约把守的唯一入口。读取会返回调用方独占的外层 slice,以及由生产者建立的 event value 别名状态。一种句柄类型同时服务两种访问——在 `read` 句柄上执行修改是运行时的 `SessionReadOnlyError`,而非类型层面的拆分——而进程内单写者所有权使得在已有活跃持有者时第二次 `open(id, 'write')` 以 `SessionAlreadyOwnedError` 拒绝。
|
|
15
|
+
|
|
16
|
+
```ts type-equiv
|
|
17
|
+
/** One persistence event slice returned by {@link SessionHandle.read}. */
|
|
18
|
+
interface SessionHandleReadResult {
|
|
19
|
+
/**
|
|
20
|
+
* Whether event values are exclusively owned or shared only after deep
|
|
21
|
+
* freezing. Slicing preserves the producer's state even when no events remain.
|
|
22
|
+
*/
|
|
23
|
+
readonly eventState: SessionSeedEventState
|
|
24
|
+
/** Event values in a caller-owned outer array. */
|
|
25
|
+
readonly events: readonly SessionEvent[]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
15
28
|
|
|
16
29
|
```ts type-equiv
|
|
17
30
|
/**
|
|
@@ -50,9 +63,9 @@ interface SessionHandle extends AsyncDisposable {
|
|
|
50
63
|
* @param length - maximum number of events to return; defaults to the rest
|
|
51
64
|
* of the log. An offset at or past the end returns an empty list.
|
|
52
65
|
* @param options - optional cancellation.
|
|
53
|
-
* @returns the
|
|
66
|
+
* @returns the caller-owned outer slice plus the ownership state of its event values.
|
|
54
67
|
*/
|
|
55
|
-
read(offset?: number, length?: number, options?: SessionHandleReadOptions): Promise<
|
|
68
|
+
read(offset?: number, length?: number, options?: SessionHandleReadOptions): Promise<SessionHandleReadResult>
|
|
56
69
|
|
|
57
70
|
/**
|
|
58
71
|
* Append a contiguous batch continuing the current logical end. The first
|
|
@@ -93,7 +106,7 @@ interface SessionHandle extends AsyncDisposable {
|
|
|
93
106
|
|
|
94
107
|
## flush 检查点
|
|
95
108
|
|
|
96
|
-
`session/event` 是一个*同步*通知;挂载的后端按会话 id 把它路由进活跃写句柄的有界 write-behind 窗口,而不阻塞生产方(后端一次性安装这些监听器,因为持久化已保证每个 id 只有一个活跃写句柄)。第一个待处理事件会开启固定的内部批处理窗口,后续事件会加入但不会重置其截止时间。窗口到期后会通过该会话的写句柄启动一次持久化 `append`;该次写入期间接纳的事件会获得自己的截止时间,并形成后续批次。`session/flush` 会取消等待并排空至完全停稳,因此循环仍将其用作在领取下一个普通轮次之前的顺序与错误观察检查点。后台写入被拒绝时会按序保留对应事件、暂停自动路径,并通过 logger 报告;下一次显式 flush 会重试,并向其调用方响亮地拒绝。`session/disposed` 会执行同样的最终排空并关闭句柄,而 `close()` 本身会经由仍然打开的存储排空已路由的缓冲,因此后端 teardown
|
|
109
|
+
`session/event` 是一个*同步*通知;挂载的后端按会话 id 把它路由进活跃写句柄的有界 write-behind 窗口,而不阻塞生产方(后端一次性安装这些监听器,因为持久化已保证每个 id 只有一个活跃写句柄)。第一个待处理事件会开启固定的内部批处理窗口,后续事件会加入但不会重置其截止时间。窗口到期后会通过该会话的写句柄启动一次持久化 `append`;该次写入期间接纳的事件会获得自己的截止时间,并形成后续批次。`session/flush` 会取消等待并排空至完全停稳,因此循环仍将其用作在领取下一个普通轮次之前的顺序与错误观察检查点。后台写入被拒绝时会按序保留对应事件、暂停自动路径,并通过 logger 报告;下一次显式 flush 会重试,并向其调用方响亮地拒绝。`session/disposed` 会执行同样的最终排空并关闭句柄,而 `close()` 本身会经由仍然打开的存储排空已路由的缓冲,因此后端 teardown 的关闭清扫不丢任何数据。该窗口只限制有意的批处理等待,不限制事件循环调度或后端完成持久化的延迟。
|
|
97
110
|
|
|
98
111
|
## 崩溃恢复保留被中断的轮次
|
|
99
112
|
|
|
@@ -101,7 +114,7 @@ interface SessionHandle extends AsyncDisposable {
|
|
|
101
114
|
|
|
102
115
|
因此修复只在写所有权之下写入:活跃会话的写句柄由其生命周期所有者持有,故并发的 `open(id, 'write')` 会以 `SessionAlreadyOwnedError` 拒绝,而不是让修复与活跃轮次竞速。只读观察方(session-query)仅在内存中用同样的闭合事件配平被中断的冷日志,不回写任何内容。
|
|
103
116
|
|
|
104
|
-
只读观察即 `open(id, 'read')`:句柄提供经过验证的连续前缀切片,绝不返回撕裂尾部,且同一句柄上的重复读取绝不会观察到比先前读取更旧的状态。持久化侧不存在已准备 Session 缓存:session-query 拥有自己的冷读缓存,按 `stat().revision` 变更令牌为每个 id 缓存一个已配平的冷 Session,仅在令牌变化时重新读取。该生命周期由[基于句柄的持久化 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-27-handle-based-session-persistence.zh.md)
|
|
117
|
+
只读观察即 `open(id, 'read')`:句柄提供经过验证的连续前缀切片,绝不返回撕裂尾部,且同一句柄上的重复读取绝不会观察到比先前读取更旧的状态。持久化侧不存在已准备 Session 缓存:session-query 拥有自己的冷读缓存,按 `stat().revision` 变更令牌为每个 id 缓存一个已配平的冷 Session,仅在令牌变化时重新读取。该生命周期由[基于句柄的持久化 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-27-handle-based-session-persistence.zh.md)定义;已归档的 [Session 准备阶段记录](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/archived/architecture/2026-08-05-session-preparation.md)记载了发布边界 `SessionPreparation` 最初的决策。
|
|
105
118
|
|
|
106
119
|
## `SessionLocation`——拒绝诊断的产物目标
|
|
107
120
|
|
|
@@ -176,7 +189,7 @@ interface SessionHeader {
|
|
|
176
189
|
|
|
177
190
|
## 格式拒绝:本构建无法可靠读取的日志
|
|
178
191
|
|
|
179
|
-
后端用 `SessionFormatUnsupportedError` 拒绝无法可靠解读的日志,它与 `SessionPersistenceCorruptionError` 区分,因为数据没有损坏。`stat` 与 `list` 会对最高规范 generation 分类,并在不读取或改变正文的前提下转换受支持的历史 header
|
|
192
|
+
后端用 `SessionFormatUnsupportedError` 拒绝无法可靠解读的日志,它与 `SessionPersistenceCorruptionError` 区分,因为数据没有损坏。`stat` 与 `list` 会对最高规范 generation 分类,并在不读取或改变正文的前提下转换受支持的历史 header。历史 `open` 会共享每个 Session 唯一的一次 migration preparation,再返回当前逻辑值,并保持每个源路径、字节与 inode 不变。JSONL provider 直接从该内存结果返回读句柄而不发布;写 open 则在持有单写者 claim 与文件 lease 时复用 preparation、排他发布最终 current generation,随后才返回可写句柄。即使仍有较旧的可读 generation,最高的未来 generation 仍会导致拒绝。当前格式恢复会保留已安装扩展和带 `ignorable: true` 的未知事件;历史 v0/v1/v2 迁移则会拒绝未知类型,即使它带有 ignorable 标记。后端为每个会话保留独立文件时,消息附上选定的原始日志路径。仓库外后端必须在自己的物理格式入口提供等价的仅当前句柄值与方向感知拒绝。[已发布格式迁移决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md)负责迁移链与不可变发布规则。
|
|
180
193
|
|
|
181
194
|
## `CreateSessionOptions`:seed 与元数据
|
|
182
195
|
|
|
@@ -192,7 +205,7 @@ interface CreateSessionOptions {
|
|
|
192
205
|
/** Initial replay or fork history supplied at construction. */
|
|
193
206
|
readonly seed?: readonly SessionEvent[]
|
|
194
207
|
/**
|
|
195
|
-
* Exact fork-inherited prefix length when `meta.isSeeded` is true.
|
|
208
|
+
* Exact fork-inherited prefix length when `meta.isSeeded` is true. The
|
|
196
209
|
* constructor seed is exactly this inherited prefix; the constructor
|
|
197
210
|
* appends the child-owned tagged marker at the cut.
|
|
198
211
|
*/
|
|
@@ -217,29 +230,37 @@ interface CreateSessionOptions {
|
|
|
217
230
|
|
|
218
231
|
## 准备与恢复所有权
|
|
219
232
|
|
|
220
|
-
`SessionStore.prepare()` 接收普通创建选项,或通过 `RestoredSessionOptions`
|
|
233
|
+
`SessionStore.prepare()` 接收普通创建选项,或通过 `RestoredSessionOptions` 接收可直接接管的 seed。它的 `eventState` 表明 event value 是独占对象,还是只有深度冻结后的共享对象;生产者负责建立该状态,slice 不会根据结果长度推断其他状态。恢复流程会校验并直接接管这些值,不再复制或冻结。`SessionPreparation` 随后持有该精确的未发布 Session,直至发布或回滚;dispose 是同步且幂等的。agent-loop 的 resume 通过该会话的写句柄读取这份结果,并在准备之前追加独占的 `interruptedTurnClosers`。
|
|
234
|
+
|
|
235
|
+
```ts type-equiv
|
|
236
|
+
/**
|
|
237
|
+
* Aliasing state of an adoptable Session seed. `shared-frozen` permits deeply
|
|
238
|
+
* frozen aliases plus independently owned unfrozen values in the same seed.
|
|
239
|
+
*/
|
|
240
|
+
type SessionSeedEventState = 'detached' | 'shared-frozen'
|
|
241
|
+
```
|
|
221
242
|
|
|
222
243
|
```ts type-equiv
|
|
223
244
|
/**
|
|
224
|
-
*
|
|
225
|
-
*
|
|
245
|
+
* Adoptable storage values transferred to {@link SessionStore.prepare}
|
|
246
|
+
* without another copy or freeze pass.
|
|
226
247
|
*/
|
|
227
248
|
interface RestoredSessionOptions {
|
|
228
|
-
/**
|
|
249
|
+
/** Events that are independently owned or already deeply frozen. */
|
|
229
250
|
readonly seed: SessionEvent[]
|
|
230
|
-
/**
|
|
251
|
+
/** Independently owned storage metadata to validate and freeze in place. */
|
|
231
252
|
readonly meta: SessionHeader
|
|
232
253
|
/** Exact number of fork-inherited leading events decoded from storage. */
|
|
233
254
|
readonly inheritedEventCount: SessionLogOffset
|
|
234
|
-
/**
|
|
235
|
-
readonly
|
|
255
|
+
/** Aliasing state carried from the operation that produced the seed. */
|
|
256
|
+
readonly eventState: SessionSeedEventState
|
|
236
257
|
}
|
|
237
258
|
```
|
|
238
259
|
|
|
239
260
|
```ts type-equiv
|
|
240
261
|
/** Inputs accepted while constructing an unpublished Session. */
|
|
241
262
|
type PrepareSessionOptions =
|
|
242
|
-
| (CreateSessionOptions & { readonly
|
|
263
|
+
| (CreateSessionOptions & { readonly eventState?: undefined })
|
|
243
264
|
| RestoredSessionOptions
|
|
244
265
|
```
|
|
245
266
|
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# 仅限 Session 内的 Schedule
|
|
7
7
|
|
|
8
|
-
Schedule 拥有持久提醒;这些提醒会作为普通的后续对话轮次返回原 live Session。[持久 Schedule Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.zh.md) 负责持久化、生命周期与活动状态呈现,[
|
|
8
|
+
Schedule 拥有持久提醒;这些提醒会作为普通的后续对话轮次返回原 live Session。[持久 Schedule Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-08-05-durable-web-schedule.zh.md) 负责持久化、生命周期与活动状态呈现,[显式时区边界](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.zh.md) 负责浏览器本地解释。本页记录 [`packages/schedule/schedule/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/schedule/schedule/src/types.ts) 中的持久数据形状和面向模型的数据形状;[包 README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/schedule/schedule/README.zh.md) 负责组合、工具行为与确切的提醒 framing。
|
|
9
9
|
|
|
10
10
|
## 持久记录
|
|
11
11
|
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# 作用域注册
|
|
7
7
|
|
|
8
|
-
[scope 包](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/scope)提供身份、载体与作用域层词汇,使同一注册上下文同时表达每个 agent(智能体)的可见性和共享生命周期所有权。它是库原语,而不是 Cordis 服务;生命周期设计理由由 [agent-scope 运行时设计 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md#scope-routing-one-opaque-key-selects-one-layer)
|
|
8
|
+
[scope 包](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/scope)提供身份、载体与作用域层词汇,使同一注册上下文同时表达每个 agent(智能体)的可见性和共享生命周期所有权。它是库原语,而不是 Cordis 服务;生命周期设计理由由 [agent-scope 运行时设计 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-12-agent-scope-runtime-design.zh.md#scope-routing-one-opaque-key-selects-one-layer)规定,可调用 API 与过滤语义则由包 [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/README.zh.md)规定。
|
|
9
9
|
|
|
10
10
|
源码:[`packages/core/scope/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/src/index.ts) 与 [`packages/core/scope/src/store.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/src/store.ts)。
|
|
11
11
|
|
|
@@ -207,6 +207,10 @@ async listCandidates( agent: Agent, query: string = '', limit: number = this.con
|
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
209
|
* Snapshot all references for one accepted direct message and return one aggregated durable context.
|
|
210
|
+
* Automatic budgets use the last assembled route, or agent options before any assembly.
|
|
211
|
+
* Missing model capacity or adapter uses 64 KiB; other metadata lookup failures and cancellation reject preparation.
|
|
212
|
+
* Truncated previews include omission facts and a full-snapshot spill locator, or an explicit unavailable notice.
|
|
213
|
+
* Cancellation prevents context publication, including when storage completes after cancellation.
|
|
210
214
|
* @param agent - target agent; references to it are rejected.
|
|
211
215
|
* @param content - already host-normalized readable message content.
|
|
212
216
|
* @param references - structured source sessions in mention order.
|
|
@@ -58,22 +58,38 @@ interface SessionTelemetryRecord {
|
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
每条权威[会话事件](./session.md)都会完整透传为一条有序 ledger 记录,包括每个携带完整紧凑 stream 的 `assistant/message` 或 `assistant/attempt`,以及该 seam 从未听说过、由插件合并进来的类型。进程本地 `agent/assistant-stream` frame 不进入该持久 feed。新 Session
|
|
61
|
+
每条权威[会话事件](./session.md)都会完整透传为一条有序 ledger 记录,包括每个携带完整紧凑 stream 的 `assistant/message` 或 `assistant/attempt`,以及该 seam 从未听说过、由插件合并进来的类型。进程本地 `agent/assistant-stream` frame 不进入该持久 feed。新 Session 对象从其生命周期边界开始,除非后端选择 `includeHistory`;重新收养同一对象时会从 handoff 游标之后继续。投递是尽力而为的:游标标记的是「已交接」而非「已送达」,记录可能丢失(崩溃、重载窗口)也可能重复(新对象回放、SDK 重试),因此接收端对 ledger 记录基于 `(session.id, session.format_version, event.seq)` 去重;ops 记录刻意省略这类标识——它们是用于告警的信号,而非用于累加的条目,重复被容忍而非被去重。
|
|
62
62
|
|
|
63
63
|
## 共享披露
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
每个后端都通过 `ctx.sessionTelemetry` 上必需的抽象 `sharing` 成员暴露其部署级模式([Service Definition README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-telemetry/README.zh.md#the-sharing-disclosure))。它既不是逐 Session 的接纳决定,也不是投递回执。`/feedback` 确认文本不查询它。
|
|
66
66
|
|
|
67
67
|
```ts type-equiv
|
|
68
68
|
/**
|
|
69
|
-
* Deployment-selected session-sharing
|
|
70
|
-
* {@link SessionTelemetryBackend} backend to human-facing acknowledgement surfaces (the
|
|
71
|
-
* `/feedback` command's confirmation text). The Service Definition owns the
|
|
72
|
-
* vocabulary so consumers and backends do not depend on a specific provider.
|
|
69
|
+
* Deployment-selected session-sharing mode, not confirmation of SDK delivery.
|
|
73
70
|
*/
|
|
74
71
|
type SessionTelemetrySharingStatus = 'full' | 'feedback-only' | 'disabled'
|
|
75
72
|
```
|
|
76
73
|
|
|
74
|
+
## 捕获策略
|
|
75
|
+
|
|
76
|
+
```ts type-equiv
|
|
77
|
+
/** Whether capture follows live events or reads the canonical log only when requested. */
|
|
78
|
+
type SessionTelemetryCapture = 'live' | 'on-demand'
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```ts type-equiv
|
|
82
|
+
/** Backend-selected capture mode and history policy. */
|
|
83
|
+
interface SessionTelemetryCaptureOptions {
|
|
84
|
+
/** Follow live events, or wait for explicit capture; defaults to live. */
|
|
85
|
+
capture?: SessionTelemetryCapture
|
|
86
|
+
/** Include stored history before this lifecycle; defaults to false. */
|
|
87
|
+
includeHistory?: boolean
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`includeHistory` 允许捕获存储与继承的记录,但本身不授权捕获。[OTel 后端](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-telemetry-otel/README.zh.md)使用按需捕获,并要求新的自身显式反馈;它只释放截至该反馈的完整前缀,适用于所有提供方。
|
|
92
|
+
|
|
77
93
|
## 后端约定
|
|
78
94
|
|
|
79
95
|
```ts type-equiv
|
|
@@ -56,6 +56,19 @@ interface SessionEventMap {
|
|
|
56
56
|
* project their `content` verbatim; `source` tells them apart.
|
|
57
57
|
*/
|
|
58
58
|
'user/message': UserMessage
|
|
59
|
+
/**
|
|
60
|
+
* The rendered system prompt on the model-visible surface. The loop appends
|
|
61
|
+
* the first one as surface node 0 before the step's first `user/message`.
|
|
62
|
+
* A prepared in-history route can append nonempty changes in a continuing
|
|
63
|
+
* series. An incapable route or new series normalizes text to the first system
|
|
64
|
+
* node. Normalization empties nonempty later nodes, then rewrites the head if
|
|
65
|
+
* needed, through logged per-node replacements. An empty rendering always
|
|
66
|
+
* clears all active system nodes, leaving no older instructions model-visible.
|
|
67
|
+
* Empty later nodes are dormant and project to no message; an empty head with
|
|
68
|
+
* no active later node records "no system prompt". Restored nonempty text follows
|
|
69
|
+
* the same route and series rule; empty nodes never restore older text.
|
|
70
|
+
*/
|
|
71
|
+
'system/message': { turn: number; step: number; message: SystemMessage }
|
|
59
72
|
/**
|
|
60
73
|
* Assembled assistant message for one step (derived history uses this).
|
|
61
74
|
* Carries the step's `usage` when the adapter reported token accounting, so
|
|
@@ -102,6 +115,7 @@ interface SessionEventMap {
|
|
|
102
115
|
turn: number
|
|
103
116
|
step: number
|
|
104
117
|
message: ToolResultMessage
|
|
118
|
+
/** Optional failure identity; allowed only when the tool-result block has `isError: true`. */
|
|
105
119
|
error?: { name: string; code: string }
|
|
106
120
|
meta?: JsonValue
|
|
107
121
|
}
|
|
@@ -116,8 +130,10 @@ interface SessionEventMap {
|
|
|
116
130
|
startsSeries?: true
|
|
117
131
|
}
|
|
118
132
|
/**
|
|
119
|
-
* Route metadata for the next request, logged only when the route
|
|
120
|
-
* changes. It does not participate in request
|
|
133
|
+
* Route metadata for the next request, logged only when the route, capacity,
|
|
134
|
+
* or system prompt update mode changes. It does not participate in request
|
|
135
|
+
* reconstruction or header equality. Prompt admission uses the bound prepared
|
|
136
|
+
* call's capability, not this snapshot from an earlier request.
|
|
121
137
|
*/
|
|
122
138
|
'request/context': RequestContext
|
|
123
139
|
/**
|
|
@@ -152,12 +168,13 @@ interface SessionEventMap {
|
|
|
152
168
|
|
|
153
169
|
### 请求头事件:`request/header`
|
|
154
170
|
|
|
155
|
-
请求信封(即 `EpochHeader`:调用配置 + 适配器所提供默认值的标记 +
|
|
171
|
+
请求信封(即 `EpochHeader`:调用配置 + 适配器所提供默认值的标记 + 已组装的工具 schema)会作为会话状态写入日志,因此每个对话请求都是日志的纯函数(见可重建性 Agent Note)。渲染后的系统提示词不属于请求头:它是派生历史,即 surface 第 0 号节点上的 `system/message` 事件以及任何后续的历史内系统节点([决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-09-02-system-prompt-as-surface-node.zh.md)),因此提示词变更替换或追加一个系统节点,而请求头保持不变。带有 reason `'initial'` 或 `'resume'` 的完整 `request/header` 快照记录每个 agent loop 实例的边界;请求变化时会追加 reason 为 `'change'` 的快照;未变的信封显式开启消息序列或跟随 surface 替换时,会追加 reason 为 `'series'` 的快照。如果发生变化的快照所属请求同时开启序列,它会携带 `startsSeries: true`。普通的仅追加后续 Turn,以及同一模型消息序列内的后续 Step 与重试沿用最新快照。`foldRequestHeader(events)` 通过选择最新快照重建请求头。该事件不是 `SurfaceEventType`,不产生 LLM 消息。
|
|
156
172
|
|
|
157
173
|
```ts type-equiv
|
|
158
174
|
/**
|
|
159
|
-
* Logged request state outside derived history: call config
|
|
160
|
-
*
|
|
175
|
+
* Logged request state outside derived history: call config and tools. The
|
|
176
|
+
* system prompt is derived history — surface node 0, a `system/message` event.
|
|
177
|
+
* The latest full `request/header` snapshot reconstructs the header; canonical
|
|
161
178
|
* empty optional fields are absent.
|
|
162
179
|
*/
|
|
163
180
|
interface EpochHeader {
|
|
@@ -165,18 +182,16 @@ interface EpochHeader {
|
|
|
165
182
|
config: LlmCallConfig
|
|
166
183
|
/** Effective config fields materialized from the exact adapter rather than proposed by a caller. */
|
|
167
184
|
adapterDefaults?: LlmCallConfigAdapterDefaults
|
|
168
|
-
/** Rendered system prompt text; absent for a system-less request. */
|
|
169
|
-
system?: string
|
|
170
185
|
/** Assembled tool schemas; absent for a tool-less request. */
|
|
171
186
|
tools?: ToolSchema[]
|
|
172
187
|
}
|
|
173
188
|
```
|
|
174
189
|
|
|
175
|
-
|
|
190
|
+
当前事件接纳要求 `request/header.header` 为规范形式:禁止任何 `system` 字段,必须省略 `tools: []` 与 `adapterDefaults: {}`。仅含空白的系统消息内容、`config.stop: []` 与嵌套扩展保持不变。seed、append 与当前持久化读取拒绝非规范 header,而不会静默规范化;[V3 信封决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-09-06-v3-canonical-session-envelopes.zh.md)负责历史转换。包含旧版 `request/header-delta` 事件或完整快照原因为 `fallback` 的旧版 v0 日志,会被拒绝,而不会以不完整方式回放。
|
|
176
191
|
|
|
177
192
|
### 路由容量事件:`request/context`
|
|
178
193
|
|
|
179
|
-
请求所解析到的路由的上下文元数据是独立的已记录状态,在同一步骤内紧随 `request/header`
|
|
194
|
+
请求所解析到的路由的上下文元数据是独立的已记录状态,在同一步骤内紧随 `request/header` 追加,且仅在提供方、模型、容量或 `systemPromptUpdate` 模式与上一条记录不同时追加。它保持在 `EpochHeader` 之外,因为该类型是 `headerEquals` 逐字段比较的重建约定。容量与更新模式描述的是路由,不是请求输入,把它们折叠进去会让一次路由变化被登记为请求信封的 `change`,也会把适配器元数据拉进 loop 的重建不变式。与 `request/header` 一样,它不是 `SurfaceEventType`,也不产生 LLM 消息。`session.requestContext()` 以增量方式归并最新一条记录;agent loop 在决定变化后的系统提示词是替换最新的系统节点还是追加到已缓存历史之后时,读取该记录的 `systemPromptUpdate`([决策规则](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/README.zh.md#understand-the-implementation))。适配器不公布容量的路由会以缺失 `contextWindow` 的形式记录,因此新记录可以清除较早路由的容量;未声明更新模式的路由同样会清除较早路由的 `systemPromptUpdate`。
|
|
180
195
|
|
|
181
196
|
```ts type-equiv
|
|
182
197
|
/** Registration-bound metadata for one resolved model route. */
|
|
@@ -187,6 +202,8 @@ interface RequestContext {
|
|
|
187
202
|
model: string
|
|
188
203
|
/** Maximum combined request and response context in tokens, when advertised. */
|
|
189
204
|
contextWindow?: number
|
|
205
|
+
/** `'in-history'` when the route reads the latest `system` message at any position as the effective system prompt. */
|
|
206
|
+
systemPromptUpdate?: SystemPromptUpdate
|
|
190
207
|
}
|
|
191
208
|
```
|
|
192
209
|
|
|
@@ -224,7 +241,7 @@ type OptionalSessionSeq = SessionSeq | null
|
|
|
224
241
|
* unions), so `switch (event.type)` narrows `event.data` without casts.
|
|
225
242
|
*
|
|
226
243
|
* The {@link sourceEventSeqs} and {@link surfaceOp} fields are conditional:
|
|
227
|
-
* they only exist on {@link SurfaceEventType} variants (`user/message`,
|
|
244
|
+
* they only exist on {@link SurfaceEventType} variants (`system/message`, `user/message`,
|
|
228
245
|
* `assistant/message`, `tool/result`).
|
|
229
246
|
* Non-surface events (boundary markers, attempts, errors) never carry
|
|
230
247
|
* surface metadata — the compiler enforces this at `Session.append()`
|
|
@@ -249,28 +266,22 @@ type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
249
266
|
* inconvenience) rather than silently resuming a gutted session.
|
|
250
267
|
*/
|
|
251
268
|
ignorable?: true
|
|
252
|
-
} & (K extends SurfaceEventType ? {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
* `assistant/message` embeds its provider stream and cannot carry this field.
|
|
257
|
-
*/
|
|
258
|
-
sourceEventSeqs?: SessionSeq[]
|
|
259
|
-
/** How this event entered the surface; absent for non-surface events. */
|
|
260
|
-
surfaceOp?: SurfaceOp
|
|
261
|
-
} : object)
|
|
269
|
+
} & (K extends SurfaceEventType ? SurfaceIntent<K> : {
|
|
270
|
+
surfaceOp?: never
|
|
271
|
+
sourceEventSeqs?: never
|
|
272
|
+
})
|
|
262
273
|
}[T]
|
|
263
274
|
```
|
|
264
275
|
|
|
265
276
|
`SessionEventType = keyof SessionEventMap`。由于 `SessionEventMap` 可通过合并扩展,对 `SessionEvent` 的 switch 语句禁止使用 `assertNever`:插件添加的变体是合法的未知值;处理已知 case 后在 `default` 中放行。
|
|
266
277
|
|
|
267
|
-
|
|
278
|
+
每个 surface 事件都要求 `surfaceOp`;已知仅日志事件禁止两个 surface 元数据字段。原生未知或已退役的可忽略信封保持不透明。`assistant/message` 嵌入其提供方 stream,并禁止 `sourceEventSeqs`。System、user 与 tool surface 事件可以在来源或替换操作需要时引用完整、非空且唯一的较早事件集合。`tool/result` 仅在工具结果块带有 `isError: true` 时可以携带 `data.error`;失败结果的失败身份仍可省略。
|
|
268
279
|
|
|
269
280
|
<a id="surface-types"></a>
|
|
270
281
|
|
|
271
282
|
## Surface 类型
|
|
272
283
|
|
|
273
|
-
|
|
284
|
+
四种产生消息的类型(`SurfaceEventType`:`system/message`、`user/message`、`assistant/message`、`tool/result`)携带 surface 元数据,用来声明它们如何加入有序的派生 surface。`system/message` 承载渲染后的系统提示词:循环把第一条追加为 surface 第 0 号节点,并在提示词变化时恰好替换最新的系统节点,或在历史内路由上追加一条新的;surface 折叠拒绝任何其他覆盖第 0 号节点 `system/message` 的替换,而后续系统节点是普通历史,压缩替换可以遮蔽它。见 [session surface Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md)。
|
|
274
285
|
|
|
275
286
|
### `SurfaceEventType`:事件类型中产生消息的子集
|
|
276
287
|
|
|
@@ -278,10 +289,11 @@ V2 `assistant/message` 嵌入 provider stream,不能携带 `sourceEventSeqs`
|
|
|
278
289
|
/**
|
|
279
290
|
* The subset of {@link SessionEventType} values whose events produce LLM
|
|
280
291
|
* messages and are eligible to appear on the ordered surface. Only these
|
|
281
|
-
* event types may carry {@link SurfaceOp}; user and tool events may also cite
|
|
292
|
+
* event types may carry {@link SurfaceOp}; system, user, and tool events may also cite
|
|
282
293
|
* earlier sources through {@link SessionEvent.sourceEventSeqs}.
|
|
283
294
|
*/
|
|
284
295
|
type SurfaceEventType =
|
|
296
|
+
| 'system/message'
|
|
285
297
|
| 'user/message'
|
|
286
298
|
| 'assistant/message'
|
|
287
299
|
| 'tool/result'
|
|
@@ -296,19 +308,19 @@ type SurfaceEventType =
|
|
|
296
308
|
*
|
|
297
309
|
* - `'append'`: added to the tail — normal path for user/assistant/tool
|
|
298
310
|
* messages.
|
|
299
|
-
* - `{ op: 'replace',
|
|
300
|
-
* (inclusive) through `
|
|
301
|
-
* surface nodes in the current surface. `
|
|
311
|
+
* - `{ op: 'replace', startSeq, endSeq }`: replaces surface nodes from `startSeq`
|
|
312
|
+
* (inclusive) through `endSeq` (inclusive) with this node. Both must exist as
|
|
313
|
+
* surface nodes in the current surface. `startSeq === endSeq` replaces a single
|
|
302
314
|
* node. The node's {@link SessionEvent.sourceEventSeqs} must include every
|
|
303
315
|
* shadowed surface node. Used by compaction; any surface-replacing producer
|
|
304
316
|
* may use it.
|
|
305
317
|
*/
|
|
306
318
|
type SurfaceOp =
|
|
307
319
|
| 'append'
|
|
308
|
-
| { op: 'replace';
|
|
320
|
+
| { op: 'replace'; startSeq: SessionSeq; endSeq: SessionSeq }
|
|
309
321
|
```
|
|
310
322
|
|
|
311
|
-
`'append'` 是常规的尾部追加路径。`replace`
|
|
323
|
+
`'append'` 是常规的尾部追加路径。`replace` 恰好包含 `op`、`startSeq` 和 `endSeq`,不接受别名或额外键。它遮蔽这两个当前 surface 事件序号之间的闭区间,并在原位置插入新事件;相同端点仅替换一个条目。端点必须早于替换事件,但它们的相对顺序按 surface 顺序而非数值序号顺序确定。
|
|
312
324
|
|
|
313
325
|
### `SurfaceIntent`:`session.append()` 的参数
|
|
314
326
|
|
|
@@ -320,7 +332,7 @@ type SurfaceOp =
|
|
|
320
332
|
type SurfaceIntent<T extends SurfaceEventType = SurfaceEventType> = {
|
|
321
333
|
surfaceOp: SurfaceOp
|
|
322
334
|
} & (T extends 'assistant/message' ? {
|
|
323
|
-
/**
|
|
335
|
+
/** Assistant messages embed their provider stream instead of citing source events. */
|
|
324
336
|
sourceEventSeqs?: never
|
|
325
337
|
} : {
|
|
326
338
|
/** Complete non-empty set of known earlier source-event seqs. */
|
|
@@ -445,13 +457,16 @@ declare class Session {
|
|
|
445
457
|
inheritedEventCount?: SessionLogOffset,
|
|
446
458
|
): Session;
|
|
447
459
|
/**
|
|
448
|
-
* Restore a detached session by
|
|
449
|
-
*
|
|
450
|
-
* and header fields are validated
|
|
460
|
+
* Restore a detached session by adopting an independently owned or deeply frozen seed.
|
|
461
|
+
* Runtime-required event fields, event envelopes, sequence continuity, surface
|
|
462
|
+
* transitions, and header fields are validated without copying or freezing events.
|
|
463
|
+
* Embedded Assistant streams remain opaque until a stream consumer or storage
|
|
464
|
+
* verifier reads them.
|
|
451
465
|
* @param id - restored session identity.
|
|
452
|
-
* @param seed -
|
|
453
|
-
* @param header -
|
|
466
|
+
* @param seed - independently owned or deeply frozen events.
|
|
467
|
+
* @param header - independently owned storage metadata.
|
|
454
468
|
* @param inheritedEventCount - exact fork-inherited prefix length decoded from storage.
|
|
469
|
+
* @param eventState - aliasing state carried from the operation that produced the seed.
|
|
455
470
|
* @returns a restored detached session.
|
|
456
471
|
*/
|
|
457
472
|
static fromRestore(
|
|
@@ -459,6 +474,7 @@ declare class Session {
|
|
|
459
474
|
seed: readonly SessionEvent[],
|
|
460
475
|
header: SessionHeader,
|
|
461
476
|
inheritedEventCount: SessionLogOffset,
|
|
477
|
+
eventState: SessionSeedEventState,
|
|
462
478
|
): Session;
|
|
463
479
|
/**
|
|
464
480
|
* Return the immutable event stored at one exact sequence number.
|
|
@@ -517,6 +533,7 @@ declare class Session {
|
|
|
517
533
|
* (BigInt, function, symbol, undefined, negative zero, non-finite number,
|
|
518
534
|
* circular reference, sparse array, or an exotic object such as
|
|
519
535
|
* Map/Set/Date/class instance), or when the candidate violates the
|
|
536
|
+
* request-header empty-field or tool-error consistency rules, or the
|
|
520
537
|
* canonical surface contract (marker shape and eligibility, unique
|
|
521
538
|
* earlier source-event references, positional replacement validity, and complete
|
|
522
539
|
* shadowed-node coverage). One iterative pass reads, validates, and
|
|
@@ -646,7 +663,7 @@ interface TurnEndReasonMap {
|
|
|
646
663
|
|
|
647
664
|
新 fork constructor 要求 seed 等于 inherited prefix,并在精确持久 cut 追加 `session/end-seed { inherited: true }`。restore 会保留该 tagged marker,并且只在完整 stored seed 尚未以 marker 结尾时追加普通 `session/end-seed {}`。两种形式都只进入 log 且不产生 message;`Session` constructor 是唯一合法 writer。
|
|
648
665
|
|
|
649
|
-
对于 fork lineage,定位 payload 携带 `inherited: true` 的最后一个 marker
|
|
666
|
+
对于 fork lineage,定位 payload 携带 `inherited: true` 的最后一个 marker;当前格式 decoding 只在 `SessionHeader.isSeeded` 为 true 时要求该 marker,并从其 seq 推导 `inheritedEventCount`。对于 lifecycle ownership,定位任一形式的最后一个 `session/end-seed`。重新打开已经以任一 marker 结尾的 seed 时,不会再追加普通 marker。
|
|
650
667
|
|
|
651
668
|
它之所以必要,是因为种子历史与实时工作在字节层面完全相同,这会让任何拥有独立开/闭括号的插件失效:一个未配对的 `compaction/start`,无论写入方是在压缩中途崩溃、还是此刻正在压缩,读起来都一样。在 `session/end-seed` 之前的开启标记来自构造种子,并且属于一个已结束的生命周期,无论结束原因为何(崩溃、进程接替,或从仍在运行的父会话 fork 出来),因此其所有方可以视之为已死。这只覆盖*本*会话继承的括号:另一个并发存活的会话可能在同一段历史上持有开放括号,而它自己的边界在别处,因此容忍并发写入方还需要日志之外的存活信号。核心写入该边界但不从中读取任何内容——括号的词汇表仍归其所属插件,这也正是崩溃修复只关闭轮次/步骤/工具边界而从不处理 `compaction/*` 的原因。
|
|
652
669
|
|
|
@@ -658,11 +675,11 @@ interface TurnEndReasonMap {
|
|
|
658
675
|
|
|
659
676
|
如果同一个插件事件族中的多条事件要组装成一个 Web Client Conversation Node,该事件族中的每条 start、update、result、resource 或 interruption 事件都必须携带或独立推导出同一个稳定业务 id。此要求只约束需要关联的 Node 事件族,并不要求每条 Session 事件都有业务 id;Client 因此无须根据相邻关系猜测归属,也无须扫描历史。参见 [Conversation 子系统](./conversation.md)。
|
|
660
677
|
|
|
661
|
-
钩子桥接层的 `hook/invoked` / `hook/result` 对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。`UserPromptSubmit`、`PreToolUse`、`PostToolUse` 与 `Stop` 在 loop 已打开的轮次内触发,因此其 `hook/*` 记录天然位于轮次之内。`SessionStart` 不生成 `hook/*` 记录,因为它在轮次 1 之前运行;其上下文会在 inbox
|
|
678
|
+
钩子桥接层的 `hook/invoked` / `hook/result` 对(来自 `@deepseek-ai/dsh-hook-protocol`)通过 `handlerId` 关联。`UserPromptSubmit`、`PreToolUse`、`PostToolUse` 与 `Stop` 在 loop 已打开的轮次内触发,因此其 `hook/*` 记录天然位于轮次之内。`SessionStart` 不生成 `hook/*` 记录,因为它在轮次 1 之前运行;其上下文会在 inbox 中保持待处理,直到唤醒交付打开一个轮次。
|
|
662
679
|
|
|
663
680
|
## 持久性约定
|
|
664
681
|
|
|
665
|
-
持久化后端依赖的约定如下:持久日志无损保存每个事件,每个 Assistant attempt 都是一个 `assistant/message` 或 `assistant/attempt`,其嵌入式紧凑 stream 会保留原始带时间 chunk。`seq` 在这些 settlement 与所有交错事件之间保持连续。后端可以为事件批次选择自己的存储 framing,只要句柄的 `read()` 返回与追加时完全一致的事件即可;当前 JSONL
|
|
682
|
+
持久化后端依赖的约定如下:持久日志无损保存每个事件,每个 Assistant attempt 都是一个 `assistant/message` 或 `assistant/attempt`,其嵌入式紧凑 stream 会保留原始带时间 chunk。`seq` 在这些 settlement 与所有交错事件之间保持连续。后端可以为事件批次选择自己的存储 framing,只要句柄的 `read()` 返回与追加时完全一致的事件即可;当前 JSONL 每个事件写一行(见 [persistence.md](./persistence.md))。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.snapshotEvents()` 始终与后端可持久化的内容一致。新增会携带不可序列化数据、破坏核心执行嵌套或违反事件所有方声明关系的事件类型,都会构成磁盘格式的破坏性变更。
|
|
666
683
|
|
|
667
684
|
消费此约定的后端见 [persistence.md](./persistence.md)。
|
|
668
685
|
|
|
@@ -670,7 +687,7 @@ interface TurnEndReasonMap {
|
|
|
670
687
|
|
|
671
688
|
`ModelCatalog` 是 `session/modelCatalog` 返回的 Host generation 模型目录:它携带部署默认值、可路由 provider id、成功的 provider 分组与相互隔离的 provider 失败。它不由某个 Session 派生,因此与 Session projection 分开保存。
|
|
672
689
|
|
|
673
|
-
`SessionOpenWorkspacePathRequest` 携带绝对路径或已按 workspace 解析的 `path`。`SessionOpenWorkspacePathValue` 确认 Host 已接受原生交接。Session-aware Client 会在已知当前 Session cwd 时据此解析相对路径;controller 将路径原样交给打开器,并通过 Session Remote 错误词汇表报告无效请求、取消与打开器失败。
|
|
690
|
+
`SessionOpenWorkspacePathRequest` 携带绝对路径或已按 workspace 解析的 `path`。`SessionOpenWorkspacePathValue` 确认 Host 已接受原生交接。Session-aware Client 会在已知当前 Session cwd 时据此解析相对路径;controller 将路径原样交给打开器,并通过 Session Remote 错误词汇表报告无效请求、取消与打开器失败。 可选的 `action: "reveal"` 选择文件管理器导航;省略时使用默认应用打开。
|
|
674
691
|
|
|
675
692
|
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
676
693
|
|
|
@@ -744,6 +761,12 @@ inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<SessionInspectio
|
|
|
744
761
|
*/
|
|
745
762
|
@Remote canOpenWorkspacePath(): boolean
|
|
746
763
|
|
|
764
|
+
/**
|
|
765
|
+
* Describe the serving desktop for authenticated file-action routes.
|
|
766
|
+
* @returns Host name, configured availability, and platform-specific file-manager behavior.
|
|
767
|
+
*/
|
|
768
|
+
workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' | 'explorer' | 'directory' | null }
|
|
769
|
+
|
|
747
770
|
/**
|
|
748
771
|
* Open one path prepared by a Session-aware caller on the Host desktop.
|
|
749
772
|
* @param request - path after best-effort Session workspace resolution.
|
|
@@ -868,10 +891,9 @@ create(id?: SessionId, options?: CreateSessionOptions): Session
|
|
|
868
891
|
*
|
|
869
892
|
* @param id - the session id; omitted, the store mints `session-<n>`.
|
|
870
893
|
* @param options - seed events and/or creation metadata for the header. With
|
|
871
|
-
* `
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
* retain no mutable aliases.
|
|
894
|
+
* `eventState`, every seed event is either independently owned or any
|
|
895
|
+
* shared value is deeply frozen; {@link Session.fromRestore} validates and
|
|
896
|
+
* adopts those values without copying or freezing them.
|
|
875
897
|
* @returns the constructed session, NOT yet in the store.
|
|
876
898
|
* @throws if a session with `id` already exists, metadata is not a plain
|
|
877
899
|
* lossless-JSON record with valid scalar fields, or `meta.cwd` is a
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Bash 执行器
|
|
7
7
|
|
|
8
|
-
bash 执行 seam 分为 Service Definition([dsh-shell](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/shell),`ctx.shell`)、Service Provider([dsh-bash-local](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/bash-local) 与 [dsh-bash-sandbox](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/bash-sandbox))和 Consumer([dsh-tool-bash](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/tool-bash),即 `bash` schema)。通用后台任务的 job id、所有权与控制位于 [jobs.md](./jobs.md);本 seam
|
|
8
|
+
bash 执行 seam 分为 Service Definition([dsh-shell](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/shell),`ctx.shell`)、Service Provider([dsh-bash-local](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/bash-local) 与 [dsh-bash-sandbox](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/bash-sandbox))和 Consumer([dsh-tool-bash](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/shell/tool-bash),即 `bash` schema)。通用后台任务的 job id、所有权与控制位于 [jobs.md](./jobs.md);本 seam 返回一个不含任务概念的进程句柄。managed-range 机制封装在[子进程 seam](./subprocess.md)之后。
|
|
9
9
|
|
|
10
10
|
源码:[`packages/shell/shell/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/shell/shell/src/types.ts)
|
|
11
11
|
|
|
@@ -101,7 +101,7 @@ interface ShellExecSpec {
|
|
|
101
101
|
}
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
`stdin` 和 `env` 是受信任的进程内插件输入,不由 `dsh-tool-bash` 暴露。本地执行器会先清除环境中的凭据,再合并调用方显式提供的 env
|
|
104
|
+
`stdin` 和 `env` 是受信任的进程内插件输入,不由 `dsh-tool-bash` 暴露。本地执行器会先清除环境中的凭据,再合并调用方显式提供的 env。
|
|
105
105
|
|
|
106
106
|
`stdoutMaxBytes` 同样仅供受信任插件使用。它让前台消费方能在有界解析预算内请求完整 stdout,而不会改变 stderr、后台任务或面向模型的 bash 工具的常规输出上限。
|
|
107
107
|
|
|
@@ -169,7 +169,7 @@ interface ShellSandboxInfo {
|
|
|
169
169
|
|
|
170
170
|
## 后台进程:`ShellProcess`
|
|
171
171
|
|
|
172
|
-
`start()` 返回不含 id 或所有者的句柄。`dsh-tool-bash` 将它适配为 `ctx.jobs.start()` 钩子;随后由通用运行时拥有任务标识与生命周期。`done`
|
|
172
|
+
`start()` 返回不含 id 或所有者的句柄。`dsh-tool-bash` 将它适配为 `ctx.jobs.start()` 钩子;随后由通用运行时拥有任务标识与生命周期。`done` 会在底层进程结算时完成且绝不 reject;subprocess 提供方的 rejection 会生成状态为 `killed` 的进程,并把不声明阶段的错误写入 stderr。进程结算后仍可读取,并且沙箱事实会在 `done` 完成前写入。
|
|
173
173
|
|
|
174
174
|
```ts type-equiv
|
|
175
175
|
/**
|
|
@@ -185,7 +185,10 @@ interface ShellProcess {
|
|
|
185
185
|
exitCode: number | null
|
|
186
186
|
/** Terminating signal name, when signal-killed. */
|
|
187
187
|
signal: NodeJS.Signals | null
|
|
188
|
-
/**
|
|
188
|
+
/**
|
|
189
|
+
* Resolves when the underlying process settles (never rejects — provider
|
|
190
|
+
* rejection settles as `killed` with a stage-neutral error on stderr).
|
|
191
|
+
*/
|
|
189
192
|
readonly done: Promise<void>
|
|
190
193
|
/** Sandbox facts, stamped once a confined process settles. */
|
|
191
194
|
sandbox?: ShellSandboxInfo
|
|
@@ -196,7 +199,7 @@ interface ShellProcess {
|
|
|
196
199
|
*/
|
|
197
200
|
readOutput(): ShellProcessRead
|
|
198
201
|
/**
|
|
199
|
-
*
|
|
202
|
+
* Terminate the provider-managed range. Returns false when it had already finished
|
|
200
203
|
* (no-op); idempotent.
|
|
201
204
|
*/
|
|
202
205
|
kill(): boolean
|
|
@@ -221,7 +224,7 @@ interface ShellProcessRead {
|
|
|
221
224
|
|
|
222
225
|
## 服务
|
|
223
226
|
|
|
224
|
-
`ShellExecutor` 拥有 `resolve`、前台 `run`、后台进程 `start` 以及 `sandboxMode` 能力事实。`dsh-bash-local`
|
|
227
|
+
`ShellExecutor` 拥有 `resolve`、前台 `run`、后台进程 `start` 以及 `sandboxMode` 能力事实。`dsh-bash-local` 拥有命令默认值补全、超时/中止分类、终端环境以及后台读取合并;managed-range 终止、有界收集器、spill 文件、凭据清除与 dispose(资源释放)后完全停稳归[子进程服务](./subprocess.md)所有。`dsh-tool-bash` 拥有面向模型的渲染,并将后台句柄适配到[通用任务运行时](./jobs.md)。`dsh-shell` 拥有 shell 工具共享的退出状态约定:导出的 `parseExitStatus`/`ParsedExitStatus` 是 `dsh-tool-bash` 的 `renderResult` 与 `dsh-tool-pwsh` 的 `renderPwshResult` 所追加的 `[exit code: N]` / `[killed by signal: X]` 标记的逆解析,两个工具的 `presentResult` 都用它把渲染文本拆分为 terminal 卡的输出正文与退出状态 pill。
|
|
225
228
|
|
|
226
229
|
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
227
230
|
|