dsh-plugin-dev-kb 1.0.0 → 1.0.2

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 (55) hide show
  1. package/README.md +60 -9
  2. package/kb/INDEX.md +1 -1
  3. package/kb/README.md +22 -11
  4. package/kb/extra/development.md +2 -0
  5. package/kb/extra/development.zh.md +2 -0
  6. package/kb/extra/event-producer-consumer.md +9 -9
  7. package/kb/extra/event-producer-consumer.zh.md +9 -9
  8. package/kb/extra/i18n/README.md +1 -1
  9. package/kb/extra/i18n/README.zh.md +1 -1
  10. package/kb/extra/module-graph.md +251 -210
  11. package/kb/extra/module-graph.zh.md +251 -210
  12. package/kb/extra/subsystems/agent-team.md +183 -0
  13. package/kb/extra/subsystems/agent-team.zh.md +183 -0
  14. package/kb/extra/subsystems/attachment.md +16 -2
  15. package/kb/extra/subsystems/attachment.zh.md +16 -2
  16. package/kb/meta/search-index.json +54 -42
  17. package/kb/meta/source.json +3 -3
  18. package/kb/meta/topics.md +1 -1
  19. package/kb/site/en/guide/providers.md +40 -1
  20. package/kb/site/en/reference/capability-seams.md +12 -0
  21. package/kb/site/en/reference/config-catalog.md +238 -72
  22. package/kb/site/en/reference/index.md +2 -0
  23. package/kb/site/en/reference/persistence-catalog.md +76 -13
  24. package/kb/site/en/reference/subsystems/client-modules.md +11 -3
  25. package/kb/site/en/reference/subsystems/commands.md +28 -5
  26. package/kb/site/en/reference/subsystems/index.md +1 -0
  27. package/kb/site/en/reference/subsystems/llm-streaming.md +11 -2
  28. package/kb/site/en/reference/subsystems/persistence.md +3 -3
  29. package/kb/site/en/reference/subsystems/plan.md +1 -1
  30. package/kb/site/en/reference/subsystems/session-reference.md +71 -5
  31. package/kb/site/en/reference/subsystems/session.md +6 -2
  32. package/kb/site/en/reference/subsystems/subagent.md +22 -3
  33. package/kb/site/en/reference/subsystems/web.md +5 -4
  34. package/kb/site/en/reference/tool-catalog.md +353 -5
  35. package/kb/site/guide/providers.md +40 -1
  36. package/kb/site/reference/capability-seams.md +12 -0
  37. package/kb/site/reference/config-catalog.md +252 -86
  38. package/kb/site/reference/index.md +2 -0
  39. package/kb/site/reference/persistence-catalog.md +76 -13
  40. package/kb/site/reference/subsystems/client-modules.md +11 -3
  41. package/kb/site/reference/subsystems/commands.md +28 -5
  42. package/kb/site/reference/subsystems/index.md +1 -0
  43. package/kb/site/reference/subsystems/llm-streaming.md +11 -2
  44. package/kb/site/reference/subsystems/persistence.md +3 -3
  45. package/kb/site/reference/subsystems/plan.md +1 -1
  46. package/kb/site/reference/subsystems/session-reference.md +71 -5
  47. package/kb/site/reference/subsystems/session.md +6 -2
  48. package/kb/site/reference/subsystems/subagent.md +22 -3
  49. package/kb/site/reference/subsystems/web.md +5 -4
  50. package/kb/site/reference/tool-catalog.md +352 -5
  51. package/lib/index.js +113 -0
  52. package/package.json +14 -2
  53. package/scripts/rebuild-index.mjs +2 -1
  54. package/scripts/selfcheck.mjs +30 -0
  55. package/skills/dsh-plugin-dev-kb.md +2 -2
@@ -95,7 +95,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
95
95
  }[T]
