dsh-plugin-dev-kb 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.en.md +6 -6
- package/README.md +6 -6
- package/kb/INDEX.md +21 -5
- package/kb/README.md +11 -10
- package/kb/extra/AGENTS.md +4 -4
- package/kb/extra/cookbook/adding-a-remote-api.md +197 -0
- package/kb/extra/cookbook/adding-a-remote-api.zh.md +197 -0
- package/kb/extra/cookbook/adding-a-vendored-package.md +2 -2
- package/kb/extra/cookbook/adding-a-vendored-package.zh.md +2 -2
- package/kb/extra/deepseek-llm-api-wire-extensions.md +163 -0
- package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +163 -0
- package/kb/extra/development.md +8 -14
- package/kb/extra/development.zh.md +8 -14
- package/kb/extra/event-producer-consumer.md +55 -48
- package/kb/extra/event-producer-consumer.zh.md +58 -51
- package/kb/extra/glossary.md +1 -1
- package/kb/extra/glossary.zh.md +1 -1
- package/kb/extra/graph-atlas.md +0 -2
- package/kb/extra/graph-atlas.zh.md +0 -2
- package/kb/extra/i18n/README.md +4 -4
- package/kb/extra/i18n/README.zh.md +4 -4
- package/kb/extra/i18n/style-samples.md +2 -2
- package/kb/extra/module-graph.md +646 -926
- package/kb/extra/module-graph.zh.md +648 -928
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +2 -2
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +2 -2
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +2 -2
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +2 -2
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +2 -2
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +2 -2
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +1 -1
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +1 -1
- package/kb/extra/rescope.md +2 -2
- package/kb/extra/rescope.zh.md +2 -2
- package/kb/extra/subsystems/agent-team.md +28 -4
- package/kb/extra/subsystems/agent-team.zh.md +28 -4
- package/kb/extra/subsystems/attachment.md +168 -7
- package/kb/extra/subsystems/attachment.zh.md +168 -7
- package/kb/extra/subsystems/extensions.md +18 -0
- package/kb/extra/subsystems/extensions.zh.md +18 -0
- package/kb/extra/subsystems/feedback.md +4 -4
- package/kb/extra/subsystems/feedback.zh.md +4 -4
- package/kb/extra/subsystems/todo.md +32 -0
- package/kb/extra/subsystems/todo.zh.md +32 -0
- package/kb/extra/subsystems/webhook.md +70 -0
- package/kb/extra/subsystems/webhook.zh.md +70 -0
- package/kb/extra/testing.md +15 -10
- package/kb/extra/testing.zh.md +13 -8
- package/kb/extra/web-styling.md +4 -0
- package/kb/extra/web-styling.zh.md +4 -0
- package/kb/meta/search-index.json +309 -177
- package/kb/meta/site-pages.txt +183 -167
- package/kb/meta/source.json +5 -5
- package/kb/meta/topics.md +14 -6
- package/kb/site/develop/basic/publish.md +2 -2
- package/kb/site/develop/basic/tool.md +1 -1
- package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +5 -4
- package/kb/site/develop/framework/events.md +1 -1
- package/kb/site/develop/practice/dynamic-cordis.md +17 -0
- package/kb/site/develop/practice/llm-adapter.md +4 -3
- package/kb/site/en/develop/basic/publish.md +2 -2
- package/kb/site/en/develop/basic/tool.md +1 -1
- package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +5 -4
- package/kb/site/en/develop/framework/events.md +1 -1
- package/kb/site/en/develop/practice/dynamic-cordis.md +17 -0
- package/kb/site/en/develop/practice/llm-adapter.md +4 -3
- package/kb/site/en/guide/github-review.md +104 -0
- package/kb/site/en/guide/mcp-memory.md +103 -0
- package/kb/site/en/guide/network-proxy.md +87 -0
- package/kb/site/en/guide/providers.md +70 -17
- package/kb/site/en/guide/python-sdk.md +80 -34
- package/kb/site/en/guide/schedule.md +23 -0
- package/kb/site/en/reference/agent-lifecycle.md +6 -4
- package/kb/{extra → site/en/reference}/api-gateway.md +12 -10
- package/kb/site/en/reference/capability-seams.md +128 -73
- package/kb/site/en/reference/config-catalog.md +481 -360
- package/kb/site/en/reference/cookbook/adding-a-package.md +3 -4
- package/kb/site/en/reference/cookbook/adding-a-settings-card.md +12 -10
- package/kb/site/en/reference/cookbook/adding-a-tool.md +11 -4
- package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +1 -1
- package/kb/site/en/reference/cookbook/extension-cookbook.md +20 -17
- package/kb/site/en/reference/cordis-api/inherited.md +1 -1
- package/kb/site/en/reference/cordis-primer.md +2 -1
- package/kb/site/en/reference/index.md +30 -11
- package/kb/site/en/reference/persistence-catalog.md +148 -80
- package/kb/site/en/reference/subsystems/approval.md +10 -10
- package/kb/site/en/reference/subsystems/client-modules.md +58 -16
- package/kb/site/en/reference/subsystems/code-runtime.md +10 -6
- package/kb/site/en/reference/subsystems/commands.md +25 -16
- package/kb/site/en/reference/subsystems/compaction.md +11 -11
- package/kb/site/en/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +50 -24
- package/kb/site/en/reference/subsystems/core.md +156 -17
- package/kb/site/en/reference/subsystems/credentials.md +44 -3
- package/kb/site/en/reference/subsystems/filesystem.md +12 -2
- package/kb/site/en/reference/subsystems/goal.md +1 -1
- package/kb/site/en/reference/subsystems/index.md +7 -2
- package/kb/site/en/reference/subsystems/jobs.md +1 -1
- package/kb/site/en/reference/subsystems/llm-streaming.md +154 -12
- package/kb/site/en/reference/subsystems/permission-presets.md +6 -6
- package/kb/site/en/reference/subsystems/persistence.md +185 -175
- package/kb/site/en/reference/subsystems/plan.md +2 -2
- package/kb/site/en/reference/subsystems/sandbox.md +2 -0
- package/kb/site/en/reference/subsystems/schedule.md +9 -3
- package/kb/site/en/reference/subsystems/session-projection.md +115 -48
- package/kb/site/en/reference/subsystems/session-query.md +28 -14
- package/kb/site/en/reference/subsystems/session-reference.md +53 -8
- package/kb/site/en/reference/subsystems/session-telemetry.md +8 -8
- package/kb/site/en/reference/subsystems/session-title.md +6 -6
- package/kb/site/en/reference/subsystems/session.md +401 -99
- package/kb/site/en/reference/subsystems/settings.md +101 -6
- package/kb/site/en/reference/subsystems/skills.md +23 -0
- package/kb/site/en/reference/subsystems/slots.md +178 -0
- package/kb/site/en/reference/subsystems/spill.md +2 -2
- package/kb/site/en/reference/subsystems/storage.md +34 -3
- package/kb/site/en/reference/subsystems/subagent.md +122 -109
- package/kb/site/en/reference/subsystems/system-prompt.md +17 -4
- package/kb/site/en/reference/subsystems/token-meter.md +27 -12
- package/kb/site/en/reference/subsystems/tools.md +39 -39
- package/kb/site/en/reference/subsystems/typert.md +62 -55
- package/kb/site/en/reference/subsystems/user-questions.md +33 -33
- package/kb/site/en/reference/subsystems/web-client.md +98 -0
- package/kb/site/en/reference/subsystems/web-server.md +11 -5
- package/kb/site/en/reference/subsystems/web.md +7 -1
- package/kb/site/en/reference/subsystems/workspace.md +102 -9
- package/kb/site/en/reference/tool-catalog.md +86 -82
- package/kb/site/en/reference/tool-execution-pipeline.md +1 -1
- package/kb/site/guide/github-review.md +104 -0
- package/kb/site/guide/mcp-memory.md +103 -0
- package/kb/site/guide/network-proxy.md +87 -0
- package/kb/site/guide/providers.md +70 -17
- package/kb/site/guide/python-sdk.md +87 -41
- package/kb/site/guide/schedule.md +23 -0
- package/kb/site/reference/agent-lifecycle.md +6 -4
- package/kb/{extra/api-gateway.zh.md → site/reference/api-gateway.md} +12 -10
- package/kb/site/reference/capability-seams.md +128 -73
- package/kb/site/reference/config-catalog.md +481 -360
- package/kb/site/reference/cookbook/adding-a-package.md +3 -4
- package/kb/site/reference/cookbook/adding-a-settings-card.md +12 -10
- package/kb/site/reference/cookbook/adding-a-tool.md +11 -4
- package/kb/site/reference/cookbook/adding-an-llm-adapter.md +1 -1
- package/kb/site/reference/cookbook/extension-cookbook.md +20 -17
- package/kb/site/reference/cordis-api/inherited.md +1 -1
- package/kb/site/reference/cordis-primer.md +2 -1
- package/kb/site/reference/index.md +30 -11
- package/kb/site/reference/persistence-catalog.md +148 -80
- package/kb/site/reference/subsystems/approval.md +10 -10
- package/kb/site/reference/subsystems/client-modules.md +58 -16
- package/kb/site/reference/subsystems/code-runtime.md +10 -6
- package/kb/site/reference/subsystems/commands.md +25 -16
- package/kb/site/reference/subsystems/compaction.md +11 -11
- package/kb/site/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +50 -24
- package/kb/site/reference/subsystems/core.md +156 -17
- package/kb/site/reference/subsystems/credentials.md +44 -3
- package/kb/site/reference/subsystems/filesystem.md +12 -2
- package/kb/site/reference/subsystems/goal.md +1 -1
- package/kb/site/reference/subsystems/index.md +7 -2
- package/kb/site/reference/subsystems/jobs.md +1 -1
- package/kb/site/reference/subsystems/llm-streaming.md +154 -12
- package/kb/site/reference/subsystems/permission-presets.md +5 -5
- package/kb/site/reference/subsystems/persistence.md +184 -174
- package/kb/site/reference/subsystems/plan.md +2 -2
- package/kb/site/reference/subsystems/schedule.md +9 -3
- package/kb/site/reference/subsystems/session-projection.md +115 -48
- package/kb/site/reference/subsystems/session-query.md +28 -14
- package/kb/site/reference/subsystems/session-reference.md +53 -8
- package/kb/site/reference/subsystems/session-telemetry.md +8 -8
- package/kb/site/reference/subsystems/session-title.md +6 -6
- package/kb/site/reference/subsystems/session.md +401 -99
- package/kb/site/reference/subsystems/settings.md +101 -6
- package/kb/site/reference/subsystems/skills.md +23 -0
- package/kb/site/reference/subsystems/slots.md +178 -0
- package/kb/site/reference/subsystems/spill.md +2 -2
- package/kb/site/reference/subsystems/storage.md +34 -3
- package/kb/site/reference/subsystems/subagent.md +122 -109
- package/kb/site/reference/subsystems/system-prompt.md +17 -4
- package/kb/site/reference/subsystems/token-meter.md +27 -12
- package/kb/site/reference/subsystems/tools.md +39 -39
- package/kb/site/reference/subsystems/typert.md +62 -55
- package/kb/site/reference/subsystems/user-questions.md +33 -33
- package/kb/site/reference/subsystems/web-client.md +98 -0
- package/kb/site/reference/subsystems/web-server.md +11 -5
- package/kb/site/reference/subsystems/web.md +7 -1
- package/kb/site/reference/subsystems/workspace.md +102 -9
- package/kb/site/reference/tool-catalog.md +85 -81
- package/kb/site/reference/tool-execution-pipeline.md +1 -1
- package/package.json +2 -2
- package/skills/dsh-plugin-dev-kb.md +8 -6
|
@@ -160,7 +160,7 @@ type InferArgs<S> = InferProperties<S, []>
|
|
|
160
160
|
```ts type-equiv
|
|
161
161
|
/**
|
|
162
162
|
* Per-scope filter over global tools. Restrictions intersect and do not affect
|
|
163
|
-
* scoped registrations or the reserved
|
|
163
|
+
* scoped registrations or the reserved PTC mode transport.
|
|
164
164
|
*/
|
|
165
165
|
interface ToolRestriction {
|
|
166
166
|
/** Global tool names that stay visible; everything else is removed. */
|
|
@@ -186,23 +186,23 @@ type ToolExecutionToken = symbol & { readonly [toolExecutionTokenBrand]: true }
|
|
|
186
186
|
* callers do not choose that token.
|
|
187
187
|
*/
|
|
188
188
|
interface ToolExecutionInput {
|
|
189
|
-
readonly callId:
|
|
189
|
+
readonly callId: ToolCallId
|
|
190
190
|
/**
|
|
191
191
|
* Root model-requested call owning this execution tree. Callers omit it for
|
|
192
192
|
* a root execution; nested dispatchers propagate the enclosing value.
|
|
193
193
|
*/
|
|
194
|
-
readonly rootCallId?:
|
|
194
|
+
readonly rootCallId?: ToolCallId
|
|
195
195
|
readonly name: string
|
|
196
196
|
/** Losslessly JSON-serializable parsed arguments (tools validate their own schema). */
|
|
197
197
|
readonly arguments: unknown
|
|
198
198
|
/** The agent on whose behalf the call runs (set by the agent loop). */
|
|
199
199
|
readonly agent?: Agent
|
|
200
200
|
/**
|
|
201
|
-
* Opaque token of the enclosing transport execution, when one exists.
|
|
202
|
-
*
|
|
201
|
+
* Opaque token of the enclosing transport execution, when one exists. PTC
|
|
202
|
+
* mode sets this on SDK sub-dispatches so commit-style observers can wait for
|
|
203
203
|
* the outer `run_code` outcome without receiving its live mutable execution.
|
|
204
204
|
* The token also marks the call as a transport sub-dispatch rather than a
|
|
205
|
-
* model-direct call: under `mode: '
|
|
205
|
+
* model-direct call: under `mode: 'ptc'`, only calls WITH a parent may
|
|
206
206
|
* execute a native tool name — a model-direct call (no parent) is denied as
|
|
207
207
|
* `UNKNOWN_TOOL` before the policy pipeline. See {@link ToolRuntime.execute}.
|
|
208
208
|
*/
|
|
@@ -255,25 +255,25 @@ type ToolExecutionMode =
|
|
|
255
255
|
| { kind: 'exclusive' }
|
|
256
256
|
```
|
|
257
257
|
|
|
258
|
-
|
|
258
|
+
PTC mode 的桥接层还会把每个已结算的子分派暴露给 `tools/ptc-dispatch-log` waterfall,该 waterfall 可以更改持久事件所存的内容副本(程序取得的值和模型可见结果均不受影响):
|
|
259
259
|
|
|
260
260
|
```ts type-equiv
|
|
261
261
|
/**
|
|
262
262
|
* One settled `run_code` sub-dispatch about to be logged, as seen by the
|
|
263
|
-
* `tools/
|
|
263
|
+
* `tools/ptc-dispatch-log` waterfall: the parent execution (session owner,
|
|
264
264
|
* outer call identity), the sub-call identity, and the outcome whose durable
|
|
265
265
|
* copy a listener may reshape. `content` is the RENDERED result projection
|
|
266
266
|
* (what a native `tool/result` would carry) — the program itself received
|
|
267
267
|
* the structured `value` (or just the error message on failure); only the
|
|
268
268
|
* `tool/code-dispatch` event's copy changes.
|
|
269
269
|
*/
|
|
270
|
-
interface
|
|
270
|
+
interface PtcDispatchLog {
|
|
271
271
|
/** The outer `run_code` execution. */
|
|
272
272
|
readonly exec: ToolExecution
|
|
273
273
|
/** The calling agent (the scope routing key and the spill owner), when the outer call has one. */
|
|
274
274
|
readonly agent?: Agent
|
|
275
275
|
/** Deterministic sub-call id (`<parent>:code:<n>`). */
|
|
276
|
-
readonly subCallId:
|
|
276
|
+
readonly subCallId: ToolCallId
|
|
277
277
|
/** The dispatched sub-tool name. */
|
|
278
278
|
readonly name: string
|
|
279
279
|
/** Whether the sub-call settled as an error. */
|
|
@@ -293,7 +293,7 @@ interface CodeDispatchLog {
|
|
|
293
293
|
*/
|
|
294
294
|
interface ToolExecution extends ToolExecutionInput {
|
|
295
295
|
/** Root model-requested call, resolved for every root and nested execution. */
|
|
296
|
-
readonly rootCallId:
|
|
296
|
+
readonly rootCallId: ToolCallId
|
|
297
297
|
/** Registry-assigned identity shared with nested calls only as their opaque `parent` token. */
|
|
298
298
|
readonly token: ToolExecutionToken
|
|
299
299
|
}
|
|
@@ -491,7 +491,7 @@ Tool registry and execution pipeline. Scoped registrations shadow globals; one v
|
|
|
491
491
|
* declaration covers every agent joined under it.
|
|
492
492
|
*
|
|
493
493
|
* Scoped only, and one declaration per scope: this is how an agent preset
|
|
494
|
-
* composes
|
|
494
|
+
* composes PTC mode agents beside native ones in the same process, and a
|
|
495
495
|
* process-global override would be the `mode` config field instead.
|
|
496
496
|
* @param mode - the presentation the covered agents' models see.
|
|
497
497
|
* @returns the exact disposer that restores the deployment default.
|
|
@@ -601,33 +601,6 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai
|
|
|
601
601
|
|
|
602
602
|
Source: [`packages/core/tools/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/index.ts)
|
|
603
603
|
|
|
604
|
-
<a id="toolscode-dispatch-log--waterfall"></a>
|
|
605
|
-
|
|
606
|
-
#### `tools/code-dispatch-log` — waterfall
|
|
607
|
-
|
|
608
|
-
Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
|
|
609
|
-
|
|
610
|
-
```ts cordis-catalog
|
|
611
|
-
/**
|
|
612
|
-
* Allow a listener to replace content in the DURABLE LOG COPY of one
|
|
613
|
-
* `run_code` sub-dispatch outcome before the bridge appends its
|
|
614
|
-
* `tool/code-dispatch` event. `next()` keeps the
|
|
615
|
-
* content unchanged; a listener may return replacement blocks (e.g. the
|
|
616
|
-
* spill policy's preview + locator for an oversized text result). Only the
|
|
617
|
-
* logged copy is affected — the program already received the complete
|
|
618
|
-
* value, and the model sees neither. A throwing listener is contained:
|
|
619
|
-
* the bridge falls back to logging the original settled content.
|
|
620
|
-
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
|
|
621
|
-
* @param dispatch - the parent execution, sub-call identity, and the settled content to log.
|
|
622
|
-
* @mode waterfall
|
|
623
|
-
*/
|
|
624
|
-
'tools/code-dispatch-log'(this: Scoped<ToolRuntime>, dispatch: CodeDispatchLog, next: () => Promise<ContentBlock[]>): Promise<ContentBlock[]>
|
|
625
|
-
```
|
|
626
|
-
|
|
627
|
-
Types: [ContentBlock](./llm-streaming.md) · [Scoped](./scope.md)
|
|
628
|
-
|
|
629
|
-
Source: [`packages/core/tools/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/index.ts)
|
|
630
|
-
|
|
631
604
|
<a id="toolsexecute--waterfall"></a>
|
|
632
605
|
|
|
633
606
|
#### `tools/execute` — waterfall
|
|
@@ -700,6 +673,33 @@ Types: [Scoped](./scope.md)
|
|
|
700
673
|
|
|
701
674
|
Source: [`packages/core/tools/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/index.ts)
|
|
702
675
|
|
|
676
|
+
<a id="toolsptc-dispatch-log--waterfall"></a>
|
|
677
|
+
|
|
678
|
+
#### `tools/ptc-dispatch-log` — waterfall
|
|
679
|
+
|
|
680
|
+
Allow a listener to replace content in the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bridge appends its `tool/code-dispatch` event. `next()` keeps the content unchanged; a listener may return replacement blocks (e.g. the spill policy's preview + locator for an oversized text result). Only the logged copy is affected — the program already received the complete value, and the model sees neither. A throwing listener is contained: the bridge falls back to logging the original settled content. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
|
|
681
|
+
|
|
682
|
+
```ts cordis-catalog
|
|
683
|
+
/**
|
|
684
|
+
* Allow a listener to replace content in the DURABLE LOG COPY of one
|
|
685
|
+
* `run_code` sub-dispatch outcome before the bridge appends its
|
|
686
|
+
* `tool/code-dispatch` event. `next()` keeps the
|
|
687
|
+
* content unchanged; a listener may return replacement blocks (e.g. the
|
|
688
|
+
* spill policy's preview + locator for an oversized text result). Only the
|
|
689
|
+
* logged copy is affected — the program already received the complete
|
|
690
|
+
* value, and the model sees neither. A throwing listener is contained:
|
|
691
|
+
* the bridge falls back to logging the original settled content.
|
|
692
|
+
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent's dispatches.
|
|
693
|
+
* @param dispatch - the parent execution, sub-call identity, and the settled content to log.
|
|
694
|
+
* @mode waterfall
|
|
695
|
+
*/
|
|
696
|
+
'tools/ptc-dispatch-log'(this: Scoped<ToolRuntime>, dispatch: PtcDispatchLog, next: () => Promise<ContentBlock[]>): Promise<ContentBlock[]>
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
Types: [ContentBlock](./llm-streaming.md) · [Scoped](./scope.md)
|
|
700
|
+
|
|
701
|
+
Source: [`packages/core/tools/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/index.ts)
|
|
702
|
+
|
|
703
703
|
<a id="toolsresult--emit"></a>
|
|
704
704
|
|
|
705
705
|
#### `tools/result` — emit
|
|
@@ -87,6 +87,8 @@ interface InvocationDescriptor {
|
|
|
87
87
|
readonly method: string
|
|
88
88
|
/** Service member invoked when the exported method name is an alias. */
|
|
89
89
|
readonly implementation?: string
|
|
90
|
+
/** Absent for unary calls; stream calls validate and deliver every yielded item. */
|
|
91
|
+
readonly mode?: 'stream'
|
|
90
92
|
/** Receiver selection mode. */
|
|
91
93
|
readonly invocation:
|
|
92
94
|
| { readonly kind: 'direct' }
|
|
@@ -98,7 +100,7 @@ interface InvocationDescriptor {
|
|
|
98
100
|
}
|
|
99
101
|
/** Optional consuming-Context projection for one direct lookup parameter. */
|
|
100
102
|
readonly scope?: {
|
|
101
|
-
/** Context kind whose Client
|
|
103
|
+
/** Context kind whose Client adapter supplies the identity. */
|
|
102
104
|
readonly context: string
|
|
103
105
|
/** Lookup parameter wire field replaced by the Context identity. */
|
|
104
106
|
readonly wire: string
|
|
@@ -110,7 +112,7 @@ interface InvocationDescriptor {
|
|
|
110
112
|
/** Reserved final Host method parameter. */
|
|
111
113
|
readonly parameter: 'signal'
|
|
112
114
|
}
|
|
113
|
-
/** Codec for the
|
|
115
|
+
/** Codec for the unary result or each yielded stream item. */
|
|
114
116
|
readonly result: TypertCodec
|
|
115
117
|
/** Source declaration used only for diagnostics. */
|
|
116
118
|
readonly sourceLocation?: InvocationSourceLocation
|
|
@@ -140,7 +142,7 @@ interface TypertRemoteNamespaceMap {}
|
|
|
140
142
|
|
|
141
143
|
## Host Gateway
|
|
142
144
|
|
|
143
|
-
Connection 会先解码 carrier envelope,再调用 `ctx.typertGateway`。请求将精确的具名 wire 字段与 carrier 的取消 signal
|
|
145
|
+
Connection 会先解码 carrier envelope,再调用 `ctx.typertGateway`。请求将精确的具名 wire 字段与 carrier 的取消 signal 分开携带;基础设施与边界失败由 `TypertGatewayError` 承载,其 `gateway/*` 码就是普通的 `RemoteError` 码,因此 RPC 适配器会把每个经结构识别的 `RemoteError` 连同其 code 与 details 原样放行,只把无法识别的异常归并为 `gateway/internal`。
|
|
144
146
|
|
|
145
147
|
```ts type-equiv
|
|
146
148
|
/** One Remote method request after a carrier has decoded its envelope. */
|
|
@@ -159,35 +161,53 @@ interface InvokeRemoteRequest {
|
|
|
159
161
|
```ts type-equiv
|
|
160
162
|
/** Stable infrastructure and boundary failures emitted before or after business execution. */
|
|
161
163
|
type TypertGatewayErrorCode =
|
|
162
|
-
| 'ambiguous-endpoint'
|
|
163
|
-
| 'arguments-invalid'
|
|
164
|
-
| 'binding-invalid'
|
|
165
|
-
| 'context-failed'
|
|
166
|
-
| 'context-not-found'
|
|
167
|
-
| 'context-unavailable'
|
|
168
|
-
| 'definition-unavailable'
|
|
169
|
-
| 'input-invalid'
|
|
170
|
-
| 'invocation-unavailable'
|
|
171
|
-
| 'lookup-failed'
|
|
172
|
-
| 'lookup-not-found'
|
|
173
|
-
| 'lookup-unavailable'
|
|
174
|
-
| 'method-unavailable'
|
|
175
|
-
| 'provider-mismatch'
|
|
176
|
-
| 'result-invalid'
|
|
177
|
-
| 'service-unavailable'
|
|
178
|
-
| 'signature-invalid'
|
|
164
|
+
| 'gateway/ambiguous-endpoint'
|
|
165
|
+
| 'gateway/arguments-invalid'
|
|
166
|
+
| 'gateway/binding-invalid'
|
|
167
|
+
| 'gateway/context-failed'
|
|
168
|
+
| 'gateway/context-not-found'
|
|
169
|
+
| 'gateway/context-unavailable'
|
|
170
|
+
| 'gateway/definition-unavailable'
|
|
171
|
+
| 'gateway/input-invalid'
|
|
172
|
+
| 'gateway/invocation-unavailable'
|
|
173
|
+
| 'gateway/lookup-failed'
|
|
174
|
+
| 'gateway/lookup-not-found'
|
|
175
|
+
| 'gateway/lookup-unavailable'
|
|
176
|
+
| 'gateway/method-unavailable'
|
|
177
|
+
| 'gateway/provider-mismatch'
|
|
178
|
+
| 'gateway/result-invalid'
|
|
179
|
+
| 'gateway/service-unavailable'
|
|
180
|
+
| 'gateway/signature-invalid'
|
|
179
181
|
```
|
|
180
182
|
|
|
181
183
|
```ts type-equiv
|
|
182
184
|
/** Host dispatcher consumed by Connection adapters. */
|
|
183
185
|
interface TypertGateway {
|
|
186
|
+
/** Carrier adapter shared by WebSocket and in-process transports. */
|
|
187
|
+
readonly wireStream: TypertGatewayWireStream
|
|
188
|
+
/**
|
|
189
|
+
* Register the application-selected forwarded-event source.
|
|
190
|
+
* @param source - stream factory installed by the Remote assembly.
|
|
191
|
+
* @param host - stable Host facts included in each Client generation's opening frame.
|
|
192
|
+
* @returns disposer removing this exact source and cancelling its active streams.
|
|
193
|
+
*/
|
|
194
|
+
registerRemoteEvents(
|
|
195
|
+
source: TypertRemoteEventSource,
|
|
196
|
+
host: RemoteEventHostInfo,
|
|
197
|
+
): () => Promise<void>
|
|
184
198
|
/**
|
|
185
199
|
* Invoke one live Remote method without assuming a carrier or response envelope.
|
|
186
200
|
* @param request - decoded endpoint and named wire arguments.
|
|
187
|
-
* @returns the
|
|
201
|
+
* @returns the business result without output decoding.
|
|
188
202
|
* @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity.
|
|
189
203
|
*/
|
|
190
204
|
invoke(request: InvokeRemoteRequest): Promise<unknown>
|
|
205
|
+
/**
|
|
206
|
+
* Open one live stream Remote method without assuming a physical carrier.
|
|
207
|
+
* @param request - decoded endpoint and named wire arguments.
|
|
208
|
+
* @returns a cancellation-aware iterable over the business results.
|
|
209
|
+
*/
|
|
210
|
+
stream(request: InvokeRemoteRequest): Promise<AsyncIterable<unknown>>
|
|
191
211
|
}
|
|
192
212
|
```
|
|
193
213
|
|
|
@@ -205,26 +225,15 @@ interface TypertClientRemote extends TypertRemoteNamespaceMap {
|
|
|
205
225
|
*/
|
|
206
226
|
$mount(contribution: TypertRemoteContribution): Promise<TypertDisposer>
|
|
207
227
|
/**
|
|
208
|
-
* Subscribe to one forwarded Host event
|
|
209
|
-
* order
|
|
228
|
+
* Subscribe to one forwarded Host event. Notifications run in registration
|
|
229
|
+
* order and isolate failures; scoped waterfalls return, delegate through
|
|
230
|
+
* `next()`, or reject the Host dispatch.
|
|
210
231
|
* @template Event - forwarded event name selected by the Host assembly.
|
|
211
232
|
* @param event - forwarded Host event name, unchanged on the wire.
|
|
212
|
-
* @param listener - receives the
|
|
233
|
+
* @param listener - receives the Client projection of the Cordis `Events` declaration.
|
|
213
234
|
* @returns disposer owned by the calling fiber.
|
|
214
235
|
*/
|
|
215
|
-
$on<Event extends TypertRemoteEvent>(event: Event, listener:
|
|
216
|
-
/**
|
|
217
|
-
* Hand one decoded forwarded frame to the subscription table. The carrier
|
|
218
|
-
* owning the Host frame sink calls this; a consumer subscribes with
|
|
219
|
-
* {@link TypertClientRemote.$on} and never calls it.
|
|
220
|
-
*
|
|
221
|
-
* `event` is a plain string because this is the wire boundary: the name is
|
|
222
|
-
* whatever the Host assembly's allowlist selected, and one nobody subscribed
|
|
223
|
-
* to is dropped silently.
|
|
224
|
-
* @param event - forwarded Host event name, exactly as the Host emitted it.
|
|
225
|
-
* @param args - the Host argument list, already JSON-decoded.
|
|
226
|
-
*/
|
|
227
|
-
$dispatch(event: string, args: readonly unknown[]): void
|
|
236
|
+
$on<Event extends TypertRemoteEvent>(event: Event, listener: TypertClientEventListener<Event>): () => void
|
|
228
237
|
}
|
|
229
238
|
```
|
|
230
239
|
|
|
@@ -236,23 +245,6 @@ interface TypertClientRemote extends TypertRemoteNamespaceMap {
|
|
|
236
245
|
|
|
237
246
|
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).
|
|
238
247
|
|
|
239
|
-
<a id="ctxapiproxy--apiproxy"></a>
|
|
240
|
-
|
|
241
|
-
### `ctx.apiProxy` — `ApiProxy`
|
|
242
|
-
|
|
243
|
-
Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row.
|
|
244
|
-
|
|
245
|
-
```ts cordis-catalog
|
|
246
|
-
/**
|
|
247
|
-
* Response entry for server requests; not a domain method.
|
|
248
|
-
* @param message - Client response carrying the server request's rpcId.
|
|
249
|
-
* @returns Transport receipt for the response delivery.
|
|
250
|
-
*/
|
|
251
|
-
respond(message: ClientResponse): Promise<RpcReceipt>
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Source: [`packages/host/apiproxy/src/api/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/apiproxy/src/api/index.ts)
|
|
255
|
-
|
|
256
248
|
<a id="ctxtypert--typertregistry"></a>
|
|
257
249
|
|
|
258
250
|
### `ctx.typert` — `TypertRegistry`
|
|
@@ -326,13 +318,28 @@ Source: [`packages/typert/registry/src/service.ts`](https://github.com/deepseek-
|
|
|
326
318
|
Resolve strict generated definitions or conservative SRC markers against current Cordis Services and Typert providers.
|
|
327
319
|
|
|
328
320
|
```ts cordis-catalog
|
|
321
|
+
/**
|
|
322
|
+
* Register the sole application-selected forwarded-event source.
|
|
323
|
+
* @param source - stream factory installed by the Remote assembly.
|
|
324
|
+
* @param host - stable Host facts included in each Client generation's opening frame.
|
|
325
|
+
* @returns disposer removing this source and cancelling its active streams.
|
|
326
|
+
*/
|
|
327
|
+
registerRemoteEvents( source: TypertRemoteEventSource, host: RemoteEventHostInfo, ): () => Promise<void>
|
|
328
|
+
|
|
329
329
|
/**
|
|
330
330
|
* Invoke one live Remote method through strict generated reflection or SRC markers.
|
|
331
331
|
* @param request - decoded endpoint and exact named wire arguments.
|
|
332
|
-
* @returns the
|
|
332
|
+
* @returns the business result without output decoding.
|
|
333
333
|
* @throws {@link TypertGatewayError} for dispatch, provider, or boundary failures; lookup-policy and business errors retain identity.
|
|
334
334
|
*/
|
|
335
335
|
async invoke(request: InvokeRemoteRequest): Promise<unknown>
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Open one live stream Remote method without assuming a physical carrier.
|
|
339
|
+
* @param request - decoded endpoint and named wire arguments.
|
|
340
|
+
* @returns a cancellation-aware iterable over the business results.
|
|
341
|
+
*/
|
|
342
|
+
async stream(request: InvokeRemoteRequest): Promise<AsyncIterable<unknown>>
|
|
336
343
|
```
|
|
337
344
|
|
|
338
345
|
Source: [`packages/api/gateway/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/gateway/src/index.ts)
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# 用户交互
|
|
7
7
|
|
|
8
|
-
[dsh-user-questions](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-questions) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent(智能体)才能继续时所使用的、提供方无关的词汇。UI
|
|
8
|
+
[dsh-user-questions](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/interaction/user-questions) 的用户交互 seam。它是工具或权限插件需要人类回答后 agent(智能体)才能继续时所使用的、提供方无关的词汇。Agent-scoped waterfall listener 组合可用的 UI 界面,其中包括转发到已连接 client 的 listener。
|
|
9
9
|
|
|
10
10
|
源码:[`packages/interaction/user-questions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/index.ts)
|
|
11
11
|
|
|
@@ -77,14 +77,7 @@ interface AskUserQuestionItem {
|
|
|
77
77
|
|
|
78
78
|
```ts type-equiv
|
|
79
79
|
/** Request for a human answer. */
|
|
80
|
-
interface AskUserQuestionRequest {
|
|
81
|
-
/** Questions to display. */
|
|
82
|
-
questions: AskUserQuestionItem[]
|
|
83
|
-
/** Exact live calling agent, when the request came from an agent tool call. */
|
|
84
|
-
agent?: Agent
|
|
85
|
-
/** Abort signal for the owning tool/step. */
|
|
86
|
-
signal?: AbortSignal
|
|
87
|
-
}
|
|
80
|
+
interface AskUserQuestionRequest extends AskUserQuestionRequestEvent {}
|
|
88
81
|
```
|
|
89
82
|
|
|
90
83
|
## 回答
|
|
@@ -111,17 +104,6 @@ interface AskUserQuestionAnswer {
|
|
|
111
104
|
}
|
|
112
105
|
```
|
|
113
106
|
|
|
114
|
-
## 提供方
|
|
115
|
-
|
|
116
|
-
同一上下文中只能有一个活跃的提供方。提供方注册绑定到 effect,因此 HMR(热模块替换)或 dispose(资源释放)会移除当前活跃的 UI。
|
|
117
|
-
|
|
118
|
-
```ts type-equiv
|
|
119
|
-
/** UI-side provider for user questions. */
|
|
120
|
-
interface UserQuestionProvider {
|
|
121
|
-
ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
107
|
## 错误
|
|
126
108
|
|
|
127
109
|
`UserQuestionError` 继承 `HarnessError`,因此 `ctx.tools.execute()` 会保留 `{ name, code }`,用于面向模型的工具失败,如 `EMPTY_QUESTIONS`、`NO_PROVIDER`、`ASK_ABORTED` 或 UI 侧取消。
|
|
@@ -148,19 +130,11 @@ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnp
|
|
|
148
130
|
|
|
149
131
|
### `ctx.userQuestions` — `UserQuestionService`
|
|
150
132
|
|
|
151
|
-
`ctx.userQuestions`:
|
|
133
|
+
`ctx.userQuestions`: validation plus the scoped answerer waterfall.
|
|
152
134
|
|
|
153
135
|
```ts cordis-catalog
|
|
154
136
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* @param provider UI-side implementation that collects answers.
|
|
158
|
-
* @returns Disposer that unregisters this provider.
|
|
159
|
-
*/
|
|
160
|
-
registerProvider(provider: UserQuestionProvider): () => void
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Ask the active UI provider and wait for the user's answer.
|
|
137
|
+
* Ask the scoped answerer waterfall and wait for the user's answer.
|
|
164
138
|
*
|
|
165
139
|
* When a caller supplies an agent, human interaction is valid only for the
|
|
166
140
|
* exact live runtime root. Runtime ownership, not durable session lineage,
|
|
@@ -170,12 +144,38 @@ registerProvider(provider: UserQuestionProvider): () => void
|
|
|
170
144
|
*
|
|
171
145
|
* @param request Questions, owner agent, and abort signal.
|
|
172
146
|
* @returns The answer chosen or typed by the human.
|
|
173
|
-
* @throws {UserQuestionError} code `
|
|
174
|
-
*
|
|
175
|
-
*
|
|
147
|
+
* @throws {UserQuestionError} code `ASK_ABORTED` when the supplied signal
|
|
148
|
+
* is already or becomes aborted, `CALLER_NOT_LIVE` when a supplied agent
|
|
149
|
+
* is not the registry's exact live instance, or `DELEGATED_CALLER` when
|
|
150
|
+
* that live agent is owned by another agent.
|
|
176
151
|
*/
|
|
177
152
|
async ask(request: AskUserQuestionRequest): Promise<AskUserQuestionAnswer>
|
|
178
153
|
```
|
|
179
154
|
|
|
180
155
|
Source: [`packages/interaction/user-questions/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/index.ts)
|
|
156
|
+
|
|
157
|
+
<a id="user-questions-events"></a>
|
|
158
|
+
|
|
159
|
+
### `user-questions/*` events
|
|
160
|
+
|
|
161
|
+
<a id="user-questionsrequest--waterfall"></a>
|
|
162
|
+
|
|
163
|
+
#### `user-questions/request` — waterfall
|
|
164
|
+
|
|
165
|
+
Ask composed answerers for structured user input. Return an answer to claim the request or call `next()` to delegate. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
|
166
|
+
|
|
167
|
+
```ts cordis-catalog
|
|
168
|
+
/**
|
|
169
|
+
* Ask composed answerers for structured user input. Return an answer to
|
|
170
|
+
* claim the request or call `next()` to delegate. Scope-filtered dispatch
|
|
171
|
+
* (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
|
172
|
+
* @param request - pending user-question request.
|
|
173
|
+
* @mode waterfall
|
|
174
|
+
*/
|
|
175
|
+
'user-questions/request'( this: Scoped<Agent>, request: AskUserQuestionRequestEvent, next: () => Promise<AskUserQuestionAnswer>, ): Promise<AskUserQuestionAnswer>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Types: [Agent](./core.md) · [Scoped](./scope.md)
|
|
179
|
+
|
|
180
|
+
Source: [`packages/interaction/user-questions/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-questions/src/types.ts)
|
|
181
181
|
<!-- END GENERATED cordis-surface -->
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
editSource: "docs/subsystems/web-client.zh.md"
|
|
3
|
+
outline: [2,3]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Web Client 架构
|
|
7
|
+
|
|
8
|
+
Web Client 是由独立加载插件组装而成的浏览器侧 Cordis 应用。它有四个可复用底座:[Client Modules](./client-modules.md) 加载插件图,[API Gateway](../api-gateway.md) 提供类型化 Host 通信,[Slots](./slots.md) 组合 React UI,[Conversation](./conversation.md) 把 Session 历史窗口变成各 target 自有的视图。本文串联这些系统,并规定 Client model 与功能包各自所在的位置。
|
|
9
|
+
|
|
10
|
+
## 分层与所有权
|
|
11
|
+
|
|
12
|
+
| 层 | 主要 owner | 职责 |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Host 应用 | 业务 service 与 `packages/api/*-controller` Host entry | 拥有权威状态、持久化、mutation 顺序、访问策略与 stream 生产。 |
|
|
15
|
+
| 传输与 API assembly | `client/connection`、`api/gateway`、`api/remotes` | 建立 Client generation,公开生成的 `ctx.remote` method 与 stream,转发选定的 Cordis event,并承载取消和结果。 |
|
|
16
|
+
| Client model | `api/session-controller/client`、`api/workspace-controller/client` | 维护不依赖 React 的 Host 状态镜像,处理 stream/unary 竞态,拥有对象 identity 与订阅,并公开收窄的 command service。 |
|
|
17
|
+
| UI adapter | `client/ui-session`、`client/ui-workspace` | 把 model observable 转换为 root 或 Session scope 的标准 Slot source,不接管业务状态所有权。 |
|
|
18
|
+
| Conversation 数据 | `client/ui-conversation`、`ui-chat` 与 `ui-trajectory` 等 target package | 把标准 event 与紧凑的 Assistant 历史批次组装成相互独立的 target snapshot,并拥有共享的 Conversation shell 与输入流程。 |
|
|
19
|
+
| 组合与渲染 | `client/ui-slots`、`client/ui-renderer`、`client/ui-layout`、各 UI 功能包 | 声明扩展位置、推导组件 props、把 observable 绑定成 React hook,并挂载最终组件树。 |
|
|
20
|
+
|
|
21
|
+
依赖方向是 Host 状态 → Remote 传输 → Client model → UI adapter → Conversation 或 presentation → Slots → React。用户操作通过 callback 反向进入注入的 Client service 或生成的 Remote namespace。Presentation component 绝不接收 Cordis `ctx`、transport object 或其他功能插件的实现。
|
|
22
|
+
|
|
23
|
+
## 浏览器启动
|
|
24
|
+
|
|
25
|
+
Host 把组合后的 `WebBootGraph` 写入 `window.__DSH_BOOT__`,并在 parser-preloaded script 执行前安装浏览器 module-loader facade。模块系统是一张 lazy CommonJS 表:加载 bundle 只注册 factory;materialize entry 时才以同步 `require` 运行 factory,并解析 platform module 和已声明的动态依赖。
|
|
26
|
+
|
|
27
|
+
Web boot kernel 创建模块系统、预取 `immediately` entry、挂载 vendored Cordis Loader,再创建图中的每个 entry。Cordis service injection 决定激活顺序;module graph 顺序只决定同步 import 能否被 materialize。完整 roster 到达 settled 状态后,`ui-renderer` hydrate 不依赖框架的 boot DOM,并调用唯一一次 context 级 `renderSlot('root')`。[Client Modules](./client-modules.md)负责 graph、bundle route、cache revision 与 loader 细节。
|
|
28
|
+
|
|
29
|
+
## Remote 通信
|
|
30
|
+
|
|
31
|
+
Host 业务 service 使用 Typert Remote decorator 标记可调用 method。Host generation 产出严格 descriptor、runtime codec、declaration merge 与 source map。Client 侧 `api-remotes` assembly 选择这些生成贡献,并把具体 method 挂到 `ctx.remote.<namespace>` 与 Session scope 的 `agentCtx.remote.<namespace>`。功能包依赖生成的 service face,而不依赖 Gateway 实现或 Host 包的运行时 entry。
|
|
32
|
+
|
|
33
|
+
Connection 拥有 request correlation、`/api` carrier、trust check、精确 Fetch 路由与 connection generation。API Gateway 拥有 Remote dispatch、取消、logical stream 与选定 Host event 的转发。Controller 操作应进入生成的 Remote method 或显式 Remote stream;功能自有的下载则注册精确 Fetch 路由。[API Gateway 参考](../api-gateway.md)定义 generation 与调用,[Connection README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/connection/README.zh.md)定义物理 carrier 与信任策略。
|
|
34
|
+
|
|
35
|
+
内部 `$events` logical stream 是 Connection generation source。它的 opening `ready` frame 携带用于路径显示的 Host home,并在 Host listener 已挂载、任何 controller 开始 baseline read 之前建立 generation。`ctx.remote.$on()` 把 allowlist 内的普通 event 交付给 root Client Context,并把 scoped waterfall event 交付给已解析的 Session Context;waterfall listener 可以返回结果、调用 `next()` 或拒绝。
|
|
36
|
+
|
|
37
|
+
## Client models
|
|
38
|
+
|
|
39
|
+
每个 API controller 包都拥有配对的 Host face 与 Client face。Host 侧拥有权威 mutation 与 stream 生产;Client 侧基于相同的生成 wire type 维护 identity 稳定、与 React 无关的 model,并公开 observable snapshot 与 command。UI 包消费这些 Client service,不在 component store 中复制 transport state。
|
|
40
|
+
|
|
41
|
+
### Sessions
|
|
42
|
+
|
|
43
|
+
[`api/session-controller`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/session-controller/README.zh.md)公开 Session list、search、creation、selection data、prompt、queue、cancellation、pagination 及 follow/control stream 等 Host command。其 Client 侧按 `ClientSessions → SessionManager → Session` 组织:
|
|
44
|
+
|
|
45
|
+
- `ClientSessions` 提供 `ctx.sessions`,拥有 Session scope 与稳定的 `SessionBinding` object,并投影选中的 list state。
|
|
46
|
+
- `SessionManager` 拥有 list baseline、实时 list/control update、惰性 Session instance、queue、projection store、subagent catalog,以及 pull 与后到 update 之间的冲突顺序。
|
|
47
|
+
- 每个 `Session` 拥有一段由 `SessionEventLikeEntry` value 表示的连续逻辑 event window、pagination、follow、prompt/control state 与供 adapter 消费的 observable snapshot。
|
|
48
|
+
|
|
49
|
+
持久 event 路径打开 `follow()`,其首帧包含当前 header、tail page、cursor 与完整 projection baseline。历史 record 带有显式 `event` 或 `chunks` 判别字段和字段对齐的内部 `event`;journal 先校验每条 record 的逻辑 seq 闭区间,Client 再直接把这些 record 保留为 `SessionEventLikeEntry`,无需逐 record 转换。每个物理 generation 都根据该 snapshot 原子替换保留窗口,随后按 seq append 标准实时 event。`page()` 只用于更早历史与 gap repair。瞬态 control stream 每代以完整 baseline 开始,随后应用 queue、job 与 projection update。
|
|
50
|
+
|
|
51
|
+
### Workspaces
|
|
52
|
+
|
|
53
|
+
[`api/workspace-controller`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/workspace-controller/README.zh.md)把 Workspace mutation policy 与权威 follow feed 留在 Host。`ClientWorkspaceModel` 拥有浏览器侧 row、order、archived Session id、command echo,以及 stream/unary 竞态合并。每代 stream 先给出完整 baseline,再给出 `upsert`、`remove`、`order` 和 `archived` increment;重连时以新 baseline 替换 model。`WorkspaceController` 把该 model 作为 `ctx.workspaces` 公开,而 `ui-workspace` 向 UI 提供 `useWorkspaces` 与 navigation callback。
|
|
54
|
+
|
|
55
|
+
这种配对不会产生第二份业务真相。Host controller 决定持久状态与 mutation outcome;Client model 维护最新可用的本地 projection,在有利于渲染时保持 object identity,并明确 delayed response 与 replacement baseline 的合并规则。
|
|
56
|
+
|
|
57
|
+
## Conversation 与 presentation
|
|
58
|
+
|
|
59
|
+
`ui-session` 安装 `session` scope adapter,并提供 `useSessions`、`useSession`、`sessionId` 和 `useProjection`。领域 adapter 可以继续添加标准 source,但不会把 React hook 放进 model object。
|
|
60
|
+
|
|
61
|
+
`ui-conversation` 对每个 `SessionBinding.eventSource` 只绑定一次。它的 event registry 把持久 Session event 与 Client-only `assistant/live-chunk` update 关联成稳定的业务 Context,view registry 则 materialize target snapshot。Chat Assistant、Trajectory Assistant 与 Turn Tail 同时解释 live chunk 和持久 settlement 中嵌入的紧凑 stream,因此重连与分页历史无需持久 token 行即可复现相同 Assistant 状态。`ui-chat` 与 `ui-trajectory` 分别注册自己的 Definition 和 builder:它们可以解释同一 event family,但不会导入或共享彼此的最终 display model。Shell 选择一个已注册 view,再通过标准 hook 与 Slot 交付其 snapshot。[Conversation](./conversation.md)定义 Context identity、replay、Location data、target builder 与 keyed renderer。
|
|
62
|
+
|
|
63
|
+
`ui-slots` 提供类型化 registry 与 lifecycle ledger;`ui-renderer` 是唯一通过 `useSyncExternalStore` 绑定裸 observable、拥有 React context 并渲染 root tree 的包。功能 component 通过推导出的 props 接收 framework hook、owner prop、store action 与显式 injection。[Web Client Slots](./slots.md)列出这些输入、扩展 API 与当前 Slot 层级。
|
|
64
|
+
|
|
65
|
+
## 数据通路
|
|
66
|
+
|
|
67
|
+
| 路径 | 顺序 |
|
|
68
|
+
|---|---|
|
|
69
|
+
| 持久 Session 展示 | Host Session log → packed Remote `follow`/`page` 历史 → Client `SessionEventLikeEntry` window → Conversation Context → target snapshot(`chat`、`trajectory` 或其他已注册 target)→ Slot view → React |
|
|
70
|
+
| 瞬态 Session control | Host control baseline → Remote snapshot stream → `SessionManager` queue/job/projection store → Session 与 list snapshot → 标准 hook → component |
|
|
71
|
+
| Workspace 状态 | Host Workspace baseline 与 increment → `ClientWorkspaceModel` → `ctx.workspaces.list` → `useWorkspaces` → sidebar、hero 与 navigation entry |
|
|
72
|
+
| scoped interaction | Host Cordis waterfall → API Remotes `$events` → Session Context 上的 `ctx.remote.$on()` → 所属 UI 包 → result 或 `next()` |
|
|
73
|
+
| 用户 command | component callback → 注册项 inject face 或 Slot owner → `ctx.sessions`、`ctx.workspaces` 或生成的 scoped Remote → Host Controller → 权威 update → stream 或 event projection 回到 Client |
|
|
74
|
+
|
|
75
|
+
## 重连
|
|
76
|
+
|
|
77
|
+
物理恢复与逻辑恢复彼此独立。Gateway mux 恢复物理 WebSocket;Connection 发布可用 generation 后,每个 `RemoteStream` 分别重开自己的 logical source。Carrier failure 可以重试;business error、非法 opening item 或 protocol violation 会令所属 logical stream 终止。
|
|
78
|
+
|
|
79
|
+
恢复方式由数据语义决定:
|
|
80
|
+
|
|
81
|
+
- 持久 Session journal 校验逻辑 seq range,并根据每个 generation 的 opening snapshot 替换窗口;`page()` 提供更早历史并修复后续 range gap。
|
|
82
|
+
- Session control 与 Workspace stream 在断开期间保留最后一次发布的值,再用新的 opening baseline 原子替换。
|
|
83
|
+
- 普通 forwarded notification 不会 replay。需要可靠恢复的 stateful domain 必须提供 baseline、cursor 或显式 query;scoped waterfall 保留自身的 request lifetime。
|
|
84
|
+
|
|
85
|
+
架构中没有统一的 Client `Runtime`、`HostFrame`、`events.mux`、`events.host` 或通用 `resync()` API。Connection 公开 generation state,Gateway 管理 logical stream,Client model 则按自身数据定义 replacement 或 resume 语义。
|
|
86
|
+
|
|
87
|
+
## 包边界
|
|
88
|
+
|
|
89
|
+
功能插件包可以通过 `import type` 共享声明;不得运行时导入或转发另一个功能插件的值。跨包行为使用注入的 Cordis service,跨包 UI 使用 Slots。特定 target 的 Conversation Definition、projection helper 与最终 view data 留在所属 target 包中,即使 Chat 和 Trajectory 有意实现平行逻辑。
|
|
90
|
+
|
|
91
|
+
共享运行时值需要一个职责收窄、没有功能生命周期的静态 owner,例如 `client/store`、`ui-primitives` 或浏览器安全的 util 包。Transport 与生成 API assembly 可以导入运行时 contribution,因为组装同一个 protocol 正是它们的显式职责。功能包不能只为绕过此规则而添加 `dsh.client.external`。
|
|
92
|
+
|
|
93
|
+
根据所添加的扩展查阅四篇详细参考:
|
|
94
|
+
|
|
95
|
+
- [Client Modules](./client-modules.md):package discovery、loading、共享 module identity 与 boot order。
|
|
96
|
+
- [API Gateway](../api-gateway.md):Host method、生成的 Remote contribution、stream 与 forwarded event。
|
|
97
|
+
- [Web Client Slots](./slots.md):component、hook、store、injection 与 placement。
|
|
98
|
+
- [Conversation](./conversation.md):持久 event correlation、target snapshot,以及 Chat 或 Trajectory view contribution。
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# HTTP 服务器
|
|
7
7
|
|
|
8
|
-
[dsh-host-webserver](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/host/webserver) 是 GUI
|
|
8
|
+
[dsh-host-webserver](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/host/webserver) 是 GUI Host 的浏览器 HTTP 载体:它是一个提供 `ctx.webServer` 的 `node:http` 插件,包含具名路由注册表、可选的 gzip 响应压缩、index.html 转换回调,以及一个可由插件认领的回退处理器。它不属于 agent loop(智能体循环),也不是能力 seam;它不了解任何 harness 概念。其他插件负责注册所有功能路由,包括 `/api` 桥接、插件 bundle 和 HMR(热模块替换)事件流([分层说明](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-24-web-config-tree-boot-and-transport-layering.zh.md))。该服务器只服务浏览器:Electron 通过 `file://` 加载已构建文件,并经 IPC 桥接发送 fetch 请求,不使用本服务器。
|
|
9
9
|
|
|
10
10
|
源码:[`packages/host/webserver/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/webserver/src/index.ts)
|
|
11
11
|
|
|
@@ -27,25 +27,31 @@ interface WebRoute {
|
|
|
27
27
|
}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist
|
|
30
|
+
匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist 服务器:Connection 在读取 dist 根目录和配置 index 的 HTML 前完成认证;非 index 资产保持公开;非 GET/HEAD 返回 405,越出 dist 根目录的遍历返回 403,现有文件直接提供,缺失或不是文件的目标返回空的 404,未知扩展名按 octet-stream 发送。
|
|
31
31
|
|
|
32
32
|
## 配置
|
|
33
33
|
|
|
34
34
|
```ts type-equiv
|
|
35
|
-
/**
|
|
35
|
+
/** Web server listen and response-compression config. */
|
|
36
36
|
interface Config {
|
|
37
37
|
/** Listen host; the two supported values are loopback and all-interfaces. */
|
|
38
38
|
host: '127.0.0.1' | '0.0.0.0'
|
|
39
39
|
/** Listen port; zero requests an OS-assigned port. */
|
|
40
40
|
port: number
|
|
41
|
+
/** Response compression for socket-backed HTTP requests. @default 'none' */
|
|
42
|
+
compression?: 'none' | 'gzip'
|
|
43
|
+
/** Gzip DEFLATE level from 0 through 9. @default 1 */
|
|
44
|
+
compressionLevel?: number
|
|
45
|
+
/** Minimum known response length eligible for gzip; unknown-length streams are eligible. @default 1024 */
|
|
46
|
+
compressionThresholdBytes?: number
|
|
41
47
|
}
|
|
42
48
|
```
|
|
43
49
|
|
|
44
|
-
`host` 只接受 `127.0.0.1`(默认姿态)和 `0.0.0.0
|
|
50
|
+
`host` 只接受 `127.0.0.1`(默认姿态)和 `0.0.0.0`(刻意的网络暴露)。载体本身不拥有 TLS、认证或 Origin 策略,因此绑定到非回环地址会暴露服务器,除非组合层提供这些控制。`compression` 默认为 `none`;随附的 Web 组合选择 gzip level 1 和 1024 字节阈值。随附的 `dsh web` 命令选择 loopback 并拒绝 `--host 0.0.0.0`;其 Connection 插件为每个 Host API route 与 stream 提供 Host/Origin 校验和浏览器会话认证。其他组合自行拥有绑定与路由认证策略。dist 位置是认领席位的前端插件的组装事实。
|
|
45
51
|
|
|
46
52
|
## 服务
|
|
47
53
|
|
|
48
|
-
`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)`
|
|
54
|
+
`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。Gzip 在服务器内部包装符合条件且基于 socket 的响应,因此 route handler 继续直接持有 `ServerResponse`,服务也不新增响应写出 API。已有内容编码、`Cache-Control: no-transform`、范围响应、SSE、ZIP 与打包后的 `.gz` Worker 镜像均保持 identity 响应。`collectIndexInjections()` 经一次 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html)` 把它们渲染进成功的根路径和配置 index 响应,随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口。
|
|
49
55
|
|
|
50
56
|
处理过程中抛出异常的请求(畸形的 % 转义撞上 `decodeURIComponent`、客户端在请求体中途断开)会记录为警告并应答 400(响应头已发出时则销毁 socket),绝不导致进程退出。dispose(资源释放)把 `close()` 与 `closeAllConnections()` 配对使用,因为处理器可能像 SSE(Server-Sent Events)那样保持响应打开,而这类连接永远不会自行结束;没有强制关闭,拆卸就会挂起。该包从不打印输出:URL 行归 shell 所有。逐包运维细节(含开发模式的 bundle 监视流水线)留在 [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/webserver/README.zh.md) 中。
|
|
51
57
|
|
|
@@ -127,13 +127,19 @@ type WebFetchBody =
|
|
|
127
127
|
|
|
128
128
|
选择从不依赖注册顺序、配置顺序或 HMR(热模块替换)顺序:一项能力要么有显式的提供方 id(配置 `searchProvider`/`fetchProvider`,或填充同一字段的对应环境变量),要么在恰好只有一个可用提供方注册时自动选择;如果存在多个可用提供方却未配置 id,则抛出 `WEB_PROVIDER_AMBIGUOUS`,而不会选用最先注册的提供方。
|
|
129
129
|
|
|
130
|
+
## 抓取网络策略
|
|
131
|
+
|
|
132
|
+
已交付的 Cordis、Code 与 Standard preset 会在所有 sandbox 和审批模式下暴露 `web_fetch`,无需逐次确认。文件 sandbox preset 不管辖 Web 网络访问。需要确认步骤的部署必须添加 `tools/pre-execute` 策略或禁用抓取。
|
|
133
|
+
|
|
134
|
+
HTTP 提供方会解析每个实际请求,拒绝包括通过当前 DNS64 前缀抵达私有 IPv4 在内的非公开结果,固定已验证的地址集合,并在每次同源重定向时重复强制执行。跨源重定向需要新的工具调用和新的公开地址校验。这些检查会阻止通过 SSRF 访问非公开目的地址,但不会阻止模型把数据发送到公开 URL。
|
|
135
|
+
|
|
130
136
|
## 错误
|
|
131
137
|
|
|
132
138
|
`WebError extends HarnessError`([core.md](./core.md) 错误分类体系),带有 `code: string`(开放式,与其他 seam 的错误一致——`LlmError`、`SubagentError`),而非封闭联合类型:提供方可以在不修改 `dsh-web` 的情况下抛出自己的错误代码,消费方必须容忍未知错误代码。错误代码按所有者划分。共享的 `WebRuntime` 约定会抛出与 seam 无关的错误代码:`WEB_PROVIDER_UNAVAILABLE`、`WEB_PROVIDER_CONFIGURED_MISSING`、`WEB_PROVIDER_CONFIGURED_UNAVAILABLE`、`WEB_PROVIDER_AMBIGUOUS`、`WEB_DUPLICATE_PROVIDER`(注册时的编程错误,类似 `LlmRuntime` 的 `DUPLICATE_ADAPTER`)、`WEB_ABORTED`,以及 `WEB_PROVIDER_ERROR`(提供方自身故障经 seam 暴露时使用的兜底代码,包括 DNS、连接被拒绝、TLS 等网络或传输故障)。抓取传输层错误代码由 `dsh-web-fetch-http` 实现拥有,不同的抓取后端无需抛出它们:`WEB_INVALID_URL`、`WEB_BLOCKED_URL`、`WEB_REDIRECT_BLOCKED`、`WEB_FETCH_TOO_LARGE`、`WEB_FETCH_TIMEOUT`、`WEB_UNSUPPORTED_CONTENT_TYPE`。
|
|
133
139
|
|
|
134
140
|
## 服务
|
|
135
141
|
|
|
136
|
-
`WebRuntime` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)
|
|
142
|
+
`WebRuntime` 注册搜索与抓取提供方,以 `WEB_DUPLICATE_PROVIDER` 拒绝重复 id,并在执行时以结构化的选择错误解析提供方。本地抓取后端仅接受 HTTP(S)、拒绝凭证、对每个 hostname 只解析一次、拒绝包含任一非公开 IPv4/IPv6 目的地址或经当前前缀转换到非公开 IPv4 的 NAT64 地址的解析结果、把请求连接固定到已验证地址、对每一次同源重定向跳转重复这些校验、限制重定向次数、字节数、字符数和时间,并解码正文;展示由工具负责。
|
|
137
143
|
|
|
138
144
|
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
139
145
|
|