@deepseek-ai/dsh-session-log-deepseek 0.1.2-alpha.5 → 0.1.3-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 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/session/session-log-deepseek/README.md
5
- README.md: b08b2d3cde78e7a3cf7050e90ff57655ad70d409
6
- README.zh.md: 0ee216c6c69178695eb629b2a81faef73103b13d
5
+ README.md: 047cd8133b88ceacce1fdaafa87a60611532a18c
6
+ README.zh.md: be6b97bc889a037847289d4f5757c12823969a63
package/README.md CHANGED
@@ -34,12 +34,12 @@ Shipped profiles mount the plugin so an overlay can enable it, but the default c
34
34
  <a id="request-field"></a>
35
35
  ## Request field
36
36
 
37
- For a request carrying a live `sessionId`, the plugin folds the greatest accepted watermark for that exact Session identity, snapshots `Session.events`, and sends the contiguous suffix after the watermark. A process-local fold scans each event once and consumes later appends incrementally; restart and HMR rebuild it from the durable log. The version-1 field contains a v0-compatible raw session header (`seedLength` is present only for a seeded Session), numeric `afterSeq` and `throughSeq`, and every complete canonical event translated to raw-number envelope fields. Forked sessions ignore inherited parent watermarks because each watermark records the Session id sent on the accepted request.
37
+ For a request carrying a live `sessionId`, the plugin folds the greatest accepted watermark for that exact Session format generation, snapshots `Session.events`, and sends the contiguous suffix after the watermark. A process-local fold scans each event once and consumes later appends incrementally; restart and HMR rebuild it from the durable log. The version-1 field contains `sessionFormatVersion`, a raw session header (`seedLength` is present only for a seeded Session), numeric `afterSeq` and `throughSeq`, and every complete canonical event translated to raw-number envelope fields. Forked sessions ignore inherited parent watermarks because both the recorded Session id and format generation must match the request source.
38
38
 
39
39
  <a id="acceptance-and-retry"></a>
40
40
  ## Acceptance and retry
41
41
 
42
- The DeepSeek adapter calls the prepared contribution's `accept()` after HTTP 2xx, before it consumes the SSE body. Acceptance appends `session-log-deepseek/delivery-accepted` with the uploaded `throughSeq`; the next request uploads that event as part of its new suffix. Transport and non-2xx failures append no acceptance record, so later requests resend the uncertain range. Concurrent deliveries may be accepted out of order; folding the maximum matching `throughSeq` prevents cursor regression.
42
+ The DeepSeek adapter calls the prepared contribution's `accept()` after HTTP 2xx, before it consumes the SSE body. Acceptance appends `session-log-deepseek/delivery-accepted` with the uploaded `throughSeq` and `sessionFormatVersion`; a record that omits the format field denotes v0. The next request uploads that event as part of its new suffix. Transport and non-2xx failures append no acceptance record, so later requests resend the uncertain range. Concurrent deliveries may be accepted out of order; folding the maximum matching `throughSeq` prevents cursor regression.
43
43
 
44
44
  A crash after server acceptance but before the watermark reaches persistence can replay an accepted range after restart. This is the at-least-once failure direction: uncertainty creates duplicates, never a skipped sequence. The ordinary session checkpoint policy persists the watermark at the next semantic checkpoint; this plugin performs no independent I/O.
45
45
 
package/README.zh.md CHANGED
@@ -34,12 +34,12 @@ kind: "package-reference"
34
34
  <a id="request-field"></a>
35
35
  ## 请求字段
36
36
 
37
- 对于携带存活 `sessionId` 的请求,插件会折叠该确切会话身份的最大已接受水位,对 `Session.events` 取快照,并发送水位之后的连续后缀。进程内 fold 会让每条事件只被扫描一次并增量消费后续追加;重启与 HMR 会从持久日志重建它。版本 1 字段包含兼容 v0 的原始会话 header(仅 seeded Session 携带 `seedLength`)、数值型 `afterSeq` 与 `throughSeq`,以及把完整权威事件翻译为原始数值 envelope 字段后的数组元素。每个水位都会记录已接受请求发送的会话 id,因此 fork 会话会忽略从父会话继承的水位。
37
+ 对于携带存活 `sessionId` 的请求,插件会折叠该确切会话格式代的最大已接受水位,对 `Session.events` 取快照,并发送水位之后的连续后缀。进程内 fold 会让每条事件只被扫描一次并增量消费后续追加;重启与 HMR 会从持久日志重建它。版本 1 字段包含 `sessionFormatVersion`、原始会话 header(仅 seeded Session 携带 `seedLength`)、数值型 `afterSeq` 与 `throughSeq`,以及把完整权威事件翻译为原始数值 envelope 字段后的数组元素。只有记录的会话 id 与格式代均匹配请求来源时水位才生效,因此 fork 会话会忽略从父会话继承的水位。
38
38
 
