@dudousxd/nestjs-agent-store-drizzle 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +219 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +228 -9
- package/dist/index.d.ts +228 -9
- package/dist/index.js +219 -27
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -94,7 +94,9 @@ var agentThread = (0, import_sqlite_core.sqliteTable)("agent_thread", {
|
|
|
94
94
|
mode: "timestamp_ms"
|
|
95
95
|
})
|
|
96
96
|
}, (table) => [
|
|
97
|
-
(0, import_sqlite_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
|
|
97
|
+
(0, import_sqlite_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
|
|
98
|
+
// `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
|
|
99
|
+
(0, import_sqlite_core.index)("agent_thread_active_stream_idx").on(table.activeStreamId)
|
|
98
100
|
]);
|
|
99
101
|
var agentMessage = (0, import_sqlite_core.sqliteTable)("agent_message", {
|
|
100
102
|
id: (0, import_sqlite_core.text)("id").primaryKey(),
|
|
@@ -144,7 +146,9 @@ var agentMessage = (0, import_sqlite_core.sqliteTable)("agent_message", {
|
|
|
144
146
|
mode: "timestamp_ms"
|
|
145
147
|
}).notNull()
|
|
146
148
|
}, (table) => [
|
|
147
|
-
(0, import_sqlite_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
|
|
149
|
+
(0, import_sqlite_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
|
|
150
|
+
// Transcript reads order a thread's messages by `seq`.
|
|
151
|
+
(0, import_sqlite_core.index)("agent_message_thread_seq_idx").on(table.threadId, table.seq)
|
|
148
152
|
]);
|
|
149
153
|
var agentToolCall = (0, import_sqlite_core.sqliteTable)("agent_tool_call", {
|
|
150
154
|
proposalId: (0, import_sqlite_core.text)("proposal_id"),
|
|
@@ -189,7 +193,11 @@ var agentToolCall = (0, import_sqlite_core.sqliteTable)("agent_tool_call", {
|
|
|
189
193
|
/** The surface the decision came through (`web`, `slack`, `remembered`, …). */
|
|
190
194
|
decidedVia: (0, import_sqlite_core.text)("decided_via")
|
|
191
195
|
}, (table) => [
|
|
192
|
-
(0, import_sqlite_core.index)("agent_tool_call_message_idx").on(table.messageId)
|
|
196
|
+
(0, import_sqlite_core.index)("agent_tool_call_message_idx").on(table.messageId),
|
|
197
|
+
// The approvals inbox: `pending_approval`, oldest first.
|
|
198
|
+
(0, import_sqlite_core.index)("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
|
|
199
|
+
(0, import_sqlite_core.index)("agent_tool_call_run_idx").on(table.runId),
|
|
200
|
+
(0, import_sqlite_core.index)("agent_tool_call_created_idx").on(table.createdAt)
|
|
193
201
|
]);
|
|
194
202
|
var agentQueuedMessage = (0, import_sqlite_core.sqliteTable)("agent_queued_message", {
|
|
195
203
|
uiCapabilities: (0, import_sqlite_core.text)("ui_capabilities", {
|
|
@@ -253,7 +261,9 @@ var agentTokenUsage = (0, import_sqlite_core.sqliteTable)("agent_token_usage", {
|
|
|
253
261
|
mode: "timestamp_ms"
|
|
254
262
|
}).notNull()
|
|
255
263
|
}, (table) => [
|
|
256
|
-
(0, import_sqlite_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
|
|
264
|
+
(0, import_sqlite_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
265
|
+
(0, import_sqlite_core.index)("agent_token_usage_created_idx").on(table.createdAt),
|
|
266
|
+
(0, import_sqlite_core.index)("agent_token_usage_thread_idx").on(table.threadId)
|
|
257
267
|
]);
|
|
258
268
|
var agentGenuiCall = (0, import_sqlite_core.sqliteTable)("agent_genui_call", {
|
|
259
269
|
id: (0, import_sqlite_core.text)("id").primaryKey(),
|
|
@@ -311,6 +321,12 @@ var agentRun = (0, import_sqlite_core.sqliteTable)("agent_run", {
|
|
|
311
321
|
agentName: (0, import_sqlite_core.text)("agent_name"),
|
|
312
322
|
status: (0, import_sqlite_core.text)("status").$type().notNull(),
|
|
313
323
|
durationMs: (0, import_sqlite_core.integer)("duration_ms"),
|
|
324
|
+
/** Turn start to the first `text` frame; null for a run that streamed none or did not complete. */
|
|
325
|
+
ttftMs: (0, import_sqlite_core.integer)("ttft_ms"),
|
|
326
|
+
/** The run's known spend (the sum of its model calls with a known cost); null when none had one. */
|
|
327
|
+
costUsd: (0, import_sqlite_core.real)("cost_usd"),
|
|
328
|
+
/** The model the run's last model call resolved to. */
|
|
329
|
+
modelId: (0, import_sqlite_core.text)("model_id"),
|
|
314
330
|
errorCode: (0, import_sqlite_core.text)("error_code"),
|
|
315
331
|
errorMessage: (0, import_sqlite_core.text)("error_message"),
|
|
316
332
|
retries: (0, import_sqlite_core.integer)("retries").notNull().default(0),
|
|
@@ -590,7 +606,9 @@ var agentThread2 = (0, import_mysql_core.mysqlTable)("agent_thread", {
|
|
|
590
606
|
updatedAt: ts("updated_at").notNull(),
|
|
591
607
|
deletedAt: ts("deleted_at")
|
|
592
608
|
}, (table) => [
|
|
593
|
-
(0, import_mysql_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
|
|
609
|
+
(0, import_mysql_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
|
|
610
|
+
// `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
|
|
611
|
+
(0, import_mysql_core.index)("agent_thread_active_stream_idx").on(table.activeStreamId)
|
|
594
612
|
]);
|
|
595
613
|
var agentMessage2 = (0, import_mysql_core.mysqlTable)("agent_message", {
|
|
596
614
|
id: key("id").primaryKey(),
|
|
@@ -616,7 +634,9 @@ var agentMessage2 = (0, import_mysql_core.mysqlTable)("agent_message", {
|
|
|
616
634
|
seq: (0, import_mysql_core.int)("seq"),
|
|
617
635
|
createdAt: ts("created_at").notNull()
|
|
618
636
|
}, (table) => [
|
|
619
|
-
(0, import_mysql_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
|
|
637
|
+
(0, import_mysql_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
|
|
638
|
+
// Transcript reads order a thread's messages by `seq`.
|
|
639
|
+
(0, import_mysql_core.index)("agent_message_thread_seq_idx").on(table.threadId, table.seq)
|
|
620
640
|
]);
|
|
621
641
|
var agentToolCall2 = (0, import_mysql_core.mysqlTable)("agent_tool_call", {
|
|
622
642
|
proposalId: key("proposal_id"),
|
|
@@ -641,7 +661,11 @@ var agentToolCall2 = (0, import_mysql_core.mysqlTable)("agent_tool_call", {
|
|
|
641
661
|
remember: (0, import_mysql_core.boolean)("remember"),
|
|
642
662
|
decidedVia: key("decided_via")
|
|
643
663
|
}, (table) => [
|
|
644
|
-
(0, import_mysql_core.index)("agent_tool_call_message_idx").on(table.messageId)
|
|
664
|
+
(0, import_mysql_core.index)("agent_tool_call_message_idx").on(table.messageId),
|
|
665
|
+
// The approvals inbox: `pending_approval`, oldest first.
|
|
666
|
+
(0, import_mysql_core.index)("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
|
|
667
|
+
(0, import_mysql_core.index)("agent_tool_call_run_idx").on(table.runId),
|
|
668
|
+
(0, import_mysql_core.index)("agent_tool_call_created_idx").on(table.createdAt)
|
|
645
669
|
]);
|
|
646
670
|
var agentQueuedMessage2 = (0, import_mysql_core.mysqlTable)("agent_queued_message", {
|
|
647
671
|
uiCapabilities: (0, import_mysql_core.json)("ui_capabilities").$type(),
|
|
@@ -683,7 +707,9 @@ var agentTokenUsage2 = (0, import_mysql_core.mysqlTable)("agent_token_usage", {
|
|
|
683
707
|
costSource: key("cost_source").$type(),
|
|
684
708
|
createdAt: ts("created_at").notNull()
|
|
685
709
|
}, (table) => [
|
|
686
|
-
(0, import_mysql_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
|
|
710
|
+
(0, import_mysql_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
711
|
+
(0, import_mysql_core.index)("agent_token_usage_created_idx").on(table.createdAt),
|
|
712
|
+
(0, import_mysql_core.index)("agent_token_usage_thread_idx").on(table.threadId)
|
|
687
713
|
]);
|
|
688
714
|
var agentGenuiCall2 = (0, import_mysql_core.mysqlTable)("agent_genui_call", {
|
|
689
715
|
id: key("id").primaryKey(),
|
|
@@ -743,6 +769,12 @@ var agentRun2 = (0, import_mysql_core.mysqlTable)("agent_run", {
|
|
|
743
769
|
agentName: key("agent_name"),
|
|
744
770
|
status: key("status").$type().notNull(),
|
|
745
771
|
durationMs: (0, import_mysql_core.int)("duration_ms"),
|
|
772
|
+
/** Turn start to the first `text` frame; null for a run that streamed none or did not complete. */
|
|
773
|
+
ttftMs: (0, import_mysql_core.int)("ttft_ms"),
|
|
774
|
+
/** The run's known spend (the sum of its model calls with a known cost); null when none had one. */
|
|
775
|
+
costUsd: (0, import_mysql_core.double)("cost_usd"),
|
|
776
|
+
/** The model the run's last model call resolved to. */
|
|
777
|
+
modelId: key("model_id"),
|
|
746
778
|
errorCode: key("error_code"),
|
|
747
779
|
errorMessage: (0, import_mysql_core.longtext)("error_message"),
|
|
748
780
|
retries: (0, import_mysql_core.int)("retries").notNull().default(0),
|
|
@@ -1036,7 +1068,9 @@ var agentThread3 = (0, import_pg_core.pgTable)("agent_thread", {
|
|
|
1036
1068
|
updatedAt: ts2("updated_at").notNull(),
|
|
1037
1069
|
deletedAt: ts2("deleted_at")
|
|
1038
1070
|
}, (table) => [
|
|
1039
|
-
(0, import_pg_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
|
|
1071
|
+
(0, import_pg_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
|
|
1072
|
+
// `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
|
|
1073
|
+
(0, import_pg_core.index)("agent_thread_active_stream_idx").on(table.activeStreamId)
|
|
1040
1074
|
]);
|
|
1041
1075
|
var agentMessage3 = (0, import_pg_core.pgTable)("agent_message", {
|
|
1042
1076
|
id: (0, import_pg_core.text)("id").primaryKey(),
|
|
@@ -1062,7 +1096,9 @@ var agentMessage3 = (0, import_pg_core.pgTable)("agent_message", {
|
|
|
1062
1096
|
seq: (0, import_pg_core.integer)("seq"),
|
|
1063
1097
|
createdAt: ts2("created_at").notNull()
|
|
1064
1098
|
}, (table) => [
|
|
1065
|
-
(0, import_pg_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
|
|
1099
|
+
(0, import_pg_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
|
|
1100
|
+
// Transcript reads order a thread's messages by `seq`.
|
|
1101
|
+
(0, import_pg_core.index)("agent_message_thread_seq_idx").on(table.threadId, table.seq)
|
|
1066
1102
|
]);
|
|
1067
1103
|
var agentToolCall3 = (0, import_pg_core.pgTable)("agent_tool_call", {
|
|
1068
1104
|
proposalId: (0, import_pg_core.text)("proposal_id"),
|
|
@@ -1087,7 +1123,11 @@ var agentToolCall3 = (0, import_pg_core.pgTable)("agent_tool_call", {
|
|
|
1087
1123
|
remember: (0, import_pg_core.boolean)("remember"),
|
|
1088
1124
|
decidedVia: (0, import_pg_core.text)("decided_via")
|
|
1089
1125
|
}, (table) => [
|
|
1090
|
-
(0, import_pg_core.index)("agent_tool_call_message_idx").on(table.messageId)
|
|
1126
|
+
(0, import_pg_core.index)("agent_tool_call_message_idx").on(table.messageId),
|
|
1127
|
+
// The approvals inbox: `pending_approval`, oldest first.
|
|
1128
|
+
(0, import_pg_core.index)("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
|
|
1129
|
+
(0, import_pg_core.index)("agent_tool_call_run_idx").on(table.runId),
|
|
1130
|
+
(0, import_pg_core.index)("agent_tool_call_created_idx").on(table.createdAt)
|
|
1091
1131
|
]);
|
|
1092
1132
|
var agentQueuedMessage3 = (0, import_pg_core.pgTable)("agent_queued_message", {
|
|
1093
1133
|
uiCapabilities: (0, import_pg_core.jsonb)("ui_capabilities").$type(),
|
|
@@ -1129,7 +1169,9 @@ var agentTokenUsage3 = (0, import_pg_core.pgTable)("agent_token_usage", {
|
|
|
1129
1169
|
costSource: (0, import_pg_core.text)("cost_source").$type(),
|
|
1130
1170
|
createdAt: ts2("created_at").notNull()
|
|
1131
1171
|
}, (table) => [
|
|
1132
|
-
(0, import_pg_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
|
|
1172
|
+
(0, import_pg_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
1173
|
+
(0, import_pg_core.index)("agent_token_usage_created_idx").on(table.createdAt),
|
|
1174
|
+
(0, import_pg_core.index)("agent_token_usage_thread_idx").on(table.threadId)
|
|
1133
1175
|
]);
|
|
1134
1176
|
var agentGenuiCall3 = (0, import_pg_core.pgTable)("agent_genui_call", {
|
|
1135
1177
|
id: (0, import_pg_core.text)("id").primaryKey(),
|
|
@@ -1189,6 +1231,12 @@ var agentRun3 = (0, import_pg_core.pgTable)("agent_run", {
|
|
|
1189
1231
|
agentName: (0, import_pg_core.text)("agent_name"),
|
|
1190
1232
|
status: (0, import_pg_core.text)("status").$type().notNull(),
|
|
1191
1233
|
durationMs: (0, import_pg_core.integer)("duration_ms"),
|
|
1234
|
+
/** Turn start to the first `text` frame; null for a run that streamed none or did not complete. */
|
|
1235
|
+
ttftMs: (0, import_pg_core.integer)("ttft_ms"),
|
|
1236
|
+
/** The run's known spend (the sum of its model calls with a known cost); null when none had one. */
|
|
1237
|
+
costUsd: (0, import_pg_core.doublePrecision)("cost_usd"),
|
|
1238
|
+
/** The model the run's last model call resolved to. */
|
|
1239
|
+
modelId: (0, import_pg_core.text)("model_id"),
|
|
1192
1240
|
errorCode: (0, import_pg_core.text)("error_code"),
|
|
1193
1241
|
errorMessage: (0, import_pg_core.text)("error_message"),
|
|
1194
1242
|
retries: (0, import_pg_core.integer)("retries").notNull().default(0),
|
|
@@ -2402,12 +2450,49 @@ var DrizzleAgentStore = class {
|
|
|
2402
2450
|
}
|
|
2403
2451
|
async listThreads(actorRef, limit = 50) {
|
|
2404
2452
|
const threads = await this.db.select().from(this.t.agentThread).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(this.t.agentThread.actorRef, actorRef), (0, import_drizzle_orm4.eq)(this.t.agentThread.transient, false), (0, import_drizzle_orm4.isNull)(this.t.agentThread.deletedAt))).orderBy((0, import_drizzle_orm4.desc)(this.t.agentThread.updatedAt)).limit(limit);
|
|
2405
|
-
const
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2453
|
+
const previews = await this.lastMessageContents(threads.map((thread) => thread.id));
|
|
2454
|
+
return threads.map((thread) => this.toSummary(thread, previews.get(thread.id)));
|
|
2455
|
+
}
|
|
2456
|
+
/**
|
|
2457
|
+
* The content of each thread's newest message ({@link messageOrderNewestFirst}), in a fixed two
|
|
2458
|
+
* reads for any number of threads: each thread's highest `seq`, then the rows holding it. Only a
|
|
2459
|
+
* thread whose every message predates `seq` is read on its own, by `created_at`.
|
|
2460
|
+
*/
|
|
2461
|
+
async lastMessageContents(threadIds) {
|
|
2462
|
+
const contents = /* @__PURE__ */ new Map();
|
|
2463
|
+
if (threadIds.length === 0) {
|
|
2464
|
+
return contents;
|
|
2465
|
+
}
|
|
2466
|
+
const message = this.t.agentMessage;
|
|
2467
|
+
const highest = await this.db.select({
|
|
2468
|
+
threadId: message.threadId,
|
|
2469
|
+
seq: (0, import_drizzle_orm4.max)(message.seq)
|
|
2470
|
+
}).from(message).where((0, import_drizzle_orm4.inArray)(message.threadId, [
|
|
2471
|
+
...threadIds
|
|
2472
|
+
])).groupBy(message.threadId);
|
|
2473
|
+
const numbered = highest.filter((row) => row.seq !== null);
|
|
2474
|
+
if (numbered.length > 0) {
|
|
2475
|
+
const rows = await this.db.select({
|
|
2476
|
+
threadId: message.threadId,
|
|
2477
|
+
content: message.content
|
|
2478
|
+
}).from(message).where((0, import_drizzle_orm4.or)(...numbered.map((row) => (0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(message.threadId, row.threadId), (0, import_drizzle_orm4.eq)(message.seq, Number(row.seq)))))).orderBy(...this.messageOrderNewestFirst());
|
|
2479
|
+
for (const row of rows) {
|
|
2480
|
+
if (!contents.has(row.threadId)) {
|
|
2481
|
+
contents.set(row.threadId, row.content);
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2409
2484
|
}
|
|
2410
|
-
|
|
2485
|
+
for (const row of highest) {
|
|
2486
|
+
if (row.seq === null) {
|
|
2487
|
+
const [last] = await this.db.select({
|
|
2488
|
+
content: message.content
|
|
2489
|
+
}).from(message).where((0, import_drizzle_orm4.eq)(message.threadId, row.threadId)).orderBy(...this.messageOrderNewestFirst()).limit(1);
|
|
2490
|
+
if (last !== void 0) {
|
|
2491
|
+
contents.set(row.threadId, last.content);
|
|
2492
|
+
}
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
return contents;
|
|
2411
2496
|
}
|
|
2412
2497
|
async softDeleteThread(threadId) {
|
|
2413
2498
|
await this.db.update(this.t.agentThread).set({
|
|
@@ -2784,6 +2869,24 @@ var DrizzleAgentStore = class {
|
|
|
2784
2869
|
}).from(agentThread).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(this.t.agentThread.id, threadId), (0, import_drizzle_orm4.isNull)(this.t.agentThread.deletedAt)));
|
|
2785
2870
|
return thread?.persona ?? null;
|
|
2786
2871
|
}
|
|
2872
|
+
async threadSettings(threadId) {
|
|
2873
|
+
const thread = this.t.agentThread;
|
|
2874
|
+
const [row] = await this.db.select({
|
|
2875
|
+
actorRef: thread.actorRef,
|
|
2876
|
+
defaultAgent: thread.defaultAgent,
|
|
2877
|
+
persona: thread.persona,
|
|
2878
|
+
model: thread.model
|
|
2879
|
+
}).from(thread).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(thread.id, threadId), (0, import_drizzle_orm4.isNull)(thread.deletedAt)));
|
|
2880
|
+
if (row === void 0) {
|
|
2881
|
+
return null;
|
|
2882
|
+
}
|
|
2883
|
+
return {
|
|
2884
|
+
actorRef: row.actorRef,
|
|
2885
|
+
defaultAgent: row.defaultAgent ?? null,
|
|
2886
|
+
persona: row.persona ?? null,
|
|
2887
|
+
model: row.model ?? null
|
|
2888
|
+
};
|
|
2889
|
+
}
|
|
2787
2890
|
async defaultAgentForThread(threadId) {
|
|
2788
2891
|
const [thread] = await this.db.select({
|
|
2789
2892
|
defaultAgent: this.t.agentThread.defaultAgent
|
|
@@ -2804,6 +2907,9 @@ var DrizzleAgentStore = class {
|
|
|
2804
2907
|
agentName: run.agentName ?? null,
|
|
2805
2908
|
status: "running",
|
|
2806
2909
|
durationMs: null,
|
|
2910
|
+
ttftMs: null,
|
|
2911
|
+
costUsd: null,
|
|
2912
|
+
modelId: null,
|
|
2807
2913
|
errorCode: null,
|
|
2808
2914
|
errorMessage: null,
|
|
2809
2915
|
retries: 0,
|
|
@@ -2823,6 +2929,15 @@ var DrizzleAgentStore = class {
|
|
|
2823
2929
|
if (end.durationMs !== void 0) {
|
|
2824
2930
|
updates.durationMs = end.durationMs;
|
|
2825
2931
|
}
|
|
2932
|
+
if (end.ttftMs !== void 0) {
|
|
2933
|
+
updates.ttftMs = end.ttftMs;
|
|
2934
|
+
}
|
|
2935
|
+
if (end.costUsd !== void 0) {
|
|
2936
|
+
updates.costUsd = end.costUsd;
|
|
2937
|
+
}
|
|
2938
|
+
if (end.modelId !== void 0) {
|
|
2939
|
+
updates.modelId = end.modelId;
|
|
2940
|
+
}
|
|
2826
2941
|
if (end.errorCode !== void 0) {
|
|
2827
2942
|
updates.errorCode = end.errorCode;
|
|
2828
2943
|
}
|
|
@@ -3087,10 +3202,43 @@ var DrizzleAgentStore = class {
|
|
|
3087
3202
|
return this.usageBetween(actorRef, day, day);
|
|
3088
3203
|
}
|
|
3089
3204
|
async usageBetween(actorRef, fromDay, toDay) {
|
|
3090
|
-
const
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3205
|
+
const [totals] = await this.usageWindows(actorRef, [
|
|
3206
|
+
{
|
|
3207
|
+
fromDay,
|
|
3208
|
+
toDay
|
|
3209
|
+
}
|
|
3210
|
+
]);
|
|
3211
|
+
return totals ?? (0, import_nestjs_agent_core4.sumUsage)([]);
|
|
3212
|
+
}
|
|
3213
|
+
/**
|
|
3214
|
+
* Every range summed by the database in one statement, each as a conditional aggregate over the
|
|
3215
|
+
* rows of the smallest span covering them all — the actor's `(actor_ref, created_at)` index serves
|
|
3216
|
+
* it, and no usage row crosses the wire.
|
|
3217
|
+
*/
|
|
3218
|
+
async usageWindows(actorRef, ranges) {
|
|
3219
|
+
if (ranges.length === 0) {
|
|
3220
|
+
return [];
|
|
3221
|
+
}
|
|
3222
|
+
const usage = this.t.agentTokenUsage;
|
|
3223
|
+
const bounds = ranges.map(({ fromDay, toDay }) => ({
|
|
3224
|
+
start: /* @__PURE__ */ new Date(`${fromDay}T00:00:00.000Z`),
|
|
3225
|
+
end: /* @__PURE__ */ new Date(`${toDay}T23:59:59.999Z`)
|
|
3226
|
+
}));
|
|
3227
|
+
const within = /* @__PURE__ */ __name((start, end) => (0, import_drizzle_orm4.and)((0, import_drizzle_orm4.gte)(usage.createdAt, start), (0, import_drizzle_orm4.lte)(usage.createdAt, end)), "within");
|
|
3228
|
+
const columns = {};
|
|
3229
|
+
bounds.forEach(({ start, end }, index4) => {
|
|
3230
|
+
columns[`tokens${index4}`] = import_drizzle_orm4.sql`sum(case when ${within(start, end)} then ${usage.inputTokens} + ${usage.outputTokens} else 0 end)`;
|
|
3231
|
+
columns[`cost${index4}`] = import_drizzle_orm4.sql`sum(case when ${within(start, end)} then ${usage.costUsd} else 0 end)`;
|
|
3232
|
+
columns[`estimated${index4}`] = import_drizzle_orm4.sql`sum(case when ${within(start, end)} and ${usage.costSource} = 'estimate' then ${usage.costUsd} else 0 end)`;
|
|
3233
|
+
});
|
|
3234
|
+
const from = new Date(Math.min(...bounds.map(({ start }) => start.getTime())));
|
|
3235
|
+
const to = new Date(Math.max(...bounds.map(({ end }) => end.getTime())));
|
|
3236
|
+
const [row] = await this.db.select(columns).from(usage).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(usage.actorRef, actorRef), within(from, to)));
|
|
3237
|
+
return bounds.map((_, index4) => ({
|
|
3238
|
+
usedTokens: Number(row?.[`tokens${index4}`] ?? 0),
|
|
3239
|
+
costUsd: Number(row?.[`cost${index4}`] ?? 0),
|
|
3240
|
+
estimatedCostUsd: Number(row?.[`estimated${index4}`] ?? 0)
|
|
3241
|
+
}));
|
|
3094
3242
|
}
|
|
3095
3243
|
toSummary(thread, lastContent) {
|
|
3096
3244
|
return {
|
|
@@ -3308,6 +3456,11 @@ function toRecentRunRow(run) {
|
|
|
3308
3456
|
agentName: run.agentName ?? null,
|
|
3309
3457
|
status: run.status,
|
|
3310
3458
|
durationMs: run.durationMs ?? null,
|
|
3459
|
+
ttftMs: run.ttftMs ?? null,
|
|
3460
|
+
// MySQL's DOUBLE and Postgres' double precision come back as numbers; a driver that hands a
|
|
3461
|
+
// decimal back as a string is normalized here so the SPI row is always a number.
|
|
3462
|
+
costUsd: run.costUsd == null ? null : Number(run.costUsd),
|
|
3463
|
+
modelId: run.modelId ?? null,
|
|
3311
3464
|
errorCode: run.errorCode ?? null,
|
|
3312
3465
|
errorMessage: run.errorMessage ?? null,
|
|
3313
3466
|
retries: run.retries,
|
|
@@ -3381,7 +3534,18 @@ var DrizzleGovernanceQueries = class {
|
|
|
3381
3534
|
}
|
|
3382
3535
|
async usageInRange(range) {
|
|
3383
3536
|
const { start, end } = (0, import_nestjs_agent_core5.dayBoundsUtc)(range);
|
|
3384
|
-
const
|
|
3537
|
+
const usage = this.t.agentTokenUsage;
|
|
3538
|
+
const rows = await this.db.select({
|
|
3539
|
+
modelId: usage.modelId,
|
|
3540
|
+
actorRef: usage.actorRef,
|
|
3541
|
+
threadId: usage.threadId,
|
|
3542
|
+
createdAt: usage.createdAt,
|
|
3543
|
+
inputTokens: usage.inputTokens,
|
|
3544
|
+
outputTokens: usage.outputTokens,
|
|
3545
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
3546
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
3547
|
+
costUsd: usage.costUsd
|
|
3548
|
+
}).from(usage).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.gte)(this.t.agentTokenUsage.createdAt, start), (0, import_drizzle_orm5.lte)(this.t.agentTokenUsage.createdAt, end)));
|
|
3385
3549
|
return rows.map(toUsageInput);
|
|
3386
3550
|
}
|
|
3387
3551
|
async spendByModel(range) {
|
|
@@ -3406,7 +3570,11 @@ var DrizzleGovernanceQueries = class {
|
|
|
3406
3570
|
if (threadIds.length === 0) {
|
|
3407
3571
|
return [];
|
|
3408
3572
|
}
|
|
3409
|
-
const threads = await this.db.select(
|
|
3573
|
+
const threads = await this.db.select({
|
|
3574
|
+
id: this.t.agentThread.id,
|
|
3575
|
+
title: this.t.agentThread.title,
|
|
3576
|
+
actorRef: this.t.agentThread.actorRef
|
|
3577
|
+
}).from(this.t.agentThread).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.inArray)(this.t.agentThread.id, threadIds), (0, import_drizzle_orm5.isNull)(this.t.agentThread.deletedAt)));
|
|
3410
3578
|
const threadsById = new Map(threads.map((thread) => [
|
|
3411
3579
|
thread.id,
|
|
3412
3580
|
{
|
|
@@ -3501,9 +3669,19 @@ var DrizzleGovernanceQueries = class {
|
|
|
3501
3669
|
const threads = await this.db.select().from(this.t.agentThread).where((0, import_drizzle_orm5.isNull)(this.t.agentThread.deletedAt)).orderBy((0, import_drizzle_orm5.desc)(this.t.agentThread.updatedAt), (0, import_drizzle_orm5.desc)(this.t.agentThread.id)).limit(limit);
|
|
3502
3670
|
return this.toThreadActivityRows(threads);
|
|
3503
3671
|
}
|
|
3672
|
+
/** The range's runs, with only the columns the rollups read. */
|
|
3504
3673
|
async runsInRange(range) {
|
|
3505
3674
|
const { start, end } = (0, import_nestjs_agent_core5.dayBoundsUtc)(range);
|
|
3506
|
-
|
|
3675
|
+
const run = this.t.agentRun;
|
|
3676
|
+
return this.db.select({
|
|
3677
|
+
agentName: run.agentName,
|
|
3678
|
+
status: run.status,
|
|
3679
|
+
retries: run.retries,
|
|
3680
|
+
durationMs: run.durationMs,
|
|
3681
|
+
ttftMs: run.ttftMs,
|
|
3682
|
+
parentRunId: run.parentRunId,
|
|
3683
|
+
startedAt: run.startedAt
|
|
3684
|
+
}).from(run).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.gte)(run.startedAt, start), (0, import_drizzle_orm5.lte)(run.startedAt, end)));
|
|
3507
3685
|
}
|
|
3508
3686
|
async runMetrics(range) {
|
|
3509
3687
|
const runs = await this.runsInRange(range);
|
|
@@ -3511,6 +3689,7 @@ var DrizzleGovernanceQueries = class {
|
|
|
3511
3689
|
let failed = 0;
|
|
3512
3690
|
let retries = 0;
|
|
3513
3691
|
const settledDurationsMs = [];
|
|
3692
|
+
const ttftsMs = [];
|
|
3514
3693
|
for (const run of runs) {
|
|
3515
3694
|
if (run.status === "completed") {
|
|
3516
3695
|
completed += 1;
|
|
@@ -3521,8 +3700,12 @@ var DrizzleGovernanceQueries = class {
|
|
|
3521
3700
|
if ((run.status === "completed" || run.status === "failed") && run.durationMs != null) {
|
|
3522
3701
|
settledDurationsMs.push(run.durationMs);
|
|
3523
3702
|
}
|
|
3703
|
+
if (run.status === "completed" && run.parentRunId == null && run.ttftMs != null) {
|
|
3704
|
+
ttftsMs.push(run.ttftMs);
|
|
3705
|
+
}
|
|
3524
3706
|
}
|
|
3525
3707
|
settledDurationsMs.sort((left, right) => left - right);
|
|
3708
|
+
ttftsMs.sort((left, right) => left - right);
|
|
3526
3709
|
return {
|
|
3527
3710
|
runs: runs.length,
|
|
3528
3711
|
completed,
|
|
@@ -3530,7 +3713,9 @@ var DrizzleGovernanceQueries = class {
|
|
|
3530
3713
|
successRate: runs.length === 0 ? 0 : completed / runs.length,
|
|
3531
3714
|
retries,
|
|
3532
3715
|
durationP50Ms: percentileMs(settledDurationsMs, 0.5),
|
|
3533
|
-
durationP95Ms: percentileMs(settledDurationsMs, 0.95)
|
|
3716
|
+
durationP95Ms: percentileMs(settledDurationsMs, 0.95),
|
|
3717
|
+
ttftP50Ms: percentileMs(ttftsMs, 0.5),
|
|
3718
|
+
ttftP95Ms: percentileMs(ttftsMs, 0.95)
|
|
3534
3719
|
};
|
|
3535
3720
|
}
|
|
3536
3721
|
async runsByAgent(range) {
|
|
@@ -3560,7 +3745,9 @@ var DrizzleGovernanceQueries = class {
|
|
|
3560
3745
|
}
|
|
3561
3746
|
async runErrors(range) {
|
|
3562
3747
|
const { start, end } = (0, import_nestjs_agent_core5.dayBoundsUtc)(range);
|
|
3563
|
-
const runs = await this.db.select(
|
|
3748
|
+
const runs = await this.db.select({
|
|
3749
|
+
errorCode: this.t.agentRun.errorCode
|
|
3750
|
+
}).from(this.t.agentRun).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.gte)(this.t.agentRun.startedAt, start), (0, import_drizzle_orm5.lte)(this.t.agentRun.startedAt, end), (0, import_drizzle_orm5.eq)(this.t.agentRun.status, "failed")));
|
|
3564
3751
|
const byError = /* @__PURE__ */ new Map();
|
|
3565
3752
|
for (const run of runs) {
|
|
3566
3753
|
const errorCode = run.errorCode ?? UNCLASSIFIED_ERROR_CODE;
|
|
@@ -3641,7 +3828,12 @@ var DrizzleGovernanceQueries = class {
|
|
|
3641
3828
|
*/
|
|
3642
3829
|
async toolStats(range) {
|
|
3643
3830
|
const { start, end } = (0, import_nestjs_agent_core5.dayBoundsUtc)(range);
|
|
3644
|
-
const calls = await this.db.select(
|
|
3831
|
+
const calls = await this.db.select({
|
|
3832
|
+
toolName: this.t.agentToolCall.toolName,
|
|
3833
|
+
toolType: this.t.agentToolCall.toolType,
|
|
3834
|
+
status: this.t.agentToolCall.status,
|
|
3835
|
+
executionMs: this.t.agentToolCall.executionMs
|
|
3836
|
+
}).from(this.t.agentToolCall).where((0, import_drizzle_orm5.and)((0, import_drizzle_orm5.gte)(this.t.agentToolCall.createdAt, start), (0, import_drizzle_orm5.lte)(this.t.agentToolCall.createdAt, end)));
|
|
3645
3837
|
const byTool = /* @__PURE__ */ new Map();
|
|
3646
3838
|
for (const call of calls) {
|
|
3647
3839
|
const key2 = `${call.toolName} ${call.toolType}`;
|