dsh-plugin-dev-kb 1.0.8 → 1.1.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 (188) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.en.md +6 -6
  3. package/README.md +6 -6
  4. package/kb/INDEX.md +21 -5
  5. package/kb/README.md +11 -10
  6. package/kb/extra/AGENTS.md +4 -4
  7. package/kb/extra/cookbook/adding-a-remote-api.md +197 -0
  8. package/kb/extra/cookbook/adding-a-remote-api.zh.md +197 -0
  9. package/kb/extra/cookbook/adding-a-vendored-package.md +2 -2
  10. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +2 -2
  11. package/kb/extra/deepseek-llm-api-wire-extensions.md +163 -0
  12. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +163 -0
  13. package/kb/extra/development.md +8 -14
  14. package/kb/extra/development.zh.md +8 -14
  15. package/kb/extra/event-producer-consumer.md +55 -48
  16. package/kb/extra/event-producer-consumer.zh.md +58 -51
  17. package/kb/extra/glossary.md +1 -1
  18. package/kb/extra/glossary.zh.md +1 -1
  19. package/kb/extra/graph-atlas.md +0 -2
  20. package/kb/extra/graph-atlas.zh.md +0 -2
  21. package/kb/extra/i18n/README.md +4 -4
  22. package/kb/extra/i18n/README.zh.md +4 -4
  23. package/kb/extra/i18n/style-samples.md +2 -2
  24. package/kb/extra/module-graph.md +646 -926
  25. package/kb/extra/module-graph.zh.md +648 -928
  26. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +2 -2
  27. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +2 -2
  28. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +2 -2
  29. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +2 -2
  30. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +2 -2
  31. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +2 -2
  32. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +1 -1
  33. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +1 -1
  34. package/kb/extra/rescope.md +2 -2
  35. package/kb/extra/rescope.zh.md +2 -2
  36. package/kb/extra/subsystems/agent-team.md +28 -4
  37. package/kb/extra/subsystems/agent-team.zh.md +28 -4
  38. package/kb/extra/subsystems/attachment.md +168 -7
  39. package/kb/extra/subsystems/attachment.zh.md +168 -7
  40. package/kb/extra/subsystems/extensions.md +18 -0
  41. package/kb/extra/subsystems/extensions.zh.md +18 -0
  42. package/kb/extra/subsystems/feedback.md +4 -4
  43. package/kb/extra/subsystems/feedback.zh.md +4 -4
  44. package/kb/extra/subsystems/todo.md +32 -0
  45. package/kb/extra/subsystems/todo.zh.md +32 -0
  46. package/kb/extra/subsystems/webhook.md +70 -0
  47. package/kb/extra/subsystems/webhook.zh.md +70 -0
  48. package/kb/extra/testing.md +15 -10
  49. package/kb/extra/testing.zh.md +13 -8
  50. package/kb/extra/web-styling.md +4 -0
  51. package/kb/extra/web-styling.zh.md +4 -0
  52. package/kb/meta/search-index.json +309 -177
  53. package/kb/meta/site-pages.txt +183 -167
  54. package/kb/meta/source.json +5 -5
  55. package/kb/meta/topics.md +14 -6
  56. package/kb/site/develop/basic/publish.md +2 -2
  57. package/kb/site/develop/basic/tool.md +1 -1
  58. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  59. package/kb/site/develop/framework/events.md +1 -1
  60. package/kb/site/develop/practice/dynamic-cordis.md +17 -0
  61. package/kb/site/develop/practice/llm-adapter.md +4 -3
  62. package/kb/site/en/develop/basic/publish.md +2 -2
  63. package/kb/site/en/develop/basic/tool.md +1 -1
  64. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  65. package/kb/site/en/develop/framework/events.md +1 -1
  66. package/kb/site/en/develop/practice/dynamic-cordis.md +17 -0
  67. package/kb/site/en/develop/practice/llm-adapter.md +4 -3
  68. package/kb/site/en/guide/github-review.md +104 -0
  69. package/kb/site/en/guide/mcp-memory.md +103 -0
  70. package/kb/site/en/guide/network-proxy.md +87 -0
  71. package/kb/site/en/guide/providers.md +70 -17
  72. package/kb/site/en/guide/python-sdk.md +80 -34
  73. package/kb/site/en/guide/schedule.md +23 -0
  74. package/kb/site/en/reference/agent-lifecycle.md +6 -4
  75. package/kb/{extra → site/en/reference}/api-gateway.md +12 -10
  76. package/kb/site/en/reference/capability-seams.md +128 -73
  77. package/kb/site/en/reference/config-catalog.md +481 -360
  78. package/kb/site/en/reference/cookbook/adding-a-package.md +3 -4
  79. package/kb/site/en/reference/cookbook/adding-a-settings-card.md +12 -10
  80. package/kb/site/en/reference/cookbook/adding-a-tool.md +11 -4
  81. package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +1 -1
  82. package/kb/site/en/reference/cookbook/extension-cookbook.md +20 -17
  83. package/kb/site/en/reference/cordis-api/inherited.md +1 -1
  84. package/kb/site/en/reference/cordis-primer.md +2 -1
  85. package/kb/site/en/reference/index.md +30 -11
  86. package/kb/site/en/reference/persistence-catalog.md +148 -80
  87. package/kb/site/en/reference/subsystems/approval.md +10 -10
  88. package/kb/site/en/reference/subsystems/client-modules.md +58 -16
  89. package/kb/site/en/reference/subsystems/code-runtime.md +10 -6
  90. package/kb/site/en/reference/subsystems/commands.md +25 -16
  91. package/kb/site/en/reference/subsystems/compaction.md +11 -11
  92. package/kb/site/en/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +50 -24
  93. package/kb/site/en/reference/subsystems/core.md +156 -17
  94. package/kb/site/en/reference/subsystems/credentials.md +44 -3
  95. package/kb/site/en/reference/subsystems/filesystem.md +12 -2
  96. package/kb/site/en/reference/subsystems/goal.md +1 -1
  97. package/kb/site/en/reference/subsystems/index.md +7 -2
  98. package/kb/site/en/reference/subsystems/jobs.md +1 -1
  99. package/kb/site/en/reference/subsystems/llm-streaming.md +154 -12
  100. package/kb/site/en/reference/subsystems/permission-presets.md +6 -6
  101. package/kb/site/en/reference/subsystems/persistence.md +185 -175
  102. package/kb/site/en/reference/subsystems/plan.md +2 -2
  103. package/kb/site/en/reference/subsystems/sandbox.md +2 -0
  104. package/kb/site/en/reference/subsystems/schedule.md +9 -3
  105. package/kb/site/en/reference/subsystems/session-projection.md +115 -48
  106. package/kb/site/en/reference/subsystems/session-query.md +28 -14
  107. package/kb/site/en/reference/subsystems/session-reference.md +53 -8
  108. package/kb/site/en/reference/subsystems/session-telemetry.md +8 -8
  109. package/kb/site/en/reference/subsystems/session-title.md +6 -6
  110. package/kb/site/en/reference/subsystems/session.md +401 -99
  111. package/kb/site/en/reference/subsystems/settings.md +101 -6
  112. package/kb/site/en/reference/subsystems/skills.md +23 -0
  113. package/kb/site/en/reference/subsystems/slots.md +178 -0
  114. package/kb/site/en/reference/subsystems/spill.md +2 -2
  115. package/kb/site/en/reference/subsystems/storage.md +34 -3
  116. package/kb/site/en/reference/subsystems/subagent.md +122 -109
  117. package/kb/site/en/reference/subsystems/system-prompt.md +17 -4
  118. package/kb/site/en/reference/subsystems/token-meter.md +27 -12
  119. package/kb/site/en/reference/subsystems/tools.md +39 -39
  120. package/kb/site/en/reference/subsystems/typert.md +62 -55
  121. package/kb/site/en/reference/subsystems/user-questions.md +33 -33
  122. package/kb/site/en/reference/subsystems/web-client.md +98 -0
  123. package/kb/site/en/reference/subsystems/web-server.md +11 -5
  124. package/kb/site/en/reference/subsystems/web.md +7 -1
  125. package/kb/site/en/reference/subsystems/workspace.md +102 -9
  126. package/kb/site/en/reference/tool-catalog.md +86 -82
  127. package/kb/site/en/reference/tool-execution-pipeline.md +1 -1
  128. package/kb/site/guide/github-review.md +104 -0
  129. package/kb/site/guide/mcp-memory.md +103 -0
  130. package/kb/site/guide/network-proxy.md +87 -0
  131. package/kb/site/guide/providers.md +70 -17
  132. package/kb/site/guide/python-sdk.md +87 -41
  133. package/kb/site/guide/schedule.md +23 -0
  134. package/kb/site/reference/agent-lifecycle.md +6 -4
  135. package/kb/{extra/api-gateway.zh.md → site/reference/api-gateway.md} +12 -10
  136. package/kb/site/reference/capability-seams.md +128 -73
  137. package/kb/site/reference/config-catalog.md +481 -360
  138. package/kb/site/reference/cookbook/adding-a-package.md +3 -4
  139. package/kb/site/reference/cookbook/adding-a-settings-card.md +12 -10
  140. package/kb/site/reference/cookbook/adding-a-tool.md +11 -4
  141. package/kb/site/reference/cookbook/adding-an-llm-adapter.md +1 -1
  142. package/kb/site/reference/cookbook/extension-cookbook.md +20 -17
  143. package/kb/site/reference/cordis-api/inherited.md +1 -1
  144. package/kb/site/reference/cordis-primer.md +2 -1
  145. package/kb/site/reference/index.md +30 -11
  146. package/kb/site/reference/persistence-catalog.md +148 -80
  147. package/kb/site/reference/subsystems/approval.md +10 -10
  148. package/kb/site/reference/subsystems/client-modules.md +58 -16
  149. package/kb/site/reference/subsystems/code-runtime.md +10 -6
  150. package/kb/site/reference/subsystems/commands.md +25 -16
  151. package/kb/site/reference/subsystems/compaction.md +11 -11
  152. package/kb/site/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +50 -24
  153. package/kb/site/reference/subsystems/core.md +156 -17
  154. package/kb/site/reference/subsystems/credentials.md +44 -3
  155. package/kb/site/reference/subsystems/filesystem.md +12 -2
  156. package/kb/site/reference/subsystems/goal.md +1 -1
  157. package/kb/site/reference/subsystems/index.md +7 -2
  158. package/kb/site/reference/subsystems/jobs.md +1 -1
  159. package/kb/site/reference/subsystems/llm-streaming.md +154 -12
  160. package/kb/site/reference/subsystems/permission-presets.md +5 -5
  161. package/kb/site/reference/subsystems/persistence.md +184 -174
  162. package/kb/site/reference/subsystems/plan.md +2 -2
  163. package/kb/site/reference/subsystems/schedule.md +9 -3
  164. package/kb/site/reference/subsystems/session-projection.md +115 -48
  165. package/kb/site/reference/subsystems/session-query.md +28 -14
  166. package/kb/site/reference/subsystems/session-reference.md +53 -8
  167. package/kb/site/reference/subsystems/session-telemetry.md +8 -8
  168. package/kb/site/reference/subsystems/session-title.md +6 -6
  169. package/kb/site/reference/subsystems/session.md +401 -99
  170. package/kb/site/reference/subsystems/settings.md +101 -6
  171. package/kb/site/reference/subsystems/skills.md +23 -0
  172. package/kb/site/reference/subsystems/slots.md +178 -0
  173. package/kb/site/reference/subsystems/spill.md +2 -2
  174. package/kb/site/reference/subsystems/storage.md +34 -3
  175. package/kb/site/reference/subsystems/subagent.md +122 -109
  176. package/kb/site/reference/subsystems/system-prompt.md +17 -4
  177. package/kb/site/reference/subsystems/token-meter.md +27 -12
  178. package/kb/site/reference/subsystems/tools.md +39 -39
  179. package/kb/site/reference/subsystems/typert.md +62 -55
  180. package/kb/site/reference/subsystems/user-questions.md +33 -33
  181. package/kb/site/reference/subsystems/web-client.md +98 -0
  182. package/kb/site/reference/subsystems/web-server.md +11 -5
  183. package/kb/site/reference/subsystems/web.md +7 -1
  184. package/kb/site/reference/subsystems/workspace.md +102 -9
  185. package/kb/site/reference/tool-catalog.md +85 -81
  186. package/kb/site/reference/tool-execution-pipeline.md +1 -1
  187. package/package.json +2 -2
  188. package/skills/dsh-plugin-dev-kb.md +8 -6
