dsh-plugin-dev-kb 1.8.0 → 1.8.1

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 (229) hide show
  1. package/CHANGELOG.md +186 -178
  2. package/README.en.md +172 -172
  3. package/README.md +183 -183
  4. package/kb/INDEX.md +236 -234
  5. package/kb/README.md +88 -88
  6. package/kb/extra/AGENTS.md +77 -77
  7. package/kb/extra/deepseek-llm-api-wire-extensions.md +162 -162
  8. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +162 -162
  9. package/kb/extra/defensive-patterns/package-surface.md +233 -232
  10. package/kb/extra/defensive-patterns/package-surface.zh.md +233 -232
  11. package/kb/extra/defensive-patterns/remote-and-api.md +117 -117
  12. package/kb/extra/defensive-patterns/remote-and-api.zh.md +117 -117
  13. package/kb/extra/development.md +221 -221
  14. package/kb/extra/development.zh.md +228 -228
  15. package/kb/extra/event-producer-consumer.md +133 -123
  16. package/kb/extra/event-producer-consumer.zh.md +135 -125
  17. package/kb/extra/module-graph.md +1961 -1888
  18. package/kb/extra/module-graph.zh.md +1963 -1890
  19. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.md +60 -0
  20. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.zh.md +60 -0
  21. package/kb/extra/persistence-changes/README.md +92 -92
  22. package/kb/extra/persistence-changes/README.zh.md +92 -92
  23. package/kb/extra/persistence-changes/historical-formats/README.md +75 -75
  24. package/kb/extra/persistence-changes/historical-formats/README.zh.md +75 -75
  25. package/kb/extra/persistence-changes/releases/README.md +103 -103
  26. package/kb/extra/persistence-changes/releases/README.zh.md +103 -103
  27. package/kb/extra/rescope.md +55 -55
  28. package/kb/extra/rescope.zh.md +55 -55
  29. package/kb/extra/subsystems/boot.md +631 -621
  30. package/kb/extra/subsystems/boot.zh.md +631 -621
  31. package/kb/extra/subsystems/computer-use.md +179 -137
  32. package/kb/extra/subsystems/computer-use.zh.md +179 -137
  33. package/kb/extra/subsystems/extensions.md +387 -384
  34. package/kb/extra/subsystems/extensions.zh.md +387 -384
  35. package/kb/extra/subsystems/feedback.md +418 -400
  36. package/kb/extra/subsystems/feedback.zh.md +418 -400
  37. package/kb/extra/subsystems/forge.md +2169 -1226
  38. package/kb/extra/subsystems/forge.zh.md +2171 -1226
  39. package/kb/extra/subsystems/liveshare.md +167 -158
  40. package/kb/extra/subsystems/liveshare.zh.md +167 -158
  41. package/kb/extra/subsystems/mcp.md +237 -234
  42. package/kb/extra/subsystems/mcp.zh.md +237 -234
  43. package/kb/extra/subsystems/office-kit.md +122 -0
  44. package/kb/extra/subsystems/office-kit.zh.md +122 -0
  45. package/kb/extra/subsystems/working-directory.md +95 -64
  46. package/kb/extra/subsystems/working-directory.zh.md +95 -64
  47. package/kb/extra/subsystems/worktrees.md +187 -127
  48. package/kb/extra/subsystems/worktrees.zh.md +187 -127
  49. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.md +21 -21
  50. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.zh.md +21 -21
  51. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.md +18 -0
  52. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.zh.md +18 -0
  53. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.md +18 -0
  54. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.zh.md +18 -0
  55. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.md +34 -0
  56. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.zh.md +34 -0
  57. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.md +49 -0
  58. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.zh.md +49 -0
  59. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.md +36 -0
  60. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.zh.md +36 -0
  61. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.md +26 -0
  62. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.zh.md +26 -0
  63. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.md +22 -0
  64. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.zh.md +22 -0
  65. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.md +21 -0
  66. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.zh.md +21 -0
  67. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.md +23 -0
  68. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.zh.md +23 -0
  69. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.md +20 -0
  70. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.zh.md +20 -0
  71. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.md +18 -0
  72. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.zh.md +18 -0
  73. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.md +23 -0
  74. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.zh.md +23 -0
  75. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.md +35 -0
  76. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.zh.md +35 -0
  77. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.md +26 -0
  78. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.zh.md +26 -0
  79. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.md +26 -0
  80. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.zh.md +26 -0
  81. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.md +19 -0
  82. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.zh.md +19 -0
  83. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.md +26 -0
  84. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.zh.md +26 -0
  85. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.md +22 -0
  86. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.zh.md +22 -0
  87. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.md +25 -0
  88. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.zh.md +25 -0
  89. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.md +48 -0
  90. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.zh.md +48 -0
  91. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.md +45 -0
  92. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.zh.md +45 -0
  93. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.md +19 -0
  94. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.zh.md +19 -0
  95. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.md +17 -0
  96. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.zh.md +17 -0
  97. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.md +27 -0
  98. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.zh.md +27 -0
  99. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.md +20 -0
  100. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.zh.md +20 -0
  101. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.md +19 -0
  102. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.zh.md +19 -0
  103. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.md +18 -0
  104. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.zh.md +18 -0
  105. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.md +41 -0
  106. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.zh.md +41 -0
  107. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.md +21 -0
  108. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.zh.md +21 -0
  109. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.md +29 -0
  110. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.zh.md +29 -0
  111. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.md +25 -0
  112. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.zh.md +25 -0
  113. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.md +31 -0
  114. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.zh.md +31 -0
  115. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.md +24 -0
  116. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.zh.md +24 -0
  117. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.md +24 -0
  118. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.zh.md +24 -0
  119. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.md +19 -0
  120. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.zh.md +19 -0
  121. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.md +15 -0
  122. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.zh.md +15 -0
  123. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.md +28 -0
  124. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.zh.md +28 -0
  125. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.md +36 -0
  126. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.zh.md +36 -0
  127. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.md +22 -0
  128. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.zh.md +22 -0
  129. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.md +31 -0
  130. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.zh.md +31 -0
  131. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.md +18 -0
  132. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.zh.md +18 -0
  133. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.md +30 -0
  134. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.zh.md +30 -0
  135. package/kb/extra/web-styling.md +57 -57
  136. package/kb/extra/web-styling.zh.md +57 -57
  137. package/kb/meta/search-index.json +4508 -3980
  138. package/kb/meta/source.json +18 -18
  139. package/kb/site/develop/practice/llm-adapter.md +192 -192
  140. package/kb/site/en/develop/practice/llm-adapter.md +192 -192
  141. package/kb/site/en/guide/desktop-uninstall-cleanup.md +63 -0
  142. package/kb/site/en/guide/plugin-market.md +153 -151
  143. package/kb/site/en/guide/providers.md +234 -234
  144. package/kb/site/en/guide/quickstart.md +35 -34
  145. package/kb/site/en/reference/capability-seams.md +789 -767
  146. package/kb/site/en/reference/config-catalog.md +5432 -5128
  147. package/kb/site/en/reference/cookbook/adding-a-package.md +175 -175
  148. package/kb/site/en/reference/cookbook/adding-a-tool.md +105 -104
  149. package/kb/site/en/reference/cookbook/extension-cookbook.md +178 -135
  150. package/kb/site/en/reference/cordis-api/context.md +373 -369
  151. package/kb/site/en/reference/cordis-api/fiber.md +457 -433
  152. package/kb/site/en/reference/cordis-api/inherited.md +44 -44
  153. package/kb/site/en/reference/cordis-api/service.md +118 -107
  154. package/kb/site/en/reference/experimental-persistence-catalog.md +36 -23
  155. package/kb/site/en/reference/index.md +174 -174
  156. package/kb/site/en/reference/persistence-catalog.md +9453 -9432
  157. package/kb/site/en/reference/subsystems/compaction.md +288 -288
  158. package/kb/site/en/reference/subsystems/core.md +1172 -1171
  159. package/kb/site/en/reference/subsystems/credentials.md +526 -497
  160. package/kb/site/en/reference/subsystems/filesystem.md +708 -708
  161. package/kb/site/en/reference/subsystems/index.md +82 -82
  162. package/kb/site/en/reference/subsystems/llm-streaming.md +1290 -1288
  163. package/kb/site/en/reference/subsystems/lsp.md +230 -206
  164. package/kb/site/en/reference/subsystems/persistence.md +451 -432
  165. package/kb/site/en/reference/subsystems/plan.md +91 -91
  166. package/kb/site/en/reference/subsystems/ptc-runtime.md +295 -261
  167. package/kb/site/en/reference/subsystems/sandbox.md +250 -232
  168. package/kb/site/en/reference/subsystems/session-query.md +525 -515
  169. package/kb/site/en/reference/subsystems/session-reference.md +231 -229
  170. package/kb/site/en/reference/subsystems/session.md +1478 -1431
  171. package/kb/site/en/reference/subsystems/sidebar-right.md +165 -165
  172. package/kb/site/en/reference/subsystems/skills.md +356 -356
  173. package/kb/site/en/reference/subsystems/slots.md +235 -231
  174. package/kb/site/en/reference/subsystems/terminal.md +188 -188
  175. package/kb/site/en/reference/subsystems/tools.md +902 -891
  176. package/kb/site/en/reference/subsystems/user-questions.md +330 -327
  177. package/kb/site/en/reference/subsystems/web-client.md +161 -104
  178. package/kb/site/en/reference/subsystems/web-server.md +434 -351
  179. package/kb/site/en/reference/subsystems/web.md +268 -268
  180. package/kb/site/en/reference/subsystems/workflow.md +287 -282
  181. package/kb/site/en/reference/subsystems/workspace.md +743 -651
  182. package/kb/site/en/reference/tool-catalog.md +2867 -2704
  183. package/kb/site/guide/desktop-uninstall-cleanup.md +63 -0
  184. package/kb/site/guide/plugin-market.md +153 -151
  185. package/kb/site/guide/providers.md +234 -234
  186. package/kb/site/guide/quickstart.md +35 -34
  187. package/kb/site/reference/capability-seams.md +789 -767
  188. package/kb/site/reference/config-catalog.md +5432 -5128
  189. package/kb/site/reference/cookbook/adding-a-package.md +175 -175
  190. package/kb/site/reference/cookbook/adding-a-tool.md +107 -106
  191. package/kb/site/reference/cookbook/extension-cookbook.md +182 -139
  192. package/kb/site/reference/cordis-api/context.md +373 -369
  193. package/kb/site/reference/cordis-api/fiber.md +459 -435
  194. package/kb/site/reference/cordis-api/inherited.md +44 -44
  195. package/kb/site/reference/cordis-api/service.md +118 -107
  196. package/kb/site/reference/experimental-persistence-catalog.md +36 -23
  197. package/kb/site/reference/index.md +178 -178
  198. package/kb/site/reference/persistence-catalog.md +9453 -9432
  199. package/kb/site/reference/subsystems/compaction.md +288 -288
  200. package/kb/site/reference/subsystems/core.md +1184 -1183
  201. package/kb/site/reference/subsystems/credentials.md +526 -497
  202. package/kb/site/reference/subsystems/filesystem.md +708 -708
  203. package/kb/site/reference/subsystems/index.md +82 -82
  204. package/kb/site/reference/subsystems/llm-streaming.md +1296 -1294
  205. package/kb/site/reference/subsystems/lsp.md +230 -206
  206. package/kb/site/reference/subsystems/persistence.md +451 -432
  207. package/kb/site/reference/subsystems/plan.md +91 -91
  208. package/kb/site/reference/subsystems/ptc-runtime.md +295 -261
  209. package/kb/site/reference/subsystems/sandbox.md +250 -232
  210. package/kb/site/reference/subsystems/session-query.md +525 -515
  211. package/kb/site/reference/subsystems/session-reference.md +231 -229
  212. package/kb/site/reference/subsystems/session.md +1482 -1435
  213. package/kb/site/reference/subsystems/sidebar-right.md +165 -165
  214. package/kb/site/reference/subsystems/skills.md +356 -356
  215. package/kb/site/reference/subsystems/slots.md +239 -235
  216. package/kb/site/reference/subsystems/terminal.md +188 -188
  217. package/kb/site/reference/subsystems/tools.md +902 -891
  218. package/kb/site/reference/subsystems/user-questions.md +330 -327
  219. package/kb/site/reference/subsystems/web-client.md +161 -104
  220. package/kb/site/reference/subsystems/web-server.md +434 -351
  221. package/kb/site/reference/subsystems/web.md +268 -268
  222. package/kb/site/reference/subsystems/workflow.md +287 -282
  223. package/kb/site/reference/subsystems/workspace.md +743 -651
  224. package/kb/site/reference/tool-catalog.md +2872 -2709
  225. package/lib/index.js +359 -359
  226. package/package.json +68 -68
  227. package/skills/dsh-plugin-dev-kb.md +71 -70
  228. package/kb/extra/subsystems/office-to-pdf.md +0 -87
  229. package/kb/extra/subsystems/office-to-pdf.zh.md +0 -87