96
96
  ```
97
97
 
98
- Sources: [`packages/core/session/src/types.ts:336`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:343`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:372`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:404`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
98
+ Sources: [`packages/core/session/src/types.ts:340`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:347`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:376`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:408`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
99
99
 
100
100
  ## Events
101
101
 
@@ -231,14 +231,18 @@ Source: [`packages/core/session/src/types.ts:266`](https://github.com/deepseek-a
231
231
  * Assembled assistant message for one step (derived history uses this).
232
232
  * Carries the step's `usage` when the adapter reported token accounting, so
233
233
  * the model output and its accounting travel together (there is no separate
234
- * usage record). `usage` is absent when the adapter reported none.
234
+ * usage record). `usage` is absent when the adapter reported none. A turn
235
+ * cancelled mid-stream finalizes its delivered text/reasoning prefix as this
236
+ * event with `interrupted: true`; undispatched tool calls are absent. The
237
+ * marker distinguishes that prefix without re-deriving interruption from turn
238
+ * boundaries. An aborted turn with no such event streamed no visible content.
235
239
  */
236
- 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage }
240
+ 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true }
237
241
  ```
238
242
 
239
243
  Types: [TokenUsage](./subsystems/llm-streaming.md)
240
244
 
241
- Source: [`packages/core/session/src/types.ts:273`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
245
+ Source: [`packages/core/session/src/types.ts:277`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
242
246
 
243
247
  ### `command/*`
244
248
 
@@ -261,7 +265,7 @@ Source: [`packages/core/session/src/types.ts:273`](https://github.com/deepseek-a
261
265
  }
262
266
  ```
263
267
 
264
- Source: [`packages/interaction/commands/src/types.ts:95`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
268
+ Source: [`packages/interaction/commands/src/types.ts:103`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
265
269
 
266
270
  <a id="commandrun--log-only"></a>
267
271
 
@@ -281,7 +285,7 @@ Source: [`packages/interaction/commands/src/types.ts:95`](https://github.com/dee
281
285
  'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource }
282
286
  ```
283
287
 
284
- Source: [`packages/interaction/commands/src/types.ts:88`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
288
+ Source: [`packages/interaction/commands/src/types.ts:96`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
285
289
 
286
290
  ### `compaction/*`
287
291
 
@@ -532,7 +536,7 @@ Source: [`packages/interaction/permission-presets/src/index.ts:50`](https://gith
532
536
  'plan/mode': { active: boolean }
533
537
  ```
534
538
 
535
- Source: [`packages/plan/plan-mode/src/index.ts:53`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/src/index.ts)
539
+ Source: [`packages/plan/plan-mode/src/index.ts:54`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/src/index.ts)
536
540
 
537
541
  ### `request/*`
538
542
 
@@ -548,7 +552,7 @@ Source: [`packages/plan/plan-mode/src/index.ts:53`](https://github.com/deepseek-
548
552
  'request/context': RequestContext
549
553
  ```
550
554
 
551
- Source: [`packages/core/session/src/types.ts:309`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
555
+ Source: [`packages/core/session/src/types.ts:313`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
552
556
 
553
557
  <a id="requestheader--log-only"></a>
554
558
 
@@ -562,7 +566,7 @@ Source: [`packages/core/session/src/types.ts:309`](https://github.com/deepseek-a
562
566
  'request/header': { header: EpochHeader; reason: RequestHeaderReason }
563
567
  ```
564
568
 
565
- Source: [`packages/core/session/src/types.ts:304`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
569
+ Source: [`packages/core/session/src/types.ts:308`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
566
570
 
567
571
  ### `sandbox/*`
568
572
 
@@ -637,7 +641,7 @@ Source: [`packages/schedule/schedule/src/types.ts:219`](https://github.com/deeps
637
641
  'session/end-seed': Record<string, never>
638
642
  ```
639
643
 
640
- Source: [`packages/core/session/src/types.ts:332`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
644
+ Source: [`packages/core/session/src/types.ts:336`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
641
645
 
642
646
  <a id="sessiontitle--log-only"></a>
643
647
 
@@ -711,6 +715,65 @@ Source: [`packages/core/session/src/types.ts:254`](https://github.com/deepseek-a
711
715
 
712
716
  Source: [`packages/subagent/subagent/src/descriptor.ts:37`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/subagent/src/descriptor.ts)
713
717
 
718
+ ### `team/*`
719
+
720
+ <a id="teammember--log-only"></a>
721
+
722
+ #### `team/member` — log-only
723
+
724
+ ```ts persistence-catalog
725
+ /** Whole teammate lifecycle value, stored only in the Team Lead Session. */
726
+ 'team/member': { version: 1; teamId: TeamId; member: TeamMemberSnapshot }
727
+ ```
728
+
729
+ Types: [TeamId](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) · [TeamMemberSnapshot](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md)
730
+
731
+ Source: [`packages/experimental/agent-team/src/types.ts:206`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/experimental/agent-team/src/types.ts)
732
+
733
+ <a id="teammessagedelivered--log-only"></a>
734
+
735
+ #### `team/message/delivered` — log-only
736
+
737
+ ```ts persistence-catalog
738
+ /** Durable acknowledgement that the target Session recorded the message. */
739
+ 'team/message/delivered': {
740
+ version: 1
741
+ teamId: TeamId
742
+ messageId: TeamMessageId
743
+ targetId: SessionId
744
+ }
745
+ ```
746
+
747
+ Types: [TeamId](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) · [TeamMessageId](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md)
748
+
749
+ Source: [`packages/experimental/agent-team/src/types.ts:212`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/experimental/agent-team/src/types.ts)
750
+
751
+ <a id="teammessagequeued--log-only"></a>
752
+
753
+ #### `team/message/queued` — log-only
754
+
755
+ ```ts persistence-catalog
756
+ /** Durable mailbox enqueue, stored before delivery is attempted. */
757
+ 'team/message/queued': { version: 1; teamId: TeamId; message: TeamMessageSnapshot }
758
+ ```
759
+
760
+ Types: [TeamId](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) · [TeamMessageSnapshot](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md)
761
+
762
+ Source: [`packages/experimental/agent-team/src/types.ts:210`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/experimental/agent-team/src/types.ts)
763
+
764
+ <a id="teamtask--log-only"></a>
765
+
766
+ #### `team/task` — log-only
767
+
768
+ ```ts persistence-catalog
769
+ /** Whole shared-task value, stored only in the Team Lead Session. */
770
+ 'team/task': { version: 1; teamId: TeamId; task: TeamTaskSnapshot }
771
+ ```
772
+
773
+ Types: [TeamId](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) · [TeamTaskSnapshot](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md)
774
+
775
+ Source: [`packages/experimental/agent-team/src/types.ts:208`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/experimental/agent-team/src/types.ts)
776
+
714
777
  ### `todo/*`
715
778
 
716
779
  <a id="todowrite--log-only"></a>
@@ -724,7 +787,7 @@ Source: [`packages/subagent/subagent/src/descriptor.ts:37`](https://github.com/d
724
787
 
725
788
  Types: [TodoItem](./subsystems/session.md)
726
789
 
727
- Source: [`packages/core/session/src/types.ts:299`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
790
+ Source: [`packages/core/session/src/types.ts:303`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
728
791
 
729
792
  ### `tool/*`
730
793
 
@@ -743,7 +806,7 @@ Source: [`packages/core/session/src/types.ts:299`](https://github.com/deepseek-a
743
806
 
744
807
  Types: [CallId](./subsystems/core.md)
745
808
 
746
- Source: [`packages/core/session/src/types.ts:279`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
809
+ Source: [`packages/core/session/src/types.ts:283`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
747
810
 
748
811
  <a id="toolcode-dispatch--log-only"></a>
749
812
 
@@ -818,7 +881,7 @@ Source: [`packages/core/tools/src/types.ts:40`](https://github.com/deepseek-ai/d
818
881
  }
819
882
  ```
820
883
 
821
- Source: [`packages/core/session/src/types.ts:291`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
884
+ Source: [`packages/core/session/src/types.ts:295`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
822
885
 
823
886
  ### `tool-workflow/*`
824
887
 
@@ -19,7 +19,9 @@ The graph is the wire single source between the Node and browser halves: the hos
19
19
  * single source: the host node half (package root) produces this same shape.
20
20
  * `immediately` marks stage-one prefetch; `inject` is informational graph
21
21
  * metadata (the authoritative edges live in each package's `dsh.client`
22
- * declaration and reach fibers through entry creation).
22
+ * declaration and reach fibers through entry creation). `external` carries
23
+ * module-graph edges: unlike `inject`, they constrain code arrival because
24
+ * `require` is synchronous (see {@link WebBootGraph.entries}).
23
25
  */
24
26
  interface WebBootEntry {
25
27
  /** Entry name == package name. */
@@ -32,6 +34,8 @@ interface WebBootEntry {
32
34
  inject?: string[]
33
35
  /** Stage-one prefetch mark: load the script for factory registration during module-face boot. */
34
36
  immediately?: boolean
37
+ /** Non-baseline module specifiers this row requests; omitted when it requests none. */
38
+ external?: string[]
35
39
  }
36
40
  ```
37
41
 
@@ -40,7 +44,11 @@ interface WebBootEntry {
40
44
  interface WebBootGraph {
41
45
  /** Consistency anchor over the whole graph (content + bundle hashes). */
42
46
  rev: string
43
- /** Composed entries; order carries no semantics (activation order is fiber inject waiting). */
47
+ /**
48
+ * Composed entries in module-graph order — a dynamic package row precedes
49
+ * rows whose `external` requests that package. Cordis activation order is
50
+ * unrelated and remains owned by fiber service waiting.
51
+ */
44
52
  entries: WebBootEntry[]
45
53
  }
46
54
  ```
@@ -117,5 +125,5 @@ onRebuilt(listener: (id: string, rev: string) => void): () => void
117
125
  onGraphChanged(listener: () => void): () => void
118
126
  ```
119
127
 
120
- Source: [`packages/client/modules/src/index.ts:184`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/index.ts)
128
+ Source: [`packages/client/modules/src/index.ts:295`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/index.ts)
121
129
  <!-- END GENERATED cordis-surface -->
@@ -11,13 +11,21 @@ Source: [`packages/interaction/commands/src/index.ts`](https://github.com/deepse
11
11
 
12
12
  ## Input metadata
13
13
 
14
- The service exposes one optional unstructured-input hint. Command availability follows plugin composition: every adapter consuming the registry sees every effective definition.
14
+ The service exposes one optional unstructured-input descriptor: a hint plus an image-acceptance flag. Command availability follows plugin composition: every adapter consuming the registry sees every effective definition.
15
15
 
16
16
  ```ts type-equiv
17
17
  /** Immutable metadata for a command's optional unstructured input. */
18
18
  interface CommandInputDescriptor {
19
19
  /** Placeholder shown before the user supplies free-form input. */
20
20
  readonly hint: string
21
+ /**
22
+ * Whether composer image attachments may accompany an invocation. Absent or
23
+ * false = the executor rejects an invocation carrying images and capable
24
+ * composers refuse the submission before dispatch. A declaring command's
25
+ * handler receives the admitted durable blocks and owns every further
26
+ * grammar decision, including rejecting sub-commands that cannot use them.
27
+ */
28
+ readonly images?: boolean
21
29
  }
22
30
  ```
23
31
 
@@ -58,6 +66,14 @@ interface CommandInvocation {
58
66
  readonly agent: Agent
59
67
  /** Exact text following the registered command name, including separator whitespace. */
60
68
  readonly rawInput: string
69
+ /**
70
+ * Durably admitted image blocks accompanying this invocation, in submission
71
+ * order; empty unless the definition declares `input.images`. The handler
72
+ * owns their model-visible use — the registry never schedules them itself —
73
+ * and a handler whose grammar cannot use them in this invocation returns an
74
+ * error so the dispatching composer retains the originals.
75
+ */
76
+ readonly attachments: readonly ImageBlock[]
61
77
  /** Cancellation signal owned by the dispatching UI request. */
62
78
  readonly signal: AbortSignal
63
79
  }
@@ -153,18 +169,25 @@ find(agent: Agent, name: string): CommandDefinition | undefined
153
169
  * handler-failure path is contained so the handler's own error stays the
154
170
  * reported failure.
155
171
  *
172
+ * Image admission is enforced here, not in the composer: images sent to a
173
+ * command that does not declare `input.images`, an absent attachment store,
174
+ * and an exceeded attachment limit each settle as an error result before
175
+ * the handler runs, and a rejected batch publishes no durable object.
176
+ *
156
177
  * @param agent - exact receiving agent.
157
178
  * @param line - complete slash-command line.
179
+ * @param images - base64-encoded composer images accompanying the line, in
180
+ * submission order; empty for a plain invocation.
158
181
  * @param signal - cancellation signal owned by the UI request.
159
182
  * @returns the settled execution (result + lifecycle pairing id), or
160
183
  * `undefined` when syntax or name does not resolve.
161
184
  */
162
- @Remote async execute( agent: Agent, line: string, signal: AbortSignal, ): Promise<CommandExecution | undefined>
185
+ @Remote async execute( agent: Agent, line: string, images: readonly EncodedImageAttachment[], signal: AbortSignal, ): Promise<CommandExecution | undefined>
163
186
  ```
164
187
 
165
- Types: [Agent](./core.md)
188
+ Types: [Agent](./core.md) · [EncodedImageAttachment](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/attachment.md)
166
189
 
167
- Source: [`packages/interaction/commands/src/index.ts:225`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/index.ts)
190
+ Source: [`packages/interaction/commands/src/index.ts:250`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/index.ts)
168
191
 
169
192
  <a id="commands-events"></a>
170
193
 
@@ -186,5 +209,5 @@ A command was registered or unregistered. This is an unfiltered registry notific
186
209
  'commands/change'(): void
187
210
  ```
188
211
 
189
- Source: [`packages/interaction/commands/src/types.ts:72`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
212
+ Source: [`packages/interaction/commands/src/types.ts:80`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
190
213
  <!-- END GENERATED cordis-surface -->
@@ -41,6 +41,7 @@ One page per subsystem of the DeepSeek Harness: what it is, the data structures
41
41
  | [skills.md](./skills.md) | the skill service: discovery priority, `SkillSummary`/`SkillDefinition`, session-prefix catalog, model-facing `skill` loading |
42
42
  | [compaction.md](./compaction.md) | the compaction seam: the `compaction/*` session events, `CompactionResult`, the `CompactionEngine` interface |
43
43
  | [subagent.md](./subagent.md) | the subagent seam: the named-provider registry, `SubagentStartRequest`/`Result`/`Run`, the start-time-vs-runtime capability split |
44
+ | [agent-team.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) | Agent Teams: implicit Lead identity, named continuable teammates, durable peer mailbox, and shared task DAG |
44
45
  | [web.md](./web.md) | the web access seam: `WebSearchRequest`/`Result`, `WebFetchRequest`/`Result`, `WebFetchBody`, provider availability, `WebError` |
45
46
  | [spill.md](./spill.md) | the spill storage seam: `SaveTextSpill`, `SpillOwner`/`SpillSource`, `SpillRef`, the branded `SpillLocator` |
46
47
  | [workflow.md](./workflow.md) | the workflow seam: `WorkflowStartRequest`, `WorkflowMeta`, `WorkflowRun`/`Result`, the `workflow/*` event payloads, `WorkflowError` fatality |
@@ -243,7 +243,7 @@ Every adapter MUST obey these, and every consumer may rely on them:
243
243
 
244
244
  ## `ResolvedRetryPolicy`
245
245
 
246
- Provider configuration resolves before route registration into an immutable discriminated union. Normal mode carries `mode: 'normal'`, finite `maxRetries`, `retryableCodes`, and required `initialDelayMs`, `maxDelayMs`, and `jitterRatio`; always mode carries `mode: 'always'` and the same required backoff fields without a finite maximum. `LlmRuntime.providerRetryPolicy(provider)` returns the currently registered value and supplies normal defaults when the adapter omits one; `llmRetryPolicyOf(stream)` returns the value captured from the serving registration after the call selects that registration, so later route disposal or replacement cannot change an in-flight failure's recovery policy. The [generated config catalog](../config-catalog.md) lists the optional input fields.
246
+ Retry configuration resolves before route registration into an immutable discriminated union. Normal mode carries `mode: 'normal'`, finite `maxRetries`, `retryableCodes`, and required `initialDelayMs`, `maxDelayMs`, and `jitterRatio`; always mode carries `mode: 'always'` and the same required backoff fields without a finite maximum. Omitting a provider policy uses the normal default of five retries. Layered settings may retain normal-only `maxRetries` or `retryableCodes` after switching to always mode; the resolver ignores those inactive fields and captures the pure always policy. `LlmRuntime.providerRetryPolicy(provider)` returns the registered value, and `llmRetryPolicyOf(stream)` returns the value captured from the serving registration after the call selects it, so later route disposal or replacement cannot change an in-flight failure's recovery policy. The [generated config catalog](../config-catalog.md) lists the optional input fields.
247
247
 
248
248
  ## `AppIdentity` — app attribution
249
249
 
@@ -301,7 +301,8 @@ One keep/drop decision covers content and metadata together: a `max-tokens` fini
301
301
  * {@link ContentBlock}s and a final assistant {@link Message}.
302
302
  *
303
303
  * The agent loop feeds it while logging raw chunks for replay fidelity, then
304
- * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends.
304
+ * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends,
305
+ * or `interruptedBlocks()` when cancellation cut the stream short.
305
306
  *
306
307
  * Tolerant of delta-only protocols (no block-start/end); deltas arriving for
307
308
  * an index already closed by `block-end` are ignored (malformed stream) so a
@@ -320,6 +321,14 @@ declare class BlockAssembler {
320
321
  * its accumulated deltas (an unknown block type never closed by `block-end` throws).
321
322
  */
322
323
  blocks(): ContentBlock[];
324
+ /**
325
+ * Assemble the prefix an interrupted stream can safely finalize: closed and
326
+ * open text/reasoning blocks with non-whitespace content, in stream order.
327
+ * Tool calls are omitted because interruption precedes dispatch; retaining
328
+ * one would require a fabricated result. Open unknown blocks are also omitted.
329
+ * @returns the kept blocks; empty when nothing streamed before the interruption.
330
+ */
331
+ interruptedBlocks(): ContentBlock[];
323
332
  /** Usage from the `usage` chunk; undefined until one arrives. */
324
333
  get usage(): TokenUsage | undefined;
325
334
  /** Finish reason from the `finish` chunk; `{kind: 'stop'}` when the stream ended without one. */
@@ -7,7 +7,7 @@ outline: [2,3]
7
7
 
8
8
  The **durability seam** for the event log. [session.md](./session.md) describes the in-memory `Session` — the append-only `SessionEvent` log that is the source of truth. This page describes how that log is made durable: the abstract `SessionPersistence` service, its backends, the flush checkpoint, crash recovery, and the metadata header that travels alongside the log. The event vocabulary the log carries is enumerated, member by member, in the generated [persistence log event catalog](../persistence-catalog.md).
9
9
 
10
- The seam is a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md): one abstract service ([dsh-session-persistence](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence), `ctx.sessionPersistence`) defining locate/create/append, reusable Session preparation, logical load/inspect, physical suffix reads, and lightweight list/snapshot observation over the existing `SessionEvent` — **no parallel persisted event type** — and two interchangeable backends implementing the same contract. See the [session-persistence Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-14-session-persistence.md).
10
+ The seam is a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md): one abstract service ([dsh-session-persistence](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence), `ctx.sessionPersistence`) defining locate/create/append, reusable Session preparation, logical load/inspect, physical suffix reads, and lightweight list/snapshot observation over the existing `SessionEvent` — **no parallel persisted event type** — and three interchangeable providers implementing the same contract. See the [session-persistence Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-14-session-persistence.md).
11
11
 
12
12
  ## The flush checkpoint
13
13
 
@@ -233,10 +233,10 @@ interface SessionPersistenceSnapshot {
233
233
 
234
234
  ## The backends
235
235
 
236
- Both implement the same abstract `SessionPersistence` (locate/create/append/prepare/load/inspect/readFrom/list/listSnapshots over `SessionEvent`, with optional cancellation on observation methods) and pass the shared `runPersistenceContract` suite:
236
+ All implement the same abstract `SessionPersistence` (locate/create/append/prepare/load/inspect/readFrom/list/listSnapshots over `SessionEvent`, with optional cancellation on observation methods) and pass the shared `runPersistenceContract` suite:
237
237
 
238
238
  - **[dsh-session-persistence-jsonl](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-jsonl)** — an append-only logical JSONL log per session, stored as checksummed concatenated Zstandard frames by default or raw lines by configuration, with crash-safe atomic writes, interrupted-turn recovery, and a read/replay path.
239
- - **[dsh-session-persistence-sqlite](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-sqlite)** — `node:sqlite`, one row per `SessionEvent`. The row fields `(session_id, seq, type, time, data, source_event_seqs, surface_op)` map 1:1 onto the event, including optional surface metadata, so there is no parallel persisted schema to keep in sync.
239
+ - **[dsh-session-persistence-sqlite](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-sqlite)** — an opt-in `node:sqlite` backend using schema 17 to store exact same-block delta runs in bounded physical `text-chunks`, `reasoning-chunks`, and `tool-call-chunks` rows. It reconstructs the complete logical event stream before returning it, packs only newly durable batches, and rejects older schemas rather than migrating them.
240
240
 
241
241
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
242
242
 
@@ -86,5 +86,5 @@ set(agent: Agent, active: boolean): 'committed' | 'queued' | 'cancelled' | 'noop
86
86
 
87
87
  Types: [Agent](./core.md)
88
88
 
89
- Source: [`packages/plan/plan-mode/src/index.ts:184`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/src/index.ts)
89
+ Source: [`packages/plan/plan-mode/src/index.ts:188`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/src/index.ts)
90
90
  <!-- END GENERATED cordis-surface -->
@@ -5,9 +5,23 @@ outline: [2,3]
5
5
 
6
6
  # Session References
7
7
 
8
- Structured cross-session reference requests and prepared message contexts. The [package contract](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/session-reference) defines canonical URIs, current-surface projection, tag-safe JSON and byte retention, stable errors, and the untrusted model prompt. Host adapters use these types instead of passing their UI mention syntax into the agent core.
8
+ Host-backed file discovery plus structured cross-session reference requests and prepared message contexts. The [file-reference contract](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/file-reference) owns path-only completion records and grammar; the [session-reference contract](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/session-reference) defines canonical URIs, current-surface projection, tag-safe JSON and byte retention, stable errors, and the untrusted model prompt. Host adapters use these types instead of passing their UI mention syntax into the agent core.
9
9
 
10
- Source: [`packages/context/session-reference/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/session-reference/src/types.ts)
10
+ Sources: [`packages/context/file-reference/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/file-reference/src/types.ts) · [`packages/context/session-reference/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/session-reference/src/types.ts)
11
+
12
+ ## File candidates
13
+
14
+ `FileReferenceCandidate` is the path-only discovery result. The addressed agent supplies the working-directory scope; providers decide ranking and namespace access without reading file contents.
15
+
16
+ ```ts type-equiv
17
+ /** One path-only completion candidate inside the target session cwd. */
18
+ interface FileReferenceCandidate {
19
+ /** User-facing path accepted by normal prompts and filesystem tools. */
20
+ path: string
21
+ /** Directories keep completion open; files finish the mention. */
22
+ kind: 'file' | 'directory'
23
+ }
24
+ ```
11
25
 
12
26
  ## Inputs and candidates
13
27
 
@@ -39,6 +53,16 @@ interface SessionReferenceCandidate {
39
53
  }
40
54
  ```
41
55
 
56
+ The `sessionReferenceResolver/candidates` Remote method serves the same discovery to browser consumers and attaches each candidate's canonical prompt mention.
57
+
58
+ ```ts type-equiv
59
+ /** One discovery candidate carrying its canonical prompt mention. */
60
+ interface SessionReferenceMentionCandidate extends SessionReferenceCandidate {
61
+ /** Canonical `@[label](dsh-session:…)` mention serialized into the prompt draft. */
62
+ mention: string
63
+ }
64
+ ```
65
+
42
66
  ## Prepared messages
43
67
 
44
68
  Preparation preserves readable current-message content and returns at most one aggregated context.
@@ -77,6 +101,37 @@ type SessionReferenceErrorCode =
77
101
 
78
102
  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`) — this section is byte-identical in both language sides of the page. 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).
79
103
 
104
+ <a id="ctxfilereferences--filereferenceservice-abstract-seam"></a>
105
+
106
+ ### `ctx.fileReferences` — `FileReferenceService` (abstract seam)
107
+
108
+ Host capability for cancellable file-reference discovery.
109
+
110
+ ```ts cordis-catalog
111
+ /**
112
+ * List file and directory candidates for one agent's working directory.
113
+ * @param agent - target agent whose session cwd bounds discovery.
114
+ * @param query - path text following `@` or `@"`.
115
+ * @param signal - caller cancellation.
116
+ * @returns deterministic path-only candidates.
117
+ */
118
+ abstract list( agent: Agent, query: string, signal: AbortSignal, ): Promise<FileReferenceCandidate[]>
119
+
120
+ /**
121
+ * Remote face of {@link list}; the decorator cannot mark the abstract
122
+ * member, so this concrete adapter carries the identical contract.
123
+ * @param agent - target agent whose session cwd bounds discovery.
124
+ * @param query - path text following `@` or `@"`.
125
+ * @param signal - caller cancellation.
126
+ * @returns deterministic path-only candidates.
127
+ */
128
+ @Remote('list') remoteExportList( agent: Agent, query: string, signal: AbortSignal, ): Promise<FileReferenceCandidate[]>
129
+ ```
130
+
131
+ Types: [Agent](./core.md)
132
+
133
+ Source: [`packages/context/file-reference/src/index.ts:27`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/file-reference/src/index.ts)
134
+
80
135
  <a id="ctxsessionreferenceresolver--sessionreferenceresolver"></a>
81
136
 
82
137
  ### `ctx.sessionReferenceResolver` — `SessionReferenceResolver`
@@ -95,11 +150,22 @@ Exact-read consumer that prepares immutable cross-session message context.
95
150
  async listCandidates( agent: Agent, query: string = '', limit: number = this.config.candidateLimit, signal?: AbortSignal, ): Promise<SessionReferenceCandidate[]>
96
151
 
97
152
  /**
98
- * Snapshot all references before enqueue and return one aggregated durable context.
153
+ * Remote face of {@link listCandidates}: the configured candidate limit
154
+ * applies, and every candidate carries the canonical mention a host inserts
155
+ * into the prompt draft.
156
+ * @param agent - target agent; self is excluded and its cwd drives ranking.
157
+ * @param query - optional case-insensitive session-id/cwd/title substring.
158
+ * @param signal - caller cancellation.
159
+ * @returns mention-carrying candidates in rank order.
160
+ */
161
+ @Remote('candidates') async remoteExportCandidates( agent: Agent, query: string, signal: AbortSignal, ): Promise<SessionReferenceMentionCandidate[]>
162
+
163
+ /**
164
+ * Snapshot all references for one accepted direct message and return one aggregated durable context.
99
165
  * @param agent - target agent; references to it are rejected.
100
166
  * @param content - already host-normalized readable message content.
101
167
  * @param references - structured source sessions in mention order.
102
- * @param signal - optional cancellation boundary for host request teardown.
168
+ * @param signal - optional cancellation boundary for the active turn.
103
169
  * @returns detached content and optional referenced-session context.
104
170
  */
105
171
  async prepare( agent: Agent, content: ContentBlock[], references: SessionReferenceInput[], signal?: AbortSignal, ): Promise<PreparedReferencedMessage>
@@ -107,5 +173,5 @@ async prepare( agent: Agent, content: ContentBlock[], references: SessionReferen
107
173
 
108
174
  Types: [Agent](./core.md) · [ContentBlock](./llm-streaming.md)
109
175
 
110
- Source: [`packages/context/session-reference/src/index.ts:70`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/session-reference/src/index.ts)
176
+ Source: [`packages/context/session-reference/src/index.ts:75`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/session-reference/src/index.ts)
111
177
  <!-- END GENERATED cordis-surface -->
@@ -62,9 +62,13 @@ interface SessionEventMap {
62
62
  * Assembled assistant message for one step (derived history uses this).
63
63
  * Carries the step's `usage` when the adapter reported token accounting, so
64
64
  * the model output and its accounting travel together (there is no separate
65
- * usage record). `usage` is absent when the adapter reported none.
65
+ * usage record). `usage` is absent when the adapter reported none. A turn
66
+ * cancelled mid-stream finalizes its delivered text/reasoning prefix as this
67
+ * event with `interrupted: true`; undispatched tool calls are absent. The
68
+ * marker distinguishes that prefix without re-deriving interruption from turn
69
+ * boundaries. An aborted turn with no such event streamed no visible content.
66
70
  */
67
- 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage }
71
+ 'assistant/message': { turn: number; step: number; message: AssistantMessage; usage?: TokenUsage; interrupted?: true }
68
72
  /**
69
73
  * The model requested one tool invocation: `name` with the raw `arguments`
70
74
  * JSON string exactly as the model produced it (unparsed). `callId` pairs the
@@ -194,7 +194,7 @@ interface ContinuableStart {
194
194
 
195
195
  An optional continuable-child setup contribution can install scope-local capabilities after base child composition and before Activation publication. The registry is ordered and transactional: a failed or revoked setup rolls back the unpublished Activation, child-scope disposal releases every installation, new registrations affect the next Activation, and registration removal revokes every resident installation immediately.
196
196
 
197
- `SubagentRuntime.reportFrom()` uses that extension point without adding a second queue or a result-bearing child wrapper. The exact live child Agent authorizes the call; callers cannot name a recipient. The manager derives the only recipient from the child's durable `parentSession`, requires that parent Agent to be live, frames the selected content as one `subagent-report` user message, and returns the message's stable `MessageId`. Quiet delivery uses `Agent.inject()` and creates no inbox occurrence or parent turn; waking delivery uses `Agent.followup()` and creates one ordinary later parent turn. Neither mode concludes the child's turn, and no final answer reports implicitly.
197
+ `SubagentRuntime.reportFrom()` uses that extension point without adding a second queue or a result-bearing child wrapper. The exact live child Agent authorizes the call; callers cannot name a recipient. The manager derives the only recipient from the child's durable `parentSession`, requires that parent Agent to be live, frames the selected content as one `subagent-report` user message, and returns the message's stable `MessageId`. Quiet delivery uses `Agent.inject()` and does not wake the parent; next-step delivery uses `Agent.steer()`, waking an idle parent or joining a running parent's nearest step boundary. Neither mode concludes the child's turn, and no final answer reports implicitly.
198
198
 
199
199
  ```ts type-equiv
200
200
  /** Durable attribution for a continuable child's explicit parent report. */
@@ -209,7 +209,7 @@ interface SubagentReportMessageSource {
209
209
 
210
210
  ```ts type-equiv
211
211
  /** Deployment scheduling policy for accepted child reports. */
212
- type SubagentReportDelivery = 'quiet' | 'wakeup'
212
+ type SubagentReportDelivery = 'quiet' | 'next-step'
213
213
  ```
214
214
 
215
215
  Reporting is the child's own choice, so the manager keeps a separate account of its own: when a resident Activation settles, it delivers one notice to the child's durable direct parent describing how that epoch ended and carrying its final assistant content. That delivery is unconditional for every child whose id a caller received, happens before the ownership release that would let the parent be judged settled, and reaches a resident parent through the same waking-admission accounting as a report. A parent whose own lineage is already tearing down receives it without a wake, because waking a quiescent Agent starts a turn rather than queueing work. Its provenance is a distinct kind so a transcript never presents a runtime account as something the child wrote.
@@ -310,7 +310,7 @@ type SubagentDescendantListEntry = SubagentListEntry & {
310
310
 
311
311
  ## The terminal result: `SubagentResult`
312
312
 
313
- The outcome of a one-shot run, resolved by `SubagentRun.result`. `structured` is present only after a requested `outputSchema` was successfully satisfied; requesting a schema does not guarantee it, and a provider may return `stopReason: 'error'` when the child fails or finishes without a valid capture. A non-`completed` `stopReason` means `output` may be partial — the consumer maps it to an `isError` tool result rather than reporting partial output as success.
313
+ The outcome of a one-shot run, resolved by `SubagentRun.result`. `structured` is present only after a requested `outputSchema` was successfully satisfied; requesting a schema does not guarantee it, and a provider may return `stopReason: 'error'` when the child fails or finishes without a valid capture. A provider may attach a safe, non-assistant `diagnostic` to a non-`completed` result; the provider removes tool inputs, file contents, environment values, credentials, and raw protocol payloads and limits the complete value to 4096 UTF-8 bytes before consumers present it separately from `output`. A non-`completed` `stopReason` means `output` may be partial — the consumer maps it to an `isError` tool result rather than reporting partial output as success.
314
314
 
315
315
  ```ts type-equiv
316
316
  /**
@@ -333,6 +333,13 @@ interface SubagentResult {
333
333
  * schema-agnostic.
334
334
  */
335
335
  readonly structured?: unknown
336
+ /**
337
+ * Provider-authored, non-assistant failure detail for a non-`completed`
338
+ * result. Providers keep this text free of tool inputs, file contents,
339
+ * environment values, credentials, and raw protocol payloads, and limit it
340
+ * to 4096 UTF-8 bytes. Consumers present it separately from {@link output}.
341
+ */
342
+ readonly diagnostic?: string
336
343
  /** Why the run ended. A non-`completed` reason means `output` may be partial. */
337
344
  readonly stopReason: SubagentStopReason
338
345
  }
@@ -565,6 +572,18 @@ registerContinuableSetup(contribution: ContinuableSetupContribution): () => void
565
572
  */
566
573
  async drainContinuableDescendants(parents: readonly Agent[]): Promise<void>
567
574
 
575
+ /**
576
+ * Release selected resident continuable direct children of one exact live
577
+ * parent. Other children of the same parent remain admitted and resident.
578
+ * Absent targets and a manager-less composition are accepted no-ops.
579
+ * @param parent - exact live direct parent authorizing the selected release.
580
+ * @param childIds - durable direct-child ids to release when resident.
581
+ * @returns once every selected Activation released its `AgentHandle`.
582
+ * @throws {SubagentError} `UNAUTHORIZED` when a resident target belongs to a
583
+ * different parent or the supplied parent identity is stale.
584
+ */
585
+ async drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise<void>
586
+
568
587
  /**
569
588
  * Enumerate the parent's direct session-backed subagents without loading or
570
589
  * resuming an Agent and without any query service: the listing merges the live
@@ -15,13 +15,14 @@ Search and fetch share no request schema and no business logic, but they are del
15
15
 
16
16
  ## Search request and result
17
17
 
18
- The model-facing tool argument is just a `query`; `maxResults` is a consumer-owned bound (`dsh-tool-web`'s `searchMaxResults` config, default `8`) passed through the seam and enforced on the way back — if a provider over-returns, the seam truncates `sources[]` and sets `truncated`.
18
+ Each seam request carries exactly one `query`. The `dsh-tool-web` consumer accepts a required `queries` array and fans it out into separate seam requests; a one-item array performs one search. `maxResults` is a consumer-owned bound (`dsh-tool-web`'s `searchMaxResults` config, default `8`) passed through the seam and enforced on the way back — if a provider over-returns, the seam truncates `sources[]` and sets `truncated`.
19
19
 
20
20
  ```ts type-equiv
21
21
  /**
22
- * What one search-capable backend can return. The model-facing argument is just
23
- * a query; `maxResults` is a `dsh-tool-web`-layer bound passed through unchanged
24
- * and enforced on the way back by the seam (see {@link WebSearchResult}).
22
+ * What one search-capable backend is asked to search. Each request carries one
23
+ * query; a consumer may issue several requests. `maxResults` is a
24
+ * `dsh-tool-web`-layer bound passed through unchanged and enforced on the way
25
+ * back by the seam (see {@link WebSearchResult}).
25
26
  */
26
27
  interface WebSearchRequest {
27
28
  readonly query: string