@morlay/session-rdb 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -166
- package/dist/artifact.d.mts +2 -2
- package/dist/artifact.mjs +3 -2
- package/dist/{branch-D4nVzQQM.mjs → branch-aiXPmnKC.mjs} +1 -8
- package/dist/deletion.d.mts +3 -4
- package/dist/deletion.mjs +2 -1
- package/dist/export.d.mts +3 -5
- package/dist/export.mjs +1 -4
- package/dist/gc.d.mts +3 -5
- package/dist/gc.mjs +1 -3
- package/dist/import.d.mts +7 -8
- package/dist/import.mjs +2 -7
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +4 -3
- package/dist/invariant.d.mts +4 -5
- package/dist/{log-BWVFYAh5.mjs → log-DYxdjJ-l.mjs} +1 -52
- package/dist/{log-CUjKQbOR.d.mts → log-DYyxRh7j.d.mts} +2216 -294
- package/dist/rolldown-runtime-EAsCxrDo.mjs +14 -0
- package/dist/routes-DGBlBE_I.mjs +10 -0
- package/dist/{sqlite-SCiSnwaz.mjs → sqlite-YCr2-Fov.mjs} +24 -62
- package/dist/{src-BZ1tffd5.mjs → src-BmogreEz.mjs} +59 -97
- package/dist/storage.d.mts +6 -26
- package/dist/storage.mjs +1 -1
- package/dist/testing.d.mts +7 -7
- package/dist/testing.mjs +2 -4
- package/dist/usage.d.mts +1 -1
- package/dist/usage.mjs +1 -17
- package/package.json +2 -2
- package/src/backend.ts +35 -54
- package/src/branch.ts +3 -5
- package/src/deletion.ts +2 -1
- package/src/entities/v3/event-usage.ts +3 -6
- package/src/entities/v3/session-counts.ts +3 -5
- package/src/entities/v3/session-usage.ts +3 -5
- package/src/export.ts +5 -4
- package/src/gc.ts +4 -3
- package/src/import.ts +5 -6
- package/src/index.ts +47 -45
- package/src/legacy.ts +3 -5
- package/src/log.ts +28 -53
- package/src/postgres.ts +70 -61
- package/src/routes.ts +16 -0
- package/src/rows.ts +11 -15
- package/src/session-query.ts +3 -7
- package/src/sqlite.ts +70 -58
- package/src/storage-takeover/projection-cache.ts +6 -8
- package/src/storage-takeover/repository.ts +2 -2
- package/src/storage-takeover/types.ts +1 -1
- package/src/usage.ts +22 -34
- package/src/write-guard.ts +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { C as postgresTableDefs, T as WriteGuard, a as EVENT_ENCODING, c as eventDimensions, i as DEFAULT_BUSY_TIMEOUT_MS, r as createStorageRepository, t as SqliteBackend, w as toPostgresSchema } from "./sqlite-
|
|
1
|
+
import { C as postgresTableDefs, T as WriteGuard, a as EVENT_ENCODING, c as eventDimensions, i as DEFAULT_BUSY_TIMEOUT_MS, r as createStorageRepository, t as SqliteBackend, w as toPostgresSchema } from "./sqlite-YCr2-Fov.mjs";
|
|
2
|
+
import { a as SESSION_ROWS_PATH, t as SESSION_DELETE_PATH } from "./routes-DGBlBE_I.mjs";
|
|
2
3
|
import { COUNTED_EVENT_TYPES, addActivityCount, addActivityTotals, addTokenTotals, addTotals, emptyTotals, localDayKey, registerSessionUsage } from "./usage.mjs";
|
|
3
|
-
import { S as usageRowOf, _ as sessionConflictRow, b as titleOfEventData, g as sealOwnEvents, h as scanRows, m as rowToMeta, r as needsShapeAdoption, u as repairReadView, v as sessionInsertRow, x as toJsonlArtifact } from "./log-
|
|
4
|
-
import { c as isLegacyVersion, o as adoptLegacyRows, s as convertLegacyRows, t as SessionBranchRdb } from "./branch-
|
|
4
|
+
import { S as usageRowOf, _ as sessionConflictRow, b as titleOfEventData, g as sealOwnEvents, h as scanRows, m as rowToMeta, r as needsShapeAdoption, u as repairReadView, v as sessionInsertRow, x as toJsonlArtifact } from "./log-DYxdjJ-l.mjs";
|
|
5
|
+
import { c as isLegacyVersion, o as adoptLegacyRows, s as convertLegacyRows, t as SessionBranchRdb } from "./branch-aiXPmnKC.mjs";
|
|
5
6
|
import { registerSessionImport } from "./import.mjs";
|
|
6
7
|
import { registerSessionExport } from "./export.mjs";
|
|
7
8
|
import { registerSessionGc } from "./gc.mjs";
|
|
@@ -23,22 +24,19 @@ import { Service } from "@deepseek-ai/cordis";
|
|
|
23
24
|
//#region src/postgres.ts
|
|
24
25
|
const postgresMigrationsDir = fileURLToPath(new URL("../drizzle/postgres/", import.meta.url));
|
|
25
26
|
const pgWriteQueues = /* @__PURE__ */ new Map();
|
|
26
|
-
|
|
27
|
+
const REFRESH_FLAG_CHUNK = 400;
|
|
27
28
|
function enqueuePgWrite(key, fn) {
|
|
28
29
|
const run = (pgWriteQueues.get(key) ?? Promise.resolve()).then(fn);
|
|
29
30
|
pgWriteQueues.set(key, run.then(() => void 0, () => void 0));
|
|
30
31
|
return run;
|
|
31
32
|
}
|
|
32
|
-
/** pg 的 text 列窄化:非字符串(含 null)都不当作文本。 */
|
|
33
33
|
function text(value) {
|
|
34
34
|
return typeof value === "string" ? value : null;
|
|
35
35
|
}
|
|
36
|
-
/** pg 的 count/sum 回落成字符串:统一转成有限数。 */
|
|
37
36
|
function numeric(value) {
|
|
38
37
|
const parsed = typeof value === "number" ? value : Number(value ?? 0);
|
|
39
38
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
40
39
|
}
|
|
41
|
-
/** SQL 的缺失求和是 NULL:没有 usage 字段的行使该字段计 0。 */
|
|
42
40
|
function tokenTotalsOf(row) {
|
|
43
41
|
return {
|
|
44
42
|
inputTokens: numeric(row["input_tokens"]),
|
|
@@ -56,7 +54,6 @@ function emptyActivity() {
|
|
|
56
54
|
toolCalls: 0
|
|
57
55
|
};
|
|
58
56
|
}
|
|
59
|
-
/** `t_session_counts` 的四项计数折成活动计数(pg 的 sum 回落成字符串)。 */
|
|
60
57
|
function activityTotalsOf(row) {
|
|
61
58
|
return {
|
|
62
59
|
turns: numeric(row["turns"]),
|
|
@@ -65,7 +62,6 @@ function activityTotalsOf(row) {
|
|
|
65
62
|
toolCalls: numeric(row["tool_calls"])
|
|
66
63
|
};
|
|
67
64
|
}
|
|
68
|
-
/** `IN (...)` 用的类型字面量(与 `COUNTED_EVENT_TYPES` 同源)。 */
|
|
69
65
|
const COUNTED_EVENT_TYPE_SQL = COUNTED_EVENT_TYPES.map((type) => `'${type}'`).join(", ");
|
|
70
66
|
var PostgresBackend = class PostgresBackend {
|
|
71
67
|
db;
|
|
@@ -252,15 +248,21 @@ var PostgresBackend = class PostgresBackend {
|
|
|
252
248
|
}).where(eq(this.tables["t_sessions"].fSessionId, id)).execute();
|
|
253
249
|
}
|
|
254
250
|
async deleteBridgeTail(exec, id, fromSequence) {
|
|
255
|
-
|
|
251
|
+
const table = this.tables["t_session_events"];
|
|
252
|
+
return (await exec.execute(sql`
|
|
253
|
+
DELETE FROM ${table} WHERE f_session_id = ${id} AND f_sequence >= ${fromSequence}
|
|
254
|
+
RETURNING f_event_id
|
|
255
|
+
`)).rows.map((row) => row.f_event_id);
|
|
256
256
|
}
|
|
257
257
|
async deleteSession(exec, id) {
|
|
258
|
-
await exec.
|
|
258
|
+
const result = await exec.execute(sql`
|
|
259
|
+
DELETE FROM ${this.tables["t_session_events"]} WHERE f_session_id = ${id} RETURNING f_event_id
|
|
260
|
+
`);
|
|
259
261
|
await exec.delete(this.tables["t_workspace_sessions"]).where(eq(this.tables["t_workspace_sessions"].fSessionId, id)).execute();
|
|
260
262
|
await exec.delete(this.tables["t_session_projcache_row"]).where(eq(this.tables["t_session_projcache_row"].fSessionId, id)).execute();
|
|
261
263
|
await exec.delete(this.tables["t_sessions"]).where(eq(this.tables["t_sessions"].fSessionId, id)).execute();
|
|
264
|
+
return result.rows.map((row) => row.f_event_id);
|
|
262
265
|
}
|
|
263
|
-
/** 事件行可能被多个会话共享(fork 派生),所以孤儿只能在全库范围内判定。 */
|
|
264
266
|
async collectOrphans() {
|
|
265
267
|
const tEvents = this.tables["t_events"];
|
|
266
268
|
const tEventUsage = this.tables["t_event_usage"];
|
|
@@ -269,7 +271,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
269
271
|
await this.db.delete(tEventUsage).where(notInArray(tEventUsage.fEventId, this.db.select({ fEventId: tEvents.fEventId }).from(tEvents))).execute();
|
|
270
272
|
return result.rowCount ?? 0;
|
|
271
273
|
}
|
|
272
|
-
/** 父会话被删后留下的 subagent 会话:父已不在表里,或本来就没有父。 */
|
|
273
274
|
async listOrphanSubagentSessions() {
|
|
274
275
|
const tSessions = this.tables["t_sessions"];
|
|
275
276
|
return (await this.db.execute(sql`
|
|
@@ -280,16 +281,26 @@ var PostgresBackend = class PostgresBackend {
|
|
|
280
281
|
`)).rows.map((row) => row.id);
|
|
281
282
|
}
|
|
282
283
|
async deleteSessions(exec, ids) {
|
|
283
|
-
if (ids.length === 0) return
|
|
284
|
-
|
|
284
|
+
if (ids.length === 0) return {
|
|
285
|
+
deleted: 0,
|
|
286
|
+
eventIds: []
|
|
287
|
+
};
|
|
288
|
+
const removed = await exec.execute(sql`
|
|
289
|
+
DELETE FROM ${this.tables["t_session_events"]}
|
|
290
|
+
WHERE f_session_id IN (${sql.join(ids.map((id) => sql`${id}`), sql`, `)})
|
|
291
|
+
RETURNING f_event_id
|
|
292
|
+
`);
|
|
285
293
|
await exec.delete(this.tables["t_workspace_sessions"]).where(inArray(this.tables["t_workspace_sessions"].fSessionId, ids)).execute();
|
|
286
294
|
await exec.delete(this.tables["t_session_projcache_row"]).where(inArray(this.tables["t_session_projcache_row"].fSessionId, ids)).execute();
|
|
287
|
-
|
|
295
|
+
const result = await exec.delete(this.tables["t_sessions"]).where(inArray(this.tables["t_sessions"].fSessionId, ids)).execute();
|
|
296
|
+
return {
|
|
297
|
+
deleted: Number(result.rowCount ?? 0),
|
|
298
|
+
eventIds: removed.rows.map((row) => row.f_event_id)
|
|
299
|
+
};
|
|
288
300
|
}
|
|
289
301
|
async vacuum() {
|
|
290
302
|
await this.db.execute(sql`VACUUM ANALYZE`);
|
|
291
303
|
}
|
|
292
|
-
/** 派生统计表的回填:任一表为空即按事件表全量重算(幂等,迁移删表重建后自愈)。 */
|
|
293
304
|
async backfillUsageTables() {
|
|
294
305
|
await this.backfillEventUsage();
|
|
295
306
|
await this.backfillSessionUsage();
|
|
@@ -299,10 +310,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
299
310
|
const existing = await this.db.execute(sql.raw(`SELECT count(*) AS n FROM ${table}`));
|
|
300
311
|
return Number(existing.rows[0]?.["n"] ?? 0) === 0;
|
|
301
312
|
}
|
|
302
|
-
/**
|
|
303
|
-
* 用量行:一条 `assistant/message` 事件行一行,物化本地日与两个归属标记。
|
|
304
|
-
* 本地日按数据库会话时区渲染(部署前提是它与 host 时区一致,`localDayKey` 同口径)。
|
|
305
|
-
*/
|
|
306
313
|
async backfillEventUsage() {
|
|
307
314
|
if (!await this.tableIsEmpty(this.qualifiedTable("t_event_usage"))) return;
|
|
308
315
|
const tEventUsage = this.tables["t_event_usage"];
|
|
@@ -341,7 +348,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
341
348
|
ON CONFLICT DO NOTHING
|
|
342
349
|
`);
|
|
343
350
|
}
|
|
344
|
-
/** 会话 × 本地日 × 模型的 token 汇总:从桥接行 × 用量行重算(含 fork 继承前缀)。 */
|
|
345
351
|
async backfillSessionUsage() {
|
|
346
352
|
if (!await this.tableIsEmpty(this.qualifiedTable("t_session_usage"))) return;
|
|
347
353
|
const tSessionUsage = this.tables["t_session_usage"];
|
|
@@ -360,7 +366,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
360
366
|
ON CONFLICT DO NOTHING
|
|
361
367
|
`);
|
|
362
368
|
}
|
|
363
|
-
/** 会话 × 本地日的活动计数:从桥接行 × 事件类型重算。 */
|
|
364
369
|
async backfillSessionCounts() {
|
|
365
370
|
if (!await this.tableIsEmpty(this.qualifiedTable("t_session_counts"))) return;
|
|
366
371
|
const tSessionCounts = this.tables["t_session_counts"];
|
|
@@ -382,7 +387,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
382
387
|
ON CONFLICT DO NOTHING
|
|
383
388
|
`);
|
|
384
389
|
}
|
|
385
|
-
/** 用量聚合:与 SQLite 侧同形,读 `t_event_usage`,数值列回来是字符串。 */
|
|
386
390
|
async listSessionRows(query = {}) {
|
|
387
391
|
const needle = query.query?.trim().toLowerCase() ?? "";
|
|
388
392
|
const like = `%${needle}%`;
|
|
@@ -432,10 +436,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
432
436
|
total: numeric(counted.rows[0]?.["n"] ?? 0)
|
|
433
437
|
};
|
|
434
438
|
}
|
|
435
|
-
/**
|
|
436
|
-
* 用量聚合:与 SQLite 侧同形——只读三张派生统计表(用量行给去重口径的总量与「天 × 模型」桶,
|
|
437
|
-
* 两张会话汇总表给按会话的行),数值列回来是字符串。物化列让这里不做 `EXISTS`、不回连事件表。
|
|
438
|
-
*/
|
|
439
439
|
async usageReport(sinceMs) {
|
|
440
440
|
const usageSince = sinceMs === void 0 ? sql`` : sql` AND f_created_at >= ${sinceMs}`;
|
|
441
441
|
const dayFilter = (column) => sinceMs === void 0 ? sql`` : sql` AND ${sql.raw(column)} >= ${localDayKey(sinceMs)}`;
|
|
@@ -525,12 +525,10 @@ var PostgresBackend = class PostgresBackend {
|
|
|
525
525
|
}))
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
|
-
/** 表名限定到配置的 schema。 */
|
|
529
528
|
qualifiedTable(name) {
|
|
530
529
|
const schema = this.options.schema ?? "public";
|
|
531
530
|
return schema === "public" ? name : `"${schema}".${name}`;
|
|
532
531
|
}
|
|
533
|
-
/** token 用量旁路累加:派生表 `t_session_usage`,不在写事务里(失败可丢,表可销毁重建)。 */
|
|
534
532
|
async incrementSessionUsage(id, buckets) {
|
|
535
533
|
if (buckets.length === 0) return;
|
|
536
534
|
const tSessionUsage = this.tables["t_session_usage"];
|
|
@@ -549,7 +547,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
549
547
|
f_total_tokens = ${tSessionUsage}.f_total_tokens + EXCLUDED.f_total_tokens
|
|
550
548
|
`);
|
|
551
549
|
}
|
|
552
|
-
/** 活动计数旁路累加:派生表 `t_session_counts`,同上(四项计数一次落)。 */
|
|
553
550
|
async incrementSessionCounts(id, buckets) {
|
|
554
551
|
if (buckets.length === 0) return;
|
|
555
552
|
const tSessionCounts = this.tables["t_session_counts"];
|
|
@@ -565,7 +562,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
565
562
|
f_tool_calls = ${tSessionCounts}.f_tool_calls + EXCLUDED.f_tool_calls
|
|
566
563
|
`);
|
|
567
564
|
}
|
|
568
|
-
/** 按会话重算两张汇总表(rewind / fork 之后):先删该会话的行,再从事件表重算。 */
|
|
569
565
|
async rebuildSessionStats(id) {
|
|
570
566
|
const tSessionUsage = this.tables["t_session_usage"];
|
|
571
567
|
const tSessionCounts = this.tables["t_session_counts"];
|
|
@@ -601,20 +597,23 @@ var PostgresBackend = class PostgresBackend {
|
|
|
601
597
|
GROUP BY 1, 2
|
|
602
598
|
`);
|
|
603
599
|
}
|
|
604
|
-
|
|
605
|
-
async refreshEventUsageFlags() {
|
|
600
|
+
async refreshEventUsageFlags(eventIds) {
|
|
606
601
|
const tEventUsage = this.tables["t_event_usage"];
|
|
607
602
|
const tSessionEvents = this.tables["t_session_events"];
|
|
608
603
|
const tSessions = this.tables["t_sessions"];
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
604
|
+
for (let at = 0; at < eventIds.length; at += REFRESH_FLAG_CHUNK) {
|
|
605
|
+
const chunk = eventIds.slice(at, at + REFRESH_FLAG_CHUNK);
|
|
606
|
+
await this.db.execute(sql`
|
|
607
|
+
UPDATE ${tEventUsage} SET
|
|
608
|
+
f_referenced = (EXISTS (SELECT 1 FROM ${tSessionEvents} rb
|
|
609
|
+
WHERE rb.f_event_id = ${tEventUsage}.f_event_id))::int,
|
|
610
|
+
f_subagent = (EXISTS (SELECT 1 FROM ${tSessionEvents} sb
|
|
611
|
+
JOIN ${tSessions} ss ON ss.f_session_id = sb.f_session_id
|
|
612
|
+
WHERE sb.f_event_id = ${tEventUsage}.f_event_id
|
|
613
|
+
AND ss.f_origin = 'subagent'))::int
|
|
614
|
+
WHERE f_event_id IN (${sql.join(chunk.map((id) => sql`${id}`), sql`, `)})
|
|
615
|
+
`);
|
|
616
|
+
}
|
|
618
617
|
}
|
|
619
618
|
async deleteSessionStats(id) {
|
|
620
619
|
await this.db.execute(sql`DELETE FROM ${this.tables["t_session_usage"]} WHERE f_session_id = ${id}`);
|
|
@@ -643,7 +642,6 @@ var PostgresBackend = class PostgresBackend {
|
|
|
643
642
|
};
|
|
644
643
|
//#endregion
|
|
645
644
|
//#region src/deletion.ts
|
|
646
|
-
const SESSION_DELETE_PATH = "/api/session.delete";
|
|
647
645
|
const STATUS_OF_DELETION_ERROR = {
|
|
648
646
|
SESSION_NOT_FOUND: 404,
|
|
649
647
|
SESSION_NOT_ARCHIVED: 409,
|
|
@@ -706,15 +704,6 @@ function registerSessionDeletion(ctx, persistence) {
|
|
|
706
704
|
}
|
|
707
705
|
//#endregion
|
|
708
706
|
//#region src/rows.ts
|
|
709
|
-
/**
|
|
710
|
-
* 管理面的会话列表:**我们自己的**一条路由(完整语料,含归档),与官方 `session/list` 分开。
|
|
711
|
-
*
|
|
712
|
-
* 官方那条(`session/list` → `ctx.sessionQuery.listSessions`)按部署策略默认排除已归档——那是给上游
|
|
713
|
-
* UI 用的。归档集的管理动作要有完整列表,所以这里单独给一条:标题直接从会话列取,最后活动时间用
|
|
714
|
-
* 该会话最后一个事件的时间。
|
|
715
|
-
*/
|
|
716
|
-
const SESSION_ROWS_PATH = "/api/session.rows";
|
|
717
|
-
/** 一页的条数上限:超过就按上限截断(这个接口给页面用,不是导出通道)。 */
|
|
718
707
|
const MAX_PAGE_SIZE = 200;
|
|
719
708
|
const DEFAULT_PAGE_SIZE = 20;
|
|
720
709
|
function registerSessionRows(ctx, backend) {
|
|
@@ -778,19 +767,12 @@ var SessionQueryRdb = class extends SessionQueryEngine {
|
|
|
778
767
|
constructor(ctx, config = {}) {
|
|
779
768
|
super(ctx, config);
|
|
780
769
|
}
|
|
781
|
-
/**
|
|
782
|
-
* 官方列表(`session/list`)**默认不含已归档**:归档是「收起来」的会话,列表与搜索都不该把它混进
|
|
783
|
-
* 日常集合(上游 client 再用 workspace registry 的归档集做「只看归档」的派生)。
|
|
784
|
-
*
|
|
785
|
-
* 完整语料(含归档)走我们自己的管理面路由 `SESSION_ROWS_PATH`——两条路分开,不在一处混。
|
|
786
|
-
*/
|
|
787
770
|
async listSessions(signal) {
|
|
788
771
|
const records = await super.listSessions(signal);
|
|
789
772
|
const archived = this.archivedSessionIds();
|
|
790
773
|
if (archived.size === 0) return records;
|
|
791
774
|
return records.filter((record) => !archived.has(String(record.header.id)));
|
|
792
775
|
}
|
|
793
|
-
/** 归档集合来自 workspace registry;服务未就绪时保守返回空集(宁可多给,不可漏掉可见会话)。 */
|
|
794
776
|
archivedSessionIds() {
|
|
795
777
|
const registry = this.ctx.get("workspaceRegistry");
|
|
796
778
|
return new Set(registry?.archivedSessionIds ?? []);
|
|
@@ -840,10 +822,6 @@ var SessionProjectionCacheRdb = class extends Service {
|
|
|
840
822
|
if (record === void 0) return void 0;
|
|
841
823
|
return identityMatches(record.identity, expected) ? record : void 0;
|
|
842
824
|
}
|
|
843
|
-
/**
|
|
844
|
-
* header-only 读(会话列表这类):上游 0.1.7 起只给 header 与 keys——它要求的是**生命周期**身份,
|
|
845
|
-
* 不再要求调用方提供 inherited cut(那个 cut 只有写路径与 hydration 用得上)。
|
|
846
|
-
*/
|
|
847
825
|
cachedSnapshot(meta, keys) {
|
|
848
826
|
const record = this.recordForLifecycle(meta);
|
|
849
827
|
const snapshot = record === void 0 ? void 0 : this.viewRecord(record, keys);
|
|
@@ -986,7 +964,6 @@ function detachJson(rows) {
|
|
|
986
964
|
if (text === void 0) throw new TypeError("projection checkpoint is not losslessly JSON-serializable");
|
|
987
965
|
return JSON.parse(text);
|
|
988
966
|
}
|
|
989
|
-
/** header 能证明的生命周期身份(不含 inherited cut):header-only 读只比对它。 */
|
|
990
967
|
function lifecycleIdentityOf(header) {
|
|
991
968
|
return {
|
|
992
969
|
formatVersion: header.version,
|
|
@@ -1158,7 +1135,6 @@ function installStorageTakeover(ctx, options) {
|
|
|
1158
1135
|
}
|
|
1159
1136
|
//#endregion
|
|
1160
1137
|
//#region src/index.ts
|
|
1161
|
-
/** 一批事件里的最大时间:写路径据此推进会话行的「最后活动时间」。 */
|
|
1162
1138
|
function maxEventTime(events) {
|
|
1163
1139
|
let max;
|
|
1164
1140
|
for (const event of events) {
|
|
@@ -1426,12 +1402,7 @@ var RdbSessionHandle = class RdbSessionHandle {
|
|
|
1426
1402
|
}
|
|
1427
1403
|
static LIVE_WRITE_BATCH_MAX_DELAY_MS = 200;
|
|
1428
1404
|
};
|
|
1429
|
-
/**
|
|
1430
|
-
* 本地化说明:`description()` 的类型签名只声明 `string`,而 meta 本身接受 `Dict<string>`
|
|
1431
|
-
* (`vendor/schemastery/src/index.ts` 的 `mergeDesc` 就是按字典合并的),所以这里只做一次类型放行。
|
|
1432
|
-
*/
|
|
1433
1405
|
const localized = (text) => text;
|
|
1434
|
-
/** 投影 checkpoint 的写回节流:两个分支共用。 */
|
|
1435
1406
|
const projectionCacheSchema = z.object({
|
|
1436
1407
|
writeEveryEvents: z.natural().min(1).default(DEFAULT_PROJECTION_WRITE_EVERY_EVENTS).description(localized({
|
|
1437
1408
|
zh: "每累计这么多事件写回一次投影 checkpoint。",
|
|
@@ -1491,7 +1462,6 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1491
1462
|
reuseEventIds = /* @__PURE__ */ new Map();
|
|
1492
1463
|
liveBuffers = /* @__PURE__ */ new Map();
|
|
1493
1464
|
liveReady = /* @__PURE__ */ new Map();
|
|
1494
|
-
/** 本次装配用的配置快照(整段 Config 是 volatile,重挂会给新的)。 */
|
|
1495
1465
|
config;
|
|
1496
1466
|
constructor(ctx, config, injectedBackend) {
|
|
1497
1467
|
super(ctx);
|
|
@@ -1634,27 +1604,24 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1634
1604
|
if (row.fArchivedAt === null) throw new SessionDeletionError(`session "${id}" is not archived; only archived sessions can be deleted`, "SESSION_NOT_ARCHIVED");
|
|
1635
1605
|
if (this.tracker.hasPending(id) || this.tracker.hasOpenHandle(id)) throw new SessionDeletionError(`session "${id}" is live; stop it before deleting`, "SESSION_LIVE");
|
|
1636
1606
|
await this.unarchiveBeforeDeletion(id);
|
|
1637
|
-
await this.backend.transaction(
|
|
1638
|
-
await tx.deleteSession(id);
|
|
1639
|
-
});
|
|
1607
|
+
const referenced = await this.backend.transaction((tx) => tx.deleteSession(id));
|
|
1640
1608
|
this.liveBuffers.delete(id);
|
|
1641
1609
|
this.liveReady.delete(id);
|
|
1642
1610
|
this.liveFailures.delete(id);
|
|
1643
1611
|
this.liveDropWarned.delete(id);
|
|
1644
1612
|
this.reuseEventIds.delete(id);
|
|
1645
1613
|
await this.dropSessionStats(id);
|
|
1614
|
+
await this.refreshEventUsageFlags(referenced);
|
|
1646
1615
|
}
|
|
1647
|
-
/** GC 通道:回收已无桥接行引用的事件行(孤儿),返回删除行数。 */
|
|
1648
1616
|
async collectOrphans() {
|
|
1649
1617
|
await this.ready;
|
|
1650
1618
|
return this.backend.collectOrphans();
|
|
1651
1619
|
}
|
|
1652
|
-
/** GC 通道:回收父已不存在的 subagent 会话(live 的跳过),返回删除的会话数。 */
|
|
1653
1620
|
async collectOrphanSessions() {
|
|
1654
1621
|
await this.ready;
|
|
1655
1622
|
const deletable = (await this.backend.listOrphanSubagentSessions()).filter((id) => !this.tracker.hasPending(id) && !this.tracker.hasOpenHandle(id));
|
|
1656
1623
|
if (deletable.length === 0) return 0;
|
|
1657
|
-
const deleted = await this.backend.transaction((tx) => tx.deleteSessions(deletable));
|
|
1624
|
+
const { deleted, eventIds } = await this.backend.transaction((tx) => tx.deleteSessions(deletable));
|
|
1658
1625
|
for (const id of deletable) {
|
|
1659
1626
|
this.liveBuffers.delete(id);
|
|
1660
1627
|
this.liveReady.delete(id);
|
|
@@ -1663,14 +1630,13 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1663
1630
|
this.reuseEventIds.delete(id);
|
|
1664
1631
|
await this.dropSessionStats(id);
|
|
1665
1632
|
}
|
|
1633
|
+
await this.refreshEventUsageFlags(eventIds);
|
|
1666
1634
|
return deleted;
|
|
1667
1635
|
}
|
|
1668
|
-
/** 用量统计:SQL 聚合的按天 × 模型桶与按会话行(事件行去重、排除孤儿行)。 */
|
|
1669
1636
|
async usageReport(sinceMs) {
|
|
1670
1637
|
await this.ready;
|
|
1671
1638
|
return this.backend.usageReport(sinceMs);
|
|
1672
1639
|
}
|
|
1673
|
-
/** GC 通道:VACUUM;调用方需先停止运行中的写路径(见 `registerSessionGc`)。 */
|
|
1674
1640
|
async vacuum() {
|
|
1675
1641
|
await this.ready;
|
|
1676
1642
|
await this.backend.vacuum();
|
|
@@ -1804,11 +1770,6 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1804
1770
|
...tornFrom !== void 0 ? { tornFrom } : {}
|
|
1805
1771
|
};
|
|
1806
1772
|
}
|
|
1807
|
-
/**
|
|
1808
|
-
* 统计衍生表的**旁路累加**:不在写事务里、失败只 warn——两张会话汇总表都是可销毁重建的
|
|
1809
|
-
* 派生表,丢几次累加不影响可用性(需要时用 `rebuildSessionStats` 重算)。
|
|
1810
|
-
* token 走写路径已折好的用量行,活动计数走本批事件类型。
|
|
1811
|
-
*/
|
|
1812
1773
|
async recordSessionStats(id, events, usageRows) {
|
|
1813
1774
|
const usageBuckets = sessionUsageBuckets(usageRows);
|
|
1814
1775
|
if (usageBuckets.length > 0) try {
|
|
@@ -1823,33 +1784,36 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1823
1784
|
this.ctx.logger.warn(`session-rdb: activity counts for "${id}" not updated (${describeError(error)})`);
|
|
1824
1785
|
}
|
|
1825
1786
|
}
|
|
1826
|
-
/**
|
|
1827
|
-
* 重算一个会话的统计(rewind / fork 之后;best-effort,同 `recordSessionStats`):
|
|
1828
|
-
* 两张汇总表按会话重算,用量行的引用标记全量重算(引用可能跨会话消失)。
|
|
1829
|
-
*/
|
|
1830
1787
|
async rebuildSessionStats(id) {
|
|
1831
1788
|
try {
|
|
1832
1789
|
await this.backend.rebuildSessionStats(id);
|
|
1833
|
-
await this.backend.refreshEventUsageFlags();
|
|
1834
1790
|
} catch (error) {
|
|
1835
1791
|
this.ctx.logger.warn(`session-rdb: session stats for "${id}" not rebuilt (${describeError(error)})`);
|
|
1836
1792
|
}
|
|
1837
1793
|
}
|
|
1838
|
-
|
|
1794
|
+
async refreshEventUsageFlags(eventIds) {
|
|
1795
|
+
const unique = [...new Set(eventIds)];
|
|
1796
|
+
if (unique.length === 0) return;
|
|
1797
|
+
try {
|
|
1798
|
+
await this.backend.refreshEventUsageFlags(unique);
|
|
1799
|
+
} catch (error) {
|
|
1800
|
+
this.ctx.logger.warn(`session-rdb: usage reference flags not refreshed (${describeError(error)})`);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1839
1803
|
async dropSessionStats(id) {
|
|
1840
1804
|
try {
|
|
1841
1805
|
await this.backend.deleteSessionStats(id);
|
|
1842
|
-
await this.backend.refreshEventUsageFlags();
|
|
1843
1806
|
} catch (error) {
|
|
1844
1807
|
this.ctx.logger.warn(`session-rdb: session stats for "${id}" not deleted (${describeError(error)})`);
|
|
1845
1808
|
}
|
|
1846
1809
|
}
|
|
1847
1810
|
async rewriteMigratedLog(id, log) {
|
|
1811
|
+
let removed = [];
|
|
1848
1812
|
await this.backend.transaction(async (tx) => {
|
|
1849
1813
|
const head = await tx.getHead(id);
|
|
1850
1814
|
if (!this.writeGuard.has(id)) this.writeGuard.confirmHead(id, head.fHeadSequence);
|
|
1851
1815
|
this.writeGuard.assertNoConcurrentWriter(id, head.fHeadSequence);
|
|
1852
|
-
await tx.deleteBridgeTail(id, 0);
|
|
1816
|
+
removed = await tx.deleteBridgeTail(id, 0);
|
|
1853
1817
|
await tx.upsertSession({
|
|
1854
1818
|
meta: log.meta,
|
|
1855
1819
|
inheritedEventCount: SessionLogOffset(log.inheritedEventCount)
|
|
@@ -1862,6 +1826,7 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1862
1826
|
await tx.bumpRevision(id, maxEventTime(log.events));
|
|
1863
1827
|
});
|
|
1864
1828
|
await this.rebuildSessionStats(id);
|
|
1829
|
+
await this.refreshEventUsageFlags(removed);
|
|
1865
1830
|
}
|
|
1866
1831
|
async listSnapshots(signal) {
|
|
1867
1832
|
signal?.throwIfAborted();
|
|
@@ -1951,7 +1916,6 @@ var SessionPersistenceRdb = class extends SessionPersistence {
|
|
|
1951
1916
|
registerReuseEventIds(childId, map) {
|
|
1952
1917
|
this.reuseEventIds.set(childId, new Map(map));
|
|
1953
1918
|
}
|
|
1954
|
-
/** 丢弃一个还没被消费的复用映射(fork 失败时):留着会让同一个 childId 之后的落写复用父会话的事件行。 */
|
|
1955
1919
|
dropReuseEventIds(childId) {
|
|
1956
1920
|
this.reuseEventIds.delete(childId);
|
|
1957
1921
|
}
|
|
@@ -2091,7 +2055,6 @@ function seedCoversPrefix(seed, prefix) {
|
|
|
2091
2055
|
return seedEvent !== void 0 && JSON.stringify(seedEvent) === JSON.stringify(event);
|
|
2092
2056
|
});
|
|
2093
2057
|
}
|
|
2094
|
-
/** 一批事件折成活动计数的桶:只数四种类型,按本地日聚合成四项。 */
|
|
2095
2058
|
function sessionCountBuckets(events) {
|
|
2096
2059
|
const counted = /* @__PURE__ */ new Map();
|
|
2097
2060
|
for (const event of events) {
|
|
@@ -2109,7 +2072,6 @@ function sessionCountBuckets(events) {
|
|
|
2109
2072
|
}
|
|
2110
2073
|
return [...counted.values()];
|
|
2111
2074
|
}
|
|
2112
|
-
/** 一批用量行折成 token 桶:按「本地日 × 模型」聚合(模型未知落空串,与表口径一致)。 */
|
|
2113
2075
|
function sessionUsageBuckets(usageRows) {
|
|
2114
2076
|
const counted = /* @__PURE__ */ new Map();
|
|
2115
2077
|
for (const row of usageRows) {
|
|
@@ -2209,4 +2171,4 @@ async function appendEventTail(tx, meta, events, anchor, reuse) {
|
|
|
2209
2171
|
};
|
|
2210
2172
|
}
|
|
2211
2173
|
//#endregion
|
|
2212
|
-
export {
|
|
2174
|
+
export { SessionPersistenceRdb as n, registerSessionDeletion as r, SessionDeletionError as t };
|
package/dist/storage.d.mts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { A as SessionRow, At as
|
|
1
|
+
import { A as SessionRow, At as WriteGuard, Ct as tSessionProjcacheRows, D as SessionCountBucket, Dt as tWorkspaceSessions, E as EventRow, Et as tStorageUnits, F as UsageAggregate, Lt as StorageRepository, O as SessionListRowsPage, Ot as tWorkspaceState, St as tSessionEvents, T as BackendTx, Tt as tSessions, _t as tEventUsage, bt as tSchemaMeta, ct as DEFAULT_BUSY_TIMEOUT_MS, dt as EventRole, ft as JournalMode, gt as eventKind, ht as eventDimensions, j as SessionUsageBucket, k as SessionListRowsQuery, kt as tWorkspaces, lt as EVENT_ENCODING, mt as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, pt as SCHEMA_VERSION, ut as EventKind, vt as tEvents, w as Backend, wt as tSessionUsage, xt as tSessionCounts, yt as tPersistenceState } from "./log-DYyxRh7j.mjs";
|
|
2
2
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
3
3
|
import { DatabaseSync } from "node:sqlite";
|
|
4
4
|
//#region src/sqlite.d.ts
|
|
5
|
-
declare function openDatabase(path: string, journalMode: JournalMode, busyTimeout?: number): Promise<DatabaseSync>;
|
|
6
|
-
interface SqliteBackendOptions {
|
|
5
|
+
export declare function openDatabase(path: string, journalMode: JournalMode, busyTimeout?: number): Promise<DatabaseSync>;
|
|
6
|
+
export interface SqliteBackendOptions {
|
|
7
7
|
path: string;
|
|
8
8
|
journalMode: JournalMode;
|
|
9
9
|
busyTimeout: number;
|
|
10
10
|
}
|
|
11
|
-
declare class SqliteBackend implements Backend {
|
|
11
|
+
export declare class SqliteBackend implements Backend {
|
|
12
12
|
private readonly options;
|
|
13
13
|
readonly kind: "sqlite";
|
|
14
14
|
storeIdentity: string;
|
|
@@ -42,38 +42,18 @@ declare class SqliteBackend implements Backend {
|
|
|
42
42
|
private deleteBridgeTail;
|
|
43
43
|
private getPrevBridge;
|
|
44
44
|
private deleteSession;
|
|
45
|
-
/** 事件行可能被多个会话共享(fork 派生),所以孤儿只能在全库范围内判定。 */
|
|
46
45
|
collectOrphans(): Promise<number>;
|
|
47
|
-
/** 父会话被删后留下的 subagent 会话:父已不在表里,或本来就没有父。 */
|
|
48
46
|
listOrphanSubagentSessions(): Promise<SessionId[]>;
|
|
49
47
|
private deleteSessions;
|
|
50
|
-
/**
|
|
51
|
-
* 用量聚合:token 用量沿 `t_event_usage` 的用量行,活动计数(轮次 / 步骤 / 用户输入 / 工具调用)
|
|
52
|
-
* 沿 `t_events` 的事件类型数——两者限定在**有 token 用量的会话**里,时间范围各自按自己的
|
|
53
|
-
* `f_created_at`(同一时刻写入,口径一致)。
|
|
54
|
-
*/
|
|
55
48
|
listSessionRows(query?: SessionListRowsQuery): Promise<SessionListRowsPage>;
|
|
56
|
-
/**
|
|
57
|
-
* 用量聚合:只读三张派生统计表——事件级用量行给去重口径的总量与「天 × 模型」桶,
|
|
58
|
-
* `t_session_usage` / `t_session_counts` 给按会话的行(含 fork 继承前缀)。
|
|
59
|
-
* 归属、本地日与「是否被引用」都是物化列,这里不再现算、也不回连事件表。
|
|
60
|
-
* 事件级按毫秒时间戳过滤、汇总表按本地日过滤——`sinceMs` 对齐到本地零点时两者等价。
|
|
61
|
-
*/
|
|
62
49
|
usageReport(sinceMs?: number): Promise<UsageAggregate>;
|
|
63
|
-
/** token 用量旁路累加:派生表 `t_session_usage`,不在写事务里(失败可丢,表可销毁重建)。 */
|
|
64
50
|
incrementSessionUsage(id: SessionId, buckets: readonly SessionUsageBucket[]): Promise<void>;
|
|
65
|
-
/** 活动计数旁路累加:派生表 `t_session_counts`,同上(四项计数一次落)。 */
|
|
66
51
|
incrementSessionCounts(id: SessionId, buckets: readonly SessionCountBucket[]): Promise<void>;
|
|
67
|
-
/** 按会话重算两张汇总表(rewind / fork 之后):先删该会话的行,再从事件表重算。 */
|
|
68
52
|
rebuildSessionStats(id: SessionId): Promise<void>;
|
|
69
|
-
|
|
70
|
-
* 全量重算用量行的引用标记:rewind 截断 / fork 复用 / 会话删除都会让「引用」跨会话变化,
|
|
71
|
-
* 只按本会话判定不够。低频路径,一次全表 UPDATE(3 万行量级)。
|
|
72
|
-
*/
|
|
73
|
-
refreshEventUsageFlags(): Promise<void>;
|
|
53
|
+
refreshEventUsageFlags(eventIds: readonly string[]): Promise<void>;
|
|
74
54
|
deleteSessionStats(id: SessionId): Promise<void>;
|
|
75
55
|
vacuum(): Promise<void>;
|
|
76
56
|
private eventRows;
|
|
77
57
|
}
|
|
78
58
|
//#endregion
|
|
79
|
-
export { DEFAULT_BUSY_TIMEOUT_MS, EVENT_ENCODING, EventKind, EventRole, type EventRow, JournalMode, SCHEMA_VERSION, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, type SessionRow,
|
|
59
|
+
export { DEFAULT_BUSY_TIMEOUT_MS, EVENT_ENCODING, EventKind, EventRole, type EventRow, JournalMode, SCHEMA_VERSION, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, type SessionRow, WriteGuard, eventDimensions, eventKind, tEventUsage, tEvents, tPersistenceState, tSchemaMeta, tSessionCounts, tSessionEvents, tSessionProjcacheRows, tSessionUsage, tSessions, tStorageUnits, tWorkspaceSessions, tWorkspaceState, tWorkspaces };
|
package/dist/storage.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as tWorkspaces, T as WriteGuard, _ as tSessionUsage, a as EVENT_ENCODING, b as tWorkspaceSessions, c as eventDimensions, d as tEvents, f as tPersistenceState, g as tSessionProjcacheRows, h as tSessionEvents, i as DEFAULT_BUSY_TIMEOUT_MS, l as eventKind, m as tSessionCounts, n as openDatabase, o as SCHEMA_VERSION, p as tSchemaMeta, s as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, t as SqliteBackend, u as tEventUsage, v as tSessions, x as tWorkspaceState, y as tStorageUnits } from "./sqlite-
|
|
1
|
+
import { S as tWorkspaces, T as WriteGuard, _ as tSessionUsage, a as EVENT_ENCODING, b as tWorkspaceSessions, c as eventDimensions, d as tEvents, f as tPersistenceState, g as tSessionProjcacheRows, h as tSessionEvents, i as DEFAULT_BUSY_TIMEOUT_MS, l as eventKind, m as tSessionCounts, n as openDatabase, o as SCHEMA_VERSION, p as tSchemaMeta, s as SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, t as SqliteBackend, u as tEventUsage, v as tSessions, x as tWorkspaceState, y as tStorageUnits } from "./sqlite-YCr2-Fov.mjs";
|
|
2
2
|
export { DEFAULT_BUSY_TIMEOUT_MS, EVENT_ENCODING, SCHEMA_VERSION, SESSION_PERSISTENCE_SQLITE_APPLICATION_ID, SqliteBackend, WriteGuard, eventDimensions, eventKind, openDatabase, tEventUsage, tEvents, tPersistenceState, tSchemaMeta, tSessionCounts, tSessionEvents, tSessionProjcacheRows, tSessionUsage, tSessions, tStorageUnits, tWorkspaceSessions, tWorkspaceState, tWorkspaces };
|
package/dist/testing.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { at as truncateLiveSession } from "./log-DYyxRh7j.mjs";
|
|
2
2
|
import { SessionPersistence } from "@deepseek-ai/dsh-session-persistence";
|
|
3
3
|
import { Session, SessionEvent, SessionHeader, SessionId } from "@deepseek-ai/dsh-session";
|
|
4
4
|
import { Context, Fiber } from "@deepseek-ai/cordis";
|
|
@@ -11,10 +11,10 @@ interface ContractBackend extends ContractBackendInstance {
|
|
|
11
11
|
reopen?: () => Promise<ContractBackendInstance>;
|
|
12
12
|
corruptTail?: (id: SessionId, cwd: string | undefined) => Promise<void>;
|
|
13
13
|
}
|
|
14
|
-
declare function meta(id: string, cwd?: string): SessionHeader;
|
|
15
|
-
declare function oneTurnLog(): SessionEvent[];
|
|
16
|
-
declare function appendLog(session: Session, events: readonly SessionEvent[]): void;
|
|
17
|
-
declare function runPersistenceContract(name: string, make: () => Promise<ContractBackend>): void;
|
|
14
|
+
export declare function meta(id: string, cwd?: string): SessionHeader;
|
|
15
|
+
export declare function oneTurnLog(): SessionEvent[];
|
|
16
|
+
export declare function appendLog(session: Session, events: readonly SessionEvent[]): void;
|
|
17
|
+
export declare function runPersistenceContract(name: string, make: () => Promise<ContractBackend>): void;
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/testing/coordinator-contract.d.ts
|
|
20
20
|
interface CoordinatorFixture {
|
|
@@ -22,6 +22,6 @@ interface CoordinatorFixture {
|
|
|
22
22
|
corruptTail?: (id: SessionId, cwd: string | undefined) => Promise<void>;
|
|
23
23
|
cleanup: () => Promise<void>;
|
|
24
24
|
}
|
|
25
|
-
declare function runCoordinatorContract(name: string, makeFixture: () => Promise<CoordinatorFixture>): void;
|
|
25
|
+
export declare function runCoordinatorContract(name: string, makeFixture: () => Promise<CoordinatorFixture>): void;
|
|
26
26
|
//#endregion
|
|
27
|
-
export { type ContractBackend, type CoordinatorFixture,
|
|
27
|
+
export { type ContractBackend, type CoordinatorFixture, truncateLiveSession };
|
package/dist/testing.mjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as __commonJSMin } from "./rolldown-runtime-EAsCxrDo.mjs";
|
|
2
|
+
import { a as truncateLiveSession } from "./branch-aiXPmnKC.mjs";
|
|
2
3
|
import { SessionAlreadyExistsError, SessionAlreadyOwnedError, SessionFormatUnsupportedError, SessionHandleClosedError, SessionPersistenceNotFoundError, SessionReadOnlyError } from "@deepseek-ai/dsh-session-persistence";
|
|
3
4
|
import SessionStore, { SESSION_FORMAT_VERSION, SessionId, SessionLogOffset, SessionSeq } from "@deepseek-ai/dsh-session";
|
|
4
5
|
import { Context } from "@deepseek-ai/cordis";
|
|
5
6
|
import { MessageId, createUserMessage, freezeMessage } from "@deepseek-ai/dsh-llm";
|
|
6
|
-
//#region \0rolldown/runtime.js
|
|
7
|
-
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
|
|
8
|
-
//#endregion
|
|
9
7
|
//#region ../../../node_modules/.pnpm/vitest@5.0.2_@opentelemetry+api@1.9.1_@types+node@26.6.3_happy-dom@20.14.5_jsdom@30.1.1_5bd35cff0016eb681427af506a019366/node_modules/vitest/dist/chunks/tinyrainbow.Ht9iggcq.js
|
|
10
8
|
var b$1 = {
|
|
11
9
|
reset: [0, 0],
|
package/dist/usage.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { B as
|
|
1
|
+
import { B as UsageTotals, F as UsageAggregate, G as emptyTotals, H as addActivityTotals, I as UsageBucket, It as SESSION_USAGE_PATH, J as resolveUsageSince, K as localDayKey, L as UsageRangeKey, M as COUNTED_EVENT_TYPES, N as SessionUsageReport, P as UsageActivityTotals, R as UsageSessionRow, U as addTokenTotals, V as addActivityCount, W as addTotals, q as registerSessionUsage, z as UsageTokenTotals } from "./log-DYyxRh7j.mjs";
|
|
2
2
|
export { COUNTED_EVENT_TYPES, SESSION_USAGE_PATH, SessionUsageReport, UsageActivityTotals, UsageAggregate, UsageBucket, UsageRangeKey, UsageSessionRow, UsageTokenTotals, UsageTotals, addActivityCount, addActivityTotals, addTokenTotals, addTotals, emptyTotals, localDayKey, registerSessionUsage, resolveUsageSince };
|
package/dist/usage.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { o as SESSION_USAGE_PATH } from "./routes-DGBlBE_I.mjs";
|
|
1
2
|
//#region src/usage.ts
|
|
2
|
-
const SESSION_USAGE_PATH = "/api/session.usage";
|
|
3
3
|
const ROLLING_DAYS = {
|
|
4
4
|
"7d": 7,
|
|
5
5
|
"30d": 30,
|
|
@@ -10,14 +10,6 @@ function localDayStart(now) {
|
|
|
10
10
|
start.setHours(0, 0, 0, 0);
|
|
11
11
|
return start;
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
14
|
-
* 范围起点(含),不限时为 undefined。**所有起点都对齐到 host 本地时区的零点**——`day` / `week` 是
|
|
15
|
-
* 今天 / 本周一的零点,`7d` / `30d` / `90d` 是「今天零点往前 N-1 天」(含今天共 N 个自然日)。
|
|
16
|
-
* 对齐的意义:事件级表按毫秒过滤、会话汇总表按本地日过滤,两者因此严格等价。
|
|
17
|
-
* @param range - 语义键。
|
|
18
|
-
* @param now - 当前时刻。
|
|
19
|
-
* @returns 起点毫秒时间戳,或 undefined。
|
|
20
|
-
*/
|
|
21
13
|
function resolveUsageSince(range, now) {
|
|
22
14
|
switch (range) {
|
|
23
15
|
case "all": return;
|
|
@@ -37,14 +29,12 @@ function resolveUsageSince(range, now) {
|
|
|
37
29
|
function parseUsageRange(value) {
|
|
38
30
|
return value === "day" || value === "week" || value === "7d" || value === "30d" || value === "90d" ? value : "all";
|
|
39
31
|
}
|
|
40
|
-
/** 计入活动计数的事件类型(轮次 / 步骤 / 用户输入 / 工具调用)。 */
|
|
41
32
|
const COUNTED_EVENT_TYPES = [
|
|
42
33
|
"turn/start",
|
|
43
34
|
"step/start",
|
|
44
35
|
"user/message",
|
|
45
36
|
"tool/call"
|
|
46
37
|
];
|
|
47
|
-
/** 按事件类型把计数累加到活动指标上(表里按类型存,读的时候折成四项)。 */
|
|
48
38
|
function addActivityCount(target, type, count) {
|
|
49
39
|
switch (type) {
|
|
50
40
|
case "turn/start":
|
|
@@ -62,7 +52,6 @@ function addActivityCount(target, type, count) {
|
|
|
62
52
|
default: return target;
|
|
63
53
|
}
|
|
64
54
|
}
|
|
65
|
-
/** 毫秒时间戳 → host 本地日(`YYYY-MM-DD`,与 SQL 的 localtime 口径一致)。 */
|
|
66
55
|
function localDayKey(ms) {
|
|
67
56
|
const date = new Date(ms);
|
|
68
57
|
const pad = (value) => String(value).padStart(2, "0");
|
|
@@ -96,16 +85,11 @@ function addActivityTotals(target, row) {
|
|
|
96
85
|
target.toolCalls += row.toolCalls;
|
|
97
86
|
return target;
|
|
98
87
|
}
|
|
99
|
-
/** 把一行的整套指标累加进目标(后端合并「是否子代理」两组时用)。 */
|
|
100
88
|
function addTotals(target, row) {
|
|
101
89
|
addActivityTotals(target, row);
|
|
102
90
|
addTokenTotals(target, row);
|
|
103
91
|
return target;
|
|
104
92
|
}
|
|
105
|
-
/**
|
|
106
|
-
* 用量统计通道:一次请求回报总览(含 subagent 拆分)、按天 × 模型的桶与按会话的行。
|
|
107
|
-
* 聚合只算被会话引用的事件行——fork 共享行因此只计一次,已删会话留下的孤儿行不计。
|
|
108
|
-
*/
|
|
109
93
|
function registerSessionUsage(ctx, persistence) {
|
|
110
94
|
ctx.inject(["webServer", "connection"], (webCtx) => {
|
|
111
95
|
const webServer = webCtx.webServer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morlay/session-rdb",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"./locale/*.json": "./locale/*.json"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@morlay/session-branch": "0.1.
|
|
42
|
+
"@morlay/session-branch": "0.1.3",
|
|
43
43
|
"drizzle-orm": "^1.0.0-rc.5-ab785fc",
|
|
44
44
|
"fflate": "^0.8.2",
|
|
45
45
|
"pg": "^8.23.0"
|