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
|
@@ -33,7 +33,7 @@ type ApprovalOutcome = 'allowed-once' | 'rejected' | 'cancelled' | 'unavailable'
|
|
|
33
33
|
|
|
34
34
|
## 按会话策略
|
|
35
35
|
|
|
36
|
-
`ApprovalPolicy` 决定在交互式应答者运行之前发生什么。`ask` 委托给组合的应答者链,链的无应答默认值为 `unavailable`;`never` 确定性地返回 `rejected`,不分发任何应答者。生效值为会话日志中最后一条 `approval/policy`
|
|
36
|
+
`ApprovalPolicy` 决定在交互式应答者运行之前发生什么。`ask` 委托给组合的应答者链,链的无应答默认值为 `unavailable`;`never` 确定性地返回 `rejected`,不分发任何应答者。生效值为会话日志中最后一条 `approval/policy` 事件,回退到服务配置。消费方通过 `ctx.approval.effectivePolicy(session)` 读取;`setApprovalPolicy(session, policy)` 是唯一的写入路径,因此回放能重建覆盖值。
|
|
37
37
|
|
|
38
38
|
```ts type-equiv
|
|
39
39
|
/**
|
|
@@ -60,7 +60,7 @@ type ApprovalPolicy = 'ask' | 'never'
|
|
|
60
60
|
* Readonly same-process permission question. `callId` links to an already
|
|
61
61
|
* presented tool call, so arguments are not duplicated here.
|
|
62
62
|
*/
|
|
63
|
-
interface ApprovalRequest {
|
|
63
|
+
interface ApprovalRequest extends ApprovalRequestEvent {
|
|
64
64
|
/**
|
|
65
65
|
* The agent on whose behalf the question is asked. Routes the question (a
|
|
66
66
|
* UI answerer only answers for agents it owns) and receives the audit
|
|
@@ -73,7 +73,7 @@ interface ApprovalRequest {
|
|
|
73
73
|
* The exact tool call being decided, when the asker has one — lets a UI
|
|
74
74
|
* attach the prompt to the tool call it already streamed.
|
|
75
75
|
*/
|
|
76
|
-
readonly callId?:
|
|
76
|
+
readonly callId?: ToolCallId
|
|
77
77
|
/** The asker's human-readable explanation of WHY it is asking. */
|
|
78
78
|
readonly reason?: string
|
|
79
79
|
/**
|
|
@@ -154,20 +154,20 @@ Source: [`packages/interaction/user-approval/src/index.ts`](https://github.com/d
|
|
|
154
154
|
|
|
155
155
|
#### `approval/request` — waterfall
|
|
156
156
|
|
|
157
|
-
Ask composed answerers for one decision. Return an outcome to claim the request or call `next()
|
|
157
|
+
Ask composed answerers for one decision. Return an outcome to claim the request or call `next()` to delegate. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
|
158
158
|
|
|
159
159
|
```ts cordis-catalog
|
|
160
160
|
/**
|
|
161
161
|
* Ask composed answerers for one decision. Return an outcome to claim the
|
|
162
|
-
* request or call `next()
|
|
163
|
-
*
|
|
164
|
-
* @param req -
|
|
162
|
+
* request or call `next()` to delegate. Scope-filtered dispatch
|
|
163
|
+
* (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
|
|
164
|
+
* @param req - pending approval request.
|
|
165
165
|
* @mode waterfall
|
|
166
166
|
*/
|
|
167
|
-
'approval/request'(this: Scoped<
|
|
167
|
+
'approval/request'( this: Scoped<Agent>, req: ApprovalRequestEvent, next: () => Promise<ApprovalOutcome>, ): Promise<ApprovalOutcome>
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
-
Types: [Scoped](./scope.md)
|
|
170
|
+
Types: [Agent](./core.md) · [Scoped](./scope.md)
|
|
171
171
|
|
|
172
|
-
Source: [`packages/interaction/user-approval/src/
|
|
172
|
+
Source: [`packages/interaction/user-approval/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/types.ts)
|
|
173
173
|
<!-- END GENERATED cordis-surface -->
|
|
@@ -5,32 +5,31 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# Client 模块
|
|
7
7
|
|
|
8
|
-
Web 插件表:[dsh-client-modules](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/modules) 中 client 模块系统的 Node 半,以 `ctx.clientModules`(`ClientModuleRegistry`)形式提供。它扫描宿主 Loader 的 entry,找出声明了 `dsh.client` 的包,组合出 `window.__DSH_BOOT__` entry 图,在 `/plugins
|
|
8
|
+
Web 插件表:[dsh-client-modules](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/modules) 中 client 模块系统的 Node 半,以 `ctx.clientModules`(`ClientModuleRegistry`)形式提供。它扫描宿主 Loader 的 entry,找出声明了 `dsh.client` 的包,组合出 `window.__DSH_BOOT__` entry 图,在 `/plugins` 下提供带版本的单资源或多资源 combo 脚本,并以启动协议行回应每次 index 注入收集——这是同一个服务的四个面。它是 Web GUI 栈的一项可选能力,不属于 agent loop(智能体循环)主干,并且是 [dsh-host-webserver](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/host/webserver) 的消费方:[web-server.md](./web-server.md) 所述的载体提供本服务注册的前缀路由与其回应的 `webserver/index-inject` 事件。同一个包的浏览器半(`ctx.modules`,即拉取并物化这些 bundle 的 lazy CJS 模块表)属于内核机件,记录在[包 README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/README.zh.md)中,不在本页。
|
|
9
9
|
|
|
10
10
|
源码:[`packages/client/modules/src/client/manifest.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/client/manifest.ts)
|
|
11
11
|
|
|
12
12
|
## wire
|
|
13
13
|
|
|
14
|
-
图是 Node
|
|
14
|
+
图是 Node 半与浏览器半之间协议层的唯一真源。宿主从扫描到的包组合出 `WebBootEntry` 行与 `WebBootBatch` 描述,随后在 Vite entry 之前向结构化 index 注入表贡献 registration facade、application preload、bootstrap 脚本与图全局量。`global` 行渲染为 `globalThis["__DSH_BOOT__"]`,其中 `<` 已转义,插件可控的字符串因此无法逃出 script 元素。没有有效 manifest 的页面无法启动:浏览器解析器会拒绝畸形 row 或批次、未知成员,以及未恰好归属一个初始 combo 描述的 entry。
|
|
15
15
|
|
|
16
16
|
```ts type-equiv
|
|
17
17
|
/**
|
|
18
18
|
* One composed client entry pushed by the host (a graph row). Wire
|
|
19
19
|
* single source: the host node half (package root) produces this same shape.
|
|
20
|
-
* `immediately` marks stage-one prefetch
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* `require` is synchronous (see {@link WebBootGraph.entries}).
|
|
20
|
+
* `immediately` marks stage-one prefetch. `inject` names package rows whose
|
|
21
|
+
* factories must arrive before this row materializes, while Cordis separately
|
|
22
|
+
* uses the same package edges to compose entries. `external` carries exact
|
|
23
|
+
* non-inject module requests (see {@link WebBootGraph.entries}).
|
|
25
24
|
*/
|
|
26
25
|
interface WebBootEntry {
|
|
27
26
|
/** Entry name == package name. */
|
|
28
27
|
id: string
|
|
29
|
-
/**
|
|
28
|
+
/** Revisioned single-resource combo endpoint used by HMR. */
|
|
30
29
|
url: string
|
|
31
|
-
/**
|
|
30
|
+
/** Opaque plugin-artifact revision used for HMR cache busting. */
|
|
32
31
|
rev: string
|
|
33
|
-
/** Package-name dependency edges
|
|
32
|
+
/** Package-name dependency edges used for factory arrival and plugin composition. */
|
|
34
33
|
inject?: string[]
|
|
35
34
|
/** Stage-one prefetch mark: load the script for factory registration during module-face boot. */
|
|
36
35
|
immediately?: boolean
|
|
@@ -39,6 +38,25 @@ interface WebBootEntry {
|
|
|
39
38
|
}
|
|
40
39
|
```
|
|
41
40
|
|
|
41
|
+
```ts type-equiv
|
|
42
|
+
/** Initial scheduling phase for one content-addressed combo script. */
|
|
43
|
+
type WebBootBatchPhase = 'bootstrap' | 'application'
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```ts type-equiv
|
|
47
|
+
/** One initial combo script; a scheduling phase may span several descriptors. */
|
|
48
|
+
interface WebBootBatch {
|
|
49
|
+
/** Parser-blocking bootstrap or preloaded application scheduling. */
|
|
50
|
+
phase: WebBootBatchPhase
|
|
51
|
+
/** Content-addressed combo script endpoint. */
|
|
52
|
+
url: string
|
|
53
|
+
/** Revision over the combined plugin script bytes and indexed source map. */
|
|
54
|
+
rev: string
|
|
55
|
+
/** Graph entry ids whose factories the script registers, in execution order. */
|
|
56
|
+
entries: string[]
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
42
60
|
```ts type-equiv
|
|
43
61
|
/** The composed client entry graph the host injects as `window.__DSH_BOOT__`. */
|
|
44
62
|
interface WebBootGraph {
|
|
@@ -50,28 +68,42 @@ interface WebBootGraph {
|
|
|
50
68
|
* unrelated and remains owned by fiber service waiting.
|
|
51
69
|
*/
|
|
52
70
|
entries: WebBootEntry[]
|
|
71
|
+
/** Initial combo descriptors; every entry belongs to exactly one descriptor. */
|
|
72
|
+
batches: WebBootBatch[]
|
|
53
73
|
}
|
|
54
74
|
```
|
|
55
75
|
|
|
56
|
-
|
|
76
|
+
每个初始 row 的 `rev` 都是不透明的进程 nonce 加序号,因此组合图时不会哈希每个插件产物。HMR 观察到变化后,该 row 的 revision 才改为新 bundle 及其可用 sourcemap 的哈希。初始描述把 row 划入 bootstrap 与 application 两个调度阶段,每个阶段都可以包含多条描述。URL 只含有序 package 资源列表与 revision,阶段名不会进入路由。图组合保持 row 顺序,并在 map 形式 URL 超过 3 KiB 前贪心切分。启动 combo revision 对合并后的插件脚本字节与 indexed sourcemap 求哈希,图 revision 则对 row 与描述一并求哈希。`immediately` 标记第一阶段的 registration barrier;同一 combo 中的 row 共享脚本传输,不同 combo 则独立加载。
|
|
57
77
|
|
|
58
78
|
## 扫描
|
|
59
79
|
|
|
60
|
-
包加入这张表的方式,是在自己的 package.json 中声明 `dsh.client`(`platform: 'web'`、可选的 `inject` 边、可选的 `immediately`),并在 `exports["./client"]` 导出构建好的 bundle
|
|
80
|
+
包加入这张表的方式,是在自己的 package.json 中声明 `dsh.client`(`platform: 'web'`、可选的 `inject` 边、可选的 `immediately`),并在 `exports["./client"]` 导出构建好的 bundle。每个 live row 都从自己的 Loader specifier 与所属 tree `baseUrl` 解析;若 `loader.internal.resolveSync` 可用,则使用 Host face import 所用的同一个实现。最近归属的 package manifest 提供浏览器模块 id,因此相对 source 与 built overlay 仍保留包身份。若不同的 active Loader source 解析到同一包名,组合会失败;一个来源卸载后,仍存活的来源无需重启 fiber 即可提供该 row。
|
|
61
81
|
|
|
62
82
|
扫描是单包增量的;不存在全量重扫代码路径。fiber 构造或 dispose(资源释放)时的每次 cordis `internal/plugin` 发射都把该 fiber 的 entry 名标脏,一次微任务 flush 把每个脏名与实时 loader entry 对账。激活趟以全部当前 entry 灌入同一个脏集合并同步 flush,因此初扫与稳态共享一条实现——但失败姿态相反。激活时,已加载 entry 中的畸形声明或缺失 bundle 会聚合为一个大声的 `AggregateError`,列出每个损坏的包:该 fiber 进入 FAILED,由启动的大声失败 sweep 上报。稳态下,损坏的包只记录一条警告,且不得殃及其他包。
|
|
63
83
|
|
|
64
|
-
包元数据——包括「非 client
|
|
84
|
+
包元数据——包括「非 client 包」这一否定结论——按 Loader specifier 与所属 tree base URL 缓存至重启。同一来源的 fiber 重启会原样复用其 row 与 rev;bundle 内容变更只经 `rebuilt()` 到达图。
|
|
65
85
|
|
|
66
86
|
## bundle 路由与 index 注入
|
|
67
87
|
|
|
68
|
-
`GET
|
|
88
|
+
`GET`/`HEAD /plugins/??<package-a>/client.js,<package-b>/client.js&rev=<rev>` 提供精确生成的 combo 脚本;单资源请求采用同一形式,也是 HMR 路径。其绝对 `sourceMappingURL` 平行改写每个资源后缀,得到 `/plugins/??<package-a>/client.js.map,<package-b>/client.js.map&rev=<rev>`。即使只有一个资源,map 仍采用 Indexed Source Map v3。组件有自带 map 时直接用于对应 section;没有时则获得 identity section,其 `sourcesContent` 是构建后 bundle,source 名取打包后的 `sourceURL` 或插件路由。每条启动请求 URL 按 UTF-8 字节计算都不超过 3 KiB;切分按更长的 map 形式计算。所有 application URL 都会预加载,所有 bootstrap URL 都会在图全局量与 Vite entry 之前执行。所有已发布响应都使用长期 immutable 缓存。未知或被修改的资源列表、缺少 revision 及陈旧 revision 都返回 404,绝不提供其他字节,也不会让 SPA fallback 把 HTML 当作 JavaScript 返回;其他方法返回 405。注入行在每次 index 渲染时携带当前图,因此重新加载总是基于实时组合启动。
|
|
69
89
|
|
|
70
90
|
## 服务
|
|
71
91
|
|
|
72
|
-
|
|
92
|
+
```ts type-equiv
|
|
93
|
+
/** Filesystem baseline captured before a client artifact snapshot is read. */
|
|
94
|
+
interface ClientArtifactBaseline {
|
|
95
|
+
/** Absolute path of the client bundle. */
|
|
96
|
+
readonly path: string
|
|
97
|
+
/** Bundle modification time in milliseconds. */
|
|
98
|
+
readonly mtimeMs: number
|
|
99
|
+
/** Bundle size in bytes. */
|
|
100
|
+
readonly size: number
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`ClientModuleRegistry`(`ctx.clientModules`,定义于 [`packages/client/modules/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/modules/src/index.ts))暴露读取面与重建面;签名见生成的[服务目录](#ctxclientmodules--clientmoduleregistry)。`graph()` 返回当前组合出的图(两次变更之间是同一个稳定对象),`clientPath(id)` 返回 bundle 的绝对路径,`artifactBaseline(id)` 返回读取当前快照前捕获的 bundle stat 值。`rebuilt(id)` 是变化后的 bundle 内容到达图的唯一入口:它把 bundle 与当前 source map 一起重新哈希,只有 rev 真正变化才会重新组合图并发出通知。`onRebuilt` 按发生变化的 bundle 逐个触发并携带新 rev;`onGraphChanged` 在任何一次重新组合了图的 flush 之后触发(行的增删,或 rebuilt 带来的 rev 变化),并采用拉取模型——监听器自行重读 `graph()`。两条通知路径都会兜住监听器异常,因此一个抛错的订阅者既不能让后续订阅者被跳过,也不能杀死触发这次 flush 的一方。
|
|
73
105
|
|
|
74
|
-
开发环境下,[dsh-client-hmr](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/hmr/README.zh.md) 是注册表的监视驱动:它的 Node
|
|
106
|
+
开发环境下,[dsh-client-hmr](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/hmr/README.zh.md) 是注册表的监视驱动:它的 Node 半从 module host 读文件前记录的基线出发,对图中每一行的 bundle 做 stat 轮询,只为变化或标脏的 row 调用 `rebuilt(id)`,经 `onGraphChanged` 重新同步监视集合,并通过 SSE(Server-Sent Events)把 rev 变化广播给浏览器半。仅 source map 变化不会触发重载;bundle 变化时,当前 map 会一起进入快照。生产环境的图完全不含 HMR(热模块替换)行;module host 自身从不监视文件。
|
|
75
107
|
|
|
76
108
|
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
77
109
|
|
|
@@ -101,6 +133,16 @@ graph(): WebBootGraph
|
|
|
101
133
|
*/
|
|
102
134
|
clientPath(id: string): string | undefined
|
|
103
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Filesystem baseline captured before an entry's current bytes were read.
|
|
138
|
+
* HMR compares it with the live files when installing a watch, so a write
|
|
139
|
+
* between startup composition and watch installation cannot disappear into
|
|
140
|
+
* the watcher's initial state.
|
|
141
|
+
* @param id - entry id (package name).
|
|
142
|
+
* @returns the path and baseline, or undefined for an unknown id.
|
|
143
|
+
*/
|
|
144
|
+
artifactBaseline(id: string): ClientArtifactBaseline | undefined
|
|
145
|
+
|
|
104
146
|
/**
|
|
105
147
|
* Re-hash one bundle (the HMR watch's registration hook — the only entry
|
|
106
148
|
* point through which bundle content changes reach the graph).
|
|
@@ -5,7 +5,7 @@ outline: [2,3]
|
|
|
5
5
|
|
|
6
6
|
# 代码运行时
|
|
7
7
|
|
|
8
|
-
代码执行 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md):其 Service Definition([dsh-code-runtime](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](./core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread Service Provider 与工具注册表 Consumer 的约定见 [
|
|
8
|
+
代码执行 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md):其 Service Definition([dsh-code-runtime](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/code-runtime/code-runtime),`ctx.codeRuntime`)使用宿主提供的异步绑定运行一段模型编写的程序,并报告其打印内容与返回值。代码执行是**一项可选能力**,不属于 agent loop(智能体循环)主干,因此其词汇定义在此而非 [core.md](./core.md) 中。各后端的执行基底与源语言不同,这两项均为服务上的只读描述符;worker-thread Service Provider 与工具注册表 Consumer 的约定见 [PTC mode 基础设计](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-06-15-ptc.zh.md) 和[类型化返回约定](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-20-ptc-typed-tool-returns.zh.md)。
|
|
9
9
|
|
|
10
10
|
源码:[`packages/code-runtime/code-runtime/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/types.ts)
|
|
11
11
|
|
|
@@ -55,7 +55,11 @@ interface CodeRunResult {
|
|
|
55
55
|
* rendered string; a failed or value-less run leaves this absent.
|
|
56
56
|
*/
|
|
57
57
|
value?: CodeJsonValue
|
|
58
|
-
/**
|
|
58
|
+
/**
|
|
59
|
+
* Captured text. Each source channel preserves emission order; interleaving
|
|
60
|
+
* across independent channels is backend-dependent. Bounded only as part of
|
|
61
|
+
* the outer result.
|
|
62
|
+
*/
|
|
59
63
|
logs: string[]
|
|
60
64
|
/** Present iff the run failed; see {@link CodeRunFailure} for the taxonomy. */
|
|
61
65
|
error?: CodeRunFailure
|
|
@@ -64,7 +68,7 @@ interface CodeRunResult {
|
|
|
64
68
|
|
|
65
69
|
## 绑定:宿主函数作为程序全局变量
|
|
66
70
|
|
|
67
|
-
每个 `CodeBindingNamespace` 在程序内成为一个由异步可调用函数组成的全局对象(
|
|
71
|
+
每个 `CodeBindingNamespace` 在程序内成为一个由异步可调用函数组成的全局对象(PTC mode Consumer 传入一个:`tools`)。参数与返回值必须是无损 JSON,且跨越边界时不受 seam 层字节上限约束;运行时可以通过结构化克隆桥接它们。命名空间可以声明程序可见的错误类,而无需让运行时知道 Consumer 的名称:运行时会注入真实构造函数,并将被拒绝的调用转为该类的实例。运行时也将绑定名视为不可信输入(`__proto__` 是普通自有属性,绝不会发生原型碰撞):
|
|
68
72
|
|
|
69
73
|
```ts type-equiv
|
|
70
74
|
/**
|
|
@@ -72,7 +76,7 @@ interface CodeRunResult {
|
|
|
72
76
|
* injects a real error constructor under `name`; rejected member calls become
|
|
73
77
|
* its instances and expose the exact member name through
|
|
74
78
|
* `memberNameProperty`. Both strings are runtime data rather than knowledge
|
|
75
|
-
* of a particular consumer such as
|
|
79
|
+
* of a particular consumer such as PTC mode.
|
|
76
80
|
*/
|
|
77
81
|
interface CodeBindingErrorClass {
|
|
78
82
|
/** Constructor global and resulting `Error.name`; same portable identifier rule as {@link CodeBindingNamespace.global}. */
|
|
@@ -134,7 +138,7 @@ type CodeBindingFunction = (args: unknown) => Promise<CodeJsonValue>
|
|
|
134
138
|
|
|
135
139
|
## 捕获的输出与失败分类体系
|
|
136
140
|
|
|
137
|
-
|
|
141
|
+
日志是纯字符串。每个来源通道保留自身的发出顺序;由于通道元数据不属于 seam,相互独立的通道如何交错由后端决定。运行时捕获程序的 console 与流输出,Consumer 只渲染文本。实现会对序列化后的外层日志数组,以及完成值或失败消息的组合载荷设置上限;固定的结果封装语法与 Consumer 展示空白不计入这份可变载荷计量。超限会显式失败,而不会在值中插入替代内容。
|
|
138
142
|
|
|
139
143
|
失败类型是**正交的结果,独立报告**(见 [defensive-patterns](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/defensive-patterns.zh.md)):预算耗尽不是异常,中止不是超时,基底崩溃(如 OOM)也不是二者中的任何一个:
|
|
140
144
|
|
|
@@ -161,7 +165,7 @@ interface CodeRunFailure {
|
|
|
161
165
|
|
|
162
166
|
## 服务
|
|
163
167
|
|
|
164
|
-
`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,已知值为 `'typescript'` 与 `'python'`,即 `dsh-tools`
|
|
168
|
+
`CodeRuntime`(`ctx.codeRuntime`,抽象服务,定义于 [`packages/code-runtime/code-runtime/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/code-runtime/code-runtime/src/index.ts))由 `run(request)` 加两个只读描述符组成:`language`(程序必须使用的语言,已知值为 `'typescript'` 与 `'python'`,即 `dsh-tools` 能呈现的那些,TypeScript 后端已发布、Python 后端为实验性且私有(未发布);生成语言相关展示的 Consumer 据此切换,遇到无法展示的语言时应显式报错)和 `isolation`(执行基底,`'worker-thread'`、`'process'`、`'container'`;仅为诊断标签,**不构成安全承诺**)。实现必须保证各次运行彼此隔离(无跨运行状态),并在 dispose(资源释放)时等待系统完全停稳:teardown 要等到所有进行中的运行均已终止并结算后才完成。
|
|
165
169
|
|
|
166
170
|
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
167
171
|
|
|
@@ -11,7 +11,7 @@ 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. */
|
|
@@ -19,13 +19,13 @@ interface CommandInputDescriptor {
|
|
|
19
19
|
/** Placeholder shown before the user supplies free-form input. */
|
|
20
20
|
readonly hint: string
|
|
21
21
|
/**
|
|
22
|
-
* Whether composer
|
|
23
|
-
* false = the executor rejects an invocation carrying
|
|
22
|
+
* Whether composer attachments may accompany an invocation. Absent or
|
|
23
|
+
* false = the executor rejects an invocation carrying attachments and capable
|
|
24
24
|
* composers refuse the submission before dispatch. A declaring command's
|
|
25
25
|
* handler receives the admitted durable blocks and owns every further
|
|
26
26
|
* grammar decision, including rejecting sub-commands that cannot use them.
|
|
27
27
|
*/
|
|
28
|
-
readonly
|
|
28
|
+
readonly attachments?: boolean
|
|
29
29
|
}
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -67,13 +67,13 @@ interface CommandInvocation {
|
|
|
67
67
|
/** Exact text following the registered command name, including separator whitespace. */
|
|
68
68
|
readonly rawInput: string
|
|
69
69
|
/**
|
|
70
|
-
* Durably admitted image blocks accompanying this invocation, in submission
|
|
71
|
-
* order; empty unless the definition declares `input.
|
|
70
|
+
* Durably admitted image and file blocks accompanying this invocation, in submission
|
|
71
|
+
* order; empty unless the definition declares `input.attachments`. The handler
|
|
72
72
|
* owns their model-visible use — the registry never schedules them itself —
|
|
73
73
|
* and a handler whose grammar cannot use them in this invocation returns an
|
|
74
74
|
* error so the dispatching composer retains the originals.
|
|
75
75
|
*/
|
|
76
|
-
readonly attachments: readonly ImageBlock[]
|
|
76
|
+
readonly attachments: readonly (ImageBlock | FileBlock)[]
|
|
77
77
|
/** Cancellation signal owned by the dispatching UI request. */
|
|
78
78
|
readonly signal: AbortSignal
|
|
79
79
|
}
|
|
@@ -86,7 +86,7 @@ type CommandResult =
|
|
|
86
86
|
readonly kind: 'success'
|
|
87
87
|
readonly text?: string
|
|
88
88
|
/** Earlier authoritative domain event that owns a richer presentation. */
|
|
89
|
-
readonly sourceEventSeq?:
|
|
89
|
+
readonly sourceEventSeq?: SessionSeq
|
|
90
90
|
}
|
|
91
91
|
| { readonly kind: 'error'; readonly text: string }
|
|
92
92
|
```
|
|
@@ -141,6 +141,13 @@ Human-command registry. Plain-context definitions are global; definitions regist
|
|
|
141
141
|
*/
|
|
142
142
|
register(definition: CommandDefinition): () => void
|
|
143
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Register the sole authority that resolves staged file receipts for command submissions.
|
|
146
|
+
* @param resolver - Session-aware receipt resolver.
|
|
147
|
+
* @returns disposer that removes this exact resolver.
|
|
148
|
+
*/
|
|
149
|
+
registerFileReceiptResolver(resolver: CommandFileReceiptResolver): () => void
|
|
150
|
+
|
|
144
151
|
/**
|
|
145
152
|
* List the effective immutable command descriptors for one agent.
|
|
146
153
|
* @param agent - exact receiving agent and scoped-layer key.
|
|
@@ -169,23 +176,25 @@ find(agent: Agent, name: string): CommandDefinition | undefined
|
|
|
169
176
|
* handler-failure path is contained so the handler's own error stays the
|
|
170
177
|
* reported failure.
|
|
171
178
|
*
|
|
172
|
-
*
|
|
173
|
-
* command that does not declare `input.
|
|
174
|
-
* and an exceeded
|
|
175
|
-
* the handler runs
|
|
179
|
+
* Attachment admission is enforced here, not in the composer: attachments sent to a
|
|
180
|
+
* command that does not declare `input.attachments`, an absent attachment store,
|
|
181
|
+
* and an exceeded image limit each settle as an error result before
|
|
182
|
+
* the handler runs. Validation rejection starts no attachment writes;
|
|
183
|
+
* a storage failure can leave only unreachable content-addressed objects
|
|
184
|
+
* for deferred collection.
|
|
176
185
|
*
|
|
177
186
|
* @param agent - exact receiving agent.
|
|
178
187
|
* @param line - complete slash-command line.
|
|
179
|
-
* @param
|
|
180
|
-
* submission order; empty for a plain invocation.
|
|
188
|
+
* @param submittedAttachments - encoded images and staged file receipts accompanying the line,
|
|
189
|
+
* in submission order; empty for a plain invocation.
|
|
181
190
|
* @param signal - cancellation signal owned by the UI request.
|
|
182
191
|
* @returns the settled execution (result + lifecycle pairing id), or
|
|
183
192
|
* `undefined` when syntax or name does not resolve.
|
|
184
193
|
*/
|
|
185
|
-
@Remote async execute( agent: Agent, line: string,
|
|
194
|
+
@Remote async execute( agent: Agent, line: string, submittedAttachments: readonly CommandSubmitAttachment[], signal: AbortSignal, ): Promise<CommandExecution | undefined>
|
|
186
195
|
```
|
|
187
196
|
|
|
188
|
-
Types: [Agent](./core.md)
|
|
197
|
+
Types: [Agent](./core.md)
|
|
189
198
|
|
|
190
199
|
Source: [`packages/interaction/commands/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/commands/src/index.ts)
|
|
191
200
|
|
|
@@ -37,11 +37,11 @@ interface CompactionResult {
|
|
|
37
37
|
/** Human command that initiated this compaction, when it was manual. */
|
|
38
38
|
sourceCommandId?: CommandId
|
|
39
39
|
/** The seq of the appended `compaction/start` event. */
|
|
40
|
-
startSeq:
|
|
40
|
+
startSeq: SessionSeq
|
|
41
41
|
/** The seq of the appended `compaction/summary` event. */
|
|
42
|
-
summarySeq:
|
|
42
|
+
summarySeq: SessionSeq
|
|
43
43
|
/** The seq of the appended `compaction/end` event. */
|
|
44
|
-
endSeq:
|
|
44
|
+
endSeq: SessionSeq
|
|
45
45
|
/** The summary content blocks produced by the backend. */
|
|
46
46
|
summary: ContentBlock[]
|
|
47
47
|
/**
|
|
@@ -52,9 +52,9 @@ interface CompactionResult {
|
|
|
52
52
|
* can be GREATER than `end`. {@link CompactionResult.shadowedSeqs} is the
|
|
53
53
|
* authoritative set of shadowed nodes, in surface order.
|
|
54
54
|
*/
|
|
55
|
-
shadowedRange: { start:
|
|
55
|
+
shadowedRange: { start: SessionSeq; end: SessionSeq }
|
|
56
56
|
/** The seqs of all shadowed surface nodes, in surface order. */
|
|
57
|
-
shadowedSeqs:
|
|
57
|
+
shadowedSeqs: SessionSeq[]
|
|
58
58
|
/** Estimated token count of the shadowed content. */
|
|
59
59
|
shadowedTokenCount: number
|
|
60
60
|
}
|
|
@@ -86,7 +86,7 @@ type ManualCompactionErrorCode =
|
|
|
86
86
|
|
|
87
87
|
`changed` 和 `summary` 保持会话表层不变,但仍会闭合失败尝试并将其持久化到日志。`commit` 可能发生在部分变更之后;`persistence` 表示内存中的标记对已闭合,但 flush 失败。取消独立于这些失败,并在完成必要清理后抛出原始 abort 原因。
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
压力压缩在 `agent/pre-step` waterfall(瀑布式事件)中运行,先于请求推导。一旦压力或规范化溢出满足条件,compaction-basic 会在选择范围前调用可选的 [`ctx.toolResultPruner`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/compaction/compaction-tool-result-pruner/README.zh.md),再通过 `ctx.tokenMeter` 重新测量,并且可以在不生成摘要的情况下推进 surface。失败请求的恢复在失败的步骤关闭后通过 `agent/request-error` 运行;仅当 surface replacement generation 前进时才返回重试动作,即便后续摘要工作在剪枝后抛异常亦如此;取消仍然优先。区域边界保持工具调用/结果配对,但不保持整个轮次,因此一个过大轮次中较早关闭的步骤可以被压缩。`dsh-compaction-basic` 拥有阈值、保留尾部策略、溢出上限与失败处理。
|
|
90
90
|
|
|
91
91
|
该 Service Definition 导出 `toolPairingBalancedBefore(session, seq)` 与 `toolPairingBalancedAfter(session, seq)`,用于检查 seq 之前与之后的工具调用/结果配对。两者都会验证当前 surface 成员关系,并拒绝缺失的 seq 与遗留结果;[包约定](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/compaction/compaction/README.zh.md#tool-pairing-boundaries)定义其缓存行为。
|
|
92
92
|
|
|
@@ -98,11 +98,11 @@ type ManualCompactionErrorCode =
|
|
|
98
98
|
/** Cited source event and size accounting for one landed surface replacement. */
|
|
99
99
|
interface PrunedEntry {
|
|
100
100
|
/** Full-fidelity tool-result event shadowed by the replacement. */
|
|
101
|
-
readonly originalSeq:
|
|
101
|
+
readonly originalSeq: SessionSeq
|
|
102
102
|
/** Newly appended pruned tool-result event. */
|
|
103
|
-
readonly replacementSeq:
|
|
103
|
+
readonly replacementSeq: SessionSeq
|
|
104
104
|
/** Tool call shared by the original and replacement. */
|
|
105
|
-
readonly callId:
|
|
105
|
+
readonly callId: ToolCallId
|
|
106
106
|
/** Original text size in Unicode code points. */
|
|
107
107
|
readonly charsBefore: number
|
|
108
108
|
/** Replacement text size in Unicode code points. */
|
|
@@ -190,10 +190,10 @@ abstract compactNow( agent: ManualCompactAgentContext, signal: AbortSignal, sour
|
|
|
190
190
|
* @throws when compaction is active or the range is missing, reversed, or unbalanced.
|
|
191
191
|
* @returns the appended event seqs, summary, replaced range, and token accounting.
|
|
192
192
|
*/
|
|
193
|
-
abstract compactRegion( start:
|
|
193
|
+
abstract compactRegion( start: SessionSeq, end: SessionSeq, agent: CompactionAgentContext, signal?: AbortSignal, ): Promise<CompactionResult>
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
Types: [CommandId](./commands.md)
|
|
196
|
+
Types: [CommandId](./commands.md) · [SessionSeq](./session.md)
|
|
197
197
|
|
|
198
198
|
Source: [`packages/compaction/compaction/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/compaction/compaction/src/index.ts)
|
|
199
199
|
|
package/kb/site/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md}
RENAMED
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
---
|
|
2
|
-
editSource: "docs/
|
|
2
|
+
editSource: "docs/subsystems/conversation.zh.md"
|
|
3
|
+
outline: [2,3]
|
|
3
4
|
---
|
|
4
5
|
|
|
5
|
-
#
|
|
6
|
+
# Conversation 组装
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
Conversation 是 Client `SessionEventLikeEntry` window 与浏览器 view 之间的 target-neutral assembly 层。[`ui-conversation`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-conversation/README.zh.md)拥有 event 与 view registry、每个 `SessionBinding` 对应的 identity-stable binding、Turn/Step Location、增量 Context assembly、target source、共享 shell 与输入编排。[`ui-chat`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/README.zh.md)和 [`ui-trajectory`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-trajectory/README.zh.md)等 target 包拥有各自的 Definition、最终 snapshot 与渲染。
|
|
8
9
|
|
|
9
|
-
[Conversation Node 组装决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-09-client-conversation-node-assembly.zh.md)
|
|
10
|
+
本文定义数据模型与业务自有 Conversation node 的扩展路径。[Web Client 架构](./web-client.md)说明该子系统在 Client model 与 Slots 之间的位置;[Conversation Node 组装决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-09-client-conversation-node-assembly.zh.md)记录其设计理由。
|
|
10
11
|
|
|
11
|
-
##
|
|
12
|
+
## 数据模型与所有权
|
|
13
|
+
|
|
14
|
+
Session Controller 拥有连续的已加载逻辑 event window。每个 `SessionEventLikeEntry` 要么是表示一个持久事件的 `{ type: 'event', event: SessionEvent }`,要么是表示一个 Client-only `assistant/live-chunk` 呈现的 `{ type: 'transient', event: AssistantLiveChunkEvent }`;两种内部 event 都公开 `type`、`seq`、`time` 与 `data`。`ui-conversation` 把这些 entry 直接交给 assembler,不另开 history stream。每个 Session 对应一个 `ConversationNodeAssembler`,它应用所有已注册 Definition,并为每个已注册 view target 发布独立 source。
|
|
15
|
+
|
|
16
|
+
| 概念 | Owner 与用途 |
|
|
17
|
+
|---|---|
|
|
18
|
+
| Event Definition | 业务包一次匹配一个持久 event 或 Client-only 瞬态 event,以稳定 `(kind, id)` 关联输入、折叠确定性 State,并可选择 materialize 一个 target node。 |
|
|
19
|
+
| Context | Engine 为一个 `(kind, id)` 拥有的有序 Match 与当前 State。一个瞬态 event 只占一个 update Match;只有 update 的证据可以保持 pending,直到分页补齐其唯一持久 start。 |
|
|
20
|
+
| Location | Engine 根据持久 boundary event 推导的 Session、Turn 或 Step 坐标。Definition 可以向一个 Turn 或 Step 发布类型化数据。 |
|
|
21
|
+
| View Definition | Target 包为每个 Session 创建一个增量 builder,并拥有该 target 的最终 snapshot 类型。 |
|
|
22
|
+
| View | Chat 或 Trajectory 等 Slot entry 只读取自身 target snapshot,并渲染 target 自有 node。 |
|
|
23
|
+
|
|
24
|
+
Chat 与 Trajectory 可以识别同一个持久 event family,但各自保留自己的 Definition State 与最终 node payload。共享的 target-neutral 机制只包括 identity routing、有序 replay、Location data、predecessor dependency 与 publication cadence。
|
|
25
|
+
|
|
26
|
+
## Target 激活
|
|
27
|
+
|
|
28
|
+
每个 Session 都保留单调增长的 active target 集合。创建或读取 target source 不会激活它。shell 会显式激活持久化选择或新选择的 View,其他消费者则通过 target source 的首个订阅激活 target。首次激活会创建该 target 的 builder,并从当前按 target 索引的 Context 调用一次 `replace()`。后续 flush 对每个 active target 调用 `apply()`,取消订阅不会移除 target。
|
|
29
|
+
|
|
30
|
+
shell 拥有 View 选择,并在 binding 创建、被选为 current 或 View roster 变化时,于渲染前解析已注册的偏好 View 或 Chat fallback。assembler 只接收解析后的 target id,不自行选择 Chat 或其他默认 target。第三方 View 使用相同的选择与激活操作。
|
|
31
|
+
|
|
32
|
+
## 可回放 event family
|
|
12
33
|
|
|
13
34
|
编写 Definition 前先选定稳定的业务 id。构成同一个 Node 的每条事件都必须携带该 id,或只凭自身 payload 独立推导出该 id;Client 绝不能把 update 猜测为属于“最近一个未完成”的 Context。
|
|
14
35
|
|
|
@@ -24,18 +45,21 @@ editSource: "docs/cookbook/adding-a-conversation-node.zh.md"
|
|
|
24
45
|
|
|
25
46
|
系统支持增量事件。如果生产方能以较低成本发出 whole-value checkpoint,应优先采用,因为 start 位于已加载窗口之外时它仍可直接使用。每条 delta 都必须携带稳定 id,并且按照日志 `seq` 升序回放时能够确定性地产生 State;它不能依赖只存在于实时内存中的状态。如果当前历史窗口只有 update,Assembler 会保留一个 pending Context,并在更早分页补齐 start 前不构造 State。如果产品必须在 start 尚未加载时渲染,terminal 或 checkpoint 事件就必须携带足够的完整 fallback 状态,让 Definition 能直接构造结果;不要通过扫描无关事件恢复它。
|
|
26
47
|
|
|
27
|
-
|
|
48
|
+
实时 Assistant delta 作为 Client-only `assistant/live-chunk` update 到达。重连 baseline 会把活跃的进程内紧凑 stream 展开为相同的瞬态 event,持久 `assistant/message` 与 `assistant/attempt` event 则嵌入完整紧凑 stream 供历史回放。瞬态 event 只能充当 update;`start()` 只接收标准 `SessionEvent`。消费 Assistant 输出的 Definition 在同一组 `match()` 与 `update()` 方法里处理 live chunk 与持久 settlement,其他 Definition 直接返回 `null`,无需展开 stream。
|
|
49
|
+
|
|
50
|
+
## Definition 与类型化 Chat payload
|
|
28
51
|
|
|
29
52
|
为了完整展示关联关系,下面把生产方声明和 Client 贡献写在同一个代码块里。实际的包族中,branded id 与 `SessionEventMap` 声明留在事件生产方,Definition、Chat data 合并与 renderer 留在 Client 插件。
|
|
30
53
|
|
|
31
54
|
```ts ignore-check
|
|
32
55
|
import { createElement } from 'react'
|
|
56
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
33
57
|
import type { Branded } from '@deepseek-ai/dsh-brand'
|
|
34
58
|
import type {
|
|
35
|
-
|
|
59
|
+
ConversationLocation, ConversationNodeContext,
|
|
36
60
|
ConversationNodeDefinition,
|
|
37
|
-
} from '@deepseek-ai/dsh-client-
|
|
38
|
-
import type { ChatNodeViewProps } from '@deepseek-ai/dsh-client-ui-
|
|
61
|
+
} from '@deepseek-ai/dsh-client-ui-conversation/client'
|
|
62
|
+
import type { ChatNodeViewProps } from '@deepseek-ai/dsh-client-ui-chat/client'
|
|
39
63
|
|
|
40
64
|
type ReviewId = Branded<'ReviewId'>
|
|
41
65
|
|
|
@@ -90,13 +114,13 @@ interface ReviewChatData {
|
|
|
90
114
|
readonly summary?: string
|
|
91
115
|
}
|
|
92
116
|
|
|
93
|
-
declare module '@deepseek-ai/dsh-client-ui-
|
|
117
|
+
declare module '@deepseek-ai/dsh-client-ui-chat/client' {
|
|
94
118
|
interface ChatNodeDataMap {
|
|
95
119
|
'review-job': ReviewChatData
|
|
96
120
|
}
|
|
97
121
|
}
|
|
98
122
|
|
|
99
|
-
declare module '@deepseek-ai/dsh-client-
|
|
123
|
+
declare module '@deepseek-ai/dsh-client-ui-conversation/client' {
|
|
100
124
|
interface ConversationStepDataMap {
|
|
101
125
|
'review-job': ReviewChatData
|
|
102
126
|
}
|
|
@@ -184,10 +208,10 @@ function ReviewNodeView({ node }: ChatNodeViewProps<'review-job'>) {
|
|
|
184
208
|
return createElement('p', null, text)
|
|
185
209
|
}
|
|
186
210
|
|
|
187
|
-
export const inject = ['
|
|
211
|
+
export const inject = ['uiConversation', 'slots']
|
|
188
212
|
|
|
189
213
|
export function apply(ctx: ClientContext): void {
|
|
190
|
-
ctx.
|
|
214
|
+
ctx.uiConversation.events.register(reviewDefinition)
|
|
191
215
|
ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({
|
|
192
216
|
name: 'conversation.chat.node',
|
|
193
217
|
key: 'review-job',
|
|
@@ -195,33 +219,33 @@ export function apply(ctx: ClientContext): void {
|
|
|
195
219
|
}
|
|
196
220
|
```
|
|
197
221
|
|
|
198
|
-
`match(event)` 是身份提取器,不是 fold
|
|
222
|
+
`match(event)` 是身份提取器,不是 fold:它只能收到当前 `SessionEventLike`,并返回 Definition 内部 id 与生命周期角色。命中后,Assembler 通过 `(kind, id)` 定位 Context;标准 event 可触发一次 `start`,标准或 packed event 可把当前 State 交给 `update`。两个函数都必须返回引擎随后采用的 State;推荐返回新的 immutable value,但函数原地修改后返回同一对象时,采用语义也相同。
|
|
199
223
|
|
|
200
224
|
`buildLocationData(context, scope)` 可以把 Definition 拥有的数据发布到引擎拥有的 Turn 或 Step 上。通过 declaration merging 为每个 key 指定精确 value 类型。同一 Location 内的另一个 Node 可以使用受限 slot hook(例如 `useTurnData(key)`)读取该值,无须取得 Session,也无须扫描 `snapshot.chat.nodes`。
|
|
201
225
|
|
|
202
226
|
`target` 与 `buildViewNode(context)` 必须同时声明一项由 target 拥有的渲染贡献。把 `context.key` 保留为 React 侧身份,根据持久排序证据选择 `anchorSeq`,并且只返回 renderer 可以直接使用的数据。某个 target Node 一旦发布,就要继续返回同一个 key;需要暂时离开可见流时使用 `visibility: 'hidden'`,不要改为返回 `null` 撤回它。
|
|
203
227
|
|
|
204
|
-
##
|
|
228
|
+
## Predecessor read
|
|
205
229
|
|
|
206
230
|
有些 Definition 需要另一个业务 kind 在当前位置之前的最新 State。`start` 会收到 `ConversationContextReader`;应在这里调用 `reader.previous<State>(kind)`,不要接收 Context 集合或扫描事件。Reader 返回当前 start `seq` 之前最近一个已启动 Context 的只读数据。
|
|
207
231
|
|
|
208
232
|
Assembler 会记录这项依赖。如果后续 older prepend 带来了更近的前序 Context、补齐了原先未知的窗口缺口,或者前序 State 被修订,引擎会从 `start` 重新运行依赖方 Context,并按 `seq` 升序回放其 update。被查询的 Definition 仍负责把有用信息写入自身 State;Reader 不提供业务专用查询方法,也不授予修改其他 Context 的权限。
|
|
209
233
|
|
|
210
|
-
##
|
|
234
|
+
## Window 更新路径
|
|
211
235
|
|
|
212
|
-
|
|
236
|
+
历史可能从尾部开始一页一页向前请求。Session journal 先校验互不重叠的逻辑 seq range,Assembler 再按每个已接受 input 的首 `seq` 排序并进入 State 回放。
|
|
213
237
|
|
|
214
238
|
| 路径 | 引擎工作 | Definition 可观察到的行为 |
|
|
215
239
|
|---|---|---|
|
|
216
|
-
| open、resync 或 gap repair 时 replace |
|
|
217
|
-
| prepend 一页更早历史 |
|
|
218
|
-
| append 一条实时事件 | 每个 Definition 各调用一次 `match`,按 key 查找命中的 Context,只更新该 Context | 对 start 之后的匹配事件执行一次 `update` 并请求一次发布;不扫描已有 Context |
|
|
240
|
+
| open、resync 或 gap repair 时 replace | 重建已加载窗口,每条标准 event 或 packed run 对每个 Definition 匹配一次,再回放每个已有 start 的 Context | 先执行 `start`,再按逻辑 `seq` 升序执行其 update;只有 update 的 pending Context 仍没有 State |
|
|
241
|
+
| prepend 一页更早历史 | 只匹配新增的更早 input,按 `(kind, id)` 合并进 Context,保留现有 keyed node,并只重放受影响的 Context 与依赖 | 新发现的 scalar start 会激活已收集的 scalar 与 packed update;Location 或前序依赖变化也可能重跑 Context |
|
|
242
|
+
| append 一条实时事件 | 每个 Definition 各调用一次 `match`,按 key 查找命中的 Context,只更新该 Context | 对 start 之后的匹配事件执行一次 scalar `update` 并请求一次发布;不扫描已有 Context |
|
|
219
243
|
|
|
220
|
-
注册 `D` 个 Definition
|
|
244
|
+
注册 `D` 个 Definition 时,一条新 scalar event 或 packed run 会进行 `D` 次仅当前 input 匹配;命中后的 Context key 查询是常数时间。Definition 代码必须维持这个性质:正常 append 热路径不得遍历完整事件窗口、所有 Context、`context.matches` 或已渲染 Node 集合。累计事实放进 State,同 Turn/Step 共享信息放进 Location data,有索引的前序依赖使用 `reader.previous()`。
|
|
221
245
|
|
|
222
|
-
`publication` 控制发生 State 变更后何时物化。结构或 terminal 变化使用 `immediate`,高频可见 delta 使用 `animation-frame`,只为后续发布积累 State 时使用 `none
|
|
246
|
+
`publication` 控制发生 State 变更后何时物化。结构或 terminal 变化使用 `immediate`,高频可见 delta 使用 `animation-frame`,只为后续发布积累 State 时使用 `none`。引擎按日志顺序应用每条 scalar update,并用一次 batch update 应用一个 packed run;该选项只合并视图发布频率。
|
|
223
247
|
|
|
224
|
-
##
|
|
248
|
+
## 验证要求
|
|
225
249
|
|
|
226
250
|
添加聚焦测试,证明以下结果:
|
|
227
251
|
|
|
@@ -231,5 +255,7 @@ Assembler 会记录这项依赖。如果后续 older prepend 带来了更近的
|
|
|
231
255
|
4. prepend 更早分页只增加更早的行;数据未变化的既有 keyed Node value 不被替换。
|
|
232
256
|
5. 重复的可见 delta 保持 `context.key`,并在请求 `animation-frame` 时每帧最多发布一次。
|
|
233
257
|
6. keyed renderer 只消费 `node.data` 与受限 Location hook,不扫描 Session 事件窗口、Context 或 Chat Node。
|
|
258
|
+
7. scalar 与 packed Assistant 历史产生相同的最终 State、timing boundary 和 target snapshot;一个 packed run 在 replace、prepend、Location replay 与 registry rebuild 中始终只保留一个 Match。
|
|
259
|
+
8. 创建 target source 不执行 builder 工作;显式选择或首次订阅执行一次完整 replace,后续更新送达所有 active target,重复激活不会再次 replace。
|
|
234
260
|
|
|
235
|
-
流式与中断处理可参考 [`packages/client/ui-
|
|
261
|
+
流式与中断处理可参考 [`packages/client/ui-chat/src/client/conversation-nodes/assistant.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/src/client/conversation-nodes/assistant.ts),前序查询可参考 [`inbox.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/src/client/conversation-nodes/inbox.ts) 与 [`message.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/src/client/conversation-nodes/message.ts),只发布 Turn data 而不创建自有 Node 的例子见 [`packages/client/ui-deliverables`](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-deliverables)。
|