@morlay/session-rdb 0.0.11 → 0.0.13
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 +0 -16
- package/dist/artifact.d.mts +64 -0
- package/dist/artifact.mjs +3 -0
- package/dist/import-D2vUnUZe.mjs +438 -0
- package/dist/import.d.mts +24 -0
- package/dist/import.mjs +2 -0
- package/dist/index-uUvn6gYp.d.mts +111 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +466 -0
- package/dist/invariant.d.mts +7 -0
- package/dist/invariant.mjs +8 -0
- package/dist/magic-string.es-BWtG0AyA.mjs +1017 -0
- package/dist/schema-B-8G4lWc.mjs +852 -0
- package/dist/schema-CFXZURX7.d.mts +116 -0
- package/dist/sqlite-DIXY-dFZ.mjs +356 -0
- package/dist/storage.d.mts +44 -0
- package/dist/storage.mjs +3 -0
- package/dist/testing.d.mts +31 -0
- package/dist/testing.mjs +16051 -0
- package/package.json +39 -22
- package/src/adapters/ddl.ts +77 -0
- package/src/adapters/index.ts +4 -0
- package/src/adapters/to-postgres.ts +91 -0
- package/src/adapters/to-sqlite.ts +79 -0
- package/src/artifact.ts +4 -0
- package/src/backend.ts +112 -0
- package/src/branch.ts +508 -0
- package/src/entities/events.ts +27 -0
- package/src/entities/index.ts +30 -0
- package/src/entities/persistence-state.ts +10 -0
- package/src/entities/schema-meta.ts +9 -0
- package/src/entities/session-events.ts +29 -0
- package/src/entities/sessions.ts +20 -0
- package/src/entities/types.ts +48 -0
- package/src/import.ts +270 -0
- package/src/index.ts +547 -0
- package/src/invariant.ts +15 -0
- package/src/log.ts +456 -0
- package/src/migrate.ts +137 -0
- package/src/postgres.ts +369 -0
- package/src/schema.ts +234 -0
- package/src/sqlite.ts +412 -0
- package/src/storage.ts +5 -0
- package/src/testing/contract.ts +562 -0
- package/src/testing/coordinator-contract.ts +1723 -0
- package/src/testing/helpers.ts +20 -0
- package/src/testing.ts +12 -0
- package/src/write-guard.ts +27 -0
- package/lib/index.d.mts +0 -558
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs +0 -2176
- package/lib/index.mjs.map +0 -1
- package/lib/invariant.d.mts +0 -15
- package/lib/invariant.d.mts.map +0 -1
- package/lib/invariant.mjs +0 -21
- package/lib/invariant.mjs.map +0 -1
|
@@ -0,0 +1,852 @@
|
|
|
1
|
+
import { SessionSeq, encodeSeqRanges, packChunkRuns } from "@deepseek-ai/dsh-session";
|
|
2
|
+
import { sql } from "drizzle-orm";
|
|
3
|
+
import { check, index, integer, sqliteTable, text, unique } from "drizzle-orm/sqlite-core";
|
|
4
|
+
import { bigint, check as check$1, index as index$1, integer as integer$1, pgSchema, pgTable, serial, text as text$1, unique as unique$1 } from "drizzle-orm/pg-core";
|
|
5
|
+
//#region src/log.ts
|
|
6
|
+
function rowToMeta(row) {
|
|
7
|
+
if (!Number.isSafeInteger(row.fCreatedAt) || row.fCreatedAt < 0) throw new Error("stored session createdAt must be a non-negative safe integer");
|
|
8
|
+
return {
|
|
9
|
+
version: row.fVersion,
|
|
10
|
+
id: row.fSessionId,
|
|
11
|
+
createdAt: row.fCreatedAt,
|
|
12
|
+
...row.fCwd !== null ? { cwd: row.fCwd } : {},
|
|
13
|
+
...row.fParentSession !== null ? { parentSession: row.fParentSession } : {},
|
|
14
|
+
isSeeded: row.fSeedLength !== null,
|
|
15
|
+
...row.fOrigin !== null ? { origin: row.fOrigin } : {},
|
|
16
|
+
...row.fDelegationDepth === null ? {} : { delegationDepth: row.fDelegationDepth }
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function sessionInsertRow(storage, incarnation) {
|
|
20
|
+
const meta = storage.meta;
|
|
21
|
+
return {
|
|
22
|
+
fSessionId: meta.id,
|
|
23
|
+
fHeadEventId: "",
|
|
24
|
+
fHeadSequence: -1,
|
|
25
|
+
fVersion: meta.version,
|
|
26
|
+
fCreatedAt: meta.createdAt,
|
|
27
|
+
fCwd: meta.cwd ?? null,
|
|
28
|
+
fParentSession: meta.parentSession ?? null,
|
|
29
|
+
fSeedLength: meta.isSeeded ? storage.inheritedEventCount : null,
|
|
30
|
+
fOrigin: meta.origin ?? null,
|
|
31
|
+
fDelegationDepth: meta.delegationDepth ?? null,
|
|
32
|
+
fIncarnation: incarnation,
|
|
33
|
+
fRevision: 0
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function sessionConflictRow(storage) {
|
|
37
|
+
const meta = storage.meta;
|
|
38
|
+
return {
|
|
39
|
+
fVersion: meta.version,
|
|
40
|
+
fCreatedAt: meta.createdAt,
|
|
41
|
+
fCwd: meta.cwd ?? null,
|
|
42
|
+
fParentSession: meta.parentSession ?? null,
|
|
43
|
+
fSeedLength: meta.isSeeded ? storage.inheritedEventCount : null,
|
|
44
|
+
fOrigin: meta.origin ?? null,
|
|
45
|
+
fDelegationDepth: meta.delegationDepth ?? null
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function remapSurfaceOp(op, remap) {
|
|
49
|
+
if (op === "append") return op;
|
|
50
|
+
return {
|
|
51
|
+
op: "replace",
|
|
52
|
+
start: SessionSeq(remap(op.start)),
|
|
53
|
+
end: SessionSeq(remap(op.end))
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function remapShadowedRange(range, remap) {
|
|
57
|
+
return {
|
|
58
|
+
start: remap(range.start),
|
|
59
|
+
end: remap(range.end)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function rowToEvent(row, seqMap) {
|
|
63
|
+
const remap = (seq) => seqMap.get(seq) ?? seq;
|
|
64
|
+
const surfaceOp = row.fSurfaceOp !== null ? remapSurfaceOp(JSON.parse(row.fSurfaceOp), remap) : void 0;
|
|
65
|
+
const data = JSON.parse(row.fData);
|
|
66
|
+
if (row.fType === "compaction/summary" || row.fType === "compaction/prune") {
|
|
67
|
+
const metering = data;
|
|
68
|
+
if (metering.shadowedRange !== void 0) metering.shadowedRange = remapShadowedRange(metering.shadowedRange, remap);
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
type: row.fType,
|
|
72
|
+
seq: row.fSequence,
|
|
73
|
+
time: row.fCreatedAt,
|
|
74
|
+
data,
|
|
75
|
+
...surfaceOp === void 0 ? {} : { surfaceOp }
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function buildSeqMap(rows) {
|
|
79
|
+
const map = /* @__PURE__ */ new Map();
|
|
80
|
+
for (const row of rows) if (!map.has(row.fOriginalSeq)) map.set(row.fOriginalSeq, row.fSequence);
|
|
81
|
+
return map;
|
|
82
|
+
}
|
|
83
|
+
const SURFACE_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
84
|
+
"user/message",
|
|
85
|
+
"assistant/message",
|
|
86
|
+
"tool/result"
|
|
87
|
+
]);
|
|
88
|
+
function recomputeReplaceProvenance(events) {
|
|
89
|
+
for (const event of events) {
|
|
90
|
+
const raw = event;
|
|
91
|
+
const op = raw.surfaceOp;
|
|
92
|
+
if (typeof op !== "object" || op === null || op.op !== "replace") continue;
|
|
93
|
+
const { start, end } = op;
|
|
94
|
+
const refs = [];
|
|
95
|
+
for (const candidate of events) if (candidate.seq >= start && candidate.seq <= end && SURFACE_EVENT_TYPES.has(candidate.type)) refs.push(candidate.seq);
|
|
96
|
+
raw.sourceEventSeqs = refs;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function isEventSeqLike(value) {
|
|
100
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && !Object.is(value, -0);
|
|
101
|
+
}
|
|
102
|
+
function isDeepEqualJson(a, b) {
|
|
103
|
+
if (a === b) return true;
|
|
104
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
105
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
106
|
+
return a.every((item, i) => isDeepEqualJson(item, b[i]));
|
|
107
|
+
}
|
|
108
|
+
if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return false;
|
|
109
|
+
const aKeys = Object.keys(a);
|
|
110
|
+
const bRecord = b;
|
|
111
|
+
if (aKeys.length !== Object.keys(bRecord).length) return false;
|
|
112
|
+
return aKeys.every((key) => Object.hasOwn(bRecord, key) && isDeepEqualJson(a[key], bRecord[key]));
|
|
113
|
+
}
|
|
114
|
+
function toolResultRewriteContentOnly(original, replacement) {
|
|
115
|
+
const originalData = original.data;
|
|
116
|
+
const replacementData = replacement.data;
|
|
117
|
+
const originalMessage = originalData["message"];
|
|
118
|
+
const replacementMessage = replacementData["message"];
|
|
119
|
+
const originalContent = Array.isArray(originalMessage?.content) ? originalMessage.content : void 0;
|
|
120
|
+
const replacementContent = Array.isArray(replacementMessage?.content) ? replacementMessage.content : void 0;
|
|
121
|
+
if (originalContent === void 0 || replacementContent === void 0) return false;
|
|
122
|
+
return isDeepEqualJson({
|
|
123
|
+
...originalData,
|
|
124
|
+
message: {
|
|
125
|
+
...originalMessage,
|
|
126
|
+
content: [{
|
|
127
|
+
...originalContent[0],
|
|
128
|
+
content: null
|
|
129
|
+
}]
|
|
130
|
+
}
|
|
131
|
+
}, {
|
|
132
|
+
...replacementData,
|
|
133
|
+
message: {
|
|
134
|
+
...replacementMessage,
|
|
135
|
+
content: [{
|
|
136
|
+
...replacementContent[0],
|
|
137
|
+
content: null
|
|
138
|
+
}]
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function findSurfaceRepairs(events) {
|
|
143
|
+
const nodes = [];
|
|
144
|
+
const degradeToAppend = /* @__PURE__ */ new Set();
|
|
145
|
+
const addAppendMarker = /* @__PURE__ */ new Set();
|
|
146
|
+
const clearSurfaceOp = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const event of events) {
|
|
148
|
+
const op = event.surfaceOp;
|
|
149
|
+
if (op === void 0) {
|
|
150
|
+
if (SURFACE_EVENT_TYPES.has(event.type)) {
|
|
151
|
+
addAppendMarker.add(event.seq);
|
|
152
|
+
nodes.push(event.seq);
|
|
153
|
+
}
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (op === "append") {
|
|
157
|
+
if (SURFACE_EVENT_TYPES.has(event.type)) nodes.push(event.seq);
|
|
158
|
+
else clearSurfaceOp.add(event.seq);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (!SURFACE_EVENT_TYPES.has(event.type)) {
|
|
162
|
+
clearSurfaceOp.add(event.seq);
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const replace = typeof op === "object" && op !== null && !Array.isArray(op) ? op : void 0;
|
|
166
|
+
const start = replace?.["start"];
|
|
167
|
+
const end = replace?.["end"];
|
|
168
|
+
const shapeOk = replace !== void 0 && replace["op"] === "replace" && isEventSeqLike(start) && isEventSeqLike(end);
|
|
169
|
+
const startIdx = shapeOk ? nodes.indexOf(start) : -1;
|
|
170
|
+
const endIdx = shapeOk ? nodes.indexOf(end) : -1;
|
|
171
|
+
const rangeOk = shapeOk && startIdx !== -1 && endIdx !== -1 && startIdx <= endIdx;
|
|
172
|
+
let rewriteOk = true;
|
|
173
|
+
if (rangeOk && event.type === "tool/result") {
|
|
174
|
+
const shadowed = nodes.slice(startIdx, endIdx + 1);
|
|
175
|
+
if (shadowed.length !== 1) rewriteOk = false;
|
|
176
|
+
else {
|
|
177
|
+
const original = events[shadowed[0]];
|
|
178
|
+
rewriteOk = original?.type === "tool/result" && toolResultRewriteContentOnly(original, event);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
if (!rangeOk || !rewriteOk) {
|
|
182
|
+
degradeToAppend.add(event.seq);
|
|
183
|
+
nodes.push(event.seq);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
nodes.splice(startIdx, endIdx - startIdx + 1, event.seq);
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
degradeToAppend,
|
|
190
|
+
addAppendMarker,
|
|
191
|
+
clearSurfaceOp
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function repairSurfaceOps(events) {
|
|
195
|
+
const repairs = findSurfaceRepairs(events);
|
|
196
|
+
if (repairs.degradeToAppend.size === 0 && repairs.addAppendMarker.size === 0 && repairs.clearSurfaceOp.size === 0) return;
|
|
197
|
+
for (const event of events) {
|
|
198
|
+
const raw = event;
|
|
199
|
+
if (repairs.degradeToAppend.has(event.seq)) raw.surfaceOp = "append";
|
|
200
|
+
else if (repairs.addAppendMarker.has(event.seq)) raw.surfaceOp = "append";
|
|
201
|
+
else if (repairs.clearSurfaceOp.has(event.seq)) delete raw.surfaceOp;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* 定位无法从空状态增量重放的 agent/inbox/spliced 事件(孤儿操作)。
|
|
206
|
+
*
|
|
207
|
+
* 上游 Inbox 每次构造都从会话起点重放全部 inbox splice,失败即拒绝整个
|
|
208
|
+
* 会话(resume / 编辑重放不可用)。rewind 截断历史轮次后若残留 splice 引用
|
|
209
|
+
* 已被截断的排队消息(插入被删、消费保留,或反之),重放时越界或重复——
|
|
210
|
+
* 无法独立重放。
|
|
211
|
+
*/
|
|
212
|
+
function orphanInboxSpliceSeqs(events) {
|
|
213
|
+
const inbox = {
|
|
214
|
+
"next-turn": [],
|
|
215
|
+
"next-step": []
|
|
216
|
+
};
|
|
217
|
+
const orphan = /* @__PURE__ */ new Set();
|
|
218
|
+
for (const raw of events) {
|
|
219
|
+
const event = raw;
|
|
220
|
+
if (event.type !== "agent/inbox/spliced") continue;
|
|
221
|
+
const { target, start, removedCount, inserted } = event.data;
|
|
222
|
+
const list = typeof target === "string" ? inbox[target] : void 0;
|
|
223
|
+
if (list === void 0) {
|
|
224
|
+
orphan.add(event.seq);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
const removed = removedCount ?? 0;
|
|
228
|
+
const parsedInserted = (inserted ?? []).map((m) => ({ id: typeof m.id === "string" ? m.id : "" }));
|
|
229
|
+
if (!Number.isSafeInteger(start) || start < 0 || start > list.length || !Number.isSafeInteger(removed) || removed < 0 || start + removed > list.length) {
|
|
230
|
+
orphan.add(event.seq);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
const candidate = [
|
|
234
|
+
...list.slice(0, start),
|
|
235
|
+
...parsedInserted,
|
|
236
|
+
...list.slice(start + removed)
|
|
237
|
+
];
|
|
238
|
+
const other = (target === "next-turn" ? inbox["next-step"] : inbox["next-turn"]) ?? [];
|
|
239
|
+
const seen = /* @__PURE__ */ new Set();
|
|
240
|
+
let dup = false;
|
|
241
|
+
for (const m of [...candidate, ...other]) {
|
|
242
|
+
if (m.id === "") continue;
|
|
243
|
+
if (seen.has(m.id)) {
|
|
244
|
+
dup = true;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
seen.add(m.id);
|
|
248
|
+
}
|
|
249
|
+
if (dup) {
|
|
250
|
+
orphan.add(event.seq);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
list.splice(start, removed, ...parsedInserted);
|
|
254
|
+
}
|
|
255
|
+
return orphan;
|
|
256
|
+
}
|
|
257
|
+
/** 内存修复:把孤儿 inbox splice 改写为 no-op(调用方负责持久化)。 */
|
|
258
|
+
function repairOrphanInboxSplices(events) {
|
|
259
|
+
const orphan = orphanInboxSpliceSeqs(events);
|
|
260
|
+
if (orphan.size === 0) return;
|
|
261
|
+
for (const event of events) {
|
|
262
|
+
if (!orphan.has(event.seq)) continue;
|
|
263
|
+
const target = event.data.target;
|
|
264
|
+
event.data = {
|
|
265
|
+
...typeof target === "string" ? { target } : { target: "next-turn" },
|
|
266
|
+
start: 0,
|
|
267
|
+
removedCount: 0,
|
|
268
|
+
inserted: []
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function scanRows(rows, base = 0, seqMap = /* @__PURE__ */ new Map()) {
|
|
273
|
+
const parsed = rows.map((row) => {
|
|
274
|
+
try {
|
|
275
|
+
return {
|
|
276
|
+
ok: true,
|
|
277
|
+
event: rowToEvent(row, seqMap)
|
|
278
|
+
};
|
|
279
|
+
} catch {
|
|
280
|
+
return { ok: false };
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
let lastTurnEnd = -1;
|
|
284
|
+
for (let i = parsed.length - 1; i >= 0; i--) if (parsed[i]?.ok && rows[i]?.fType === "turn/end") {
|
|
285
|
+
lastTurnEnd = i;
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
288
|
+
const preserved = [];
|
|
289
|
+
for (let i = 0; i < rows.length; i++) {
|
|
290
|
+
const p = parsed[i];
|
|
291
|
+
if (!p?.ok || p.event === void 0) {
|
|
292
|
+
if (i <= lastTurnEnd) throw new Error(`corrupt session log: unparsable committed event at seq ${rows[i]?.fSequence}`);
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
if (p.event.seq !== base + i) {
|
|
296
|
+
if (i <= lastTurnEnd) throw new Error(`corrupt session log: seq gap in committed region (expected ${base + i}, got ${p.event.seq})`);
|
|
297
|
+
break;
|
|
298
|
+
}
|
|
299
|
+
preserved.push(p.event);
|
|
300
|
+
}
|
|
301
|
+
return preserved.length < rows.length ? {
|
|
302
|
+
preserved,
|
|
303
|
+
tornFrom: base + preserved.length
|
|
304
|
+
} : { preserved };
|
|
305
|
+
}
|
|
306
|
+
function toStorageRecord(record) {
|
|
307
|
+
const withSeqs = record;
|
|
308
|
+
if (withSeqs.sourceEventSeqs === void 0) return record;
|
|
309
|
+
return {
|
|
310
|
+
...record,
|
|
311
|
+
sourceEventSeqs: encodeSeqRanges(withSeqs.sourceEventSeqs)
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function toJsonlArtifact(meta, inheritedEventCount, events) {
|
|
315
|
+
const header = {
|
|
316
|
+
type: "session",
|
|
317
|
+
version: meta.version,
|
|
318
|
+
id: meta.id,
|
|
319
|
+
createdAt: meta.createdAt,
|
|
320
|
+
...meta.cwd === void 0 ? {} : { cwd: meta.cwd },
|
|
321
|
+
...meta.parentSession === void 0 ? {} : { parentSession: meta.parentSession },
|
|
322
|
+
...meta.isSeeded ? { seedLength: inheritedEventCount } : {},
|
|
323
|
+
...meta.origin === void 0 ? {} : { origin: meta.origin },
|
|
324
|
+
delegationDepth: meta.delegationDepth ?? 0,
|
|
325
|
+
...meta.agentPreset === void 0 ? {} : { agentPreset: meta.agentPreset }
|
|
326
|
+
};
|
|
327
|
+
const lines = [JSON.stringify(header)];
|
|
328
|
+
for (const record of packChunkRuns(events)) lines.push(JSON.stringify(toStorageRecord(record)));
|
|
329
|
+
return lines.join("\n");
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region src/entities/types.ts
|
|
333
|
+
function toProperty(name) {
|
|
334
|
+
return name.replace(/_([a-z])/g, (_match, char) => char.toUpperCase());
|
|
335
|
+
}
|
|
336
|
+
//#endregion
|
|
337
|
+
//#region src/adapters/to-sqlite.ts
|
|
338
|
+
function buildColumn$1(c, tables) {
|
|
339
|
+
let col;
|
|
340
|
+
switch (c.type) {
|
|
341
|
+
case "text":
|
|
342
|
+
col = text(c.name);
|
|
343
|
+
break;
|
|
344
|
+
case "serial":
|
|
345
|
+
col = integer(c.name).primaryKey({ autoIncrement: true });
|
|
346
|
+
break;
|
|
347
|
+
case "integer":
|
|
348
|
+
case "bigint": {
|
|
349
|
+
const built = integer(c.name);
|
|
350
|
+
col = c.primaryKey ? built.primaryKey() : built;
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (c.notNull) col = col.notNull();
|
|
355
|
+
if (c.default !== void 0) col = col.default(c.default);
|
|
356
|
+
if (c.unique) col = col.unique();
|
|
357
|
+
if (c.references) {
|
|
358
|
+
const { table, column, onDelete } = c.references;
|
|
359
|
+
col = col.references(() => tables[table][toProperty(column)], { onDelete });
|
|
360
|
+
}
|
|
361
|
+
return col;
|
|
362
|
+
}
|
|
363
|
+
function toSqliteSchema(defs) {
|
|
364
|
+
const tables = {};
|
|
365
|
+
for (const def of defs) {
|
|
366
|
+
const columns = {};
|
|
367
|
+
for (const c of def.columns) columns[toProperty(c.name)] = buildColumn$1(c, tables);
|
|
368
|
+
const extra = (self) => [
|
|
369
|
+
...(def.checks ?? []).map((c) => check(c.name, sql.raw(c.expression))),
|
|
370
|
+
...(def.uniques ?? []).map((u) => unique(u.name).on(...u.columns.map((name) => self[toProperty(name)]))),
|
|
371
|
+
...(def.indexes ?? []).map((i) => index(i.name).on(...i.columns.map((name) => self[toProperty(name)])))
|
|
372
|
+
];
|
|
373
|
+
tables[def.name] = sqliteTable(def.name, columns, extra);
|
|
374
|
+
}
|
|
375
|
+
return tables;
|
|
376
|
+
}
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/adapters/to-postgres.ts
|
|
379
|
+
function buildColumn(c, tables) {
|
|
380
|
+
let col;
|
|
381
|
+
switch (c.type) {
|
|
382
|
+
case "text":
|
|
383
|
+
col = text$1(c.name);
|
|
384
|
+
break;
|
|
385
|
+
case "serial":
|
|
386
|
+
col = serial(c.name).primaryKey();
|
|
387
|
+
break;
|
|
388
|
+
case "integer": {
|
|
389
|
+
const built = integer$1(c.name);
|
|
390
|
+
col = c.primaryKey ? built.primaryKey() : built;
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
case "bigint": {
|
|
394
|
+
const built = bigint(c.name, { mode: "number" });
|
|
395
|
+
col = c.primaryKey ? built.primaryKey() : built;
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (c.notNull) col = col.notNull();
|
|
400
|
+
if (c.default !== void 0) col = col.default(c.default);
|
|
401
|
+
if (c.unique) col = col.unique();
|
|
402
|
+
if (c.references) {
|
|
403
|
+
const { table, column, onDelete } = c.references;
|
|
404
|
+
col = col.references(() => tables[table][toProperty(column)], { onDelete });
|
|
405
|
+
}
|
|
406
|
+
return col;
|
|
407
|
+
}
|
|
408
|
+
function toPostgresSchema(defs, schemaName = "public") {
|
|
409
|
+
const tables = {};
|
|
410
|
+
const table = schemaName === "public" ? pgTable : pgSchema(schemaName).table;
|
|
411
|
+
for (const def of defs) {
|
|
412
|
+
const columns = {};
|
|
413
|
+
for (const c of def.columns) columns[toProperty(c.name)] = buildColumn(c, tables);
|
|
414
|
+
const extra = (self) => [
|
|
415
|
+
...(def.checks ?? []).map((c) => check$1(c.name, sql.raw(c.expression))),
|
|
416
|
+
...(def.uniques ?? []).map((u) => unique$1(u.name).on(...u.columns.map((name) => self[toProperty(name)]))),
|
|
417
|
+
...(def.indexes ?? []).map((i) => index$1(i.name).on(...i.columns.map((name) => self[toProperty(name)])))
|
|
418
|
+
];
|
|
419
|
+
tables[def.name] = table(def.name, columns, extra);
|
|
420
|
+
}
|
|
421
|
+
return tables;
|
|
422
|
+
}
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/entities/persistence-state.ts
|
|
425
|
+
const persistenceState = {
|
|
426
|
+
name: "t_persistence_state",
|
|
427
|
+
columns: [{
|
|
428
|
+
name: "f_singleton",
|
|
429
|
+
type: "integer",
|
|
430
|
+
primaryKey: true
|
|
431
|
+
}, {
|
|
432
|
+
name: "f_store_id",
|
|
433
|
+
type: "text",
|
|
434
|
+
notNull: true
|
|
435
|
+
}],
|
|
436
|
+
checks: [{
|
|
437
|
+
name: "ck_persistence_state_singleton",
|
|
438
|
+
expression: "f_singleton = 1"
|
|
439
|
+
}]
|
|
440
|
+
};
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/entities/schema-meta.ts
|
|
443
|
+
const schemaMeta = {
|
|
444
|
+
name: "t_schema_meta",
|
|
445
|
+
columns: [{
|
|
446
|
+
name: "f_key",
|
|
447
|
+
type: "text",
|
|
448
|
+
primaryKey: true
|
|
449
|
+
}, {
|
|
450
|
+
name: "f_value",
|
|
451
|
+
type: "text",
|
|
452
|
+
notNull: true
|
|
453
|
+
}]
|
|
454
|
+
};
|
|
455
|
+
//#endregion
|
|
456
|
+
//#region src/entities/sessions.ts
|
|
457
|
+
const sessions = {
|
|
458
|
+
name: "t_sessions",
|
|
459
|
+
columns: [
|
|
460
|
+
{
|
|
461
|
+
name: "f_id",
|
|
462
|
+
type: "serial",
|
|
463
|
+
primaryKey: true
|
|
464
|
+
},
|
|
465
|
+
{
|
|
466
|
+
name: "f_session_id",
|
|
467
|
+
type: "text",
|
|
468
|
+
notNull: true,
|
|
469
|
+
unique: true
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
name: "f_head_event_id",
|
|
473
|
+
type: "text",
|
|
474
|
+
notNull: true,
|
|
475
|
+
default: ""
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
name: "f_head_sequence",
|
|
479
|
+
type: "integer",
|
|
480
|
+
notNull: true,
|
|
481
|
+
default: -1
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
name: "f_version",
|
|
485
|
+
type: "integer",
|
|
486
|
+
notNull: true
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
name: "f_created_at",
|
|
490
|
+
type: "bigint",
|
|
491
|
+
notNull: true
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
name: "f_cwd",
|
|
495
|
+
type: "text"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: "f_parent_session",
|
|
499
|
+
type: "text"
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "f_seed_length",
|
|
503
|
+
type: "integer"
|
|
504
|
+
},
|
|
505
|
+
{
|
|
506
|
+
name: "f_origin",
|
|
507
|
+
type: "text"
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
name: "f_delegation_depth",
|
|
511
|
+
type: "integer"
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
name: "f_incarnation",
|
|
515
|
+
type: "text",
|
|
516
|
+
notNull: true
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
name: "f_revision",
|
|
520
|
+
type: "integer",
|
|
521
|
+
notNull: true
|
|
522
|
+
}
|
|
523
|
+
]
|
|
524
|
+
};
|
|
525
|
+
//#endregion
|
|
526
|
+
//#region src/entities/events.ts
|
|
527
|
+
const events = {
|
|
528
|
+
name: "t_events",
|
|
529
|
+
columns: [
|
|
530
|
+
{
|
|
531
|
+
name: "f_id",
|
|
532
|
+
type: "serial",
|
|
533
|
+
primaryKey: true
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
name: "f_event_id",
|
|
537
|
+
type: "text",
|
|
538
|
+
notNull: true,
|
|
539
|
+
unique: true
|
|
540
|
+
},
|
|
541
|
+
{
|
|
542
|
+
name: "f_parent_id",
|
|
543
|
+
type: "text",
|
|
544
|
+
notNull: true,
|
|
545
|
+
default: ""
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
name: "f_type",
|
|
549
|
+
type: "text",
|
|
550
|
+
notNull: true,
|
|
551
|
+
default: ""
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
name: "f_kind",
|
|
555
|
+
type: "text",
|
|
556
|
+
notNull: true,
|
|
557
|
+
default: ""
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
name: "f_role",
|
|
561
|
+
type: "text",
|
|
562
|
+
notNull: true,
|
|
563
|
+
default: ""
|
|
564
|
+
},
|
|
565
|
+
{
|
|
566
|
+
name: "f_name",
|
|
567
|
+
type: "text",
|
|
568
|
+
notNull: true,
|
|
569
|
+
default: ""
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
name: "f_action_id",
|
|
573
|
+
type: "text",
|
|
574
|
+
notNull: true,
|
|
575
|
+
default: ""
|
|
576
|
+
},
|
|
577
|
+
{
|
|
578
|
+
name: "f_encoding",
|
|
579
|
+
type: "text",
|
|
580
|
+
notNull: true,
|
|
581
|
+
default: ""
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
name: "f_data",
|
|
585
|
+
type: "text",
|
|
586
|
+
notNull: true
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
name: "f_created_at",
|
|
590
|
+
type: "bigint",
|
|
591
|
+
notNull: true,
|
|
592
|
+
default: 0
|
|
593
|
+
}
|
|
594
|
+
],
|
|
595
|
+
indexes: [
|
|
596
|
+
{
|
|
597
|
+
name: "idx_events_kind",
|
|
598
|
+
columns: ["f_kind"]
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: "idx_events_role",
|
|
602
|
+
columns: ["f_role"]
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
name: "idx_events_name",
|
|
606
|
+
columns: ["f_name"]
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
name: "idx_events_action_id",
|
|
610
|
+
columns: ["f_action_id"]
|
|
611
|
+
}
|
|
612
|
+
]
|
|
613
|
+
};
|
|
614
|
+
//#endregion
|
|
615
|
+
//#region src/entities/session-events.ts
|
|
616
|
+
const sessionEvents = {
|
|
617
|
+
name: "t_session_events",
|
|
618
|
+
columns: [
|
|
619
|
+
{
|
|
620
|
+
name: "f_id",
|
|
621
|
+
type: "serial",
|
|
622
|
+
primaryKey: true
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
name: "f_session_id",
|
|
626
|
+
type: "text",
|
|
627
|
+
notNull: true,
|
|
628
|
+
references: {
|
|
629
|
+
table: "t_sessions",
|
|
630
|
+
column: "f_session_id",
|
|
631
|
+
onDelete: "cascade"
|
|
632
|
+
}
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
name: "f_event_id",
|
|
636
|
+
type: "text",
|
|
637
|
+
notNull: true,
|
|
638
|
+
references: {
|
|
639
|
+
table: "t_events",
|
|
640
|
+
column: "f_event_id",
|
|
641
|
+
onDelete: "cascade"
|
|
642
|
+
}
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
name: "f_sequence",
|
|
646
|
+
type: "integer",
|
|
647
|
+
notNull: true
|
|
648
|
+
},
|
|
649
|
+
{
|
|
650
|
+
name: "f_original_seq",
|
|
651
|
+
type: "integer",
|
|
652
|
+
notNull: true
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
name: "f_surface_op",
|
|
656
|
+
type: "text"
|
|
657
|
+
}
|
|
658
|
+
],
|
|
659
|
+
uniques: [{
|
|
660
|
+
name: "uq_session_events_session_sequence",
|
|
661
|
+
columns: ["f_session_id", "f_sequence"]
|
|
662
|
+
}],
|
|
663
|
+
indexes: [{
|
|
664
|
+
name: "idx_session_events_event_id",
|
|
665
|
+
columns: ["f_event_id"]
|
|
666
|
+
}]
|
|
667
|
+
};
|
|
668
|
+
//#endregion
|
|
669
|
+
//#region src/entities/index.ts
|
|
670
|
+
const sqliteTableDefs = [
|
|
671
|
+
persistenceState,
|
|
672
|
+
sessions,
|
|
673
|
+
events,
|
|
674
|
+
sessionEvents
|
|
675
|
+
];
|
|
676
|
+
const postgresTableDefs = [
|
|
677
|
+
persistenceState,
|
|
678
|
+
schemaMeta,
|
|
679
|
+
sessions,
|
|
680
|
+
events,
|
|
681
|
+
sessionEvents
|
|
682
|
+
];
|
|
683
|
+
//#endregion
|
|
684
|
+
//#region src/schema.ts
|
|
685
|
+
const SCHEMA_VERSION = 2;
|
|
686
|
+
const SESSION_PERSISTENCE_SQLITE_APPLICATION_ID = 1146308688;
|
|
687
|
+
const EPHEMERAL_EVENT_TYPES = ["assistant/chunk"];
|
|
688
|
+
const EVENT_ENCODING = "json";
|
|
689
|
+
const sqliteTables = toSqliteSchema(sqliteTableDefs);
|
|
690
|
+
const tPersistenceState = sqliteTables["t_persistence_state"];
|
|
691
|
+
const tSessions = sqliteTables["t_sessions"];
|
|
692
|
+
const tEvents = sqliteTables["t_events"];
|
|
693
|
+
const tSessionEvents = sqliteTables["t_session_events"];
|
|
694
|
+
const DEFAULT_BUSY_TIMEOUT_MS = 5e3;
|
|
695
|
+
function isEphemeralType(type) {
|
|
696
|
+
return EPHEMERAL_EVENT_TYPES.includes(type);
|
|
697
|
+
}
|
|
698
|
+
function isPersistedEvent(event) {
|
|
699
|
+
return !isEphemeralType(event.type) && event.ignorable !== true;
|
|
700
|
+
}
|
|
701
|
+
function eventKind(event) {
|
|
702
|
+
switch (event.type) {
|
|
703
|
+
case "user/message": return "message";
|
|
704
|
+
case "assistant/message":
|
|
705
|
+
if ((event.data.message?.content)?.some((block) => block?.type === "reasoning")) return "thinking";
|
|
706
|
+
return "message";
|
|
707
|
+
case "turn/start":
|
|
708
|
+
case "turn/end":
|
|
709
|
+
case "step/start":
|
|
710
|
+
case "step/end":
|
|
711
|
+
case "session/end-seed": return "turn";
|
|
712
|
+
case "tool/call":
|
|
713
|
+
case "tool/result":
|
|
714
|
+
case "tool/code-dispatch-start":
|
|
715
|
+
case "tool/code-dispatch": return "tool";
|
|
716
|
+
case "request/header":
|
|
717
|
+
case "request/context": return "request";
|
|
718
|
+
case "model/selection":
|
|
719
|
+
case "permission/preset":
|
|
720
|
+
case "approval/policy":
|
|
721
|
+
case "sandbox/mode":
|
|
722
|
+
case "plan/mode":
|
|
723
|
+
case "agent-preset/selected": return "config";
|
|
724
|
+
case "approval/asked":
|
|
725
|
+
case "approval/decided":
|
|
726
|
+
case "command/run":
|
|
727
|
+
case "command/done":
|
|
728
|
+
case "hook/invoked":
|
|
729
|
+
case "hook/result":
|
|
730
|
+
case "feedback/record": return "audit";
|
|
731
|
+
case "session/title":
|
|
732
|
+
case "session/title-llm-request":
|
|
733
|
+
case "session-log-deepseek/delivery-accepted": return "lifecycle";
|
|
734
|
+
case "agent/inbox/spliced": return "inbox";
|
|
735
|
+
case "compaction/start":
|
|
736
|
+
case "compaction/end":
|
|
737
|
+
case "compaction/summary":
|
|
738
|
+
case "compaction/prune": return "compaction";
|
|
739
|
+
case "llm/retry":
|
|
740
|
+
case "llm/retry-started": return "llm";
|
|
741
|
+
case "subagent/descriptor":
|
|
742
|
+
case "subagent/model-selection-policy": return "subagent";
|
|
743
|
+
case "team/member":
|
|
744
|
+
case "team/task":
|
|
745
|
+
case "team/message/queued":
|
|
746
|
+
case "team/message/delivered": return "team";
|
|
747
|
+
case "tool-workflow/run-start":
|
|
748
|
+
case "tool-workflow/run-end":
|
|
749
|
+
case "tool-workflow/agent-start":
|
|
750
|
+
case "tool-workflow/agent-end": return "workflow";
|
|
751
|
+
case "goal/change": return "goal";
|
|
752
|
+
case "schedule/change": return "schedule";
|
|
753
|
+
case "todo/write": return "todo";
|
|
754
|
+
case "web/deepseek-search-llm-request": return "web";
|
|
755
|
+
default: return "";
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
function eventDimensions(event) {
|
|
759
|
+
const kind = eventKind(event);
|
|
760
|
+
const type = event.type;
|
|
761
|
+
const data = event.data;
|
|
762
|
+
switch (type) {
|
|
763
|
+
case "user/message": return {
|
|
764
|
+
kind,
|
|
765
|
+
role: "user",
|
|
766
|
+
name: "",
|
|
767
|
+
actionId: ""
|
|
768
|
+
};
|
|
769
|
+
case "assistant/message": return {
|
|
770
|
+
kind,
|
|
771
|
+
role: "assistant",
|
|
772
|
+
name: "",
|
|
773
|
+
actionId: ""
|
|
774
|
+
};
|
|
775
|
+
case "tool/result": return {
|
|
776
|
+
kind,
|
|
777
|
+
role: "tool",
|
|
778
|
+
name: "",
|
|
779
|
+
actionId: data["message"]?.content?.[0]?.toolCallId ?? ""
|
|
780
|
+
};
|
|
781
|
+
case "tool/call": return {
|
|
782
|
+
kind,
|
|
783
|
+
role: "",
|
|
784
|
+
name: typeof data["name"] === "string" ? data["name"] : "",
|
|
785
|
+
actionId: typeof data["callId"] === "string" ? data["callId"] : ""
|
|
786
|
+
};
|
|
787
|
+
case "tool/code-dispatch-start":
|
|
788
|
+
case "tool/code-dispatch": return {
|
|
789
|
+
kind,
|
|
790
|
+
role: "",
|
|
791
|
+
name: "",
|
|
792
|
+
actionId: typeof data["subCallId"] === "string" ? data["subCallId"] : ""
|
|
793
|
+
};
|
|
794
|
+
case "command/run":
|
|
795
|
+
case "command/done": return {
|
|
796
|
+
kind,
|
|
797
|
+
role: "",
|
|
798
|
+
name: type === "command/run" && typeof data["name"] === "string" ? data["name"] : "",
|
|
799
|
+
actionId: typeof data["commandId"] === "string" ? data["commandId"] : ""
|
|
800
|
+
};
|
|
801
|
+
case "approval/asked":
|
|
802
|
+
case "approval/decided": return {
|
|
803
|
+
kind,
|
|
804
|
+
role: "",
|
|
805
|
+
name: "",
|
|
806
|
+
actionId: typeof data["id"] === "string" ? data["id"] : ""
|
|
807
|
+
};
|
|
808
|
+
case "hook/invoked":
|
|
809
|
+
case "hook/result": return {
|
|
810
|
+
kind,
|
|
811
|
+
role: "",
|
|
812
|
+
name: "",
|
|
813
|
+
actionId: typeof data["handlerId"] === "string" ? data["handlerId"] : ""
|
|
814
|
+
};
|
|
815
|
+
case "llm/retry":
|
|
816
|
+
case "llm/retry-started": return {
|
|
817
|
+
kind,
|
|
818
|
+
role: "",
|
|
819
|
+
name: "",
|
|
820
|
+
actionId: typeof data["retryId"] === "string" ? data["retryId"] : ""
|
|
821
|
+
};
|
|
822
|
+
case "tool-workflow/run-start":
|
|
823
|
+
case "tool-workflow/run-end":
|
|
824
|
+
case "tool-workflow/agent-start":
|
|
825
|
+
case "tool-workflow/agent-end": return {
|
|
826
|
+
kind,
|
|
827
|
+
role: "",
|
|
828
|
+
name: "",
|
|
829
|
+
actionId: typeof data["runId"] === "string" ? data["runId"] : ""
|
|
830
|
+
};
|
|
831
|
+
case "todo/write": return {
|
|
832
|
+
kind,
|
|
833
|
+
role: "",
|
|
834
|
+
name: "todos",
|
|
835
|
+
actionId: ""
|
|
836
|
+
};
|
|
837
|
+
case "subagent/descriptor": return {
|
|
838
|
+
kind,
|
|
839
|
+
role: "",
|
|
840
|
+
name: typeof data["label"] === "string" ? data["label"] : "",
|
|
841
|
+
actionId: ""
|
|
842
|
+
};
|
|
843
|
+
default: return {
|
|
844
|
+
kind,
|
|
845
|
+
role: "",
|
|
846
|
+
name: "",
|
|
847
|
+
actionId: ""
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
//#endregion
|
|
852
|
+
export { toJsonlArtifact as A, repairOrphanInboxSplices as C, scanRows as D, rowToMeta as E, sessionConflictRow as O, remapSurfaceOp as S, rowToEvent 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, sessionInsertRow 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, repairSurfaceOps as w, remapShadowedRange as x, orphanInboxSpliceSeqs as y };
|