@morlay/session-rdb 0.0.21-alpha.7 → 0.0.21-alpha.9
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 +31 -12
- package/dist/artifact.d.mts +2 -101
- package/dist/artifact.mjs +2 -2
- package/dist/{branch-BjUR6wfe.mjs → branch-D4nVzQQM.mjs} +3 -3
- package/dist/deletion.d.mts +1 -1
- package/dist/deletion.mjs +1 -1
- package/dist/{dist-vIVO6bA-.mjs → dist-DHer1cql.mjs} +14 -7
- package/dist/export.d.mts +8 -0
- package/dist/export.mjs +76 -0
- package/dist/gc.d.mts +8 -0
- package/dist/gc.mjs +51 -0
- package/dist/import.d.mts +1 -1
- package/dist/import.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +3 -3
- package/dist/{log-qCNkDjh5.mjs → log-BWVFYAh5.mjs} +39 -12
- package/dist/{backend-E0bmTXpz.d.mts → log-CUjKQbOR.d.mts} +222 -39
- package/dist/{sqlite-zcXVyMxr.mjs → sqlite-SCiSnwaz.mjs} +321 -259
- package/dist/{src-B9X8BKyh.mjs → src-BZ1tffd5.mjs} +342 -310
- package/dist/storage.d.mts +20 -7
- package/dist/storage.mjs +2 -2
- package/dist/testing.d.mts +1 -1
- package/dist/testing.mjs +48 -29
- package/dist/usage.d.mts +2 -0
- package/dist/usage.mjs +152 -0
- package/drizzle/postgres/20260923120000_v3_usage_materialized/migration.sql +48 -0
- package/drizzle/sqlite/20260923120000_v3_usage_materialized/migration.sql +48 -0
- package/package.json +25 -30
- package/src/backend.ts +41 -17
- package/src/branch.ts +4 -4
- package/src/drizzle/postgres-v3.ts +2 -0
- package/src/drizzle/sqlite-v3.ts +2 -0
- package/src/entities/v3/event-usage.ts +8 -1
- package/src/entities/v3/index.ts +8 -0
- package/src/entities/v3/session-counts.ts +23 -0
- package/src/entities/v3/session-usage.ts +29 -0
- package/src/index.ts +230 -88
- package/src/log.ts +58 -17
- package/src/postgres.ts +248 -149
- package/src/rows.ts +2 -1
- package/src/schema.ts +4 -0
- package/src/sqlite.ts +263 -124
- package/src/storage-takeover/repository.ts +1 -4
- package/src/usage.ts +10 -6
- package/cordis.patch.yml +0 -13
package/src/backend.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { SessionId } from "@deepseek-ai/dsh-session";
|
|
2
2
|
import type { SessionStorageMetadata } from "@deepseek-ai/dsh-session-persistence";
|
|
3
|
+
import type { EventUsageRow } from "./log.ts";
|
|
3
4
|
import type { StorageRepository } from "./storage-takeover/types.ts";
|
|
4
|
-
import type { UsageAggregate } from "./usage.ts";
|
|
5
|
+
import type { UsageActivityTotals, UsageAggregate, UsageTokenTotals } from "./usage.ts";
|
|
5
6
|
|
|
6
7
|
export interface SessionRow {
|
|
7
8
|
fSessionId: string;
|
|
@@ -74,7 +75,11 @@ export interface BackendTx {
|
|
|
74
75
|
|
|
75
76
|
refreshTitle(id: SessionId): Promise<void>;
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
/**
|
|
79
|
+
* 插入事件行与它们的用量行(`usageRows` 由写路径一次折好,读侧维度已物化在行上)。
|
|
80
|
+
* 这一批事件与桥接行同事务,提交即「被引用」。
|
|
81
|
+
*/
|
|
82
|
+
insertEvents(events: EventInsert[], usageRows: readonly EventUsageRow[]): Promise<void>;
|
|
78
83
|
|
|
79
84
|
insertBridges(
|
|
80
85
|
rows: Array<{
|
|
@@ -139,11 +144,16 @@ export interface SessionListRowsPage {
|
|
|
139
144
|
total: number;
|
|
140
145
|
}
|
|
141
146
|
|
|
142
|
-
/** 活动计数的一个桶:本地日 +
|
|
143
|
-
export interface
|
|
147
|
+
/** 活动计数的一个桶:本地日 + 四项计数(轮次 / 步骤 / 用户输入 / 工具调用)。 */
|
|
148
|
+
export interface SessionCountBucket extends UsageActivityTotals {
|
|
149
|
+
day: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** 用量累加的一个桶:本地日 + 模型归属 + 五个 token 列。 */
|
|
153
|
+
export interface SessionUsageBucket extends UsageTokenTotals {
|
|
144
154
|
day: string;
|
|
145
|
-
|
|
146
|
-
|
|
155
|
+
provider: string | null;
|
|
156
|
+
model: string | null;
|
|
147
157
|
}
|
|
148
158
|
|
|
149
159
|
export interface Backend {
|
|
@@ -178,9 +188,10 @@ export interface Backend {
|
|
|
178
188
|
listOrphanSubagentSessions(): Promise<SessionId[]>;
|
|
179
189
|
|
|
180
190
|
/**
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
* @param sinceMs -
|
|
191
|
+
* 用量统计的原始聚合:读三张派生统计表(`t_event_usage` + 两张会话汇总表),
|
|
192
|
+
* 给出总量 / subagent 拆分、按天×模型的桶与按会话的行(事件行去重、排除孤儿)。
|
|
193
|
+
* @param sinceMs - 只算该时刻(含)之后的用量;省略即全量。会话汇总表按本地日过滤,
|
|
194
|
+
* 与毫秒过滤等价的前提是调用方把起点对齐到本地零点(见 `resolveUsageSince`)。
|
|
184
195
|
*/
|
|
185
196
|
usageReport(sinceMs?: number): Promise<UsageAggregate>;
|
|
186
197
|
|
|
@@ -188,21 +199,34 @@ export interface Backend {
|
|
|
188
199
|
listSessionRows(query?: SessionListRowsQuery): Promise<SessionListRowsPage>;
|
|
189
200
|
|
|
190
201
|
/**
|
|
191
|
-
*
|
|
192
|
-
* 每个 (会话, 本地日,
|
|
202
|
+
* token 用量**旁路累加**(派生表 `t_session_usage`,不参与写事务、失败可丢——表可销毁重建):
|
|
203
|
+
* 每个 (会话, 本地日, 模型) 记一行累加。
|
|
204
|
+
* @param id - 会话 id。
|
|
205
|
+
* @param buckets - 本批要累加的 (day, provider, model, tokens)。
|
|
206
|
+
*/
|
|
207
|
+
incrementSessionUsage(id: SessionId, buckets: readonly SessionUsageBucket[]): Promise<void>;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* 活动计数**旁路累加**(派生表 `t_session_counts`,同上):每个 (会话, 本地日) 累加四项计数。
|
|
193
211
|
* @param id - 会话 id。
|
|
194
|
-
* @param buckets - 本批要累加的 (day,
|
|
212
|
+
* @param buckets - 本批要累加的 (day, turns, steps, userInputs, toolCalls)。
|
|
195
213
|
*/
|
|
196
|
-
|
|
214
|
+
incrementSessionCounts(id: SessionId, buckets: readonly SessionCountBucket[]): Promise<void>;
|
|
197
215
|
|
|
198
216
|
/**
|
|
199
|
-
*
|
|
217
|
+
* 按会话从事件表重算两张会话汇总表(rewind / fork 之后调用):先删该会话的行再重算。
|
|
200
218
|
* @param id - 会话 id。
|
|
201
219
|
*/
|
|
202
|
-
|
|
220
|
+
rebuildSessionStats(id: SessionId): Promise<void>;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* 全量重算 `t_event_usage` 的引用标记(`f_referenced` / `f_subagent`):rewind / fork / 会话删除之后调用。
|
|
224
|
+
* 引用可能跨会话消失(截断、删除),只按本会话判定不够,故这里是全量。
|
|
225
|
+
*/
|
|
226
|
+
refreshEventUsageFlags(): Promise<void>;
|
|
203
227
|
|
|
204
|
-
/**
|
|
205
|
-
|
|
228
|
+
/** 删掉一个会话的汇总行(会话删除时;外键 CASCADE 之外再显式清一次)。 */
|
|
229
|
+
deleteSessionStats(id: SessionId): Promise<void>;
|
|
206
230
|
|
|
207
231
|
/** 回收空间与统计(含 VACUUM);不得在事务内执行。 */
|
|
208
232
|
vacuum(): Promise<void>;
|
package/src/branch.ts
CHANGED
|
@@ -311,8 +311,8 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
|
|
|
311
311
|
internals.dropReuseEventIds(childId);
|
|
312
312
|
throw error;
|
|
313
313
|
}
|
|
314
|
-
//
|
|
315
|
-
await this.persistence.
|
|
314
|
+
// 子会话继承了前缀事件:统计按子会话重算(派生表,best-effort)。
|
|
315
|
+
await this.persistence.rebuildSessionStats(childId);
|
|
316
316
|
return childId;
|
|
317
317
|
}
|
|
318
318
|
|
|
@@ -443,8 +443,8 @@ export class SessionBranchRdbProvider implements SessionBranchProvider {
|
|
|
443
443
|
});
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
//
|
|
447
|
-
await this.persistence.
|
|
446
|
+
// 截断后该会话的事件集合变了:统计跟着重算(派生表,best-effort)。
|
|
447
|
+
await this.persistence.rebuildSessionStats(id);
|
|
448
448
|
|
|
449
449
|
return { header: rowToMeta(row), revision: (await internals.readStoredRevision(id))! };
|
|
450
450
|
}
|
|
@@ -14,3 +14,5 @@ export const tWorkspaceSessions = tables["t_workspace_sessions"]!;
|
|
|
14
14
|
export const tWorkspaceState = tables["t_workspace_state"]!;
|
|
15
15
|
export const tSessionProjcacheRows = tables["t_session_projcache_row"]!;
|
|
16
16
|
export const tEventUsage = tables["t_event_usage"]!;
|
|
17
|
+
export const tSessionUsage = tables["t_session_usage"]!;
|
|
18
|
+
export const tSessionCounts = tables["t_session_counts"]!;
|
package/src/drizzle/sqlite-v3.ts
CHANGED
|
@@ -14,3 +14,5 @@ export const tWorkspaceSessions = tables["t_workspace_sessions"]!;
|
|
|
14
14
|
export const tWorkspaceState = tables["t_workspace_state"]!;
|
|
15
15
|
export const tSessionProjcacheRows = tables["t_session_projcache_row"]!;
|
|
16
16
|
export const tEventUsage = tables["t_event_usage"]!;
|
|
17
|
+
export const tSessionUsage = tables["t_session_usage"]!;
|
|
18
|
+
export const tSessionCounts = tables["t_session_counts"]!;
|
|
@@ -2,7 +2,9 @@ import type { TableDef } from "../../adapters/types.ts";
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 用量日志:一条 `assistant/message` 事件一行(按事件行唯一,fork 共享行不重复)。
|
|
5
|
-
*
|
|
5
|
+
* 读侧维度全部物化在行上——本地日、是否被会话引用、是否被子代理会话引用——统计因此不做
|
|
6
|
+
* `EXISTS` 判定、也不回连事件表;事件行本身仍留在 `t_events`。
|
|
7
|
+
* 取舍见 ADR-统计衍生表物化归属与汇总。
|
|
6
8
|
*/
|
|
7
9
|
export const eventUsage: TableDef = {
|
|
8
10
|
name: "t_event_usage",
|
|
@@ -14,8 +16,13 @@ export const eventUsage: TableDef = {
|
|
|
14
16
|
},
|
|
15
17
|
// 毫秒时间戳:SQLite 的 integer 是 64 位,PG 的 integer 只有 int4(21 亿上限)——必须是 bigint。
|
|
16
18
|
f_created_at: { type: "bigint", notNull: true },
|
|
19
|
+
// host 本地日 `YYYY-MM-DD`(与统计桶的 localtime 口径一致)。
|
|
20
|
+
f_day: { type: "text", notNull: true },
|
|
17
21
|
f_provider: { type: "text" },
|
|
18
22
|
f_model: { type: "text" },
|
|
23
|
+
// 被任何会话桥接行引用(孤儿 0,不计入统计)/ 被任何 subagent 会话引用(拆「人类 / 子代理」)。
|
|
24
|
+
f_referenced: { type: "integer", notNull: true, default: 0 },
|
|
25
|
+
f_subagent: { type: "integer", notNull: true, default: 0 },
|
|
19
26
|
f_input_tokens: { type: "integer", notNull: true, default: 0 },
|
|
20
27
|
f_output_tokens: { type: "integer", notNull: true, default: 0 },
|
|
21
28
|
f_cache_read_tokens: { type: "integer", notNull: true, default: 0 },
|
package/src/entities/v3/index.ts
CHANGED
|
@@ -9,6 +9,8 @@ import { workspaceSessions } from "./workspace-sessions.ts";
|
|
|
9
9
|
import { workspaceState } from "./workspace-state.ts";
|
|
10
10
|
import { sessionProjcacheRows } from "./session-projcache-rows.ts";
|
|
11
11
|
import { eventUsage } from "./event-usage.ts";
|
|
12
|
+
import { sessionUsage } from "./session-usage.ts";
|
|
13
|
+
import { sessionCounts } from "./session-counts.ts";
|
|
12
14
|
|
|
13
15
|
export { persistenceState };
|
|
14
16
|
export { schemaMeta };
|
|
@@ -21,6 +23,8 @@ export { workspaceSessions };
|
|
|
21
23
|
export { workspaceState };
|
|
22
24
|
export { sessionProjcacheRows };
|
|
23
25
|
export { eventUsage };
|
|
26
|
+
export { sessionUsage };
|
|
27
|
+
export { sessionCounts };
|
|
24
28
|
|
|
25
29
|
export const sqliteTableDefs = [
|
|
26
30
|
persistenceState,
|
|
@@ -34,6 +38,8 @@ export const sqliteTableDefs = [
|
|
|
34
38
|
workspaceState,
|
|
35
39
|
sessionProjcacheRows,
|
|
36
40
|
eventUsage,
|
|
41
|
+
sessionUsage,
|
|
42
|
+
sessionCounts,
|
|
37
43
|
] as const;
|
|
38
44
|
|
|
39
45
|
export const postgresTableDefs = [
|
|
@@ -48,4 +54,6 @@ export const postgresTableDefs = [
|
|
|
48
54
|
workspaceState,
|
|
49
55
|
sessionProjcacheRows,
|
|
50
56
|
eventUsage,
|
|
57
|
+
sessionUsage,
|
|
58
|
+
sessionCounts,
|
|
51
59
|
] as const;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TableDef } from "../../adapters/types.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 会话 × 本地日的活动计数(派生统计表):轮次 / 步骤 / 用户输入 / 工具调用四列直接读,
|
|
5
|
+
* 不再存事件类型、也不在读取时折。旁路累加、可按会话重建,读侧只读;
|
|
6
|
+
* 取舍见 ADR-统计衍生表物化归属与汇总。
|
|
7
|
+
*/
|
|
8
|
+
export const sessionCounts: TableDef = {
|
|
9
|
+
name: "t_session_counts",
|
|
10
|
+
columns: {
|
|
11
|
+
f_session_id: {
|
|
12
|
+
type: "text",
|
|
13
|
+
notNull: true,
|
|
14
|
+
references: { table: "t_sessions", column: "f_session_id", onDelete: "cascade" },
|
|
15
|
+
},
|
|
16
|
+
f_day: { type: "text", notNull: true },
|
|
17
|
+
f_turns: { type: "integer", notNull: true, default: 0 },
|
|
18
|
+
f_steps: { type: "integer", notNull: true, default: 0 },
|
|
19
|
+
f_user_inputs: { type: "integer", notNull: true, default: 0 },
|
|
20
|
+
f_tool_calls: { type: "integer", notNull: true, default: 0 },
|
|
21
|
+
},
|
|
22
|
+
uniques: { uq_session_counts_key: { columns: ["f_session_id", "f_day"] } },
|
|
23
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TableDef } from "../../adapters/types.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 会话 × 本地日 × 模型的 token 汇总(派生统计表):**按会话的行**读它,因此保住
|
|
5
|
+
* 「fork 子会话含继承前缀」的口径(各会话行之和 ≥ 总量)而不回连事件表。
|
|
6
|
+
* 旁路累加、可按会话重建,读侧只读;取舍见 ADR-统计衍生表物化归属与汇总。
|
|
7
|
+
*/
|
|
8
|
+
export const sessionUsage: TableDef = {
|
|
9
|
+
name: "t_session_usage",
|
|
10
|
+
columns: {
|
|
11
|
+
f_session_id: {
|
|
12
|
+
type: "text",
|
|
13
|
+
notNull: true,
|
|
14
|
+
references: { table: "t_sessions", column: "f_session_id", onDelete: "cascade" },
|
|
15
|
+
},
|
|
16
|
+
f_day: { type: "text", notNull: true },
|
|
17
|
+
// 模型未知时落空串(不是 NULL):唯一键里的 NULL 在 SQLite 下互不冲突,空串才保证一行。
|
|
18
|
+
f_provider: { type: "text", notNull: true, default: "" },
|
|
19
|
+
f_model: { type: "text", notNull: true, default: "" },
|
|
20
|
+
f_input_tokens: { type: "integer", notNull: true, default: 0 },
|
|
21
|
+
f_output_tokens: { type: "integer", notNull: true, default: 0 },
|
|
22
|
+
f_cache_read_tokens: { type: "integer", notNull: true, default: 0 },
|
|
23
|
+
f_reasoning_tokens: { type: "integer", notNull: true, default: 0 },
|
|
24
|
+
f_total_tokens: { type: "integer", notNull: true, default: 0 },
|
|
25
|
+
},
|
|
26
|
+
uniques: {
|
|
27
|
+
uq_session_usage_key: { columns: ["f_session_id", "f_day", "f_provider", "f_model"] },
|
|
28
|
+
},
|
|
29
|
+
};
|