@morlay/session-rdb 0.0.13 → 0.0.14
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/dist/artifact.d.mts +14 -1
- package/dist/artifact.mjs +3 -3
- package/dist/{import-D2vUnUZe.mjs → import-B-tf5vQn.mjs} +1 -1
- package/dist/import.mjs +1 -1
- package/dist/index.mjs +3 -3
- package/dist/{schema-B-8G4lWc.mjs → schema-BfPVmr1X.mjs} +26 -3
- package/dist/{sqlite-DIXY-dFZ.mjs → sqlite-BUWnS0so.mjs} +1 -1
- package/dist/storage.mjs +2 -2
- package/package.json +1 -1
- package/src/log.ts +43 -3
package/dist/artifact.d.mts
CHANGED
|
@@ -35,8 +35,21 @@ declare function remapShadowedRange(range: {
|
|
|
35
35
|
start: number;
|
|
36
36
|
end: number;
|
|
37
37
|
};
|
|
38
|
+
declare function remapShadowedSeqs(seqs: readonly number[], remap: (seq: number) => number): number[];
|
|
38
39
|
declare function rowToEvent(row: EventRow, seqMap: ReadonlyMap<number, number>): SessionEvent;
|
|
39
40
|
declare function buildSeqMap(rows: readonly Pick<EventRow, "fSequence" | "fOriginalSeq">[]): Map<number, number>;
|
|
41
|
+
/**
|
|
42
|
+
* 读取时重计算 replace 的 sourceEventSeqs(sourceEventSeqs 不落库)。
|
|
43
|
+
*
|
|
44
|
+
* 优先采用紧邻 metering 事件(compaction/summary | compaction/prune)的
|
|
45
|
+
* shadowedSeqs:它是压缩事务落库的**权威被遮蔽节点列表**(range 只是首尾
|
|
46
|
+
* 边界对,压缩竞态下可能漏掉并发落地的节点——range 数值扫描会漏掉这些
|
|
47
|
+
* 节点,使上游 assertProvenance 报 missing)。shadowedSeqs 已由 rowToEvent
|
|
48
|
+
* 重映射到稠密坐标,与 replace 的 surfaceOp range 同空间。
|
|
49
|
+
*
|
|
50
|
+
* 无紧邻 metering 事件时回退到 range 数值扫描(历史数据 / 非压缩 replace,
|
|
51
|
+
* 如 tool-result pruner 的旧样式),保证既有行为不变。
|
|
52
|
+
*/
|
|
40
53
|
declare function recomputeReplaceProvenance(events: SessionEvent[]): void;
|
|
41
54
|
declare function findSurfaceRepairs(events: readonly SessionEvent[]): {
|
|
42
55
|
degradeToAppend: Set<number>;
|
|
@@ -61,4 +74,4 @@ declare function scanRows(rows: readonly EventRow[], base?: number, seqMap?: Rea
|
|
|
61
74
|
};
|
|
62
75
|
declare function toJsonlArtifact(meta: SessionHeader, inheritedEventCount: number, events: readonly SessionEvent[]): string;
|
|
63
76
|
//#endregion
|
|
64
|
-
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, buildSeqMap, expandProvenanceFromStorage, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, remapShadowedRange, remapSurfaceOp, repairOrphanInboxSplices, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, toJsonlArtifact };
|
|
77
|
+
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, buildSeqMap, expandProvenanceFromStorage, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, remapShadowedRange, remapShadowedSeqs, remapSurfaceOp, repairOrphanInboxSplices, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, toJsonlArtifact };
|
package/dist/artifact.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { a as parseJsonlArtifact, i as parseImportZip, n as SESSION_LOG_ARTIFACT_FILENAME, o as persistImport, r as expandProvenanceFromStorage, s as registerSessionImport, t as SESSION_IMPORT_PATH } from "./import-
|
|
3
|
-
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, buildSeqMap, expandProvenanceFromStorage, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, remapShadowedRange, remapSurfaceOp, repairOrphanInboxSplices, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, toJsonlArtifact };
|
|
1
|
+
import { A as sessionInsertRow, C as remapSurfaceOp, D as rowToMeta, E as rowToEvent, O as scanRows, S as remapShadowedSeqs, T as repairSurfaceOps, _ as buildSeqMap, b as recomputeReplaceProvenance, j as toJsonlArtifact, k as sessionConflictRow, v as findSurfaceRepairs, w as repairOrphanInboxSplices, x as remapShadowedRange, y as orphanInboxSpliceSeqs } from "./schema-BfPVmr1X.mjs";
|
|
2
|
+
import { a as parseJsonlArtifact, i as parseImportZip, n as SESSION_LOG_ARTIFACT_FILENAME, o as persistImport, r as expandProvenanceFromStorage, s as registerSessionImport, t as SESSION_IMPORT_PATH } from "./import-B-tf5vQn.mjs";
|
|
3
|
+
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, buildSeqMap, expandProvenanceFromStorage, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, remapShadowedRange, remapShadowedSeqs, remapSurfaceOp, repairOrphanInboxSplices, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, toJsonlArtifact };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { D as rowToMeta, l as isPersistedEvent } from "./schema-BfPVmr1X.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { SESSION_FORMAT_VERSION, SessionLogOffset, decodeSeqRanges, decodeStorageRecord } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { SessionBranch, SessionBranchError, balanceRewindPrefix, buildTimeline } from "@morlay/session-branch";
|
package/dist/import.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as parseJsonlArtifact, i as parseImportZip, n as SESSION_LOG_ARTIFACT_FILENAME, o as persistImport, r as expandProvenanceFromStorage, s as registerSessionImport, t as SESSION_IMPORT_PATH } from "./import-
|
|
1
|
+
import { a as parseJsonlArtifact, i as parseImportZip, n as SESSION_LOG_ARTIFACT_FILENAME, o as persistImport, r as expandProvenanceFromStorage, s as registerSessionImport, t as SESSION_IMPORT_PATH } from "./import-B-tf5vQn.mjs";
|
|
2
2
|
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, expandProvenanceFromStorage, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { i as WriteGuard, r as createTablesSql, t as SqliteBackend } from "./sqlite-
|
|
2
|
-
import { A as
|
|
3
|
-
import { c as SessionBranchRdb, l as SessionBranchRdbProvider, s as registerSessionImport, u as locateTurnEnd } from "./import-
|
|
1
|
+
import { i as WriteGuard, r as createTablesSql, t as SqliteBackend } from "./sqlite-BUWnS0so.mjs";
|
|
2
|
+
import { A as sessionInsertRow, D as rowToMeta, O as scanRows, T as repairSurfaceOps, _ as buildSeqMap, a as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, b as recomputeReplaceProvenance, g as toPostgresSchema, i as SCHEMA_VERSION, j as toJsonlArtifact, k as sessionConflictRow, l as isPersistedEvent, m as postgresTableDefs, n as EPHEMERAL_EVENT_TYPES, o as eventDimensions, r as EVENT_ENCODING, t as DEFAULT_BUSY_TIMEOUT_MS, w as repairOrphanInboxSplices } from "./schema-BfPVmr1X.mjs";
|
|
3
|
+
import { c as SessionBranchRdb, l as SessionBranchRdbProvider, s as registerSessionImport, u as locateTurnEnd } from "./import-B-tf5vQn.mjs";
|
|
4
4
|
import z from "@deepseek-ai/schemastery";
|
|
5
5
|
import { randomUUID } from "node:crypto";
|
|
6
6
|
import { Pool } from "pg";
|
|
@@ -59,6 +59,9 @@ function remapShadowedRange(range, remap) {
|
|
|
59
59
|
end: remap(range.end)
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
|
+
function remapShadowedSeqs(seqs, remap) {
|
|
63
|
+
return seqs.map(remap);
|
|
64
|
+
}
|
|
62
65
|
function rowToEvent(row, seqMap) {
|
|
63
66
|
const remap = (seq) => seqMap.get(seq) ?? seq;
|
|
64
67
|
const surfaceOp = row.fSurfaceOp !== null ? remapSurfaceOp(JSON.parse(row.fSurfaceOp), remap) : void 0;
|
|
@@ -66,6 +69,7 @@ function rowToEvent(row, seqMap) {
|
|
|
66
69
|
if (row.fType === "compaction/summary" || row.fType === "compaction/prune") {
|
|
67
70
|
const metering = data;
|
|
68
71
|
if (metering.shadowedRange !== void 0) metering.shadowedRange = remapShadowedRange(metering.shadowedRange, remap);
|
|
72
|
+
if (metering.shadowedSeqs !== void 0) metering.shadowedSeqs = remapShadowedSeqs(metering.shadowedSeqs, remap);
|
|
69
73
|
}
|
|
70
74
|
return {
|
|
71
75
|
type: row.fType,
|
|
@@ -85,12 +89,31 @@ const SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
85
89
|
"assistant/message",
|
|
86
90
|
"tool/result"
|
|
87
91
|
]);
|
|
92
|
+
const METERING_EVENT_TYPES = /* @__PURE__ */ new Set(["compaction/summary", "compaction/prune"]);
|
|
93
|
+
/**
|
|
94
|
+
* 读取时重计算 replace 的 sourceEventSeqs(sourceEventSeqs 不落库)。
|
|
95
|
+
*
|
|
96
|
+
* 优先采用紧邻 metering 事件(compaction/summary | compaction/prune)的
|
|
97
|
+
* shadowedSeqs:它是压缩事务落库的**权威被遮蔽节点列表**(range 只是首尾
|
|
98
|
+
* 边界对,压缩竞态下可能漏掉并发落地的节点——range 数值扫描会漏掉这些
|
|
99
|
+
* 节点,使上游 assertProvenance 报 missing)。shadowedSeqs 已由 rowToEvent
|
|
100
|
+
* 重映射到稠密坐标,与 replace 的 surfaceOp range 同空间。
|
|
101
|
+
*
|
|
102
|
+
* 无紧邻 metering 事件时回退到 range 数值扫描(历史数据 / 非压缩 replace,
|
|
103
|
+
* 如 tool-result pruner 的旧样式),保证既有行为不变。
|
|
104
|
+
*/
|
|
88
105
|
function recomputeReplaceProvenance(events) {
|
|
89
|
-
for (
|
|
90
|
-
const raw =
|
|
106
|
+
for (let i = 0; i < events.length; i++) {
|
|
107
|
+
const raw = events[i];
|
|
91
108
|
const op = raw.surfaceOp;
|
|
92
109
|
if (typeof op !== "object" || op === null || op.op !== "replace") continue;
|
|
93
110
|
const { start, end } = op;
|
|
111
|
+
const metering = i > 0 ? events[i - 1] : void 0;
|
|
112
|
+
const meteringData = metering !== void 0 && METERING_EVENT_TYPES.has(metering.type) ? metering.data : void 0;
|
|
113
|
+
if (meteringData?.shadowedSeqs !== void 0) {
|
|
114
|
+
raw.sourceEventSeqs = meteringData.shadowedSeqs;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
94
117
|
const refs = [];
|
|
95
118
|
for (const candidate of events) if (candidate.seq >= start && candidate.seq <= end && SURFACE_EVENT_TYPES.has(candidate.type)) refs.push(candidate.seq);
|
|
96
119
|
raw.sourceEventSeqs = refs;
|
|
@@ -849,4 +872,4 @@ function eventDimensions(event) {
|
|
|
849
872
|
}
|
|
850
873
|
}
|
|
851
874
|
//#endregion
|
|
852
|
-
export {
|
|
875
|
+
export { sessionInsertRow as A, remapSurfaceOp as C, rowToMeta as D, rowToEvent as E, scanRows as O, remapShadowedSeqs as S, repairSurfaceOps as T, buildSeqMap as _, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID as a, recomputeReplaceProvenance as b, isEphemeralType as c, tPersistenceState as d, tSessionEvents as f, toPostgresSchema as g, sqliteTableDefs as h, SCHEMA_VERSION as i, toJsonlArtifact as j, sessionConflictRow as k, isPersistedEvent as l, postgresTableDefs as m, EPHEMERAL_EVENT_TYPES as n, eventDimensions as o, tSessions as p, EVENT_ENCODING as r, eventKind as s, DEFAULT_BUSY_TIMEOUT_MS as t, tEvents as u, findSurfaceRepairs as v, repairOrphanInboxSplices as w, remapShadowedRange as x, orphanInboxSpliceSeqs as y };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as sessionInsertRow, a as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, d as tPersistenceState, f as tSessionEvents, h as sqliteTableDefs, k as sessionConflictRow, o as eventDimensions, p as tSessions, t as DEFAULT_BUSY_TIMEOUT_MS, u as tEvents } from "./schema-BfPVmr1X.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { and, desc, eq, gte, sql } from "drizzle-orm";
|
|
4
4
|
import { statSync } from "node:fs";
|
package/dist/storage.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { i as WriteGuard, n as openDatabase, t as SqliteBackend } from "./sqlite-
|
|
2
|
-
import { a as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, c as isEphemeralType, d as tPersistenceState, f as tSessionEvents, i as SCHEMA_VERSION, l as isPersistedEvent, n as EPHEMERAL_EVENT_TYPES, o as eventDimensions, p as tSessions, r as EVENT_ENCODING, s as eventKind, t as DEFAULT_BUSY_TIMEOUT_MS, u as tEvents } from "./schema-
|
|
1
|
+
import { i as WriteGuard, n as openDatabase, t as SqliteBackend } from "./sqlite-BUWnS0so.mjs";
|
|
2
|
+
import { a as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, c as isEphemeralType, d as tPersistenceState, f as tSessionEvents, i as SCHEMA_VERSION, l as isPersistedEvent, n as EPHEMERAL_EVENT_TYPES, o as eventDimensions, p as tSessions, r as EVENT_ENCODING, s as eventKind, t as DEFAULT_BUSY_TIMEOUT_MS, u as tEvents } from "./schema-BfPVmr1X.mjs";
|
|
3
3
|
export { DEFAULT_BUSY_TIMEOUT_MS, EPHEMERAL_EVENT_TYPES, EVENT_ENCODING, SCHEMA_VERSION, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, SqliteBackend, WriteGuard, eventDimensions, eventKind, isEphemeralType, isPersistedEvent, openDatabase, tEvents, tPersistenceState, tSessionEvents, tSessions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morlay/session-rdb",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.14",
|
|
4
4
|
"description": "RDB durable session backend for DeepSeek Harness: implements both session-persistence and session-branch (rewind / retry / fork) providers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"branch",
|
package/src/log.ts
CHANGED
|
@@ -90,6 +90,13 @@ export function remapShadowedRange(
|
|
|
90
90
|
return { start: remap(range.start), end: remap(range.end) };
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
export function remapShadowedSeqs(
|
|
94
|
+
seqs: readonly number[],
|
|
95
|
+
remap: (seq: number) => number,
|
|
96
|
+
): number[] {
|
|
97
|
+
return seqs.map(remap);
|
|
98
|
+
}
|
|
99
|
+
|
|
93
100
|
export function rowToEvent(row: EventRow, seqMap: ReadonlyMap<number, number>): SessionEvent {
|
|
94
101
|
const remap = (seq: number): number => seqMap.get(seq) ?? seq;
|
|
95
102
|
const surfaceOp =
|
|
@@ -97,12 +104,21 @@ export function rowToEvent(row: EventRow, seqMap: ReadonlyMap<number, number>):
|
|
|
97
104
|
? remapSurfaceOp(JSON.parse(row.fSurfaceOp) as SurfaceOp, remap)
|
|
98
105
|
: undefined;
|
|
99
106
|
const data = JSON.parse(row.fData) as SessionEvent["data"];
|
|
100
|
-
// compaction 事件的 shadowedRange
|
|
107
|
+
// compaction 事件的 shadowedRange / shadowedSeqs 是插件合并字段,经结构化
|
|
108
|
+
// 视图重映射到稠密坐标。shadowedSeqs 是权威的被遮蔽节点列表(range 只是
|
|
109
|
+
// 首尾边界对,压缩竞态下可能漏掉并发落地的节点),replace 的 provenance
|
|
110
|
+
// 重计算依赖它,必须与 range 同空间。
|
|
101
111
|
if (row.fType === "compaction/summary" || row.fType === "compaction/prune") {
|
|
102
|
-
const metering = data as unknown as {
|
|
112
|
+
const metering = data as unknown as {
|
|
113
|
+
shadowedRange?: { start: number; end: number };
|
|
114
|
+
shadowedSeqs?: number[];
|
|
115
|
+
};
|
|
103
116
|
if (metering.shadowedRange !== undefined) {
|
|
104
117
|
metering.shadowedRange = remapShadowedRange(metering.shadowedRange, remap);
|
|
105
118
|
}
|
|
119
|
+
if (metering.shadowedSeqs !== undefined) {
|
|
120
|
+
metering.shadowedSeqs = remapShadowedSeqs(metering.shadowedSeqs, remap);
|
|
121
|
+
}
|
|
106
122
|
}
|
|
107
123
|
return {
|
|
108
124
|
type: row.fType as SessionEvent["type"],
|
|
@@ -125,14 +141,38 @@ export function buildSeqMap(
|
|
|
125
141
|
|
|
126
142
|
const SURFACE_EVENT_TYPES = new Set(["user/message", "assistant/message", "tool/result"]);
|
|
127
143
|
|
|
144
|
+
const METERING_EVENT_TYPES = new Set(["compaction/summary", "compaction/prune"]);
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* 读取时重计算 replace 的 sourceEventSeqs(sourceEventSeqs 不落库)。
|
|
148
|
+
*
|
|
149
|
+
* 优先采用紧邻 metering 事件(compaction/summary | compaction/prune)的
|
|
150
|
+
* shadowedSeqs:它是压缩事务落库的**权威被遮蔽节点列表**(range 只是首尾
|
|
151
|
+
* 边界对,压缩竞态下可能漏掉并发落地的节点——range 数值扫描会漏掉这些
|
|
152
|
+
* 节点,使上游 assertProvenance 报 missing)。shadowedSeqs 已由 rowToEvent
|
|
153
|
+
* 重映射到稠密坐标,与 replace 的 surfaceOp range 同空间。
|
|
154
|
+
*
|
|
155
|
+
* 无紧邻 metering 事件时回退到 range 数值扫描(历史数据 / 非压缩 replace,
|
|
156
|
+
* 如 tool-result pruner 的旧样式),保证既有行为不变。
|
|
157
|
+
*/
|
|
128
158
|
export function recomputeReplaceProvenance(events: SessionEvent[]): void {
|
|
129
|
-
for (
|
|
159
|
+
for (let i = 0; i < events.length; i++) {
|
|
160
|
+
const event = events[i]!;
|
|
130
161
|
const raw = event as SessionEvent & { surfaceOp?: unknown; sourceEventSeqs?: number[] };
|
|
131
162
|
const op = raw.surfaceOp;
|
|
132
163
|
if (typeof op !== "object" || op === null || (op as { op?: string }).op !== "replace") {
|
|
133
164
|
continue;
|
|
134
165
|
}
|
|
135
166
|
const { start, end } = op as { start: number; end: number };
|
|
167
|
+
const metering = i > 0 ? events[i - 1] : undefined;
|
|
168
|
+
const meteringData =
|
|
169
|
+
metering !== undefined && METERING_EVENT_TYPES.has(metering.type)
|
|
170
|
+
? (metering.data as unknown as { shadowedSeqs?: number[] })
|
|
171
|
+
: undefined;
|
|
172
|
+
if (meteringData?.shadowedSeqs !== undefined) {
|
|
173
|
+
raw.sourceEventSeqs = meteringData.shadowedSeqs;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
136
176
|
const refs: number[] = [];
|
|
137
177
|
for (const candidate of events) {
|
|
138
178
|
if (
|