@deepseek-ai/dsh-session 0.0.1-rc.2 → 0.0.1-rc.3

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 CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/core/session/README.md
5
- README.md: 57569e9c0dbfa7cb696e3a561a9ff108c2ac981f
6
- README.zh.md: 16629dc70c79ca838ba7088aeafcc5b38b124f87
5
+ README.md: 02aae21d71101e626bf2d2ead0bfd5d155723165
6
+ README.zh.md: 2da8c5db8fe25d55faafdd6d44ea9090dd232576
package/README.md CHANGED
@@ -70,7 +70,7 @@ A `user/message` stores the complete `UserMessage` directly, including the ident
70
70
 
71
71
  The generated [persistence log event catalog](../../../docs/persistence-catalog.md) enumerates each append-only event type with its payload, surface badge, and declaration site. Token accounting reads per-step `assistant/chunk { type: 'usage' }` records and treats `assistant/message.usage` as the committed-step fallback when no usage chunk exists; failed model-request attempts have no assistant message. Each `assistant/message` records the provider, model, and optional replay state.
72
72
 
73
- Merge-extensible via `SessionEventMap` — a plugin declaration-merges its own types (the compaction seam's `compact/*`, bounded recovery's non-surface `llm/retry`, the hook bridges' `hook/*`); merged members appear in the same catalog. A plugin owns the relational invariant for its merged events, including whether a log-only event may appear between turns. A producer that requires durability appends through `Session` and then awaits `ctx.sessions.flush(session)` without fabricating an execution turn.
73
+ Merge-extensible via `SessionEventMap` — a plugin declaration-merges its own types (the compaction seam's `compaction/*`, bounded recovery's non-surface `llm/retry`, the hook bridges' `hook/*`); merged members appear in the same catalog. A plugin owns the relational invariant for its merged events, including whether a log-only event may appear between turns. A producer that requires durability appends through `Session` and then awaits `ctx.sessions.flush(session)` without fabricating an execution turn.
74
74
 
75
75
  Also defines `TurnEndReasonMap`, the merge-extensible `kind`-tagged sum type for turn endings. `turn/start` carries only the turn number; the following entered `user/message` batch records its input, while `llm/retry` records request recovery.
76
76
 
@@ -90,7 +90,7 @@ Every `SessionEvent` carries three optional top-level fields (structural metadat
90
90
 
91
91
  - Persistence plugins: subscribe to `session/event` (write-behind) and drain on `session/flush` (awaited) and fiber dispose. A durable backend reads the log and reloads it into a live session; the metadata contract (`SessionHeader`, `session.header`) is what such a backend stores beside the log.
92
92
  - Replay/fork: `create(id, { seed })` validates and freezes a contiguous current-format log and rebuilds its surface; request headers require provider/model, and assistant messages require provider/model provenance. Persistence owns read compatibility before constructing this current-format seed. `fork(source, boundary?, childSessionId?)` selects a completed-turn prefix and records lineage.
93
- - Compaction: `dsh-compact-basic` appends a `user/message` replacement for summary checkpoints, while `dsh-compact-tool-result-prune` appends a content-only `tool/result` replacement. Tool-pairing boundary policy and its cache belong to the [`dsh-compact` seam](../../compact/compact/README.md), while this package owns ordered surface membership, replacement validation, and `replaceGeneration`.
93
+ - Compaction: `dsh-compaction-basic` appends a `user/message` replacement for summary checkpoints, while `dsh-compaction-tool-result-pruner` appends a content-only `tool/result` replacement. Tool-pairing boundary policy and its cache belong to the [`dsh-compaction` seam](../../compaction/compaction/README.md), while this package owns ordered surface membership, replacement validation, and `replaceGeneration`.
94
94
 
95
95
  ## Model Experience
96
96
 
package/README.zh.md CHANGED
@@ -13,7 +13,7 @@
13
13
  ### 公共 API
14
14
 
15
15
  - `ctx.sessions.create(id?, { seed?, meta? }?)` 校验持久种子/头部数据并生成脱离副本,补齐版本和 id,在未提供 `createdAt` 时使用当前时间,发布会话并将其绑定到调用方 fiber。持久化重建会提供原始的 `createdAt`、`seedLength` 和 `delegationDepth`。
16
- - `ctx.sessions.flush(session)` 通过会话捕获的作用域分发受等待的并行持久性检查点。每个监听器都会启动;调用会等待全部结算后才报告失败。未发布、已脱离和陈旧的对象会被拒绝。
16
+ - `ctx.sessions.flush(session)` 通过会话捕获的作用域分发一个需等待完成的并行持久性检查点。每个监听器都会启动;调用会等待全部结算后才报告失败。未发布、已脱离和陈旧的对象会被拒绝。
17
17
  - `ctx.sessions.fork(source, boundary?, childSessionId?): Session`:解析实时会话对象或 id,选取截至 `boundary` 事件序号(含该事件)的种子(默认为当前最后一个事件),要求所选前缀结束时没有开放轮次,再创建带谱系元数据的实时子会话。
18
18
  - `ctx.sessions.get(id: SessionId): Session | undefined`
19
19
  - `ctx.sessions.list(): Session[]`
@@ -36,7 +36,7 @@
36
36
 
37
37
  普通类(不是 Cordis 服务)。活跃会话通过 `ctx.sessions.create()` 创建,脱离态的回放或检查会话通过 `Session.create()` 创建;脱离态工厂不会发布生命周期事件,也不会将会话绑定到 fiber。
38
38
 
39
- - `session.append(type, data, opts?)` 会为持久数据和 surface 元数据制作快照并冻结它们,校验标记形态、被引用的源事件 seq、替换覆盖完整性,以及仅修改内容的单个 `tool/result` 重写,随后同步提交,再在彼此独立的失败收容下通知观察者。对已附加会话的重入追加会被拒绝,运行时检查也覆盖扩宽后的联合类型和已加载日志。
39
+ - `session.append(type, data, opts?)` 会为持久数据和 surface 元数据制作快照并冻结它们,校验标记形态、被引用的源事件 seq、替换覆盖完整性,以及仅修改内容的单个 `tool/result` 重写,随后同步提交,再在彼此独立的失败收容下通知观察者。对已挂接会话的重入追加会被拒绝,运行时检查也覆盖扩宽后的联合类型和已加载日志。
40
40
  - `session.deriveMessages()` 对每个新的 surface 条目只做一次增量投影,并返回一个新数组,其中包含这些条目存储的完整、带标识且冻结的消息。assistant 消息的模型来源会保留生成该消息的提供方和模型,以及适配器私有回放状态。surface 重写会重建投影;不存在原始日志回退。
41
41
  - `session.deriveEventMessage(event)` 是重建和请求检查使用的规范逐事件投影。
42
42
  - `session.surface` 暴露只读 `SessionSurface` 视图,由会话唯一的增量 surface 管理器所有;每次提交重写,`replaceGeneration` 都会变化。
@@ -70,11 +70,11 @@
70
70
 
71
71
  生成的[持久化日志事件目录](../../../docs/persistence-catalog.md)逐成员列举仅追加日志的事件类型、载荷、surface 标记与声明位置。Token 记账读取每个步骤的 `assistant/chunk { type: 'usage' }` 记录;如果没有用量分片,则将 `assistant/message.usage` 作为已提交步骤的后备。失败的模型请求尝试没有 assistant 消息。每条 `assistant/message` 都会记录提供方、模型和可选回放状态。
72
72
 
73
- `SessionEventMap` 可通过合并扩展:插件使用声明合并添加自身类型(压缩 seam 的 `compact/*`、有界恢复的非 surface `llm/retry`、hook(钩子)桥接层的 `hook/*`);合并成员会出现在同一目录中。插件拥有其合并事件的关系不变量,包括是否允许纯日志事件出现在轮次之间。需要持久性的生产方通过 `Session` 追加,再等待 `ctx.sessions.flush(session)`,无需虚构一个执行轮次。
73
+ `SessionEventMap` 可通过合并扩展:插件使用声明合并添加自身类型(压缩 seam 的 `compaction/*`、有界恢复的非 surface `llm/retry`、钩子桥接层的 `hook/*`);合并成员会出现在同一目录中。插件拥有其合并事件的关系不变量,包括是否允许纯日志事件出现在轮次之间。需要持久性的生产方通过 `Session` 追加,再等待 `ctx.sessions.flush(session)`,无需虚构一个执行轮次。
74
74
 
75
75
  此包还定义 `TurnEndReasonMap`,即用于轮次结束、可合并扩展且以 `kind` 为标签的和类型。`turn/start` 只携带轮次编号;随后已进入的 `user/message` 批次记录其输入,`llm/retry` 则记录请求恢复。
76
76
 
77
- 被中断的实时轮次以 `{ kind: 'aborted', reason: AgentCancelCause }` 结束,在持久 transcript(文本记录)中保留类型化取消原因。持久化会将受支持旧格式中的粗粒度中止结果导入为 `{ kind: 'aborted', reason: { kind: 'legacy' } }`,因为该记录没有保留调用方。轮次失败携带 `{ kind: 'error', error }`;只有崩溃恢复会合成 `{ kind: 'interrupted' }`。
77
+ 被中断的实时轮次以 `{ kind: 'aborted', reason: AgentCancelCause }` 结束,在持久 transcript 中保留类型化取消原因。持久化会将受支持旧格式中的粗粒度中止结果导入为 `{ kind: 'aborted', reason: { kind: 'legacy' } }`,因为该记录没有保留调用方。轮次失败携带 `{ kind: 'error', error }`;只有崩溃恢复会合成 `{ kind: 'interrupted' }`。
78
78
 
79
79
  每个 `SessionEvent` 都有三个可选顶层字段(结构元数据):
80
80
 
@@ -84,13 +84,13 @@
84
84
 
85
85
  ### 元数据类型(`types.ts`)
86
86
 
87
- - `SessionHeader`:会话元数据,在发布为 `Session.header` 时写入一次;脱离和深冻结保证运行时不可变:`{ version, id, createdAt, cwd?, parentSession?, seedLength?, delegationDepth? }`。持久化 loader 可返回相同数据类型的可变脱离副本。该类型由此包与 `SessionId` 一同所有,因为 `Session.header` 以它为类型;持久化后端只是重新导出而不拥有它,否则会形成包循环依赖。
87
+ - `SessionHeader`:会话元数据,在发布为 `Session.header` 时写入一次;脱离和深冻结保证运行时不可变:`{ version, id, createdAt, cwd?, parentSession?, seedLength?, delegationDepth? }`。持久化 loader 可返回相同数据类型的可变脱离副本。该类型与 `SessionId` 一同归此包所有,因为 `Session.header` 以它为类型;持久化后端只是重新导出而不拥有它,否则会形成包循环依赖。
88
88
 
89
89
  ### 扩展点
90
90
 
91
91
  - 持久化插件:订阅 `session/event`(延后写入),并在 `session/flush`(受等待)及 fiber dispose(资源释放)时排空。持久后端读取日志并重新加载到实时会话;这类后端会把元数据约定(`SessionHeader`、`session.header`)与日志一同存储。
92
92
  - 回放/fork:`create(id, { seed })` 校验并冻结连续的当前格式日志,再重建 surface;请求头必须包含提供方/模型,assistant 消息必须包含提供方/模型溯源信息。持久化层在构造该当前格式 seed 前负责读取兼容性处理。`fork(source, boundary?, childSessionId?)` 选择已完成轮次前缀并记录谱系。
93
- - 压缩:`dsh-compact-basic` 为摘要检查点追加一个替换用 `user/message`,而 `dsh-compact-tool-result-prune` 追加仅修改内容的 `tool/result` 替换。工具配对边界策略及其缓存归 [`dsh-compact` seam](../../compact/compact/README.md) 所有;此包拥有有序 surface 成员关系、替换校验与 `replaceGeneration`。
93
+ - 压缩:`dsh-compaction-basic` 为摘要检查点追加一个替换用 `user/message`,而 `dsh-compaction-tool-result-pruner` 追加仅修改内容的 `tool/result` 替换。工具配对边界策略及其缓存归 [`dsh-compaction` seam](../../compaction/compaction/README.md) 所有;此包拥有有序 surface 成员关系、替换校验与 `replaceGeneration`。
94
94
 
95
95
  ## 模型体验
96
96
 
@@ -98,7 +98,7 @@
98
98
 
99
99
  #### 模型看到的内容
100
100
 
101
- 模型会原样接收 `user/message`、`assistant/message` 和 `tool/result` surface 条目中的完整消息。其标识、角色、来源和内容块都与创建时确定的值相同;投影不会生成标识。提示词封装只改变面向人的呈现;其前缀上下文和请求分隔符已经位于事件内容中。工具调用包含在 assistant 消息内。分片、边界、用量、hook 记录、todo 记录以及其他仅日志事件不会添加消息。
101
+ 模型会原样接收 `user/message`、`assistant/message` 和 `tool/result` surface 条目中的完整消息。其标识、角色、来源和内容块都与创建时确定的值相同;投影不会生成标识。提示词封装只改变面向人的呈现;其前缀上下文和请求分隔符已经位于事件内容中。工具调用包含在 assistant 消息内。分片、边界、用量、钩子记录、todo 记录以及其他仅日志事件不会添加消息。
102
102
 
103
103
  #### Token 影响
104
104
 
@@ -116,7 +116,7 @@
116
116
 
117
117
  #### Token 影响
118
118
 
119
- 完整会话的 token 增量为零。恢复时,每个修复后的调用都会添加保留的、针对具体风险的错误文本。
119
+ 未受损会话的 token 增量为零。恢复时,每个修复后的调用都会添加保留的、针对具体风险的错误文本。
120
120
 
121
121
  #### KV Cache 影响
122
122
 
@@ -138,7 +138,7 @@
138
138
 
139
139
  ## 已知限制与暂缓事项
140
140
 
141
- - **会话分支/树**(pi 风格条目树):除非需要超越基于边界的 `fork()` 能力,否则暂缓。
141
+ - **会话分支/树结构**(pi 风格条目树):除非需要超越基于边界的 `fork()` 能力,否则暂缓。
142
142
  - **`fork()` 仅在实时会话的稳定边界处切分**:所选前缀结束时不得有开放轮次,且源会话必须位于存储中;[fork API](../../../.agents/notes/implemented/feature/2026-06-30-session-store-fork-api.md) 不支持对已持久化但未加载的会话进行 fork。
143
143
  - **`SESSION_FORMAT_VERSION` 固定为 `0`**:预发布阶段不承诺广泛兼容性;`Session` 只接受当前 seed 形状,后端拒绝其他任何版本并说明方向(更新的版本提示"由更新的 harness 写入,请升级";更旧的版本说明尚无升级路径)。不认识的事件类型同样被拒绝,除非信封带 `ignorable` 标记;版本机制见 [session-log 版本机制 Agent Note](../../../.agents/notes/implemented/architecture/2026-08-10-session-log-version-mechanism.md)。范围受限的存储导入升级应由持久化边界负责([政策](../../../AGENTS.md)、[消息标识机制引入前的消息恢复](../../../.agents/notes/implemented/bug-fix/2026-07-28-load-pre-identity-session-messages.md))。
144
144
  - **`TurnEndReasonMap` 不含 ACP(Agent Client Protocol)命名的 `refusal`/`max_turn_requests` 变体**:受生产方约束;只有当适配器或循环首次产生这些变体时才加入。
package/lib/index.js CHANGED
@@ -1079,10 +1079,10 @@ const KNOWN_SESSION_EVENT_TYPES = new Set([
1079
1079
  "assistant/message",
1080
1080
  "command/done",
1081
1081
  "command/run",
1082
- "compact/end",
1083
- "compact/prune",
1084
- "compact/start",
1085
- "compact/summary",
1082
+ "compaction/end",
1083
+ "compaction/prune",
1084
+ "compaction/start",
1085
+ "compaction/summary",
1086
1086
  "feedback/record",
1087
1087
  "goal/change",
1088
1088
  "hook/invoked",
@@ -1793,7 +1793,7 @@ var SessionStore = class extends Service {
1793
1793
  * Dispatch the awaited `session/flush` durability checkpoint for `session`,
1794
1794
  * with the carrier captured at {@link enter}. THE flush entry point: the
1795
1795
  * store owns the carrier, so callers (the checkpoint policy's per-request
1796
- * barrier, goal-session's idle checkpoint, teardown drains, and consumers
1796
+ * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
1797
1797
  * that flush themselves before reading storage) must come through here
1798
1798
  * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner,
1799
1799
  * one spelling, and the scoped-dispatch invariant can pin it.
@@ -9,7 +9,7 @@ import { Context, Service } from '@deepseek-ai/cordis';
9
9
  import type { Scoped } from '@deepseek-ai/dsh-scope';
10
10
  import type { Message } from '@deepseek-ai/dsh-llm';
11
11
  import { SessionId } from './types.ts';
12
- import type { TypeRTLookup } from '@deepseek-ai/dsh-type-meta';
12
+ import type { TypertLookup } from '@deepseek-ai/dsh-typert-protocol';
13
13
  import type { CreateSessionOptions, EpochHeader, PrepareSessionOptions, RequestContext, SessionEvent, SessionEventMap, SessionEventType, SessionHeader, SurfaceIntent, SurfaceEventType } from './types.ts';
14
14
  import type { SessionSurface } from './surface.ts';
15
15
  export * from './types.ts';
@@ -75,9 +75,9 @@ declare module '@deepseek-ai/cordis' {
75
75
  'session/flush'(this: Scoped<Session>, session: Session): Promise<void> | void;
76
76
  }
77
77
  }
78
- declare module '@deepseek-ai/dsh-type-meta' {
79
- interface TypeRTLookupMap {
80
- session: TypeRTLookup<Session, SessionId>;
78
+ declare module '@deepseek-ai/dsh-typert-protocol' {
79
+ interface TypertLookupMap {
80
+ session: TypertLookup<Session, SessionId>;
81
81
  }
82
82
  }
83
83
  /**
@@ -373,7 +373,7 @@ export declare class SessionStore extends Service {
373
373
  * Dispatch the awaited `session/flush` durability checkpoint for `session`,
374
374
  * with the carrier captured at {@link enter}. THE flush entry point: the
375
375
  * store owns the carrier, so callers (the checkpoint policy's per-request
376
- * barrier, goal-session's idle checkpoint, teardown drains, and consumers
376
+ * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
377
377
  * that flush themselves before reading storage) must come through here
378
378
  * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner,
379
379
  * one spelling, and the scoped-dispatch invariant can pin it.
@@ -868,7 +868,7 @@ export class SessionStore extends Service {
868
868
  * Dispatch the awaited `session/flush` durability checkpoint for `session`,
869
869
  * with the carrier captured at {@link enter}. THE flush entry point: the
870
870
  * store owns the carrier, so callers (the checkpoint policy's per-request
871
- * barrier, goal-session's idle checkpoint, teardown drains, and consumers
871
+ * barrier, goal-round-driver's idle checkpoint, teardown drains, and consumers
872
872
  * that flush themselves before reading storage) must come through here
873
873
  * rather than dispatch a raw `ctx.parallel('session/flush', …)` — one owner,
874
874
  * one spelling, and the scoped-dispatch invariant can pin it.
@@ -25,10 +25,10 @@ export const KNOWN_SESSION_EVENT_TYPES = new Set([
25
25
  'assistant/message',
26
26
  'command/done',
27
27
  'command/run',
28
- 'compact/end',
29
- 'compact/prune',
30
- 'compact/start',
31
- 'compact/summary',
28
+ 'compaction/end',
29
+ 'compaction/prune',
30
+ 'compaction/start',
31
+ 'compaction/summary',
32
32
  'feedback/record',
33
33
  'goal/change',
34
34
  'hook/invoked',
@@ -76,7 +76,7 @@ export function deriveEventMessage(event) {
76
76
  // Ordinary prompts and injected context project in user role: the event's
77
77
  // model-facing content stays verbatim. Do NOT re-add per-type framing
78
78
  // (e.g. `<context>`) here: framing is caller-owned — a producer bakes it
79
- // into `content`, as workspace-context does with `<system-reminder>` — or,
79
+ // into `content`, as agent-instructions does with `<system-reminder>` — or,
80
80
  // if reintroduced, must be driven by the event `meta` map and a dedicated
81
81
  // renderer, keeping this projection a verbatim pass-through. See the
82
82
  // deferred design note in
@@ -343,8 +343,8 @@ export interface SessionEventMap {
343
343
  * companion deliberately constrains nothing here, so a plugin appending one
344
344
  * would silently classify every live bracket before it as seed history.
345
345
  *
346
- * An owner of a standalone open/close bracket (`compact/start` …
347
- * `compact/end`) reads it because seed history and live work are otherwise
346
+ * An owner of a standalone open/close bracket (`compaction/start` …
347
+ * `compaction/end`) reads it because seed history and live work are otherwise
348
348
  * byte-identical: an unmatched opening marker before this event belongs to
349
349
  * an ended lifecycle, whatever ended it. NOT a liveness signal about other
350
350
  * writers — a concurrently live session holds its own boundary elsewhere,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-session",
3
3
  "description": "Event-sourced session store for the DeepSeek Harness",
4
- "version": "0.0.1-rc.2",
4
+ "version": "0.0.1-rc.3",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
7
7
  },
@@ -41,20 +41,20 @@
41
41
  ],
42
42
  "license": "BSD-3-Clause",
43
43
  "peerDependencies": {
44
- "@deepseek-ai/dsh-brand": "^0.0.1-rc.2",
45
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.2",
46
- "@deepseek-ai/dsh-llm": "^0.0.1-rc.2",
47
- "@deepseek-ai/dsh-scope": "^0.0.1-rc.2",
48
- "@deepseek-ai/dsh-type-meta": "^0.0.1-rc.2",
44
+ "@deepseek-ai/dsh-brand": "^0.0.1-rc.3",
45
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.3",
46
+ "@deepseek-ai/dsh-llm": "^0.0.1-rc.3",
47
+ "@deepseek-ai/dsh-scope": "^0.0.1-rc.3",
48
+ "@deepseek-ai/dsh-typert-protocol": "^0.0.1-rc.3",
49
49
  "@deepseek-ai/cordis": "^4.0.1-rc.1"
50
50
  },
51
51
  "devDependencies": {
52
- "@deepseek-ai/dsh-brand": "^0.0.1-rc.2",
53
- "@deepseek-ai/dsh-invariants": "^0.0.1-rc.2",
54
- "@deepseek-ai/dsh-llm": "^0.0.1-rc.2",
55
- "@deepseek-ai/dsh-scope": "^0.0.1-rc.2",
56
- "@deepseek-ai/dsh-type-meta": "^0.0.1-rc.2",
57
- "@deepseek-ai/dsh-typert-registry": "^0.0.1-rc.2",
52
+ "@deepseek-ai/dsh-brand": "^0.0.1-rc.3",
53
+ "@deepseek-ai/dsh-invariants": "^0.0.1-rc.3",
54
+ "@deepseek-ai/dsh-llm": "^0.0.1-rc.3",
55
+ "@deepseek-ai/dsh-scope": "^0.0.1-rc.3",
56
+ "@deepseek-ai/dsh-typert-protocol": "^0.0.1-rc.3",
57
+ "@deepseek-ai/dsh-typert-registry": "^0.0.1-rc.3",
58
58
  "@deepseek-ai/cordis": "^4.0.1-rc.1"
59
59
  }
60
60
  }