@@ -26,12 +26,25 @@ interface ContentBlockMap {
26
26
  'text': TextBlock
27
27
  'reasoning': ReasoningBlock
28
28
  'image': ImageBlock
29
+ 'file': FileBlock
29
30
  'tool-call': ToolCallBlock
30
31
  'tool-result': ToolResultBlock
31
32
  }
32
33
  ```
33
34
 
34
- 各块接口(完整字段见源码):`TextBlock`(`text`)、`ReasoningBlock`(thinking,区别于可见文本)、`ImageBlock`(一个持久的[图片附件](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/attachment.zh.md))、`ToolCallBlock`(`id: CallId`、`name`、原始 JSON `arguments`),以及 `ToolResultBlock`(`toolCallId`、嵌套 `content: ContentBlock[]`、`isError?`)。`ContentBlock = ContentBlockMap[ContentBlockType]`。仅当适配器、UI、压缩(compaction)和持久回放路径均支持某种新模态时,才将其纳入可合并扩展的 map。
35
+ 各块接口(完整字段见源码):`TextBlock`(`text`)、`ReasoningBlock`(thinking,区别于可见文本)、`ImageBlock`(一个持久的[图片附件](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/attachment.zh.md))、`FileBlock`(一个持久的原样[文件附件](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/attachment.zh.md),请求组装对每条路由都把它投影为 handle 文本)、`ToolCallBlock`(`id: ToolCallId`、`name`、原始 JSON `arguments`),以及 `ToolResultBlock`(`toolCallId`、嵌套 `content: ContentBlock[]`、`isError?`)。`ContentBlock = ContentBlockMap[ContentBlockType]`。仅当适配器、UI、压缩(compaction)和持久回放路径均支持某种新模态时,才将其纳入可合并扩展的 map。
36
+
37
+ 图片访问方式属于请求序列化,不属于持久附件或确定性请求图片版本。`resolveImageAttachmentAccess()` 把附件提供方可选的宿主对象路径,与消费方为当前工具执行文件系统提供的映射组合起来。结果只适用于本次请求,不参与 `variantId`。
38
+
39
+ 源码:[`packages/llm/llm/src/content.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm/src/content.ts)
40
+
41
+ ```ts type-equiv
42
+ /** Execution-world path that model tools can use to read one normalized attachment. */
43
+ interface ImageAttachmentAccess {
44
+ /** Absolute path to immutable normalized bytes; callers must treat it as read-only. */
45
+ readonlyPath: string
46
+ }
47
+ ```
35
48
 
