dsh-plugin-dev-kb 1.0.1 → 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 (54) hide show
  1. package/README.md +37 -4
  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/package.json +8 -2
  52. package/scripts/rebuild-index.mjs +2 -1
  53. package/scripts/selfcheck.mjs +30 -0
  54. package/skills/dsh-plugin-dev-kb.md +2 -2
@@ -107,6 +107,8 @@ turn/end
107
107
 
108
108
  seam 正是替换一个提供方就能改变整个产品的原因。文件系统与进程提供方共享同一个执行世界,因此把它们指向远程沙箱,也就把 Bash、PTY 和 LSP 一并搬了过去,无需提供方专用 fork。[subagent 提供方](./subsystems/subagent.md)在同一个接口之后同样千差万别,从新建一个子 agent,到把一个轮次委派给另一个产品。
109
109
 
110
+ [实验性 Agent Teams](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) 是 `ctx.agentTeams` 上的私有显式启用协作 seam,在可继续 subagent 之上提供持久 roster、任务板和 mailbox。
111
+
110
112
  ## 新行为的归属位置
111
113
 
112
114
  新行为附加到已有文档记录的扩展点。改动循环本身时,本映射随之更新。
@@ -95,7 +95,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
95
95
  }[T]
96
96
  ```
97
97
 
98
- 来源:[`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
+ 来源:[`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
  ## 事件
101
101
 
@@ -231,14 +231,18 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
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
  类型:[TokenUsage](./subsystems/llm-streaming.md)
240
244
 
241
- 来源:[`packages/core/session/src/types.ts:273`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
245
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
261
265
  }
262
266
  ```
263
267
 
264
- 来源:[`packages/interaction/commands/src/types.ts:95`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
268
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
281
285
  'command/run': { commandId: CommandId; name: string; args?: string; source: CommandSource }
282
286
  ```
283
287
 
284
- 来源:[`packages/interaction/commands/src/types.ts:88`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/types.ts)
288
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
532
536
  'plan/mode': { active: boolean }
533
537
  ```
534
538
 
535
- 来源:[`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
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
548
552
  'request/context': RequestContext
549
553
  ```
550
554
 
551
- 来源:[`packages/core/session/src/types.ts:309`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
555
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
562
566
  'request/header': { header: EpochHeader; reason: RequestHeaderReason }
563
567
  ```
564
568
 
565
- 来源:[`packages/core/session/src/types.ts:304`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
569
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
637
641
  'session/end-seed': Record<string, never>
638
642
  ```
639
643
 
640
- 来源:[`packages/core/session/src/types.ts:332`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
644
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
711
715
 
712
716
  来源:[`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
+ 类型:[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
+ 来源:[`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
+ 类型:[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
+ 来源:[`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
+ 类型:[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
+ 来源:[`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
+ 类型:[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
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
724
787
 
725
788
  类型:[TodoItem](./subsystems/session.md)
726
789
 
727
- 来源:[`packages/core/session/src/types.ts:299`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
790
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
743
806
 
744
807
  类型:[CallId](./subsystems/core.md)
745
808
 
746
- 来源:[`packages/core/session/src/types.ts:279`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
809
+ 来源:[`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 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
818
881
  }
819
882
  ```
820
883
 
821
- 来源:[`packages/core/session/src/types.ts:291`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
884
+ 来源:[`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 @@ Web 插件表:[dsh-client-modules](https://github.com/deepseek-ai/deepseek-har
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 @@ outline: [2,3]
11
11
 
12
12
  ## 输入元数据
13
13
 
14
- 该服务公开一个可选的非结构化输入提示。命令的可用性由插件组合决定:每个消费注册表的适配器都会看到全部生效定义。
14
+ 该服务公开一个可选的非结构化输入描述符:提示文本加图片接受标志。命令的可用性由插件组合决定:每个消费注册表的适配器都会看到全部生效定义。
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 @@ outline: [2,3]
41
41
  | [skills.md](./skills.md) | skill(技能)服务:发现优先级、`SkillSummary`/`SkillDefinition`、会话前缀目录、面向模型的 `skill` 加载 |
42
42
  | [compaction.md](./compaction.md) | 压缩(compaction)seam:`compaction/*` 会话事件、`CompactionResult`、`CompactionEngine` 接口 |
43
43
  | [subagent.md](./subagent.md) | subagent seam:命名提供方注册表、`SubagentStartRequest`/`Result`/`Run`、启动时与运行时能力拆分 |
44
+ | [agent-team.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/agent-team.md) | Agent Teams:隐式 Lead 身份、具名 continuable teammate、持久 peer mailbox 与共享任务 DAG |
44
45
  | [web.md](./web.md) | Web 访问 seam:`WebSearchRequest`/`Result`、`WebFetchRequest`/`Result`、`WebFetchBody`、提供方可用性、`WebError` |
45
46
  | [spill.md](./spill.md) | spill 存储 seam:`SaveTextSpill`、`SpillOwner`/`SpillSource`、`SpillRef`、品牌类型 `SpillLocator` |
46
47
  | [workflow.md](./workflow.md) | 工作流 seam:`WorkflowStartRequest`、`WorkflowMeta`、`WorkflowRun`/`Result`、`workflow/*` 事件载荷、`WorkflowError` 致命性 |
@@ -245,7 +245,7 @@ interface LlmFailure {
245
245
 
246
246
  ## `ResolvedRetryPolicy`
247
247
 
248
- 提供方配置会在路由注册前解析为不可变的可辨识联合。normal mode 携带 `mode: 'normal'`、有限的 `maxRetries`、`retryableCodes`,以及必填的 `initialDelayMs`、`maxDelayMs` 与 `jitterRatio`;always mode 携带 `mode: 'always'` 和相同的必填退避字段,但没有有限上限。`LlmRuntime.providerRetryPolicy(provider)` 返回当前注册的值,并在适配器省略策略时提供 normal 默认值;调用选定该注册后,`llmRetryPolicyOf(stream)` 返回为该调用服务的注册所捕获的值,因此之后释放或替换路由都无法改变进行中失败的恢复策略。可选配置输入字段由[生成的配置目录](../config-catalog.md)列出。
248
+ 重试配置会在路由注册前解析为不可变的可辨识联合。normal mode 携带 `mode: 'normal'`、有限的 `maxRetries`、`retryableCodes`,以及必填的 `initialDelayMs`、`maxDelayMs` 与 `jitterRatio`;always mode 携带 `mode: 'always'` 和相同的必填退避字段,但没有有限上限。省略提供方策略时使用重试五次的 normal 默认值。分层 settings 在切换到 always 模式后可能保留仅属于 normal 的 `maxRetries` 或 `retryableCodes`;解析器会忽略这些未启用字段,并捕获纯 always 策略。`LlmRuntime.providerRetryPolicy(provider)` 返回注册值;调用选定实际提供服务的注册后,`llmRetryPolicyOf(stream)` 返回从中捕获的值,因此之后释放或替换路由都无法改变进行中失败的恢复策略。可选配置输入字段由[生成的配置目录](../config-catalog.md)列出。
249
249
 
250
250
  ## `AppIdentity`:应用归属
251
251
 
@@ -307,7 +307,8 @@ interface TokenUsage {
307
307
  * {@link ContentBlock}s and a final assistant {@link Message}.
308
308
  *
309
309
  * The agent loop feeds it while logging raw chunks for replay fidelity, then
310
- * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends.
310
+ * reads `blocks()` / `message()` / `usage` / `finish` once the stream ends,
311
+ * or `interruptedBlocks()` when cancellation cut the stream short.
311
312
  *
312
313
  * Tolerant of delta-only protocols (no block-start/end); deltas arriving for
313
314
  * an index already closed by `block-end` are ignored (malformed stream) so a
@@ -326,6 +327,14 @@ declare class BlockAssembler {
326
327
  * its accumulated deltas (an unknown block type never closed by `block-end` throws).
327
328
  */
328
329
  blocks(): ContentBlock[];
330
+ /**
331
+ * Assemble the prefix an interrupted stream can safely finalize: closed and
332
+ * open text/reasoning blocks with non-whitespace content, in stream order.
333
+ * Tool calls are omitted because interruption precedes dispatch; retaining
334
+ * one would require a fabricated result. Open unknown blocks are also omitted.
335
+ * @returns the kept blocks; empty when nothing streamed before the interruption.
336
+ */
337
+ interruptedBlocks(): ContentBlock[];
329
338
  /** Usage from the `usage` chunk; undefined until one arrives. */
330
339
  get usage(): TokenUsage | undefined;
331
340
  /** 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
  事件日志的**持久性 seam**。[session.md](./session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述如何使该日志持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一同存储的元数据头。日志承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐项列举。
9
9
 
10
- 该 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence),`ctx.sessionPersistence`)在现有 `SessionEvent` 上定义 locate/create/append、可复用的 Session 准备流程、逻辑 load/inspect、物理后缀读取,以及轻量的 list/snapshot 观察——**没有平行的持久化事件类型**——以及两个实现同一约定的可互换后端。见 [session-persistence Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)。
10
+ 该 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence),`ctx.sessionPersistence`)在现有 `SessionEvent` 上定义 locate/create/append、可复用的 Session 准备流程、逻辑 load/inspect、物理后缀读取,以及轻量的 list/snapshot 观察——**没有平行的持久化事件类型**——以及三个实现同一约定的可互换提供方。见 [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
  ## flush 检查点
13
13
 
@@ -235,8 +235,8 @@ interface SessionPersistenceSnapshot {
235
235
 
236
236
  两者都实现同一个抽象 `SessionPersistence`(在 `SessionEvent` 上执行 locate/create/append/prepare/load/inspect/readFrom/list/listSnapshots,观察方法可选支持取消),并通过共享的 `runPersistenceContract` 套件:
237
237
 
238
- - **[dsh-session-persistence-jsonl](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-jsonl)**——每个会话一份仅追加的逻辑 JSONL 日志,默认存储为带 checksum 的连续 Zstandard frame,也可配置为原始行;支持崩溃安全的原子写入、被中断轮次的恢复以及读取/回放路径。
239
- - **[dsh-session-persistence-sqlite](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行字段 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包含可选的 surface 元数据),因此没有需要保持同步的并行持久化 schema
238
+ - **[dsh-session-persistence-jsonl](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-jsonl)**——逐会话仅追加的逻辑 JSONL 日志,默认存储为带 checksum 的连续 Zstandard frame,也可配置为原始行;支持崩溃安全的原子写入、被中断轮次的恢复以及读取/回放路径。
239
+ - **[dsh-session-persistence-sqlite](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-sqlite)**:一个可选启用的 `node:sqlite` 后端,使用 schema 17 把同一分片块中字段完全匹配的 delta 连续段存为有界物理 `text-chunks`、`reasoning-chunks` `tool-call-chunks` 行。它在返回前重建完整逻辑事件流,只打包新增的持久批次,并拒绝旧 schema,而不是执行迁移。
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
  # 会话引用
7
7
 
8
- 结构化的跨会话引用请求与准备后的消息上下文。[包约定](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/session-reference) 定义规范 URI、当前表层投影、标签安全的 JSON 与字节保留、稳定错误和不可信的模型提示词。宿主适配器使用这些类型,而不会把各自 UI 的提及语法传入 agent(智能体)核心。
8
+ 由 Host 支撑的文件发现,以及结构化的跨会话引用请求与准备后的消息上下文。[文件引用约定](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/file-reference)负责仅含路径的补全记录与语法;[会话引用约定](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/session-reference)定义规范 URI、当前表层投影、标签安全的 JSON 与字节保留、稳定错误和不可信的模型提示词。宿主适配器使用这些类型,而不会把各自 UI 的提及语法传入 agent(智能体)核心。
9
9
 
10
- 来源:[`packages/context/session-reference/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/context/session-reference/src/types.ts)
10
+ 来源:[`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
+ ## 文件候选项
13
+
14
+ `FileReferenceCandidate` 是仅含路径的发现结果。被寻址的 agent 提供工作目录范围;提供方负责排序和命名空间访问,但不会读取文件内容。
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
  ## 输入与候选项
13
27
 
@@ -39,6 +53,16 @@ interface SessionReferenceCandidate {
39
53
  }
40
54
  ```
41
55
 
56
+ `sessionReferenceResolver/candidates` Remote 方法向浏览器消费方提供同一发现能力,并为每个候选附上规范提示词 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
  ## 准备后的消息
43
67
 
44
68
  准备过程保留可读的当前消息内容,并最多返回一个聚合上下文。
@@ -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
  可选的可继续 child 设置贡献可以在 child 基础组合完成后、Activation 发布前安装限定在作用域内的能力。该注册表按顺序执行且具有事务性:设置失败或被撤销时会回滚未发布的 Activation;child 作用域 dispose 时会释放所有安装;新注册项在下一个 Activation 生效;移除注册项时则会立即撤销每个驻留中的安装。
196
196
 
197
- `SubagentRuntime.reportFrom()` 通过该扩展点实现报告,无需新增第二条队列或承载结果的 child 包装层。调用由确切的在线 child Agent 授权,调用方不能指定接收方。管理器从 child 的持久化 `parentSession` 中推导唯一接收方,要求该 parent Agent 必须在线,将选中内容封装为一条 `subagent-report` 用户消息,并返回该消息的稳定 `MessageId`。静默投递使用 `Agent.inject()`,不产生 inbox 条目实例或 parent 轮次;唤醒投递使用 `Agent.followup()`,会产生一个普通的后续 parent 轮次。两种模式都不会结束 child 轮次,最终回答也不会隐式报告。
197
+ `SubagentRuntime.reportFrom()` 通过该扩展点实现报告,无需新增第二条队列或承载结果的 child 包装层。调用由确切的在线 child Agent 授权,调用方不能指定接收方。管理器从 child 的持久化 `parentSession` 中推导唯一接收方,要求该 parent Agent 必须在线,将选中内容封装为一条 `subagent-report` 用户消息,并返回该消息的稳定 `MessageId`。静默投递使用 `Agent.inject()`,不会唤醒 parent;next-step 投递使用 `Agent.steer()`,会唤醒空闲 parent,或加入运行中 parent 最近的 step 边界。两种模式都不会结束 child 轮次,最终回答也不会隐式报告。
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
  上报是 child 自己的选择,因此管理器还保有一份属于自己的记账:当驻留 Activation 结算时,它会向该 child 持久化的直接 parent 投递一条通知,说明该 epoch 如何结束,并携带其最终 assistant 内容。对每个调用方拿到过 id 的 child,这条投递都是无条件的;它发生在会让 parent 被判定为已结算的所有权释放之前,并通过与上报相同的唤醒准入记账到达驻留 parent。若 parent 自身所在的谱系已在拆卸中,这条通知会以不唤醒的方式送达,因为唤醒一个静息 Agent 是开启一个轮次,而不是排队等待工作。其来源信息使用一个独立的 kind,因此 transcript(文本记录)绝不会把运行时的记账呈现为 child 自己写下的内容。
@@ -310,7 +310,7 @@ type SubagentDescendantListEntry = SubagentListEntry & {
310
310
 
311
311
  ## 终态结果:`SubagentResult`
312
312
 
313
- 单次 run 的最终产出,由 `SubagentRun.result` resolve。`structured` 仅在请求了 `outputSchema` 且成功满足时才存在;请求 schema 不保证一定能得到它,当子 agent 失败或结束时未产出有效 capture 时,提供方可能返回 `stopReason: 'error'`。非 `completed` 的 `stopReason` 意味着 `output` 可能不完整——消费方将其映射为 `isError` 的工具结果,而非将部分输出报告为成功。
313
+ 单次 run 的最终产出,由 `SubagentRun.result` resolve。`structured` 仅在请求了 `outputSchema` 且成功满足时才存在;请求 schema 不保证一定能得到它,当子 agent 失败或结束时未产出有效 capture 时,提供方可能返回 `stopReason: 'error'`。提供方可以为非 `completed` 结果附带安全且不属于 assistant 内容的 `diagnostic`;在消费方将它与 `output` 分开呈现前,提供方会排除工具输入、文件内容、环境值、凭证与原始协议载荷,并把完整值限制在 4096 个 UTF-8 字节以内。非 `completed` 的 `stopReason` 意味着 `output` 可能不完整——消费方将其映射为 `isError` 的工具结果,而非将部分输出报告为成功。
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
  }
@@ -567,6 +574,18 @@ registerContinuableSetup(contribution: ContinuableSetupContribution): () => void
567
574
  */
568
575
  async drainContinuableDescendants(parents: readonly Agent[]): Promise<void>
569
576
 
577
+ /**
578
+ * Release selected resident continuable direct children of one exact live
579
+ * parent. Other children of the same parent remain admitted and resident.
580
+ * Absent targets and a manager-less composition are accepted no-ops.
581
+ * @param parent - exact live direct parent authorizing the selected release.
582
+ * @param childIds - durable direct-child ids to release when resident.
583
+ * @returns once every selected Activation released its `AgentHandle`.
584
+ * @throws {SubagentError} `UNAUTHORIZED` when a resident target belongs to a
585
+ * different parent or the supplied parent identity is stale.
586
+ */
587
+ async drainContinuableChildren(parent: Agent, childIds: readonly SessionId[]): Promise<void>
588
+
570
589
  /**
571
590
  * Enumerate the parent's direct session-backed subagents without loading or
572
591
  * resuming an Agent and without any query service: the listing merges the live
@@ -15,13 +15,14 @@ Web 访问 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-h
15
15
 
16
16
  ## 搜索请求与结果
17
17
 
18
- 面向模型的工具参数仅为一个 `query`;`maxResults` 是消费方自有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `8`),通过 seam 传递并在返回时强制执行——如果提供方返回超量,seam 截断 `sources[]` 并设置 `truncated`。
18
+ 每个 seam 请求只携带一个 `query`。消费方 `dsh-tool-web` 接受必填的 `queries` 数组,并把它扇出为多个独立 seam 请求;单元素数组执行一次搜索。`maxResults` 是消费方自有的上限(`dsh-tool-web` 的 `searchMaxResults` 配置,默认 `8`),通过 seam 传递并在返回时强制执行——如果提供方返回超量,seam 截断 `sources[]` 并设置 `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