@deepseek-ai/dsh-session 0.2.0-rc.2 → 0.2.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +15 -12
- package/README.md +16 -5
- package/README.zh.md +16 -5
- package/lib/index.js +136 -20
- package/lib/types/index.d.ts +51 -7
- package/lib/types/index.js +122 -7
- package/lib/types/known-event-types.js +1 -0
- package/lib/types/surface.js +2 -8
- package/lib/types/types.d.ts +47 -16
- package/lib/types/types.js +14 -14
- package/package.json +10 -16
- package/lib/invariant.js +0 -174
- package/lib/types/invariant.d.ts +0 -18
- package/lib/types/invariant.js +0 -207
package/README.i18n.yaml
CHANGED
|
@@ -24,8 +24,11 @@
|
|
|
24
24
|
en: aa5f1951ecf3ac0c
|
|
25
25
|
zh: 62a599ace8f2bf15
|
|
26
26
|
/deepseek-ai-dsh-session/use-this-package/read-the-log:
|
|
27
|
-
en:
|
|
28
|
-
zh:
|
|
27
|
+
en: c4bf3103b9762b6c
|
|
28
|
+
zh: 369c734bb20de2ea
|
|
29
|
+
/deepseek-ai-dsh-session/use-this-package/write-experimental-plugin-records:
|
|
30
|
+
en: 6c758f98535b734c
|
|
31
|
+
zh: ac54342937477f37
|
|
29
32
|
/deepseek-ai-dsh-session/use-this-package/fork-a-session:
|
|
30
33
|
en: 1c40d17a786059d3
|
|
31
34
|
zh: 81320ce118977c65
|
|
@@ -42,17 +45,17 @@
|
|
|
42
45
|
en: bbfb53c50100ab13
|
|
43
46
|
zh: 303a8ee47f4f656a
|
|
44
47
|
/deepseek-ai-dsh-session/understand-the-implementation/source-map:
|
|
45
|
-
en:
|
|
46
|
-
zh:
|
|
48
|
+
en: c596a8f74b4f1b79
|
|
49
|
+
zh: a29f23c4c1d1ff75
|
|
47
50
|
/deepseek-ai-dsh-session/understand-the-implementation/append-validation:
|
|
48
51
|
en: 5c09583bc8e1ffc6
|
|
49
52
|
zh: 3b25552de2d1f9b6
|
|
50
53
|
/deepseek-ai-dsh-session/understand-the-implementation/shared-recovery:
|
|
51
|
-
en:
|
|
52
|
-
zh:
|
|
54
|
+
en: 160b35afd9d866e4
|
|
55
|
+
zh: cd1021e0ef567f87
|
|
53
56
|
/deepseek-ai-dsh-session/understand-the-implementation/derived-history:
|
|
54
|
-
en:
|
|
55
|
-
zh:
|
|
57
|
+
en: 4a9861492a8c3869
|
|
58
|
+
zh: e9566de647206230
|
|
56
59
|
/deepseek-ai-dsh-session/understand-the-implementation/the-request-header:
|
|
57
60
|
en: 1349f47bea4dab00
|
|
58
61
|
zh: 20cc03f2c87ec492
|
|
@@ -78,8 +81,8 @@
|
|
|
78
81
|
en: 9c2efc3e9064e3c4
|
|
79
82
|
zh: 9a7783991b322750
|
|
80
83
|
/deepseek-ai-dsh-session/model-experience/tool-result-recovery-and-fork-results/what-the-model-sees:
|
|
81
|
-
en:
|
|
82
|
-
zh:
|
|
84
|
+
en: d15c350efc66e832
|
|
85
|
+
zh: b769ba23dbb374e7
|
|
83
86
|
/deepseek-ai-dsh-session/model-experience/tool-result-recovery-and-fork-results/token-effect:
|
|
84
87
|
en: 1339facbd3d7cee0
|
|
85
88
|
zh: 9d392a053ef90032
|
|
@@ -99,8 +102,8 @@
|
|
|
99
102
|
en: 5eb30cfb410d52c0
|
|
100
103
|
zh: da56365b8ab896da
|
|
101
104
|
/deepseek-ai-dsh-session/known-limitations-and-deferred-work:
|
|
102
|
-
en:
|
|
103
|
-
zh:
|
|
105
|
+
en: 45afe96a4e252db9
|
|
106
|
+
zh: 920bcc011823817b
|
|
104
107
|
/deepseek-ai-dsh-session/known-limitations-and-deferred-work/dev-note:
|
|
105
108
|
en: e67f633dc6fe7773
|
|
106
109
|
zh: 3bb0c20c93f16f98
|
package/README.md
CHANGED
|
@@ -63,6 +63,18 @@ Append, seed/restore, and event adoption/snapshot reject any `header.system` and
|
|
|
63
63
|
|
|
64
64
|
Session log positions use two numeric types. `SessionSeq` identifies an existing event or inclusive event watermark; `SessionLogOffset` identifies a gap, prefix length, or read boundary and may equal the event count. `SessionSeqCursor` adds the `-1` “no event yet” value, while `OptionalSessionSeq` uses `null` when absence is data. The constructors validate non-negative safe integers, and the brands disappear at runtime, so durable JSON and wire values remain ordinary numbers.
|
|
65
65
|
|
|
66
|
+
<a id="write-experimental-plugin-records"></a>
|
|
67
|
+
|
|
68
|
+
### Write experimental plugin records
|
|
69
|
+
|
|
70
|
+
`appendPluginRecord(session, type, data)` appends one plugin record for a package under `packages/experimental/`; the `verify-plugin-record-callers` check rejects any other production caller in this repository. Plugins outside this repository must not call it either, although no repository check can inspect them.
|
|
71
|
+
|
|
72
|
+
Declare each record in `PluginRecordMap` through `@deepseek-ai/dsh-session/types`, with a description and an explicit payload type annotation in the owning experimental package's `src/`. Names use `plugin:<owner>/<record>`, where `owner` is the suffix of the package name `@deepseek-ai/dsh-experimental-<owner>`; for example, `plugin:pi-extensions/entry`. TypeScript checks each name and payload against its declaration; the writer's runtime JSON snapshot rejects values that cannot be preserved losslessly. Put extension-defined or other dynamic names inside the payload of a declared record.
|
|
73
|
+
|
|
74
|
+
The [experimental persistence catalog](../../../docs/experimental-persistence-catalog.md) lists current plugin-record declarations with their owners, descriptions, payload type annotations, and source files. These declarations remain separate from `SessionEventMap`, expanded persistence schemas, released type history, and `KNOWN_SESSION_EVENT_TYPES`. Records carry `ignorable: true`: a build that does not recognize one retains and skips it on read. Records never enter the model-visible surface. Resume and fork carry them with the rest of the log; Session format migration keeps them on a best-effort basis.
|
|
75
|
+
|
|
76
|
+
`pluginRecordOf(event)` returns an event as a record, or `undefined` for any other event; a `ctx.sessionProjections` unit that passes each event to it rebuilds plugin state on resume. Its `data` remains `unknown` even when the current map declares the name. The owner validates it before use because earlier builds can write different payloads, and the V3-to-V4 format edge can rename an unknown ignorable V3 event into the same `plugin:` namespace. Removing or renaming a declaration does not discard stored records. The [ignorable events decision](../../../.agents/notes/implemented/architecture/2026-08-30-retain-ignorable-external-session-events.md) owns the compatibility policy.
|
|
77
|
+
|
|
66
78
|
### Fork a session
|
|
67
79
|
|
|
68
80
|
`ctx.sessions.fork(source, boundary?, childSessionId?)` copies an exact inclusive event prefix (default: the last event) from a live source. `buildForkSeed` in `dsh-session/fork` places an inherited marker after the copied events, adds missing error tool results only for the open step, and closes that step and turn with a `forked` reason. Closed steps and turns remain unchanged, including historical missing results. The marker and closers belong to the child; `inheritedEventCount` counts only the copied prefix.
|
|
@@ -101,7 +113,6 @@ The package is built on event sourcing: a `Session` is an append-only log of typ
|
|
|
101
113
|
| [`src/request-header.ts`](src/request-header.ts) | `request/header` folding and reconstruction |
|
|
102
114
|
| [`dsh-util-values`](../../util/values/README.md) | Shared lossless JSON validation and detached snapshots |
|
|
103
115
|
| [`src/repair.ts`](src/repair.ts) | Shared tool-result recovery for failed steps, interrupted logs, and fork seeds |
|
|
104
|
-
| [`src/invariant.ts`](src/invariant.ts) | Invariant companion: seq, turn/step enclosure, tool call/result pairing |
|
|
105
116
|
|
|
106
117
|
### Append validation
|
|
107
118
|
|
|
@@ -109,11 +120,11 @@ Every append uses the shared iterative `snapshotJsonValue()` pass, which reads,
|
|
|
109
120
|
|
|
110
121
|
### Shared recovery
|
|
111
122
|
|
|
112
|
-
`ToolCallRecovery` tracks unanswered requests from committed events without retaining event history. AgentLoop observes live steps; crash recovery and fork-seed construction replay their prefixes through `openTurnClosers`. Live failures and crash recovery use interrupted-result wording by default; fork construction passes the fork cause to select its distinct retry guidance. The caller appends recovery results before closing the step ([
|
|
123
|
+
`ToolCallRecovery` tracks unanswered requests from committed events without retaining event history. AgentLoop observes live steps; crash recovery and fork-seed construction replay their prefixes through `openTurnClosers`. Live failures and crash recovery use interrupted-result wording by default; fork construction passes the fork cause to select its distinct retry guidance. The caller appends recovery results before closing the step ([reference](../agent-loop/README.md)).
|
|
113
124
|
|
|
114
125
|
### Derived history
|
|
115
126
|
|
|
116
|
-
`deriveMessages()` caches deep-frozen projections and returns a fresh array per call. The surface event types (`system/message`, `developer/message`, `user/message`, `assistant/message`, `tool/result`) supply their recorded message identities and content; empty-content system and developer nodes project to no message. Plugin-owned projections change derived content without mutating recorded messages. Replacements and projection decisions invalidate the cache. Embedded Assistant streams and `assistant/attempt` events remain replay and diagnostic data only.
|
|
127
|
+
`deriveMessages()` caches deep-frozen projections and returns a fresh array per call. The surface event types (`system/message`, `developer/message`, `user/message`, `assistant/message`, `tool/result`) supply their recorded message identities and content; empty-content system and developer nodes project to no message. Plugin-owned projections change derived content without mutating recorded messages. Replacements and projection decisions invalidate the cache. Embedded Assistant streams and `assistant/attempt` events remain replay and diagnostic data only. Ordinary prompts and injected context project without automatic type- or source-specific wrappers. Producers own any framing in their recorded content.
|
|
117
128
|
|
|
118
129
|
### The request header
|
|
119
130
|
|
|
@@ -157,7 +168,7 @@ Appended surface entries preserve reusable prefixes. A `replace` operation inval
|
|
|
157
168
|
|
|
158
169
|
#### What the model sees
|
|
159
170
|
|
|
160
|
-
If recovery finds an assistant tool request with no durable `tool/call`, its synthetic `TOOL_NOT_STARTED` result says `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.` If a durable `tool/call` has no result, its `TOOL_OUTCOME_UNKNOWN` result says `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.` Fork-generated results describe only the inherited records: the parent may have started or completed a call after the selected event. `TOOL_NOT_STARTED` means the prefix contains no start record; `TOOL_OUTCOME_UNKNOWN` means it contains a start but no result. Both tell the model to retry only read-only or idempotent operations without further checks; operations with side effects require external verification or user input. See the [fork
|
|
171
|
+
If recovery finds an assistant tool request with no durable `tool/call`, its synthetic `TOOL_NOT_STARTED` result says `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.` If a durable `tool/call` has no result, its `TOOL_OUTCOME_UNKNOWN` result says `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.` Fork-generated results describe only the inherited records: the parent may have started or completed a call after the selected event. `TOOL_NOT_STARTED` means the prefix contains no start record; `TOOL_OUTCOME_UNKNOWN` means it contains a start but no result. Both tell the model to retry only read-only or idempotent operations without further checks; operations with side effects require external verification or user input. See the [fork reference](src/fork.ts).
|
|
161
172
|
|
|
162
173
|
#### Token effect
|
|
163
174
|
|
|
@@ -189,7 +200,7 @@ Logging causes no invalidation, and exact reconstruction preserves request-prefi
|
|
|
189
200
|
These limits define when the session store needs special care. They are current package constraints, not a task backlog.
|
|
190
201
|
|
|
191
202
|
- **Live-source Store API** — persisted-but-unloaded sources use the Host observation path. Fork closes only the open tail and does not repair missing results in previously closed steps.
|
|
192
|
-
- **`SESSION_FORMAT_VERSION` names the [current logical representation](../../../docs/session-format-status.md)** — the current reader rejects retired `header.system` and validates `system/message` payloads and protected-head rewrites. Historical headers and events belong to adjacent format packages; the [adjacent migration chain](../../session/session-format-catalog/README.md) converts supported history before constructing `Session`, and the write-open path publishes only the current-format successor. Equal-version unknown events require the envelope's explicit `ignorable` marker, which does not promise safe structural migration ([mechanism](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md)).
|
|
203
|
+
- **`SESSION_FORMAT_VERSION` names the [current logical representation](../../../docs/session-format-status.md)** — the current reader rejects retired `header.system` and validates `system/message` payloads and protected-head rewrites. Historical headers and events belong to adjacent format packages; the [adjacent migration chain](../../session/session-format-catalog/README.md) converts supported history before constructing `Session`, and the write-open path publishes only the current-format successor. Equal-version unknown events require the envelope's explicit `ignorable` marker, which does not promise safe structural migration ([mechanism](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.md)). [Reader compatibility](../../../.agents/notes/implemented/process/2026-10-08-session-reader-compatibility-review.md) determines whether a change needs a version increase.
|
|
193
204
|
- **`TurnEndReasonMap` omits the ACP-named `refusal` / `max_turn_requests` variants** — producer-gated: they land when an adapter or the loop first emits them.
|
|
194
205
|
- **No session tree beyond fork** — a pi-style entry tree over branched sessions is deferred unless a consumer needs more than boundary-based forking.
|
|
195
206
|
|
package/README.zh.md
CHANGED
|
@@ -63,6 +63,18 @@ session.deriveMessages() // the derived model history
|
|
|
63
63
|
|
|
64
64
|
会话日志位置使用两种数字类型。`SessionSeq` 标识已有事件或包含端点的事件水位;`SessionLogOffset` 标识间隙、前缀长度或读取边界,并且可以等于事件数量。`SessionSeqCursor` 添加 `-1` 这个“尚无事件”值,`OptionalSessionSeq` 则在缺失本身属于数据时使用 `null`。构造函数会校验非负安全整数,brand 在运行时会被擦除,因此持久 JSON 与 wire 值仍是普通数字。
|
|
65
65
|
|
|
66
|
+
<a id="write-experimental-plugin-records"></a>
|
|
67
|
+
|
|
68
|
+
### 写入实验性插件记录
|
|
69
|
+
|
|
70
|
+
`appendPluginRecord(session, type, data)` 为 `packages/experimental/` 下的包追加一条插件记录;`verify-plugin-record-callers` 检查拒绝本仓库中任何其他生产调用方。本仓库之外的插件同样不得调用它,尽管仓库检查无法检查它们。
|
|
71
|
+
|
|
72
|
+
在所属实验性包的 `src/` 中,通过 `@deepseek-ai/dsh-session/types` 的 `PluginRecordMap` 为每条记录声明描述与显式 payload 类型注解。名称使用 `plugin:<owner>/<record>`,其中 `owner` 是包名 `@deepseek-ai/dsh-experimental-<owner>` 的后缀;例如 `plugin:pi-extensions/entry`。TypeScript 按声明检查每个名称与 payload;写入方运行时的 JSON 快照拒绝无法无损保留的值。扩展自定义名称或其他动态名称放在已声明记录的 payload 中。
|
|
73
|
+
|
|
74
|
+
[实验性持久化目录](../../../docs/experimental-persistence-catalog.zh.md)列出当前插件记录声明及其所属包、描述、payload 类型注解与源文件。这些声明与 `SessionEventMap`、展开的持久化 schema、已发布类型历史及 `KNOWN_SESSION_EVENT_TYPES` 分开。记录带有 `ignorable: true`:不认识某条记录的构建在读取时保留并跳过它。记录从不进入模型可见的 surface。resume 与 fork 随日志其余部分一起携带它们;Session 格式迁移以尽力而为的方式保留它们。
|
|
75
|
+
|
|
76
|
+
`pluginRecordOf(event)` 把事件作为记录返回,对其他任何事件返回 `undefined`;把每个事件都交给它的 `ctx.sessionProjections` 单元在 resume 时重建插件状态。即使当前映射声明了该名称,其 `data` 仍为 `unknown`。所属包在使用前校验数据,因为早先构建可能写入不同的 payload,V3-to-V4 格式迁移边也可能把未知的 ignorable V3 事件改名放入同一个 `plugin:` 命名空间。删除或重命名声明不会丢弃已存记录。[ignorable 事件决策](../../../.agents/notes/implemented/architecture/2026-08-30-retain-ignorable-external-session-events.zh.md)定义兼容性策略。
|
|
77
|
+
|
|
66
78
|
### 派生会话的 fork
|
|
67
79
|
|
|
68
80
|
`ctx.sessions.fork(source, boundary?, childSessionId?)` 从实时源会话复制包含切点的精确事件前缀(默认:最后一个事件)。`dsh-session/fork` 的 `buildForkSeed` 在复制事件之后放置继承标记,仅为开放步骤补缺失的错误工具结果,并以 `forked` 原因关闭步骤和轮次。已关闭的步骤与轮次保持原样,包括历史缺失结果。标记和结束事件属于子会话;`inheritedEventCount` 只统计复制的前缀。
|
|
@@ -101,7 +113,6 @@ session.deriveMessages() // the derived model history
|
|
|
101
113
|
| [`src/request-header.ts`](src/request-header.ts) | `request/header` 折叠与重建 |
|
|
102
114
|
| [`dsh-util-values`](../../util/values/README.zh.md) | 共享无损 JSON 校验与分离式快照 |
|
|
103
115
|
| [`src/repair.ts`](src/repair.ts) | 失败步骤、中断日志与 fork 种子共享的工具结果恢复 |
|
|
104
|
-
| [`src/invariant.ts`](src/invariant.ts) | 不变式配套:序号、轮次/步骤闭合、工具调用/结果配对 |
|
|
105
116
|
|
|
106
117
|
### 追加校验
|
|
107
118
|
|
|
@@ -109,11 +120,11 @@ session.deriveMessages() // the derived model history
|
|
|
109
120
|
|
|
110
121
|
### 共享恢复逻辑
|
|
111
122
|
|
|
112
|
-
`ToolCallRecovery` 从已提交事件中跟踪尚无结果的请求,不保留事件历史。AgentLoop 观察实时步骤;崩溃恢复与 fork 种子构造通过 `openTurnClosers` 回放各自的前缀。实时失败与崩溃恢复默认使用中断结果文案;fork 构造传入 fork 原因,以选择其专用的重试指引。调用方在关闭步骤之前追加恢复结果([
|
|
123
|
+
`ToolCallRecovery` 从已提交事件中跟踪尚无结果的请求,不保留事件历史。AgentLoop 观察实时步骤;崩溃恢复与 fork 种子构造通过 `openTurnClosers` 回放各自的前缀。实时失败与崩溃恢复默认使用中断结果文案;fork 构造传入 fork 原因,以选择其专用的重试指引。调用方在关闭步骤之前追加恢复结果([参考](../agent-loop/README.zh.md))。
|
|
113
124
|
|
|
114
125
|
### 派生历史
|
|
115
126
|
|
|
116
|
-
`deriveMessages()` 缓存深度冻结的派生消息,每次调用返回新数组。surface 事件类型(`system/message`、`developer/message`、`user/message`、`assistant/message`、`tool/result`)提供记录的消息身份和内容,空内容的 system 和 developer 节点不派生消息。插件拥有的投影修改派生内容,不修改记录的消息。替换和投影决策使缓存失效。嵌入式 Assistant stream 与 `assistant/attempt`
|
|
127
|
+
`deriveMessages()` 缓存深度冻结的派生消息,每次调用返回新数组。surface 事件类型(`system/message`、`developer/message`、`user/message`、`assistant/message`、`tool/result`)提供记录的消息身份和内容,空内容的 system 和 developer 节点不派生消息。插件拥有的投影修改派生内容,不修改记录的消息。替换和投影决策使缓存失效。嵌入式 Assistant stream 与 `assistant/attempt` 事件只保留回放和诊断数据。普通提示与注入上下文在派生时不会按类型或来源自动添加包装。生产方负责记录内容中的所有框定格式。
|
|
117
128
|
|
|
118
129
|
### 请求头
|
|
119
130
|
|
|
@@ -157,7 +168,7 @@ session.deriveMessages() // the derived model history
|
|
|
157
168
|
|
|
158
169
|
#### 模型看到什么
|
|
159
170
|
|
|
160
|
-
如果恢复发现 assistant 工具请求没有持久 `tool/call`,其合成 `TOOL_NOT_STARTED` 结果内容为 `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.`。如果持久 `tool/call` 没有结果,其 `TOOL_OUTCOME_UNKNOWN` 结果内容为 `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.`。 Fork 生成的结果只描述继承记录:父会话可能已经在所选事件之后启动或完成调用。`TOOL_NOT_STARTED` 表示前缀中没有启动记录;`TOOL_OUTCOME_UNKNOWN` 表示有启动记录但没有结果。两者都要求模型仅对只读或幂等操作直接重试;有副作用的操作需要先验证外部状态或询问用户。参见 [fork
|
|
171
|
+
如果恢复发现 assistant 工具请求没有持久 `tool/call`,其合成 `TOOL_NOT_STARTED` 结果内容为 `The tool call was interrupted before the Harness recorded it as started. Retry it if it is still needed.`。如果持久 `tool/call` 没有结果,其 `TOOL_OUTCOME_UNKNOWN` 结果内容为 `The tool call was interrupted after it was recorded, but no result was durably recorded. Its outcome is unknown. Decide whether to retry from the tool semantics: retry only if the operation is read-only or idempotent; if it may have side effects, first verify external state or ask the user. Do not retry blindly.`。 Fork 生成的结果只描述继承记录:父会话可能已经在所选事件之后启动或完成调用。`TOOL_NOT_STARTED` 表示前缀中没有启动记录;`TOOL_OUTCOME_UNKNOWN` 表示有启动记录但没有结果。两者都要求模型仅对只读或幂等操作直接重试;有副作用的操作需要先验证外部状态或询问用户。参见 [fork 参考](src/fork.ts)。
|
|
161
172
|
|
|
162
173
|
#### Token 影响
|
|
163
174
|
|
|
@@ -189,7 +200,7 @@ session.deriveMessages() // the derived model history
|
|
|
189
200
|
这些限制说明会话存储何时需要特别留意。它们是当前包约束,不是任务积压。
|
|
190
201
|
|
|
191
202
|
- **Store API 仅接受活跃源会话** — 已持久化但未加载的源会话通过 Host 观察路径处理。Fork 仅闭合开放尾部,不修复先前已闭合步骤中缺失的结果。
|
|
192
|
-
- **`SESSION_FORMAT_VERSION` 命名[当前逻辑表示](../../../docs/session-format-status.zh.md)**——当前读取器拒绝已退役的 `header.system`,并校验 `system/message` 载荷与受保护头节点的重写。历史 header 与事件归相邻格式包所有;[相邻迁移链](../../session/session-format-catalog/README.zh.md)在构造 `Session` 前转换受支持的历史,写打开只发布当前格式的后继代际。同版本未知事件要求信封显式带有 `ignorable` 标记,但这不保证结构迁移的安全性([机制](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md))。
|
|
203
|
+
- **`SESSION_FORMAT_VERSION` 命名[当前逻辑表示](../../../docs/session-format-status.zh.md)**——当前读取器拒绝已退役的 `header.system`,并校验 `system/message` 载荷与受保护头节点的重写。历史 header 与事件归相邻格式包所有;[相邻迁移链](../../session/session-format-catalog/README.zh.md)在构造 `Session` 前转换受支持的历史,写打开只发布当前格式的后继代际。同版本未知事件要求信封显式带有 `ignorable` 标记,但这不保证结构迁移的安全性([机制](../../../.agents/notes/implemented/architecture/2026-08-31-released-session-format-migrations.zh.md))。[读取器兼容性](../../../.agents/notes/implemented/process/2026-10-08-session-reader-compatibility-review.zh.md)决定变更是否需要升版本。
|
|
193
204
|
- **`TurnEndReasonMap` 不含 ACP(Agent Client Protocol)命名的 `refusal`/`max_turn_requests` 变体**:受生产方约束;只有当适配器或循环首次产生这些变体时才加入。
|
|
194
205
|
- **fork 之外没有会话树**:基于分支会话的 pi 风格条目树被推迟,除非消费方需要超越基于边界的 forking 的能力。
|
|
195
206
|
|
package/lib/index.js
CHANGED
|
@@ -38,20 +38,20 @@ function SessionLogOffset(value) {
|
|
|
38
38
|
* event-body read composes the build-static adjacent chain and publishes only
|
|
39
39
|
* this final generation before constructing a Session.
|
|
40
40
|
*
|
|
41
|
-
* The version is a single monotonic integer with no major/minor split.
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* `.agents/notes/implemented/
|
|
41
|
+
* The version is a single monotonic integer with no major/minor split. Retain
|
|
42
|
+
* it when older readers resume correctly, preserve safely ignorable records,
|
|
43
|
+
* or refuse required features before execution, mutation, or tail repair.
|
|
44
|
+
* New readers must preserve historical meanings, including logs mixing old
|
|
45
|
+
* and new record representations. Bump when an existing discriminator cannot
|
|
46
|
+
* prevent unsafe interpretation; a structural difference alone is insufficient.
|
|
47
|
+
* Unknown fields and values require evidence of the released reader's actual
|
|
48
|
+
* admission behavior. The per-event {@link SessionEvent.ignorable} marker
|
|
49
|
+
* governs unknown event types, not arbitrary nested payload changes.
|
|
50
|
+
* Same-version readers retain earlier representations: the adjacent migration
|
|
51
|
+
* chain does not run when stored and current versions match. A subsequent
|
|
52
|
+
* migration must account for all supported representations of its source.
|
|
53
|
+
* Compatibility review and the retained migration obligations are recorded in
|
|
54
|
+
* `.agents/notes/implemented/process/2026-10-08-session-reader-compatibility-review.md`.
|
|
55
55
|
*/
|
|
56
56
|
const SESSION_FORMAT_VERSION = 4;
|
|
57
57
|
//#endregion
|
|
@@ -135,6 +135,7 @@ const KNOWN_SESSION_EVENT_TYPES = new Set([
|
|
|
135
135
|
"turn/start",
|
|
136
136
|
"user/message",
|
|
137
137
|
"web/deepseek-search-llm-request",
|
|
138
|
+
"working-directory/change",
|
|
138
139
|
"workspace/changes"
|
|
139
140
|
]);
|
|
140
141
|
/** Event types whose model-visible effects require an explicit pure interpreter. */
|
|
@@ -1238,6 +1239,79 @@ function invokeContainedSessionObservers(ctx, name, id, args, callbacks) {
|
|
|
1238
1239
|
/** Store attachment for the append path; module-private to keep Session store-agnostic publicly. */
|
|
1239
1240
|
const attachments = /* @__PURE__ */ new WeakMap();
|
|
1240
1241
|
/**
|
|
1242
|
+
* Grammar of a {@link PluginRecordType}: `plugin:` followed by
|
|
1243
|
+
* slash-separated segments of lowercase letters, digits, `.`, `_`, and `-`,
|
|
1244
|
+
* each segment starting with a letter or digit.
|
|
1245
|
+
*/
|
|
1246
|
+
const PLUGIN_RECORD_TYPE = /^plugin:[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9][a-z0-9._-]*)*$/u;
|
|
1247
|
+
/**
|
|
1248
|
+
* Whether one event type name follows the plugin record grammar.
|
|
1249
|
+
* @param type - an event type name.
|
|
1250
|
+
* @returns whether the name is a {@link PluginRecordType}.
|
|
1251
|
+
*/
|
|
1252
|
+
function isPluginRecordType(type) {
|
|
1253
|
+
return PLUGIN_RECORD_TYPE.test(type);
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Type one constructed plugin record as a log event after checking its type
|
|
1257
|
+
* against the plugin record grammar. A restored Session already holds events
|
|
1258
|
+
* whose types are outside `SessionEventMap` when they are marked ignorable;
|
|
1259
|
+
* a plugin record is such an event.
|
|
1260
|
+
* @param value - the frozen record envelope built by {@link Session}.
|
|
1261
|
+
* @throws when the record type is outside the plugin record grammar.
|
|
1262
|
+
*/
|
|
1263
|
+
function assertPluginRecordEvent(value) {
|
|
1264
|
+
const { type } = value;
|
|
1265
|
+
if (!isPluginRecordType(type)) throw new Error(`plugin record type "${type}" must be "plugin:" followed by lowercase slash-separated segments`);
|
|
1266
|
+
}
|
|
1267
|
+
/** Module-private access to {@link Session}'s record commit, assigned once by its static block. */
|
|
1268
|
+
let commitPluginRecord;
|
|
1269
|
+
/**
|
|
1270
|
+
* Append one experimental plugin record: an event marked `ignorable` whose
|
|
1271
|
+
* type is declared in {@link PluginRecordMap}, outside {@link SessionEventMap}.
|
|
1272
|
+
* The plugin record catalog lists it separately from released event schemas.
|
|
1273
|
+
* A reader that does not recognize the type retains and skips the record, which never
|
|
1274
|
+
* enters the model-visible surface, and fork and resume carry it with the rest
|
|
1275
|
+
* of the log. A Session format migration retains records on a best-effort
|
|
1276
|
+
* basis, so a record holds plugin-owned state that its owner can lose without
|
|
1277
|
+
* changing how the rest of the log is interpreted.
|
|
1278
|
+
*
|
|
1279
|
+
* Only production source under `packages/experimental/` may call this
|
|
1280
|
+
* function; the `verify-plugin-record-callers` gate rejects any other
|
|
1281
|
+
* production caller in this repository. Read records back with
|
|
1282
|
+
* {@link pluginRecordOf}.
|
|
1283
|
+
* @param session - the Session whose log receives the record.
|
|
1284
|
+
* @param type - declared record name: `plugin:` followed by slash-separated
|
|
1285
|
+
* segments of lowercase letters, digits, `.`, `_`, and `-`, each starting
|
|
1286
|
+
* with a letter or digit.
|
|
1287
|
+
* @param data - JSON payload, snapshotted before it enters the log.
|
|
1288
|
+
* @returns the sequence number of the committed record.
|
|
1289
|
+
* @throws when `type` is outside that grammar, when `data` is not losslessly
|
|
1290
|
+
* JSON-serializable, or when the call reenters another append's publication;
|
|
1291
|
+
* a rejected record does not change the log.
|
|
1292
|
+
*/
|
|
1293
|
+
function appendPluginRecord(session, type, data) {
|
|
1294
|
+
return commitPluginRecord(session, type, data);
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Read one committed event as a plugin record. The V3-to-V4 format edge also
|
|
1298
|
+
* renames each unknown ignorable V3 event into the `plugin:` namespace, so an
|
|
1299
|
+
* owner names its records under its own package name and validates `data`.
|
|
1300
|
+
* @param event - any committed Session event, live or restored.
|
|
1301
|
+
* @returns the record, or undefined when the event is not an ignorable event
|
|
1302
|
+
* whose type follows the plugin record grammar.
|
|
1303
|
+
*/
|
|
1304
|
+
function pluginRecordOf(event) {
|
|
1305
|
+
const type = event.type;
|
|
1306
|
+
if (event.ignorable !== true || !isPluginRecordType(type)) return void 0;
|
|
1307
|
+
return {
|
|
1308
|
+
type,
|
|
1309
|
+
seq: event.seq,
|
|
1310
|
+
time: event.time,
|
|
1311
|
+
data: event.data
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
/**
|
|
1241
1315
|
* An event-sourced session: an append-only log of {@link SessionEvent}s.
|
|
1242
1316
|
*
|
|
1243
1317
|
* Plain class (not a Service) — create live instances via
|
|
@@ -1448,8 +1522,7 @@ var Session = class Session {
|
|
|
1448
1522
|
if (dataSnapshot === void 0) throw new Error(`session event "${type}" carries non-JSON-serializable data`);
|
|
1449
1523
|
const surfaceMetadataSnapshot = snapshotJsonValue(surfaceMetadata);
|
|
1450
1524
|
if (surfaceMetadataSnapshot === void 0) throw new Error(`session event "${type}" carries non-JSON-serializable surface metadata`);
|
|
1451
|
-
const entry =
|
|
1452
|
-
if (entry?.appending) throw new Error("session append cannot reenter while another append is being published");
|
|
1525
|
+
const entry = this.publicationEntry();
|
|
1453
1526
|
const event = deepFreeze({
|
|
1454
1527
|
type,
|
|
1455
1528
|
seq: SessionSeq(this.log.length),
|
|
@@ -1458,6 +1531,50 @@ var Session = class Session {
|
|
|
1458
1531
|
...surfaceMetadataSnapshot
|
|
1459
1532
|
});
|
|
1460
1533
|
validateSessionEventData(event, `session event "${type}" at seq ${event.seq}`);
|
|
1534
|
+
this.commit(event, entry);
|
|
1535
|
+
return event;
|
|
1536
|
+
}
|
|
1537
|
+
static {
|
|
1538
|
+
commitPluginRecord = (session, type, data) => session.#appendRecord(type, data);
|
|
1539
|
+
}
|
|
1540
|
+
/**
|
|
1541
|
+
* Commit one plugin record; {@link appendPluginRecord} is the only caller.
|
|
1542
|
+
* @param type - record type, checked against the plugin record grammar.
|
|
1543
|
+
* @param data - JSON payload, snapshotted before it enters the log.
|
|
1544
|
+
* @returns the record's sequence number.
|
|
1545
|
+
*/
|
|
1546
|
+
#appendRecord(type, data) {
|
|
1547
|
+
const dataSnapshot = snapshotJsonValue(data);
|
|
1548
|
+
if (dataSnapshot === void 0) throw new Error(`plugin record "${type}" carries non-JSON-serializable data`);
|
|
1549
|
+
const entry = this.publicationEntry();
|
|
1550
|
+
const record = deepFreeze({
|
|
1551
|
+
type,
|
|
1552
|
+
seq: SessionSeq(this.log.length),
|
|
1553
|
+
time: Date.now(),
|
|
1554
|
+
data: dataSnapshot,
|
|
1555
|
+
ignorable: true
|
|
1556
|
+
});
|
|
1557
|
+
assertPluginRecordEvent(record);
|
|
1558
|
+
this.commit(record, entry);
|
|
1559
|
+
return record.seq;
|
|
1560
|
+
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Read the store attachment for one append, refusing an append that
|
|
1563
|
+
* reenters while another append is being published.
|
|
1564
|
+
* @returns the attachment, or undefined for a detached Session.
|
|
1565
|
+
*/
|
|
1566
|
+
publicationEntry() {
|
|
1567
|
+
const entry = attachments.get(this);
|
|
1568
|
+
if (entry?.appending) throw new Error("session append cannot reenter while another append is being published");
|
|
1569
|
+
return entry;
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* Accept one frozen candidate at the next sequence number, enter it into the
|
|
1573
|
+
* log, and notify `session/event` observers with per-listener containment.
|
|
1574
|
+
* @param event - the candidate built at the current log length.
|
|
1575
|
+
* @param entry - the attachment read before the candidate was built.
|
|
1576
|
+
*/
|
|
1577
|
+
commit(event, entry) {
|
|
1461
1578
|
this.surfaceManager.validateNext(event);
|
|
1462
1579
|
if (entry !== void 0) entry.appending = true;
|
|
1463
1580
|
try {
|
|
@@ -1471,7 +1588,6 @@ var Session = class Session {
|
|
|
1471
1588
|
this.log.push(event);
|
|
1472
1589
|
this.eventsSnapshot = void 0;
|
|
1473
1590
|
if (callbacks !== void 0 && entry !== void 0) invokeContainedSessionObservers(entry.emitCtx, "session/event", entry.id, callbackArgs, callbacks);
|
|
1474
|
-
return event;
|
|
1475
1591
|
} finally {
|
|
1476
1592
|
if (entry !== void 0) {
|
|
1477
1593
|
entry.appending = false;
|
|
@@ -1822,8 +1938,8 @@ var SessionStore = class extends Service {
|
|
|
1822
1938
|
* store owns the carrier, so callers (the checkpoint policy's per-request
|
|
1823
1939
|
* barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
|
|
1824
1940
|
* that flush themselves before reading storage) must come through here
|
|
1825
|
-
* rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner
|
|
1826
|
-
* one spelling
|
|
1941
|
+
* rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner
|
|
1942
|
+
* and one spelling.
|
|
1827
1943
|
* @param session - the session whose buffered events must reach durable storage.
|
|
1828
1944
|
* @returns whether at least one durability listener participated, after every
|
|
1829
1945
|
* listener has settled successfully.
|
|
@@ -1930,4 +2046,4 @@ var SessionStore = class extends Service {
|
|
|
1930
2046
|
}
|
|
1931
2047
|
};
|
|
1932
2048
|
//#endregion
|
|
1933
|
-
export { KNOWN_SESSION_EVENT_TYPES, SESSION_FORMAT_VERSION, Session, SessionForkError, SessionId, SessionLogOffset, SessionPreparation, SessionSeq, SessionStore, SessionStore as default, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN, ToolCallRecovery, adoptSessionEvent, buildForkSeed, canonicalHeader, decodeSeqRanges, deriveEventMessage, encodeSeqRanges, foldRequestHeader, foldSurface, headerEquals, interruptedTurnClosers, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEligibleType, isSurfaceEvent, snapshotSessionEvent };
|
|
2049
|
+
export { KNOWN_SESSION_EVENT_TYPES, SESSION_FORMAT_VERSION, Session, SessionForkError, SessionId, SessionLogOffset, SessionPreparation, SessionSeq, SessionStore, SessionStore as default, TOOL_NOT_STARTED, TOOL_OUTCOME_UNKNOWN, ToolCallRecovery, adoptSessionEvent, appendPluginRecord, buildForkSeed, canonicalHeader, decodeSeqRanges, deriveEventMessage, encodeSeqRanges, foldRequestHeader, foldSurface, headerEquals, interruptedTurnClosers, isAppendSurfaceEvent, isReplacementSurfaceEvent, isSurfaceEligibleType, isSurfaceEvent, pluginRecordOf, snapshotSessionEvent };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { Scoped } from '@deepseek-ai/dsh-scope';
|
|
|
10
10
|
import type { Message } from '@deepseek-ai/dsh-llm';
|
|
11
11
|
import { SessionLogOffset, SessionSeq } from './types.ts';
|
|
12
12
|
import type { TypertLookup } from '@deepseek-ai/dsh-typert-protocol';
|
|
13
|
-
import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SessionId, SessionSeedEventState, SurfaceIntent, SurfaceEventType } from './types.ts';
|
|
13
|
+
import type { CreateSessionOptions, EpochHeader, PluginRecord, PluginRecordMap, PluginRecordType, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SessionId, SessionSeedEventState, SurfaceIntent, SurfaceEventType } from './types.ts';
|
|
14
14
|
import type { SessionSurface, SessionMessageProjection } from './surface.ts';
|
|
15
15
|
import type { ToolHistory } from '@deepseek-ai/dsh-llm';
|
|
16
16
|
export { buildForkSeed } from './fork.ts';
|
|
@@ -36,7 +36,6 @@ declare module '@deepseek-ai/cordis' {
|
|
|
36
36
|
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
|
|
37
37
|
* receive only sessions entered through that agent's context.
|
|
38
38
|
* @param session - the session just entered and announced.
|
|
39
|
-
* @dshScopeScan unsupported
|
|
40
39
|
* @mode emit
|
|
41
40
|
*/
|
|
42
41
|
'session/created'(this: Scoped<Session>, session: Session): void;
|
|
@@ -46,7 +45,6 @@ declare module '@deepseek-ai/cordis' {
|
|
|
46
45
|
* did not begin. Listener failures are logged and contained.
|
|
47
46
|
* Scope-filtered dispatch (`@deepseek-ai/dsh-scope`) reuses the owner scope.
|
|
48
47
|
* @param session - the session that is no longer live in the store.
|
|
49
|
-
* @dshScopeScan unsupported
|
|
50
48
|
* @mode emit
|
|
51
49
|
*/
|
|
52
50
|
'session/disposed'(this: Scoped<Session>, session: Session): void;
|
|
@@ -58,7 +56,6 @@ declare module '@deepseek-ai/cordis' {
|
|
|
58
56
|
* receive only events from sessions entered through that agent's context.
|
|
59
57
|
* @param session - the session whose log grew.
|
|
60
58
|
* @param event - the appended event, exactly as recorded.
|
|
61
|
-
* @dshScopeScan unsupported
|
|
62
59
|
* @mode emit
|
|
63
60
|
*/
|
|
64
61
|
'session/event'(this: Scoped<Session>, session: Session, event: SessionEvent): void;
|
|
@@ -67,7 +64,6 @@ declare module '@deepseek-ai/cordis' {
|
|
|
67
64
|
* caller awaits all of them, with no waterfall veto. Scope-filtered dispatch
|
|
68
65
|
* (`@deepseek-ai/dsh-scope`) reuses the session's owner scope.
|
|
69
66
|
* @param session - the session whose buffered events must reach durable storage.
|
|
70
|
-
* @dshScopeScan unsupported
|
|
71
67
|
* @mode parallel
|
|
72
68
|
*/
|
|
73
69
|
'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void;
|
|
@@ -94,6 +90,40 @@ export declare function adoptSessionEvent<T extends SessionEvent>(event: T): T;
|
|
|
94
90
|
* @returns a detached event snapshot with a validated, deeply frozen message.
|
|
95
91
|
*/
|
|
96
92
|
export declare function snapshotSessionEvent<T extends SessionEvent>(event: T): T;
|
|
93
|
+
/**
|
|
94
|
+
* Append one experimental plugin record: an event marked `ignorable` whose
|
|
95
|
+
* type is declared in {@link PluginRecordMap}, outside {@link SessionEventMap}.
|
|
96
|
+
* The plugin record catalog lists it separately from released event schemas.
|
|
97
|
+
* A reader that does not recognize the type retains and skips the record, which never
|
|
98
|
+
* enters the model-visible surface, and fork and resume carry it with the rest
|
|
99
|
+
* of the log. A Session format migration retains records on a best-effort
|
|
100
|
+
* basis, so a record holds plugin-owned state that its owner can lose without
|
|
101
|
+
* changing how the rest of the log is interpreted.
|
|
102
|
+
*
|
|
103
|
+
* Only production source under `packages/experimental/` may call this
|
|
104
|
+
* function; the `verify-plugin-record-callers` gate rejects any other
|
|
105
|
+
* production caller in this repository. Read records back with
|
|
106
|
+
* {@link pluginRecordOf}.
|
|
107
|
+
* @param session - the Session whose log receives the record.
|
|
108
|
+
* @param type - declared record name: `plugin:` followed by slash-separated
|
|
109
|
+
* segments of lowercase letters, digits, `.`, `_`, and `-`, each starting
|
|
110
|
+
* with a letter or digit.
|
|
111
|
+
* @param data - JSON payload, snapshotted before it enters the log.
|
|
112
|
+
* @returns the sequence number of the committed record.
|
|
113
|
+
* @throws when `type` is outside that grammar, when `data` is not losslessly
|
|
114
|
+
* JSON-serializable, or when the call reenters another append's publication;
|
|
115
|
+
* a rejected record does not change the log.
|
|
116
|
+
*/
|
|
117
|
+
export declare function appendPluginRecord<K extends Extract<keyof PluginRecordMap, PluginRecordType>>(session: Session, type: K, data: NoInfer<PluginRecordMap[K]>): SessionSeq;
|
|
118
|
+
/**
|
|
119
|
+
* Read one committed event as a plugin record. The V3-to-V4 format edge also
|
|
120
|
+
* renames each unknown ignorable V3 event into the `plugin:` namespace, so an
|
|
121
|
+
* owner names its records under its own package name and validates `data`.
|
|
122
|
+
* @param event - any committed Session event, live or restored.
|
|
123
|
+
* @returns the record, or undefined when the event is not an ignorable event
|
|
124
|
+
* whose type follows the plugin record grammar.
|
|
125
|
+
*/
|
|
126
|
+
export declare function pluginRecordOf(event: SessionEvent): PluginRecord | undefined;
|
|
97
127
|
/**
|
|
98
128
|
* An event-sourced session: an append-only log of {@link SessionEvent}s.
|
|
99
129
|
*
|
|
@@ -103,6 +133,7 @@ export declare function snapshotSessionEvent<T extends SessionEvent>(event: T):
|
|
|
103
133
|
* @typert object
|
|
104
134
|
*/
|
|
105
135
|
export declare class Session {
|
|
136
|
+
#private;
|
|
106
137
|
private log;
|
|
107
138
|
/** Single incremental owner of surface acceptance and projection state. */
|
|
108
139
|
private readonly surfaceManager;
|
|
@@ -244,6 +275,19 @@ export declare class Session {
|
|
|
244
275
|
* rejects before the log changes.
|
|
245
276
|
*/
|
|
246
277
|
append<T extends SessionEventType>(type: T, data: SessionEventMap[T], ...opts: T extends SurfaceEventType ? [opts: SurfaceIntent<T>] : []): SessionEvent<T>;
|
|
278
|
+
/**
|
|
279
|
+
* Read the store attachment for one append, refusing an append that
|
|
280
|
+
* reenters while another append is being published.
|
|
281
|
+
* @returns the attachment, or undefined for a detached Session.
|
|
282
|
+
*/
|
|
283
|
+
private publicationEntry;
|
|
284
|
+
/**
|
|
285
|
+
* Accept one frozen candidate at the next sequence number, enter it into the
|
|
286
|
+
* log, and notify `session/event` observers with per-listener containment.
|
|
287
|
+
* @param event - the candidate built at the current log length.
|
|
288
|
+
* @param entry - the attachment read before the candidate was built.
|
|
289
|
+
*/
|
|
290
|
+
private commit;
|
|
247
291
|
/** Cached fold of the request-header events — see {@link requestHeader}. */
|
|
248
292
|
private headerFold;
|
|
249
293
|
/** Log position (events consumed) the header fold has reached. */
|
|
@@ -429,8 +473,8 @@ export declare class SessionStore extends Service {
|
|
|
429
473
|
* store owns the carrier, so callers (the checkpoint policy's per-request
|
|
430
474
|
* barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
|
|
431
475
|
* that flush themselves before reading storage) must come through here
|
|
432
|
-
* rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner
|
|
433
|
-
* one spelling
|
|
476
|
+
* rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner
|
|
477
|
+
* and one spelling.
|
|
434
478
|
* @param session - the session whose buffered events must reach durable storage.
|
|
435
479
|
* @returns whether at least one durability listener participated, after every
|
|
436
480
|
* listener has settled successfully.
|