36
49
  源码:[`packages/llm/llm/src/message.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm/src/message.ts)
37
50
 
@@ -196,7 +209,7 @@ type StreamChunk =
196
209
  | { type: 'block-start'; index: number; blockType: ContentBlockType }
197
210
  | { type: 'text-delta'; index: number; text: string }
198
211
  | { type: 'reasoning-delta'; index: number; text: string }
199
- | { type: 'tool-call-delta'; index: number; id: CallId; name?: string; argumentsDelta: string }
212
+ | { type: 'tool-call-delta'; index: number; id: ToolCallId; name?: string; argumentsDelta: string }
200
213
  | { type: 'block-end'; index: number; block: ContentBlock }
201
214
  | { type: 'usage'; usage: TokenUsage }
202
215
  | {
@@ -207,6 +220,16 @@ type StreamChunk =
207
220
  }
208
221
  ```
209
222
 
223
+ <a id="compact-assistant-streams"></a>
224
+
225
+ ## 紧凑 Assistant stream
226
+
227
+ `AssistantStreamAccumulator` 把每个 `StreamChunk` 与其原始安全整数时间戳配对,并生成 `AssistantStreamRecord[]`。同一 block 的连续 text、reasoning 或 tool argument delta 会变成一个 record,使用 `time0`、精确时间戳间隔和每个原始 delta 对应的一个数组成员;其他 chunk 保留为带时间戳的 raw record。该表示会移除重复 event envelope,但不会合并 token 边界,也不会丢弃 terminal、usage、block、failure 或 replay 事实。
228
+
229
+ `snapshot()` 返回分离且不可变的 stream。`expandAssistantStream()` 会严格检查 record key、成员数、index、时间戳、tool-call identity 与无损 JSON,再重建精确的带时间 chunk 序列。Session 日志会把该 stream 嵌入作为 surface result 的 `assistant/message`,或嵌入没有 surface message 的 `assistant/attempt`。
230
+
231
+ 进程本地 `agent/assistant-stream` frame 承载实时呈现。持久回放、遥测、token 记账与历史 UI 组装会展开嵌入式 settlement,而不会把 live frame 当作持久事实。
232
+
210
233
  <a id="llmfailure"></a>
211
234
 
212
235
  ## `LlmFailure`
@@ -229,13 +252,51 @@ interface LlmFailure {
229
252
  }
230
253
  ```
231
254
 
255
+ ## 请求图片定价
256
+
257
+ 提供方对请求图片收取视觉 token 的适配器通过覆写 `LlmAdapter.imageRequestPricing` 声明按路由的定价,消费方经 `ctx.llm.imageRequestPricing(provider, model)` 同步解析。token 计量服务在每次计量时解析路由模型的定价,使 compaction 的压力、保留与选段都按路由请求实际发送的形式为图片历史计价;DeepSeek 适配器复现自身的请求投影(按模型的像素预算、最旧优先 offload),并用官方公布的 v4 视觉计量为保留图片定价,已完成请求仍以 provider usage 为权威锚点。
258
+
259
+ ```ts type-equiv
260
+ /**
261
+ * Request price of one ordered image occurrence under one exact model route's
262
+ * request projection. Every occurrence resolves to the pair the wire actually
263
+ * carries: provider visual tokens for a retained image, plus the model-visible
264
+ * text sent with or instead of it (request-preview handle, offload placeholder,
265
+ * or text-only substitution). The caller prices `text` with its own text
266
+ * estimator so provider pricing never fixes a text tokenization.
267
+ */
268
+ interface LlmImageRequestPrice {
269
+ /** Provider visual tokens for the retained request image; 0 when only text represents this occurrence. */
270
+ visualTokens: number
271
+ /** Model-visible text sent for this occurrence, to be priced by the caller's text estimator. */
272
+ text: string
273
+ }
274
+ ```
275
+
276
+ ```ts type-equiv
277
+ /**
278
+ * Provider-side request-image pricing for one exact model route. Implemented
279
+ * by adapters whose provider charges visual tokens; consumers (the token
280
+ * meter) resolve it synchronously per measurement, so implementations must not
281
+ * perform I/O.
282
+ */
283
+ interface LlmImageRequestPricing {
284
+ /**
285
+ * Price every image occurrence of one request projection.
286
+ * @param images - durable image references in request order, one entry per occurrence.
287
+ * @returns one price per occurrence, aligned by index with `images`.
288
+ */
289
+ priceImages(images: readonly ImageAttachmentRef[]): readonly LlmImageRequestPrice[]
290
+ }
291
+ ```
292
+
232
293
  ## 适配器约定
233
294
 
234
295
  每个适配器必须遵守以下规则,每个消费方可以依赖它们:
235
296
 
236
297
  - **`usage` 在 `finish` 之前,`finish` 之后不再有任何分片。** 将两者都推迟到提供方的流结束标记,这样尾部的 usage-only 分片就不会违反顺序。
237
298
  - **工具调用的 `arguments` 全程保持原始 JSON 字符串。** 部分片段通过 `argumentsDelta` 流式传输;如果提供方返回的是已解析的对象,适配器在 `block-end` 时重新序列化为字符串。
238
- - **两条受支持的错误路径,共用一个 `LlmFailure` 类型。** 失败可以从 `stream()` 抛出(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted', failure}` 结束流(无法在流中途抛异常的适配器用它表示提供方带内错误)。`LlmError.failure` 携带同一个 `LlmFailure`。调用选定适配器后,流会保留被抛出的确切 `Error` 对象,并将不可变事实以及实际服务注册所对应的不可变重试策略关联到该调用;agent loop(智能体循环)关闭失败步骤,再把错误、事实、不可变的先前已重试失败事实、实际服务策略和轮次信号提供给 `agent/request-error`。处理该错误的 listener 在其 await 的修复完成后返回 `{ kind: 'retry' }`;若未恢复,结构化失败会成为轮次错误,并且该次尝试不会提交正常 assistant 消息或工具副作用。
299
+ - **两条受支持的错误路径,共用一个 `LlmFailure` 类型。** 失败可以从 `stream()` 抛出(传输/协议错误),**或者**以 `finish {kind:'error'|'aborted', failure}` 结束流(无法在流中途抛异常的适配器用它表示提供方带内错误)。`LlmError.failure` 携带同一个 `LlmFailure`。调用选定适配器后,流会保留被抛出的确切 `Error` 对象,并将不可变事实以及实际服务注册所对应的不可变重试策略关联到该调用;agent loop(智能体循环)先把 attempt stream 提交为 `assistant/attempt`,再关闭失败步骤,并把错误、事实、不可变的先前已重试失败事实、实际服务策略和轮次信号提供给 `agent/request-error`。处理该错误的 listener 在其 await 的修复完成后返回 `{ kind: 'retry' }`;若未恢复,结构化失败会成为轮次错误,并且该次 attempt 不会提交 surface Assistant message 或工具副作用。
239
300
  - **一次适配器调用就是一次提供方尝试。** 适配器禁用库重试。agent 层恢复会打开另一个持久、带编号的轮次;直接调用 `ctx.llm.stream()` 的调用方仍然只尝试一次。
240
301
  - **提供方停顿在传输层受到时限约束。** 两个已交付的远程适配器都暴露正数且有限的 `streamIdleTimeoutMs`,默认五分钟。watchdog 只在 iterator `next()` 尚未完成时启动,整个请求使用同一个稳定 signal,把自身到期映射为 `TIMEOUT`,并把更早发生的调用方中止保留为 `ABORTED`。
241
302
  - **上下文溢出只有一个规范 code。** 两个 DeepSeek 适配器都通过 `isContextWindowExceededError()` 对提供方的显式细节分类并暴露 `CONTEXT_WINDOW_EXCEEDED`,无论失败以抛出的 HTTP `LlmError` 还是带内 finish error 到达。消费方按 code 路由,绝不依赖提供方文本。
@@ -273,7 +334,7 @@ interface AppIdentity {
273
334
 
274
335
  ## `TokenUsage`
275
336
 
276
- 逐调用 token 记账。各计数**互不重叠**:`inputTokens` 只包含未缓存输入;缓存输入单独报告,计费输入是三者之和。若提供方把缓存命中折入单一提示词总数(如 DeepSeek 的 `prompt_tokens`),适配器会再将其扣除。`reasoningTokens` 存在时只是信息性细节,已经包含在 `outputTokens` 中;汇总时不得重复相加。
337
+ 逐调用 token 记账。各计数**互不重叠**:`inputTokens` 只包含未缓存输入;缓存输入单独报告,计费输入是三者之和。若提供方把缓存命中折入单一提示词总数(如 DeepSeek 的 `prompt_tokens`),适配器会再将其扣除。可选的 `totalTokens` 是精确的提示词与输出聚合计数,由适配器保留提供方原值或从权威聚合计数重建;不可用或不一致时省略。`reasoningTokens` 存在时只是信息性细节,已经包含在 `outputTokens` 中;汇总时不得重复相加。
277
338
 
278
339
  ```ts type-equiv
279
340
  /**
@@ -287,6 +348,14 @@ interface AppIdentity {
287
348
  interface TokenUsage {
288
349
  inputTokens: number
289
350
  outputTokens: number
351
+ /**
352
+ * Exact full-call total including aggregate prompt and output tokens.
353
+ *
354
+ * Adapters preserve a provider total or derive it from authoritative
355
+ * aggregate prompt/output counters; they omit it when unavailable or
356
+ * inconsistent.
357
+ */
358
+ totalTokens?: number
290
359
  cacheReadTokens?: number
291
360
  cacheWriteTokens?: number
292
361
  reasoningTokens?: number
@@ -362,7 +431,7 @@ declare class BlockAssembler {
362
431
 
363
432
  源码:[`packages/llm/llm/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm/src/types.ts)
364
433
 
365
- 提供方与模型发现使用小型、提供方无关的描述符。模型目录仅供参考:路由仍以已注册提供方为键,适配器也可以接受未列出的模型 id。
434
+ 提供方与模型发现使用小型、提供方无关的描述符。模型目录仅供参考:路由仍以已注册提供方为键。
366
435
 
367
436
  注册适配器会返回一个句柄:既是释放器,也带有原子的路由替换——路由集合由用户配置决定的插件正需要它。
368
437
 
@@ -610,8 +679,6 @@ interface LlmModelDiscoveryRequest {
610
679
  api?: string
611
680
  /** Credential for this interrogation alone; the harness never stores it. */
612
681
  apiKey?: string
613
- /** Caller cancellation; implementations must settle promptly after it aborts. */
614
- signal?: AbortSignal
615
682
  }
616
683
  ```
617
684
 
@@ -671,6 +738,12 @@ interface LlmCallConfigAdapterDefaults {
671
738
  }
672
739
  ```
673
740
 
741
+ ## DeepSeek 官方请求扩展
742
+
743
+ `ctx.deepseekLlmApiExtensions` 是用于向 `deepseek-official` 请求添加顶层字段的提供方特定注册表。贡献插件通过 `register(field, provider)` 认领一个字段;适配器在序列化基础正文后调用 `prepare(request)`,并在 HTTP 前合并返回字段。已准备的 `accept()` 事务会在 2xx 后运行,因此贡献方可以提交交付状态,而不会把传输失败或提供方拒绝当作接受。准备、冲突与接受失败会使用 `REQUEST_EXTENSION`,并使模型请求失败。
744
+
745
+ [协议参考](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/deepseek-llm-api-wire-extensions.zh.md)定义确切的请求标头、扩展事务、字段版本和接收方义务。随附组合会将 [`dsh_session_log`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-log-deepseek/README.zh.md) 注册为无损增量权威日志后缀,并将 [`dsh_plugin_packages`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/plugin-package-inventory-deepseek/README.zh.md) 注册为完整存活 Loader 包集合。这些字段仍位于模型消息之外,也不会进入 pi-ai 适配器路径。
746
+
674
747
  ## 服务与提供方约定
675
748
 
676
749
  `LlmAdapter` 是提供方约定:创建子类、实现 `stream()`,再用 `ctx.llm.registerAdapter(providers, adapter)` 注册一个适配器实例。`GenerateOptions.provider` 选择已注册适配器;`GenerateOptions.model` 会传给该适配器,无需在生命周期启动时注册。重复提供方路由会原子失败。可选的 `providerRetryPolicy()` 会按路由捕获并填入 normal 默认值,`providerInfo()` 与异步 `listModels()` 方法则为 `LlmRuntime.listProviders()` / `listModels()` 提供分离的 selector 元数据。该目录仅供参考,不是请求白名单:适配器仍是权威,并可接受未列出的模型 id。单次异步 `resolveModel()` 查询返回确切模型身份,以及可选的对正确性敏感的上下文容量、适配器配置的 `defaultMaxTokens`、由模型持有的有序推理强度 ID 和可选的部署默认值;字段缺失表示元数据不可用或保留提供方持有的行为,而不表示目录成员关系无效。解析器会接收可选的取消信号,并且必须在信号中止后迅速完成结算。`LlmRuntime.resolveModelInfo()` 会校验聚合结果并返回分离值。在最终适配器边界,`resolveCallConfig()` 仅在 `maxTokens` 缺失时填入输出默认值,并校验和填入推理强度,因此直接调用也无法绕过任何一项已配置行为;直接分派会在等待解析前捕获一项适配器注册。agent loop 则使用 `prepareCall()`,使模型解析、请求头持久记录和分派全程使用同一项注册,保留来自同一次查询的分离上下文元数据,并报告适配器填入的配置字段。适配器查找发生在 `llm/stream` waterfall 的终端 continuation,因此 listener 可以在查找前短路调用,或路由一个可变的一次性请求。AgentLoop 在外层 waterfall 返回流句柄时观察到一次请求尝试;这个有限边界不能证明惰性终端适配器已构造完成或开始提供方 I/O。`block-start` / `block-end` 的 `index` 关联与 assembler 共同意味着适配器只需 emit 格式正确的分片——块重组不是每个适配器各自的问题。`ctx.llm.stream()` 与 `llm/stream` waterfall 在一个轮次中的位置见 [architecture.md](../index.md#turn-flow)。
@@ -719,6 +792,16 @@ declare abstract class LlmAdapter {
719
792
  * @returns a resolved policy, or `undefined` to use the normal defaults.
720
793
  */
721
794
  providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined;
795
+ /**
796
+ * Resolve provider-side request-image pricing for one exact model route.
797
+ * The default declares none, so consumers fall back to their own neutral
798
+ * estimate. Implementations must answer synchronously without I/O; the
799
+ * token meter resolves this per measurement.
800
+ * @param _provider - a route passed to `registerAdapter()` for this instance.
801
+ * @param _model - exact model id passed to {@link GenerateOptions.model}.
802
+ * @returns route-owned image pricing, or `undefined` when the route declares none.
803
+ */
804
+ imageRequestPricing(_provider: string, _model: string): LlmImageRequestPricing | undefined;
722
805
  /**
723
806
  * List models this adapter can currently advertise for one owned provider.
724
807
  * The result is advisory: an adapter may accept unlisted model ids, and
@@ -770,6 +853,33 @@ declare abstract class LlmAdapter {
770
853
 
771
854
  Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — the language sides differ only in locale-specific paired document paths. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
772
855
 
856
+ <a id="ctxdeepseekllmapiextensions--deepseekllmapiextensionregistry"></a>
857
+
858
+ ### `ctx.deepseekLlmApiExtensions` — `DeepSeekLlmApiExtensionRegistry`
859
+
860
+ Registry of independently owned top-level fields for official DeepSeek requests.
861
+
862
+ ```ts cordis-catalog
863
+ /**
864
+ * Register the sole provider of one top-level request field. Registration is effect-scoped.
865
+ * @param field - declaration-merged field owned by the provider.
866
+ * @param provider - request-time field preparation and optional acceptance behavior.
867
+ * @returns disposer that releases the field.
868
+ */
869
+ register<K extends keyof DeepSeekLlmApiExtensionMap>( field: K, provider: DeepSeekLlmApiExtensionProvider<DeepSeekLlmApiExtensionMap[K]>, ): () => Promise<void>
870
+
871
+ /**
872
+ * Prepare every currently registered field from one immutable base request.
873
+ * Preparation failures reject before HTTP dispatch. Field values are cloned and frozen;
874
+ * providers retain no mutable alias to the outgoing request.
875
+ * @param request - exact serialized request facts before extension fields.
876
+ * @returns detached fields and their idempotent joint acceptance transaction.
877
+ */
878
+ async prepare(request: DeepSeekLlmApiExtensionRequest): Promise<PreparedDeepSeekLlmApiExtensions>
879
+ ```
880
+
881
+ Source: [`packages/llm/deepseek-llm-api-extensions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/deepseek-llm-api-extensions/src/index.ts)
882
+
773
883
  <a id="ctxllm--llmruntime"></a>
774
884
 
775
885
  ### `ctx.llm` — `LlmRuntime`
@@ -791,7 +901,7 @@ registerAdapter(providers: string[], adapter: LlmAdapter): AdapterRegistrationHa
791
901
  * Describe provider routes with a registered adapter.
792
902
  * @returns detached provider metadata in registration order.
793
903
  */
794
- listProviders(): LlmProviderInfo[]
904
+ @Remote listProviders(): LlmProviderInfo[]
795
905
 
796
906
  /**
797
907
  * Declare provider routes an adapter plugin can activate through
@@ -807,7 +917,7 @@ registerConfigurableProviders(entries: readonly LlmConfigurableProvider[]): Dire
807
917
  * List every declared configurable provider, registered or dormant.
808
918
  * @returns detached directory entries in declaration order.
809
919
  */
810
- listConfigurableProviders(): LlmConfigurableProvider[]
920
+ @Remote listConfigurableProviders(): LlmConfigurableProvider[]
811
921
 
812
922
  /**
813
923
  * Offer to interrogate provider endpoints on behalf of the settings
@@ -816,10 +926,10 @@ listConfigurableProviders(): LlmConfigurableProvider[]
816
926
  * directory, and because a provider being *added* has no route to name yet.
817
927
  * Disposed with the fiber.
818
928
  * @param settingsNs - the namespace whose profiles this discovery serves.
819
- * @param discover - interrogates one endpoint; must honor `request.signal`.
929
+ * @param discover - interrogates one endpoint and must honor the supplied signal.
820
930
  * @returns the disposer that withdraws the offer.
821
931
  */
822
- registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscoveryRequest) => Promise<readonly LlmDiscoveredModel[]>, ): () => void
932
+ registerModelDiscovery( settingsNs: string, discover: ( request: LlmModelDiscoveryRequest, signal?: AbortSignal, ) => Promise<readonly LlmDiscoveredModel[]>, ): () => void
823
933
 
