dsh-plugin-dev-kb 1.6.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 (622) hide show
  1. package/CHANGELOG.md +186 -141
  2. package/README.en.md +172 -155
  3. package/README.md +183 -163
  4. package/kb/INDEX.md +236 -234
  5. package/kb/README.md +88 -83
  6. package/kb/extra/AGENTS.md +77 -77
  7. package/kb/extra/cli-help.md +15 -7
  8. package/kb/extra/cli-help.zh.md +15 -7
  9. package/kb/extra/cookbook/adding-a-plugin-preview.md +18 -25
  10. package/kb/extra/cookbook/adding-a-plugin-preview.zh.md +18 -25
  11. package/kb/extra/cookbook/reviewing-persistence-type-changes.md +1 -1
  12. package/kb/extra/cookbook/reviewing-persistence-type-changes.zh.md +1 -1
  13. package/kb/extra/cookbook/reviewing-ui-design.md +166 -0
  14. package/kb/extra/cookbook/reviewing-ui-design.zh.md +166 -0
  15. package/kb/extra/deepseek-llm-api-wire-extensions.md +162 -162
  16. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +162 -162
  17. package/kb/extra/defensive-patterns/conversation-and-session.md +2 -2
  18. package/kb/extra/defensive-patterns/conversation-and-session.zh.md +2 -2
  19. package/kb/extra/defensive-patterns/general.md +2 -0
  20. package/kb/extra/defensive-patterns/general.zh.md +2 -0
  21. package/kb/extra/defensive-patterns/package-surface.md +233 -231
  22. package/kb/extra/defensive-patterns/package-surface.zh.md +233 -231
  23. package/kb/extra/defensive-patterns/remote-and-api.md +117 -115
  24. package/kb/extra/defensive-patterns/remote-and-api.zh.md +117 -115
  25. package/kb/extra/development.md +221 -214
  26. package/kb/extra/development.zh.md +228 -221
  27. package/kb/extra/event-producer-consumer.md +133 -110
  28. package/kb/extra/event-producer-consumer.zh.md +135 -112
  29. package/kb/extra/i18n/README.md +2 -0
  30. package/kb/extra/i18n/README.zh.md +2 -0
  31. package/kb/extra/module-graph.md +1961 -1776
  32. package/kb/extra/module-graph.zh.md +1963 -1778
  33. package/kb/extra/persistence-changes/2026-10-13-liveshare-share-viewer-principal.md +60 -0
  34. package/kb/extra/persistence-changes/2026-10-13-liveshare-share-viewer-principal.zh.md +60 -0
  35. package/kb/extra/persistence-changes/2026-10-19-session-team-mode.md +48 -0
  36. package/kb/extra/persistence-changes/2026-10-19-session-team-mode.zh.md +48 -0
  37. package/kb/extra/persistence-changes/2026-10-22-action-card-status.md +60 -0
  38. package/kb/extra/persistence-changes/2026-10-22-action-card-status.zh.md +60 -0
  39. package/kb/extra/persistence-changes/2026-10-25-skill-catalog-incomplete.md +60 -0
  40. package/kb/extra/persistence-changes/2026-10-25-skill-catalog-incomplete.zh.md +60 -0
  41. package/kb/extra/persistence-changes/2026-10-27-retry-control-input.md +60 -0
  42. package/kb/extra/persistence-changes/2026-10-27-retry-control-input.zh.md +60 -0
  43. package/kb/extra/persistence-changes/2026-10-27-subagent-settlement-attribution.md +60 -0
  44. package/kb/extra/persistence-changes/2026-10-27-subagent-settlement-attribution.zh.md +60 -0
  45. package/kb/extra/persistence-changes/2026-11-02-subagent-catalog-names.md +48 -0
  46. package/kb/extra/persistence-changes/2026-11-02-subagent-catalog-names.zh.md +48 -0
  47. package/kb/extra/persistence-changes/2026-11-02-team-task-owner-names.md +48 -0
  48. package/kb/extra/persistence-changes/2026-11-02-team-task-owner-names.zh.md +48 -0
  49. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.md +60 -0
  50. package/kb/extra/persistence-changes/2026-11-05-timeline-priority-notice.zh.md +60 -0
  51. package/kb/extra/persistence-changes/README.md +92 -90
  52. package/kb/extra/persistence-changes/README.zh.md +92 -90
  53. package/kb/extra/persistence-changes/historical-formats/README.md +75 -75
  54. package/kb/extra/persistence-changes/historical-formats/README.zh.md +75 -75
  55. package/kb/extra/persistence-changes/releases/README.md +103 -103
  56. package/kb/extra/persistence-changes/releases/README.zh.md +103 -103
  57. package/kb/extra/rescope.md +55 -53
  58. package/kb/extra/rescope.zh.md +55 -53
  59. package/kb/extra/subsystems/agent-team.md +38 -75
  60. package/kb/extra/subsystems/agent-team.zh.md +38 -75
  61. package/kb/extra/subsystems/attachment.md +36 -13
  62. package/kb/extra/subsystems/attachment.zh.md +36 -13
  63. package/kb/extra/subsystems/boot.md +631 -447
  64. package/kb/extra/subsystems/boot.zh.md +631 -447
  65. package/kb/extra/subsystems/computer-use.md +179 -59
  66. package/kb/extra/subsystems/computer-use.zh.md +179 -59
  67. package/kb/extra/subsystems/deliverables.md +2 -0
  68. package/kb/extra/subsystems/deliverables.zh.md +2 -0
  69. package/kb/extra/subsystems/extensions.md +387 -384
  70. package/kb/extra/subsystems/extensions.zh.md +387 -384
  71. package/kb/extra/subsystems/feedback.md +418 -400
  72. package/kb/extra/subsystems/feedback.zh.md +418 -400
  73. package/kb/extra/subsystems/forge.md +2169 -0
  74. package/kb/extra/subsystems/forge.zh.md +2171 -0
  75. package/kb/extra/subsystems/liveshare.md +167 -0
  76. package/kb/extra/subsystems/liveshare.zh.md +167 -0
  77. package/kb/extra/subsystems/mcp.md +237 -139
  78. package/kb/extra/subsystems/mcp.zh.md +237 -139
  79. package/kb/extra/subsystems/office-kit.md +122 -0
  80. package/kb/extra/subsystems/office-kit.zh.md +122 -0
  81. package/kb/extra/subsystems/working-directory.md +95 -64
  82. package/kb/extra/subsystems/working-directory.zh.md +95 -64
  83. package/kb/extra/subsystems/worktrees.md +187 -76
  84. package/kb/extra/subsystems/worktrees.zh.md +187 -76
  85. package/kb/extra/testing.md +1 -1
  86. package/kb/extra/testing.zh.md +1 -1
  87. package/kb/extra/ui-design-review-cases.md +445 -0
  88. package/kb/extra/ui-design-review-cases.zh.md +445 -0
  89. package/kb/extra/ui-radius.md +3 -1
  90. package/kb/extra/ui-radius.zh.md +3 -1
  91. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.md +21 -21
  92. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/python-ptc-sandbox/guide.zh.md +21 -21
  93. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md +1 -1
  94. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md +1 -1
  95. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/cordis-timer-wrappers/guide.md +24 -0
  96. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/cordis-timer-wrappers/guide.zh.md +24 -0
  97. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/plugin-manager-view-fields/guide.md +25 -0
  98. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/plugin-manager-view-fields/guide.zh.md +25 -0
  99. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/model-switch-compaction/guide.md +30 -0
  100. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/model-switch-compaction/guide.zh.md +30 -0
  101. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/session-model-selection/guide.md +28 -0
  102. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/session-model-selection/guide.zh.md +28 -0
  103. package/kb/extra/upgrade-guide/v0.2.1-rc.1/agent-instructions-chain-budgets/guide.md +24 -0
  104. package/kb/extra/upgrade-guide/v0.2.1-rc.1/agent-instructions-chain-budgets/guide.zh.md +24 -0
  105. package/kb/extra/upgrade-guide/v0.2.1-rc.1/subagent-control-tools/guide.md +23 -0
  106. package/kb/extra/upgrade-guide/v0.2.1-rc.1/subagent-control-tools/guide.zh.md +23 -0
  107. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-runtime-owner/guide.md +20 -0
  108. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-runtime-owner/guide.zh.md +20 -0
  109. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-team-subagents/guide.md +31 -0
  110. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-team-subagents/guide.zh.md +31 -0
  111. package/kb/extra/upgrade-guide/v0.2.1-rc.2/approval-projection-dependency/guide.md +34 -0
  112. package/kb/extra/upgrade-guide/v0.2.1-rc.2/approval-projection-dependency/guide.zh.md +34 -0
  113. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-shutdown/guide.md +20 -0
  114. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-shutdown/guide.zh.md +20 -0
  115. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-user-sources/guide.md +18 -0
  116. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-user-sources/guide.zh.md +18 -0
  117. package/kb/extra/upgrade-guide/v0.2.1-rc.2/built-in-japanese/guide.md +18 -0
  118. package/kb/extra/upgrade-guide/v0.2.1-rc.2/built-in-japanese/guide.zh.md +18 -0
  119. package/kb/extra/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.md +25 -0
  120. package/kb/extra/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.zh.md +25 -0
  121. package/kb/extra/upgrade-guide/v0.2.1-rc.2/context-menu-services/guide.md +23 -0
  122. package/kb/extra/upgrade-guide/v0.2.1-rc.2/context-menu-services/guide.zh.md +23 -0
  123. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-consent-storage/guide.md +22 -0
  124. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-consent-storage/guide.zh.md +22 -0
  125. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-preset-scope/guide.md +18 -0
  126. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-preset-scope/guide.zh.md +18 -0
  127. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-relative-coordinates/guide.md +17 -0
  128. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-relative-coordinates/guide.zh.md +17 -0
  129. package/kb/extra/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.md +19 -0
  130. package/kb/extra/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.zh.md +19 -0
  131. package/kb/extra/upgrade-guide/v0.2.1-rc.2/headless-policy-composition/guide.md +27 -0
  132. package/kb/extra/upgrade-guide/v0.2.1-rc.2/headless-policy-composition/guide.zh.md +27 -0
  133. package/kb/extra/upgrade-guide/v0.2.1-rc.2/model-badge-package-removal/guide.md +18 -0
  134. package/kb/extra/upgrade-guide/v0.2.1-rc.2/model-badge-package-removal/guide.zh.md +18 -0
  135. package/kb/extra/upgrade-guide/v0.2.1-rc.2/new-session-blank-reuse/guide.md +22 -0
  136. package/kb/extra/upgrade-guide/v0.2.1-rc.2/new-session-blank-reuse/guide.zh.md +22 -0
  137. package/kb/extra/upgrade-guide/v0.2.1-rc.2/node-24/guide.md +17 -0
  138. package/kb/extra/upgrade-guide/v0.2.1-rc.2/node-24/guide.zh.md +17 -0
  139. package/kb/extra/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md +18 -0
  140. package/kb/extra/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md +18 -0
  141. package/kb/extra/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.md +18 -0
  142. package/kb/extra/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.zh.md +18 -0
  143. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-default-capacities/guide.md +18 -0
  144. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-default-capacities/guide.zh.md +18 -0
  145. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-model-catalog/guide.md +53 -0
  146. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-model-catalog/guide.zh.md +53 -0
  147. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-protocol-replay/guide.md +30 -0
  148. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-protocol-replay/guide.zh.md +30 -0
  149. package/kb/extra/upgrade-guide/v0.2.1-rc.2/ptc-script-format/guide.md +20 -0
  150. package/kb/extra/upgrade-guide/v0.2.1-rc.2/ptc-script-format/guide.zh.md +20 -0
  151. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-desktop-context/guide.md +18 -0
  152. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-desktop-context/guide.zh.md +18 -0
  153. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-minimal-checkpoints/guide.md +18 -0
  154. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-minimal-checkpoints/guide.zh.md +18 -0
  155. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-projection-handles/guide.md +24 -0
  156. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-projection-handles/guide.zh.md +24 -0
  157. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.md +25 -0
  158. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.zh.md +25 -0
  159. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-team-mode/guide.md +22 -0
  160. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-team-mode/guide.zh.md +22 -0
  161. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-activation-options/guide.md +18 -0
  162. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-activation-options/guide.zh.md +18 -0
  163. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-service-methods/guide.md +19 -0
  164. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-service-methods/guide.zh.md +19 -0
  165. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-user-controls/guide.md +26 -0
  166. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-user-controls/guide.zh.md +26 -0
  167. package/kb/extra/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.md +35 -0
  168. package/kb/extra/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.zh.md +35 -0
  169. package/kb/extra/upgrade-guide/v0.2.1-rc.2/web-fetch-private-destinations/guide.md +21 -0
  170. package/kb/extra/upgrade-guide/v0.2.1-rc.2/web-fetch-private-destinations/guide.zh.md +21 -0
  171. package/kb/extra/upgrade-guide/v0.2.1-rc.2/webserver-index-peer/guide.md +17 -0
  172. package/kb/extra/upgrade-guide/v0.2.1-rc.2/webserver-index-peer/guide.zh.md +17 -0
  173. package/kb/extra/upgrade-guide/v0.2.1-rc.3/attachment-read-access/guide.md +23 -0
  174. package/kb/extra/upgrade-guide/v0.2.1-rc.3/attachment-read-access/guide.zh.md +23 -0
  175. package/kb/extra/upgrade-guide/v0.2.1-rc.3/computer-use-helper-permissions/guide.md +21 -0
  176. package/kb/extra/upgrade-guide/v0.2.1-rc.3/computer-use-helper-permissions/guide.zh.md +21 -0
  177. package/kb/extra/upgrade-guide/v0.2.1-rc.3/cua-bundle-id-consent/guide.md +20 -0
  178. package/kb/extra/upgrade-guide/v0.2.1-rc.3/cua-bundle-id-consent/guide.zh.md +20 -0
  179. package/kb/extra/upgrade-guide/v0.2.1-rc.3/generated-worktree-names/guide.md +20 -0
  180. package/kb/extra/upgrade-guide/v0.2.1-rc.3/generated-worktree-names/guide.zh.md +20 -0
  181. package/kb/extra/upgrade-guide/v0.2.1-rc.3/inbox-only-agent-wait/guide.md +19 -0
  182. package/kb/extra/upgrade-guide/v0.2.1-rc.3/inbox-only-agent-wait/guide.zh.md +19 -0
  183. package/kb/extra/upgrade-guide/v0.2.1-rc.3/independent-session-forks/guide.md +23 -0
  184. package/kb/extra/upgrade-guide/v0.2.1-rc.3/independent-session-forks/guide.zh.md +23 -0
  185. package/kb/extra/upgrade-guide/v0.2.1-rc.3/ptc-caller-cancellation/guide.md +20 -0
  186. package/kb/extra/upgrade-guide/v0.2.1-rc.3/ptc-caller-cancellation/guide.zh.md +20 -0
  187. package/kb/extra/upgrade-guide/v0.2.1-rc.3/session-follow-activation/guide.md +21 -0
  188. package/kb/extra/upgrade-guide/v0.2.1-rc.3/session-follow-activation/guide.zh.md +21 -0
  189. package/kb/extra/upgrade-guide/v0.2.1-rc.3/subagent-runtime-ownership/guide.md +21 -0
  190. package/kb/extra/upgrade-guide/v0.2.1-rc.3/subagent-runtime-ownership/guide.zh.md +21 -0
  191. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-mode-menu/guide.md +18 -0
  192. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-mode-menu/guide.zh.md +18 -0
  193. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-projection/guide.md +20 -0
  194. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-projection/guide.zh.md +20 -0
  195. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-file-downloads/guide.md +19 -0
  196. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-file-downloads/guide.zh.md +19 -0
  197. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-search-defaults/guide.md +18 -0
  198. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-search-defaults/guide.zh.md +18 -0
  199. package/kb/extra/upgrade-guide/v0.2.1-rc.4/model-listing-refresh/guide.md +22 -0
  200. package/kb/extra/upgrade-guide/v0.2.1-rc.4/model-listing-refresh/guide.zh.md +22 -0
  201. package/kb/extra/upgrade-guide/v0.2.1-rc.4/reasoning-body-props/guide.md +20 -0
  202. package/kb/extra/upgrade-guide/v0.2.1-rc.4/reasoning-body-props/guide.zh.md +20 -0
  203. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.md +18 -0
  204. package/kb/extra/upgrade-guide/v0.2.1-rc.4/sandbox-unsupported-policy-error/guide.zh.md +18 -0
  205. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/context-menu-target/guide.md +19 -0
  206. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/context-menu-target/guide.zh.md +19 -0
  207. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cordis-loader-entry-trees/guide.md +24 -0
  208. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cordis-loader-entry-trees/guide.zh.md +24 -0
  209. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/css-anchored-menus/guide.md +21 -0
  210. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/css-anchored-menus/guide.zh.md +21 -0
  211. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cua-source-dev-helper/guide.md +19 -0
  212. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cua-source-dev-helper/guide.zh.md +19 -0
  213. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/desktop-stable-channel/guide.md +18 -0
  214. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/desktop-stable-channel/guide.zh.md +18 -0
  215. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-git-permissions/guide.md +21 -0
  216. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-git-permissions/guide.zh.md +21 -0
  217. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-worktree-entry/guide.md +29 -0
  218. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-worktree-entry/guide.zh.md +29 -0
  219. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/fs-observation-policy-default-off/guide.md +29 -0
  220. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/fs-observation-policy-default-off/guide.zh.md +29 -0
  221. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.md +18 -0
  222. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-error-builtin-codes/guide.zh.md +18 -0
  223. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-request-purpose-declarations/guide.md +29 -0
  224. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-request-purpose-declarations/guide.zh.md +29 -0
  225. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/pi-ai-request-image-count/guide.md +18 -0
  226. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/pi-ai-request-image-count/guide.zh.md +18 -0
  227. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-event-frames/guide.md +32 -0
  228. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-event-frames/guide.zh.md +32 -0
  229. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-released-checkpoint/guide.md +30 -0
  230. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-released-checkpoint/guide.zh.md +30 -0
  231. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-snapshot-scope/guide.md +19 -0
  232. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-snapshot-scope/guide.zh.md +19 -0
  233. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/retained-ptc-timeout/guide.md +21 -0
  234. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/retained-ptc-timeout/guide.zh.md +21 -0
  235. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-agent-tools/guide.md +37 -0
  236. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-agent-tools/guide.zh.md +37 -0
  237. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-remote-host-tasks/guide.md +22 -0
  238. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-remote-host-tasks/guide.zh.md +22 -0
  239. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/sdk-run-commands/guide.md +24 -0
  240. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/sdk-run-commands/guide.zh.md +24 -0
  241. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/session-header-menu/guide.md +20 -0
  242. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/session-header-menu/guide.zh.md +20 -0
  243. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/subagent-explicit-reasoning/guide.md +20 -0
  244. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/subagent-explicit-reasoning/guide.zh.md +20 -0
  245. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-credential-modes/guide.md +17 -0
  246. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-credential-modes/guide.zh.md +17 -0
  247. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-default-provider/guide.md +19 -0
  248. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-default-provider/guide.zh.md +19 -0
  249. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/chat-process-activity-context/guide.md +18 -0
  250. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/chat-process-activity-context/guide.zh.md +18 -0
  251. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.md +34 -0
  252. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-kit-package/guide.zh.md +34 -0
  253. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.md +49 -0
  254. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-operation-tools/guide.zh.md +49 -0
  255. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.md +36 -0
  256. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/office-skill-resources/guide.zh.md +36 -0
  257. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.md +29 -0
  258. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.zh.md +29 -0
  259. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.md +26 -0
  260. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-notification-fields/guide.zh.md +26 -0
  261. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.md +22 -0
  262. package/kb/extra/upgrade-guide/v0.2.2-rc.1/account-remote-provider/guide.zh.md +22 -0
  263. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.md +21 -0
  264. package/kb/extra/upgrade-guide/v0.2.2-rc.1/archive-worktrees/guide.zh.md +21 -0
  265. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.md +23 -0
  266. package/kb/extra/upgrade-guide/v0.2.2-rc.1/attachment-error-codes/guide.zh.md +23 -0
  267. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.md +20 -0
  268. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-ax-read-limits/guide.zh.md +20 -0
  269. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.md +18 -0
  270. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-hover-ax-only/guide.zh.md +18 -0
  271. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.md +23 -0
  272. package/kb/extra/upgrade-guide/v0.2.2-rc.1/cua-native-platform/guide.zh.md +23 -0
  273. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.md +35 -0
  274. package/kb/extra/upgrade-guide/v0.2.2-rc.1/dsh-doc-skill/guide.zh.md +35 -0
  275. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.md +26 -0
  276. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-change-request-overview/guide.zh.md +26 -0
  277. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.md +26 -0
  278. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-pinned-diff/guide.zh.md +26 -0
  279. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.md +19 -0
  280. package/kb/extra/upgrade-guide/v0.2.2-rc.1/forge-review-reads/guide.zh.md +19 -0
  281. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.md +26 -0
  282. package/kb/extra/upgrade-guide/v0.2.2-rc.1/package-export-cleanup/guide.zh.md +26 -0
  283. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.md +22 -0
  284. package/kb/extra/upgrade-guide/v0.2.2-rc.1/plugin-update-method/guide.zh.md +22 -0
  285. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.md +25 -0
  286. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-bootstrap-protocol/guide.zh.md +25 -0
  287. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.md +48 -0
  288. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-inspect-output/guide.zh.md +48 -0
  289. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.md +45 -0
  290. package/kb/extra/upgrade-guide/v0.2.2-rc.1/ptc-scoped-repl-default/guide.zh.md +45 -0
  291. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.md +19 -0
  292. package/kb/extra/upgrade-guide/v0.2.2-rc.1/runtime-context-reminders/guide.zh.md +19 -0
  293. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.md +17 -0
  294. package/kb/extra/upgrade-guide/v0.2.2-rc.1/session-append-overloads/guide.zh.md +17 -0
  295. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.md +27 -0
  296. package/kb/extra/upgrade-guide/v0.2.2-rc.1/subagent-interrupt-default/guide.zh.md +27 -0
  297. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.md +20 -0
  298. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-backend-cleanup-error/guide.zh.md +20 -0
  299. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.md +19 -0
  300. package/kb/extra/upgrade-guide/v0.2.2-rc.1/terminal-bundle-sidebar-backend/guide.zh.md +19 -0
  301. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.md +18 -0
  302. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-fetch-transport-error-codes/guide.zh.md +18 -0
  303. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.md +41 -0
  304. package/kb/extra/upgrade-guide/v0.2.2-rc.1/web-search-billing/guide.zh.md +41 -0
  305. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.md +21 -0
  306. package/kb/extra/upgrade-guide/v0.2.2-rc.1/window-drag-regions/guide.zh.md +21 -0
  307. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.md +29 -0
  308. package/kb/extra/upgrade-guide/v0.2.2-rc.2/client-module-metadata/guide.zh.md +29 -0
  309. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.md +25 -0
  310. package/kb/extra/upgrade-guide/v0.2.2-rc.2/connection-page-peer/guide.zh.md +25 -0
  311. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.md +31 -0
  312. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cordis-root-and-intercept-metadata/guide.zh.md +31 -0
  313. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.md +24 -0
  314. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-agents-without-preset/guide.zh.md +24 -0
  315. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.md +24 -0
  316. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-macos-provider/guide.zh.md +24 -0
  317. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.md +19 -0
  318. package/kb/extra/upgrade-guide/v0.2.2-rc.2/cua-partial-observations/guide.zh.md +19 -0
  319. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.md +15 -0
  320. package/kb/extra/upgrade-guide/v0.2.2-rc.2/deepseek-files-timeout/guide.zh.md +15 -0
  321. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.md +28 -0
  322. package/kb/extra/upgrade-guide/v0.2.2-rc.2/experimental-tool-error-codes/guide.zh.md +28 -0
  323. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.md +36 -0
  324. package/kb/extra/upgrade-guide/v0.2.2-rc.2/package-export-cleanup/guide.zh.md +36 -0
  325. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.md +22 -0
  326. package/kb/extra/upgrade-guide/v0.2.2-rc.2/python-ptc-removal/guide.zh.md +22 -0
  327. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.md +31 -0
  328. package/kb/extra/upgrade-guide/v0.2.2-rc.2/session-status-package/guide.zh.md +31 -0
  329. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.md +18 -0
  330. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shared-search-filter/guide.zh.md +18 -0
  331. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.md +30 -0
  332. package/kb/extra/upgrade-guide/v0.2.2-rc.2/shell-fs-tool-error-codes/guide.zh.md +30 -0
  333. package/kb/extra/web-styling.md +57 -39
  334. package/kb/extra/web-styling.zh.md +57 -39
  335. package/kb/meta/search-index.json +4508 -3806
  336. package/kb/meta/source.json +18 -14
  337. package/kb/site/develop/cordis-tutorial/04-events.md +1 -1
  338. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  339. package/kb/site/develop/framework/events.md +1 -1
  340. package/kb/site/develop/practice/dynamic-cordis.md +1 -1
  341. package/kb/site/develop/practice/llm-adapter.md +192 -192
  342. package/kb/site/en/develop/cordis-tutorial/04-events.md +1 -1
  343. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  344. package/kb/site/en/develop/framework/events.md +1 -1
  345. package/kb/site/en/develop/practice/dynamic-cordis.md +1 -1
  346. package/kb/site/en/develop/practice/llm-adapter.md +192 -192
  347. package/kb/site/en/guide/desktop-uninstall-cleanup.md +63 -0
  348. package/kb/site/en/guide/network-proxy.md +1 -1
  349. package/kb/site/en/guide/plugin-market.md +153 -151
  350. package/kb/site/en/guide/providers.md +234 -230
  351. package/kb/site/en/guide/python-sdk.md +17 -2
  352. package/kb/site/en/guide/quickstart.md +35 -34
  353. package/kb/site/en/guide/schedule.md +45 -26
  354. package/kb/site/en/reference/agent-lifecycle.md +3 -1
  355. package/kb/site/en/reference/api-gateway.md +4 -4
  356. package/kb/site/en/reference/capability-seams.md +789 -719
  357. package/kb/site/en/reference/config-catalog.md +5432 -4806
  358. package/kb/site/en/reference/cookbook/adding-a-package.md +175 -173
  359. package/kb/site/en/reference/cookbook/adding-a-tool.md +105 -104
  360. package/kb/site/en/reference/cookbook/extension-cookbook.md +178 -135
  361. package/kb/site/en/reference/cordis-api/context.md +373 -369
  362. package/kb/site/en/reference/cordis-api/events.md +9 -9
  363. package/kb/site/en/reference/cordis-api/fiber.md +457 -380
  364. package/kb/site/en/reference/cordis-api/inherited.md +44 -43
  365. package/kb/site/en/reference/cordis-api/service.md +118 -107
  366. package/kb/site/en/reference/experimental-persistence-catalog.md +36 -20
  367. package/kb/site/en/reference/index.md +174 -168
  368. package/kb/site/en/reference/persistence-catalog.md +9453 -9146
  369. package/kb/site/en/reference/subsystems/client-modules.md +19 -11
  370. package/kb/site/en/reference/subsystems/compaction.md +288 -288
  371. package/kb/site/en/reference/subsystems/conversation.md +2 -0
  372. package/kb/site/en/reference/subsystems/core.md +1172 -1117
  373. package/kb/site/en/reference/subsystems/credentials.md +526 -497
  374. package/kb/site/en/reference/subsystems/filesystem.md +708 -534
  375. package/kb/site/en/reference/subsystems/index.md +82 -80
  376. package/kb/site/en/reference/subsystems/llm-streaming.md +1290 -1200
  377. package/kb/site/en/reference/subsystems/lsp.md +230 -206
  378. package/kb/site/en/reference/subsystems/persistence.md +451 -422
  379. package/kb/site/en/reference/subsystems/plan.md +91 -91
  380. package/kb/site/en/reference/subsystems/ptc-runtime.md +295 -254
  381. package/kb/site/en/reference/subsystems/sandbox.md +250 -225
  382. package/kb/site/en/reference/subsystems/schedule.md +194 -430
  383. package/kb/site/en/reference/subsystems/session-projection.md +186 -44
  384. package/kb/site/en/reference/subsystems/session-query.md +525 -515
  385. package/kb/site/en/reference/subsystems/session-reference.md +231 -228
  386. package/kb/site/en/reference/subsystems/session.md +1478 -1343
  387. package/kb/site/en/reference/subsystems/sidebar-right.md +165 -164
  388. package/kb/site/en/reference/subsystems/skills.md +356 -356
  389. package/kb/site/en/reference/subsystems/slots.md +235 -204
  390. package/kb/site/en/reference/subsystems/storage.md +26 -9
  391. package/kb/site/en/reference/subsystems/subagent.md +119 -102
  392. package/kb/site/en/reference/subsystems/system-prompt.md +13 -11
  393. package/kb/site/en/reference/subsystems/terminal.md +188 -188
  394. package/kb/site/en/reference/subsystems/token-meter.md +45 -0
  395. package/kb/site/en/reference/subsystems/tools.md +902 -751
  396. package/kb/site/en/reference/subsystems/typert.md +21 -11
  397. package/kb/site/en/reference/subsystems/user-questions.md +330 -311
  398. package/kb/site/en/reference/subsystems/web-client.md +161 -104
  399. package/kb/site/en/reference/subsystems/web-server.md +434 -306
  400. package/kb/site/en/reference/subsystems/web.md +268 -210
  401. package/kb/site/en/reference/subsystems/workflow.md +287 -282
  402. package/kb/site/en/reference/subsystems/workspace.md +743 -651
  403. package/kb/site/en/reference/tool-catalog.md +2867 -2829
  404. package/kb/site/en/reference/tool-execution-pipeline.md +5 -4
  405. package/kb/site/guide/desktop-uninstall-cleanup.md +63 -0
  406. package/kb/site/guide/network-proxy.md +1 -1
  407. package/kb/site/guide/plugin-market.md +153 -151
  408. package/kb/site/guide/providers.md +234 -230
  409. package/kb/site/guide/python-sdk.md +17 -2
  410. package/kb/site/guide/quickstart.md +35 -34
  411. package/kb/site/guide/schedule.md +45 -26
  412. package/kb/site/reference/agent-lifecycle.md +3 -1
  413. package/kb/site/reference/api-gateway.md +4 -4
  414. package/kb/site/reference/capability-seams.md +789 -719
  415. package/kb/site/reference/config-catalog.md +5432 -4806
  416. package/kb/site/reference/cookbook/adding-a-package.md +175 -173
  417. package/kb/site/reference/cookbook/adding-a-tool.md +107 -106
  418. package/kb/site/reference/cookbook/extension-cookbook.md +182 -139
  419. package/kb/site/reference/cordis-api/context.md +373 -369
  420. package/kb/site/reference/cordis-api/events.md +9 -9
  421. package/kb/site/reference/cordis-api/fiber.md +459 -380
  422. package/kb/site/reference/cordis-api/inherited.md +44 -43
  423. package/kb/site/reference/cordis-api/service.md +118 -107
  424. package/kb/site/reference/experimental-persistence-catalog.md +36 -20
  425. package/kb/site/reference/index.md +178 -172
  426. package/kb/site/reference/persistence-catalog.md +9453 -9146
  427. package/kb/site/reference/subsystems/client-modules.md +19 -11
  428. package/kb/site/reference/subsystems/compaction.md +288 -288
  429. package/kb/site/reference/subsystems/conversation.md +4 -0
  430. package/kb/site/reference/subsystems/core.md +1184 -1129
  431. package/kb/site/reference/subsystems/credentials.md +526 -497
  432. package/kb/site/reference/subsystems/filesystem.md +708 -534
  433. package/kb/site/reference/subsystems/index.md +82 -80
  434. package/kb/site/reference/subsystems/llm-streaming.md +1296 -1206
  435. package/kb/site/reference/subsystems/lsp.md +230 -206
  436. package/kb/site/reference/subsystems/persistence.md +451 -422
  437. package/kb/site/reference/subsystems/plan.md +91 -91
  438. package/kb/site/reference/subsystems/ptc-runtime.md +295 -254
  439. package/kb/site/reference/subsystems/sandbox.md +250 -225
  440. package/kb/site/reference/subsystems/schedule.md +197 -433
  441. package/kb/site/reference/subsystems/session-projection.md +186 -44
  442. package/kb/site/reference/subsystems/session-query.md +525 -515
  443. package/kb/site/reference/subsystems/session-reference.md +231 -228
  444. package/kb/site/reference/subsystems/session.md +1482 -1347
  445. package/kb/site/reference/subsystems/sidebar-right.md +165 -164
  446. package/kb/site/reference/subsystems/skills.md +356 -356
  447. package/kb/site/reference/subsystems/slots.md +239 -208
  448. package/kb/site/reference/subsystems/storage.md +26 -9
  449. package/kb/site/reference/subsystems/subagent.md +119 -102
  450. package/kb/site/reference/subsystems/system-prompt.md +13 -11
  451. package/kb/site/reference/subsystems/terminal.md +188 -188
  452. package/kb/site/reference/subsystems/token-meter.md +45 -0
  453. package/kb/site/reference/subsystems/tools.md +902 -751
  454. package/kb/site/reference/subsystems/typert.md +21 -11
  455. package/kb/site/reference/subsystems/user-questions.md +330 -311
  456. package/kb/site/reference/subsystems/web-client.md +161 -104
  457. package/kb/site/reference/subsystems/web-server.md +434 -306
  458. package/kb/site/reference/subsystems/web.md +268 -210
  459. package/kb/site/reference/subsystems/workflow.md +287 -282
  460. package/kb/site/reference/subsystems/workspace.md +743 -651
  461. package/kb/site/reference/tool-catalog.md +2872 -2835
  462. package/kb/site/reference/tool-execution-pipeline.md +4 -3
  463. package/lib/index.js +359 -244
  464. package/lib/kb-version.js +118 -0
  465. package/package.json +68 -66
  466. package/scripts/refresh-kb.mjs +153 -0
  467. package/scripts/selfcheck.mjs +18 -0
  468. package/scripts/smoke.mjs +77 -0
  469. package/skills/dsh-plugin-dev-kb.md +71 -69
  470. package/skills/dsh-plugin-starter.md +65 -0
  471. package/skills/dsh-upgrade-assistant.md +62 -0
  472. package/kb/extra/agent-lifecycle.md +0 -91
  473. package/kb/extra/agent-lifecycle.zh.md +0 -93
  474. package/kb/extra/api-gateway.md +0 -172
  475. package/kb/extra/api-gateway.zh.md +0 -178
  476. package/kb/extra/architecture.md +0 -165
  477. package/kb/extra/architecture.zh.md +0 -169
  478. package/kb/extra/capability-seams.md +0 -714
  479. package/kb/extra/capability-seams.zh.md +0 -716
  480. package/kb/extra/config-catalog.md +0 -4801
  481. package/kb/extra/config-catalog.zh.md +0 -4803
  482. package/kb/extra/cookbook/adding-a-package.md +0 -170
  483. package/kb/extra/cookbook/adding-a-package.zh.md +0 -170
  484. package/kb/extra/cookbook/adding-a-settings-card.md +0 -72
  485. package/kb/extra/cookbook/adding-a-settings-card.zh.md +0 -72
  486. package/kb/extra/cookbook/adding-a-tool.md +0 -101
  487. package/kb/extra/cookbook/adding-a-tool.zh.md +0 -103
  488. package/kb/extra/cookbook/adding-an-llm-adapter.md +0 -43
  489. package/kb/extra/cookbook/adding-an-llm-adapter.zh.md +0 -43
  490. package/kb/extra/cookbook/extension-cookbook.md +0 -132
  491. package/kb/extra/cookbook/extension-cookbook.zh.md +0 -136
  492. package/kb/extra/cordis-api/context.md +0 -364
  493. package/kb/extra/cordis-api/context.zh.md +0 -366
  494. package/kb/extra/cordis-api/events.md +0 -207
  495. package/kb/extra/cordis-api/events.zh.md +0 -209
  496. package/kb/extra/cordis-api/fiber.md +0 -375
  497. package/kb/extra/cordis-api/fiber.zh.md +0 -377
  498. package/kb/extra/cordis-api/inherited.md +0 -38
  499. package/kb/extra/cordis-api/registry.md +0 -152
  500. package/kb/extra/cordis-api/registry.zh.md +0 -154
  501. package/kb/extra/cordis-api/service.md +0 -102
  502. package/kb/extra/cordis-api/service.zh.md +0 -104
  503. package/kb/extra/cordis-tutorial/01-first-plugin.md +0 -95
  504. package/kb/extra/cordis-tutorial/01-first-plugin.zh.md +0 -95
  505. package/kb/extra/cordis-tutorial/02-lifecycle-and-effects.md +0 -98
  506. package/kb/extra/cordis-tutorial/02-lifecycle-and-effects.zh.md +0 -98
  507. package/kb/extra/cordis-tutorial/03-services.md +0 -98
  508. package/kb/extra/cordis-tutorial/03-services.zh.md +0 -98
  509. package/kb/extra/cordis-tutorial/04-events.md +0 -144
  510. package/kb/extra/cordis-tutorial/04-events.zh.md +0 -144
  511. package/kb/extra/cordis-tutorial/05-config.md +0 -111
  512. package/kb/extra/cordis-tutorial/05-config.zh.md +0 -111
  513. package/kb/extra/cordis-tutorial/06-composition-and-hmr.md +0 -113
  514. package/kb/extra/cordis-tutorial/06-composition-and-hmr.zh.md +0 -113
  515. package/kb/extra/cordis-tutorial/07-into-the-harness.md +0 -108
  516. package/kb/extra/cordis-tutorial/07-into-the-harness.zh.md +0 -108
  517. package/kb/extra/cordis-tutorial/index.md +0 -60
  518. package/kb/extra/cordis-tutorial/index.zh.md +0 -62
  519. package/kb/extra/experimental-persistence-catalog.md +0 -17
  520. package/kb/extra/experimental-persistence-catalog.zh.md +0 -17
  521. package/kb/extra/persistence-catalog.md +0 -9140
  522. package/kb/extra/persistence-catalog.zh.md +0 -9142
  523. package/kb/extra/subsystems/README.md +0 -76
  524. package/kb/extra/subsystems/README.zh.md +0 -76
  525. package/kb/extra/subsystems/approval.md +0 -170
  526. package/kb/extra/subsystems/approval.zh.md +0 -170
  527. package/kb/extra/subsystems/client-modules.md +0 -198
  528. package/kb/extra/subsystems/client-modules.zh.md +0 -198
  529. package/kb/extra/subsystems/client-resources.md +0 -92
  530. package/kb/extra/subsystems/client-resources.zh.md +0 -92
  531. package/kb/extra/subsystems/commands.md +0 -223
  532. package/kb/extra/subsystems/commands.zh.md +0 -223
  533. package/kb/extra/subsystems/compaction.md +0 -284
  534. package/kb/extra/subsystems/compaction.zh.md +0 -284
  535. package/kb/extra/subsystems/conversation.md +0 -301
  536. package/kb/extra/subsystems/conversation.zh.md +0 -303
  537. package/kb/extra/subsystems/core.md +0 -1113
  538. package/kb/extra/subsystems/core.zh.md +0 -1125
  539. package/kb/extra/subsystems/credentials.md +0 -493
  540. package/kb/extra/subsystems/credentials.zh.md +0 -493
  541. package/kb/extra/subsystems/filesystem.md +0 -530
  542. package/kb/extra/subsystems/filesystem.zh.md +0 -530
  543. package/kb/extra/subsystems/goal.md +0 -313
  544. package/kb/extra/subsystems/goal.zh.md +0 -313
  545. package/kb/extra/subsystems/jobs.md +0 -554
  546. package/kb/extra/subsystems/jobs.zh.md +0 -554
  547. package/kb/extra/subsystems/llm-streaming.md +0 -1196
  548. package/kb/extra/subsystems/llm-streaming.zh.md +0 -1202
  549. package/kb/extra/subsystems/lsp.md +0 -202
  550. package/kb/extra/subsystems/lsp.zh.md +0 -202
  551. package/kb/extra/subsystems/office-to-pdf.md +0 -87
  552. package/kb/extra/subsystems/office-to-pdf.zh.md +0 -87
  553. package/kb/extra/subsystems/permission-presets.md +0 -167
  554. package/kb/extra/subsystems/permission-presets.zh.md +0 -167
  555. package/kb/extra/subsystems/persistence.md +0 -418
  556. package/kb/extra/subsystems/persistence.zh.md +0 -418
  557. package/kb/extra/subsystems/plan.md +0 -87
  558. package/kb/extra/subsystems/plan.zh.md +0 -87
  559. package/kb/extra/subsystems/ptc-runtime.md +0 -250
  560. package/kb/extra/subsystems/ptc-runtime.zh.md +0 -250
  561. package/kb/extra/subsystems/sandbox.md +0 -221
  562. package/kb/extra/subsystems/sandbox.zh.md +0 -221
  563. package/kb/extra/subsystems/schedule.md +0 -550
  564. package/kb/extra/subsystems/schedule.zh.md +0 -550
  565. package/kb/extra/subsystems/scope.md +0 -59
  566. package/kb/extra/subsystems/scope.zh.md +0 -61
  567. package/kb/extra/subsystems/session-projection.md +0 -356
  568. package/kb/extra/subsystems/session-projection.zh.md +0 -356
  569. package/kb/extra/subsystems/session-query.md +0 -511
  570. package/kb/extra/subsystems/session-query.zh.md +0 -511
  571. package/kb/extra/subsystems/session-reference.md +0 -224
  572. package/kb/extra/subsystems/session-reference.zh.md +0 -224
  573. package/kb/extra/subsystems/session-telemetry.md +0 -212
  574. package/kb/extra/subsystems/session-telemetry.zh.md +0 -212
  575. package/kb/extra/subsystems/session-title.md +0 -213
  576. package/kb/extra/subsystems/session-title.zh.md +0 -213
  577. package/kb/extra/subsystems/session.md +0 -1339
  578. package/kb/extra/subsystems/session.zh.md +0 -1343
  579. package/kb/extra/subsystems/settings.md +0 -155
  580. package/kb/extra/subsystems/settings.zh.md +0 -155
  581. package/kb/extra/subsystems/shell.md +0 -314
  582. package/kb/extra/subsystems/shell.zh.md +0 -314
  583. package/kb/extra/subsystems/sidebar-right.md +0 -160
  584. package/kb/extra/subsystems/sidebar-right.zh.md +0 -160
  585. package/kb/extra/subsystems/skills.md +0 -352
  586. package/kb/extra/subsystems/skills.zh.md +0 -352
  587. package/kb/extra/subsystems/slots.md +0 -200
  588. package/kb/extra/subsystems/slots.zh.md +0 -204
  589. package/kb/extra/subsystems/spill.md +0 -124
  590. package/kb/extra/subsystems/spill.zh.md +0 -124
  591. package/kb/extra/subsystems/storage.md +0 -259
  592. package/kb/extra/subsystems/storage.zh.md +0 -259
  593. package/kb/extra/subsystems/subagent.md +0 -686
  594. package/kb/extra/subsystems/subagent.zh.md +0 -688
  595. package/kb/extra/subsystems/subprocess.md +0 -321
  596. package/kb/extra/subsystems/subprocess.zh.md +0 -321
  597. package/kb/extra/subsystems/system-prompt.md +0 -254
  598. package/kb/extra/subsystems/system-prompt.zh.md +0 -254
  599. package/kb/extra/subsystems/terminal.md +0 -184
  600. package/kb/extra/subsystems/terminal.zh.md +0 -184
  601. package/kb/extra/subsystems/token-meter.md +0 -106
  602. package/kb/extra/subsystems/token-meter.zh.md +0 -106
  603. package/kb/extra/subsystems/tools.md +0 -747
  604. package/kb/extra/subsystems/tools.zh.md +0 -747
  605. package/kb/extra/subsystems/typert.md +0 -690
  606. package/kb/extra/subsystems/typert.zh.md +0 -690
  607. package/kb/extra/subsystems/user-questions.md +0 -307
  608. package/kb/extra/subsystems/user-questions.zh.md +0 -307
  609. package/kb/extra/subsystems/web-client.md +0 -100
  610. package/kb/extra/subsystems/web-client.zh.md +0 -100
  611. package/kb/extra/subsystems/web-server.md +0 -302
  612. package/kb/extra/subsystems/web-server.zh.md +0 -302
  613. package/kb/extra/subsystems/web.md +0 -206
  614. package/kb/extra/subsystems/web.zh.md +0 -206
  615. package/kb/extra/subsystems/workflow.md +0 -278
  616. package/kb/extra/subsystems/workflow.zh.md +0 -278
  617. package/kb/extra/subsystems/workspace.md +0 -647
  618. package/kb/extra/subsystems/workspace.zh.md +0 -647
  619. package/kb/extra/tool-catalog.md +0 -2824
  620. package/kb/extra/tool-catalog.zh.md +0 -2832
  621. package/kb/extra/tool-execution-pipeline.md +0 -65
  622. package/kb/extra/tool-execution-pipeline.zh.md +0 -67
