dsh-plugin-dev-kb 1.0.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/LICENSE +21 -0
- package/README.md +56 -0
- package/cordis.patch.yml +12 -0
- package/kb/INDEX.md +210 -0
- package/kb/README.md +69 -0
- package/kb/extra/AGENTS.md +75 -0
- package/kb/extra/api-gateway.md +164 -0
- package/kb/extra/api-gateway.zh.md +164 -0
- package/kb/extra/cookbook/adding-a-vendored-package.md +59 -0
- package/kb/extra/cookbook/adding-a-vendored-package.zh.md +59 -0
- package/kb/extra/cookbook/maintaining-dsh-code-review.md +64 -0
- package/kb/extra/cookbook/maintaining-dsh-code-review.zh.md +64 -0
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +32 -0
- package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +32 -0
- package/kb/extra/defensive-patterns.md +33 -0
- package/kb/extra/defensive-patterns.zh.md +33 -0
- package/kb/extra/development.md +171 -0
- package/kb/extra/development.zh.md +171 -0
- package/kb/extra/event-producer-consumer.md +76 -0
- package/kb/extra/event-producer-consumer.zh.md +78 -0
- package/kb/extra/glossary.md +45 -0
- package/kb/extra/glossary.zh.md +45 -0
- package/kb/extra/graph-atlas.md +24 -0
- package/kb/extra/graph-atlas.zh.md +26 -0
- package/kb/extra/i18n/README.md +60 -0
- package/kb/extra/i18n/README.zh.md +60 -0
- package/kb/extra/i18n/style-samples.md +87 -0
- package/kb/extra/i18n/terminology.md +214 -0
- package/kb/extra/i18n/translation-prompt.md +263 -0
- package/kb/extra/i18n/translation-rules.md +69 -0
- package/kb/extra/i18n/translation-rules.zh.md +69 -0
- package/kb/extra/module-graph.md +1641 -0
- package/kb/extra/module-graph.zh.md +1643 -0
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +113 -0
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +113 -0
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +47 -0
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +47 -0
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +53 -0
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +53 -0
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +55 -0
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +55 -0
- package/kb/extra/postmortem/README.md +18 -0
- package/kb/extra/postmortem/README.zh.md +18 -0
- package/kb/extra/rescope.md +53 -0
- package/kb/extra/rescope.zh.md +53 -0
- package/kb/extra/subsystems/attachment.md +125 -0
- package/kb/extra/subsystems/attachment.zh.md +125 -0
- package/kb/extra/subsystems/extensions.md +364 -0
- package/kb/extra/subsystems/extensions.zh.md +364 -0
- package/kb/extra/subsystems/feedback.md +266 -0
- package/kb/extra/subsystems/feedback.zh.md +266 -0
- package/kb/extra/testing.md +49 -0
- package/kb/extra/testing.zh.md +49 -0
- package/kb/extra/web-styling.md +25 -0
- package/kb/extra/web-styling.zh.md +25 -0
- package/kb/meta/search-index.json +1328 -0
- package/kb/meta/site-pages.txt +168 -0
- package/kb/meta/source.json +13 -0
- package/kb/meta/topics.md +75 -0
- package/kb/site/develop/basic/config.md +108 -0
- package/kb/site/develop/basic/index.md +146 -0
- package/kb/site/develop/basic/publish.md +185 -0
- package/kb/site/develop/basic/tool.md +54 -0
- package/kb/site/develop/cordis-tutorial/01-first-plugin.md +95 -0
- package/kb/site/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
- package/kb/site/develop/cordis-tutorial/03-services.md +98 -0
- package/kb/site/develop/cordis-tutorial/04-events.md +144 -0
- package/kb/site/develop/cordis-tutorial/05-config.md +84 -0
- package/kb/site/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
- package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +107 -0
- package/kb/site/develop/cordis-tutorial/index.md +62 -0
- package/kb/site/develop/framework/events.md +145 -0
- package/kb/site/develop/framework/index.md +139 -0
- package/kb/site/develop/framework/service.md +152 -0
- package/kb/site/develop/practice/index.md +157 -0
- package/kb/site/develop/practice/llm-adapter.md +190 -0
- package/kb/site/en/develop/basic/config.md +108 -0
- package/kb/site/en/develop/basic/index.md +146 -0
- package/kb/site/en/develop/basic/publish.md +185 -0
- package/kb/site/en/develop/basic/tool.md +54 -0
- package/kb/site/en/develop/cordis-tutorial/01-first-plugin.md +95 -0
- package/kb/site/en/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
- package/kb/site/en/develop/cordis-tutorial/03-services.md +98 -0
- package/kb/site/en/develop/cordis-tutorial/04-events.md +144 -0
- package/kb/site/en/develop/cordis-tutorial/05-config.md +84 -0
- package/kb/site/en/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
- package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +107 -0
- package/kb/site/en/develop/cordis-tutorial/index.md +60 -0
- package/kb/site/en/develop/framework/events.md +145 -0
- package/kb/site/en/develop/framework/index.md +139 -0
- package/kb/site/en/develop/framework/service.md +150 -0
- package/kb/site/en/develop/practice/index.md +157 -0
- package/kb/site/en/develop/practice/llm-adapter.md +190 -0
- package/kb/site/en/guide/providers-custom-form.png +0 -0
- package/kb/site/en/guide/providers-models-page.png +0 -0
- package/kb/site/en/guide/providers.md +100 -0
- package/kb/site/en/guide/python-sdk.md +106 -0
- package/kb/site/en/guide/quickstart.md +32 -0
- package/kb/site/en/index.md +8 -0
- package/kb/site/en/reference/agent-lifecycle.md +86 -0
- package/kb/site/en/reference/capability-seams.md +475 -0
- package/kb/site/en/reference/config-catalog.md +3155 -0
- package/kb/site/en/reference/cookbook/adding-a-conversation-node.md +235 -0
- package/kb/site/en/reference/cookbook/adding-a-package.md +120 -0
- package/kb/site/en/reference/cookbook/adding-a-settings-card.md +102 -0
- package/kb/site/en/reference/cookbook/adding-a-tool.md +96 -0
- package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +45 -0
- package/kb/site/en/reference/cookbook/extension-cookbook.md +131 -0
- package/kb/site/en/reference/cordis-api/context.md +368 -0
- package/kb/site/en/reference/cordis-api/events.md +211 -0
- package/kb/site/en/reference/cordis-api/fiber.md +379 -0
- package/kb/site/en/reference/cordis-api/inherited.md +43 -0
- package/kb/site/en/reference/cordis-api/registry.md +156 -0
- package/kb/site/en/reference/cordis-api/service.md +106 -0
- package/kb/site/en/reference/cordis-primer.md +46 -0
- package/kb/site/en/reference/index.md +131 -0
- package/kb/site/en/reference/persistence-catalog.md +949 -0
- package/kb/site/en/reference/subsystems/approval.md +173 -0
- package/kb/site/en/reference/subsystems/client-modules.md +121 -0
- package/kb/site/en/reference/subsystems/code-runtime.md +194 -0
- package/kb/site/en/reference/subsystems/commands.md +190 -0
- package/kb/site/en/reference/subsystems/compaction.md +241 -0
- package/kb/site/en/reference/subsystems/core.md +1073 -0
- package/kb/site/en/reference/subsystems/credentials.md +136 -0
- package/kb/site/en/reference/subsystems/filesystem.md +498 -0
- package/kb/site/en/reference/subsystems/goal.md +280 -0
- package/kb/site/en/reference/subsystems/index.md +58 -0
- package/kb/site/en/reference/subsystems/invariants.md +91 -0
- package/kb/site/en/reference/subsystems/jobs.md +293 -0
- package/kb/site/en/reference/subsystems/llm-streaming.md +920 -0
- package/kb/site/en/reference/subsystems/lsp.md +205 -0
- package/kb/site/en/reference/subsystems/permission-presets.md +134 -0
- package/kb/site/en/reference/subsystems/persistence.md +388 -0
- package/kb/site/en/reference/subsystems/plan.md +90 -0
- package/kb/site/en/reference/subsystems/sandbox.md +221 -0
- package/kb/site/en/reference/subsystems/schedule.md +189 -0
- package/kb/site/en/reference/subsystems/scope.md +62 -0
- package/kb/site/en/reference/subsystems/session-projection.md +265 -0
- package/kb/site/en/reference/subsystems/session-query.md +498 -0
- package/kb/site/en/reference/subsystems/session-reference.md +111 -0
- package/kb/site/en/reference/subsystems/session-telemetry.md +197 -0
- package/kb/site/en/reference/subsystems/session-title.md +207 -0
- package/kb/site/en/reference/subsystems/session.md +852 -0
- package/kb/site/en/reference/subsystems/settings.md +313 -0
- package/kb/site/en/reference/subsystems/shell.md +306 -0
- package/kb/site/en/reference/subsystems/skills.md +334 -0
- package/kb/site/en/reference/subsystems/spill.md +120 -0
- package/kb/site/en/reference/subsystems/storage.md +232 -0
- package/kb/site/en/reference/subsystems/subagent.md +737 -0
- package/kb/site/en/reference/subsystems/subprocess.md +327 -0
- package/kb/site/en/reference/subsystems/system-prompt.md +210 -0
- package/kb/site/en/reference/subsystems/terminal.md +187 -0
- package/kb/site/en/reference/subsystems/token-meter.md +93 -0
- package/kb/site/en/reference/subsystems/tools.md +723 -0
- package/kb/site/en/reference/subsystems/typert.md +339 -0
- package/kb/site/en/reference/subsystems/user-questions.md +181 -0
- package/kb/site/en/reference/subsystems/web-server.md +111 -0
- package/kb/site/en/reference/subsystems/web.md +202 -0
- package/kb/site/en/reference/subsystems/workflow.md +281 -0
- package/kb/site/en/reference/subsystems/workspace.md +231 -0
- package/kb/site/en/reference/tool-catalog.md +1877 -0
- package/kb/site/en/reference/tool-execution-pipeline.md +66 -0
- package/kb/site/guide/providers-custom-form.zh.png +0 -0
- package/kb/site/guide/providers-models-page.zh.png +0 -0
- package/kb/site/guide/providers.md +100 -0
- package/kb/site/guide/python-sdk.md +106 -0
- package/kb/site/guide/quickstart.md +32 -0
- package/kb/site/index.md +8 -0
- package/kb/site/reference/agent-lifecycle.md +86 -0
- package/kb/site/reference/capability-seams.md +475 -0
- package/kb/site/reference/config-catalog.md +3154 -0
- package/kb/site/reference/cookbook/adding-a-conversation-node.md +235 -0
- package/kb/site/reference/cookbook/adding-a-package.md +120 -0
- package/kb/site/reference/cookbook/adding-a-settings-card.md +102 -0
- package/kb/site/reference/cookbook/adding-a-tool.md +98 -0
- package/kb/site/reference/cookbook/adding-an-llm-adapter.md +45 -0
- package/kb/site/reference/cookbook/extension-cookbook.md +133 -0
- package/kb/site/reference/cordis-api/context.md +368 -0
- package/kb/site/reference/cordis-api/events.md +211 -0
- package/kb/site/reference/cordis-api/fiber.md +379 -0
- package/kb/site/reference/cordis-api/inherited.md +43 -0
- package/kb/site/reference/cordis-api/registry.md +156 -0
- package/kb/site/reference/cordis-api/service.md +106 -0
- package/kb/site/reference/cordis-primer.md +52 -0
- package/kb/site/reference/index.md +135 -0
- package/kb/site/reference/persistence-catalog.md +949 -0
- package/kb/site/reference/subsystems/approval.md +173 -0
- package/kb/site/reference/subsystems/client-modules.md +121 -0
- package/kb/site/reference/subsystems/code-runtime.md +194 -0
- package/kb/site/reference/subsystems/commands.md +190 -0
- package/kb/site/reference/subsystems/compaction.md +241 -0
- package/kb/site/reference/subsystems/core.md +1081 -0
- package/kb/site/reference/subsystems/credentials.md +136 -0
- package/kb/site/reference/subsystems/filesystem.md +498 -0
- package/kb/site/reference/subsystems/goal.md +280 -0
- package/kb/site/reference/subsystems/index.md +58 -0
- package/kb/site/reference/subsystems/invariants.md +91 -0
- package/kb/site/reference/subsystems/jobs.md +293 -0
- package/kb/site/reference/subsystems/llm-streaming.md +926 -0
- package/kb/site/reference/subsystems/lsp.md +205 -0
- package/kb/site/reference/subsystems/permission-presets.md +134 -0
- package/kb/site/reference/subsystems/persistence.md +388 -0
- package/kb/site/reference/subsystems/plan.md +90 -0
- package/kb/site/reference/subsystems/sandbox.md +221 -0
- package/kb/site/reference/subsystems/schedule.md +189 -0
- package/kb/site/reference/subsystems/scope.md +62 -0
- package/kb/site/reference/subsystems/session-projection.md +265 -0
- package/kb/site/reference/subsystems/session-query.md +498 -0
- package/kb/site/reference/subsystems/session-reference.md +111 -0
- package/kb/site/reference/subsystems/session-telemetry.md +197 -0
- package/kb/site/reference/subsystems/session-title.md +207 -0
- package/kb/site/reference/subsystems/session.md +854 -0
- package/kb/site/reference/subsystems/settings.md +313 -0
- package/kb/site/reference/subsystems/shell.md +306 -0
- package/kb/site/reference/subsystems/skills.md +334 -0
- package/kb/site/reference/subsystems/spill.md +120 -0
- package/kb/site/reference/subsystems/storage.md +232 -0
- package/kb/site/reference/subsystems/subagent.md +739 -0
- package/kb/site/reference/subsystems/subprocess.md +327 -0
- package/kb/site/reference/subsystems/system-prompt.md +210 -0
- package/kb/site/reference/subsystems/terminal.md +187 -0
- package/kb/site/reference/subsystems/token-meter.md +93 -0
- package/kb/site/reference/subsystems/tools.md +723 -0
- package/kb/site/reference/subsystems/typert.md +339 -0
- package/kb/site/reference/subsystems/user-questions.md +181 -0
- package/kb/site/reference/subsystems/web-server.md +111 -0
- package/kb/site/reference/subsystems/web.md +202 -0
- package/kb/site/reference/subsystems/workflow.md +281 -0
- package/kb/site/reference/subsystems/workspace.md +231 -0
- package/kb/site/reference/tool-catalog.md +1880 -0
- package/kb/site/reference/tool-execution-pipeline.md +66 -0
- package/package.json +40 -0
- package/scripts/rebuild-index.mjs +88 -0
- package/skills/dsh-plugin-dev-kb.md +66 -0
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
---
|
|
2
|
+
editSource: "docs/subsystems/persistence.zh.md"
|
|
3
|
+
outline: [2,3]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 会话持久化
|
|
7
|
+
|
|
8
|
+
事件日志的**持久性 seam**。[session.md](./session.md) 描述了内存中的 `Session`:仅追加的 `SessionEvent` 日志即为真源。本页描述如何使该日志持久化:抽象的 `SessionPersistence` 服务、它的后端、flush 检查点、崩溃恢复,以及随日志一同存储的元数据头。日志承载的事件词汇在生成的[持久化日志事件目录](../persistence-catalog.md)中逐项列举。
|
|
9
|
+
|
|
10
|
+
该 seam 是一个[能力 seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-13-capability-seams.md):一个抽象服务([dsh-session-persistence](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence),`ctx.sessionPersistence`)在现有 `SessionEvent` 上定义 locate/create/append、可复用的 Session 准备流程、逻辑 load/inspect、物理后缀读取,以及轻量的 list/snapshot 观察——**没有平行的持久化事件类型**——以及两个实现同一约定的可互换后端。见 [session-persistence Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-14-session-persistence.md)。
|
|
11
|
+
|
|
12
|
+
## flush 检查点
|
|
13
|
+
|
|
14
|
+
`session/event` 是一个*同步*通知;持久化插件会将事件复制到逐会话控制器,而不阻塞生产方。第一个待处理事件会开启固定批处理窗口,后续事件会加入但不会重置截止时间。窗口到期后会启动一个持久化批次;该次写入期间接纳的事件会获得自己的截止时间,并形成后续批次。`session/flush` 会取消等待并排空至完全停稳,因此循环仍将其用作在领取下一个普通轮次之前的顺序与错误观察检查点。后台写入被拒绝时会保留对应事件并暂停自动重试;新事件会开启新的固定窗口,而显式 flush 会立即重试,并通过 `agent/error` 和 logger 报告失败,绝不会把失败记录成已关闭轮次之后的会话事件。dispose(资源释放)会执行同样的最终排空。配置的最大值只限制有意的批处理等待,不限制事件循环调度或后端完成持久化的延迟([决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-08-bounded-session-persistence-write-batching.md))。
|
|
15
|
+
|
|
16
|
+
## 崩溃恢复保留被中断的轮次
|
|
17
|
+
|
|
18
|
+
后端重新加载一个在轮次中途崩溃的日志时,会发现一个已打开的 `turn/start` 却没有 `turn/end`。它**不会**截断日志:在长周期任务中,单个轮次可能非常庞大(许多步骤、大量工具输出),而这些事件在崩溃前已被持久追加。后端改为用一个合成的 `turn/end { reason: { kind: 'interrupted' } }` 关闭这个遗留轮次,在不改变其前后任何独立事件的情况下配平被中断的执行。`interrupted` 是唯一一个不由循环发出的 `TurnEndReason`(见 [session.md](./session.md#why-a-turn-ended-turnendreasonmap))。
|
|
19
|
+
|
|
20
|
+
修复仅适用于冷会话。对于活跃 id,`SessionPersistence.load(id)` 会等待权威内存快照完成持久化,并且只在日志平衡时返回;若活跃轮次仍未闭合,则拒绝操作,而不是添加合成的中断边界。HMR(热模块替换)会接管活跃前缀,而不会关闭其中正在进行的轮次。
|
|
21
|
+
|
|
22
|
+
`SessionPersistence.inspect(id)` 会构造一个不可变的逻辑 Session,但不发布它,也不写入恢复内容。冷检查会在内存中配平中断的轮次,同时保持撕裂的物理尾部不变;检查已处于活跃状态的 Session 则借用其当前不可变快照,因此可能包含未闭合的轮次。使用协调器的实现会在有界 LRU 中保留这个精确的冷未发布 Session,因此重复历史读取与后续 `prepare(id)` 可复用同一次读取、解压、验证、冻结及 Session 构造。`prepare(id)` 会预留该 Session、提交待处理修复并返回可 dispose 的发布句柄;`load(id)` 使用相同机制提交修复,但不会发布 Session。该生命周期由 [Session 准备阶段决策](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-05-session-preparation.md)定义。
|
|
23
|
+
|
|
24
|
+
## `SessionLocation`——可选的逐会话产物目标
|
|
25
|
+
|
|
26
|
+
`SessionPersistence.locate(meta)` 会同步解析一个归后端所有的独立产物,而不会读取、创建或 flush 它。JSONL 返回其项目/会话目录内 transcript(文本记录)的绝对路径;SQLite 因各会话共享一个数据库而返回 `undefined`。因此,返回的路径可能指向尚不存在的文件,或指向还不包含当前尚未 flush 轮次的文件;它是位置提示,不是授权或新鲜度保证。
|
|
27
|
+
|
|
28
|
+
```ts type-equiv
|
|
29
|
+
/**
|
|
30
|
+
* A backend-resolved, per-session local artifact location. The path is an
|
|
31
|
+
* absolute target path and can name an artifact that has not materialized yet.
|
|
32
|
+
* Consumers must treat it as a location hint, never as an authorization token.
|
|
33
|
+
*/
|
|
34
|
+
interface SessionLocation {
|
|
35
|
+
/** Backend-specific artifact kind, for example `jsonl`. */
|
|
36
|
+
readonly kind: string
|
|
37
|
+
/** Absolute path to this session's backend-owned artifact. */
|
|
38
|
+
readonly path: string
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
<a id="sessionheader--metadata-beside-the-log"></a>
|
|
43
|
+
|
|
44
|
+
## `SessionHeader`:日志旁的元数据
|
|
45
|
+
|
|
46
|
+
每个会话的元数据与事件日志**分开**存储:格式版本、cwd、血统与 seed 边界是存储层关注点而非对话事件,因此不进入 `SessionEventMap`,也不会到达 `deriveMessages()`。header 通过 `session.header` 附加到 `Session` 上。
|
|
47
|
+
|
|
48
|
+
源码:[`packages/core/session/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/session/src/types.ts)
|
|
49
|
+
|
|
50
|
+
```ts type-equiv
|
|
51
|
+
/**
|
|
52
|
+
* Immutable validated storage metadata, kept outside the conversation event log.
|
|
53
|
+
*/
|
|
54
|
+
interface SessionHeader {
|
|
55
|
+
/**
|
|
56
|
+
* On-disk format version, stamped from {@link SESSION_FORMAT_VERSION} when the
|
|
57
|
+
* session is created. A persistence backend rejects any other version on load
|
|
58
|
+
* (no migration — see the constant).
|
|
59
|
+
*/
|
|
60
|
+
readonly version: number
|
|
61
|
+
/** The session's id (mirrors the {@link Session}'s id). */
|
|
62
|
+
readonly id: SessionId
|
|
63
|
+
/** Non-negative safe-integer Unix epoch milliseconds when the session was created. */
|
|
64
|
+
readonly createdAt: number
|
|
65
|
+
/** Absolute working directory the session was created in (if any). */
|
|
66
|
+
readonly cwd?: string
|
|
67
|
+
/** The session this one was forked from (seed lineage), if any. */
|
|
68
|
+
readonly parentSession?: SessionId
|
|
69
|
+
/**
|
|
70
|
+
* How many leading events were inherited through a seed. Persisting this
|
|
71
|
+
* boundary lets resume and replay distinguish parent history from child work.
|
|
72
|
+
*/
|
|
73
|
+
readonly seedLength?: number
|
|
74
|
+
/**
|
|
75
|
+
* Coarse product classification for a session created as a subagent child.
|
|
76
|
+
* This is presentation metadata, not proof that the child is continuable.
|
|
77
|
+
*/
|
|
78
|
+
readonly origin?: 'subagent'
|
|
79
|
+
/**
|
|
80
|
+
* Delegation depth: absent (zero) for a top-level session, parent depth + 1
|
|
81
|
+
* for a subagent child. Persisted so a recursion budget survives restart and
|
|
82
|
+
* resume — a runtime-only depth would reset a resumed child to top-level.
|
|
83
|
+
*/
|
|
84
|
+
readonly delegationDepth?: number
|
|
85
|
+
/**
|
|
86
|
+
* Id of the agent preset this session's agent was composed from, when the
|
|
87
|
+
* deployment composes per session. Durable because the preset decides the
|
|
88
|
+
* session's tools and prompt: a resume that restored a different composition
|
|
89
|
+
* would replay history the model can no longer act on.
|
|
90
|
+
*/
|
|
91
|
+
readonly agentPreset?: string
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## 格式拒绝:本构建无法可靠读取的日志
|
|
96
|
+
|
|
97
|
+
后端用 `SessionFormatUnsupportedError` 拒绝无法可靠解读的日志,它与 `SessionPersistenceCorruptionError` 区分,因为数据没有损坏。header 的 `version` 比 `SESSION_FORMAT_VERSION` 新时,消息说明方向("由更新的 harness 写入,请升级 harness 后打开");比它旧时说明本构建没有升级路径。经过 legacy 形状归一化后,本构建生成词汇表(`KNOWN_SESSION_EVENT_TYPES`,由 `gen-persistence-catalog` 生成)之外的事件类型同样被拒绝,除非该事件的信封带 `ignorable: true`:静默跳过一个不认识的必需事件可能改变日志其余部分的解读方式。后端为每个会话保留独立文件时,消息附上原始日志路径,被拒绝的文本仍然可读。JSONL 后端直接从原始 header 行拒绝外来版本,先于当前 header 形状校验和任何事件行解码,因此结构完全不同的未来格式仍会报告升级方向,绝不会报"损坏";SQLite 则先由自己的 `SCHEMA_VERSION` pragma 把关整个文件的结构。设计理由与推迟建设的升级器链见 [session-log 版本机制 Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md)。
|
|
98
|
+
|
|
99
|
+
## `CreateSessionOptions`:seed 与元数据
|
|
100
|
+
|
|
101
|
+
通过 store 创建 `Session` 时会接收 `seed`(初始回放或 fork 历史)与 `meta`(store 整合进 `SessionHeader` 的存储层字段)。store 填充 `version`/`id` 并为 `createdAt` 提供默认值;调用方可以提供已校验的绝对 `cwd`、`parentSession` 谱系、`seedLength` 种子边界、可选的粗粒度 `origin`、`delegationDepth`、用于组装该 agent(智能体)的 `agentPreset` 以及已有的 `createdAt`。`origin: 'subagent'` 让产品导航能够隐藏重复的 child 行;它不证明描述符有效,也不证明 child 可以恢复。
|
|
102
|
+
|
|
103
|
+
```ts type-equiv
|
|
104
|
+
/**
|
|
105
|
+
* Options for creating a {@link Session} via the store. `seed` replays/forks
|
|
106
|
+
* an existing event log; `meta` carries the caller-supplied storage fields the
|
|
107
|
+
* store folds into a {@link SessionHeader}.
|
|
108
|
+
*/
|
|
109
|
+
interface CreateSessionOptions {
|
|
110
|
+
/** Initial replay or fork history supplied at construction. */
|
|
111
|
+
readonly seed?: readonly SessionEvent[]
|
|
112
|
+
/**
|
|
113
|
+
* Storage metadata read once before publication. `seedLength` is explicit
|
|
114
|
+
* because a resumed seed contains the full stored log, not only its inherited prefix.
|
|
115
|
+
*/
|
|
116
|
+
readonly meta?: {
|
|
117
|
+
readonly cwd?: string
|
|
118
|
+
readonly parentSession?: SessionId
|
|
119
|
+
readonly createdAt?: number
|
|
120
|
+
readonly seedLength?: number
|
|
121
|
+
readonly origin?: 'subagent'
|
|
122
|
+
readonly delegationDepth?: number
|
|
123
|
+
readonly agentPreset?: string
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
因此,回放/fork 的调用方式为 `ctx.sessions.create(id, { seed: seedEvents })`;将一个*持久化*会话恢复为活跃 agent 的调用方式为 `ctx.agents.resume({ resumeSessionId })`。
|
|
129
|
+
|
|
130
|
+
## `SessionRawArtifact`——逐字存储工件文本
|
|
131
|
+
|
|
132
|
+
后端为单个会话自持的工件文本,与其持久化写入的字节逐字一致(按物理编码解码)。`readRaw` 返回它而不从解析后事件重建,因此后端特定的序列化(chunk 打包、键序、换行)得以保留。Consumer 须先检查 `supportsRawArtifacts`:`false` 表示后端不提供此能力(如 SQLite),而 `readRaw(...) === undefined` 表示受支持的后端没有该会话的已实体化工件。
|
|
133
|
+
|
|
134
|
+
```ts type-equiv
|
|
135
|
+
/** A backend's own raw artifact text for one session, verbatim. */
|
|
136
|
+
interface SessionRawArtifact {
|
|
137
|
+
/** The session header parsed from the artifact's own first line. */
|
|
138
|
+
readonly meta: SessionHeader
|
|
139
|
+
/** The artifact's base filename on disk, without any physical encoding suffix. */
|
|
140
|
+
readonly filename: string
|
|
141
|
+
/** The artifact's full text content, decoded from the backend's physical encoding. */
|
|
142
|
+
readonly content: string
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 准备与恢复所有权
|
|
147
|
+
|
|
148
|
+
`SessionStore.prepare()` 接收普通创建选项,或通过 `RestoredSessionOptions` 转移所有权的全新的持久化对象图。恢复分支会就地验证并冻结转移来的 header 与事件,因此调用方不得保留可变别名。`SessionPreparation` 随后持有该精确的未发布 Session,直至发布或回滚;dispose 是同步且幂等的。持久化检查只暴露 `SessionInspection`,即从同一个已准备 Session 借用的不可变逻辑视图。
|
|
149
|
+
|
|
150
|
+
```ts type-equiv
|
|
151
|
+
/**
|
|
152
|
+
* Fresh storage values transferred to {@link SessionStore.prepare} without a
|
|
153
|
+
* second serialization copy. Callers retain no mutable aliases.
|
|
154
|
+
*/
|
|
155
|
+
interface RestoredSessionOptions {
|
|
156
|
+
/** Fresh detached storage events to validate and freeze in place. */
|
|
157
|
+
readonly seed: SessionEvent[]
|
|
158
|
+
/** Fresh detached storage metadata to validate and freeze in place. */
|
|
159
|
+
readonly meta: SessionHeader
|
|
160
|
+
/** Select the persistence ownership-transfer path. */
|
|
161
|
+
readonly seedSource: 'persistence'
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```ts type-equiv
|
|
166
|
+
/** Inputs accepted while constructing an unpublished Session. */
|
|
167
|
+
type PrepareSessionOptions =
|
|
168
|
+
| (CreateSessionOptions & { readonly seedSource?: undefined })
|
|
169
|
+
| RestoredSessionOptions
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
```ts type-equiv
|
|
173
|
+
/** Options for a preparation whose provider retains unpublished state. */
|
|
174
|
+
interface SessionPreparationOptions {
|
|
175
|
+
/** Release provider-owned state when the Session was not published. */
|
|
176
|
+
readonly release?: () => void
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
```ts public-api
|
|
181
|
+
/**
|
|
182
|
+
* One exact unpublished Session and the provider state that keeps it usable.
|
|
183
|
+
* Disposal is synchronous and idempotent. Providers decide whether release
|
|
184
|
+
* returns the Session to a cache or discards it; publication may consume that
|
|
185
|
+
* state before disposal, making the callback a no-op.
|
|
186
|
+
*/
|
|
187
|
+
declare class SessionPreparation implements Disposable {
|
|
188
|
+
/** The exact Session to use for setup and publication. */
|
|
189
|
+
readonly session: Session;
|
|
190
|
+
/**
|
|
191
|
+
* Wrap an unpublished Session in one preparation lifetime.
|
|
192
|
+
* @param session - exact unpublished Session.
|
|
193
|
+
* @param options - optional provider release behavior.
|
|
194
|
+
* @returns a preparation disposed after publication or rollback.
|
|
195
|
+
*/
|
|
196
|
+
static create(session: Session, options?: SessionPreparationOptions): SessionPreparation;
|
|
197
|
+
/** Release provider state once when this preparation leaves its caller. */
|
|
198
|
+
[Symbol.dispose](): void;
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```ts type-equiv
|
|
203
|
+
/** Immutable logical session prepared from persistence or a live owner. */
|
|
204
|
+
interface SessionInspection {
|
|
205
|
+
/** Validated immutable session metadata. */
|
|
206
|
+
readonly meta: SessionHeader
|
|
207
|
+
/** Validated contiguous logical event log. */
|
|
208
|
+
readonly events: readonly SessionEvent[]
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 轻量源修订号
|
|
213
|
+
|
|
214
|
+
派生状态的消费方会在加载完整事件日志之前比较一个低开销的不透明修订号。其表示由持久化后端拥有,并随 append 或会修改数据的 load 修复以事务方式改变;调用方仅比较修订号是否相等。
|
|
215
|
+
|
|
216
|
+
```ts type-equiv
|
|
217
|
+
/**
|
|
218
|
+
* Backend-owned token that identifies both one storage source and one revision
|
|
219
|
+
* of a persisted session log.
|
|
220
|
+
*/
|
|
221
|
+
type SessionPersistenceRevision = Branded<'SessionPersistenceRevision'>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```ts type-equiv
|
|
225
|
+
/** Lightweight immutable source identity returned without loading a full log. */
|
|
226
|
+
interface SessionPersistenceSnapshot {
|
|
227
|
+
/** Detached metadata for one materialized session. */
|
|
228
|
+
header: SessionHeader
|
|
229
|
+
/** Opaque source-qualified token that changes whenever this stored log changes. */
|
|
230
|
+
revision: SessionPersistenceRevision
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 后端
|
|
235
|
+
|
|
236
|
+
两者都实现同一个抽象 `SessionPersistence`(在 `SessionEvent` 上执行 locate/create/append/prepare/load/inspect/readFrom/list/listSnapshots,观察方法可选支持取消),并通过共享的 `runPersistenceContract` 套件:
|
|
237
|
+
|
|
238
|
+
- **[dsh-session-persistence-jsonl](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-jsonl)**——每个会话一份仅追加的逻辑 JSONL 日志,默认存储为带 checksum 的连续 Zstandard frame,也可配置为原始行;支持崩溃安全的原子写入、被中断轮次的恢复以及读取/回放路径。
|
|
239
|
+
- **[dsh-session-persistence-sqlite](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/session/session-persistence-sqlite)**:基于 `node:sqlite`,每个 `SessionEvent` 一行。行字段 `(session_id, seq, type, time, data, source_event_seqs, surface_op)` 与事件 1:1 映射(包含可选的 surface 元数据),因此没有需要保持同步的并行持久化 schema。
|
|
240
|
+
|
|
241
|
+
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
242
|
+
|
|
243
|
+
<a id="cordis-surface"></a>
|
|
244
|
+
|
|
245
|
+
## Cordis API
|
|
246
|
+
|
|
247
|
+
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
|
248
|
+
|
|
249
|
+
<a id="ctxsessionpersistence--sessionpersistence-abstract-seam"></a>
|
|
250
|
+
|
|
251
|
+
### `ctx.sessionPersistence` — `SessionPersistence` (abstract seam)
|
|
252
|
+
|
|
253
|
+
Durable append-only session storage. Implementations preserve contiguous, losslessly JSON-serializable events; append resolves only after durability, and load balances a complete interrupted tail without rewriting committed events.
|
|
254
|
+
|
|
255
|
+
```ts cordis-catalog
|
|
256
|
+
/**
|
|
257
|
+
* Resolve this backend's independent local artifact for a session without
|
|
258
|
+
* reading, creating, flushing, or otherwise materializing it. Backends such
|
|
259
|
+
* as SQLite that do not own one artifact per session return `undefined`.
|
|
260
|
+
* @param meta - the immutable session header whose artifact is requested.
|
|
261
|
+
* @returns the backend-specific absolute location, when one exists.
|
|
262
|
+
*/
|
|
263
|
+
abstract locate(meta: SessionHeader): SessionLocation | undefined
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Read a session's backend-owned artifact text verbatim — the exact durable
|
|
267
|
+
* bytes the backend wrote (decoded from its physical encoding, e.g. a
|
|
268
|
+
* decompressed JSONL). The returned `content` is the raw text, not a
|
|
269
|
+
* reconstruction from parsed events, so it preserves backend-specific
|
|
270
|
+
* serialization (chunk packing, key order, line breaks). Callers first test
|
|
271
|
+
* {@link supportsRawArtifacts}; `undefined` then means only that the requested
|
|
272
|
+
* session has no materialized artifact.
|
|
273
|
+
* @param _id - the persisted session to read (unused by the default: no
|
|
274
|
+
* per-session artifact).
|
|
275
|
+
* @param signal - optional cancellation for backend read work.
|
|
276
|
+
* @returns the raw artifact plus its parsed header, or `undefined` when the
|
|
277
|
+
* session is absent.
|
|
278
|
+
* @throws when this backend does not expose per-session raw artifacts.
|
|
279
|
+
*/
|
|
280
|
+
readRaw(_id: SessionId, signal?: AbortSignal): Promise<SessionRawArtifact | undefined>
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Register a new session's metadata. A backend MAY defer the physical write
|
|
284
|
+
* until the first {@link append} (lazy materialization), in which case a
|
|
285
|
+
* created-but-never-appended session is absent from {@link list}
|
|
286
|
+
* — abandoned sessions leave nothing behind.
|
|
287
|
+
* @param meta - the immutable header (id, version, cwd, lineage) to record.
|
|
288
|
+
*/
|
|
289
|
+
abstract create(meta: SessionHeader): Promise<void>
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Durably persist a batch of events. Honors the append-only and contiguous-
|
|
293
|
+
* seq contracts: the first event's `seq` MUST equal the stored next-seq
|
|
294
|
+
* (after `load` has durably closed any interrupted turn). Rejects non-JSON-
|
|
295
|
+
* serializable `event.data` with an error naming the offending event type.
|
|
296
|
+
* @param id - the session the batch belongs to.
|
|
297
|
+
* @param events - the contiguous batch to persist, in seq order.
|
|
298
|
+
*/
|
|
299
|
+
abstract append(id: SessionId, events: readonly SessionEvent[]): Promise<void>
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Prepare the exact unpublished Session used by resume. Implementations may
|
|
303
|
+
* reuse object graphs retained by an earlier {@link inspect} after confirming
|
|
304
|
+
* their durable revision is still current; disposal releases an unpublished
|
|
305
|
+
* reservation. Revision retries require the durable log to remain unchanged
|
|
306
|
+
* for one read/check round trip; continuous external writers may delay completion.
|
|
307
|
+
* @param id - persisted session to prepare.
|
|
308
|
+
* @param signal - optional cancellation for preparation work.
|
|
309
|
+
* @returns one owned unpublished Session preparation.
|
|
310
|
+
*/
|
|
311
|
+
async prepare(id: SessionId, signal?: AbortSignal): Promise<SessionPreparation>
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Load an immutable balanced logical view and commit any required cold
|
|
315
|
+
* recovery. A complete interrupted final turn is preserved and durably
|
|
316
|
+
* closed with missing tool errors plus any open step and turn boundaries;
|
|
317
|
+
* only a torn final record is discarded. Unknown versions and corruption in
|
|
318
|
+
* the committed prefix reject. Implementations MUST NOT crash-repair an
|
|
319
|
+
* identity still bound to a live Session: a balanced live log may return as a
|
|
320
|
+
* durable snapshot, while an open live turn rejects. Returned values may be
|
|
321
|
+
* shared with immutable live or prepared state and must not be mutated.
|
|
322
|
+
* Revision-based implementations may wait for one stable read/check round trip.
|
|
323
|
+
* @param id - the persisted session to reload.
|
|
324
|
+
* @returns the header and a log ending on a balanced `turn/end`.
|
|
325
|
+
*/
|
|
326
|
+
abstract load(id: SessionId): Promise<SessionInspection>
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Inspect an immutable logical session without committing recovery or
|
|
330
|
+
* publishing it. A cold complete interrupted turn receives synthetic closers
|
|
331
|
+
* in memory and a torn physical tail remains untouched. An already-live
|
|
332
|
+
* Session instead yields its current immutable snapshot, which may contain an
|
|
333
|
+
* open turn and its `session/end-seed` boundary. Coordinator-backed
|
|
334
|
+
* implementations retain the exact cold unpublished Session for bounded
|
|
335
|
+
* reuse by a later {@link prepare}. A stale ready source is reloaded; a source
|
|
336
|
+
* already committing or reserved for resume remains exclusive, and inspection
|
|
337
|
+
* may borrow its immutable view. Callers borrow only the immutable header and
|
|
338
|
+
* log. Continuous external writers may delay revision convergence.
|
|
339
|
+
* @param id - the persisted session to inspect.
|
|
340
|
+
* @param signal - optional cancellation for queued and backend read work.
|
|
341
|
+
* @returns the validated header and current logical event log.
|
|
342
|
+
*/
|
|
343
|
+
abstract inspect(id: SessionId, signal?: AbortSignal): Promise<SessionInspection>
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Read the stored events from `fromSeq` onward — the read-from-seq
|
|
347
|
+
* primitive for read models that resume from a watermark (e.g. a persisted
|
|
348
|
+
* projection cache folding only the tail past its checkpoint). Unlike
|
|
349
|
+
* {@link inspect}, it is a detached physical suffix read: no preparation
|
|
350
|
+
* cache, torn-tail truncation, synthetic closers, or coordinator-state
|
|
351
|
+
* publication. Only events from the valid contiguous stored prefix are
|
|
352
|
+
* returned, so a torn fragment never reaches the caller. `fromSeq` at or
|
|
353
|
+
* beyond the stored prefix returns an empty event list (never an error).
|
|
354
|
+
* Backends whose medium can seek by seq
|
|
355
|
+
* (SQLite) read only the suffix; sequential media (JSONL, both encodings)
|
|
356
|
+
* still parse the whole artifact and skip forward — the primitive bounds
|
|
357
|
+
* what is RETURNED and refolded, not every backend's physical read.
|
|
358
|
+
* @param id - the persisted session to read.
|
|
359
|
+
* @param fromSeq - first event seq to include; a non-negative safe integer.
|
|
360
|
+
* @param signal - optional cancellation for queued and backend read work.
|
|
361
|
+
* @returns the header and the stored events with `seq >= fromSeq`.
|
|
362
|
+
*/
|
|
363
|
+
abstract readFrom(id: SessionId, fromSeq: number, signal?: AbortSignal): Promise<{ meta: SessionHeader; events: SessionEvent[] }>
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Lightweight listing from metadata, without a full-log parse.
|
|
367
|
+
* @param signal - optional cancellation for backend listing work.
|
|
368
|
+
* @returns one header per materialized session.
|
|
369
|
+
*/
|
|
370
|
+
abstract list(signal?: AbortSignal): Promise<SessionHeader[]>
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* List materialized sessions with cheap per-log change tokens.
|
|
374
|
+
*
|
|
375
|
+
* Repeated observations of an unchanged log return the same revision. A
|
|
376
|
+
* successful mutating {@link load} repair changes the next listed revision.
|
|
377
|
+
* Revisions also distinguish independently backed stores so backend-local
|
|
378
|
+
* counters cannot compare equal across different persistence sources.
|
|
379
|
+
* @param signal - optional cancellation for backend snapshot-listing work.
|
|
380
|
+
* @returns one header and opaque revision per materialized session without loading full logs.
|
|
381
|
+
*/
|
|
382
|
+
abstract listSnapshots(signal?: AbortSignal): Promise<SessionPersistenceSnapshot[]>
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Types: [SessionEvent](./session.md) · [SessionId](./core.md)
|
|
386
|
+
|
|
387
|
+
Source: [`packages/session/session-persistence/src/index.ts:84`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-persistence/src/index.ts)
|
|
388
|
+
<!-- END GENERATED cordis-surface -->
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
editSource: "docs/subsystems/plan.zh.md"
|
|
3
|
+
outline: [2,3]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 计划模式
|
|
7
|
+
|
|
8
|
+
计划模式是 [dsh-plan-mode](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/plan/plan-mode) 拥有的、记录到日志的逐 agent(智能体)协作状态(`ctx.planMode`,`PlanModeController`):激活期间,每个模型请求都会包含一段部署持有的指引。计划模式是**软性指引**。[沙箱模式](./sandbox.md)与[审批策略](./approval.md)分别强制限制;两者都不读写计划状态,因此部署需要分别配置它们。该包是可选项,agent loop(智能体循环)不依赖它。它贡献 `plan:policy` 提示词段落,并注册 `exit_plan_mode` 工具和 `/plan` 命令。[设计说明](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/simplification/2026-07-22-plan-specific-collaboration-state.md)负责决策依据;[包 README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/README.md)负责模型体验与限制细节。
|
|
9
|
+
|
|
10
|
+
源码:[`packages/plan/plan-mode/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/src/index.ts)
|
|
11
|
+
|
|
12
|
+
## 已记录状态与恢复
|
|
13
|
+
|
|
14
|
+
`plan/mode`(`{ active: boolean }`)是仅记日志、整值替换的[会话事件](./session.md):持久且可回放,绝不进入模型 transcript(文本记录)。`foldPlanMode(events, end?)` 返回前缀中最后一条已记录值,没有时返回 `false`:生效状态始终是会话日志的纯折叠,因此恢复、fork 与压缩(compaction)无需实时镜像即可将其复原,UI 通过 `session/event` 观察已提交的切换。完整事件声明见[持久化日志事件目录](../persistence-catalog.md)。
|
|
15
|
+
|
|
16
|
+
## 待生效选择与 pre-step 追加
|
|
17
|
+
|
|
18
|
+
由于每个会话事件都位于轮次之内,用户选择会保持待生效状态,直到下一个被接受的轮内 pre-step 在派生请求之前追加该选择,无论该 pre-step 位于哪个轮次。选择不会强制续行,因此在某轮最后一个被接受的 pre-step 之后作出的选择会在之后的轮次追加。`set(agent, active)` 记录待生效选择(目标值与已记录或已在等待的状态相同时不做任何事),`get(agent)` 返回 `{ active: boolean; pending?: boolean }`:用于组装当前步骤的已记录状态,以及等待追加的已选状态。
|
|
19
|
+
|
|
20
|
+
agent 运行时,唯一的追加点是前置(prepend)注册的 `agent/pre-step` 监听器。它会观察每个候选请求步骤,包括第 1 轮第 1 步和请求恢复重试;它先调用下游监听器,只在下游接受该步骤后追加。提示词准入发生在轮次开启之前,无法追加 `plan/mode`,因此在提示词处作出的选择由它开启的轮次内第一个被接受的 pre-step 追加。追加失败不能阻塞轮次,且该选择会继续等待之后被接受的轮内 pre-step。追加用户选择时还会记录一条插件来源的 `user/message` 通知,但仅当最后记录的请求头描述的是另一种状态时才记录,因此模型恰好在上下文变化时收到通知,且绝不重复。在某轮最后一个被接受的 pre-step 之后作出的选择只存在于进程内;如果进程在另一个被接受的轮内 pre-step 之前退出,该选择会丢失([README 限制](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/README.md#known-limitations-and-deferred-work))。
|
|
21
|
+
|
|
22
|
+
## 配置
|
|
23
|
+
|
|
24
|
+
```ts type-equiv
|
|
25
|
+
/** Deployment-owned plan guidance. */
|
|
26
|
+
interface PlanModeConfig {
|
|
27
|
+
/** Guidance rendered as the `plan:policy` prompt section while plan mode is active. */
|
|
28
|
+
section: string
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`section` 缺失、为空白或不是字符串,以及任何未知键,都会在插件加载时失败,而不是被忽略。计划模式激活期间,确切的 `section` 文本以 order 50 渲染为 `plan:policy` [系统提示词段落](./system-prompt.md);未激活的计划模式不贡献任何文本。
|
|
33
|
+
|
|
34
|
+
## 退出工具与 `/plan` 命令
|
|
35
|
+
|
|
36
|
+
[`exit_plan_mode`](../tool-catalog.md#deepseek-aidsh-plan-mode) 在计划模式未激活时仍保持注册,因此进入或离开计划模式只改变提示词段落,绝不改变请求的工具目录;在计划模式之外执行会失败。在计划模式中,它要求一份以 `#` 标题开头的完整 markdown 计划,并通过[用户交互 seam](./user-questions.md) 呈交评审。批准返回 `{ approved: true }`,并记录一个静默(不叙述)的待生效退出,由下一个被接受的轮内 pre-step 追加。因此,计划指引在 assistant 当前这批工具调用的剩余部分继续生效,而工具结果本身会报告这次转换。「继续规划」则是一次携带用户反馈的失败调用,模型据此修订并再次呈交;评审期间交互通道缺失或服务重载同样使调用失败,而不是静默离开计划模式。
|
|
37
|
+
|
|
38
|
+
当 [`ctx.commands`](./commands.md) 被组合时,插件注册 `/plan [off|message]`:单独的 `/plan` 选择计划模式;任何其他非空消息先选择计划模式,再通过 `agent.steer()` 提交该文本,使其在计划指引下成为下一步骤的普通已记录用户消息;确切参数 `off` 选择未激活,这还会在待生效条目被追加并对请求可见之前将其取消。
|
|
39
|
+
|
|
40
|
+
## 服务
|
|
41
|
+
|
|
42
|
+
`ctx.planMode` 拥有已记录的计划状态,在步骤开始时应用并叙述选中的状态,还拥有 `plan:policy` 段落、`/plan` 命令和稳定注册的退出工具;`get`/`set` 签名见生成的[服务目录](#ctxplanmode--planmodecontroller)。
|
|
43
|
+
|
|
44
|
+
<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
|
|
45
|
+
|
|
46
|
+
<a id="cordis-surface"></a>
|
|
47
|
+
|
|
48
|
+
## Cordis API
|
|
49
|
+
|
|
50
|
+
Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
|
|
51
|
+
|
|
52
|
+
<a id="ctxplanmode--planmodecontroller"></a>
|
|
53
|
+
|
|
54
|
+
### `ctx.planMode` — `PlanModeController`
|
|
55
|
+
|
|
56
|
+
`ctx.planMode`: owns logged plan state, applies and narrates selected state at step start, the `plan:policy` section, the `/plan` command, and the stable exit tool. UIs observe committed flips through `session/event`; there is no live mirror.
|
|
57
|
+
|
|
58
|
+
```ts cordis-catalog
|
|
59
|
+
/**
|
|
60
|
+
* Read the logged plan state and any selected state awaiting the next
|
|
61
|
+
* accepted in-turn pre-step.
|
|
62
|
+
*
|
|
63
|
+
* @param agent The agent to read.
|
|
64
|
+
* @returns Current logged state plus a pending selection, when present.
|
|
65
|
+
*/
|
|
66
|
+
get(agent: Agent): { active: boolean; pending?: boolean }
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Select whether plan mode should be active. Between turns the method
|
|
70
|
+
* appends the change immediately because no in-turn pre-step will run until
|
|
71
|
+
* another prompt starts a turn. The open-turn fold is the idle signal:
|
|
72
|
+
* agent status stays `running` through post-turn checkpointing, when no
|
|
73
|
+
* further in-turn pre-step runs. During an open turn the selection remains
|
|
74
|
+
* pending until the next accepted in-turn pre-step. Repeated selection of
|
|
75
|
+
* the current or already-pending state is a no-op.
|
|
76
|
+
*
|
|
77
|
+
* @param agent The agent to switch.
|
|
78
|
+
* @param active Whether plan mode should be active.
|
|
79
|
+
* @returns what happened: `committed` (logged now), `queued` (awaiting the
|
|
80
|
+
* next accepted in-turn pre-step), `cancelled` (an opposite pending selection
|
|
81
|
+
* was cleared; the logged state already matches), or `noop` (already in that
|
|
82
|
+
* state).
|
|
83
|
+
*/
|
|
84
|
+
set(agent: Agent, active: boolean): 'committed' | 'queued' | 'cancelled' | 'noop'
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Types: [Agent](./core.md)
|
|
88
|
+
|
|
89
|
+
Source: [`packages/plan/plan-mode/src/index.ts:184`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/src/index.ts)
|
|
90
|
+
<!-- END GENERATED cordis-surface -->
|