824
934
  /**
825
935
  * Interrogate one provider endpoint for the models it advertises. The
@@ -828,9 +938,20 @@ registerModelDiscovery( settingsNs: string, discover: (request: LlmModelDiscover
828
938
  * candidate metadata a surface may offer for adoption.
829
939
  * @param settingsNs - namespace whose registered discovery serves this draft.
830
940
  * @param request - the endpoint, protocol, and one-shot credential to use.
941
+ * @param signal - caller cancellation.
831
942
  * @returns the advertised models, deduplicated in endpoint order.
832
943
  */
833
- async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, ): Promise<LlmDiscoveredModel[]>
944
+ async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, signal?: AbortSignal, ): Promise<LlmDiscoveredModel[]>
945
+
946
+ /**
947
+ * Remote adapter for one draft provider interrogation.
948
+ * @param settingsNs - namespace whose registered discovery serves this draft.
949
+ * @param request - endpoint, protocol, and one-shot credential to use.
950
+ * @param signal - caller cancellation supplied by the Remote carrier.
951
+ * @returns advertised models in endpoint order.
952
+ * @throws RemoteError with `llm/model-discovery-rejected` when discovery refuses or fails.
953
+ */
954
+ @Remote('discoverModels') async remoteDiscoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, signal: AbortSignal, ): Promise<LlmDiscoveredModel[]>
834
955
 