@@ -1,1117 +1,1172 @@
1
- ---
2
- editSource: "docs/subsystems/core.md"
3
- rawMarkdownPath: "en/reference/subsystems/core.md"
4
- outline: [2,3]
5
- ---
6
-
7
- # Core
8
-
9
- The **core** subsystem is [`packages/core`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/README.md) — the packages every composition boots: the event-sourced session log, system-prompt assembly, the tool registry, the agent types, and the concrete loop that drives them. This page explains what the `agent`/`agent-loop` pair declares — how an agent is created and owned, and the `Agent` handle's delivery, cancellation, and interception contracts — plus the two type patterns every subsystem follows. The group's dedicated pages and the rest of the folder are indexed in the [subsystems README](./index.md).
10
-
11
- ## The spine, package by package
12
-
13
- A turn flows through the six packages in one loop: the driver in [`agent-loop`](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/agent-loop) claims a queued prompt, opens a turn on the [session log](./session.md) (`ctx.sessions`), assembles the request prefix through [system-prompt](./system-prompt.md) (`ctx.systemPrompt`) and derives history from the log, streams the model response through the [LLM seam](./llm-streaming.md), dispatches tool calls through the [tool registry](./tools.md) (`ctx.tools`), and appends every model-visible fact back onto the log before the next step derives from it. The conversation vocabulary the loop moves — `Message`, `ContentBlock`, `StreamChunk`, the model request — is declared by [`packages/llm`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/README.md) and documented on [llm-streaming.md](./llm-streaming.md).
14
-
15
- | Package | Owns | Page |
16
- |---|---|---|
17
- | `session/` | The append-only `SessionEvent` log and in-memory store — the single source of truth (`ctx.sessions`) | [session.md](./session.md) |
18
- | `system-prompt/` | Prompt-section and tool-schema assembly (`ctx.systemPrompt`) | [system-prompt.md](./system-prompt.md) |
19
- | `tools/` | The scoped tool registry and guarded execution pipeline (`ctx.tools`) | [tools.md](./tools.md) |
20
- | `agent/` | The `Agent` interface, live registry, initiator scope, and `agent/*` event vocabulary (`ctx.agents`) | this page |
21
- | `agent-loop/` | The concrete driver implementing the public `Agent` contract (`ctx.agentLoop`) | this page |
22
- | `scope/` | The scoped-registration primitive the registries and loop build per-agent scoping on | [scope.md](./scope.md) |
23
-
24
- `scope/` is the one non-service package: a dependency-free library (`createScope`/`scopeOf`/`scopeTarget`) that sits below `session/` and `system-prompt/` in the module graph precisely so they can consume it without a cycle. `agent-loop` is the one concrete implementation of the public `Agent` contract and lives here because it is the harness's default product loop; it runs each driver inside `ctx.agents.withInitiator()`. Extension plugins depend on `agent` — including when they need the initiating Agent — and never on `agent-loop` directly, so the loop stays swappable. [`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.md) is the default product composition, while [`dsh-sdk-minimal`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-minimal/README.md) declares a smaller standalone tree.
25
-
26
- ## Creation and ownership
27
-
28
- Consumers create agents through `ctx.agents` — `create()` builds a fresh session and agent under one caller-supplied `SessionId`, `resume()` loads a persisted session first — or declaratively through the loop's config entries. Programmatic creation returns the owner's handle:
29
-
30
- Source: [`packages/core/agent/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/index.ts)
31
-
32
- ```ts type-equiv
33
- /**
34
- * An owned agent plus its disposer, returned by {@link AgentRegistry.create} /
35
- * {@link AgentRegistry.resume}. The disposer is a CAPABILITY: among consumers,
36
- * only the holder can tear this agent down. The registered factory provider is
37
- * also a structural owner because the scoped agent depends on that provider's
38
- * service API; provider unload stops and drains every live handle it made.
39
- * `dispose()` stops the loop, awaits its exit, unregisters the agent, removes
40
- * its session from the store, and finally unwinds its scoped world.
41
- *
42
- * `ctx.agents.get(id)` still returns a bare {@link Agent} — the handle is
43
- * exposed only to the consumer owner that created it; the structural provider
44
- * reaches the same teardown internally. Config-created agents (the loop's own
45
- * startup) are owned by the loop fiber and never need a handle.
46
- */
47
- interface AgentHandle {
48
- agent: Agent
49
- dispose(): Promise<void>
50
- }
51
- ```
52
-
53
- `CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: an optional live `parentAgent`, session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `parentAgent`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) receives `(agentCtx, agent)` while both ids are still unpublished: the context owns scoped registrations, while the explicit Agent supplies the exact child Session without a reverse property on the Context. Everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly. Setup may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal rolls the transaction back without publishing either id.
54
-
55
- `AgentFactory` is the creation interface behind the registry: the loop registers its factory via `ctx.agents.setFactory()`, so consumers use `ctx.agents` without depending on the concrete loop package. A runtime child creator sets `options.parentAgent`; the registry passes the options and caller Context to the factory without deriving one from the other. The exact `create`/`resume` signatures and rollback contracts are in the [generated section](#ctxagents--agentregistry) below.
56
-
57
- ## The agent handle
58
-
59
- `Agent` is the surface every plugin (UI, hooks, orchestrators) programs against; `ctx.agents.get(id)` returns it, and the [initiator scope](#initiating-agent) carries it. The concrete implementation is package-internal to dsh-agent-loop; nothing outside the loop depends on it. The unified `send` method exposes target and wakeup routing directly; `followup`, `steer`, and `inject` are fixed-preset aliases.
60
-
61
- Source: [`packages/core/agent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
62
-
63
- ```ts type-equiv
64
- /** Public live-agent handle; the runtime face augments its live capabilities. */
65
- interface Agent {
66
- /** Session-backed Agent identity. */
67
- readonly id: SessionId
68
- /** The provider route and model this agent's requests use. */
69
- readonly options: AgentOptions
70
- /** The live session this agent drives; its log is the durable source of truth. */
71
- readonly session: Session
72
- /** Agent-owned access to durable pending work. */
73
- readonly inbox: Inbox
74
- /** The current lifecycle state, mirrored on every `agent/status` transition. */
75
- readonly status: AgentStatus
76
- /** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */
77
- readonly ctx: Context
78
-
79
- /**
80
- * Clear queued and steering work — unless `keepInbox` — and abort the active
81
- * turn or between-turn task. The first cause wins for that activity. With no
82
- * active activity, cancellation is a no-op and does not arm later work.
83
- * @param cause - the stable caller intent carried by the active operation signal.
84
- * @param options - cancellation options; `keepInbox` preserves pending work.
85
- */
86
- cancel(cause: AgentCancelCause, options?: CancelOptions): void
87
-
88
- /**
89
- * Resolve after the current whole-agent activity reaches quiescence. This
90
- * follows replacement work started before the observed driver retires,
91
- * but does not identify the settlement of any particular message.
92
- * @returns fulfillment after no active driver or maintenance task remains.
93
- */
94
- whenIdle(): Promise<void>
95
-
96
- /**
97
- * Run one non-turn maintenance task from the true idle phase. The task starts
98
- * synchronously after claiming that phase; later waking input remains in the
99
- * inbox until the task settles, while public status stays `idle`.
100
- * `whenIdle()` follows both the task and any waking work released behind it.
101
- * @param task - operation whose fulfillment or rejection is preserved, with a signal aborted by {@link cancel}.
102
- * @throws synchronously when turn-driving or another maintenance task already owns the agent.
103
- * @returns the task promise.
104
- */
105
- runMaintenance<T>(task: (signal: AbortSignal) => Promise<T>): Promise<T>
106
-
107
- /**
108
- * Route identified input to an inbox boundary and optionally wake the driver.
109
- * Waking input submitted after active cancellation is queued for the next
110
- * turn and runs when the aborted activity converges to idle; a `disposed`
111
- * cancel leaves it parked. A wake submitted while already idle always opens
112
- * its turn boundary, even when its message is cleared before the driver
113
- * claims ([driver wake convergence](../../agent-loop/src/agent.ts)).
114
- * @param message - identified content and the source that supplied it.
115
- * @param target - the preferred next-turn or next-step inbox boundary.
116
- * @param wakeup - whether delivery may wake the driver.
117
- */
118
- send(message: UserMessage, target: InboxTarget, wakeup: boolean): void
119
-
120
- /**
121
- * Queue an ordinary follow-up turn and wake the driver. The item becomes the
122
- * sole ordinary message of its own turn.
123
- * @param message - identified prompt content and the source that supplied it.
124
- */
125
- followup(message: UserMessage): void
126
-
127
- /**
128
- * Submit steering for the nearest step. An idle driver starts a turn;
129
- * a running driver consumes it at its next step boundary.
130
- * A rejected step leaves steering parked in the inbox until the next
131
- * wake; cancellation or disposal may discard pending steering.
132
- * @param message - identified steering content and the source that supplied it.
133
- */
134
- steer(message: UserMessage): void
135
-
136
- /**
137
- * Queue model-facing context for the next pre-step without waking the
138
- * driver. A running driver claims it at the nearest later step boundary;
139
- * idle drivers leave it pending until follow-up or steering
140
- * wakes them. It may miss a request whose pre-step already claimed its
141
- * batch. Cancellation or disposal may discard pending context.
142
- * @param message - identified injected context and the source that supplied it.
143
- */
144
- inject(message: UserMessage): void
145
- }
146
- ```
147
-
148
- ```ts type-equiv
149
- /**
150
- * An agent's lifecycle state, emitted on every transition as `agent/status`:
151
- * `idle` means no driver is active; `running` begins when waking input starts
152
- * cancellable pre-step processing and lasts while the driver drains,
153
- * closes, or checkpoints turns. Disposal removes the agent from its registry;
154
- * it is not a third observable status.
155
- */
156
- type AgentStatus = 'idle' | 'running'
157
- ```
158
-
159
- ```ts type-equiv
160
- /** One process-local live assistant streaming publication. */
161
- type AssistantStreamFrame =
162
- | {
163
- readonly type: 'start'
164
- readonly attemptId: LlmAttemptId
165
- /** Monotone within one attached Agent lifecycle; replacement restarts at 1. */
166
- readonly revision: number
167
- readonly turn: number
168
- readonly step: number
169
- }
170
- | {
171
- readonly type: 'chunk'
172
- readonly attemptId: LlmAttemptId
173
- readonly revision: number
174
- /** Dense zero-based position within the attempt. */
175
- readonly index: number
176
- /** Safe-integer timestamp reused by the durable embedded stream. */
177
- readonly time: number
178
- readonly chunk: StreamChunk
179
- }
180
- | {
181
- readonly type: 'end'
182
- readonly attemptId: LlmAttemptId
183
- readonly revision: number
184
- /** Number of chunk frames emitted by this attempt. */
185
- readonly index: number
186
- /** Durable settlement committed before this notification, or live abandonment without one. */
187
- readonly outcome:
188
- | {
189
- readonly kind: 'committed'
190
- readonly eventType: 'assistant/message' | 'assistant/attempt'
191
- readonly seq: SessionSeq
192
- }
193
- | { readonly kind: 'abandoned' }
194
- }
195
- ```
196
-
197
- `running` describes the driver-wide drain interval and may span consecutive queued turns; it does not prove a turn is still open. Disposal removes the agent from the registry and emits `agent/disposed`; it is not a terminal status value. `followup()` returns no handle: its `MessageId` identifies durable inbox insertion, claim, and discard facts, not a later assistant output or turn ending. `whenIdle()` observes the whole agent, so callers may call a receipt-to-idle interval a run only when they explicitly own that interval ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md)).
198
-
199
- ```ts type-equiv
200
- /** Merge-extensible agent creation options. Persona belongs to system-prompt sections. */
201
- interface AgentOptions {
202
- /** Provider route (must have a registered adapter at call time). */
203
- provider?: string
204
- /** Model id interpreted by the selected provider adapter. */
205
- model?: string
206
- /** Adapter-owned reasoning effort for the selected provider/model route. */
207
- reasoningEffort?: ReasoningEffortId
208
- /** Maximum output tokens for each conversation-model request. */
209
- maxTokens?: number
210
- }
211
- ```
212
-
213
- Dispatch requires `provider` and `model` after `agent/request`. An explicit `reasoningEffort` seeds the first request on that route; exact-model resolution validates it, while omission allows the adapter default to materialize. When present, `maxTokens` must be a positive safe integer and caps every conversation-model request; omission allows the exact-model adapter default to materialize before the request header, or otherwise leaves provider behavior unchanged. An agent-scoped `deployment:persona-prefix` prompt section may shadow the global default persona.
214
-
215
- The inbox is the delivery vocabulary — two ordered pending-message lists the agent owns as a durable projection:
216
-
217
- ```ts type-equiv
218
- /** Agent-owned access to pending work; concrete storage belongs to the driver. */
219
- interface Inbox {
220
- /** Prompts awaiting individual turns. */
221
- readonly nextTurn: readonly UserMessage[]
222
- /** Input awaiting the next step boundary. */
223
- readonly nextStep: readonly UserMessage[]
224
-
225
- /** Durably cancel all pending input, clearing next-step before next-turn. */
226
- clear(): void
227
-
228
- /**
229
- * Append one message to a pending list.
230
- * @param target - pending list to extend.
231
- * @param message - message to append.
232
- */
233
- append(target: InboxTarget, message: UserMessage): void
234
-
235
- /**
236
- * Prepend one message to a pending list.
237
- * @param target - pending list to extend.
238
- * @param message - message to prepend.
239
- */
240
- prepend(target: InboxTarget, message: UserMessage): void
241
-
242
- /**
243
- * Replace one pending message in place.
244
- * @param messageId - identity of the pending message to replace.
245
- * @param newMessage - replacement message.
246
- * @returns whether the message was still pending.
247
- */
248
- replace(messageId: MessageId, newMessage: UserMessage): boolean
249
-
250
- /**
251
- * Remove one pending message.
252
- * @param messageId - identity of the pending message to remove.
253
- * @returns whether the message was still pending.
254
- */
255
- remove(messageId: MessageId): boolean
256
-
257
- /**
258
- * Apply standard splice semantics and durably record the normalized result.
259
- * @param target - pending list to mutate.
260
- * @param start - splice position.
261
- * @param deleteCount - maximum number of messages to remove.
262
- * @param inserted - messages to insert at the resolved position.
263
- * @returns messages removed by the splice.
264
- */
265
- splice(
266
- target: InboxTarget,
267
- start: number,
268
- deleteCount: number,
269
- inserted: UserMessage[],
270
- ): UserMessage[]
271
- }
272
- ```
273
-
274
- ```ts type-equiv
275
- /** One of the two ordered pending-message lists owned by an agent. */
276
- type InboxTarget = 'next-turn' | 'next-step'
277
- ```
278
-
279
- Every pending occurrence is its `UserMessage`; `MessageId` is the sole identity. The structural `Inbox` methods record normalized durable `agent/inbox/spliced` mutations and reject duplicate pending ids. `replace(messageId, newMessage)` and `remove(messageId)` locate the pending message across both lists; replacement may change identity and emits the old message as discarded followed by the new message as inserted. Ordinary removals and `clear()` are cancellations. At a step boundary, dsh-agent-loop's package-internal `ReactLoopInbox` removes the proposed batch — all `next-step` input plus, at a turn boundary, one `next-turn` message — through pure deletion splices without discarded notifications, then emits per-message claimed notifications. Loop-only pending detection and claiming are not part of `Agent.inbox`. The `AgentLoop` service registers the standard `inbox` projection before publishing its factory; its cell is the sole live state, and the same fold serves cold consumers even when no Agent exists. The fold rejects unsafe or out-of-range splice coordinates and duplicate identities across both lists, identifying malformed durable history by event seq. Consumers following one message use the exact `agent/inbox/inserted`, `claimed`, and `discarded` notifications.
280
-
281
- Cancellation:
282
-
283
- ```ts type-equiv
284
- /** Options for {@link Agent.cancel}. */
285
- interface CancelOptions {
286
- /**
287
- * Preserve queued and steering inbox items instead of discarding them. The
288
- * active turn is still aborted, but un-started and pending work survives for a
289
- * later turn and no canceled inbox splice is logged.
290
- */
291
- keepInbox?: boolean | undefined
292
- }
293
- ```
294
-
295
- ```ts type-equiv
296
- /** Why an active agent driver was cancelled. */
297
- type AgentCancelCause =
298
- | { readonly kind: 'user' }
299
- | { readonly kind: 'parent' }
300
- | { readonly kind: 'hook'; readonly reason: string }
301
- | { readonly kind: 'disposed' }
302
- ```
303
-
304
- The cause is a TypeScript-enforced same-process input. An active cancellation holder exposes that same object as the runtime-only `AbortSignal.reason`; a signal grants cooperating listeners no classification authority. Durable `turn/end` records the outcome as `{ kind: 'aborted', reason: TurnEndCancelCause }`, so the cancel cause lands in the terminal result.
305
-
306
- The [event taxonomy](../index.md#events) owns the `agent/*` lifecycle, checkpoint, and waterfall contracts. Turn and step boundaries are durable session events rather than agent emits.
307
-
308
- ## Initiating Agent
309
-
310
- The process-local initiator carried by `ctx.agents` is the exact `Agent` above, not a separate frame or copied identity. Ambient presence is neither liveness proof nor authorization; the [initiator-scope decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md) defines its lifetime and scope rules.
311
-
312
- ## Interception decisions
313
-
314
- Pre-step decisions use the same identified `UserMessage` type as durable user-role input. The entered batch is authoritative and preserves every message's `id` and `source`. Hook bridges map their native decision fields onto this typed result.
315
-
316
- Source: [`packages/core/agent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
317
-
318
- `agent/pre-step` receives one payload carrying the exclusive claimed batch (`messages`), the proposed step's coordinates (`turn`, `step`), and the current turn's cancellation `signal`. The initial proposal runs inside an open turn before any step; a tool continuation may submit an empty claimed batch between steps:
319
-
320
- It returns a `PreStepDecision`. Reject opens no step. Enter supplies the complete message batch appended after `step/start`; claimed messages omitted by the final decision remain removed, while input inserted after the claim stays pending:
321
-
322
- ```ts type-equiv
323
- /** Whether and with which messages the loop enters a proposed step. */
324
- type PreStepDecision =
325
- | { kind: 'reject' }
326
- | {
327
- kind: 'enter'
328
- messages: UserMessage[]
329
- /** Start a distinct model-message series before this step's admitted messages. */
330
- startsRequestSeries?: true
331
- }
332
- ```
333
-
334
- `agent/request-error` runs after a failed model step closes and before its turn closes. Listeners can repair durable state or await policy work while the failed turn's signal is still live. A handling listener returns `{ kind: 'retry' }` without calling `next()`; the default `undefined` leaves the failure terminal.
335
-
336
- ```ts type-equiv
337
- /** Action returned by a listener that owns model-request recovery. */
338
- type RequestErrorAction = { kind: 'retry' } | undefined
339
- ```
340
-
341
- `agent/pre-step` is the only waterfall listener chain before request derivation. `agent/turn-stopping` runs when a turn has no tool or steering continuation, before one final steering drain.
342
-
343
- `agent/created` carries a `SessionStartSource` (why the session lifecycle began; a bridge keys its SessionStart matcher on it):
344
-
345
- ```ts type-equiv
346
- /** Why a session lifecycle began; seeded creates are `startup`, while persisted loads are `resume`. */
347
- type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
348
- ```
349
-
350
- ## Sessions
351
-
352
- A `Session` is an **append-only log** of typed `SessionEvent`s — the single source of truth. The LLM message history is *derived* from the log (`deriveMessages()`), not stored separately. Every entry carries a monotonic `seq`, a `time`, and a `type`-discriminated `data` payload; surface variants may also list cited earlier events in `sourceEventSeqs` and carry a `surfaceOp`.
353
-
354
- The `SessionEvent` envelope's exact conditional fields, the thirteen core event variants (`turn/start`, `turn/end`, `step/start`, `step/end`, `user/message`, `system/message`, `assistant/message`, `assistant/attempt`, `tool/call`, `tool/result`, `request/header`, `request/context`, `session/end-seed`), the `deriveMessages()` projection rules, the `TurnEndReason` reasons, and the execution-enclosure and standalone-event rules are on **[session.md](./session.md)**. How the log is made durable — the `SessionPersistence` interface, JSONL provider, `session/flush` checkpoint, crash recovery, and `SessionHeader` — is on **[persistence.md](./persistence.md)**.
355
-
356
- ## `ToolDefinition`
357
-
358
- The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional final-content and UI callbacks. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed arguments), but it is the contract the registry holds and the loop dispatches through.
359
-
360
- Its full fields, the `defineTool`/`ValueSchemaSpec`/`ParameterSchemaSpec` typed schema DSL, the `ToolExecution`/`ToolExecutionResult` waterfall types, and the tool-presentation UI types are on **[tools.md](./tools.md)**.
361
-
362
- ## Repo-wide type patterns
363
-
364
- Two patterns recur across every subsystem and are documented once, here.
365
-
366
- <a id="the-map--derived-union-pattern"></a>
367
-
368
- ### The `…Map → derived-union` pattern
369
-
370
- Almost every extensible sum type in the harness follows one pattern: an interface keyed by a discriminant tag (the `…Map`), from which the union is derived with `keyof`. Plugins add variants by **declaration merging** — no edit to the owning package.
371
-
372
- ```ts ignore-check
373
- // The pattern, schematically:
374
- interface ThingMap {
375
- 'a': { kind: 'a'; /* … */ }
376
- 'b': { kind: 'b'; /* … */ }
377
- }
378
- type ThingKind = keyof ThingMap // 'a' | 'b'
379
- type Thing = ThingMap[keyof ThingMap] // the discriminated union
380
-
381
- // A plugin extends it without touching the source package:
382
- declare module '@deepseek-ai/dsh-llm' {
383
- interface ThingMap {
384
- 'c': { kind: 'c'; /* … */ }
385
- }
386
- }
387
- ```
388
-
389
- Five canonical maps use this pattern; a plugin author extends these:
390
-
391
- | Map | Package | Derives | Catalog |
392
- |---|---|---|---|
393
- | `ContentBlockMap` | dsh-llm | `ContentBlock` | [llm-streaming.md](./llm-streaming.md#content-blocks-and-messages) |
394
- | `MessageSourceMap` | dsh-llm | `MessageSource` | [llm-streaming.md](./llm-streaming.md#content-blocks-and-messages) |
395
- | `FinishReasonMap` | dsh-llm | `FinishReason` | [llm-streaming.md](./llm-streaming.md#the-model-request-and-result) |
396
- | `TurnEndReasonMap` | dsh-session | `TurnEndReason` | [session.md](./session.md) |
397
- | `SessionEventMap` | dsh-session | `SessionEvent` | [session.md](./session.md) |
398
-
399
- Two large discriminated unions are the ones consumers `switch` over most: **`StreamChunk`** (the streaming protocol) and **`SessionEvent`** (the log entry). Per the repo convention, `switch` on the tag — don't chain `if`s — so each arm narrows and a typo'd tag fails to compile.
400
-
401
- ### Branded IDs
402
-
403
- IDs passed between packages are **branded** — structurally strings, but non-interchangeable at the type level (a `SessionId` cannot be passed where a `ToolCallId` is expected). Construction uses the shared `brandString<T>()` helper or an owner-defined validating factory; comparison, logging, and JSON behave as ordinary strings.
404
-
405
- The `Branded<B>` primitive and stateless constructor live in [dsh-brand](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/util/brand), which has no harness capability dependency. `brandString<T>()` applies a compile-time-only string brand.
406
-
407
- Source: [`packages/util/brand/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/util/brand/src/index.ts)
408
-
409
- ```ts type-equiv
410
- /** A string carrying a compile-time-only brand `B`. */
411
- type Branded<B extends string> = string & { readonly [BRAND]: B }
412
- ```
413
-
414
- The two core IDs are `ToolCallId` (correlates a tool call with its result; dsh-llm) and `SessionId` (the shared live agent and durable session identity; dsh-session). Capability packages brand their own ids too, such as `JobId` in [jobs.md](./jobs.md).
415
-
416
- <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
417
-
418
- <a id="cordis-surface"></a>
419
-
420
- ## Cordis API
421
-
422
- 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).
423
-
424
- <a id="ctxagentdefaultmodel--agentdefaultmodelconfig"></a>
425
-
426
- ### `ctx.agentDefaultModel` — `AgentDefaultModelConfig`
427
-
428
- Owns the default model selection independently of any Host or transport. Each operation reads the owning Config references.
429
-
430
- ```ts cordis-catalog
431
- /**
432
- * Read the current default model selection.
433
- * @returns a detached provider, model, and optional reasoning selection.
434
- */
435
- currentSelection(): ModelSelection
436
-
437
- /**
438
- * Save the complete default model selection. A deployment without a configuration
439
- * editor keeps its composition entry. Saves commit in submission order; a failed
440
- * save rejects its caller without blocking later saves.
441
- * @param next - resolved selection accepted by an entry point.
442
- * @returns fulfillment after the optional profile write settles.
443
- */
444
- async saveSelection(next: ModelSelection): Promise<void>
445
- ```
446
-
447
- Source: [`packages/core/agent-default-model/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-default-model/src/index.ts)
448
-
449
- <a id="ctxagentloop--agentloop"></a>
450
-
451
- ### `ctx.agentLoop` — `AgentLoop`
452
-
453
- Concrete agent factory and driver service.
454
-
455
- ```ts cordis-catalog
456
- /**
457
- * Create an agent and session under one caller-supplied identity, owned by
458
- * the accessing fiber. Constructor-driven config calls mint a fresh combined
459
- * id before entering this boundary. When a persistence backend is mounted,
460
- * the session's durable identity and any seed are stored before publication.
461
- * @param id - shared agent/session identity.
462
- * @param options - concrete loop options.
463
- * @param meta - optional fresh-session workspace metadata.
464
- * @returns the published running agent.
465
- */
466
- async create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd'> = {}): Promise<Agent>
467
-
468
- /**
469
- * Create an owned agent on a caller-supplied session id.
470
- * @param ownerCtx - caller context that structurally owns the lifecycle.
471
- * @param options - identities, optional live parent, session seed/metadata, loop options, setup, and cancellation.
472
- * @returns the published handle.
473
- */
474
- async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>
475
-
476
- /**
477
- * Resume an owned agent from the configured persistence service.
478
- * @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
479
- * @param options - persisted identity, optional live parent, loop options, setup, and cancellation.
480
- * @returns the published handle.
481
- */
482
- async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>
483
- ```
484
-
485
- Types: [SessionHeader](./persistence.md)
486
-
487
- Source: [`packages/core/agent-loop/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/src/index.ts)
488
-
489
- <a id="ctxagentpresets--agentpresetregistry"></a>
490
-
491
- ### `ctx.agentPresets` — `AgentPresetRegistry`
492
-
493
- Registry of YAML-declared presets and the revisions live Agents retain.
494
-
495
- ```ts cordis-catalog
496
- /** Register and eagerly load a definition; activation failure remains visible in the roster.
497
- * @param definition Parsed configuration supplied by the declaring plugin.
498
- * @returns Definition disposer after activation or its diagnostic settles; the declaring plugin owns it.
499
- */
500
- async register(definition: PresetDefinition): Promise<() => Promise<void>>
501
-
502
- /** Inspect retained revisions, or the exact revision an Agent joined.
503
- * @param ctx - optional Agent context; omission includes all retained revisions.
504
- * @returns detached module references and isolation diagnostics; no match returns an empty list.
505
- */
506
- inspectCompositions(ctx?: Context): AgentPresetInspection[]
507
-
508
- /** Read every declared preset, including activation failures.
509
- * @returns Display metadata and loading diagnostics.
510
- */
511
- async list(): Promise<AgentPreset[]>
512
-
513
- /** Read the selection roster.
514
- * @returns Current presets, each marked when it is the default.
515
- */
516
- @Remote('list') async remoteExportList(): Promise<AgentPresetRoster>
517
-
518
- /** Resolve an identity without starting an Agent.
519
- * @param id Explicit preset or the current default.
520
- * @returns Current metadata, including failure when activation failed.
521
- */
522
- async resolve(id?: string): Promise<AgentPreset>
523
-
524
- /** Read one declaration's child plugin list as YAML, for viewing only.
525
- * @param agentPreset Preset identity.
526
- * @returns The declared composition beside its published metadata.
527
- */
528
- @Remote('read') readDocument(agentPreset: string): Promise<AgentPresetDocument>
529
-
530
- /** Bind an unpublished Agent to the current preset revision.
531
- * @param ctx Agent context from its setup callback.
532
- * @param id Requested preset, or the default.
533
- * @returns Bound preset identity.
534
- */
535
- async mount(ctx: Context, id?: string): Promise<AgentPreset>
536
-
537
- /** Join a child to the exact revision retained by its parent.
538
- * @param ctx Child Agent context.
539
- * @param parent Parent Agent context.
540
- * @returns Inherited preset id, or undefined in a preset-free composition.
541
- */
542
- composeFrom(ctx: Context, parent: Context): string | undefined
543
-
544
- /** Read the preset a live Agent uses.
545
- * @param ctx Agent context.
546
- * @returns Its preset id, if bound.
547
- */
548
- composedPreset(ctx: Context): string | undefined
549
-
550
- /** Read a service supplied inside an Agent's isolated preset group.
551
- * @param agent Agent whose composition is queried.
552
- * @param name Cordis service name.
553
- * @returns The service, or undefined.
554
- */
555
- serviceFor<K extends string & keyof Context>(agent: { ctx: Context }, name: K): Context[K] | undefined
556
-
557
- /** Rebind a blank Agent; the caller owns the blank-session check.
558
- * @param ctx Agent context.
559
- * @param id Requested preset.
560
- * @returns The bound identity.
561
- */
562
- async recompose(ctx: Context, id: string): Promise<AgentPreset>
563
-
564
- /** Select a preset before a session starts its first turn. A Session whose
565
- * log records the preset and whose Agent runs its current revision keeps its
566
- * composition; nothing is logged or announced.
567
- * @param agent Target Agent.
568
- * @param agentPreset Requested identity.
569
- * @returns Committed preset identity.
570
- */
571
- @Remote('select') async select(agent: Agent, agentPreset: string): Promise<string>
572
-
573
- /** Read current registrations for cold transcript presentation.
574
- * @param id Preset identity or the default.
575
- * @returns A revision lease; dispose it after the scoped read completes.
576
- */
577
- async acquireScope(id?: string): Promise<{ key: ScopeKey } & AsyncDisposable>
578
-
579
- /** Read plugin rows without creating an Agent.
580
- * @returns Current declaration metadata and activation states.
581
- */
582
- compositionInventory(): Promise<AgentPresetComposition[]>
583
- ```
584
-
585
- Types: [ScopeKey](./scope.md)
586
-
587
- Source: [`packages/preset/agent-preset-registry/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/preset/agent-preset-registry/src/index.ts)
588
-
589
- <a id="ctxagents--agentregistry"></a>
590
-
591
- ### `ctx.agents` — `AgentRegistry`
592
-
593
- Agent service (`ctx.agents`): tracks live agents and carries the initiating Agent through one process-local asynchronous driver chain. Agent *creation* is provided by whichever plugin implements the AgentFactory (`@deepseek-ai/dsh-agent-loop`), registered via setFactory.
594
-
595
- Initiator methods provide same-process causal attribution only. Ambient presence is neither liveness proof nor authorization; subjects and owners remain explicit, as does identity at worker, process, persistence, and wire boundaries. Returned Promise boundaries drain during teardown, except a nested lineage that starts an owning-fiber unload is excluded from its own drain.
596
-
597
- ```ts cordis-catalog
598
- /**
599
- * Read the Agent that initiated the inherited asynchronous driver chain.
600
- * Use this optional form for logging, tracing, metrics, or host attribution
601
- * that also supports agentless calls. When a parent creates a child, setup
602
- * reports the causal parent while the setup callback's Agent parameter
603
- * identifies the child.
604
- * @returns the inherited Agent, or `undefined` outside an initiator boundary
605
- * and inside an explicit clearing boundary.
606
- * @throws when this service instance has been disposed.
607
- */
608
- currentInitiator(): Agent | undefined
609
-
610
- /**
611
- * Read the initiating Agent and fail when no initiator boundary is active.
612
- * Use this for private helpers contractually below a driver, or for a
613
- * deployment-owned outbound request whose contract forbids agentless calls.
614
- * Generic or direct-call paths use optional lookup or explicit request fields.
615
- * @returns the inherited Agent.
616
- * @throws when no initiator is active or this service instance has been disposed.
617
- */
618
- requireInitiator(): Agent
619
-
620
- /**
621
- * Run an operation with one exact Agent as its process-local initiator. The
622
- * exact synchronous value or Promise returned by the operation is preserved.
623
- * Custom drivers and test harnesses wrap their complete returned foreground
624
- * lifetime.
625
- * A queue or wire receiver may establish this boundary only after validating
626
- * explicit identity and resolving the exact live Agent; this method does neither.
627
- * Detached work remains owned by the subsystem that starts it.
628
- * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization.
629
- * @param operation - synchronous or asynchronous operation to invoke.
630
- * @returns the exact value returned by `operation`.
631
- * @throws when the initiator scope is closing/disposed, or when `operation` throws.
632
- */
633
- withInitiator<T>(agent: Agent, operation: () => T): T
634
-
635
- /**
636
- * Run an operation inside a boundary that hides any inherited initiating
637
- * Agent. The exact synchronous value or Promise is preserved.
638
- * Use this while creating lazy shared timers, queue pumps, pool maintenance,
639
- * watchers, or exporters so they do not inherit the first Agent that happens
640
- * to initialize them. It clears only initiator attribution, not explicit
641
- * fields, and does not own or drain detached resources.
642
- * @param operation - synchronous or asynchronous operation to invoke without an initiator.
643
- * @returns the exact value returned by `operation`.
644
- * @throws when the initiator scope is closing/disposed, or when `operation` throws.
645
- */
646
- withoutInitiator<T>(operation: () => T): T
647
-
648
- /**
649
- * Register the agent-creation factory (the loop calls this on construction,
650
- * effect-scoped). A traced Cordis service is canonicalized to its concrete
651
- * target; each create/resume call is then traced through that caller's
652
- * context so ownership follows the caller without stacking proxy layers.
653
- * Throws if a factory is already registered. Returns the disposer; on
654
- * dispose the factory slot is cleared.
655
- * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to.
656
- * @returns the disposer that clears the factory slot. The exact
657
- * Cordis effect disposer (single-shot): composite (generator) effects may
658
- * yield it directly — exact identity nests the teardown in order.
659
- */
660
- setFactory(factory: AgentFactory): () => void
661
-
662
- /**
663
- * Create and publish a new agent through the registered factory.
664
- * Distinct from {@link register} (which records an already-constructed
665
- * agent): this constructs the agent and its session. Rejects if no factory is
666
- * registered or creation/setup fails. The resolved {@link AgentHandle} lets
667
- * the owner tear down exactly this agent.
668
- * @param options - shared identity, optional live parent, session seed/metadata, and agent options.
669
- * @returns the handle after setup, rollback-covered publication, and loop start complete.
670
- */
671
- async create(options: CreateAgentOptions): Promise<AgentHandle>
672
-
673
- /**
674
- * Load a persisted session and resume an agent on it through the registered
675
- * factory. Rejects if no factory is registered; the factory rejects if
676
- * session persistence is not configured or persistence/setup fails.
677
- * @param options - persisted identity, optional live parent, configuration, and setup.
678
- * @returns the handle after setup, rollback-covered publication, and loop start complete.
679
- */
680
- async resume(options: ResumeAgentOptions): Promise<AgentHandle>
681
-
682
- /**
683
- * Register a live agent with source `startup`. Rejects if the id is already registered or a
684
- * serial `agent/created` listener fails. Emits `agent/disposed`
685
- * when the calling fiber is disposed — both with the agent's scope carrier
686
- * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the
687
- * emits are scope-filtered regardless of which context invoked `register`
688
- * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always
689
- * requires passing the carrier). The entry is a runtime root; factory-backed
690
- * creation uses `options.parentAgent` for child ownership. Await the registration before using the agent.
691
- * @param agent - the already-constructed agent to record in the store.
692
- * @returns the awaitable Cordis effect disposer (single-shot; a repeat call
693
- * returns undefined without awaiting an in-flight teardown). Exact
694
- * identity is load-bearing: a composite (generator) effect that owns a
695
- * teardown ORDER — the agent factory's lifecycle chain — must yield THIS
696
- * function so Cordis nests the unregistration at that yield position;
697
- * yielding a wrapper would leave it disposing as a concurrent sibling on
698
- * owner unload, unregistering the agent (and emitting `agent/disposed`)
699
- * while its final turn is still draining.
700
- */
701
- register(agent: Agent): ReturnType<Context['effect']>
702
-
703
- /**
704
- * Insert an already-constructed agent without announcing it. This is the
705
- * advanced ordered-lifecycle primitive used by the async agent factory: it
706
- * first completes setup while the agent is unpublished, then assigns the
707
- * returned detach closure into its pre-installed composite teardown before
708
- * calling {@link announce}. Ordinary callers use {@link register}.
709
- * @param agent - the prepared, unpublished agent.
710
- * @param owner - explicitly supplied live runtime owner, or
711
- * undefined for a top-level runtime root. This is runtime ownership, not
712
- * the resumed session's durable parent lineage.
713
- * @returns an idempotent closure that removes this exact entry and emits
714
- * `agent/disposed` with listener failures contained. When called from a
715
- * `agent/created` listener, removal and disposal wait until the serial
716
- * creation dispatch settles.
717
- */
718
- enter(agent: Agent, owner: Agent | undefined): () => void
719
-
720
- /**
721
- * Announce an agent previously inserted with {@link enter}.
722
- * @param agent - the live inserted agent to announce.
723
- * @param source - fresh creation, resume, clear, or compaction source.
724
- * @param signal - optional factory initialization cancellation signal passed to listeners.
725
- * @returns completion of the serial creation listeners; a listener failure rejects.
726
- * @throws if `agent` is not the exact live registry entry for its id, or its
727
- * creation announcement already began (including a reentrant call from a
728
- * creation listener).
729
- */
730
- async announce(agent: Agent, source: SessionStartSource, signal?: AbortSignal): Promise<void>
731
-
732
- /**
733
- * Look up a live agent.
734
- * @param id - the shared agent/session id to look up.
735
- * @returns the agent, or undefined when no live agent has that id.
736
- */
737
- get(id: SessionId): Agent | undefined
738
-
739
- /**
740
- * Test whether a live agent was created through one exact parent agent's
741
- * scoped context. Runtime ownership is independent of durable session
742
- * lineage and remains unambiguous when unrelated providers reuse an id.
743
- * @param id - the candidate child agent's shared agent/session id.
744
- * @param owner - the expected runtime creator agent.
745
- * @returns true only while the exact child entry is live under that owner.
746
- */
747
- isOwnedBy(id: SessionId, owner: Agent): boolean
748
-
749
- /**
750
- * All live agents, in registration order.
751
- * @returns a fresh array; mutating it does not affect the registry.
752
- */
753
- list(): Agent[]
754
-
755
- /**
756
- * All live top-level agents in registration order. A top-level agent was
757
- * created without an owning agent context; durable session lineage does not
758
- * affect this runtime relation, so a resumed fork may still be a root.
759
- * @returns a fresh array; mutating it does not affect the registry.
760
- */
761
- roots(): Agent[]
762
- ```
763
-
764
- Source: [`packages/core/agent/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/index.ts)
765
-
766
- <a id="agent-events"></a>
767
-
768
- ### `agent/*` events
769
-
770
- <a id="agentassistant-stream--emit"></a>
771
-
772
- #### `agent/assistant-stream` — emit
773
-
774
- Process-local assistant-stream publication. Chunk frames are transient; the loop appends one final v2 `assistant/message` or `assistant/attempt` with the same stream before a committed end frame.
775
-
776
- ```ts cordis-catalog
777
- /**
778
- * Process-local assistant-stream publication. Chunk frames are transient;
779
- * the loop appends one final v2 `assistant/message` or `assistant/attempt`
780
- * with the same stream before a committed end frame.
781
- * @param payload.agent - the agent whose attempt produced the frame.
782
- * @param payload.frame - one ordered start, chunk, or end publication.
783
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
784
- * @mode emit
785
- */
786
- 'agent/assistant-stream'(this: Scoped<Agent>, payload: { agent: Agent; frame: AssistantStreamFrame }): void
787
- ```
788
-
789
- Types: [Scoped](./scope.md)
790
-
791
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
792
-
793
- <a id="agentcreated--serial"></a>
794
-
795
- #### `agent/created` — serial
796
-
797
- An entered agent is ready for per-agent initialization after factory setup. Listeners run in order and are awaited before creation resolves. AgentLoop holds queued input until all listeners finish. A throw or rejection fails creation and skips later listeners. Disposal retains the scope and session until dispatch settles; listeners must not await agent.whenIdle() or their own owner's disposal.
798
-
799
- ```ts cordis-catalog
800
- /**
801
- * An entered agent is ready for per-agent initialization after factory setup.
802
- * Listeners run in order and are awaited before creation resolves. AgentLoop
803
- * holds queued input until all listeners finish. A throw or rejection fails
804
- * creation and skips later listeners. Disposal retains the scope and session
805
- * until dispatch settles; listeners must not await agent.whenIdle() or their
806
- * own owner's disposal.
807
- * @param payload.agent - the newly registered agent with its live session and completed setup.
808
- * @param payload.source - fresh creation, resume, clear, or compaction source.
809
- * @param payload.signal - factory initialization cancellation signal, when provided.
810
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
811
- * @mode serial
812
- */
813
- 'agent/created'(this: Scoped<Agent>, payload: { agent: Agent; source: SessionStartSource; signal?: AbortSignal }): undefined | Promise<undefined>
814
- ```
815
-
816
- Types: [Scoped](./scope.md)
817
-
818
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
819
-
820
- <a id="agentdisposed--emit"></a>
821
-
822
- #### `agent/disposed` — emit
823
-
824
- An agent left the registry; AgentLoop emits this after driver quiescence and scoped-registration unwind, but before session detachment. Custom registry users own their driver-ordering contract.
825
-
826
- ```ts cordis-catalog
827
- /**
828
- * An agent left the registry; AgentLoop emits this after driver quiescence
829
- * and scoped-registration unwind, but before session detachment. Custom
830
- * registry users own their driver-ordering contract.
831
- * @param payload.agent - the exact agent removed from the registry.
832
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
833
- * @mode emit
834
- */
835
- 'agent/disposed'(this: Scoped<Agent>, payload: { agent: Agent }): void
836
- ```
837
-
838
- Types: [Scoped](./scope.md)
839
-
840
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
841
-
842
- <a id="agenterror--emit"></a>
843
-
844
- #### `agent/error` — emit
845
-
846
- A step or turn errored. The machine reports a failure here even when the error has no in-turn position for a durable record.
847
-
848
- ```ts cordis-catalog
849
- /**
850
- * A step or turn errored. The machine reports a failure here even when
851
- * the error has no in-turn position for a durable record.
852
- * @param payload.agent - the agent whose turn errored.
853
- * @param payload.turn - the turn in which the failure surfaced.
854
- * @param payload.step - the step at which the failure surfaced.
855
- * @param payload.error - the failure, verbatim.
856
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
857
- * @mode emit
858
- */
859
- 'agent/error'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; step: number; error: unknown }): void
860
- ```
861
-
862
- Types: [Scoped](./scope.md)
863
-
864
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
865
-
866
- <a id="agentinboxclaimed--emit"></a>
867
-
868
- #### `agent/inbox/claimed` — emit
869
-
870
- One message left the inbox inside its open turn. If the proposed step is rejected, the claimed message ends here: it is neither discarded nor re-emitted as a user/message, and the turn closes without a step.
871
-
872
- ```ts cordis-catalog
873
- /**
874
- * One message left the inbox inside its open turn. If the proposed step
875
- * is rejected, the claimed message ends here: it is neither discarded nor
876
- * re-emitted as a user/message, and the turn closes without a step.
877
- * @param payload.agent - the agent whose inbox changed.
878
- * @param payload.message - the claimed message.
879
- * @param payload.turn - the owning turn.
880
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
881
- * @mode emit
882
- */
883
- 'agent/inbox/claimed'(this: Scoped<Agent>, payload: { agent: Agent; message: UserMessage; turn: number }): void
884
- ```
885
-
886
- Types: [Scoped](./scope.md) · [UserMessage](./session.md)
887
-
888
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
889
-
890
- <a id="agentinboxdiscarded--emit"></a>
891
-
892
- #### `agent/inbox/discarded` — emit
893
-
894
- One message was discarded from the live inbox.
895
-
896
- ```ts cordis-catalog
897
- /**
898
- * One message was discarded from the live inbox.
899
- * @param payload.agent - the agent whose inbox changed.
900
- * @param payload.message - the discarded message.
901
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
902
- * @mode emit
903
- */
904
- 'agent/inbox/discarded'(this: Scoped<Agent>, payload: { agent: Agent; message: UserMessage }): void
905
- ```
906
-
907
- Types: [Scoped](./scope.md) · [UserMessage](./session.md)
908
-
909
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
910
-
911
- <a id="agentinboxinserted--emit"></a>
912
-
913
- #### `agent/inbox/inserted` — emit
914
-
915
- One message entered the live inbox.
916
-
917
- ```ts cordis-catalog
918
- /**
919
- * One message entered the live inbox.
920
- * @param payload.agent - the agent whose inbox changed.
921
- * @param payload.message - the inserted message.
922
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
923
- * @mode emit
924
- */
925
- 'agent/inbox/inserted'(this: Scoped<Agent>, payload: { agent: Agent; message: UserMessage }): void
926
- ```
927
-
928
- Types: [Scoped](./scope.md) · [UserMessage](./session.md)
929
-
930
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
931
-
932
- <a id="agentpre-step--waterfall"></a>
933
-
934
- #### `agent/pre-step` — waterfall
935
-
936
- Reject a proposed step or replace the messages that enter it. Calling `next()` preserves the current messages.
937
-
938
- ```ts cordis-catalog
939
- /**
940
- * Reject a proposed step or replace the messages that enter it. Calling
941
- * `next()` preserves the current messages.
942
- * @param payload.agent - the agent proposing the step.
943
- * @param payload.messages - messages removed from the inbox for this step.
944
- * @param payload.turn - the turn that will own the step.
945
- * @param payload.step - the step proposed by the loop.
946
- * @param payload.signal - the current turn's cancellation signal.
947
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
948
- * @mode waterfall
949
- */
950
- 'agent/pre-step'(this: Scoped<Agent>, payload: { agent: Agent; messages: UserMessage[]; turn: number; step: number; signal: AbortSignal }, next: () => Promise<PreStepDecision>): Promise<PreStepDecision>
951
- ```
952
-
953
- Types: [Scoped](./scope.md) · [UserMessage](./session.md)
954
-
955
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
956
-
957
- <a id="agentrequest--waterfall"></a>
958
-
959
- #### `agent/request` — waterfall
960
-
961
- Replace the frozen call configuration. `await next()` yields the config the machine would use (agent options on the first request, the logged header afterwards); return a replacement to switch. On step admission, this runs after assembly and `step/start`, before the system prompt and accepted user batch are committed. Cancellation here or during subsequent `prepareCall()` resolution commits neither. The prepared call capability governs prompt admission. Model-visible content must use logged channels; this waterfall cannot mutate messages.
962
-
963
- ```ts cordis-catalog
964
- /**
965
- * Replace the frozen call configuration. `await next()` yields the config
966
- * the machine would use (agent options on the first request, the logged
967
- * header afterwards); return a replacement to switch. On step admission,
968
- * this runs after assembly and `step/start`, before the system prompt and
969
- * accepted user batch are committed. Cancellation here or during subsequent
970
- * `prepareCall()` resolution commits neither. The prepared call capability
971
- * governs prompt admission. Model-visible content must use logged channels;
972
- * this waterfall cannot mutate messages.
973
- * @param payload.agent - the agent making the model call.
974
- * @param payload.turn - the open turn number.
975
- * @param payload.step - the step whose request this is.
976
- * @param payload.signal - the current turn's explicit abort signal.
977
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
978
- * @mode waterfall
979
- */
980
- 'agent/request'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; step: number; signal: AbortSignal }, next: () => Promise<LlmCallConfig>): Promise<LlmCallConfig>
981
- ```
982
-
983
- Types: [LlmCallConfig](./llm-streaming.md) · [Scoped](./scope.md)
984
-
985
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
986
-
987
- <a id="agentrequest-error--waterfall"></a>
988
-
989
- #### `agent/request-error` — waterfall
990
-
991
- Handle one failed model-request attempt before the loop retries or closes its step. A listener returns `{ kind: 'retry' }` without calling `next()` when it owns recovery, or calls `next()` to delegate. The default `undefined` leaves the failure terminal.
992
-
993
- ```ts cordis-catalog
994
- /**
995
- * Handle one failed model-request attempt before the loop retries or closes
996
- * its step. A listener returns `{ kind: 'retry' }` without calling `next()`
997
- * when it owns recovery, or calls `next()` to delegate. The default
998
- * `undefined` leaves the failure terminal.
999
- * @param payload.agent - the agent whose request failed.
1000
- * @param payload.turn - the turn containing the failed request.
1001
- * @param payload.step - the step containing the failed request attempt.
1002
- * @param payload.provider - the provider selected for the failed request.
1003
- * @param payload.failure - serializable facts normalized at the final adapter boundary.
1004
- * @param payload.retryPolicy - the policy of the adapter registration that served the failed request.
1005
- * @param payload.signal - the turn abort signal.
1006
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1007
- * @mode waterfall
1008
- */
1009
- 'agent/request-error'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; step: number; provider: string; failure: LlmFailure; retryPolicy: ResolvedRetryPolicy | undefined; signal: AbortSignal }, next: () => Promise<RequestErrorAction>): Promise<RequestErrorAction>
1010
- ```
1011
-
1012
- Types: [LlmFailure](./llm-streaming.md) · [ResolvedRetryPolicy](./llm-streaming.md) · [Scoped](./scope.md)
1013
-
1014
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1015
-
1016
- <a id="agentstatus--emit"></a>
1017
-
1018
- #### `agent/status` — emit
1019
-
1020
- Agent status changed (`idle` ⇄ `running`). A waking delivery enters `running` synchronously after reserving cancellation; `idle` means no driver remains scheduled or active.
1021
-
1022
- ```ts cordis-catalog
1023
- /**
1024
- * Agent status changed (`idle` ⇄ `running`). A waking delivery enters
1025
- * `running` synchronously after reserving cancellation; `idle` means no
1026
- * driver remains scheduled or active.
1027
- * @param payload.agent - the agent whose status flipped.
1028
- * @param payload.status - the status just entered (the transition's destination).
1029
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1030
- * @mode emit
1031
- */
1032
- 'agent/status'(this: Scoped<Agent>, payload: { agent: Agent; status: AgentStatus }): void
1033
- ```
1034
-
1035
- Types: [Scoped](./scope.md)
1036
-
1037
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1038
-
1039
- <a id="agentturn-stopping--serial"></a>
1040
-
1041
- #### `agent/turn-stopping` — serial
1042
-
1043
- The turn is about to close: the model owes no response (no live tool calls, no fresh steering). Awaited before the boundary commits — a listener that objects steers (`agent.steer(...)`) and the machine re-reads its inbox: fresh steering runs another step, none closes the turn. Data decides, so listener order cannot change the outcome. The inverse control (stop a tool loop early) is data too: a tool result carrying `concludesTurn` ends the turn at its step. The conclusion never short-circuits already-submitted next-step work: same-step `additionalContexts` or racing steering still runs, and the turn closes only when that inbox drains.
1044
-
1045
- ```ts cordis-catalog
1046
- /**
1047
- * The turn is about to close: the model owes no response (no live tool
1048
- * calls, no fresh steering). Awaited before the boundary commits — a
1049
- * listener that objects steers (`agent.steer(...)`) and the machine
1050
- * re-reads its inbox: fresh steering runs another step, none closes the
1051
- * turn. Data decides, so listener order cannot change the outcome. The
1052
- * inverse control (stop a tool loop early) is data too: a tool result
1053
- * carrying `concludesTurn` ends the turn at its step. The conclusion
1054
- * never short-circuits already-submitted next-step work: same-step
1055
- * `additionalContexts` or racing steering still runs, and the turn
1056
- * closes only when that inbox drains.
1057
- * @param payload.agent - the agent whose turn is at its stop boundary.
1058
- * @param payload.turn - the turn about to close.
1059
- * @param payload.signal - the current turn's explicit abort signal.
1060
- * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1061
- * @mode serial
1062
- */
1063
- 'agent/turn-stopping'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; signal: AbortSignal }): Promise<void> | void
1064
- ```
1065
-
1066
- Types: [Scoped](./scope.md)
1067
-
1068
- Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1069
-
1070
- <a id="agent-loop-events"></a>
1071
-
1072
- ### `agent-loop/*` events
1073
-
1074
- <a id="agent-loopconfig-start-failed--emit"></a>
1075
-
1076
- #### `agent-loop/config-start-failed` — emit
1077
-
1078
- A declarative agent entry failed before it could publish a live agent. Consumers that buffer work for the configured identity use this transient signal to reject that work instead of waiting forever. Normal factory teardown suppresses failures from the cancelled startup attempt.
1079
-
1080
- ```ts cordis-catalog
1081
- /**
1082
- * A declarative agent entry failed before it could publish a live agent.
1083
- * Consumers that buffer work for the configured identity use this
1084
- * transient signal to reject that work instead of waiting forever. Normal
1085
- * factory teardown suppresses failures from the cancelled startup attempt.
1086
- * @param payload.sessionId - exact shared agent/session identity that failed startup.
1087
- * @param payload.error - persistence, setup, or publication failure.
1088
- * @mode emit
1089
- */
1090
- 'agent-loop/config-start-failed'(payload: { sessionId: SessionId; error: unknown }): void
1091
- ```
1092
-
1093
- Source: [`packages/core/agent-loop/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/src/index.ts)
1094
-
1095
- <a id="agent-preset-events"></a>
1096
-
1097
- ### `agent-preset/*` events
1098
-
1099
- <a id="agent-presetselected--emit"></a>
1100
-
1101
- #### `agent-preset/selected` — emit
1102
-
1103
- One session committed a different agent preset to its durable log. Consumers invalidate only state derived from that session's composition.
1104
-
1105
- ```ts cordis-catalog
1106
- /**
1107
- * One session committed a different agent preset to its durable log.
1108
- * Consumers invalidate only state derived from that session's composition.
1109
- * @mode emit
1110
- * @param sessionId - the session whose composition changed.
1111
- * @param agentPreset - the preset recorded by the committed selection.
1112
- */
1113
- 'agent-preset/selected'(sessionId: SessionId, agentPreset: string): void
1114
- ```
1115
-
1116
- Source: [`packages/preset/agent-preset-registry/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/preset/agent-preset-registry/src/types.ts)
1117
- <!-- END GENERATED cordis-surface -->
1
+ ---
2
+ editSource: "docs/subsystems/core.md"
3
+ rawMarkdownPath: "en/reference/subsystems/core.md"
4
+ outline: [2,3]
5
+ ---
6
+
7
+ # Core
8
+
9
+ The **core** subsystem is [`packages/core`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/README.md) — the packages every composition boots: the event-sourced session log, system-prompt assembly, the tool registry, the agent types, and the concrete loop that drives them. This page explains what the `agent`/`agent-loop` pair declares — how an agent is created and owned, and the `Agent` handle's delivery, cancellation, and interception contracts — plus the two type patterns every subsystem follows. The group's dedicated pages and the rest of the folder are indexed in the [subsystems README](./index.md).
10
+
11
+ ## The spine, package by package
12
+
13
+ A turn flows through the six packages in one loop: the driver in [`agent-loop`](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/agent-loop) claims a queued prompt, opens a turn on the [session log](./session.md) (`ctx.sessions`), assembles the request prefix through [system-prompt](./system-prompt.md) (`ctx.systemPrompt`) and derives history from the log, streams the model response through the [LLM seam](./llm-streaming.md), dispatches tool calls through the [tool registry](./tools.md) (`ctx.tools`), and appends every model-visible fact back onto the log before the next step derives from it. The conversation vocabulary the loop moves — `Message`, `ContentBlock`, `StreamChunk`, the model request — is declared by [`packages/llm`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/README.md) and documented on [llm-streaming.md](./llm-streaming.md).
14
+
15
+ | Package | Owns | Page |
16
+ |---|---|---|
17
+ | `session/` | The append-only `SessionEvent` log and in-memory store — the single source of truth (`ctx.sessions`) | [session.md](./session.md) |
18
+ | `system-prompt/` | Prompt-section and tool-schema assembly (`ctx.systemPrompt`) | [system-prompt.md](./system-prompt.md) |
19
+ | `tools/` | The scoped tool registry and guarded execution pipeline (`ctx.tools`) | [tools.md](./tools.md) |
20
+ | `agent/` | The `Agent` interface, live registry, initiator scope, and `agent/*` event vocabulary (`ctx.agents`) | this page |
21
+ | `agent-loop/` | The concrete driver implementing the public `Agent` contract (`ctx.agentLoop`) | this page |
22
+ | `scope/` | The scoped-registration primitive the registries and loop build per-agent scoping on | [scope.md](./scope.md) |
23
+
24
+ `scope/` is the one non-service package: a dependency-free library (`createScope`/`scopeOf`/`scopeTarget`) that sits below `session/` and `system-prompt/` in the module graph precisely so they can consume it without a cycle. `agent-loop` is the one concrete implementation of the public `Agent` contract and lives here because it is the harness's default product loop; it runs each driver inside `ctx.agents.withInitiator()`. Extension plugins depend on `agent` — including when they need the initiating Agent — and never on `agent-loop` directly, so the loop stays swappable. [`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.md) is the default product composition, while [`dsh-sdk-minimal`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-minimal/README.md) declares a smaller standalone tree.
25
+
26
+ ## Creation and ownership
27
+
28
+ Consumers create agents through `ctx.agents` — `create()` builds a fresh session and agent under one caller-supplied `SessionId`, `resume()` loads a persisted session first — or declaratively through the loop's config entries. Programmatic creation returns the owner's handle:
29
+
30
+ Source: [`packages/core/agent/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/index.ts)
31
+
32
+ ```ts type-equiv
33
+ /**
34
+ * An owned agent plus its disposer, returned by {@link AgentRegistry.create} /
35
+ * {@link AgentRegistry.resume}. The disposer is a CAPABILITY: among consumers,
36
+ * only the holder can tear this agent down. The registered factory provider is
37
+ * also a structural owner because the scoped agent depends on that provider's
38
+ * service API; provider unload stops and drains every live handle it made.
39
+ * `dispose()` stops the loop, awaits its exit, unregisters the agent, removes
40
+ * its session from the store, and finally unwinds its scoped world.
41
+ *
42
+ * `ctx.agents.get(id)` still returns a bare {@link Agent} — the handle is
43
+ * exposed only to the consumer owner that created it; the structural provider
44
+ * reaches the same teardown internally. Config-created agents (the loop's own
45
+ * startup) are owned by the loop fiber and never need a handle.
46
+ */
47
+ interface AgentHandle {
48
+ agent: Agent
49
+ dispose(): Promise<void>
50
+ }
51
+ ```
52
+
53
+ `CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) receives `(agentCtx, agent)` after Session store entry and completed `session/created`, before Agent registration: the context owns scoped registrations, while the explicit Agent supplies the exact child Session without a reverse property on the Context. Everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly. Setup may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal unwinds the transaction, removes the Session, and preserves restored pending input and already stored events.
54
+
55
+ `AgentFactory` is the creation interface behind the registry: the loop registers its factory via `ctx.agents.setFactory()`, so consumers use `ctx.agents` without depending on the concrete loop package. The registry passes creation options and the caller Context to the factory; the caller Context owns the returned handle's lifetime. The exact `create`/`resume` signatures and rollback contracts are in the [generated section](#ctxagents--agentregistry) below.
56
+
57
+ ## The agent handle
58
+
59
+ `Agent` is the surface every plugin (UI, hooks, orchestrators) programs against; `ctx.agents.get(id)` returns it, and the [initiator scope](#initiating-agent) carries it. The concrete implementation is package-internal to dsh-agent-loop; nothing outside the loop depends on it. The unified `send` method exposes target and wakeup routing directly; `followup`, `steer`, and `inject` are fixed-preset aliases.
60
+
61
+ Source: [`packages/core/agent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
62
+
63
+ ```ts type-equiv
64
+ /** Public live-agent handle; the runtime face augments its live capabilities. */
65
+ interface Agent {
66
+ /** Session-backed Agent identity. */
67
+ readonly id: SessionId
68
+ /** Route fallback and output controls; live accessors apply until the Session records a selection or request. */
69
+ readonly options: AgentOptions
70
+ /** The live session this agent drives; its log is the durable source of truth. */
71
+ readonly session: Session
72
+ /** Agent-owned access to durable model selection for future steps. */
73
+ readonly model: Model
74
+ /** Agent-owned access to durable pending work. */
75
+ readonly inbox: Inbox
76
+ /** The current lifecycle state, mirrored on every `agent/status` transition. */
77
+ readonly status: AgentStatus
78
+ /** Agent-scoped context; its contributions are agent-local, unwind on disposal, and reject registration afterward. */
79
+ readonly ctx: Context
80
+
81
+ /**
82
+ * Clear queued and steering work — unless `keepInbox` — and abort the active
83
+ * turn or between-turn task. The first cause wins for that activity. With no
84
+ * active activity, cancellation is a no-op and does not arm later work.
85
+ * Queue-write failures still abort the activity and propagate to the caller.
86
+ * @param cause - the stable caller intent carried by the active operation signal.
87
+ * @param options - cancellation options; `keepInbox` preserves pending work.
88
+ */
89
+ cancel(cause: AgentCancelCause, options?: CancelOptions): void
90
+
91
+ /**
92
+ * Resolve after the current whole-agent activity reaches quiescence. This
93
+ * follows replacement work started before the observed driver retires,
94
+ * but does not identify the settlement of any particular message.
95
+ * @returns fulfillment after no active driver or maintenance task remains.
96
+ */
97
+ whenIdle(): Promise<void>
98
+
99
+ /**
100
+ * Run one non-turn maintenance task from the true idle phase. The task starts
101
+ * synchronously after claiming that phase; later waking input remains in the
102
+ * inbox until the task settles, while public status stays `idle`.
103
+ * `whenIdle()` follows both the task and any waking work released behind it.
104
+ * @param task - operation whose fulfillment or rejection is preserved, with a signal aborted by {@link cancel}.
105
+ * @throws synchronously when turn-driving or another maintenance task already owns the agent.
106
+ * @returns the task promise.
107
+ */
108
+ runMaintenance<T>(task: (signal: AbortSignal) => Promise<T>): Promise<T>
109
+
110
+ /**
111
+ * Route identified input to an inbox boundary and optionally wake the driver.
112
+ * Waking input submitted after active cancellation is queued for the next
113
+ * turn and runs when the aborted activity converges to idle; a `disposed`
114
+ * cancel leaves it parked. A wake submitted while already idle always opens
115
+ * its turn boundary, even when its message is cleared before the driver
116
+ * claims ([driver wake convergence](../../agent-loop/src/agent.ts)).
117
+ * @param message - identified content and the source that supplied it.
118
+ * @param target - the preferred next-turn or next-step inbox boundary.
119
+ * @param wakeup - whether delivery may wake the driver.
120
+ */
121
+ send(message: UserMessage, target: InboxTarget, wakeup: boolean): void
122
+
123
+ /**
124
+ * Queue an ordinary follow-up turn and wake the driver. The item becomes the
125
+ * sole ordinary message of its own turn.
126
+ * @param message - identified prompt content and the source that supplied it.
127
+ */
128
+ followup(message: UserMessage): void
129
+
130
+ /**
131
+ * Submit steering for the nearest step. An idle driver starts a turn;
132
+ * a running driver consumes it at its next step boundary.
133
+ * A rejected step leaves steering parked in the inbox until the next
134
+ * wake; cancellation or disposal may discard pending steering.
135
+ * @param message - identified steering content and the source that supplied it.
136
+ */
137
+ steer(message: UserMessage): void
138
+
139
+ /**
140
+ * Queue model-facing context for the next pre-step without waking the
141
+ * driver. A running driver claims it at the nearest later step boundary;
142
+ * idle drivers leave it pending until follow-up or steering
143
+ * wakes them. It may miss a request whose pre-step already claimed its
144
+ * batch. Cancellation or disposal may discard pending context.
145
+ * @param message - identified injected context and the source that supplied it.
146
+ */
147
+ inject(message: UserMessage): void
148
+ }
149
+ ```
150
+
151
+ ```ts type-equiv
152
+ /**
153
+ * An agent's lifecycle state, emitted on every transition as `agent/status`:
154
+ * `idle` means no driver is active; `running` begins when waking input starts
155
+ * cancellable pre-step processing and lasts while the driver drains,
156
+ * closes, or checkpoints turns. Disposal removes the agent from its registry;
157
+ * it is not a third observable status.
158
+ */
159
+ type AgentStatus = 'idle' | 'running'
160
+ ```
161
+
162
+ ```ts type-equiv
163
+ /** One process-local live assistant streaming publication. */
164
+ type AssistantStreamFrame =
165
+ | {
166
+ readonly type: 'start'
167
+ readonly attemptId: LlmAttemptId
168
+ /** Monotone within one attached Agent lifecycle; replacement restarts at 1. */
169
+ readonly revision: number
170
+ readonly turn: number
171
+ readonly step: number
172
+ }
173
+ | {
174
+ readonly type: 'chunk'
175
+ readonly attemptId: LlmAttemptId
176
+ readonly revision: number
177
+ /** Dense zero-based position within the attempt. */
178
+ readonly index: number
179
+ /** Safe-integer timestamp reused by the durable embedded stream. */
180
+ readonly time: number
181
+ readonly chunk: StreamChunk
182
+ }
183
+ | {
184
+ readonly type: 'end'
185
+ readonly attemptId: LlmAttemptId
186
+ readonly revision: number
187
+ /** Number of chunk frames emitted by this attempt. */
188
+ readonly index: number
189
+ /** Durable settlement committed before this notification, or live abandonment without one. */
190
+ readonly outcome:
191
+ | {
192
+ readonly kind: 'committed'
193
+ readonly eventType: 'assistant/message' | 'assistant/attempt'
194
+ readonly seq: SessionSeq
195
+ }
196
+ | { readonly kind: 'abandoned' }
197
+ }
198
+ ```
199
+
200
+ `running` describes the driver-wide drain interval and may span consecutive queued turns; it does not prove a turn is still open. Disposal removes the agent from the registry and emits `agent/disposed`; it is not a terminal status value. `followup()` returns no handle: its `MessageId` identifies durable inbox insertion, claim, and discard facts, not a later assistant output or turn ending. `whenIdle()` observes the whole agent, so callers may call a receipt-to-idle interval a run only when they explicitly own that interval ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md)).
201
+
202
+ ```ts type-equiv
203
+ /**
204
+ * Merge-extensible agent options. Route fields may be live accessors until the
205
+ * Session records a selection or request; step preparation captures their value.
206
+ * Persona belongs to system-prompt sections.
207
+ */
208
+ interface AgentOptions {
209
+ /** Provider route (must have a registered adapter at call time). */
210
+ provider?: string
211
+ /** Model id interpreted by the selected provider adapter. */
212
+ model?: string
213
+ /** Adapter-owned reasoning effort for the selected provider/model route. */
214
+ reasoningEffort?: ReasoningEffortId | undefined
215
+ /** Maximum output tokens for each conversation-model request. */
216
+ maxTokens?: number
217
+ }
218
+ ```
219
+
220
+ Step preparation requires `provider` and `model` before prompt assembly. The deprecated `agent/request` hook may change request controls but must preserve that route. An explicit `reasoningEffort` seeds the first request on that route; exact-model resolution validates it, while omission allows the adapter default to materialize. When present, `maxTokens` must be a positive safe integer and caps every conversation-model request; omission allows the exact-model adapter default to materialize before the request header, or otherwise leaves provider behavior unchanged. An agent-scoped `deployment:persona-prefix` prompt section may shadow the global default persona.
221
+
222
+ `AgentLoop` registers `modelSelection` on `ctx.sessionProjections` and exposes selection operations through each `agent.model` instance. `model/selection` records a complete choice without entering model history. A matching request header clears `pending`; the latest request remains `lastUsed`. Adapter-defaulted effort is omitted so later requests resolve the default again. `next` is null only before either a choice or a request is recorded; in that case `AgentOptions` supplies the route. The [Agent model API](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/README.md) describes selection precedence and resume policy.
223
+
224
+ ```ts type-equiv
225
+ /** Agent-owned access to the model choice for future steps. */
226
+ interface Model {
227
+ /**
228
+ * Resolve the choice for the next step to begin preparation. Recorded choices
229
+ * take precedence over the last request and then the Agent's live options.
230
+ * This read neither starts a step nor changes an already-prepared step.
231
+ * @returns a detached choice, or undefined when no source names both provider and model.
232
+ */
233
+ current(): Readonly<ModelSelection> | undefined
234
+
235
+ /**
236
+ * Replace the next step's complete selection. Omitted effort follows adapter
237
+ * defaults without inheriting a previous effort or resolving defaults here.
238
+ * An equal recorded choice is a no-op; an options-only fallback is
239
+ * always recorded. Callers own model availability and capability validation.
240
+ * The append uses the Session's existing persistence and failure guarantees.
241
+ * @param selection - complete provider, model, and optional explicit effort.
242
+ */
243
+ select(selection: Readonly<ModelSelection>): void
244
+
245
+ }
246
+ ```
247
+
248
+ ```ts type-equiv
249
+ /** Complete provider, model, and optional reasoning effort chosen for one Session's model steps. */
250
+ interface ModelSelection {
251
+ /** Registered provider route. */
252
+ provider: string
253
+ /** Provider-owned model id. */
254
+ model: string
255
+ /** Adapter-owned reasoning effort, or provider/default behavior when absent. */
256
+ reasoningEffort?: ReasoningEffortId
257
+ }
258
+ ```
259
+
260
+ ```ts type-equiv
261
+ /**
262
+ * Durable model-selection state for one Session. An effort the adapter
263
+ * defaulted on a recorded request is omitted, so later requests resolve the
264
+ * default again instead of pinning it as a choice.
265
+ */
266
+ interface ModelSelectionProjectionState {
267
+ /** Selection used by the latest recorded model request. */
268
+ readonly lastUsed: ModelSelection | null
269
+ /** Later recorded selection not yet used by a matching model request. */
270
+ readonly pending: ModelSelection | null
271
+ }
272
+ ```
273
+
274
+ ```ts type-equiv
275
+ /** Client view of the durable model-selection fold. */
276
+ interface ModelSelectionProjection {
277
+ /** Selection used by the latest recorded model request. */
278
+ readonly lastUsed: ModelSelection | null
279
+ /** Selection the next model step uses; null while the Agent's initial options supply the route. */
280
+ readonly next: ModelSelection | null
281
+ }
282
+ ```
283
+
284
+ The inbox is the delivery vocabulary — two ordered pending-message lists the agent owns as a durable projection:
285
+
286
+ ```ts type-equiv
287
+ /** Agent-owned access to pending work; concrete storage belongs to the driver. */
288
+ interface Inbox {
289
+ /** Prompts awaiting individual turns. */
290
+ readonly nextTurn: readonly UserMessage[]
291
+ /** Input awaiting the next step boundary. */
292
+ readonly nextStep: readonly UserMessage[]
293
+
294
+ /** Durably cancel all pending input, clearing next-step before next-turn. */
295
+ clear(): void
296
+
297
+ /**
298
+ * Append one message to a pending list.
299
+ * @param target - pending list to extend.
300
+ * @param message - message to append.
301
+ */
302
+ append(target: InboxTarget, message: UserMessage): void
303
+
304
+ /**
305
+ * Prepend one message to a pending list.
306
+ * @param target - pending list to extend.
307
+ * @param message - message to prepend.
308
+ */
309
+ prepend(target: InboxTarget, message: UserMessage): void
310
+
311
+ /**
312
+ * Replace one pending message in place.
313
+ * @param messageId - identity of the pending message to replace.
314
+ * @param newMessage - replacement message.
315
+ * @returns whether the message was still pending.
316
+ */
317
+ replace(messageId: MessageId, newMessage: UserMessage): boolean
318
+
319
+ /**
320
+ * Remove one pending message.
321
+ * @param messageId - identity of the pending message to remove.
322
+ * @returns whether the message was still pending.
323
+ */
324
+ remove(messageId: MessageId): boolean
325
+
326
+ /**
327
+ * Apply standard splice semantics and durably record the normalized result.
328
+ * @param target - pending list to mutate.
329
+ * @param start - splice position.
330
+ * @param deleteCount - maximum number of messages to remove.
331
+ * @param inserted - messages to insert at the resolved position.
332
+ * @returns messages removed by the splice.
333
+ */
334
+ splice(
335
+ target: InboxTarget,
336
+ start: number,
337
+ deleteCount: number,
338
+ inserted: UserMessage[],
339
+ ): UserMessage[]
340
+ }
341
+ ```
342
+
343
+ ```ts type-equiv
344
+ /** One of the two ordered pending-message lists owned by an agent. */
345
+ type InboxTarget = 'next-turn' | 'next-step'
346
+ ```
347
+
348
+ Every pending occurrence is its `UserMessage`; `MessageId` is the sole identity. The structural `Inbox` methods record normalized durable `agent/inbox/spliced` mutations and reject duplicate pending ids. `replace(messageId, newMessage)` and `remove(messageId)` locate the pending message across both lists; replacement may change identity and emits the old message as discarded followed by the new message as inserted. Ordinary removals and `clear()` are cancellations. At a step boundary, dsh-agent-loop's package-internal `ReactLoopInbox` removes the proposed batch — all `next-step` input plus, at a turn boundary, one `next-turn` message — through pure deletion splices without discarded notifications, then emits per-message claimed notifications. Loop-only pending detection and claiming are not part of `Agent.inbox`. The `AgentLoop` service registers the standard `inbox` projection before publishing its factory; its cell is the sole live state, and the same fold serves cold consumers even when no Agent exists. The fold rejects unsafe or out-of-range splice coordinates and duplicate identities across both lists, identifying malformed durable history by event seq. Consumers following one message use the exact `agent/inbox/inserted`, `claimed`, and `discarded` notifications.
349
+
350
+ Cancellation:
351
+
352
+ ```ts type-equiv
353
+ /** Options for {@link Agent.cancel}. */
354
+ interface CancelOptions {
355
+ /**
356
+ * Preserve queued and steering inbox items instead of discarding them. The
357
+ * active turn is still aborted, but un-started and pending work survives for a
358
+ * later turn and no canceled inbox splice is logged.
359
+ */
360
+ keepInbox?: boolean | undefined
361
+ }
362
+ ```
363
+
364
+ ```ts type-equiv
365
+ /** Why an active agent driver was cancelled. */
366
+ type AgentCancelCause =
367
+ | { readonly kind: 'user' }
368
+ | { readonly kind: 'parent' }
369
+ | { readonly kind: 'hook'; readonly reason: string }
370
+ | { readonly kind: 'disposed' }
371
+ ```
372
+
373
+ The cause is a TypeScript-enforced same-process input. An active cancellation holder exposes that same object as the runtime-only `AbortSignal.reason`; a signal grants cooperating listeners no classification authority. Durable `turn/end` records the outcome as `{ kind: 'aborted', reason: TurnEndCancelCause }`, so the cancel cause lands in the terminal result.
374
+
375
+ The [event taxonomy](../index.md#events) owns the `agent/*` lifecycle, checkpoint, and waterfall contracts. Turn and step boundaries are durable session events rather than agent emits.
376
+
377
+ ## Initiating Agent
378
+
379
+ The process-local initiator carried by `ctx.agents` is the exact `Agent` above, not a separate frame or copied identity. Ambient presence is neither liveness proof nor authorization; the [initiator-scope decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-15-agent-initiator-scope.md) defines its lifetime and scope rules.
380
+
381
+ ## Interception decisions
382
+
383
+ Pre-step decisions use the same identified `UserMessage` type as durable user-role input. The entered batch is authoritative and preserves every message's `id` and `source`. Hook bridges map their native decision fields onto this typed result.
384
+
385
+ Source: [`packages/core/agent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
386
+
387
+ `agent/pre-step` receives one payload carrying the exclusive claimed batch (`messages`), the proposed step's coordinates (`turn`, `step`), and the current turn's cancellation `signal`. The initial proposal runs inside an open turn before any step; a tool continuation may submit an empty claimed batch between steps:
388
+
389
+ It returns a `PreStepDecision`. Reject opens no step. Enter supplies the complete message batch appended after `step/start`; claimed messages omitted by the final decision remain removed, while input inserted after the claim stays pending:
390
+
391
+ ```ts type-equiv
392
+ /** Whether and with which messages the loop enters a proposed step. */
393
+ type PreStepDecision =
394
+ | { kind: 'reject' }
395
+ | {
396
+ kind: 'enter'
397
+ messages: UserMessage[]
398
+ /** Start a distinct model-message series before this step's admitted messages. */
399
+ startsRequestSeries?: true
400
+ }
401
+ ```
402
+
403
+ `agent/request-error` runs after a failed model step closes and before its turn closes. Listeners can repair durable state or await policy work while the failed turn's signal is still live. A handling listener returns `{ kind: 'retry' }` without calling `next()`; the default `undefined` leaves the failure terminal.
404
+
405
+ ```ts type-equiv
406
+ /** Action returned by a listener that owns model-request recovery. */
407
+ type RequestErrorAction = { kind: 'retry' } | undefined
408
+ ```
409
+
410
+ `agent/pre-step` is the only waterfall listener chain before request derivation. `agent/turn-stopping` runs when a turn has no tool or steering continuation, before one final steering drain.
411
+
412
+ `agent/created` carries a `SessionStartSource` (why the session lifecycle began; a bridge keys its SessionStart matcher on it):
413
+
414
+ ```ts type-equiv
415
+ /** Why a session lifecycle began; seeded creates are `startup`, while persisted loads are `resume`. */
416
+ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
417
+ ```
418
+
419
+ ## Sessions
420
+
421
+ A `Session` is an **append-only log** of typed `SessionEvent`s — the single source of truth. The LLM message history is *derived* from the log (`deriveMessages()`), not stored separately. Every entry carries a monotonic `seq`, a `time`, and a `type`-discriminated `data` payload; surface variants may also list cited earlier events in `sourceEventSeqs` and carry a `surfaceOp`.
422
+
423
+ The `SessionEvent` envelope's exact conditional fields, the thirteen core event variants (`turn/start`, `turn/end`, `step/start`, `step/end`, `user/message`, `system/message`, `assistant/message`, `assistant/attempt`, `tool/call`, `tool/result`, `request/header`, `request/context`, `session/end-seed`), the `deriveMessages()` projection rules, the `TurnEndReason` reasons, and the execution-enclosure and standalone-event rules are on **[session.md](./session.md)**. How the log is made durable — the `SessionPersistence` interface, JSONL provider, `session/flush` checkpoint, crash recovery, and `SessionHeader` — is on **[persistence.md](./persistence.md)**.
424
+
425
+ ## `ToolDefinition`
426
+
427
+ The one pipeline-authoring type that is core: what every registered tool *is* — a model-facing `ToolSchema` plus an `execute` function and optional final-content and UI callbacks. A tool author rarely constructs it by hand (the `defineTool` DSL builds it with typed arguments), but it is the contract the registry holds and the loop dispatches through.
428
+
429
+ Its full fields, the `defineTool`/`ValueSchemaSpec`/`ParameterSchemaSpec` typed schema DSL, the `ToolExecution`/`ToolExecutionResult` waterfall types, and the tool-presentation UI types are on **[tools.md](./tools.md)**.
430
+
431
+ ## Repo-wide type patterns
432
+
433
+ Two patterns recur across every subsystem and are documented once, here.
434
+
435
+ <a id="the-map--derived-union-pattern"></a>
436
+
437
+ ### The `…Map → derived-union` pattern
438
+
439
+ Almost every extensible sum type in the harness follows one pattern: an interface keyed by a discriminant tag (the `…Map`), from which the union is derived with `keyof`. Plugins add variants by **declaration merging** — no edit to the owning package.
440
+
441
+ ```ts ignore-check
442
+ // The pattern, schematically:
443
+ interface ThingMap {
444
+ 'a': { kind: 'a'; /* … */ }
445
+ 'b': { kind: 'b'; /* … */ }
446
+ }
447
+ type ThingKind = keyof ThingMap // 'a' | 'b'
448
+ type Thing = ThingMap[keyof ThingMap] // the discriminated union
449
+
450
+ // A plugin extends it without touching the source package:
451
+ declare module '@deepseek-ai/dsh-llm' {
452
+ interface ThingMap {
453
+ 'c': { kind: 'c'; /* … */ }
454
+ }
455
+ }
456
+ ```
457
+
458
+ Six canonical maps use this pattern; a plugin author extends these:
459
+
460
+ | Map | Package | Derives | Catalog |
461
+ |---|---|---|---|
462
+ | `ContentBlockMap` | dsh-llm | `ContentBlock` | [llm-streaming.md](./llm-streaming.md#content-blocks-and-messages) |
463
+ | `MessageSourceMap` | dsh-llm | `MessageSource` | [llm-streaming.md](./llm-streaming.md#content-blocks-and-messages) |
464
+ | `LlmRequestPurposeMap` | dsh-llm | `LlmRequestPurpose` | [llm-streaming.md](./llm-streaming.md#the-model-request-and-result) |
465
+ | `FinishReasonMap` | dsh-llm | `FinishReason` | [llm-streaming.md](./llm-streaming.md#the-model-request-and-result) |
466
+ | `TurnEndReasonMap` | dsh-session | `TurnEndReason` | [session.md](./session.md) |
467
+ | `SessionEventMap` | dsh-session | `SessionEvent` | [session.md](./session.md) |
468
+
469
+ Two large discriminated unions are the ones consumers `switch` over most: **`StreamChunk`** (the streaming protocol) and **`SessionEvent`** (the log entry). Per the repo convention, `switch` on the tag — don't chain `if`s — so each arm narrows and a typo'd tag fails to compile.
470
+
471
+ ### Branded IDs
472
+
473
+ IDs passed between packages are **branded** — structurally strings, but non-interchangeable at the type level (a `SessionId` cannot be passed where a `ToolCallId` is expected). Construction uses the shared `brandString<T>()` helper or an owner-defined validating factory; comparison, logging, and JSON behave as ordinary strings.
474
+
475
+ The `Branded<B>` primitive and stateless constructor live in [dsh-brand](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/util/brand), which has no harness capability dependency. `brandString<T>()` applies a compile-time-only string brand.
476
+
477
+ Source: [`packages/util/brand/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/util/brand/src/index.ts)
478
+
479
+ ```ts type-equiv
480
+ /** A string carrying a compile-time-only brand `B`. */
481
+ type Branded<B extends string> = string & { readonly [BRAND]: B }
482
+ ```
483
+
484
+ The two core IDs are `ToolCallId` (correlates a tool call with its result; dsh-llm) and `SessionId` (the shared live agent and durable session identity; dsh-session). Capability packages brand their own ids too, such as `JobId` in [jobs.md](./jobs.md).
485
+
486
+ ## `TurnBoundaryProjection`
487
+
488
+ `ctx.agents.turnBoundaryOf(session)` reads recorded turn and step positions without requiring a live Agent. The registry owns this state; consumers do not register its projection definition.
489
+
490
+ Source: [`packages/core/agent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
491
+
492
+ ```ts type-equiv
493
+ /** Turn and step positions recorded in a Session. */
494
+ interface TurnBoundaryProjection {
495
+ /** Seq of the open turn's `turn/start`, or null between turns. */
496
+ readonly openTurnStartSeq: OptionalSessionSeq
497
+ /** Seq of the latest `step/start` event, or null before the first step. */
498
+ readonly lastStepStartSeq: OptionalSessionSeq
499
+ /** The latest step boundary (`step/start` or `step/end`) and its seq, or null before the first step boundary. */
500
+ readonly lastStepBoundary: { readonly kind: 'start' | 'end'; readonly seq: SessionSeq } | null
501
+ /** Turn number of the latest `turn/start`; 0 before the first turn. */
502
+ readonly lastTurn: number
503
+ }
504
+ ```
505
+
506
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
507
+
508
+ <a id="cordis-surface"></a>
509
+
510
+ ## Cordis API
511
+
512
+ 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).
513
+
514
+ <a id="ctxagentdefaultmodel--agentdefaultmodelconfig"></a>
515
+
516
+ ### `ctx.agentDefaultModel` — `AgentDefaultModelConfig`
517
+
518
+ Owns the default model selection independently of any Host or transport. Each operation reads the owning Config references.
519
+
520
+ ```ts cordis-catalog
521
+ /**
522
+ * Read the current default model selection.
523
+ * @returns a detached provider, model, and optional reasoning selection.
524
+ */
525
+ currentSelection(): ModelSelection
526
+
527
+ /**
528
+ * Save the complete default model selection. A deployment without a configuration
529
+ * editor keeps its composition entry. Saves commit in submission order; a failed
530
+ * save rejects its caller without blocking later saves.
531
+ * @param next - resolved selection accepted by an entry point.
532
+ * @returns fulfillment after the optional profile write settles.
533
+ */
534
+ async saveSelection(next: ModelSelection): Promise<void>
535
+ ```
536
+
537
+ Source: [`packages/core/agent-default-model/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-default-model/src/index.ts)
538
+
539
+ <a id="ctxagentloop--agentloop"></a>
540
+
541
+ ### `ctx.agentLoop` — `AgentLoop`
542
+
543
+ Concrete agent factory and driver service.
544
+
545
+ ```ts cordis-catalog
546
+ /**
547
+ * Create an agent and session under one caller-supplied identity, owned by
548
+ * the accessing fiber. Constructor-driven config calls mint a fresh combined
549
+ * id before entering this boundary. When a persistence backend is mounted,
550
+ * the session's durable identity and any seed are stored before publication.
551
+ * @param id - shared agent/session identity.
552
+ * @param options - concrete loop options.
553
+ * @param meta - optional fresh-session workspace metadata.
554
+ * @returns the published running agent.
555
+ */
556
+ async create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd'> = {}): Promise<Agent>
557
+
558
+ /**
559
+ * Create an owned agent on a caller-supplied session id.
560
+ * @param ownerCtx - caller context that structurally owns the lifecycle.
561
+ * @param options - identities, optional live parent, session seed/metadata, loop options, setup, and cancellation.
562
+ * @returns the published handle.
563
+ */
564
+ async createAgent(ownerCtx: Context, options: CreateAgentOptions): Promise<AgentHandle>
565
+
566
+ /**
567
+ * Resume an owned agent from the configured persistence service.
568
+ * @param ownerCtx - caller context that owns load, setup, and the live lifecycle.
569
+ * @param options - persisted identity, optional live parent, loop options, setup, and cancellation.
570
+ * @returns the published handle.
571
+ */
572
+ async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise<AgentHandle>
573
+ ```
574
+
575
+ Types: [SessionHeader](./persistence.md)
576
+
577
+ Source: [`packages/core/agent-loop/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/src/index.ts)
578
+
579
+ <a id="ctxagentpresets--agentpresetregistry"></a>
580
+
581
+ ### `ctx.agentPresets` — `AgentPresetRegistry`
582
+
583
+ Registry of YAML-declared presets and the revisions live Agents retain.
584
+
585
+ ```ts cordis-catalog
586
+ /**
587
+ * Read the preset recorded for a Session, including selections no longer in the roster.
588
+ * @param session - Session whose committed preset selection is read.
589
+ * @returns the recorded preset, or null when none was selected.
590
+ */
591
+ presetForSession(session: Session): string | null
592
+
593
+ /** Register and eagerly load a definition; activation failure remains visible in the roster.
594
+ * @param definition Parsed configuration supplied by the declaring plugin.
595
+ * @returns Definition disposer after activation or its diagnostic settles; the declaring plugin owns it.
596
+ */
597
+ async register(definition: PresetDefinition): Promise<() => Promise<void>>
598
+
599
+ /** Inspect retained revisions, or the exact revision an Agent joined.
600
+ * @param ctx - optional Agent context; omission includes all retained revisions.
601
+ * @returns detached module references and isolation diagnostics; no match returns an empty list.
602
+ */
603
+ inspectCompositions(ctx?: Context): AgentPresetInspection[]
604
+
605
+ /** Read every declared preset, including activation failures.
606
+ * @returns Display metadata and loading diagnostics.
607
+ */
608
+ async list(): Promise<AgentPreset[]>
609
+
610
+ /** Read the selection roster.
611
+ * @returns Current presets, each marked when it is the default.
612
+ */
613
+ @Remote('list') async remoteExportList(): Promise<AgentPresetRoster>
614
+
615
+ /** Resolve an identity without starting an Agent.
616
+ * @param id Explicit preset or the current default.
617
+ * @returns Current metadata, including failure when activation failed.
618
+ */
619
+ async resolve(id?: string): Promise<AgentPreset>
620
+
621
+ /** Read one declaration's child plugin list as YAML, for viewing only.
622
+ * @param agentPreset Preset identity.
623
+ * @returns The declared composition beside its published metadata.
624
+ */
625
+ @Remote('read') readDocument(agentPreset: string): Promise<AgentPresetDocument>
626
+
627
+ /** Bind an unpublished Agent to the current preset revision.
628
+ * @param ctx Agent context from its setup callback.
629
+ * @param id Requested preset, or the default.
630
+ * @returns Bound preset identity.
631
+ */
632
+ async mount(ctx: Context, id?: string): Promise<AgentPreset>
633
+
634
+ /** Join a child to the exact revision retained by its parent.
635
+ * @param ctx Child Agent context.
636
+ * @param parent Parent Agent context.
637
+ * @returns Inherited preset id, or undefined in a preset-free composition.
638
+ */
639
+ composeFrom(ctx: Context, parent: Context): string | undefined
640
+
641
+ /** Read the preset a live Agent uses.
642
+ * @param ctx Agent context.
643
+ * @returns Its preset id, if bound.
644
+ */
645
+ composedPreset(ctx: Context): string | undefined
646
+
647
+ /** Read a service supplied inside an Agent's isolated preset group.
648
+ * @param agent Agent whose composition is queried.
649
+ * @param name Cordis service name.
650
+ * @returns The service, or undefined.
651
+ */
652
+ serviceFor<K extends string & keyof Context>(agent: { ctx: Context }, name: K): Context[K] | undefined
653
+
654
+ /** Rebind a blank Agent; the caller owns the blank-session check.
655
+ * @param ctx Agent context.
656
+ * @param id Requested preset.
657
+ * @returns The bound identity.
658
+ */
659
+ async recompose(ctx: Context, id: string): Promise<AgentPreset>
660
+
661
+ /** Select a preset before a session starts its first turn. A Session whose
662
+ * log records the preset and whose Agent runs its current revision keeps its
663
+ * composition; nothing is logged or announced.
664
+ * @param agent Target Agent.
665
+ * @param agentPreset Requested identity.
666
+ * @returns Committed preset identity.
667
+ */
668
+ @Remote('select') async select(agent: Agent, agentPreset: string): Promise<string>
669
+
670
+ /** Read current registrations for cold transcript presentation.
671
+ * @param id Preset identity or the default.
672
+ * @returns A revision lease; dispose it after the scoped read completes.
673
+ */
674
+ async acquireScope(id?: string): Promise<{ key: ScopeKey } & AsyncDisposable>
675
+
676
+ /** Read plugin rows without creating an Agent.
677
+ * @returns Current declaration metadata and activation states.
678
+ */
679
+ compositionInventory(): Promise<AgentPresetComposition[]>
680
+ ```
681
+
682
+ Types: [ScopeKey](./scope.md) · [Session](./session.md)
683
+
684
+ Source: [`packages/preset/agent-preset-registry/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/preset/agent-preset-registry/src/index.ts)
685
+
686
+ <a id="ctxagents--agentregistry"></a>
687
+
688
+ ### `ctx.agents` — `AgentRegistry`
689
+
690
+ Agent service (`ctx.agents`): tracks live agents and carries the initiating Agent through one process-local asynchronous driver chain. Agent *creation* is provided by whichever plugin implements the AgentFactory (`@deepseek-ai/dsh-agent-loop`), registered via setFactory.
691
+
692
+ Initiator methods provide same-process causal attribution only. Ambient presence is neither liveness proof nor authorization; subjects and owners remain explicit, as does identity at worker, process, persistence, and wire boundaries. Returned Promise boundaries drain during teardown, except a nested lineage that starts an owning-fiber unload is excluded from its own drain.
693
+
694
+ ```ts cordis-catalog
695
+ /**
696
+ * Read the turn and step positions recorded in a Session.
697
+ * @param session - Session whose committed events are read.
698
+ * @returns the current turn and step positions; do not mutate the returned value.
699
+ */
700
+ turnBoundaryOf(session: Session): TurnBoundaryProjection
701
+
702
+ /**
703
+ * Read the Agent that initiated the inherited asynchronous driver chain.
704
+ * Use this optional form for logging, tracing, metrics, or host attribution
705
+ * that also supports agentless calls. When a parent creates a child, setup
706
+ * reports the causal parent while the setup callback's Agent parameter
707
+ * identifies the child.
708
+ * @returns the inherited Agent, or `undefined` outside an initiator boundary
709
+ * and inside an explicit clearing boundary.
710
+ * @throws when this service instance has been disposed.
711
+ */
712
+ currentInitiator(): Agent | undefined
713
+
714
+ /**
715
+ * Read the initiating Agent and fail when no initiator boundary is active.
716
+ * Use this for private helpers contractually below a driver, or for a
717
+ * deployment-owned outbound request whose contract forbids agentless calls.
718
+ * Generic or direct-call paths use optional lookup or explicit request fields.
719
+ * @returns the inherited Agent.
720
+ * @throws when no initiator is active or this service instance has been disposed.
721
+ */
722
+ requireInitiator(): Agent
723
+
724
+ /**
725
+ * Run an operation with one exact Agent as its process-local initiator. The
726
+ * exact synchronous value or Promise returned by the operation is preserved.
727
+ * Custom drivers and test harnesses wrap their complete returned foreground
728
+ * lifetime.
729
+ * A queue or wire receiver may establish this boundary only after validating
730
+ * explicit identity and resolving the exact live Agent; this method does neither.
731
+ * Detached work remains owned by the subsystem that starts it.
732
+ * @param agent - initiating Agent to inherit; presence is neither liveness proof nor authorization.
733
+ * @param operation - synchronous or asynchronous operation to invoke.
734
+ * @returns the exact value returned by `operation`.
735
+ * @throws when the initiator scope is closing/disposed, or when `operation` throws.
736
+ */
737
+ withInitiator<T>(agent: Agent, operation: () => T): T
738
+
739
+ /**
740
+ * Run an operation inside a boundary that hides any inherited initiating
741
+ * Agent. The exact synchronous value or Promise is preserved.
742
+ * Use this while creating lazy shared timers, queue pumps, pool maintenance,
743
+ * watchers, or exporters so they do not inherit the first Agent that happens
744
+ * to initialize them. It clears only initiator attribution, not explicit
745
+ * fields, and does not own or drain detached resources.
746
+ * @param operation - synchronous or asynchronous operation to invoke without an initiator.
747
+ * @returns the exact value returned by `operation`.
748
+ * @throws when the initiator scope is closing/disposed, or when `operation` throws.
749
+ */
750
+ withoutInitiator<T>(operation: () => T): T
751
+
752
+ /**
753
+ * Register the agent-creation factory (the loop calls this on construction,
754
+ * effect-scoped). A traced Cordis service is canonicalized to its concrete
755
+ * target; each create/resume call is then traced through that caller's
756
+ * context so ownership follows the caller without stacking proxy layers.
757
+ * Throws if a factory is already registered. Returns the disposer; on
758
+ * dispose the factory slot is cleared.
759
+ * @param factory - the loop-owned factory {@link create}/{@link resume} delegate to.
760
+ * @returns the disposer that clears the factory slot. The exact
761
+ * Cordis effect disposer (single-shot): composite (generator) effects may
762
+ * yield it directly — exact identity nests the teardown in order.
763
+ */
764
+ setFactory(factory: AgentFactory): () => void
765
+
766
+ /**
767
+ * Create and publish a new agent through the registered factory.
768
+ * Distinct from {@link register} (which records an already-constructed
769
+ * agent): this constructs the agent and its session. Rejects if no factory is
770
+ * registered or creation/setup fails. The resolved {@link AgentHandle} lets
771
+ * the owner tear down exactly this agent.
772
+ * @param options - shared identity, session seed/metadata, and agent options.
773
+ * @returns the handle after setup, rollback-covered publication, and loop start complete.
774
+ */
775
+ async create(options: CreateAgentOptions): Promise<AgentHandle>
776
+
777
+ /**
778
+ * Load a persisted session and resume an agent on it through the registered
779
+ * factory. Rejects if no factory is registered; the factory rejects if
780
+ * session persistence is not configured or persistence/setup fails.
781
+ * @param options - persisted identity, configuration, and setup.
782
+ * @returns the handle after setup, rollback-covered publication, and loop start complete.
783
+ */
784
+ async resume(options: ResumeAgentOptions): Promise<AgentHandle>
785
+
786
+ /**
787
+ * Register a live agent with source `startup`. Rejects if the id is already registered or a
788
+ * serial `agent/created` listener fails. Emits `agent/disposed`
789
+ * when the calling fiber is disposed — both with the agent's scope carrier
790
+ * (`scopeTarget(agent, agent)`): the subject is the agent in hand, so the
791
+ * emits are scope-filtered regardless of which context invoked `register`
792
+ * (calling through `agent.ctx` scopes EFFECTS; dispatch scoping always
793
+ * requires passing the carrier). Await registration before using the agent.
794
+ * @param agent - the already-constructed agent to record in the store.
795
+ * @returns the awaitable Cordis effect disposer (single-shot; a repeat call
796
+ * returns undefined without awaiting an in-flight teardown). Exact
797
+ * identity is load-bearing: a composite (generator) effect that owns a
798
+ * teardown ORDER — the agent factory's lifecycle chain — must yield THIS
799
+ * function so Cordis nests the unregistration at that yield position;
800
+ * yielding a wrapper would leave it disposing as a concurrent sibling on
801
+ * owner unload, unregistering the agent (and emitting `agent/disposed`)
802
+ * while its final turn is still draining.
803
+ */
804
+ register(agent: Agent): ReturnType<Context['effect']>
805
+
806
+ /**
807
+ * Insert an already-constructed agent without announcing it. This is the
808
+ * advanced ordered-lifecycle primitive used by the async agent factory: it
809
+ * first completes setup while the agent is unpublished, then assigns the
810
+ * returned detach closure into its pre-installed composite teardown before
811
+ * calling {@link announce}. Ordinary callers use {@link register}.
812
+ * @param agent - the prepared, unpublished agent.
813
+ * @returns an idempotent closure that removes this exact entry and emits
814
+ * `agent/disposed` with listener failures contained. When called from a
815
+ * `agent/created` listener, removal and disposal wait until the serial
816
+ * creation dispatch settles.
817
+ */
818
+ enter(agent: Agent): () => void
819
+
820
+ /**
821
+ * Announce an agent previously inserted with {@link enter}.
822
+ * @param agent - the live inserted agent to announce.
823
+ * @param source - fresh creation, resume, clear, or compaction source.
824
+ * @param signal - optional factory initialization cancellation signal passed to listeners.
825
+ * @returns completion of the serial creation listeners; a listener failure rejects.
826
+ * @throws if `agent` is not the exact live registry entry for its id, or its
827
+ * creation announcement already began (including a reentrant call from a
828
+ * creation listener).
829
+ */
830
+ async announce(agent: Agent, source: SessionStartSource, signal?: AbortSignal): Promise<void>
831
+
832
+ /**
833
+ * Look up a live agent.
834
+ * @param id - the shared agent/session id to look up.
835
+ * @returns the agent, or undefined when no live agent has that id.
836
+ */
837
+ get(id: SessionId): Agent | undefined
838
+
839
+ /**
840
+ * All live agents, in registration order.
841
+ * @returns a fresh array; mutating it does not affect the registry.
842
+ */
843
+ list(): Agent[]
844
+ ```
845
+
846
+ Types: [Session](./session.md)
847
+
848
+ Source: [`packages/core/agent/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/index.ts)
849
+
850
+ <a id="agent-events"></a>
851
+
852
+ ### `agent/*` events
853
+
854
+ <a id="agentassistant-stream--emit"></a>
855
+
856
+ #### `agent/assistant-stream` — emit
857
+
858
+ Process-local assistant-stream publication. Chunk frames are transient; the loop appends one final v2 `assistant/message` or `assistant/attempt` with the same stream before a committed end frame.
859
+
860
+ ```ts cordis-catalog
861
+ /**
862
+ * Process-local assistant-stream publication. Chunk frames are transient;
863
+ * the loop appends one final v2 `assistant/message` or `assistant/attempt`
864
+ * with the same stream before a committed end frame.
865
+ * @param payload.agent - the agent whose attempt produced the frame.
866
+ * @param payload.frame - one ordered start, chunk, or end publication.
867
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
868
+ * @mode emit
869
+ */
870
+ 'agent/assistant-stream'(this: Scoped<Agent>, payload: { agent: Agent; frame: AssistantStreamFrame }): void
871
+ ```
872
+
873
+ Types: [Scoped](./scope.md)
874
+
875
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
876
+
877
+ <a id="agentcreated--serial"></a>
878
+
879
+ #### `agent/created` — serial
880
+
881
+ An entered agent is ready for per-agent initialization after factory setup. Listeners run in order and are awaited before creation resolves. AgentLoop holds queued input until all listeners finish. A throw or rejection fails creation and skips later listeners. Disposal retains the scope and session until dispatch settles; listeners must not await agent.whenIdle() or their own owner's disposal.
882
+
883
+ ```ts cordis-catalog
884
+ /**
885
+ * An entered agent is ready for per-agent initialization after factory setup.
886
+ * Listeners run in order and are awaited before creation resolves. AgentLoop
887
+ * holds queued input until all listeners finish. A throw or rejection fails
888
+ * creation and skips later listeners. Disposal retains the scope and session
889
+ * until dispatch settles; listeners must not await agent.whenIdle() or their
890
+ * own owner's disposal.
891
+ * @param payload.agent - the newly registered agent with its live session and completed setup.
892
+ * @param payload.source - fresh creation, resume, clear, or compaction source.
893
+ * @param payload.signal - factory initialization cancellation signal, when provided.
894
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
895
+ * @mode serial
896
+ */
897
+ 'agent/created'(this: Scoped<Agent>, payload: { agent: Agent; source: SessionStartSource; signal?: AbortSignal }): undefined | Promise<undefined>
898
+ ```
899
+
900
+ Types: [Scoped](./scope.md)
901
+
902
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
903
+
904
+ <a id="agentdisposed--emit"></a>
905
+
906
+ #### `agent/disposed` — emit
907
+
908
+ An agent left the registry; AgentLoop emits this after driver quiescence and scoped-registration unwind, but before session detachment. Custom registry users own their driver-ordering contract.
909
+
910
+ ```ts cordis-catalog
911
+ /**
912
+ * An agent left the registry; AgentLoop emits this after driver quiescence
913
+ * and scoped-registration unwind, but before session detachment. Custom
914
+ * registry users own their driver-ordering contract.
915
+ * @param payload.agent - the exact agent removed from the registry.
916
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
917
+ * @mode emit
918
+ */
919
+ 'agent/disposed'(this: Scoped<Agent>, payload: { agent: Agent }): void
920
+ ```
921
+
922
+ Types: [Scoped](./scope.md)
923
+
924
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
925
+
926
+ <a id="agenterror--emit"></a>
927
+
928
+ #### `agent/error` — emit
929
+
930
+ A step or turn errored. The machine reports a failure here even when the error has no in-turn position for a durable record.
931
+
932
+ ```ts cordis-catalog
933
+ /**
934
+ * A step or turn errored. The machine reports a failure here even when
935
+ * the error has no in-turn position for a durable record.
936
+ * @param payload.agent - the agent whose turn errored.
937
+ * @param payload.turn - the turn in which the failure surfaced.
938
+ * @param payload.step - the step at which the failure surfaced.
939
+ * @param payload.error - the failure, verbatim.
940
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
941
+ * @mode emit
942
+ */
943
+ 'agent/error'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; step: number; error: unknown }): void
944
+ ```
945
+
946
+ Types: [Scoped](./scope.md)
947
+
948
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
949
+
950
+ <a id="agentinboxclaimed--emit"></a>
951
+
952
+ #### `agent/inbox/claimed` — emit
953
+
954
+ One message left the inbox inside its open turn. If the proposed step is rejected, the claimed message ends here: it is neither discarded nor re-emitted as a user/message, and the turn closes without a step.
955
+
956
+ ```ts cordis-catalog
957
+ /**
958
+ * One message left the inbox inside its open turn. If the proposed step
959
+ * is rejected, the claimed message ends here: it is neither discarded nor
960
+ * re-emitted as a user/message, and the turn closes without a step.
961
+ * @param payload.agent - the agent whose inbox changed.
962
+ * @param payload.message - the claimed message.
963
+ * @param payload.turn - the owning turn.
964
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
965
+ * @mode emit
966
+ */
967
+ 'agent/inbox/claimed'(this: Scoped<Agent>, payload: { agent: Agent; message: UserMessage; turn: number }): void
968
+ ```
969
+
970
+ Types: [Scoped](./scope.md) · [UserMessage](./session.md)
971
+
972
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
973
+
974
+ <a id="agentinboxdiscarded--emit"></a>
975
+
976
+ #### `agent/inbox/discarded` — emit
977
+
978
+ One message was discarded from the live inbox.
979
+
980
+ ```ts cordis-catalog
981
+ /**
982
+ * One message was discarded from the live inbox.
983
+ * @param payload.agent - the agent whose inbox changed.
984
+ * @param payload.message - the discarded message.
985
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
986
+ * @mode emit
987
+ */
988
+ 'agent/inbox/discarded'(this: Scoped<Agent>, payload: { agent: Agent; message: UserMessage }): void
989
+ ```
990
+
991
+ Types: [Scoped](./scope.md) · [UserMessage](./session.md)
992
+
993
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
994
+
995
+ <a id="agentinboxinserted--emit"></a>
996
+
997
+ #### `agent/inbox/inserted` — emit
998
+
999
+ One message entered the live inbox.
1000
+
1001
+ ```ts cordis-catalog
1002
+ /**
1003
+ * One message entered the live inbox.
1004
+ * @param payload.agent - the agent whose inbox changed.
1005
+ * @param payload.message - the inserted message.
1006
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1007
+ * @mode emit
1008
+ */
1009
+ 'agent/inbox/inserted'(this: Scoped<Agent>, payload: { agent: Agent; message: UserMessage }): void
1010
+ ```
1011
+
1012
+ Types: [Scoped](./scope.md) · [UserMessage](./session.md)
1013
+
1014
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1015
+
1016
+ <a id="agentpre-step--waterfall"></a>
1017
+
1018
+ #### `agent/pre-step` — waterfall
1019
+
1020
+ Reject a proposed step or replace the messages that enter it. Calling `next()` preserves the current messages.
1021
+
1022
+ ```ts cordis-catalog
1023
+ /**
1024
+ * Reject a proposed step or replace the messages that enter it. Calling
1025
+ * `next()` preserves the current messages.
1026
+ * @param payload.agent - the agent proposing the step.
1027
+ * @param payload.messages - messages removed from the inbox for this step.
1028
+ * @param payload.turn - the turn that will own the step.
1029
+ * @param payload.step - the step proposed by the loop.
1030
+ * @param payload.signal - the current turn's cancellation signal.
1031
+ * @param payload.modelSelection - captured step selection, retained across retries; omitted effort uses adapter defaults.
1032
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1033
+ * @mode waterfall
1034
+ */
1035
+ 'agent/pre-step'(this: Scoped<Agent>, payload: { agent: Agent; messages: UserMessage[]; turn: number; step: number; signal: AbortSignal; modelSelection: Readonly<ModelSelection> }, next: () => Promise<PreStepDecision>): Promise<PreStepDecision>
1036
+ ```
1037
+
1038
+ Types: [Scoped](./scope.md) · [UserMessage](./session.md)
1039
+
1040
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1041
+
1042
+ <a id="agentrequest-error--waterfall"></a>
1043
+
1044
+ #### `agent/request-error` — waterfall
1045
+
1046
+ Handle one failed model-request attempt before the loop retries or closes its step. A listener returns `{ kind: 'retry' }` without calling `next()` when it owns recovery, or calls `next()` to delegate. The default `undefined` leaves the failure terminal.
1047
+
1048
+ ```ts cordis-catalog
1049
+ /**
1050
+ * Handle one failed model-request attempt before the loop retries or closes
1051
+ * its step. A listener returns `{ kind: 'retry' }` without calling `next()`
1052
+ * when it owns recovery, or calls `next()` to delegate. The default
1053
+ * `undefined` leaves the failure terminal.
1054
+ * @param payload.agent - the agent whose request failed.
1055
+ * @param payload.turn - the turn containing the failed request.
1056
+ * @param payload.step - the step containing the failed request attempt.
1057
+ * @param payload.provider - the provider selected for the failed request.
1058
+ * @param payload.failure - serializable facts normalized at the final adapter boundary.
1059
+ * @param payload.retryPolicy - the policy of the adapter registration that served the failed request.
1060
+ * @param payload.signal - the turn abort signal.
1061
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1062
+ * @mode waterfall
1063
+ */
1064
+ 'agent/request-error'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; step: number; provider: string; failure: LlmFailure; retryPolicy: ResolvedRetryPolicy | undefined; signal: AbortSignal }, next: () => Promise<RequestErrorAction>): Promise<RequestErrorAction>
1065
+ ```
1066
+
1067
+ Types: [LlmFailure](./llm-streaming.md) · [ResolvedRetryPolicy](./llm-streaming.md) · [Scoped](./scope.md)
1068
+
1069
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1070
+
1071
+ <a id="agentstatus--emit"></a>
1072
+
1073
+ #### `agent/status` — emit
1074
+
1075
+ Agent status changed (`idle` ⇄ `running`). A waking delivery enters `running` synchronously after reserving cancellation; `idle` means no driver remains scheduled or active.
1076
+
1077
+ ```ts cordis-catalog
1078
+ /**
1079
+ * Agent status changed (`idle` ⇄ `running`). A waking delivery enters
1080
+ * `running` synchronously after reserving cancellation; `idle` means no
1081
+ * driver remains scheduled or active.
1082
+ * @param payload.agent - the agent whose status flipped.
1083
+ * @param payload.status - the status just entered (the transition's destination).
1084
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1085
+ * @mode emit
1086
+ */
1087
+ 'agent/status'(this: Scoped<Agent>, payload: { agent: Agent; status: AgentStatus }): void
1088
+ ```
1089
+
1090
+ Types: [Scoped](./scope.md)
1091
+
1092
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1093
+
1094
+ <a id="agentturn-stopping--serial"></a>
1095
+
1096
+ #### `agent/turn-stopping` — serial
1097
+
1098
+ The turn is about to close: the model owes no response (no live tool calls, no fresh steering). Awaited before the boundary commits — a listener that objects steers (`agent.steer(...)`) and the machine re-reads its inbox: fresh steering runs another step, none closes the turn. Data decides, so listener order cannot change the outcome. The inverse control (stop a tool loop early) is data too: a tool result carrying `concludesTurn` ends the turn at its step. The conclusion never short-circuits already-submitted next-step work: same-step `additionalContexts` or racing steering still runs, and the turn closes only when that inbox drains.
1099
+
1100
+ ```ts cordis-catalog
1101
+ /**
1102
+ * The turn is about to close: the model owes no response (no live tool
1103
+ * calls, no fresh steering). Awaited before the boundary commits — a
1104
+ * listener that objects steers (`agent.steer(...)`) and the machine
1105
+ * re-reads its inbox: fresh steering runs another step, none closes the
1106
+ * turn. Data decides, so listener order cannot change the outcome. The
1107
+ * inverse control (stop a tool loop early) is data too: a tool result
1108
+ * carrying `concludesTurn` ends the turn at its step. The conclusion
1109
+ * never short-circuits already-submitted next-step work: same-step
1110
+ * `additionalContexts` or racing steering still runs, and the turn
1111
+ * closes only when that inbox drains.
1112
+ * @param payload.agent - the agent whose turn is at its stop boundary.
1113
+ * @param payload.turn - the turn about to close.
1114
+ * @param payload.signal - the current turn's explicit abort signal.
1115
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
1116
+ * @mode serial
1117
+ */
1118
+ 'agent/turn-stopping'(this: Scoped<Agent>, payload: { agent: Agent; turn: number; signal: AbortSignal }): Promise<void> | void
1119
+ ```
1120
+
1121
+ Types: [Scoped](./scope.md)
1122
+
1123
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
1124
+
1125
+ <a id="agent-loop-events"></a>
1126
+
1127
+ ### `agent-loop/*` events
1128
+
1129
+ <a id="agent-loopconfig-start-failed--emit"></a>
1130
+
1131
+ #### `agent-loop/config-start-failed` — emit
1132
+
1133
+ A declarative agent entry failed before it could publish a live agent. Consumers that buffer work for the configured identity use this transient signal to reject that work instead of waiting forever. Normal factory teardown suppresses failures from the cancelled startup attempt.
1134
+
1135
+ ```ts cordis-catalog
1136
+ /**
1137
+ * A declarative agent entry failed before it could publish a live agent.
1138
+ * Consumers that buffer work for the configured identity use this
1139
+ * transient signal to reject that work instead of waiting forever. Normal
1140
+ * factory teardown suppresses failures from the cancelled startup attempt.
1141
+ * @param payload.sessionId - exact shared agent/session identity that failed startup.
1142
+ * @param payload.error - persistence, setup, or publication failure.
1143
+ * @mode emit
1144
+ */
1145
+ 'agent-loop/config-start-failed'(payload: { sessionId: SessionId; error: unknown }): void
1146
+ ```
1147
+
1148
+ Source: [`packages/core/agent-loop/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent-loop/src/index.ts)
1149
+
1150
+ <a id="agent-preset-events"></a>
1151
+
1152
+ ### `agent-preset/*` events
1153
+
1154
+ <a id="agent-presetselected--emit"></a>
1155
+
1156
+ #### `agent-preset/selected` — emit
1157
+
1158
+ One session committed a different agent preset to its durable log. Consumers invalidate only state derived from that session's composition.
1159
+
1160
+ ```ts cordis-catalog
1161
+ /**
1162
+ * One session committed a different agent preset to its durable log.
1163
+ * Consumers invalidate only state derived from that session's composition.
1164
+ * @mode emit
1165
+ * @param sessionId - the session whose composition changed.
1166
+ * @param agentPreset - the preset recorded by the committed selection.
1167
+ */
1168
+ 'agent-preset/selected'(sessionId: SessionId, agentPreset: string): void
1169
+ ```
1170
+
1171
+ Source: [`packages/preset/agent-preset-registry/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/preset/agent-preset-registry/src/types.ts)
1172
+ <!-- END GENERATED cordis-surface -->