dsh-plugin-dev-kb 1.0.7 → 1.0.9
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 +16 -0
- package/README.en.md +144 -0
- package/README.md +21 -7
- package/kb/INDEX.md +19 -5
- package/kb/README.md +11 -10
- package/kb/extra/AGENTS.md +4 -4
- 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 +159 -0
- package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +159 -0
- package/kb/extra/development.md +8 -14
- package/kb/extra/development.zh.md +8 -14
- package/kb/extra/event-producer-consumer.md +47 -41
- package/kb/extra/event-producer-consumer.zh.md +47 -41
- 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/module-graph.md +680 -413
- package/kb/extra/module-graph.zh.md +681 -414
- 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 +24 -1
- package/kb/extra/subsystems/agent-team.zh.md +24 -1
- package/kb/extra/subsystems/attachment.md +12 -4
- package/kb/extra/subsystems/attachment.zh.md +12 -4
- package/kb/extra/subsystems/extensions.md +18 -0
- package/kb/extra/subsystems/extensions.zh.md +18 -0
- package/kb/extra/subsystems/feedback.md +2 -2
- package/kb/extra/subsystems/feedback.zh.md +2 -2
- 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 +11 -10
- package/kb/extra/testing.zh.md +8 -7
- package/kb/meta/search-index.json +269 -161
- package/kb/meta/site-pages.txt +182 -168
- 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 +4 -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 +3 -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 +4 -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 +3 -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/python-sdk.md +80 -34
- package/kb/site/en/guide/schedule.md +21 -0
- package/kb/site/en/reference/agent-lifecycle.md +1 -1
- package/kb/{extra → site/en/reference}/api-gateway.md +11 -9
- package/kb/site/en/reference/capability-seams.md +115 -67
- package/kb/site/en/reference/config-catalog.md +358 -164
- package/kb/site/en/reference/cookbook/adding-a-package.md +2 -2
- package/kb/site/en/reference/cookbook/adding-a-settings-card.md +2 -2
- 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 +6 -6
- 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 +19 -7
- package/kb/site/en/reference/persistence-catalog.md +91 -44
- 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 +3 -3
- package/kb/site/en/reference/subsystems/compaction.md +2 -2
- package/kb/site/en/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +43 -24
- package/kb/site/en/reference/subsystems/core.md +70 -12
- package/kb/site/en/reference/subsystems/credentials.md +43 -3
- package/kb/site/en/reference/subsystems/filesystem.md +12 -2
- package/kb/site/en/reference/subsystems/index.md +6 -1
- package/kb/site/en/reference/subsystems/jobs.md +1 -1
- package/kb/site/en/reference/subsystems/llm-streaming.md +132 -11
- package/kb/site/en/reference/subsystems/permission-presets.md +1 -1
- package/kb/site/en/reference/subsystems/persistence.md +22 -3
- package/kb/site/en/reference/subsystems/plan.md +1 -1
- package/kb/site/en/reference/subsystems/session-projection.md +74 -33
- package/kb/site/en/reference/subsystems/session-query.md +9 -1
- package/kb/site/en/reference/subsystems/session-reference.md +28 -7
- package/kb/site/en/reference/subsystems/session-telemetry.md +2 -3
- package/kb/site/en/reference/subsystems/session.md +260 -41
- package/kb/site/en/reference/subsystems/settings.md +78 -1
- package/kb/site/en/reference/subsystems/skills.md +23 -0
- package/kb/site/en/reference/subsystems/slots.md +177 -0
- package/kb/site/en/reference/subsystems/spill.md +2 -2
- package/kb/site/en/reference/subsystems/storage.md +9 -1
- package/kb/site/en/reference/subsystems/subagent.md +90 -23
- package/kb/site/en/reference/subsystems/system-prompt.md +4 -4
- package/kb/site/en/reference/subsystems/token-meter.md +25 -10
- package/kb/site/en/reference/subsystems/tools.md +39 -39
- package/kb/site/en/reference/subsystems/typert.md +44 -37
- 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 +95 -2
- package/kb/site/en/reference/tool-catalog.md +76 -18
- 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/python-sdk.md +87 -41
- package/kb/site/guide/schedule.md +21 -0
- package/kb/site/reference/agent-lifecycle.md +1 -1
- package/kb/{extra/api-gateway.zh.md → site/reference/api-gateway.md} +11 -9
- package/kb/site/reference/capability-seams.md +115 -67
- package/kb/site/reference/config-catalog.md +357 -163
- package/kb/site/reference/cookbook/adding-a-package.md +2 -2
- package/kb/site/reference/cookbook/adding-a-settings-card.md +2 -2
- 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 +6 -6
- 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 +19 -7
- package/kb/site/reference/persistence-catalog.md +87 -40
- 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 +3 -3
- package/kb/site/reference/subsystems/compaction.md +2 -2
- package/kb/site/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +43 -24
- package/kb/site/reference/subsystems/core.md +70 -12
- package/kb/site/reference/subsystems/credentials.md +43 -3
- package/kb/site/reference/subsystems/filesystem.md +12 -2
- package/kb/site/reference/subsystems/index.md +6 -1
- package/kb/site/reference/subsystems/jobs.md +1 -1
- package/kb/site/reference/subsystems/llm-streaming.md +132 -11
- package/kb/site/reference/subsystems/persistence.md +22 -3
- package/kb/site/reference/subsystems/plan.md +1 -1
- package/kb/site/reference/subsystems/session-projection.md +74 -33
- package/kb/site/reference/subsystems/session-query.md +9 -1
- package/kb/site/reference/subsystems/session-reference.md +28 -7
- package/kb/site/reference/subsystems/session-telemetry.md +2 -3
- package/kb/site/reference/subsystems/session.md +260 -41
- package/kb/site/reference/subsystems/settings.md +78 -1
- package/kb/site/reference/subsystems/skills.md +23 -0
- package/kb/site/reference/subsystems/slots.md +177 -0
- package/kb/site/reference/subsystems/spill.md +2 -2
- package/kb/site/reference/subsystems/storage.md +9 -1
- package/kb/site/reference/subsystems/subagent.md +90 -23
- package/kb/site/reference/subsystems/system-prompt.md +4 -4
- package/kb/site/reference/subsystems/token-meter.md +25 -10
- package/kb/site/reference/subsystems/tools.md +39 -39
- package/kb/site/reference/subsystems/typert.md +44 -37
- 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 +95 -2
- package/kb/site/reference/tool-catalog.md +76 -18
- package/kb/site/reference/tool-execution-pipeline.md +1 -1
- package/package.json +11 -3
- package/skills/dsh-plugin-dev-kb.md +8 -6
|
@@ -22,7 +22,7 @@ packages/<group>/<pkg>/
|
|
|
22
22
|
# (or a whitelist entry in scripts/verify-package-readme-limitations.ts)
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
当已有分组与包的角色匹配时,选择该分组(`core`、`llm`、`
|
|
25
|
+
当已有分组与包的角色匹配时,选择该分组(`core`、`llm`、`shell`、`compaction`、`subagent`、`todo`、`session`、`client`/`host`、`util` 或 `test-support`)。允许新建分组,但分组只是纯容器:没有 `package.json`,没有源文件,包仍然恰好位于其下一层。
|
|
26
26
|
|
|
27
27
|
package.json 不变式(由 `pnpm run constraints` / `scripts/check-workspace-constraints.ts` 强制执行):`private: true`,`version` 与根 `package.json` 一致,`type: module`,`main: "lib/index.js"`,`types: "lib/types/index.d.ts"`,`exports["."].types: "./lib/types/index.d.ts"`,`exports["."].default: "./lib/index.js"`,`@deepseek-ai/cordis` 同时出现在 peerDependencies 和 devDependencies 中(相同范围)。每个 dsh 对等依赖(peer dependency)都要在 devDependencies 中镜像。`@deepseek-ai/schemastery` 放在 `dependencies` 中(它是运行时校验器),与 agent-loop 保持一致。`files` 列表精确包含 `lib/index.js`、`lib/invariant.js`、`lib/types/**/*.d.ts` 以及门禁认可的包专用运行时产物;如果包的运行时 export 指向输出树,还要包含 `lib/types/**/*.js`。不要发布 `src`、声明映射、JS map 或陈旧的根声明文件。带有 `bin` 的 CLI 应用包在 `files` 中将 `lib/bin.js` 紧跟在 `lib/index.js` 之后。
|
|
28
28
|
|
|
@@ -76,7 +76,7 @@ package.json 不变式(由 `pnpm run constraints` / `scripts/check-workspace-c
|
|
|
76
76
|
|
|
77
77
|
## 4. 编写包 README
|
|
78
78
|
|
|
79
|
-
将包特有的服务 API
|
|
79
|
+
将包特有的服务 API、配置、事件、扩展点和设计说明放在前面。根据 [dsh-doc 元数据参考](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/skills/dsh-doc/references/metadata-links-i18n.md#the-kind-system)中的四种 kind 标签——组、参考、库或 bundle——选择 frontmatter 的 `kind`,使其匹配包在仓库中的位置与入口形态;每个 kind 恰好对应一个 README 模板。limitations 部分记录持久的消费方缺口和本包拥有的非显而易见的维护者约束;日常清理事项留在源码 TODO 或 Agent Note 中。间接的 Model Experience 语句可以点名暴露本包贡献的消费方,但不重述该消费方的实现。包 README 以如下规范序列结尾:
|
|
80
80
|
|
|
81
81
|
````markdown
|
|
82
82
|
## Model Experience
|
|
@@ -50,7 +50,7 @@ export function apply(ctx: Context, config: Config) {
|
|
|
50
50
|
卡片以自己的命名空间为键注册进 `settings.plugin.item`,并拥有其中的一切——外观、控件与文案。它通过 `ctx.settingsScope` 读写,后者用读取时的 revision 为每次写入设栅:
|
|
51
51
|
|
|
52
52
|
```ts ignore-check
|
|
53
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
53
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
54
54
|
// Type-only: the keyed slot's declaration. Cross-plugin collaboration goes
|
|
55
55
|
// through cordis services; a value import fails the client bundle-purity gate.
|
|
56
56
|
import type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'
|
|
@@ -99,4 +99,4 @@ import { clientBundle } from '../tsdown.client.ts'
|
|
|
99
99
|
export default clientBundle('@deepseek-ai/dsh-client-my-plugin', ['lib/types/index.js', 'lib/types/invariant.js'])
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
没有已发布的预设暴露该包,因此本仓库之外的包得自行复刻同样的输出格式。bundle 纯净度门禁同时拒绝跨插件的值导入,所以卡片无法导入本分区的卡片外观或其暂存表单模型——它渲染自己的那一份,并自行拥有暂存与 revision 设栅。这两条限制都记在[本分区的已知限制](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-settings-plugins/README.zh.md#known-limitations-and-deferred-work)里。
|
|
@@ -52,7 +52,7 @@ export function apply(ctx: Context) {
|
|
|
52
52
|
|
|
53
53
|
## 长时间运行的工作
|
|
54
54
|
|
|
55
|
-
通过 producer 配置控制 `run_in_background`,然后使用 `ctx.jobs.start({ kind, label, owner: exec.agent, run })` 注册任务。注册表会在进入 producer 主体前将已预先中止的调用判为失败;运行时会在 `run()` 启动工作前校验 owner 和任务控制器是否可用,随后提供 id、会话围栏、通用控制工具、通知和 owner cleanup。成功的后台分支会返回类型化的规范句柄,如 `{ kind: 'background', jobId }`;其 Native 渲染器可以保留 `started background job bash-1` 这类供人阅读的自然语言,但
|
|
55
|
+
通过 producer 配置控制 `run_in_background`,然后使用 `ctx.jobs.start({ kind, label, owner: exec.agent, run })` 注册任务。注册表会在进入 producer 主体前将已预先中止的调用判为失败;运行时会在 `run()` 启动工作前校验 owner 和任务控制器是否可用,随后提供 id、会话围栏、通用控制工具、通知和 owner cleanup。成功的后台分支会返回类型化的规范句柄,如 `{ kind: 'background', jobId }`;其 Native 渲染器可以保留 `started background job bash-1` 这类供人阅读的自然语言,但 PTC mode 绝不能通过解析该文本取得 id。
|
|
56
56
|
|
|
57
57
|
producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的 `done`,以及可选的消费式 `readOutput`(负责有界输出的格式化)。预先中止的调用属于失败,因为此时没有任务,其 id 无法满足成功输出 schema。`ctx.jobs.start()` 发布 id 后,应使用任务自有的取消信号,而不是 `exec.signal`:之后取消外层调用只会停止等待本次调用,不会终止已经发布的工作;该生命周期归 `job_kill`、owner dispose 和服务 teardown 所有。前台工作仍与 `exec.signal` 耦合。流式 producer 的示例和完整约定见[后台任务运行时 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.zh.md)与 `dsh-tool-bash`。
|
|
58
58
|
|
|
@@ -62,9 +62,9 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的
|
|
|
62
62
|
|
|
63
63
|
尽量不要把部署策略内建到工具中。使用 `tools/pre-execute` 实现可扩展的允许/拒绝/询问策略(见[权限门禁示例](./extension-cookbook.md#a-hook-plugin-permission-gate-example));使用 `ctx.tools.guard()` 设置最终的单调拒绝,后续监听器无法撤销;使用 `tools/execute` 为分发添加截止时间、重试或指标收集;使用 `tools/post-execute` 替换展示内容或返回值、阻止结果,或附加模型可见上下文;使用 `tools/result` 观测不可变的归一化结果而不改变它。替换内容不会阻止程序化访问 `value`;保密策略会屏蔽或替换该值。沙箱实现也可以在工具的执行器实现中运行;[`dsh-tools` README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/README.zh.md#extension-points) 定义每个扩展点的输入、顺序、返回值和失败行为。
|
|
64
64
|
|
|
65
|
-
##
|
|
65
|
+
## PTC mode 自动触达你的工具
|
|
66
66
|
|
|
67
|
-
在 [
|
|
67
|
+
在 [PTC mode](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/README.zh.md) 中,每个可见的已注册工具都可通过 `await tools.<name>(args)` 调用,无需额外集成。生成的 `ToolArgsMap` 和 `ToolOutputMap` 会根据同一组 schema 分别派生精确的参数类型与规范返回类型,调用则重新进入正常的执行流水线。成功调用会解析为策略处理后的最终规范 JSON 值,而不是渲染后的 Native 内容。失败调用会以真正的 `ToolCallError` reject;程序只能检查其 `name`、`toolName` 和可供人阅读的 `message`,无法取得内部错误代码或失败联合。
|
|
68
68
|
|
|
69
69
|
请把 `output.schema` 设计为实用的程序化 API:直接返回句柄与字段;当标量、数组或 null 确实就是结果时,允许采用相应的根类型;将面向人类的解释放入 `output.render`。中间值只存在于执行期间,不会被持久化或按提示词上限截断,也不设字节上限,因此生产方如实声明的采集边界和进程内存仍然重要。只有外层 `run_code` 日志/结果会受到可配置输出上限和面向模型的 spill 流水线约束。
|
|
70
70
|
|
|
@@ -82,6 +82,7 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的
|
|
|
82
82
|
- `generic` 提供可选的标题和内容。
|
|
83
83
|
- `terminal` 提供原始输出和可选的退出元数据;各 UI 根据自身能力渲染对应视图或回退视图。
|
|
84
84
|
- `diff` 提供已应用的 hunk,通常由 `output.presentationMeta` 派生并通过持久化的 `result.meta` 携带,使回放能重现它们。变更类工具保留 diff 结果,因为完成后的视图会替换 pending 卡片。
|
|
85
|
+
- `read` 提供从持久化 `result.meta` 重建的已完成文件窗口:文件 `path`、从 1 开始的 `offset`、返回的 `lines`(每行保留其文件行号)、`totalLines`,以及可选的 `lang` 高亮提示;不具备 `read` 能力的 UI 回退到原始结果内容。没有 `read` 调用视图——读取调用的 pending 状态保持为 generic 卡片,因为内容只在 `execute` 之后才存在。(tool-fs `read`。)
|
|
85
86
|
- `search` 提供从持久化 `result.meta` 重建的发现型结果:按文件分组的匹配(`shape: 'matches'`,grep)或扁平路径列表(`shape: 'paths'`,glob),外加 `truncated`/`total` 使 UI 永不把被截断的结果当作完整结果呈现。该视图不携带结果文本(无 search 卡片的 UI 回退到原始结果内容),也没有 `search` 调用视图——发现型调用的 pending 状态保持为 generic 卡片,因为匹配只在 `execute` 之后才存在。(tool-fs-search 的 `grep`/`glob`。)
|
|
86
87
|
- `web` 提供已完成的 web 检索,以 `kind: 'search' | 'fetch'` 区分(结构化的搜索来源或抓取摘要),由 `result.meta` 派生;它不携带正文副本,因此不具备 `web` 能力的 UI 回退到原始结果内容。(tool-web `web_search`/`web_fetch`。)
|
|
87
88
|
|
|
@@ -91,7 +92,13 @@ producer 提供同步的 `cancel`、在资源清理后 settle 且不 reject 的
|
|
|
91
92
|
- **UI 格式不进入模型结果。** 围栏 ` ```console ` 块、diff、相对化路径均不应仅为服务 UI 而进入规范值或 Native 内容。`output.render` 负责模型可见的自然语言;`presentationMeta` 和卡片展示器负责可回放的 UI 状态。`terminal` 结果视图携带原始输出,由适配器按需添加回退格式。
|
|
92
93
|
- **`defineTool` 对展示路径做软校验。** 格式错误或旧版日志中的参数会使包装器返回 `undefined`(通用回退)而非抛异常——展示绝不能导致回放崩溃。
|
|
93
94
|
|
|
94
|
-
中性词汇定义在 `dsh-tools` 中;工具绝不导入 UI
|
|
95
|
+
中性词汇定义在 `dsh-tools` 中;工具绝不导入 UI 或传输类型。使用该 API 的消费方把每个 `card` 映射到自己的视图。设计与原因见[渲染意图联合体 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.zh.md);`dsh-tool-fs`(generic/diff)和 `dsh-tool-bash`(terminal)是参考实现。
|
|
96
|
+
|
|
97
|
+
## Web Client 展示
|
|
98
|
+
|
|
99
|
+
内置 Web Client 不消费 `presentCall` 或 `presentResult`。Session `page` 与 `follow` 运输原始 `tool/call` 和 `tool/result` 事件,包括持久化的 `result.meta`。Client 插件在 keyed slot `tool.call.toolview` 中注册自己的 wire 工具名称,并从 `ToolCallBlock` 的参数、内容、错误、metadata、现有 Code Dispatch `parentCallId` 与 Session 路径事实派生组件 props。插件在本地校验这些 wire 值,并让格式错误或不受支持的输入回退到 generic 行。
|
|
100
|
+
|
|
101
|
+
现有 Web 卡片需要模型可见内容无法无损保存的有界结构化结果事实时,使用 `output.presentationMeta(args, value)`。不要在 metadata 中保存 React props 或预选卡片,不要把 Host 工具实现导入浏览器 bundle,也不要建立另一套 Client presenter registry。只定义 Host 展示方法不会增加专用 Web 卡片。[Client 派生展示 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-23-client-derived-tool-presentation.zh.md)规定 owner、fallback 与对等要求。
|
|
95
102
|
|
|
96
103
|
## 验证
|
|
97
104
|
|
|
@@ -31,7 +31,7 @@ export function apply(ctx: Context, config: Config) {
|
|
|
31
31
|
- 按首次出现的流顺序分配块 `index`;同一个块的每次 delta 复用该 index。
|
|
32
32
|
- 错误有且仅有两条合法路径:从 `stream()` **抛出**(传输与协议故障——使用带稳定 code 的 `LlmError`),或以 `finish {kind: 'error' | 'aborted'}` 结束流(提供方带内故障)。消费方两者都处理;按故障类别选择路径并加以文档化。
|
|
33
33
|
- 遵守 `options.signal`(将其传递给 fetch 或你的 SDK)。
|
|
34
|
-
- 如果 `GenerateOptions` 中某个字段你的提供方无法支持(例如提供方不支持 stop sequences 时收到 `stop` 列表):抛出 `LlmError(..., '
|
|
34
|
+
- 如果 `GenerateOptions` 中某个字段你的提供方无法支持(例如提供方不支持 stop sequences 时收到 `stop` 列表):抛出 `LlmError(..., 'UNSUPPORTED_OPTION')`,而非静默丢弃。
|
|
35
35
|
- 如果提供方在后续调用中需要响应 ID、签名或其他原生元数据,请将其最小无损 JSON 投影作为 `finish.replayState` 发出。重建历史时验证该状态。只有历史提供方路由和目标提供方路由当前由完全相同的适配器实例拥有时,`LlmRuntime` 才会传递该状态;由适配器决定同模型、跨模型或跨提供方恢复是否合法。状态缺失时,切勿仅根据提供方/模型名称推断原生回放。
|
|
36
36
|
|
|
37
37
|
提供方特有的思考模式开关仍放在适配器的 Config 中。确切模型元数据使用一处提供方无关的能力 seam:实现 `resolveModel()`,返回提供方/模型身份以及可选的 `context` 和 `reasoning` 字段;仅当存在配置指定的默认值时才声明 `defaultEffort`;遵守解析模型时传入的可选 `AbortSignal`。推理(reasoning)强度是由适配器映射到提供方请求的有序不透明 ID。请保留适配器给出的权威可选列表,包括适配器在支持时定义的 `off`;不得暴露最终协议值的具体拼写,也不得自动调整不支持的值。ID 无需与其协议表示相同。
|
|
@@ -34,11 +34,11 @@ export function apply(ctx: Context) {
|
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
这个 waterfall(瀑布式事件)是可重排的策略层。当不变式需要单调的最终拒绝时使用 `ctx.tools.guard()
|
|
37
|
+
这个 waterfall(瀑布式事件)是可重排的策略层。当不变式需要单调的最终拒绝时使用 `ctx.tools.guard()`;当插件需要包裹分发生命周期时(超时/重试/指标;仅 `exec.signal` 可替换)使用 `tools/execute`;显式结果变换使用 `tools/post-execute`;对不可变最终结果的受限观察使用 `tools/result`。选择规则见[添加工具指南](./adding-a-tool.md#execution-policy-and-observation)。
|
|
38
38
|
|
|
39
39
|
## UI 插件
|
|
40
40
|
|
|
41
|
-
UI 插件从 `session/event` 事件流渲染(助手 token 流以 `assistant/chunk` 形式到达,加上轮次/步骤边界与工具活动),并通过 `agent.followup()` / `agent.steer()` 将输入驱动回去。如果浏览器插件要向内建 Web Client 贡献业务行,则应注册 `ConversationNodeDefinition` 与 keyed Chat renderer
|
|
41
|
+
UI 插件从 `session/event` 事件流渲染(助手 token 流以 `assistant/chunk` 形式到达,加上轮次/步骤边界与工具活动),并通过 `agent.followup()` / `agent.steer()` 将输入驱动回去。如果浏览器插件要向内建 Web Client 贡献业务行,则应注册 `ConversationNodeDefinition` 与 keyed Chat renderer;具体约定见 [Conversation 子系统参考](../subsystems/conversation.md)。
|
|
42
42
|
|
|
43
43
|
```ts
|
|
44
44
|
import type { Context } from '@deepseek-ai/cordis'
|
|
@@ -94,7 +94,7 @@ export function apply(ctx: Context) {
|
|
|
94
94
|
|
|
95
95
|
## 可运行的组装示例
|
|
96
96
|
|
|
97
|
-
|
|
97
|
+
交付应用通过 `packages/bundle/*/cordis.patch.yml` 提供 profile 层,产品 `dsh` 启动器通过具名 profile 负责 Web、ACP、SDK 与一次性 headless 执行。可选的用户 overlay 位于 `apps/cli/config/examples/`;profile 集成测试位于 `apps/cli/tests/profiles/`,包专属 Loader 组合则留在对应包的测试目录中。
|
|
98
98
|
|
|
99
99
|
<a id="the-feature--mechanism-map"></a>
|
|
100
100
|
|
|
@@ -102,7 +102,7 @@ export function apply(ctx: Context) {
|
|
|
102
102
|
|
|
103
103
|
每个产品功能都映射到一个文档化扩展点上的监听器——微内核声明由此可验证([微内核 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.zh.md))。没有任何一行修改循环本身。
|
|
104
104
|
|
|
105
|
-
`system-prompt/assemble` 是一个专家协作式的整体装配变换:其返回的装配结果具有权威性,因此监听器作者有责任保留活跃的
|
|
105
|
+
`system-prompt/assemble` 是一个专家协作式的整体装配变换:其返回的装配结果具有权威性,因此监听器作者有责任保留活跃的 PTC mode 和结构化输出协议的贡献。对于需要在展示、查找和执行之间保持对齐的工具过滤,优先使用 `ctx.tools.restrict()`。
|
|
106
106
|
|
|
107
107
|
| 产品功能 | 插件机制 |
|
|
108
108
|
|---|---|
|
|
@@ -123,11 +123,11 @@ export function apply(ctx: Context) {
|
|
|
123
123
|
| 子进程沙箱(landlock / sandbox-exec) | 通过 `dsh-bash-sandbox` 使用 `ctx.sandbox` 后端;能力级别的拒绝使用 `tools/pre-execute` |
|
|
124
124
|
| 权限系统 / AskUserQuestion | 从 `tools/pre-execute` 返回 `ask` 并通过 `ctx.approval` 应答;为普通用户提问注册一个独立的面向模型的 ask 工具 |
|
|
125
125
|
| Plan mode | [`@deepseek-ai/dsh-plan-mode`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/README.zh.md):落日志的 `plan/mode` 状态、`plan:policy` 引导段、`/plan [message]` 入口、`/plan off` 直接退出,以及经用户评审的 `exit_plan_mode` 出口;强制约束留在独立的沙箱/审批轴上 |
|
|
126
|
-
| subagent 委派 | `ctx.subagents` 提供方注册表(`dsh-subagent-spawn-in-process
|
|
126
|
+
| subagent 委派 | `ctx.subagents` 提供方注册表(`dsh-subagent-spawn-in-process`/`dsh-subagent-fork-in-process`/`dsh-subagent-acp`/`dsh-subagent-codex`/`dsh-subagent-claude-code`/`dsh-subagent-dsh-sdk`)+ `dsh-tool-subagent` 向模型暴露一个已配置的提供方 |
|
|
127
127
|
| MCP | 每个服务器一个插件:发现工具 → `ctx.tools.register()` |
|
|
128
128
|
| skill(技能) | section + 工具注册;调用时通过 `inject()` 注入 skill 内容 |
|
|
129
129
|
| 记忆 | section 提供方 + 工具 |
|
|
130
|
-
| 定时任务(cron) | 插件注册面向模型的调度工具;定时器触发 → 空闲时 `followup(…, {source: {kind: '
|
|
130
|
+
| 定时任务(cron) | 插件注册面向模型的调度工具;定时器触发 → 空闲时 `followup(…, {source: {kind: 'plugin', plugin: 'schedule'}})`/忙碌时 `inject()` 通知 |
|
|
131
131
|
| UI(GUI;CLI(命令行界面)输出 JSONL) | 监听 `session/event`(助手分片、边界、工具活动);输入 → `followup()` |
|
|
132
132
|
| Web Client Chat 业务节点 | 注册 `ConversationNodeDefinition` 与 `conversation.chat.node` keyed renderer |
|
|
133
133
|
| 遥测 / 可回放 trace | `session/event` → JSONL;回放 = `sessions.create(id, { seed })` |
|
|
@@ -19,7 +19,7 @@ This file is GENERATED from source (`scripts/gen-cordis-catalog.ts`) and verifie
|
|
|
19
19
|
- `ctx.effect` — Register a disposable side effect tied to the fiber. ([`vendor/cordis/src/fiber.ts:9`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/fiber.ts))
|
|
20
20
|
- `ctx.get / ctx.set / ctx.provide / ctx.accessor / ctx.mixin` — Low-level service-store access and binding. ([`vendor/cordis/src/reflect.ts:7`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/reflect.ts))
|
|
21
21
|
- `ctx.extend / ctx.isolate / ctx.intercept` — Derive a child context (scoped services / isolation / interception). ([`vendor/cordis/src/context.ts:42`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/context.ts))
|
|
22
|
-
- `ctx.root / ctx.
|
|
22
|
+
- `ctx.root / ctx.fiber / ctx.registry / ctx.reflect / ctx.events / ctx.logger` — Ambient handles onto the running context graph. ([`vendor/cordis/src/context.ts:16`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/context.ts))
|
|
23
23
|
- `ctx.timer (+ interval / timeout / throttle / debounce)` — Disposable timer helpers. The `timer` key is provided at runtime; the four supported helpers are mixed onto ctx directly (declared via Pick). ([`vendor/timer/src/index.ts:4`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/timer/src/index.ts))
|
|
24
24
|
- `ctx.loader` — The config Loader that booted the app (present under the loader). ([`vendor/loader/src/index.ts:30`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/loader/src/index.ts))
|
|
25
25
|
- `ctx.hmr` — The hot-module-reload watcher (present under the hmr plugin). ([`vendor/hmr/src/index.ts:15`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/hmr/src/index.ts))
|
|
@@ -11,7 +11,7 @@ Cordis 是 DeepSeek Harness 底层以 vendor 方式引入的插件框架。本
|
|
|
11
11
|
- **插件是实现 Service 的对象。** 它可以是一个带有可选 `inject` 和 `apply(ctx)` 字段的函数,也可以是一个 `Service` 子类,其生命周期由 Cordis 挂载到当前上下文中。
|
|
12
12
|
- **上下文是服务的容器。** 一个服务占据一个稳定的 `ctx.<key>`(如 `ctx.tools`、`ctx.llm`、`ctx.sessions`);其他插件通过 key 查找服务,而非导入具体实现。
|
|
13
13
|
- **通过 `inject` 声明服务依赖。** 插件声明所需的服务后,会等待这些服务就绪才启动;加载顺序通过服务依赖表达,而非手动编排启动序列。
|
|
14
|
-
- **类型化事件用于通信。** 服务通过 TypeScript 声明合并注册事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel` 或 `
|
|
14
|
+
- **类型化事件用于通信。** 服务通过 TypeScript 声明合并注册事件名,然后以 `emit`、`waterfall`(瀑布式事件)、`parallel`、`serial` 或 `bail` 方式分发,分别对应监听者观察、包装、并行扇出、按序执行或停在首个 bail 值。
|
|
15
15
|
- **注册是可逆的副作用。** 提示词片段、工具 schema、适配器、提供方和监听器通过 `ctx.effect()` 或 `ctx.on()` 安装,reload 和 teardown 时会按预期撤销。
|
|
16
16
|
|
|
17
17
|
<a id="dispatch-modes"></a>
|
|
@@ -26,6 +26,7 @@ Cordis 是 DeepSeek Harness 底层以 vendor 方式引入的插件框架。本
|
|
|
26
26
|
| `waterfall` | 否 | 监听器按注册顺序观察 | 是 |
|
|
27
27
|
| `parallel` | 是 | 所有监听器并行观察事件 | 否 |
|
|
28
28
|
| `serial` | 是 | 监听器按注册顺序观察 | 是 |
|
|
29
|
+
| `bail` | 否 | 监听器按注册顺序观察,直到某个监听器返回 bail 值 | 是 |
|
|
29
30
|
|
|
30
31
|
分发模式是事件公开约定的一部分。新的 harness 事件通过 `@mode` 标签记录模式,以便生成的目录可以将声明与分发调用点做交叉校验。
|
|
31
32
|
|
|
@@ -10,7 +10,7 @@ editSource: "docs/architecture.zh.md"
|
|
|
10
10
|
|
|
11
11
|
## Cordis
|
|
12
12
|
|
|
13
|
-
[Cordis](./cordis-primer.md) 是 dsh 底层的框架:插件向共享上下文贡献服务、类型化事件和可逆的副作用。产品的每一部分都是插件,包括模型适配器、工具注册表、会话日志,以及 agent loop
|
|
13
|
+
[Cordis](./cordis-primer.md) 是 dsh 底层的框架:插件向共享上下文贡献服务、类型化事件和可逆的副作用。产品的每一部分都是插件,包括模型适配器、工具注册表、会话日志,以及 agent loop(智能体循环)本身,因此每个都可以从配置替换。
|
|
14
14
|
|
|
15
15
|
不存在需要打补丁的特权内核:扩展 dsh 的方式是把插件挂载到其他插件旁边,而各项注册都是副作用,会在其插件卸载时撤销。
|
|
16
16
|
|
|
@@ -18,17 +18,19 @@ editSource: "docs/architecture.zh.md"
|
|
|
18
18
|
|
|
19
19
|
运行中的 `dsh` 是一棵插件树,由启动时按序叠加的各层组合而成。
|
|
20
20
|
|
|
21
|
-
**profile** 是存放在 Harness home 中的具名组装。它列出自己叠放的组合包,存放自己安装的树外插件,并保存用户自己的 `cordis.patch.yml`。`web` 和 `
|
|
21
|
+
**profile** 是存放在 Harness home 中的具名组装。它列出自己叠放的组合包,存放自己安装的树外插件,并保存用户自己的 `cordis.patch.yml`。`web`、`headless`、`sdk`、`sdk-minimal` 和 `acp` 作为模板随发行版交付。
|
|
22
22
|
|
|
23
23
|
**组合包**是 Cordis 配置项及其挂载代码的分发格式,因此它插入的内容始终可被其上各层 patch。
|
|
24
24
|
|
|
25
25
|
两者都在各自的 `package.json` 中通过 `dsh` 字段声明自己:`dsh.profile` 列出一个 profile 的组合包,`dsh.bundle` 指向一个组合包的 patch 文件。
|
|
26
26
|
|
|
27
|
-
[`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.zh.md)
|
|
27
|
+
[`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.zh.md) 是 `web`、`headless`、`sdk` 与 `acp` profile 的共享第一层:模型适配器、工具、持久化、沙箱与审批策略、设置、凭据、遥测。[`dsh-web-app`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/web-app/README.zh.md) 增加浏览器应用,[`dsh-headless`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/headless/README.zh.md) 增加不带服务器的一次性运行器,[`dsh-sdk-app`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-app/README.zh.md) 增加 SDK JSON-RPC 服务器,[`dsh-acp-app`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/acp-app/README.zh.md) 增加仅用于自动化的 ACP 服务器。[`dsh-sdk-minimal`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-minimal/README.zh.md) 是刻意保留的例外:一个组合包拥有完整的显式 SDK 配置树,不应用 `dsh-base`。
|
|
28
28
|
|
|
29
29
|
各层按此顺序应用在空条目列表之上:先按 profile 列出的顺序应用每个组合包,然后是 profile 的 `cordis.patch.yml`,然后是 home 级的那份,最后是任意 `--patch` overlay。一条 patch 按 id 定位某个条目并替换其整个 config,或插入新条目。
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
自定义 profile 默认实时重载 patch。随附的 `web` profile 使用实时重载;`headless`、`sdk`、`sdk-minimal` 和 `acp` 则只在启动时应用一次所有配置层,因为一次性应用或 stdio 应用拥有工作之后,替换其依赖会破坏该生命周期。
|
|
32
|
+
|
|
33
|
+
要查看你的机器启动的配置树:
|
|
32
34
|
|
|
33
35
|
```sh
|
|
34
36
|
dsh --profile web --dump-config
|
|
@@ -38,6 +40,14 @@ dsh --profile web --dump-config
|
|
|
38
40
|
|
|
39
41
|
组装机制见 [app-boot](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/boot/app-boot/README.zh.md#profiles);配置字段见生成的[配置目录](./config-catalog.md)。
|
|
40
42
|
|
|
43
|
+
## 应用启动
|
|
44
|
+
|
|
45
|
+
所有受支持的 Node 应用都从 `dsh` CLI 与具名 profile 启动。随附应用是 `dsh web`(刻意为 `--profile web` 保留的别名)、`dsh --profile headless`、`dsh --profile sdk`、`dsh --profile sdk-minimal` 与 `dsh --profile acp`。TypeScript SDK 会解析其同版本 `dsh` 依赖并选择 `sdk`;自定义插件组合继续由 profile 与有序 patch 文件表达,而不是另一个可执行文件或内联应用树。`sdk-minimal` 是位于同一 launcher 后的仓库自有独立组合包,而不是由调用方提供的 Cordis 配置树。
|
|
46
|
+
|
|
47
|
+
Vendored CLI、仅用于构建和测试的可执行文件、进程内直接挂载插件以及私有浏览器 WebWorker 预览都不属于 Harness 应用启动器。[`verify-application-entrypoints`](https://github.com/deepseek-ai/deepseek-harness/blob/master/scripts/verify-application-entrypoints.ts)将每个包 bin、可执行源码与根 demo 归入显式类别,并拒绝任何绕过 `dsh` 的 Node 应用路径。
|
|
48
|
+
|
|
49
|
+
Python SDK 遵循相同的应用架构。其运行时 wheel 把普通 `dsh` CLI 打包为 `deepseek-harness-sdk-runtime-<platform>-<arch>`,客户端默认以显式 Harness home 启动 `dsh --profile sdk`。极简示例选择随附的 `sdk-minimal` profile。Python 暴露 profile 选择与有序 patch 文件,而不是完整 Cordis 树;持久外部插件通过 `dsh plugin` 安装。已删除的私有直读配置载体没有兼容 bin 或回退 parser。
|
|
50
|
+
|
|
41
51
|
## 核心包
|
|
42
52
|
|
|
43
53
|
以下是向 Cordis 树贡献内容的部分核心包。
|
|
@@ -51,6 +61,7 @@ dsh --profile web --dump-config
|
|
|
51
61
|
| [`core/agent-loop`](./subsystems/core.md) | 实现该接口的默认驱动器 | `ctx.agentLoop` |
|
|
52
62
|
| [`core/scope`](./subsystems/scope.md) | 按 agent 划分作用域的注册原语 | 库,无 ctx 键 |
|
|
53
63
|
| [`llm/llm`](./subsystems/llm-streaming.md) | 消息与流式词汇表,以及适配器 seam | `ctx.llm` |
|
|
64
|
+
| [`webhook/webhook`](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/webhook.zh.md) | 已认证 delivery 的分派和 Workspace Session 创建 | `ctx.webhookRuntime` |
|
|
54
65
|
|
|
55
66
|
<a id="events"></a>
|
|
56
67
|
|
|
@@ -74,7 +85,7 @@ dsh --profile web --dump-config
|
|
|
74
85
|
turn/start
|
|
75
86
|
claim next-step input plus one queued message
|
|
76
87
|
assemble prompt sections + tool schemas
|
|
77
|
-
-> agent/pre-step reject | enter(messages)
|
|
88
|
+
-> agent/pre-step reject | enter(messages, startsRequestSeries?)
|
|
78
89
|
reject, or a first enter rewritten empty -> close the turn with no step
|
|
79
90
|
step/start
|
|
80
91
|
append entered messages as user/message
|
|
@@ -91,7 +102,7 @@ turn/end
|
|
|
91
102
|
|
|
92
103
|
输入通过同一个 inbox 到达驱动器。有些消息会立即唤醒它;注入的上下文会留在 inbox 中,直到另一条消息将其唤醒。
|
|
93
104
|
|
|
94
|
-
`agent/pre-step`
|
|
105
|
+
`agent/pre-step` 决定模型看到什么。监听器可以改写已领取的消息,也可以直接拒绝它们;首次领取被拒绝或被改写为空时,仍会关闭一个不含步骤的持久轮次,因此日志会记录这次尝试。enter 决策还可以设置 `startsRequestSeries` 来开启独立的模型消息序列:loop 会随之记录一个新的 `request/header`(原因为 `series`,或在封装同时变化时为携带 `startsSeries: true` 的 `change`)。重建下游 enter 决策的监听器必须展开它(`{ ...decision, messages }`),该声明才能存活。每个步骤读取插件注册的提示词片段和工具 schema。
|
|
95
106
|
|
|
96
107
|
详情见[时序图](./agent-lifecycle.md)、[工具流水线](./tool-execution-pipeline.md)和[取消与错误恢复](./subsystems/core.md#the-agent-handle)。
|
|
97
108
|
|
|
@@ -122,6 +133,7 @@ seam 正是替换一个提供方就能改变整个产品的原因。文件系统
|
|
|
122
133
|
| 添加持久化终端执行 | 注册 `ctx.terminals` 后端和 `dsh-tool-terminal` |
|
|
123
134
|
| 添加用户命令 | 在 `ctx.commands` 上注册;它无需模型轮次即可分派 |
|
|
124
135
|
| 添加后台工作 | 在 `ctx.jobs` 上注册;`job_*` 工具负责收集或停止 |
|
|
136
|
+
| 从外部 webhook 启动 Session | 在 `ctx.webhookRuntime` 上注册可信规则,并挂载提供方适配器 |
|
|
125
137
|
| 添加文件系统访问或策略 | 注册 `ctx.fs` 提供方,或监听 `fs/*` 事件 |
|
|
126
138
|
| 限制所启动的进程 | 使用 `ctx.sandbox` 后端;消费方在启动进程前包装 argv |
|
|
127
139
|
| 拦截请求、工具或轮次 | 使用相应的 `agent/*` 或 `tools/*` 事件;`agent/turn-stopping` 会停止轮次 |
|
|
@@ -134,4 +146,4 @@ seam 正是替换一个提供方就能改变整个产品的原因。文件系统
|
|
|
134
146
|
| fork 活跃会话 | `ctx.sessions.fork(source, boundary?, childSessionId?)` |
|
|
135
147
|
| 将注册项限定到单个 agent | 使用该 agent 的 `agent.ctx` |
|
|
136
148
|
|
|
137
|
-
[扩展实操手册](./cookbook/extension-cookbook.md)将功能映射到能力,并索引[包](./cookbook/adding-a-package.md)、[工具](./cookbook/adding-a-tool.md)、[LLM(大语言模型)适配器](./cookbook/adding-an-llm-adapter.md)
|
|
149
|
+
[扩展实操手册](./cookbook/extension-cookbook.md)将功能映射到能力,并索引[包](./cookbook/adding-a-package.md)、[工具](./cookbook/adding-a-tool.md)、[LLM(大语言模型)适配器](./cookbook/adding-an-llm-adapter.md)和[设置卡片](./cookbook/adding-a-settings-card.md)的分步指南。[Conversation 子系统](./subsystems/conversation.md)负责 Chat node 组装。
|
|
@@ -12,7 +12,7 @@ outline: "deep"
|
|
|
12
12
|
|
|
13
13
|
英文源文件根据源码生成(`scripts/gen-persistence-catalog.ts`),并由 `pnpm run verify-persistence-catalog`(`doc-sync`(文档同步门禁)的一部分)验证新鲜度;本中文文件作为经评审对侧通过双语配对维护。声明块保留源码声明和嵌套属性的 JSDoc,只移除其所在接口/模块带来的缩进,并使用 `ts persistence-catalog` 围栏(doc-typecheck 会跳过这些围栏,因为声明引用了其所属模块中的类型)。payload 中的类型名称会链接到记录该类型的页面。参见 [persistence-log-catalog Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/archived/process/2026-07-04-persistence-log-catalog.md)。
|
|
14
14
|
|
|
15
|
-
以下信封声明组合了每个事件的 `type`、单调递增的 `seq`、以 epoch 毫秒表示的 `time`、`data
|
|
15
|
+
以下信封声明组合了每个事件的 `type`、单调递增的 `seq`、以 epoch 毫秒表示的 `time`、`data`,以及条件字段 `surfaceOp`/`sourceEventSeqs`。**surface** 表示 `SurfaceEventType` 成员:它会生成一条 LLM(大语言模型)消息,并声明该事件如何加入 surface 列表。**log-only** 表示其他所有事件:这类记录可持久化、可回放,但不参与派生历史。每个 payload 均可进行 JSON 序列化(在 `Session.append` 处强制执行),整个格式固定为 `SESSION_FORMAT_VERSION = 0`:这是预发布格式,不暗示任何兼容性(参见[版本立场](./subsystems/persistence.md))。范围仅限本仓库中的包;下游插件可以继续合并其他事件类型,而这些类型按设计不属于本目录。
|
|
16
16
|
|
|
17
17
|
## 事件信封
|
|
18
18
|
|
|
@@ -68,17 +68,6 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
68
68
|
/** Unix epoch milliseconds. */
|
|
69
69
|
time: number
|
|
70
70
|
data: SessionEventMap[K]
|
|
71
|
-
/**
|
|
72
|
-
* Marks an event a reader may safely skip when it does not recognize
|
|
73
|
-
* `type`. Absent means required: a reader meeting an unrecognized type
|
|
74
|
-
* without this marker MUST refuse to reconstruct the session instead of
|
|
75
|
-
* silently dropping the event, because an unrecognized required event may
|
|
76
|
-
* change how the rest of the log is interpreted. A writer sets `true` only
|
|
77
|
-
* on purely informational records whose loss cannot affect reconstruction;
|
|
78
|
-
* defaulting to required means a forgotten marker over-refuses (an
|
|
79
|
-
* inconvenience) rather than silently resuming a gutted session.
|
|
80
|
-
*/
|
|
81
|
-
ignorable?: true
|
|
82
71
|
} & (K extends SurfaceEventType ? {
|
|
83
72
|
/**
|
|
84
73
|
* Seq numbers of earlier events that this event cites as sources
|
|
@@ -95,7 +84,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
95
84
|
}[T]
|
|
96
85
|
```
|
|
97
86
|
|
|
98
|
-
来源:[`packages/core/session/src/types.ts:
|
|
87
|
+
来源:[`packages/core/session/src/types.ts:321`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:328`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:357`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts) · [`packages/core/session/src/types.ts:389`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
99
88
|
|
|
100
89
|
## 事件
|
|
101
90
|
|
|
@@ -120,7 +109,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
120
109
|
}
|
|
121
110
|
```
|
|
122
111
|
|
|
123
|
-
来源:[`packages/core/agent/src/types.ts:
|
|
112
|
+
来源:[`packages/core/agent/src/types.ts:38`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
|
|
124
113
|
|
|
125
114
|
### `agent-preset/*`
|
|
126
115
|
|
|
@@ -138,7 +127,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
138
127
|
'agent-preset/selected': { agentPreset: string }
|
|
139
128
|
```
|
|
140
129
|
|
|
141
|
-
来源:[`packages/preset/agent-presets/src/session.ts:
|
|
130
|
+
来源:[`packages/preset/agent-presets/src/session.ts:28`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/preset/agent-presets/src/session.ts)
|
|
142
131
|
|
|
143
132
|
### `approval/*`
|
|
144
133
|
|
|
@@ -158,14 +147,14 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
158
147
|
'approval/asked': {
|
|
159
148
|
id: ApprovalRequestId
|
|
160
149
|
toolName: string
|
|
161
|
-
callId?:
|
|
150
|
+
callId?: ToolCallId
|
|
162
151
|
reason?: string
|
|
163
152
|
}
|
|
164
153
|
```
|
|
165
154
|
|
|
166
|
-
类型:[
|
|
155
|
+
类型:[ToolCallId](./subsystems/core.md)
|
|
167
156
|
|
|
168
|
-
来源:[`packages/interaction/user-approval/src/
|
|
157
|
+
来源:[`packages/interaction/user-approval/src/types.ts:44`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/types.ts)
|
|
169
158
|
|
|
170
159
|
<a id="approvaldecided--log-only"></a>
|
|
171
160
|
|
|
@@ -183,7 +172,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
183
172
|
}
|
|
184
173
|
```
|
|
185
174
|
|
|
186
|
-
来源:[`packages/interaction/user-approval/src/
|
|
175
|
+
来源:[`packages/interaction/user-approval/src/types.ts:55`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/types.ts)
|
|
187
176
|
|
|
188
177
|
<a id="approvalpolicy--log-only"></a>
|
|
189
178
|
|
|
@@ -205,7 +194,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
205
194
|
}
|
|
206
195
|
```
|
|
207
196
|
|
|
208
|
-
来源:[`packages/interaction/user-approval/src/index.ts:
|
|
197
|
+
来源:[`packages/interaction/user-approval/src/index.ts:32`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/interaction/user-approval/src/index.ts)
|
|
209
198
|
|
|
210
199
|
### `assistant/*`
|
|
211
200
|
|
|
@@ -220,7 +209,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
220
209
|
|
|
221
210
|
类型:[StreamChunk](./subsystems/llm-streaming.md)
|
|
222
211
|
|
|
223
|
-
来源:[`packages/core/session/src/types.ts:
|
|
212
|
+
来源:[`packages/core/session/src/types.ts:249`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
224
213
|
|
|
225
214
|
<a id="assistantmessage--surface"></a>
|
|
226
215
|
|
|
@@ -242,7 +231,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
242
231
|
|
|
243
232
|
类型:[TokenUsage](./subsystems/llm-streaming.md)
|
|
244
233
|
|
|
245
|
-
来源:[`packages/core/session/src/types.ts:
|
|
234
|
+
来源:[`packages/core/session/src/types.ts:260`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
246
235
|
|
|
247
236
|
### `command/*`
|
|
248
237
|
|
|
@@ -503,6 +492,22 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
503
492
|
|
|
504
493
|
来源:[`packages/llm/llm-retry/src/types.ts:11`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/llm/llm-retry/src/types.ts)
|
|
505
494
|
|
|
495
|
+
### `model/*`
|
|
496
|
+
|
|
497
|
+
<a id="modelselection--log-only"></a>
|
|
498
|
+
|
|
499
|
+
#### `model/selection` — log-only
|
|
500
|
+
|
|
501
|
+
```ts persistence-catalog
|
|
502
|
+
/**
|
|
503
|
+
* Complete validated model selection requested for subsequent prompt
|
|
504
|
+
* assembly. Log-only: it never enters derived model history.
|
|
505
|
+
*/
|
|
506
|
+
'model/selection': ModelSelection
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
来源:[`packages/api/session-controller/src/types.ts:39`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/session-controller/src/types.ts)
|
|
510
|
+
|
|
506
511
|
### `permission/*`
|
|
507
512
|
|
|
508
513
|
<a id="permissionpreset--log-only"></a>
|
|
@@ -552,7 +557,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
552
557
|
'request/context': RequestContext
|
|
553
558
|
```
|
|
554
559
|
|
|
555
|
-
来源:[`packages/core/session/src/types.ts:
|
|
560
|
+
来源:[`packages/core/session/src/types.ts:294`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
556
561
|
|
|
557
562
|
<a id="requestheader--log-only"></a>
|
|
558
563
|
|
|
@@ -563,10 +568,15 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
563
568
|
* Full header for the next request, appended inside its step before dispatch.
|
|
564
569
|
* It is log-only; the latest snapshot reconstructs the request header.
|
|
565
570
|
*/
|
|
566
|
-
'request/header': {
|
|
571
|
+
'request/header': {
|
|
572
|
+
header: EpochHeader
|
|
573
|
+
reason: RequestHeaderReason
|
|
574
|
+
/** A changed header also begins a distinct model-message series. */
|
|
575
|
+
startsSeries?: true
|
|
576
|
+
}
|
|
567
577
|
```
|
|
568
578
|
|
|
569
|
-
来源:[`packages/core/session/src/types.ts:
|
|
579
|
+
来源:[`packages/core/session/src/types.ts:289`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
570
580
|
|
|
571
581
|
### `sandbox/*`
|
|
572
582
|
|
|
@@ -641,7 +651,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
641
651
|
'session/end-seed': Record<string, never>
|
|
642
652
|
```
|
|
643
653
|
|
|
644
|
-
来源:[`packages/core/session/src/types.ts:
|
|
654
|
+
来源:[`packages/core/session/src/types.ts:317`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
645
655
|
|
|
646
656
|
<a id="sessiontitle--log-only"></a>
|
|
647
657
|
|
|
@@ -672,6 +682,24 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
672
682
|
|
|
673
683
|
来源:[`packages/session/session-title-llm/src/index.ts:43`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-title-llm/src/index.ts)
|
|
674
684
|
|
|
685
|
+
### `session-log-deepseek/*`
|
|
686
|
+
|
|
687
|
+
<a id="session-log-deepseekdelivery-accepted--log-only"></a>
|
|
688
|
+
|
|
689
|
+
#### `session-log-deepseek/delivery-accepted` — log-only
|
|
690
|
+
|
|
691
|
+
```ts persistence-catalog
|
|
692
|
+
/** Records that the configured endpoint accepted one delivery through `throughSeq`. */
|
|
693
|
+
'session-log-deepseek/delivery-accepted': {
|
|
694
|
+
/** Session identity the accepted delivery carried; inherited fork markers retain the parent's id. */
|
|
695
|
+
sessionId: import('@deepseek-ai/dsh-session/types').SessionId
|
|
696
|
+
/** Last canonical event included in the accepted request. */
|
|
697
|
+
throughSeq: number
|
|
698
|
+
}
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
来源:[`packages/session/session-log-deepseek/src/types.ts:26`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-log-deepseek/src/types.ts)
|
|
702
|
+
|
|
675
703
|
### `step/*`
|
|
676
704
|
|
|
677
705
|
<a id="stepend--log-only"></a>
|
|
@@ -683,7 +711,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
683
711
|
'step/end': { turn: number; step: number }
|
|
684
712
|
```
|
|
685
713
|
|
|
686
|
-
来源:[`packages/core/session/src/types.ts:
|
|
714
|
+
来源:[`packages/core/session/src/types.ts:239`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
687
715
|
|
|
688
716
|
<a id="stepstart--log-only"></a>
|
|
689
717
|
|
|
@@ -694,7 +722,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
694
722
|
'step/start': { turn: number; step: number }
|
|
695
723
|
```
|
|
696
724
|
|
|
697
|
-
来源:[`packages/core/session/src/types.ts:
|
|
725
|
+
来源:[`packages/core/session/src/types.ts:237`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
698
726
|
|
|
699
727
|
### `subagent/*`
|
|
700
728
|
|
|
@@ -713,7 +741,26 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
713
741
|
'subagent/descriptor': SubagentDescriptorData
|
|
714
742
|
```
|
|
715
743
|
|
|
716
|
-
来源:[`packages/subagent/subagent/src/descriptor.ts:
|
|
744
|
+
来源:[`packages/subagent/subagent/src/descriptor.ts:38`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/subagent/src/descriptor.ts)
|
|
745
|
+
|
|
746
|
+
<a id="subagentmodel-selection-policy--log-only"></a>
|
|
747
|
+
|
|
748
|
+
#### `subagent/model-selection-policy` — 仅日志
|
|
749
|
+
|
|
750
|
+
```ts persistence-catalog
|
|
751
|
+
/**
|
|
752
|
+
* Records that this session's delegation tool exposes child provider,
|
|
753
|
+
* model, and reasoning-effort selection. Appended before the first model
|
|
754
|
+
* request; absence means the fixed-route definition. Log-only: it carries
|
|
755
|
+
* no `surfaceOp` and never enters model history.
|
|
756
|
+
*/
|
|
757
|
+
'subagent/model-selection-policy': {
|
|
758
|
+
/** Exact routes this Session may select explicitly for a child. */
|
|
759
|
+
allowedModels: AllowedModelRoute[]
|
|
760
|
+
}
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
来源:[`packages/subagent/tool-subagent/src/model-selection-state.ts:14`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/tool-subagent/src/model-selection-state.ts)
|
|
717
764
|
|
|
718
765
|
### `team/*`
|
|
719
766
|
|
|
@@ -785,9 +832,9 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
785
832
|
'todo/write': { todos: TodoItem[] }
|
|
786
833
|
```
|
|
787
834
|
|
|
788
|
-
类型:[TodoItem](
|
|
835
|
+
类型:[TodoItem](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/todo.zh.md)
|
|
789
836
|
|
|
790
|
-
来源:[`packages/
|
|
837
|
+
来源:[`packages/todo/tool-todo/src/types.ts:31`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/todo/tool-todo/src/types.ts)
|
|
791
838
|
|
|
792
839
|
### `tool/*`
|
|
793
840
|
|
|
@@ -801,12 +848,12 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
801
848
|
* JSON string exactly as the model produced it (unparsed). `callId` pairs the
|
|
802
849
|
* call with its `tool/result`.
|
|
803
850
|
*/
|
|
804
|
-
'tool/call': { turn: number; step: number; callId:
|
|
851
|
+
'tool/call': { turn: number; step: number; callId: ToolCallId; name: string; arguments: string }
|
|
805
852
|
```
|
|
806
853
|
|
|
807
|
-
类型:[
|
|
854
|
+
类型:[ToolCallId](./subsystems/core.md)
|
|
808
855
|
|
|
809
|
-
来源:[`packages/core/session/src/types.ts:
|
|
856
|
+
来源:[`packages/core/session/src/types.ts:266`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
810
857
|
|
|
811
858
|
<a id="toolcode-dispatch--log-only"></a>
|
|
812
859
|
|
|
@@ -828,7 +875,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
828
875
|
* before returning), so its execution-enclosure relation holds by
|
|
829
876
|
* construction.
|
|
830
877
|
*/
|
|
831
|
-
'tool/code-dispatch':
|
|
878
|
+
'tool/code-dispatch': PtcDispatchEventData
|
|
832
879
|
```
|
|
833
880
|
|
|
834
881
|
来源:[`packages/core/tools/src/types.ts:56`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/types.ts)
|
|
@@ -851,7 +898,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
851
898
|
* with `tool/code-dispatch` by `subCallId` (timing = the two events'
|
|
852
899
|
* `time` fields).
|
|
853
900
|
*/
|
|
854
|
-
'tool/code-dispatch-start':
|
|
901
|
+
'tool/code-dispatch-start': PtcDispatchStartEventData
|
|
855
902
|
```
|
|
856
903
|
|
|
857
904
|
来源:[`packages/core/tools/src/types.ts:40`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/types.ts)
|
|
@@ -881,7 +928,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
881
928
|
}
|
|
882
929
|
```
|
|
883
930
|
|
|
884
|
-
来源:[`packages/core/session/src/types.ts:
|
|
931
|
+
来源:[`packages/core/session/src/types.ts:278`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
885
932
|
|
|
886
933
|
### `tool-workflow/*`
|
|
887
934
|
|
|
@@ -961,7 +1008,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
961
1008
|
|
|
962
1009
|
类型:[TurnEndReason](./subsystems/session.md)
|
|
963
1010
|
|
|
964
|
-
来源:[`packages/core/session/src/types.ts:
|
|
1011
|
+
来源:[`packages/core/session/src/types.ts:235`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
965
1012
|
|
|
966
1013
|
<a id="turnstart--log-only"></a>
|
|
967
1014
|
|
|
@@ -977,7 +1024,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
977
1024
|
'turn/start': { turn: number }
|
|
978
1025
|
```
|
|
979
1026
|
|
|
980
|
-
来源:[`packages/core/session/src/types.ts:
|
|
1027
|
+
来源:[`packages/core/session/src/types.ts:226`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
981
1028
|
|
|
982
1029
|
### `user/*`
|
|
983
1030
|
|
|
@@ -996,7 +1043,7 @@ export type SessionEvent<T extends SessionEventType = SessionEventType> = {
|
|
|
996
1043
|
'user/message': UserMessage
|
|
997
1044
|
```
|
|
998
1045
|
|
|
999
|
-
来源:[`packages/core/session/src/types.ts:
|
|
1046
|
+
来源:[`packages/core/session/src/types.ts:247`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
1000
1047
|
|
|
1001
1048
|
### `web/*`
|
|
1002
1049
|
|