835
956
  /**
836
957
  * Resolve the retry policy captured when one provider route was registered.
@@ -839,6 +960,25 @@ async discoverModels( settingsNs: string, request: LlmModelDiscoveryRequest, ):
839
960
  */
840
961
  providerRetryPolicy(provider: string): ResolvedRetryPolicy
841
962
 
963
+ /**
964
+ * Resolve provider-side request-image pricing for one exact route, or
965
+ * `undefined` when the provider is unregistered or declares none. Unknown
966
+ * providers degrade to `undefined` rather than throwing because callers
967
+ * price durable history whose route may no longer be mounted.
968
+ * @param provider - provider route named by a request header.
969
+ * @param model - exact model id named by the same header.
970
+ * @returns the owning adapter's image pricing for the route, when declared.
971
+ */
972
+ imageRequestPricing(provider: string, model: string): LlmImageRequestPricing | undefined
973
+
974
+ /**
975
+ * Resolve the exact text one durable file occurrence contributes to every
976
+ * provider request in the current execution environment.
977
+ * @param ref - durable verbatim file reference from model history.
978
+ * @returns the same deterministic handle text used at adapter dispatch.
979
+ */
980
+ fileRequestText(ref: FileAttachmentRef): string
981
+
842
982
  /**
843
983
  * Discover models advertised by one registered provider. Catalog membership
844
984
  * is advisory and never changes routing or request validation.
@@ -894,6 +1034,8 @@ async prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise<Prepared
894
1034
  stream(options: GenerateOptions): AsyncIterable<StreamChunk>
895
1035
  ```
896
1036
 
1037
+ Types: [FileAttachmentRef](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/attachment.zh.md)
1038
+
897
1039
  Source: [`packages/llm/llm/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm/src/index.ts)
898
1040
 
899
1041
  <a id="llm-events"></a>
@@ -48,7 +48,7 @@ interface Config {
48
48
 
49
49
  ## 当前预设与派生的 `custom`
50
50
 
51
- `current(events)` knob 派生实际生效的预设,而不是只看自身事件:它折叠会话的生效沙箱模式(回退到执行器配置的模式)与生效审批策略(先回退到审批服务配置,再回退到 `ask`),优先取仍然匹配的已记录选择,其次取声明顺序中第一个匹配的表项,否则返回 `CUSTOM_PRESET`(`'custom'`)。`custom` 只是派生值:客户端可以把它显示为当前值,但它绝不是切换目标,也绝不出现在事件 payload 中。
51
+ `current(session)` 从可选注册的 `permissions` 投影派生实际生效的预设。该单元折叠会话的沙箱模式、审批策略和已记录选择;状态内部的缺失值回退到执行器配置的模式与审批服务配置,最后回退到 `ask`。注册表或投影 key 缺失时会显式失败。服务优先取仍然匹配的选择,其次取声明顺序中第一个匹配的表项,否则返回 `CUSTOM_PRESET`(`'custom'`)。`custom` 只是派生值:客户端可以把它显示为当前值,但它绝不是切换目标,也绝不出现在事件 payload 中。
52
52
 
53
53
  `names` 按预设表声明顺序列出可切换的预设;`optionOf(name)` 为某个表键(label 回退为该键)或 `custom` 构建客户端渲染的选项,传入其他任何名称都会抛出异常。
54
54
 
@@ -68,7 +68,7 @@ interface PresetOption {
68
68
 
69
69
  `set(session, name)` 解析预设(未知名称抛出异常),在 `name` 尚不是生效预设时追加一条仅记日志的 `permission/preset` 事件,然后通过各旋钮自己的 setter([dsh-sandbox-policy](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/sandbox/sandbox-policy) 的 `setSandboxMode` 与 [dsh-user-approval](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-approval) 的 `setApprovalPolicy`)写入,且仅当该 knob的生效值发生变化时才写。同一轮次内,选择事件先于旋钮事件出现;重新选择当前生效的预设则什么都不追加。
70
70
 
71
- `permission/preset` 是持久、仅记日志的用户意图:它不进入模型 transcript(文本记录),模型可见的后果由 knob 事件经各自消费方承担;它存在是为了在两个预设共享同一个旋钮组合时,让 `current()` 仍能保住用户选择的究竟是哪一个预设;`effectivePermissionPreset(events)` 折叠最后一条,回放不需要任何追赶状态。完整事件声明见[持久化日志事件目录](../persistence-catalog.md);方法签名见生成的[服务目录](#ctxpermissionpresets--permissionpresetservice)。
71
+ `permission/preset` 是持久、仅记日志的用户意图:它不进入模型 transcript(文本记录),模型可见的后果由 knob 事件经各自消费方承担;它存在是为了在两个预设共享同一个旋钮组合时,让 `current()` 仍能保住用户选择的究竟是哪一个预设。`permissions` 投影把该选择与两个 knob 事件一同折叠,并保留用于区分空恢复 seed 与新会话的 `session/end-seed` 边界;回放不需要任何追赶状态或原始日志重扫。完整事件声明见[持久化日志事件目录](../persistence-catalog.md);方法签名见生成的[服务目录](#ctxpermissionpresets--permissionpresetservice)。
72
72
 
73
73
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
74
74
 
@@ -89,10 +89,10 @@ Owns the deployment's permission presets and their write path. Requires a confin
89
89
  * Resolve the preset matching the effective knob values. A still-matching
90
90
  * last selection wins shared-bundle ties; otherwise the first table match
91
91
  * wins, or {@link CUSTOM_PRESET} when no entry matches.
92
- * @param events - the session's events in log order.
92
+ * @param session - the session whose knob state is read.
93
93
  * @returns the effective preset name, or `custom` when nothing matches.
94
94
  */
95
- current(events: readonly SessionEvent[]): string
95
+ current(session: Session): string
96
96
 
97
97
  /**
98
98
  * Build the whole select value for one folded knob state: every table
@@ -128,7 +128,7 @@ optionOf(name: string): PresetOption
128
128
  set(session: Session, name: string): void
129
129
  ```
130
130
 
131
- Types: [Session](./session.md) · [SessionEvent](./session.md)
131
+ Types: [Session](./session.md)
132
132
 
133
133
  Source: [`packages/interaction/permission-presets/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/permission-presets/src/index.ts)
134
134
  <!-- END GENERATED cordis-surface -->