@@ -1,327 +1,330 @@
1
- ---
2
- editSource: "docs/subsystems/user-questions.zh.md"
3
- rawMarkdownPath: "reference/subsystems/user-questions.md"
4
- outline: [2,3]
5
- ---
6
-
7
- # 用户交互
8
-
9
- [dsh-user-questions](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-questions) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent(智能体)才能继续时所使用的、提供方无关的词汇。Agent-scoped waterfall listener 组合可用的 UI 界面,其中包括转发到已连接 client 的 listener。
10
-
11
- 源码:[`packages/interaction/user-questions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/index.ts)
12
-
13
- ## 问题选项
14
-
15
- `AskUserQuestionOption` 包含一个可供选择的选项。`label` 是面向用户的选项文字,同时也是面向模型的选中值;`description` 是可选的 UI 帮助文本。
16
-
17
- ```ts type-equiv
18
- /** One selectable answer offered to the user. */
19
- interface AskUserQuestionOption {
20
- /** User-facing label. */
21
- label: string
22
- /** Optional extra context rendered by capable UIs. */
23
- description?: string
24
- }
25
- ```
26
-
27
- ## 呈现意图
28
-
29
- `AskUserQuestionIntent` 改变呈现方式,保留选项标签和调用方的决策规则。`plan-review` 指定批准选项,并要求提供计划正文。`approval` 要求只有一个阻塞式问题,带有说明以及互不相同的拒绝、允许和可选的始终允许标签,完整对应已提供的选项,不支持多选或计时等待。CUA 前端通过现有 composer 呈现自己的固定审批;普通问答和计划审阅继续使用原有呈现。
30
-
31
- ```ts type-equiv
32
- /**
33
- * A caller-declared presentation intent: the question IS this kind of
34
- * decision, so a UI that recognises the tag may present it as such instead of as a
35
- * generic option list. Tagged so further intents can be added; a UI that does
36
- * not know a tag renders the generic flow, and the answer encoding is identical
37
- * either way — an intent changes presentation only, never the protocol.
38
- */
39
- type AskUserQuestionIntent = {
40
- /** A plan submitted for review: `detail` is the plan markdown `ask()` requires, and the decision approves or declines it. */
41
- kind: 'plan-review'
42
- /**
43
- * The option label that approves the plan; every other option declines it.
44
- * Named rather than positional so no UI infers the verdict from option order.
45
- * An `approve` naming no option of its own question is rejected at `ask()`.
46
- */
47
- approve: string
48
- /** Logged tool invocation whose arguments contain the reviewed plan. */
49
- callId?: ToolCallId
50
- } | {
51
- /** A blocking permission decision with fixed actions and no free-text answer. */
52
- kind: 'approval'
53
- /** Option label granting the scope described by the caller. */
54
- approve: string
55
- /** Option label refusing the requested access. */
56
- reject: string
57
- /** Optional persistent grant offered only when the caller supports it. */
58
- always?: string
59
- /** Metadata for human recognition; the caller admits icon sources, which the UI may load as URLs. Never an authorization identity. */
60
- subject?: { name: string; icon?: string }
61
- /** Localized question and limited-grant label; fixed cards own reject/always wording. Option labels remain answer values. */
62
- display?: {
63
- question: { en: string; [locale: string]: string }
64
- detail?: { en: string; [locale: string]: string }
65
- approve?: { en: string; [locale: string]: string }
66
- }
67
- }
68
- ```
69
-
70
- ## 问题条目
71
-
72
- `AskUserQuestionItem` 是请求中的一个问题。调用方提供稳定的 `id`,它会随答案原样返回,使批量问题仍可路由。可选的 `detail` 携带辅助文本;提供方会将其随问题渲染,但不会放入可选选项标签。
73
-
74
- ```ts type-equiv
75
- /** One question in a user-questions request. */
76
- interface AskUserQuestionItem {
77
- /** Stable caller-provided question id, echoed in the answer. */
78
- id: string
79
- /** The question to display. */
80
- question: string
81
- /** Optional supporting detail rendered with the question but kept out of option labels. */
82
- detail?: string
83
- /** Optional short heading/group label. */
84
- header?: string
85
- /** Optional choices the UI can render as a menu. */
86
- options?: AskUserQuestionOption[]
87
- /** Whether more than one option may be selected. Defaults to single-select. */
88
- multiSelect?: boolean
89
- /** Optional presentation intent for capable UIs; absent asks for the generic option list. */
90
- intent?: AskUserQuestionIntent
91
- }
92
- ```
93
-
94
- ## 提问请求
95
-
96
- `AskUserQuestionRequest` 是跨包请求。`questions` 是数组,这样 UI 可以在一个流程中呈现相关提示,同时保持每个回答有稳定的 id。如提供 `agent`,它必须与存活调用方是同一实例;只有当当前注册表将该实例识别为运行时根时,交互 seam 才会接纳该 agent。
97
-
98
- ```ts type-equiv
99
- /** Request for a human answer. */
100
- interface AskUserQuestionRequest extends AskUserQuestionRequestEvent {}
101
- ```
102
-
103
- ## 回答
104
-
105
- 提供方为每个问题 id 返回一个回答项。`selected` 包含选中的选项标签,`custom` 在用户输入自由文本时携带「其他」回答。对于单选题,`custom` 会覆盖选中的选项,且 `selected` 为空。对于多选题,`custom` 可以补充 `selected` 中的标签。UI 也可以使用 `selected` 为空且不含 `custom` 的回答项,在其余问题均已完成的批次中保留被跳过的问题。
106
-
107
- ```ts type-equiv
108
- /** Answer to one question. */
109
- interface AskUserQuestionAnswerItem {
110
- /** The answered question id. */
111
- id: string
112
- /** Selected option labels. May accompany custom text for a multi-select question. */
113
- selected: string[]
114
- /** Optional free-text "Other" answer. */
115
- custom?: string
116
- }
117
- ```
118
-
119
- ```ts type-equiv
120
- /** The human's answer. */
121
- interface AskUserQuestionAnswer {
122
- /** Structured answers keyed by question id. */
123
- answers: AskUserQuestionAnswerItem[]
124
- }
125
- ```
126
-
127
- 计时回答器收到 `wait: { callId, timed: true }`。调用 id 标识卡片及前台等待。Client 调用 `attachWait` 接手等待并取得剩余时长;传输层转发原事件,不检查或改写这些字段。不带 `timed` 的 `wait` 表示无限期等待的具名卡片请求;没有 `wait` 则表示不带卡片 key 的阻塞请求。
128
-
129
- ```ts type-equiv
130
- /** Client-safe payload declared for the user-question answerer waterfall. */
131
- interface AskUserQuestionRequestEvent {
132
- /** Questions to display. */
133
- questions: AskUserQuestionItem[]
134
- /** Agent identity projected to the corresponding Client Context in transit. */
135
- agent?: Agent
136
- /** Cancellation lifetime of the pending request. */
137
- signal?: AbortSignal
138
- /**
139
- * Tool call the Client card is keyed by. Timed answerers attach to the
140
- * business wait stream before starting their local countdown.
141
- */
142
- wait?: {
143
- /** Tool call the Client card is keyed by. */
144
- callId: ToolCallId
145
- /** True for a foreground wait that requires a Client claim; absent for indefinite waits. */
146
- timed?: boolean
147
- }
148
- }
149
- ```
150
-
151
- ## 计时问题与迟到回复
152
-
153
- 计时问题在有界的前台窗口内等待,然后让 agent 继续独立工作。用户在窗口内回答,工具返回整批答案;否则 `TimedUserQuestionResult` 为 `{ pending: true, callId }`。pending 表示问题仍可回答,不是空答案、拒绝、确认或授权。
154
-
155
- ```ts type-equiv
156
- /** Timed ask result returned when the foreground answer window closes. */
157
- type TimedUserQuestionResult = AskUserQuestionAnswer | { pending: true; callId: ToolCallId }
158
- ```
159
-
160
- Client 接手通过业务 Remote stream 表达,不等同于 Gateway 投递。`TimedQuestionWait` 保存原 Host deadline,仅在没有接手记录时运行计时器。`attachWait` stream 发出当前剩余时长,Client 用本地时钟倒计时。聚焦、编辑和「慢慢回答」状态仍归本地所有。stream 取消释放相应接手记录;最后一个接手方离开后,Host 恢复原 deadline。无人接手时超时中止前台 waterfall 专属的 signal 并返回 pending,不取消 Turn。Gateway 与 `api-remotes` 不包含问答专属计时策略。
161
-
162
- `userQuestions` Session 投影把现有事件折叠成可回答的问题集合与已结算的集合;不记录任何等待状态、聚焦状态或 deadline。每个 `request/header` 都记录了模型看到的确切工具 schema。只有请求头声明了带 `timeout` 参数的 timed `ask_user_question` schema,投影才跟踪原生调用;阻塞式 legacy 工具从不声明它。原生 `tool/call` 打开一个问题。`tool/result` 只在两种情况下把它标为 `continued`:带 pending 载荷,或是 Session resume 修复补写的 `TOOL_OUTCOME_UNKNOWN` 合成结果;回答批次把它连同该批次移入 `settled`,其他结果或失败都丢弃它。`run_code` 的 PTC 子调用若在 `tool/ptc-dispatch` 结果中返回 pending,也会进入投影,尽管请求头只列出 `run_code`。迟到回复在消息获准成为 `user/message` 时,才把已继续的问题连同消息中的回答批次移入 `settled`:计时调用自己的结果记录的是超时,transcript 行无处可读用户最终的选择。排队的回复可在准入前取消,此时问题仍可回答。回复正文不含可读批次时,该调用以零答案结算;回复指向的调用已不在可回答集合中时不改变任何内容。
163
-
164
- ```ts type-equiv
165
- /** `open` while the tool call may still return the answer; `continued` once the answer can only arrive as a new turn. */
166
- type UserQuestionState = 'open' | 'continued'
167
- ```
168
-
169
- ```ts type-equiv
170
- /** One unanswered timed `ask_user_question` call reconstructed from the Session log. */
171
- interface PendingUserQuestion {
172
- readonly callId: ToolCallId
173
- readonly questions: readonly AskUserQuestionItem[]
174
- readonly state: UserQuestionState
175
- }
176
- ```
177
-
178
- ```ts type-equiv
179
- /**
180
- * One timed `ask_user_question` call and the answers it settled with: the
181
- * batch its own result carried when the user answered inside the window,
182
- * otherwise the batch its late reply carried, because that call's own result
183
- * recorded the timeout. A transcript row reads what the user finally answered
184
- * from here, and only a call listed here was a timed one.
185
- */
186
- interface SettledUserQuestion {
187
- /** The settled call. */
188
- readonly callId: ToolCallId
189
- /** The recorded batch, one entry per question; empty when the late reply carried none. */
190
- readonly answers: readonly AskUserQuestionAnswerItem[]
191
- }
192
- ```
193
-
194
- ```ts type-equiv
195
- /**
196
- * Both halves of one Session's timed `ask_user_question` state, as every
197
- * Client reads them. A call made while the blocking legacy tool was in
198
- * effect appears in neither half.
199
- */
200
- interface UserQuestionProjectionView {
201
- /** Calls that can still take an answer, in ask order. */
202
- readonly active: readonly PendingUserQuestion[]
203
- /** Calls an answer settled, in settlement order. */
204
- readonly settled: readonly SettledUserQuestion[]
205
- }
206
- ```
207
-
208
- 开放中的问题只能通过 waterfall 回答。问题变为 `continued` 后,`answer` Remote 方法向所属 agent 排入一条用户消息,并在其空闲时唤醒它。消息的 source 为 `user-question-reply`,outcome 为 `answered`,正文是 `answer_to_pending_question` 载荷。开放或未知调用返回 `false`;回复仍在排队时的第二次提交以 `REPLY_QUEUED` 拒绝,Host 重启后也一样;遗漏或重复问题的回答批次以 `BAD_ANSWER` 拒绝。
209
-
210
- 收起 Client 面板不会发送内容。前台超时只结束工具等待。已继续的问题没有期限;在回复进入会话前,问题仍可回答。
211
-
212
- Host 重启后,Session 重开时 Remote 层会恢复根 agent。之后的迟到回复会作为新一轮进入。
213
-
214
- ## 错误
215
-
216
- `UserQuestionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会保留 `{ name, code }`,用于面向模型的工具失败,如 `EMPTY_QUESTIONS`、`BAD_INTENT`、`NO_PROVIDER`、`ASK_ABORTED` 或 UI 侧取消。
217
-
218
- ```ts type-equiv
219
- /** Stable error taxonomy for user-questions failures. */
220
- class UserQuestionError extends HarnessError {
221
- constructor(message: string, code: string, options?: ErrorOptions) {
222
- super(message, code, options)
223
- this.name = 'UserQuestionError'
224
- }
225
- }
226
- ```
227
-
228
- <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
229
-
230
- <a id="cordis-surface"></a>
231
-
232
- ## Cordis API
233
-
234
- 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).
235
-
236
- <a id="ctxuserquestions--userquestionservice"></a>
237
-
238
- ### `ctx.userQuestions` — `UserQuestionService`
239
-
240
- `ctx.userQuestions`: validation plus the scoped answerer waterfall.
241
-
242
- ```ts cordis-catalog
243
- /**
244
- * Answer a continued question. The reply is steered into the agent as a
245
- * user message whose source names the call; that message is also the
246
- * record that closes the question in the projection.
247
- * @param agent - Live root agent for the owning Session.
248
- * @param callId - Continued question identity.
249
- * @param answer - Complete structured answer batch, one item per question of the call.
250
- * @returns Whether the question is still continued; an accepted reply stays
251
- * queued until the agent admits its user message.
252
- * @throws {UserQuestionError} `BAD_ANSWER` when the batch does not name each
253
- * question of the call exactly once, or `REPLY_QUEUED` when a reply is
254
- * already waiting for admission.
255
- */
256
- @Remote answer(agent: Agent, callId: ToolCallId, answer: AskUserQuestionAnswer): boolean
257
-
258
- /**
259
- * Let one answer UI hold a live timed wait. Closing the stream releases its claim.
260
- * @param agent - Live root agent owning the question.
261
- * @param callId - Foreground tool call to attach to.
262
- * @param signal - Remote stream cancellation, including Client disconnect.
263
- * @returns One Host-computed remaining duration, or no frames once the wait ended.
264
- */
265
- @Remote({ mode: 'stream' }) async *attachWait(agent: Agent, callId: ToolCallId, signal: AbortSignal): AsyncIterable<{ remainingMs: number }>
266
-
267
- /**
268
- * Foreground wait whose first settlement the Client decides: the Client
269
- * rejects with `ASK_TIMED_OUT` when its countdown ends, and this method maps
270
- * that code to the pending result.
271
- * @param request - Questions, live owner agent, and abort signal.
272
- * @param callId - Tool call identity the Client card is keyed by.
273
- * @param timeoutMs - Positive foreground wait in milliseconds.
274
- * @returns The answer when it arrives inside the window, otherwise a pending
275
- * result, also when no connected Client claimed the request by the deadline.
276
- * @throws {UserQuestionError} `BAD_TIMEOUT` for a non-integer, non-positive,
277
- * or oversized wait.
278
- */
279
- async askTimed( request: AskUserQuestionRequest & { agent: Agent }, callId: ToolCallId, timeoutMs: number, ): Promise<TimedUserQuestionResult>
280
-
281
- /**
282
- * Ask the scoped answerer waterfall and wait for the user's answer.
283
- *
284
- * When a caller supplies an agent, human interaction is valid only for the
285
- * exact live instance of an ordinary Session. Explicit subagent origin
286
- * rejects delegated callers; historical ordinary forks may retain parent
287
- * metadata and still ask normally.
288
- *
289
- * @param request Questions, owner agent, and abort signal.
290
- * @returns The answer chosen or typed by the human.
291
- * @throws {UserQuestionError} code `ASK_ABORTED` when the supplied signal
292
- * is already or becomes aborted, `CALLER_NOT_LIVE` when a supplied agent
293
- * is not the registry's exact live instance, or `DELEGATED_CALLER` when
294
- * that live agent has subagent origin.
295
- */
296
- async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
297
- ```
298
-
299
- Types: [Agent](./core.md) · [ToolCallId](./core.md)
300
-
301
- Source: [`packages/interaction/user-questions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/index.ts)
302
-
303
- <a id="user-questions-events"></a>
304
-
305
- ### `user-questions/*` events
306
-
307
- <a id="user-questionsrequest--waterfall"></a>
308
-
309
- #### `user-questions/request` — waterfall
310
-
311
- Ask composed answerers for structured user input. Return an answer to claim the request or call `next()` to delegate. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
312
-
313
- ```ts cordis-catalog
314
- /**
315
- * Ask composed answerers for structured user input. Return an answer to
316
- * claim the request or call `next()` to delegate. Scope-filtered dispatch
317
- * (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
318
- * @param request - pending user-question request.
319
- * @mode waterfall
320
- */
321
- 'user-questions/request'( this: Scoped<Agent>, request: AskUserQuestionRequestEvent, next: () => Promise<AskUserQuestionAnswer>, ): Promise<AskUserQuestionAnswer>
322
- ```
323
-
324
- Types: [Agent](./core.md) · [Scoped](./scope.md)
325
-
326
- Source: [`packages/interaction/user-questions/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/types.ts)
327
- <!-- END GENERATED cordis-surface -->
1
+ ---
2
+ editSource: "docs/subsystems/user-questions.zh.md"
3
+ rawMarkdownPath: "reference/subsystems/user-questions.md"
4
+ outline: [2,3]
5
+ ---
6
+
7
+ # 用户交互
8
+
9
+ [dsh-user-questions](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-questions) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent(智能体)才能继续时所使用的、提供方无关的词汇。Agent-scoped waterfall listener 组合可用的 UI 界面,其中包括转发到已连接 client 的 listener。
10
+
11
+ 源码:[`packages/interaction/user-questions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/index.ts)
12
+
13
+ ## 问题选项
14
+
15
+ `AskUserQuestionOption` 包含一个可供选择的选项。`label` 是面向用户的选项文字,同时也是面向模型的选中值;`description` 是可选的 UI 帮助文本。
16
+
17
+ ```ts type-equiv
18
+ /** One selectable answer offered to the user. */
19
+ interface AskUserQuestionOption {
20
+ /** User-facing label. */
21
+ label: string
22
+ /** Optional extra context rendered by capable UIs. */
23
+ description?: string
24
+ }
25
+ ```
26
+
27
+ ## 呈现意图
28
+
29
+ `AskUserQuestionIntent` 改变呈现方式,保留选项标签和调用方的决策规则。`plan-review` 指定批准选项,并要求提供计划正文。`approval` 要求只有一个阻塞式问题,带有说明以及互不相同的拒绝、允许和可选的始终允许标签,完整对应已提供的选项,不支持多选或计时等待。CUA 前端通过现有 composer 呈现自己的固定审批;普通问答和计划审阅继续使用原有呈现。
30
+
31
+ ```ts type-equiv
32
+ /**
33
+ * A caller-declared presentation intent: the question IS this kind of
34
+ * decision, so a UI that recognises the tag may present it as such instead of as a
35
+ * generic option list. Tagged so further intents can be added; a UI that does
36
+ * not know a tag renders the generic flow, and the answer encoding is identical
37
+ * either way — an intent changes presentation only, never the protocol.
38
+ */
39
+ type AskUserQuestionIntent = {
40
+ /** A plan submitted for review: `detail` is the plan markdown `ask()` requires, and the decision approves or declines it. */
41
+ kind: 'plan-review'
42
+ /**
43
+ * The option label that approves the plan; every other option declines it.
44
+ * Named rather than positional so no UI infers the verdict from option order.
45
+ * An `approve` naming no option of its own question is rejected at `ask()`.
46
+ */
47
+ approve: string
48
+ /** Logged tool invocation whose arguments contain the reviewed plan. */
49
+ callId?: ToolCallId
50
+ } | {
51
+ /** A blocking permission decision with fixed actions and no free-text answer. */
52
+ kind: 'approval'
53
+ /** Option label granting the scope described by the caller. */
54
+ approve: string
55
+ /** Option label refusing the requested access. */
56
+ reject: string
57
+ /** Optional persistent grant offered only when the caller supports it. */
58
+ always?: string
59
+ /** Metadata for human recognition; the caller admits icon sources, which the UI may load as URLs. Never an authorization identity. */
60
+ subject?: { name: string; icon?: string }
61
+ /** Localized question and limited-grant label; fixed cards own reject/always wording. Option labels remain answer values. */
62
+ display?: {
63
+ question: { en: string; [locale: string]: string }
64
+ detail?: { en: string; [locale: string]: string }
65
+ approve?: { en: string; [locale: string]: string }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## 问题条目
71
+
72
+ `AskUserQuestionItem` 是请求中的一个问题。调用方提供稳定的 `id`,它会随答案原样返回,使批量问题仍可路由。可选的 `detail` 携带辅助文本;提供方会将其随问题渲染,但不会放入可选选项标签。
73
+
74
+ ```ts type-equiv
75
+ /** One question in a user-questions request. */
76
+ interface AskUserQuestionItem {
77
+ /** Stable caller-provided question id, echoed in the answer. */
78
+ id: string
79
+ /** The question to display. */
80
+ question: string
81
+ /** Optional supporting detail rendered with the question but kept out of option labels. */
82
+ detail?: string
83
+ /** Optional short heading/group label. */
84
+ header?: string
85
+ /** Optional choices the UI can render as a menu. */
86
+ options?: AskUserQuestionOption[]
87
+ /** Whether more than one option may be selected. Defaults to single-select. */
88
+ multiSelect?: boolean
89
+ /** Optional presentation intent for capable UIs; absent asks for the generic option list. */
90
+ intent?: AskUserQuestionIntent
91
+ }
92
+ ```
93
+
94
+ ## 提问请求
95
+
96
+ `AskUserQuestionRequest` 是跨包请求。`questions` 是数组,这样 UI 可以在一个流程中呈现相关提示,同时保持每个回答有稳定的 id。如提供 `agent`,它必须与存活调用方是同一实例;只有当当前注册表将该实例识别为运行时根时,交互 seam 才会接纳该 agent。
97
+
98
+ ```ts type-equiv
99
+ /** Request for a human answer. */
100
+ interface AskUserQuestionRequest extends AskUserQuestionRequestEvent {}
101
+ ```
102
+
103
+ ## 回答
104
+
105
+ 提供方为每个问题 id 返回一个回答项。`selected` 包含选中的选项标签,`custom` 在用户输入自由文本时携带「其他」回答。对于单选题,`custom` 会覆盖选中的选项,且 `selected` 为空。对于多选题,`custom` 可以补充 `selected` 中的标签。UI 也可以使用 `selected` 为空且不含 `custom` 的回答项,在其余问题均已完成的批次中保留被跳过的问题。
106
+
107
+ ```ts type-equiv
108
+ /** Answer to one question. */
109
+ interface AskUserQuestionAnswerItem {
110
+ /** The answered question id. */
111
+ id: string
112
+ /** Selected option labels. May accompany custom text for a multi-select question. */
113
+ selected: string[]
114
+ /** Optional free-text "Other" answer. */
115
+ custom?: string
116
+ }
117
+ ```
118
+
119
+ ```ts type-equiv
120
+ /** The human's answer. */
121
+ interface AskUserQuestionAnswer {
122
+ /** Structured answers keyed by question id. */
123
+ answers: AskUserQuestionAnswerItem[]
124
+ }
125
+ ```
126
+
127
+ 计时回答器收到 `wait: { callId, timed: true }`。调用 id 标识卡片及前台等待。Client 调用 `attachWait` 接手等待并取得剩余时长;传输层转发原事件,不检查或改写这些字段。不带 `timed` 的 `wait` 表示无限期等待的具名卡片请求;没有 `wait` 则表示不带卡片 key 的阻塞请求。
128
+
129
+ ```ts type-equiv
130
+ /** Client-safe payload declared for the user-question answerer waterfall. */
131
+ interface AskUserQuestionRequestEvent {
132
+ /** Questions to display. */
133
+ questions: AskUserQuestionItem[]
134
+ /** Agent identity projected to the corresponding Client Context in transit. */
135
+ agent?: Agent
136
+ /** Cancellation lifetime of the pending request. */
137
+ signal?: AbortSignal
138
+ /**
139
+ * Tool call the Client card is keyed by. Timed answerers attach to the
140
+ * business wait stream before starting their local countdown.
141
+ */
142
+ wait?: {
143
+ /** Tool call the Client card is keyed by. */
144
+ callId: ToolCallId
145
+ /** True for a foreground wait that requires a Client claim; absent for indefinite waits. */
146
+ timed?: boolean
147
+ }
148
+ }
149
+ ```
150
+
151
+ ## 计时问题与迟到回复
152
+
153
+ 计时问题在有界的前台窗口内等待,然后让 agent 继续独立工作。用户在窗口内回答,工具返回整批答案;否则 `TimedUserQuestionResult` 为 `{ pending: true, callId }`。pending 表示问题仍可回答,不是空答案、拒绝、确认或授权。
154
+
155
+ ```ts type-equiv
156
+ /** Timed ask result returned when the foreground answer window closes. */
157
+ type TimedUserQuestionResult = AskUserQuestionAnswer | { pending: true; callId: ToolCallId }
158
+ ```
159
+
160
+ Client 接手通过业务 Remote stream 表达,不等同于 Gateway 投递。`TimedQuestionWait` 保存原 Host deadline,仅在没有接手记录时运行计时器。`attachWait` stream 发出当前剩余时长,Client 用本地时钟倒计时。聚焦、编辑和「慢慢回答」状态仍归本地所有。stream 取消释放相应接手记录;最后一个接手方离开后,Host 恢复原 deadline。无人接手时超时中止前台 waterfall 专属的 signal 并返回 pending,不取消 Turn。Gateway 与 `api-remotes` 不包含问答专属计时策略。
161
+
162
+ `userQuestions` Session 投影把现有事件折叠成可回答的问题集合与已结算的集合;不记录任何等待状态、聚焦状态或 deadline。每个 `request/header` 都记录了模型看到的确切工具 schema。只有请求头声明了带 `timeout` 参数的 timed `ask_user_question` schema,投影才跟踪原生调用;阻塞式 legacy 工具从不声明它。原生 `tool/call` 打开一个问题。`tool/result` 只在两种情况下把它标为 `continued`:带 pending 载荷,或是 Session resume 修复补写的 `TOOL_OUTCOME_UNKNOWN` 合成结果;回答批次把它连同该批次移入 `settled`,其他结果或失败都丢弃它。`run_code` 的 PTC 子调用若在 `tool/ptc-dispatch` 结果中返回 pending,也会进入投影,尽管请求头只列出 `run_code`。迟到回复在消息获准成为 `user/message` 时,才把已继续的问题连同消息中的回答批次移入 `settled`:计时调用自己的结果记录的是超时,transcript 行无处可读用户最终的选择。排队的回复可在准入前取消,此时问题仍可回答。回复正文不含可读批次时,该调用以零答案结算;回复指向的调用已不在可回答集合中时不改变任何内容。
163
+
164
+ ```ts type-equiv
165
+ /** `open` while the tool call may still return the answer; `continued` once the answer can only arrive as a new turn. */
166
+ type UserQuestionState = 'open' | 'continued'
167
+ ```
168
+
169
+ ```ts type-equiv
170
+ /** One unanswered timed `ask_user_question` call reconstructed from the Session log. */
171
+ interface PendingUserQuestion {
172
+ readonly callId: ToolCallId
173
+ readonly questions: readonly AskUserQuestionItem[]
174
+ readonly state: UserQuestionState
175
+ }
176
+ ```
177
+
178
+ ```ts type-equiv
179
+ /**
180
+ * One timed `ask_user_question` call and the answers it settled with: the
181
+ * batch its own result carried when the user answered inside the window,
182
+ * otherwise the batch its late reply carried, because that call's own result
183
+ * recorded the timeout. A transcript row reads what the user finally answered
184
+ * from here, and only a call listed here was a timed one.
185
+ */
186
+ interface SettledUserQuestion {
187
+ /** The settled call. */
188
+ readonly callId: ToolCallId
189
+ /** The recorded batch, one entry per question; empty when the late reply carried none. */
190
+ readonly answers: readonly AskUserQuestionAnswerItem[]
191
+ }
192
+ ```
193
+
194
+ ```ts type-equiv
195
+ /**
196
+ * Both halves of one Session's timed `ask_user_question` state, as every
197
+ * Client reads them. A call made while the blocking legacy tool was in
198
+ * effect appears in neither half.
199
+ */
200
+ interface UserQuestionProjectionView {
201
+ /** Calls that can still take an answer, in ask order. */
202
+ readonly active: readonly PendingUserQuestion[]
203
+ /** Calls an answer settled, in settlement order. */
204
+ readonly settled: readonly SettledUserQuestion[]
205
+ }
206
+ ```
207
+
208
+ 开放中的问题只能通过 waterfall 回答。问题变为 `continued` 后,`answer` Remote 方法向所属 agent 排入一条用户消息,并在其空闲时唤醒它。消息的 source 为 `user-question-reply`,outcome 为 `answered`,正文是 `answer_to_pending_question` 载荷。开放或未知调用返回 `false`;回复仍在排队时的第二次提交以 `REPLY_QUEUED` 拒绝,Host 重启后也一样;遗漏或重复问题的回答批次以 `BAD_ANSWER` 拒绝。
209
+
210
+ 收起 Client 面板不会发送内容。前台超时只结束工具等待。已继续的问题没有期限;在回复进入会话前,问题仍可回答。
211
+
212
+ Host 重启后,Session 重开时 Remote 层会恢复根 agent。之后的迟到回复会作为新一轮进入。
213
+
214
+ ## 错误
215
+
216
+ `UserQuestionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会保留 `{ name, code }`,用于面向模型的工具失败,如 `EMPTY_QUESTIONS`、`BAD_INTENT`、`NO_PROVIDER`、`ASK_ABORTED` 或 UI 侧取消。不是 `HarnessError` 的应答方失败会变为 `PROVIDER_ERROR`,保留原 message,原错误作为 `cause`;其他 `HarnessError` 保留自身的 `name` 与 `code`。
217
+
218
+ ```ts type-equiv
219
+ /** Stable error taxonomy for user-questions failures. */
220
+ class UserQuestionError extends HarnessError {
221
+ constructor(message: string, code: string, options?: ErrorOptions) {
222
+ super(message, code, options)
223
+ this.name = 'UserQuestionError'
224
+ }
225
+ }
226
+ ```
227
+
228
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
229
+
230
+ <a id="cordis-surface"></a>
231
+
232
+ ## Cordis API
233
+
234
+ 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).
235
+
236
+ <a id="ctxuserquestions--userquestionservice"></a>
237
+
238
+ ### `ctx.userQuestions` — `UserQuestionService`
239
+
240
+ `ctx.userQuestions`: validation plus the scoped answerer waterfall.
241
+
242
+ ```ts cordis-catalog
243
+ /**
244
+ * Answer a continued question. The reply is steered into the agent as a
245
+ * user message whose source names the call; that message is also the
246
+ * record that closes the question in the projection.
247
+ * @param agent - Live root agent for the owning Session.
248
+ * @param callId - Continued question identity.
249
+ * @param answer - Complete structured answer batch, one item per question of the call.
250
+ * @returns Whether the question is still continued; an accepted reply stays
251
+ * queued until the agent admits its user message.
252
+ * @throws {UserQuestionError} `BAD_ANSWER` when the batch does not name each
253
+ * question of the call exactly once, or `REPLY_QUEUED` when a reply is
254
+ * already waiting for admission.
255
+ */
256
+ @Remote answer(agent: Agent, callId: ToolCallId, answer: AskUserQuestionAnswer): boolean
257
+
258
+ /**
259
+ * Let one answer UI hold a live timed wait. Closing the stream releases its claim.
260
+ * @param agent - Live root agent owning the question.
261
+ * @param callId - Foreground tool call to attach to.
262
+ * @param signal - Remote stream cancellation, including Client disconnect.
263
+ * @returns One Host-computed remaining duration, or no frames once the wait ended.
264
+ */
265
+ @Remote({ mode: 'stream' }) async *attachWait(agent: Agent, callId: ToolCallId, signal: AbortSignal): AsyncIterable<{ remainingMs: number }>
266
+
267
+ /**
268
+ * Foreground wait whose first settlement the Client decides: the Client
269
+ * rejects with `ASK_TIMED_OUT` when its countdown ends, and this method maps
270
+ * that code to the pending result.
271
+ * @param request - Questions, live owner agent, and abort signal.
272
+ * @param callId - Tool call identity the Client card is keyed by.
273
+ * @param timeoutMs - Positive foreground wait in milliseconds.
274
+ * @returns The answer when it arrives inside the window, otherwise a pending
275
+ * result, also when no connected Client claimed the request by the deadline.
276
+ * @throws {UserQuestionError} `BAD_TIMEOUT` for a non-integer, non-positive,
277
+ * or oversized wait.
278
+ */
279
+ async askTimed( request: AskUserQuestionRequest & { agent: Agent }, callId: ToolCallId, timeoutMs: number, ): Promise<TimedUserQuestionResult>
280
+
281
+ /**
282
+ * Ask the scoped answerer waterfall and wait for the user's answer.
283
+ *
284
+ * When a caller supplies an agent, human interaction is valid only for the
285
+ * exact live instance of an ordinary Session. Explicit subagent origin
286
+ * rejects delegated callers; historical ordinary forks may retain parent
287
+ * metadata and still ask normally.
288
+ *
289
+ * @param request Questions, owner agent, and abort signal.
290
+ * @returns The answer chosen or typed by the human.
291
+ * @throws {UserQuestionError} code `ASK_ABORTED` when the supplied signal
292
+ * is already or becomes aborted, `CALLER_NOT_LIVE` when a supplied agent
293
+ * is not the registry's exact live instance, `DELEGATED_CALLER` when
294
+ * that live agent has subagent origin, or `PROVIDER_ERROR`, keeping the
295
+ * original message, when an answerer fails with a value that is not a
296
+ * `HarnessError`; a coded `HarnessError` from an answerer keeps its `name`
297
+ * and `code`.
298
+ */
299
+ async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
300
+ ```
301
+
302
+ Types: [Agent](./core.md) · [ToolCallId](./core.md)
303
+
304
+ Source: [`packages/interaction/user-questions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/index.ts)
305
+
306
+ <a id="user-questions-events"></a>
307
+
308
+ ### `user-questions/*` events
309
+
310
+ <a id="user-questionsrequest--waterfall"></a>
311
+
312
+ #### `user-questions/request` — waterfall
313
+
314
+ Ask composed answerers for structured user input. Return an answer to claim the request or call `next()` to delegate. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
315
+
316
+ ```ts cordis-catalog
317
+ /**
318
+ * Ask composed answerers for structured user input. Return an answer to
319
+ * claim the request or call `next()` to delegate. Scope-filtered dispatch
320
+ * (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
321
+ * @param request - pending user-question request.
322
+ * @mode waterfall
323
+ */
324
+ 'user-questions/request'( this: Scoped<Agent>, request: AskUserQuestionRequestEvent, next: () => Promise<AskUserQuestionAnswer>, ): Promise<AskUserQuestionAnswer>
325
+ ```
326
+
327
+ Types: [Agent](./core.md) · [Scoped](./scope.md)
328
+
329
+ Source: [`packages/interaction/user-questions/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/types.ts)
330
+ <!-- END GENERATED cordis-surface -->