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.
Files changed (121) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.en.md +14 -8
  3. package/README.md +14 -8
  4. package/docs/banner.svg +25 -0
  5. package/kb/INDEX.md +6 -2
  6. package/kb/README.md +4 -4
  7. package/kb/extra/AGENTS.md +2 -2
  8. package/kb/extra/cookbook/adding-a-session-format-version.md +109 -0
  9. package/kb/extra/cookbook/adding-a-session-format-version.zh.md +109 -0
  10. package/kb/extra/cookbook/adding-a-vendored-package.md +1 -1
  11. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +1 -1
  12. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +1 -1
  13. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +1 -1
  14. package/kb/extra/deepseek-llm-api-wire-extensions.md +2 -2
  15. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +2 -2
  16. package/kb/extra/development.md +13 -3
  17. package/kb/extra/development.zh.md +13 -3
  18. package/kb/extra/event-producer-consumer.md +33 -31
  19. package/kb/extra/event-producer-consumer.zh.md +34 -32
  20. package/kb/extra/i18n/README.md +2 -1
  21. package/kb/extra/i18n/README.zh.md +3 -2
  22. package/kb/extra/i18n/translation-prompt.md +1 -1
  23. package/kb/extra/module-graph.md +62 -24
  24. package/kb/extra/module-graph.zh.md +62 -24
  25. package/kb/extra/rescope.md +1 -1
  26. package/kb/extra/rescope.zh.md +1 -1
  27. package/kb/extra/session-format-status.md +47 -0
  28. package/kb/extra/session-format-status.zh.md +47 -0
  29. package/kb/extra/subsystems/agent-team.md +1 -1
  30. package/kb/extra/subsystems/agent-team.zh.md +1 -1
  31. package/kb/extra/subsystems/feedback.md +164 -30
  32. package/kb/extra/subsystems/feedback.zh.md +164 -30
  33. package/kb/extra/testing.md +4 -3
  34. package/kb/extra/testing.zh.md +4 -3
  35. package/kb/extra/web-styling.md +1 -0
  36. package/kb/extra/web-styling.zh.md +1 -0
  37. package/kb/meta/search-index.json +151 -103
  38. package/kb/meta/site-pages.txt +188 -184
  39. package/kb/meta/source.json +5 -5
  40. package/kb/meta/topics.md +2 -2
  41. package/kb/site/develop/basic/publish.md +1 -1
  42. package/kb/site/en/develop/basic/publish.md +1 -1
  43. package/kb/site/en/guide/providers.md +1 -1
  44. package/kb/site/en/guide/python-sdk.md +19 -3
  45. package/kb/site/en/reference/agent-lifecycle.md +12 -5
  46. package/kb/site/en/reference/capability-seams.md +10 -3
  47. package/kb/site/en/reference/config-catalog.md +173 -42
  48. package/kb/site/en/reference/cookbook/adding-a-tool.md +1 -1
  49. package/kb/site/en/reference/cookbook/extension-cookbook.md +1 -1
  50. package/kb/site/en/reference/index.md +18 -8
  51. package/kb/site/en/reference/persistence-catalog.md +121 -48
  52. package/kb/site/en/reference/subsystems/approval.md +1 -1
  53. package/kb/site/en/reference/subsystems/client-modules.md +9 -0
  54. package/kb/site/en/reference/subsystems/client-resources.md +94 -0
  55. package/kb/site/en/reference/subsystems/compaction.md +1 -1
  56. package/kb/site/en/reference/subsystems/core.md +79 -16
  57. package/kb/site/en/reference/subsystems/filesystem.md +15 -0
  58. package/kb/site/en/reference/subsystems/goal.md +37 -1
  59. package/kb/site/en/reference/subsystems/index.md +2 -0
  60. package/kb/site/en/reference/subsystems/invariants.md +1 -1
  61. package/kb/site/en/reference/subsystems/llm-streaming.md +20 -10
  62. package/kb/site/en/reference/subsystems/lsp.md +1 -1
  63. package/kb/site/en/reference/subsystems/persistence.md +36 -15
  64. package/kb/site/en/reference/subsystems/schedule.md +1 -1
  65. package/kb/site/en/reference/subsystems/scope.md +1 -1
  66. package/kb/site/en/reference/subsystems/session-reference.md +4 -0
  67. package/kb/site/en/reference/subsystems/session-telemetry.md +22 -6
  68. package/kb/site/en/reference/subsystems/session.md +64 -42
  69. package/kb/site/en/reference/subsystems/shell.md +9 -6
  70. package/kb/site/en/reference/subsystems/sidebar-right.md +151 -0
  71. package/kb/site/en/reference/subsystems/slots.md +41 -33
  72. package/kb/site/en/reference/subsystems/spill.md +13 -6
  73. package/kb/site/en/reference/subsystems/subagent.md +20 -13
  74. package/kb/site/en/reference/subsystems/subprocess.md +25 -26
  75. package/kb/site/en/reference/subsystems/system-prompt.md +3 -1
  76. package/kb/site/en/reference/subsystems/token-meter.md +2 -1
  77. package/kb/site/en/reference/subsystems/tools.md +5 -5
  78. package/kb/site/en/reference/subsystems/workspace.md +80 -1
  79. package/kb/site/en/reference/tool-catalog.md +46 -2
  80. package/kb/site/en/reference/tool-execution-pipeline.md +2 -2
  81. package/kb/site/guide/providers.md +1 -1
  82. package/kb/site/guide/python-sdk.md +19 -3
  83. package/kb/site/reference/agent-lifecycle.md +12 -5
  84. package/kb/site/reference/capability-seams.md +10 -3
  85. package/kb/site/reference/config-catalog.md +173 -42
  86. package/kb/site/reference/cookbook/adding-a-tool.md +1 -1
  87. package/kb/site/reference/cookbook/extension-cookbook.md +1 -1
  88. package/kb/site/reference/index.md +18 -8
  89. package/kb/site/reference/persistence-catalog.md +127 -54
  90. package/kb/site/reference/subsystems/approval.md +1 -1
  91. package/kb/site/reference/subsystems/client-modules.md +9 -0
  92. package/kb/site/reference/subsystems/client-resources.md +94 -0
  93. package/kb/site/reference/subsystems/compaction.md +1 -1
  94. package/kb/site/reference/subsystems/core.md +79 -16
  95. package/kb/site/reference/subsystems/filesystem.md +15 -0
  96. package/kb/site/reference/subsystems/goal.md +37 -1
  97. package/kb/site/reference/subsystems/index.md +14 -12
  98. package/kb/site/reference/subsystems/invariants.md +1 -1
  99. package/kb/site/reference/subsystems/llm-streaming.md +20 -10
  100. package/kb/site/reference/subsystems/lsp.md +1 -1
  101. package/kb/site/reference/subsystems/persistence.md +36 -15
  102. package/kb/site/reference/subsystems/schedule.md +1 -1
  103. package/kb/site/reference/subsystems/scope.md +1 -1
  104. package/kb/site/reference/subsystems/session-reference.md +4 -0
  105. package/kb/site/reference/subsystems/session-telemetry.md +22 -6
  106. package/kb/site/reference/subsystems/session.md +64 -42
  107. package/kb/site/reference/subsystems/shell.md +9 -6
  108. package/kb/site/reference/subsystems/sidebar-right.md +151 -0
  109. package/kb/site/reference/subsystems/slots.md +41 -33
  110. package/kb/site/reference/subsystems/spill.md +13 -6
  111. package/kb/site/reference/subsystems/subagent.md +20 -13
  112. package/kb/site/reference/subsystems/subprocess.md +25 -26
  113. package/kb/site/reference/subsystems/system-prompt.md +3 -1
  114. package/kb/site/reference/subsystems/token-meter.md +2 -1
  115. package/kb/site/reference/subsystems/tools.md +5 -5
  116. package/kb/site/reference/subsystems/workspace.md +80 -1
  117. package/kb/site/reference/tool-catalog.md +46 -2
  118. package/kb/site/reference/tool-execution-pipeline.md +2 -2
  119. package/lib/index.js +25 -44
  120. package/package.json +3 -2
  121. 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 寻址的服务方法:句柄是跨进程写租约把守的那扇唯一的门。一种句柄类型同时服务两种访问——在 `read` 句柄上执行修改是运行时的 `SessionReadOnlyError`,而非类型层面的拆分——而进程内单写者所有权使得在已有活跃持有者时第二次 `open(id, 'write')` 以 `SessionAlreadyOwnedError` 拒绝。
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 events with `seq >= offset`, at most `length` of them.
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<readonly SessionEvent[]>
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 的关闭清扫不丢任何数据。该窗口只限制有意的批处理等待,不限制事件循环调度或后端完成持久化的延迟([决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.zh.md))。
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)定义;[Session 准备阶段决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-05-session-preparation.zh.md)记录仍然保留的发布边界 `SessionPreparation`。
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。`open` 会在按 id 串行化的区段内运行构建时静态确定的相邻迁移链,再返回句柄;每个源路径、字节与 inode 都保持不变,并且只排他发布最终的当前 generation。即使仍有较旧的可读 generation,最高的未来 generation 仍会导致拒绝。当前 v2 恢复会保留已安装扩展和带 `ignorable: true` 的未知事件;历史 v0/v1 迁移则会拒绝未知类型,即使它带有 ignorable 标记。后端为每个会话保留独立文件时,消息附上选定的原始日志路径。JSONL 后端把已发布 v0 或 v1 迁移到当前 v2,并在解读其版本专属字段或事件行前拒绝未来版本。仓库外后端必须在自己的物理格式入口提供等价的仅当前句柄值与方向感知拒绝。[已发布格式迁移决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md)负责迁移链与不可变发布规则。
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. In v2 the
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` 转移所有权的全新的持久化对象图。恢复分支会就地验证并冻结转移来的 header 与事件,因此调用方不得保留可变别名。`SessionPreparation` 随后持有该精确的未发布 Session,直至发布或回滚;dispose 是同步且幂等的。agent-loop 的 resume 通过该会话的写句柄读取已存储的日志,并在准备之前追加所需的 `interruptedTurnClosers`,以此构建这些对象图。
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
- * Fresh storage values transferred to {@link SessionStore.prepare} without a
225
- * second serialization copy. Callers retain no mutable aliases.
245
+ * Adoptable storage values transferred to {@link SessionStore.prepare}
246
+ * without another copy or freeze pass.
226
247
  */
227
248
  interface RestoredSessionOptions {
228
- /** Fresh detached storage events to validate and freeze in place. */
249
+ /** Events that are independently owned or already deeply frozen. */
229
250
  readonly seed: SessionEvent[]
230
- /** Fresh detached storage metadata to validate and freeze in place. */
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
- /** Select the persistence ownership-transfer path. */
235
- readonly seedSource: 'persistence'
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 seedSource?: undefined })
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) 负责持久化、生命周期与活动状态呈现,[对话式交付](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/simplification/2026-08-09-conversational-schedule-delivery.zh.md) 负责无回执边界,[显式时区边界](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/simplification/2026-08-09-explicit-schedule-time-zone.zh.md) 负责浏览器本地解释,[有界固定速率 Schedule](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/simplification/2026-08-09-bounded-fixed-rate-schedule.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。
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)规定,注册表层决策由[共享存储 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-12-scoped-layers-store.zh.md)规定,可调用 API 与过滤语义则由包 [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/scope/README.zh.md)规定。
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 对象会从 seq 0 回放完整日志,包括构造 seed 历史;重新收养同一对象时会从 handoff 游标之后继续。投递是尽力而为的:游标标记的是「已交接」而非「已送达」,记录可能丢失(崩溃、重载窗口)也可能重复(新对象回放、SDK 重试),因此接收端对 ledger 记录基于 `(session.id, session.format_version, event.seq)` 去重;ops 记录刻意省略这类标识——它们是用于告警的信号,而非用于累加的条目,重复被容忍而非被去重。
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
- seam 的确认契约(归属 [Service Definition README 的共享披露段](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-telemetry/README.zh.md#the-sharing-disclosure)):每个后端都通过 `ctx.sessionTelemetry` 上必需的抽象 `sharing` 成员披露其部署级共享策略,消费方只有在未挂载任何遥测服务时才渲染「未配置」。披露只陈述当前策略,绝不承诺投递或留存——交接是非阻塞入队,批处理、重试与丢失策略仍归上报 SDK。
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 policy disclosed by a mounted
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 or capacity
120
- * changes. It does not participate in request reconstruction or header equality.
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`:调用配置 + 适配器所提供默认值的标记 + 渲染后的系统提示词 + 已组装的工具 schema)会作为会话状态写入日志,因此每个对话请求都是日志的纯函数(见可重建性 Agent Note)。带有 reason `'initial'` 或 `'resume'` 的完整 `request/header` 快照记录每个 agent loop 实例的边界;请求变化时会追加 reason 为 `'change'` 的快照;未变的信封显式开启消息序列或跟随 surface 替换时,会追加 reason 为 `'series'` 的快照。如果发生变化的快照所属请求同时开启序列,它会携带 `startsSeries: true`。普通的仅追加后续 Turn,以及同一模型消息序列内的后续 Step 与重试沿用最新快照。`foldRequestHeader(events)` 通过选择最新快照重建请求头。该事件不是 `SurfaceEventType`,不产生 LLM 消息。
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, system prompt, and
160
- * tools. The latest full `request/header` snapshot reconstructs it; canonical
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
- 规范形式:空系统提示词和空工具列表都表示为字段缺失,与请求构建方式一致。包含旧版 `request/header-delta` 事件或完整快照原因为 `fallback` 的旧版 v0 日志,会在 seed、append 和持久化加载边界被拒绝,而不会以不完整方式回放。
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` 追加,且仅在提供方、模型或容量与上一条记录不同时追加。它保持在 `EpochHeader` 之外,因为该类型是 `headerEquals` 逐字段比较的重建约定。容量描述的是路由,不是请求输入,把它折叠进去会让一次容量变化被登记为请求信封的 `change`,也会把适配器元数据拉进 loop 的重建不变式。与 `request/header` 一样,它不是 `SurfaceEventType`,也不产生 LLM 消息。`session.requestContext()` 以增量方式归并最新一条记录。适配器不公布容量的路由会以缺失 `contextWindow` 的形式记录,因此新记录可以清除较早路由的容量。
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
- * Seq numbers of earlier events that this event cites as sources, such as
255
- * the surface nodes shadowed by a compaction replacement. A v2
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
- V2 `assistant/message` 嵌入 provider stream,不能携带 `sourceEventSeqs`。User 与 tool surface event 可以在 provenance replacement operation 需要时引用完整且非空的唯一较早 event 集合。
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
- 三种产生消息的类型(`SurfaceEventType`:`user/message`、`assistant/message`、`tool/result`)携带 surface 元数据,用来声明它们如何加入有序的派生 surface。见 [session surface Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-18-session-surface.zh.md)。
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', start, end }`: replaces surface nodes from `start`
300
- * (inclusive) through `end` (inclusive) with this node. Both must exist as
301
- * surface nodes in the current surface. `start === end` replaces a single
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'; start: SessionSeq; end: SessionSeq }
320
+ | { op: 'replace'; startSeq: SessionSeq; endSeq: SessionSeq }
309
321
  ```
310
322
 
311
- `'append'` 是常规的尾部追加路径。`replace` 会遮蔽从 `start` `end`(含两端)的 surface 条目(两者都必须是有效的 surface seq;`start === end` 时仅替换单个条目),并在原位置插入新事件。
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
- /** V2 Assistant messages embed their provider stream instead of citing source events. */
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 taking ownership of fresh persistence values.
449
- * The storage format, event envelopes, sequence continuity, surface transitions,
450
- * and header fields are validated before the restored objects are frozen.
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 - fresh detached events whose ownership is transferred.
453
- * @param header - fresh detached metadata whose ownership is transferred.
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;v2 decoding 只在 `SessionHeader.isSeeded` 为 true 时要求该 marker,并从其 seq 推导 `inheritedEventCount`。对于 lifecycle ownership,定位任一形式的最后一个 `session/end-seed`。重新打开已经以任一 marker 结尾的 seed 时,不会再追加普通 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 中保持待处理,直到唤醒交付打开一个轮次(见[钩子桥接 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-30-hook-bridges.zh.md))。
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 v2 每个事件写一行(见 [persistence.md](./persistence.md))。所有 `event.data` 都必须可序列化为 JSON;`Session.append` 会从源头强制这一要求(遇到不可序列化数据时抛出),因此错误事件绝不会进入日志,`session.snapshotEvents()` 始终与后端可持久化的内容一致。新增会携带不可序列化数据、破坏核心执行嵌套或违反事件所有方声明关系的事件类型,都会构成磁盘格式的破坏性变更。
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
- * `seedSource: 'persistence'`, metadata and events must be fresh detached
872
- * graphs whose ownership transfers to this call: they are validated and
873
- * frozen in place through {@link Session.fromRestore}, so the caller must
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 返回一个不含任务概念的进程句柄。原始进程组机制封装在[子进程 seam](./subprocess.md)之后。
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。见 [bash-stdin-env Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-30-bash-stdin-env-trusted-plugin-api.zh.md)
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` 在进程关闭时完成且绝不被拒绝;进程结束后仍可读取,并且沙箱事实会在 `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
- /** Resolves when the underlying process closes (never rejects — a spawn failure settles as `killed` with the error on stderr). */
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
- * Kill the process group. Returns false when it had already finished
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` 拥有命令默认值补全、超时/中止分类、终端环境以及后台读取合并;进程组、有界收集器、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。
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