39
39
  <a id="acceptance-and-retry"></a>
40
40
  ## 接受与重试
41
41
 
42
- DeepSeek 适配器会在 HTTP 2xx 后、消费 SSE(Server-Sent Events)正文前调用已准备贡献的 `accept()`。接受操作会追加 `session-log-deepseek/delivery-accepted` 及已上传的 `throughSeq`;下一次请求再把该事件作为新后缀的一部分上传。传输失败与非 2xx 失败不会追加接受记录,因此后续请求会重发不确定范围。并发交付可能乱序得到接受;折叠匹配记录中最大的 `throughSeq` 可以防止游标回退。
42
+ DeepSeek 适配器会在 HTTP 2xx 后、消费 SSE(Server-Sent Events)正文前调用已准备贡献的 `accept()`。接受操作会追加 `session-log-deepseek/delivery-accepted`、已上传的 `throughSeq` 与 `sessionFormatVersion`;省略格式字段的记录表示 v0。下一次请求再把该事件作为新后缀的一部分上传。传输失败与非 2xx 失败不会追加接受记录,因此后续请求会重发不确定范围。并发交付可能乱序得到接受;折叠匹配记录中最大的 `throughSeq` 可以防止游标回退。
43
43
 
44
44
  服务端接受后、持久化水位前发生崩溃,可能让恢复后的进程重放已经接受的范围。这是至少一次交付的失败方向:不确定性会制造重复,绝不会跳过序列。普通会话检查点策略会在下一个语义检查点持久化水位;本插件不执行独立 I/O。
45
45
 
package/lib/index.js CHANGED
@@ -15,7 +15,7 @@ const inject = ["deepseekLlmApiExtensions", "sessions"];
15
15
  /** Validated Session-log request contribution configuration. */
16
16
  const Config = z.object({ enabled: z.boolean().default(false) });
17
17
  const acceptanceFolds = /* @__PURE__ */ new WeakMap();
