@morlay/session-rdb 0.0.15 → 0.0.16-alpha.1
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.md +11 -13
- package/dist/artifact.d.mts +30 -16
- package/dist/artifact.mjs +3 -3
- package/dist/{import-DFed8DBt.mjs → import-mZZgDBLd.mjs} +73 -83
- package/dist/import.d.mts +2 -3
- package/dist/import.mjs +2 -2
- package/dist/index-GdKkSSb-.d.mts +239 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +763 -168
- package/dist/log-DBFUBPhv.mjs +394 -0
- package/dist/{schema-CFXZURX7.d.mts → schema-COK7-wRV.d.mts} +3 -15
- package/dist/sqlite-CnWwGToZ.mjs +698 -0
- package/dist/storage.d.mts +2 -7
- package/dist/storage.mjs +2 -3
- package/dist/testing.d.mts +30 -1
- package/dist/testing.mjs +676 -1991
- package/drizzle/postgres/20260908072805_v2_initial/migration.sql +58 -0
- package/drizzle/postgres/20260908072805_v2_initial/snapshot.json +686 -0
- package/drizzle/postgres/20260908072806_v3_drop_original_seq/migration.sql +1 -0
- package/drizzle/postgres/20260908072806_v3_drop_original_seq/snapshot.json +673 -0
- package/drizzle/sqlite/20260908072751_v2_initial/migration.sql +53 -0
- package/drizzle/sqlite/20260908072751_v2_initial/snapshot.json +492 -0
- package/drizzle/sqlite/20260908072752_v3_drop_original_seq/migration.sql +6 -0
- package/drizzle/sqlite/20260908072752_v3_drop_original_seq/snapshot.json +513 -0
- package/package.json +17 -12
- package/src/adapters/index.ts +10 -2
- package/src/adapters/to-postgres.ts +19 -15
- package/src/adapters/to-sqlite.ts +20 -14
- package/src/{entities → adapters}/types.ts +7 -8
- package/src/backend.ts +0 -7
- package/src/branch.ts +29 -110
- package/src/drizzle/postgres-v2.ts +11 -0
- package/src/drizzle/postgres-v3.ts +11 -0
- package/src/drizzle/sqlite-v2.ts +10 -0
- package/src/drizzle/sqlite-v3.ts +11 -0
- package/src/entities/index.ts +2 -30
- package/src/entities/v2/index.ts +20 -0
- package/src/entities/v2/session-events.ts +11 -0
- package/src/entities/v3/events.ts +27 -0
- package/src/entities/v3/index.ts +27 -0
- package/src/entities/v3/persistence-state.ts +10 -0
- package/src/entities/v3/schema-meta.ts +9 -0
- package/src/entities/v3/session-events.ts +26 -0
- package/src/entities/v3/sessions.ts +20 -0
- package/src/import.ts +65 -57
- package/src/index.ts +929 -227
- package/src/invariant.ts +0 -2
- package/src/legacy.ts +110 -0
- package/src/log.ts +143 -91
- package/src/postgres.ts +75 -93
- package/src/schema.ts +3 -14
- package/src/sqlite.ts +59 -46
- package/src/testing/contract.ts +460 -375
- package/src/testing/coordinator-contract.ts +108 -1374
- package/src/testing.ts +1 -6
- package/dist/index-uUvn6gYp.d.mts +0 -111
- package/dist/schema-vwzwEXNE.mjs +0 -878
- package/dist/sqlite-CG_Qcx5C.mjs +0 -356
- package/src/adapters/ddl.ts +0 -77
- package/src/entities/events.ts +0 -27
- package/src/entities/persistence-state.ts +0 -10
- package/src/entities/schema-meta.ts +0 -9
- package/src/entities/session-events.ts +0 -29
- package/src/entities/sessions.ts +0 -20
- package/src/migrate.ts +0 -137
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @morlay/session-rdb
|
|
2
2
|
|
|
3
|
-
RDB(SQLite / PostgreSQL)持久会话后端(`ctx.sessionPersistence
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
RDB(SQLite / PostgreSQL)持久会话后端(`ctx.sessionPersistence`):实现上游
|
|
4
|
+
`SessionHandle` 模型(`create`/`open`/`flush`/`stat`/`list`),支持配置选择
|
|
5
|
+
SQLite 或 PostgreSQL 后端。设计细节(表结构、原样存储、并发写、方言差异、
|
|
6
|
+
仓库结构)见 [docs/design.md](docs/design.md)。
|
|
7
7
|
|
|
8
8
|
## 配置
|
|
9
9
|
|
|
@@ -59,18 +59,16 @@ type Config =
|
|
|
59
59
|
provider 抽象并**随插件自动注册 `ctx.sessionBranch`**(`SessionBranchRdb`),
|
|
60
60
|
在不修改上游代码的前提下提供 `rewind / retry / fork` 的持久化闭环:
|
|
61
61
|
|
|
62
|
-
- **`forkFrom`**:走标准
|
|
62
|
+
- **`forkFrom`**:走标准 handle 路径(`create` + `append`)从闭合边界
|
|
63
63
|
派生新会话(纯 append,`parentSession` / `seedLength` lineage);
|
|
64
64
|
- **`rewind`**:直接操作后端事务截断到闭合边界(DELETE 尾部 + head 回退 +
|
|
65
|
-
revision bump
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
截断);
|
|
65
|
+
revision bump),并更新并发写检测 head;**支持 live 会话**(`ctx.sessions`
|
|
66
|
+
有 owner 时同样就地工作:先 flush write-behind 缓冲 → 截断 RDB → 截断
|
|
67
|
+
live 内存 log 并复位 surface/header/context/derived 派生缓存 → 重置 agent
|
|
68
|
+
请求头标记 → 对齐 handle cursor;不调用 `load`——live 时 load 会先 flush
|
|
69
|
+
撤销截断);
|
|
71
70
|
- **`timeline`**:`parentSession` + `seedLength` 版本树投影(live 会话含
|
|
72
|
-
版本效果;cold
|
|
73
|
-
lineage 骨架)。
|
|
71
|
+
版本效果;cold 会话版本事件原样落库,效果详情可恢复)。
|
|
74
72
|
|
|
75
73
|
上层编排(edit / reroll / retry / rewind / fork 完整功能)由
|
|
76
74
|
`@morlay/ui-conversation-message-actions` 提供,或直接在 `ctx.sessionBranch` /
|
package/dist/artifact.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME,
|
|
1
|
+
import { v as EventRow, y as SessionRow } from "./schema-COK7-wRV.mjs";
|
|
2
|
+
import { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport } from "./import.mjs";
|
|
3
3
|
import { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
|
|
4
|
-
import { SessionEvent, SessionHeader
|
|
4
|
+
import { SessionEvent, SessionHeader } from "@deepseek-ai/dsh-session";
|
|
5
5
|
//#region src/log.d.ts
|
|
6
6
|
declare function rowToMeta(row: SessionRow): SessionHeader;
|
|
7
7
|
declare function sessionInsertRow(storage: SessionStorageMetadata, incarnation: string): {
|
|
@@ -27,17 +27,7 @@ declare function sessionConflictRow(storage: SessionStorageMetadata): {
|
|
|
27
27
|
fOrigin: string | null;
|
|
28
28
|
fDelegationDepth: number | null;
|
|
29
29
|
};
|
|
30
|
-
declare function
|
|
31
|
-
declare function remapShadowedRange(range: {
|
|
32
|
-
start: number;
|
|
33
|
-
end: number;
|
|
34
|
-
}, remap: (seq: number) => number): {
|
|
35
|
-
start: number;
|
|
36
|
-
end: number;
|
|
37
|
-
};
|
|
38
|
-
declare function remapShadowedSeqs(seqs: readonly number[], seqMap: ReadonlyMap<number, number>): number[];
|
|
39
|
-
declare function rowToEvent(row: EventRow, seqMap: ReadonlyMap<number, number>): SessionEvent;
|
|
40
|
-
declare function buildSeqMap(rows: readonly Pick<EventRow, "fSequence" | "fOriginalSeq">[]): Map<number, number>;
|
|
30
|
+
declare function rowToEvent(row: EventRow): SessionEvent;
|
|
41
31
|
/**
|
|
42
32
|
* 读取时重计算 replace 的 sourceEventSeqs(sourceEventSeqs 不落库)。
|
|
43
33
|
*
|
|
@@ -55,8 +45,32 @@ declare function findSurfaceRepairs(events: readonly SessionEvent[]): {
|
|
|
55
45
|
degradeToAppend: Set<number>;
|
|
56
46
|
addAppendMarker: Set<number>;
|
|
57
47
|
clearSurfaceOp: Set<number>;
|
|
48
|
+
clampEnd: Map<number, number>;
|
|
58
49
|
};
|
|
59
50
|
declare function repairSurfaceOps(events: SessionEvent[]): void;
|
|
51
|
+
/**
|
|
52
|
+
* 读取时补全 assistant 结算字段:旧写入器不落库 `stream`(v2 才把流式记录
|
|
53
|
+
* 嵌入消息),读回时缺失即补空数组——上游 seed 校验要求 turn/step/stream
|
|
54
|
+
* 三者齐备,缺失会让整个会话加载失败。
|
|
55
|
+
*/
|
|
56
|
+
declare function repairAssistantSettlement(events: SessionEvent[]): void;
|
|
57
|
+
/**
|
|
58
|
+
* 把紧邻 replace 的 metering 事件的 `shadowedRange` / `shadowedSeqs` 对齐到
|
|
59
|
+
* replace 最终的稠密 range。
|
|
60
|
+
*
|
|
61
|
+
* 旧写入器重编号事件后,metering 与 replace 一起落在旧坐标空间:二者数值
|
|
62
|
+
* 相等但与当前 surface 无关。夹取(或 range 本身已落在稠密空间而 metering
|
|
63
|
+
* 仍是旧值)后二者不再相等,而上游 token-meter 契约要求紧邻的 metering
|
|
64
|
+
* range 与 replace range 完全一致(否则报 no adjacent shadow price)。range
|
|
65
|
+
* 已一致时不改写——当前写入器保证一致,shadowedSeqs 的额外并发节点因此
|
|
66
|
+
* 原样保留。
|
|
67
|
+
*/
|
|
68
|
+
declare function syncMeteringRanges(events: SessionEvent[]): void;
|
|
69
|
+
/**
|
|
70
|
+
* 读取视图修复总入口:结算字段补全 → surface 语义修复 → metering 对齐 →
|
|
71
|
+
* provenance 重算 → 孤儿 inbox splice 改写。全部只作用于内存视图,不落库。
|
|
72
|
+
*/
|
|
73
|
+
declare function repairReadView(events: SessionEvent[]): void;
|
|
60
74
|
/**
|
|
61
75
|
* 定位无法从空状态增量重放的 agent/inbox/spliced 事件(孤儿操作)。
|
|
62
76
|
*
|
|
@@ -68,10 +82,10 @@ declare function repairSurfaceOps(events: SessionEvent[]): void;
|
|
|
68
82
|
declare function orphanInboxSpliceSeqs(events: readonly SessionEvent[]): Set<number>;
|
|
69
83
|
/** 内存修复:把孤儿 inbox splice 改写为 no-op(调用方负责持久化)。 */
|
|
70
84
|
declare function repairOrphanInboxSplices(events: SessionEvent[]): void;
|
|
71
|
-
declare function scanRows(rows: readonly EventRow[], base?: number
|
|
85
|
+
declare function scanRows(rows: readonly EventRow[], base?: number): {
|
|
72
86
|
preserved: SessionEvent[];
|
|
73
87
|
tornFrom?: number;
|
|
74
88
|
};
|
|
75
89
|
declare function toJsonlArtifact(meta: SessionHeader, inheritedEventCount: number, events: readonly SessionEvent[]): string;
|
|
76
90
|
//#endregion
|
|
77
|
-
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME,
|
|
91
|
+
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, repairAssistantSettlement, repairOrphanInboxSplices, repairReadView, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, syncMeteringRanges, toJsonlArtifact };
|
package/dist/artifact.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as
|
|
3
|
-
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME,
|
|
1
|
+
import { a as repairOrphanInboxSplices, c as rowToEvent, d as sessionConflictRow, f as sessionInsertRow, i as repairAssistantSettlement, l as rowToMeta, m as toJsonlArtifact, n as orphanInboxSpliceSeqs, o as repairReadView, p as syncMeteringRanges, r as recomputeReplaceProvenance, s as repairSurfaceOps, t as findSurfaceRepairs, u as scanRows } from "./log-DBFUBPhv.mjs";
|
|
2
|
+
import { a as persistImport, i as parseJsonlArtifact, n as SESSION_LOG_ARTIFACT_FILENAME, o as registerSessionImport, r as parseImportZip, t as SESSION_IMPORT_PATH } from "./import-mZZgDBLd.mjs";
|
|
3
|
+
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, findSurfaceRepairs, orphanInboxSpliceSeqs, parseImportZip, parseJsonlArtifact, persistImport, recomputeReplaceProvenance, registerSessionImport, repairAssistantSettlement, repairOrphanInboxSplices, repairReadView, repairSurfaceOps, rowToEvent, rowToMeta, scanRows, sessionConflictRow, sessionInsertRow, syncMeteringRanges, toJsonlArtifact };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { l as rowToMeta } from "./log-DBFUBPhv.mjs";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
-
import { SESSION_FORMAT_VERSION, SessionLogOffset
|
|
3
|
+
import { SESSION_FORMAT_VERSION, SessionLogOffset } from "@deepseek-ai/dsh-session";
|
|
4
|
+
import { sessionFormatCatalog } from "@deepseek-ai/dsh-session-format-catalog";
|
|
4
5
|
import { SessionBranch, SessionBranchError, balanceRewindPrefix, buildTimeline } from "@morlay/session-branch";
|
|
5
6
|
import { unzipSync } from "fflate";
|
|
6
7
|
//#region src/branch.ts
|
|
@@ -78,10 +79,7 @@ var SessionBranchRdbProvider = class {
|
|
|
78
79
|
constructor(persistence, live = {
|
|
79
80
|
getSession: () => void 0,
|
|
80
81
|
getAgent: () => void 0,
|
|
81
|
-
flush: async () => true
|
|
82
|
-
setCoordinatorCursor: () => {},
|
|
83
|
-
setCoordinatorState: () => {},
|
|
84
|
-
setCoordinatorSeedLength: () => {}
|
|
82
|
+
flush: async () => true
|
|
85
83
|
}) {
|
|
86
84
|
this.persistence = persistence;
|
|
87
85
|
this.live = live;
|
|
@@ -95,7 +93,7 @@ var SessionBranchRdbProvider = class {
|
|
|
95
93
|
};
|
|
96
94
|
}
|
|
97
95
|
async readRawEvents(id, signal) {
|
|
98
|
-
const stored = await this.persistence.
|
|
96
|
+
const stored = await this.persistence.readLog(id, {}, signal);
|
|
99
97
|
if (stored === void 0) throw new SessionBranchError(`session "${id}" not found`, "SESSION_NOT_FOUND");
|
|
100
98
|
return {
|
|
101
99
|
meta: stored.meta,
|
|
@@ -105,7 +103,8 @@ var SessionBranchRdbProvider = class {
|
|
|
105
103
|
async forkFrom(sourceId, options = {}, signal) {
|
|
106
104
|
signal?.throwIfAborted();
|
|
107
105
|
const { atSeq, anchorMode = "after", seedSuffix = [], childSessionId, meta = {} } = options;
|
|
108
|
-
const source = await this.persistence.
|
|
106
|
+
const source = await this.persistence.readLog(sourceId, {}, signal);
|
|
107
|
+
if (source === void 0) throw new SessionBranchError(`session "${sourceId}" not found`, "SESSION_NOT_FOUND");
|
|
109
108
|
const boundary = locateTurnEnd(source.events, atSeq, anchorMode);
|
|
110
109
|
const prefix = source.events.slice(0, boundary + 1);
|
|
111
110
|
const childId = childSessionId ?? mintSessionId();
|
|
@@ -123,15 +122,19 @@ var SessionBranchRdbProvider = class {
|
|
|
123
122
|
const seed = [...renumber(prefix, 0), ...renumber(seedSuffix, prefix.length)];
|
|
124
123
|
const internals = this.persistence.internals();
|
|
125
124
|
const sourceRows = await internals.backend.getEventRows(sourceId);
|
|
126
|
-
const sourceEventIds = new Map(sourceRows.map((row) => [row.
|
|
125
|
+
const sourceEventIds = new Map(sourceRows.map((row) => [row.fSequence, row.fEventId]));
|
|
127
126
|
const reuse = /* @__PURE__ */ new Map();
|
|
128
127
|
for (const event of prefix) {
|
|
129
128
|
const eventId = sourceEventIds.get(event.seq);
|
|
130
129
|
if (eventId !== void 0) reuse.set(event.seq, eventId);
|
|
131
130
|
}
|
|
132
131
|
internals.registerReuseEventIds(childId, reuse);
|
|
133
|
-
await this.persistence.create(childMeta, prefix.length);
|
|
134
|
-
|
|
132
|
+
const handle = await this.persistence.create(childMeta, { inheritedEventCount: SessionLogOffset(prefix.length) });
|
|
133
|
+
try {
|
|
134
|
+
if (seed.length > 0) await handle.append(seed);
|
|
135
|
+
} finally {
|
|
136
|
+
await handle.close();
|
|
137
|
+
}
|
|
135
138
|
return childId;
|
|
136
139
|
}
|
|
137
140
|
async rewind(id, toBoundary, signal) {
|
|
@@ -140,7 +143,7 @@ var SessionBranchRdbProvider = class {
|
|
|
140
143
|
const live = this.live.getSession(id);
|
|
141
144
|
if (live !== void 0) await this.live.flush(live);
|
|
142
145
|
const raw = live === void 0 ? await this.readRawEvents(id, signal) : void 0;
|
|
143
|
-
const inspection = live === void 0 ? void 0 : await this.persistence.inspect(id, signal);
|
|
146
|
+
const inspection = live === void 0 ? void 0 : await this.persistence.internals().inspect(id, signal);
|
|
144
147
|
const events = live === void 0 ? raw.events : inspection.events;
|
|
145
148
|
const meta = live === void 0 ? raw.meta : inspection.meta;
|
|
146
149
|
const boundaryEvent = events[toBoundary];
|
|
@@ -149,7 +152,7 @@ var SessionBranchRdbProvider = class {
|
|
|
149
152
|
const rawKeepLength = toBoundary === -1 ? 0 : boundaryEvent.type === "turn/end" ? toBoundary + 1 : toBoundary;
|
|
150
153
|
const keepLength = balanceRewindPrefix(events.slice(0, rawKeepLength)).length;
|
|
151
154
|
const internals = this.persistence.internals();
|
|
152
|
-
const denseBoundary =
|
|
155
|
+
const denseBoundary = keepLength - 1;
|
|
153
156
|
const newSeedLength = await internals.backend.transaction(async (tx) => {
|
|
154
157
|
signal?.throwIfAborted();
|
|
155
158
|
const head = await tx.getHead(id);
|
|
@@ -169,7 +172,6 @@ var SessionBranchRdbProvider = class {
|
|
|
169
172
|
await tx.bumpRevision(id);
|
|
170
173
|
return shrunk;
|
|
171
174
|
});
|
|
172
|
-
if (newSeedLength !== null) this.live.setCoordinatorSeedLength(id, newSeedLength);
|
|
173
175
|
internals.writeGuard.confirmHead(id, denseBoundary);
|
|
174
176
|
if (live !== void 0) {
|
|
175
177
|
truncateLiveSession(live, keepLength);
|
|
@@ -180,9 +182,9 @@ var SessionBranchRdbProvider = class {
|
|
|
180
182
|
const phase = agent.phase;
|
|
181
183
|
if (phase !== void 0) phase.lastTurn = lastTurn;
|
|
182
184
|
}
|
|
183
|
-
this.
|
|
184
|
-
|
|
185
|
-
|
|
185
|
+
const handle = this.persistence.tracker.writerOf(id);
|
|
186
|
+
if (handle !== void 0) handle.resetAfterRewind(keepLength, newSeedLength === null ? void 0 : newSeedLength);
|
|
187
|
+
}
|
|
186
188
|
const row = await internals.backend.getSession(id);
|
|
187
189
|
if (row === void 0) return {
|
|
188
190
|
header: {
|
|
@@ -214,29 +216,7 @@ var SessionBranchRdb = class extends SessionBranch {
|
|
|
214
216
|
getAgent: (id) => {
|
|
215
217
|
return this.ctx.get("agents")?.get(id);
|
|
216
218
|
},
|
|
217
|
-
flush: (session) => this.ctx.sessions.flush(session)
|
|
218
|
-
setCoordinatorCursor: (id, cursor) => {
|
|
219
|
-
const state = this.ctx.sessionPersistence.coordinator?.states?.get(id);
|
|
220
|
-
if (state !== void 0) state.cursor = cursor;
|
|
221
|
-
},
|
|
222
|
-
setCoordinatorState: (id, cursor, meta) => {
|
|
223
|
-
const states = this.ctx.sessionPersistence.coordinator?.states;
|
|
224
|
-
if (states === void 0) return;
|
|
225
|
-
const state = states.get(id);
|
|
226
|
-
if (state !== void 0) state.cursor = cursor;
|
|
227
|
-
else states.set(id, {
|
|
228
|
-
meta,
|
|
229
|
-
cursor,
|
|
230
|
-
materialized: true
|
|
231
|
-
});
|
|
232
|
-
},
|
|
233
|
-
setCoordinatorSeedLength: (id, seedLength) => {
|
|
234
|
-
const state = this.ctx.sessionPersistence.coordinator?.states?.get(id);
|
|
235
|
-
if (state?.storage !== void 0 && state.storage.inheritedEventCount > seedLength) state.storage = {
|
|
236
|
-
...state.storage,
|
|
237
|
-
inheritedEventCount: seedLength
|
|
238
|
-
};
|
|
239
|
-
}
|
|
219
|
+
flush: (session) => this.ctx.sessions.flush(session)
|
|
240
220
|
});
|
|
241
221
|
readBranchPrefix(id, atSeq, mode, signal) {
|
|
242
222
|
return this.provider.readBranchPrefix(id, atSeq, mode, signal);
|
|
@@ -250,22 +230,13 @@ var SessionBranchRdb = class extends SessionBranch {
|
|
|
250
230
|
rewind(id, toBoundary, signal) {
|
|
251
231
|
return this.provider.rewind(id, toBoundary, signal);
|
|
252
232
|
}
|
|
253
|
-
syncLiveCursor(sessionId) {
|
|
254
|
-
const live = this.ctx.sessions.get(sessionId);
|
|
255
|
-
if (live === void 0) return;
|
|
256
|
-
const state = this.ctx.sessionPersistence.coordinator?.states?.get(sessionId);
|
|
257
|
-
if (state === void 0) return;
|
|
258
|
-
let cursor = state.cursor;
|
|
259
|
-
while (live.snapshotEvents()[cursor]?.ignorable === true) cursor += 1;
|
|
260
|
-
state.cursor = cursor;
|
|
261
|
-
}
|
|
262
233
|
async timeline(sessionId, signal) {
|
|
263
234
|
const persistence = this.ctx.sessionPersistence;
|
|
264
235
|
const snapshots = await persistence.listSnapshots(signal);
|
|
265
236
|
const readOwnEvents = async (id, fromSeq, s) => {
|
|
266
237
|
const live = this.ctx.sessions.get(id);
|
|
267
238
|
if (live !== void 0) return live.snapshotEvents().slice(fromSeq);
|
|
268
|
-
return (await persistence.readFrom(id, fromSeq, s)).events;
|
|
239
|
+
return (await persistence.internals().readFrom(id, fromSeq, s)).events;
|
|
269
240
|
};
|
|
270
241
|
return buildTimeline(snapshots, readOwnEvents, sessionId, signal);
|
|
271
242
|
}
|
|
@@ -275,16 +246,6 @@ var SessionBranchRdb = class extends SessionBranch {
|
|
|
275
246
|
const SESSION_LOG_ARTIFACT_FILENAME = "session.jsonl";
|
|
276
247
|
const SESSION_IMPORT_PATH = "/api/session.import";
|
|
277
248
|
const MAX_IMPORT_ZIP_BYTES = 67108864;
|
|
278
|
-
function expandProvenanceFromStorage(parsed) {
|
|
279
|
-
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) throw new TypeError("imported session records must be objects");
|
|
280
|
-
const record = parsed;
|
|
281
|
-
if (record.sourceEventSeqs === void 0) return parsed;
|
|
282
|
-
if (!Number.isSafeInteger(record.seq) || record.seq < 0) throw new TypeError("imported session event seq must be a non-negative safe integer");
|
|
283
|
-
return {
|
|
284
|
-
...record,
|
|
285
|
-
sourceEventSeqs: decodeSeqRanges(record.sourceEventSeqs, record.seq + 1)
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
249
|
function parseJsonlArtifact(content) {
|
|
289
250
|
const lines = content.split("\n");
|
|
290
251
|
if (lines.length === 0 || lines[0] === "") throw new Error("imported session log is empty");
|
|
@@ -294,10 +255,15 @@ function parseJsonlArtifact(content) {
|
|
|
294
255
|
} catch {
|
|
295
256
|
throw new Error("imported session log has an unparsable header line");
|
|
296
257
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
258
|
+
let restore;
|
|
259
|
+
try {
|
|
260
|
+
restore = sessionFormatCatalog.createRestore(header, {
|
|
261
|
+
recovery: "strict",
|
|
262
|
+
validation: "transformed"
|
|
263
|
+
});
|
|
264
|
+
} catch (error) {
|
|
265
|
+
throw new Error(`imported session log has an invalid header line: ${error instanceof Error ? error.message : String(error)}`);
|
|
266
|
+
}
|
|
301
267
|
for (let i = 1; i < lines.length; i++) {
|
|
302
268
|
const line = lines[i];
|
|
303
269
|
if (line === void 0 || line === "") continue;
|
|
@@ -307,23 +273,33 @@ function parseJsonlArtifact(content) {
|
|
|
307
273
|
} catch {
|
|
308
274
|
throw new Error(`imported session log has an unparsable event line at ${i}`);
|
|
309
275
|
}
|
|
310
|
-
|
|
276
|
+
try {
|
|
277
|
+
restore.decodeRow(parsed);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
throw new Error(`imported session log has an invalid event line at ${i}: ${error instanceof Error ? error.message : String(error)}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
let artifact;
|
|
283
|
+
try {
|
|
284
|
+
artifact = restore.finish();
|
|
285
|
+
} catch (error) {
|
|
286
|
+
throw new Error(`imported session log is incomplete: ${error instanceof Error ? error.message : String(error)}`);
|
|
311
287
|
}
|
|
288
|
+
const meta = artifact.header;
|
|
289
|
+
const events = artifact.events;
|
|
312
290
|
for (let i = 0; i < events.length; i++) if (events[i].seq !== i) throw new Error(`imported session log seq gap at ${i} (got ${events[i].seq}); import requires a dense log`);
|
|
313
|
-
const
|
|
314
|
-
const delegationDepth = header["delegationDepth"];
|
|
315
|
-
const inheritedEventCount = Math.min(seedLength ?? 0, events.length);
|
|
291
|
+
const inheritedEventCount = Math.min(artifact.inheritedEventCount, events.length);
|
|
316
292
|
return {
|
|
317
293
|
meta: {
|
|
318
|
-
version:
|
|
319
|
-
id:
|
|
320
|
-
createdAt:
|
|
321
|
-
...
|
|
322
|
-
...
|
|
323
|
-
isSeeded:
|
|
324
|
-
...origin ===
|
|
325
|
-
...
|
|
326
|
-
...
|
|
294
|
+
version: SESSION_FORMAT_VERSION,
|
|
295
|
+
id: meta.id,
|
|
296
|
+
createdAt: meta.createdAt,
|
|
297
|
+
...meta.cwd === void 0 ? {} : { cwd: meta.cwd },
|
|
298
|
+
...meta.parentSession === void 0 ? {} : { parentSession: meta.parentSession },
|
|
299
|
+
isSeeded: meta.isSeeded,
|
|
300
|
+
...meta.origin === void 0 ? {} : { origin: meta.origin },
|
|
301
|
+
...meta.delegationDepth === void 0 ? {} : { delegationDepth: meta.delegationDepth },
|
|
302
|
+
...meta.agentPreset === void 0 ? {} : { agentPreset: meta.agentPreset }
|
|
327
303
|
},
|
|
328
304
|
inheritedEventCount: SessionLogOffset(inheritedEventCount),
|
|
329
305
|
events
|
|
@@ -345,11 +321,25 @@ async function persistImport(persistence, branch, imported, targetId, sessions)
|
|
|
345
321
|
if (targetId !== void 0) {
|
|
346
322
|
if (branch === void 0) throw new Error("sessionBranch service is unavailable");
|
|
347
323
|
await branch.rewind(targetId, -1);
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
324
|
+
const liveHandle = persistence.tracker.writerOf(targetId);
|
|
325
|
+
if (liveHandle !== void 0) {
|
|
326
|
+
if (imported.events.length > 0) await liveHandle.append(imported.events);
|
|
327
|
+
} else {
|
|
328
|
+
const handle = await persistence.open(targetId, "write");
|
|
329
|
+
try {
|
|
330
|
+
if (imported.events.length > 0) await handle.append(imported.events);
|
|
331
|
+
} finally {
|
|
332
|
+
await handle.close();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
} else {
|
|
336
|
+
const handle = await persistence.create({
|
|
337
|
+
...imported.meta,
|
|
338
|
+
id
|
|
339
|
+
}, { inheritedEventCount: imported.inheritedEventCount });
|
|
340
|
+
if (imported.events.length > 0) await handle.append(imported.events);
|
|
341
|
+
await handle.close();
|
|
342
|
+
}
|
|
353
343
|
if (targetId !== void 0) {
|
|
354
344
|
const live = sessions?.get(targetId);
|
|
355
345
|
if (live !== void 0) replaceLiveSessionLog(live, imported.events);
|
|
@@ -435,4 +425,4 @@ function registerSessionImport(ctx, persistence) {
|
|
|
435
425
|
});
|
|
436
426
|
}
|
|
437
427
|
//#endregion
|
|
438
|
-
export {
|
|
428
|
+
export { persistImport as a, SessionBranchRdbProvider as c, parseJsonlArtifact as i, locateTurnEnd as l, SESSION_LOG_ARTIFACT_FILENAME as n, registerSessionImport as o, parseImportZip as r, SessionBranchRdb as s, SESSION_IMPORT_PATH as t };
|
package/dist/import.d.mts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { n as SessionPersistenceRdb } from "./index-
|
|
1
|
+
import { n as SessionPersistenceRdb } from "./index-GdKkSSb-.mjs";
|
|
2
2
|
import { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
|
|
3
3
|
import { Session, SessionEvent, SessionId } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
//#region src/import.d.ts
|
|
6
6
|
declare const SESSION_LOG_ARTIFACT_FILENAME = "session.jsonl";
|
|
7
7
|
declare const SESSION_IMPORT_PATH = "/api/session.import";
|
|
8
|
-
declare function expandProvenanceFromStorage(parsed: unknown): unknown;
|
|
9
8
|
declare function parseJsonlArtifact(content: string): SessionStorageMetadata & {
|
|
10
9
|
events: SessionEvent[];
|
|
11
10
|
};
|
|
@@ -21,4 +20,4 @@ declare function persistImport(persistence: SessionPersistenceRdb, branch: {
|
|
|
21
20
|
}): Promise<SessionId>;
|
|
22
21
|
declare function registerSessionImport(ctx: Context, persistence: SessionPersistenceRdb): void;
|
|
23
22
|
//#endregion
|
|
24
|
-
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME,
|
|
23
|
+
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport };
|
package/dist/import.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME,
|
|
1
|
+
import { a as persistImport, i as parseJsonlArtifact, n as SESSION_LOG_ARTIFACT_FILENAME, o as registerSessionImport, r as parseImportZip, t as SESSION_IMPORT_PATH } from "./import-mZZgDBLd.mjs";
|
|
2
|
+
export { SESSION_IMPORT_PATH, SESSION_LOG_ARTIFACT_FILENAME, parseImportZip, parseJsonlArtifact, persistImport, registerSessionImport };
|