18
- /** Translate logical Session metadata back to the stable version-0 wire header. */
18
+ /** Translate logical Session metadata to raw external request fields. */
19
19
  function wireHeader(session) {
20
20
  const header = session.header;
21
21
  return {
@@ -49,7 +49,7 @@ function wireEvent(event) {
49
49
  };
50
50
  }
51
51
  /**
52
- * Highest confirmed sequence for this exact session identity.
52
+ * Highest confirmed sequence for this exact Session format generation.
53
53
  * @param session - canonical log whose matching acceptance events are folded.
54
54
  * @returns greatest accepted sequence, or `-1` before any accepted request.
55
55
  */
@@ -62,6 +62,9 @@ function acceptedThrough(session) {
62
62
  const event = session.eventAt(SessionSeq(index));
63
63
  if (event === void 0) throw new Error(`session-log-deepseek: missing event ${String(index)} below captured length ${String(length)}`);
64
64
  if (event.type !== "session-log-deepseek/delivery-accepted") continue;
65
+ const acceptedFormatVersion = event.data.sessionFormatVersion ?? 0;
66
+ if (!Number.isSafeInteger(acceptedFormatVersion) || acceptedFormatVersion < 0 || Object.is(acceptedFormatVersion, -0)) throw new Error(`session-log-deepseek: malformed acceptance format version at seq ${event.seq}`);
67
+ if (acceptedFormatVersion !== session.header.version) continue;
65
68
  let acceptedSeq;
66
69
  try {
67
70
  acceptedSeq = SessionSeq(event.data.throughSeq);
@@ -96,6 +99,7 @@ function apply(ctx, config) {
96
99
  return {
97
100
  value: {
98
101
  version: 1,
102
+ sessionFormatVersion: session.header.version,
99
103
  session: wireHeader(session),
100
104
  afterSeq: Number(afterSeq),
101
105
  throughSeq: Number(throughSeq),
@@ -104,6 +108,7 @@ function apply(ctx, config) {
104
108
  accept: () => {
105
109
  session.append("session-log-deepseek/delivery-accepted", {
106
110
  sessionId: session.id,
111
+ sessionFormatVersion: session.header.version,
107
112
  throughSeq
108
113
  });
109
114
  }
package/lib/invariant.js CHANGED
@@ -9,6 +9,9 @@ const inject = ["invariants"];
9
9
  /** Validate one acceptance watermark against its containing event and session. */
10
10
  function validateDeliveryAccepted(session, event, fail) {
11
11
  const { sessionId, throughSeq } = event.data;
12
+ const acceptedFormatVersion = event.data.sessionFormatVersion ?? 0;
13
+ if (!Number.isSafeInteger(acceptedFormatVersion) || acceptedFormatVersion < 0 || Object.is(acceptedFormatVersion, -0)) fail(`session-log-deepseek/delivery-accepted sessionFormatVersion must be a non-negative safe integer, got ${String(acceptedFormatVersion)}`);
14
+ if (acceptedFormatVersion !== session.header.version) return;
12
15
  const inherited = session.header.parentSession !== void 0 && !session.isOwnSeq(event.seq);
13
16
  if (sessionId !== session.id && !inherited) fail("a non-inherited session-log-deepseek/delivery-accepted event must name its containing session");
14
17
  let acceptedSeq;
@@ -20,7 +20,7 @@ export interface Config {
20
20
  /** Validated Session-log request contribution configuration. */
21
21
  export declare const Config: z<Config>;
22
22
  /**
23
- * Highest confirmed sequence for this exact session identity.
23
+ * Highest confirmed sequence for this exact Session format generation.
24
24
  * @param session - canonical log whose matching acceptance events are folded.
25
25
  * @returns greatest accepted sequence, or `-1` before any accepted request.
26
26
  */
@@ -16,7 +16,7 @@ export const Config = z.object({
16
16
  enabled: z.boolean().default(false),
17
17
  });
18
18
  const acceptanceFolds = new WeakMap();
19
- /** Translate logical Session metadata back to the stable version-0 wire header. */
19
+ /** Translate logical Session metadata to raw external request fields. */
20
20
  function wireHeader(session) {
21
21
  const header = session.header;
22
22
  return {
@@ -52,7 +52,7 @@ function wireEvent(event) {
52
52
  };
53
53
  }
54
54
  /**
55
- * Highest confirmed sequence for this exact session identity.
55
+ * Highest confirmed sequence for this exact Session format generation.
56
56
  * @param session - canonical log whose matching acceptance events are folded.
57
57
  * @returns greatest accepted sequence, or `-1` before any accepted request.
58
58
  */
@@ -68,6 +68,14 @@ export function acceptedThrough(session) {
68
68
  }
69
69
  if (event.type !== 'session-log-deepseek/delivery-accepted')
70
70
  continue;
71
+ const acceptedFormatVersion = event.data.sessionFormatVersion ?? 0;
72
+ if (!Number.isSafeInteger(acceptedFormatVersion)
73
+ || acceptedFormatVersion < 0
74
+ || Object.is(acceptedFormatVersion, -0)) {
75
+ throw new Error(`session-log-deepseek: malformed acceptance format version at seq ${event.seq}`);
76
+ }
77
+ if (acceptedFormatVersion !== session.header.version)
78
+ continue;
71
79
  let acceptedSeq;
72
80
  try {
73
81
  acceptedSeq = SessionSeq(event.data.throughSeq);
@@ -111,6 +119,7 @@ export function apply(ctx, config) {
111
119
  const suffix = session.snapshotEvents(SessionLogOffset(afterSeq + 1));
112
120
  const value = {
113
121
  version: 1,
122
+ sessionFormatVersion: session.header.version,
114
123
  session: wireHeader(session),
115
124
  afterSeq: Number(afterSeq),
116
125
  throughSeq: Number(throughSeq),
@@ -119,7 +128,11 @@ export function apply(ctx, config) {
119
128
  return {
120
129
  value,
121
130
  accept: () => {
122
- session.append('session-log-deepseek/delivery-accepted', { sessionId: session.id, throughSeq });
131
+ session.append('session-log-deepseek/delivery-accepted', {
132
+ sessionId: session.id,
133
+ sessionFormatVersion: session.header.version,
134
+ throughSeq,
135
+ });
123
136
  // TODO: Add an immediate lightweight checkpoint if duplicate replay after a 2xx crash window becomes unacceptable.
124
137
  },
125
138
  };
@@ -8,6 +8,15 @@ export const inject = ['invariants'];
8
8
  /** Validate one acceptance watermark against its containing event and session. */
9
9
  function validateDeliveryAccepted(session, event, fail) {
10
10
  const { sessionId, throughSeq } = event.data;
11
+ const acceptedFormatVersion = event.data.sessionFormatVersion ?? 0;
12
+ if (!Number.isSafeInteger(acceptedFormatVersion)
13
+ || acceptedFormatVersion < 0
14
+ || Object.is(acceptedFormatVersion, -0)) {
15
+ fail('session-log-deepseek/delivery-accepted sessionFormatVersion must be a non-negative safe integer'
16
+ + `, got ${String(acceptedFormatVersion)}`);
17
+ }
18
+ if (acceptedFormatVersion !== session.header.version)
19
+ return;
11
20
  const inherited = session.header.parentSession !== undefined
12
21
  && !session.isOwnSeq(event.seq);
13
22
  if (sessionId !== session.id && !inherited) {
@@ -1,7 +1,7 @@
1
1
  /** Wire types for lossless incremental DeepSeek session-log upload. */
2
2
  import type { SessionEvent } from '@deepseek-ai/dsh-session';
3
3
  import type { JsonValue } from '@deepseek-ai/dsh-util-values';
4
- /** Version-0 Session header fields serialized on the external request wire. */
4
+ /** Session header fields serialized as raw JSON primitives on the external request wire. */
5
5
  export interface DeepSeekSessionLogWireHeader {
6
6
  readonly version: number;
7
7
  readonly id: string;
@@ -33,6 +33,8 @@ export interface DeepSeekSessionLogWireEvent {
33
33
  /** Versioned incremental session-log field carried by an official DeepSeek request. */
34
34
  export interface DeepSeekSessionLogExtension {
35
35
  readonly version: 1;
36
+ /** Session format generation represented by this suffix. */
37
+ readonly sessionFormatVersion: number;
36
38
  readonly session: DeepSeekSessionLogWireHeader;
37
39
  /** Highest sequence durably recorded as accepted before this request, or `-1`. */
38
40
  readonly afterSeq: number;
@@ -52,6 +54,8 @@ declare module '@deepseek-ai/dsh-session/types' {
52
54
  'session-log-deepseek/delivery-accepted': {
53
55
  /** Session identity the accepted delivery carried; inherited fork markers retain the parent's id. */
54
56
  sessionId: import('@deepseek-ai/dsh-session/types').SessionId;
57
+ /** Accepted Session format generation; absence identifies version 0. */
58
+ sessionFormatVersion?: number;
55
59
  /** Last canonical event included in the accepted request. */
56
60
  throughSeq: import('@deepseek-ai/dsh-session/types').SessionSeq;
57
61
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-session-log-deepseek",
3
3
  "description": "Incremental lossless session-log request extension for the official DeepSeek LLM API",
4
- "version": "0.1.2-alpha.5",
4
+ "version": "0.1.3-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -37,20 +37,28 @@
37
37
  ],
38
38
  "license": "MIT",
39
39
  "dependencies": {
40
- "@deepseek-ai/dsh-brand": "^0.1.2-alpha.5",
41
- "@deepseek-ai/dsh-util-values": "^0.1.2-alpha.5",
40
+ "@deepseek-ai/dsh-brand": "^0.1.3-alpha.2",
41
+ "@deepseek-ai/dsh-util-values": "^0.1.3-alpha.2",
42
42
  "@deepseek-ai/schemastery": "^3.18.2"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "@deepseek-ai/cordis": "^4.0.2",
46
- "@deepseek-ai/dsh-deepseek-llm-api-extensions": "^0.1.2-alpha.5",
47
- "@deepseek-ai/dsh-session": "^0.1.2-alpha.5",
48
- "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.5"
46
+ "@deepseek-ai/dsh-deepseek-llm-api-extensions": "^0.1.3-alpha.2",
47
+ "@deepseek-ai/dsh-invariants": "^0.1.3-alpha.2",
48
+ "@deepseek-ai/dsh-session": "^0.1.3-alpha.2"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@deepseek-ai/cordis": "^4.0.2",
52
- "@deepseek-ai/dsh-deepseek-llm-api-extensions": "^0.1.2-alpha.5",
53
- "@deepseek-ai/dsh-invariants": "^0.1.2-alpha.5",
54
- "@deepseek-ai/dsh-session": "^0.1.2-alpha.5"
52
+ "@deepseek-ai/cordis-plugin-include": "^1.0.7",
53
+ "@deepseek-ai/cordis-plugin-loader": "^1.0.3",
54
+ "@deepseek-ai/dsh-command-feedback": "^0.1.3-alpha.2",
55
+ "@deepseek-ai/dsh-invariants": "^0.1.3-alpha.2",
56
+ "@deepseek-ai/dsh-llm": "^0.1.3-alpha.2",
57
+ "@deepseek-ai/dsh-llm-mock-server": "^0.1.3-alpha.2",
58
+ "@deepseek-ai/dsh-llm-deepseek": "^0.1.3-alpha.2",
59
+ "@deepseek-ai/dsh-message-feedback": "^0.1.3-alpha.2",
60
+ "@deepseek-ai/dsh-session": "^0.1.3-alpha.2",
61
+ "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.3-alpha.2",
62
+ "@deepseek-ai/dsh-deepseek-llm-api-extensions": "^0.1.3-alpha.2"
55
63
  }
56
64
  }