@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.js
CHANGED
|
@@ -32,7 +32,9 @@ var agentThread = sqliteTable("agent_thread", {
|
|
|
32
32
|
mode: "timestamp_ms"
|
|
33
33
|
})
|
|
34
34
|
}, (table) => [
|
|
35
|
-
index("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
|
|
35
|
+
index("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
|
|
36
|
+
// `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
|
|
37
|
+
index("agent_thread_active_stream_idx").on(table.activeStreamId)
|
|
36
38
|
]);
|
|
37
39
|
var agentMessage = sqliteTable("agent_message", {
|
|
38
40
|
id: text("id").primaryKey(),
|
|
@@ -82,7 +84,9 @@ var agentMessage = sqliteTable("agent_message", {
|
|
|
82
84
|
mode: "timestamp_ms"
|
|
83
85
|
}).notNull()
|
|
84
86
|
}, (table) => [
|
|
85
|
-
index("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
|
|
87
|
+
index("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
|
|
88
|
+
// Transcript reads order a thread's messages by `seq`.
|
|
89
|
+
index("agent_message_thread_seq_idx").on(table.threadId, table.seq)
|
|
86
90
|
]);
|
|
87
91
|
var agentToolCall = sqliteTable("agent_tool_call", {
|
|
88
92
|
proposalId: text("proposal_id"),
|
|
@@ -127,7 +131,11 @@ var agentToolCall = sqliteTable("agent_tool_call", {
|
|
|
127
131
|
/** The surface the decision came through (`web`, `slack`, `remembered`, …). */
|
|
128
132
|
decidedVia: text("decided_via")
|
|
129
133
|
}, (table) => [
|
|
130
|
-
index("agent_tool_call_message_idx").on(table.messageId)
|
|
134
|
+
index("agent_tool_call_message_idx").on(table.messageId),
|
|
135
|
+
// The approvals inbox: `pending_approval`, oldest first.
|
|
136
|
+
index("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
|
|
137
|
+
index("agent_tool_call_run_idx").on(table.runId),
|
|
138
|
+
index("agent_tool_call_created_idx").on(table.createdAt)
|
|
131
139
|
]);
|
|
132
140
|
var agentQueuedMessage = sqliteTable("agent_queued_message", {
|
|
133
141
|
uiCapabilities: text("ui_capabilities", {
|
|
@@ -191,7 +199,9 @@ var agentTokenUsage = sqliteTable("agent_token_usage", {
|
|
|
191
199
|
mode: "timestamp_ms"
|
|
192
200
|
}).notNull()
|
|
193
201
|
}, (table) => [
|
|
194
|
-
index("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
|
|
202
|
+
index("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
203
|
+
index("agent_token_usage_created_idx").on(table.createdAt),
|
|
204
|
+
index("agent_token_usage_thread_idx").on(table.threadId)
|
|
195
205
|
]);
|
|
196
206
|
var agentGenuiCall = sqliteTable("agent_genui_call", {
|
|
197
207
|
id: text("id").primaryKey(),
|
|
@@ -249,6 +259,12 @@ var agentRun = sqliteTable("agent_run", {
|
|
|
249
259
|
agentName: text("agent_name"),
|
|
250
260
|
status: text("status").$type().notNull(),
|
|
251
261
|
durationMs: integer("duration_ms"),
|
|
262
|
+
/** Turn start to the first `text` frame; null for a run that streamed none or did not complete. */
|
|
263
|
+
ttftMs: integer("ttft_ms"),
|
|
264
|
+
/** The run's known spend (the sum of its model calls with a known cost); null when none had one. */
|
|
265
|
+
costUsd: real("cost_usd"),
|
|
266
|
+
/** The model the run's last model call resolved to. */
|
|
267
|
+
modelId: text("model_id"),
|
|
252
268
|
errorCode: text("error_code"),
|
|
253
269
|
errorMessage: text("error_message"),
|
|
254
270
|
retries: integer("retries").notNull().default(0),
|
|
@@ -528,7 +544,9 @@ var agentThread2 = mysqlTable("agent_thread", {
|
|
|
528
544
|
updatedAt: ts("updated_at").notNull(),
|
|
529
545
|
deletedAt: ts("deleted_at")
|
|
530
546
|
}, (table) => [
|
|
531
|
-
index2("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
|
|
547
|
+
index2("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
|
|
548
|
+
// `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
|
|
549
|
+
index2("agent_thread_active_stream_idx").on(table.activeStreamId)
|
|
532
550
|
]);
|
|
533
551
|
var agentMessage2 = mysqlTable("agent_message", {
|
|
534
552
|
id: key("id").primaryKey(),
|
|
@@ -554,7 +572,9 @@ var agentMessage2 = mysqlTable("agent_message", {
|
|
|
554
572
|
seq: int("seq"),
|
|
555
573
|
createdAt: ts("created_at").notNull()
|
|
556
574
|
}, (table) => [
|
|
557
|
-
index2("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
|
|
575
|
+
index2("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
|
|
576
|
+
// Transcript reads order a thread's messages by `seq`.
|
|
577
|
+
index2("agent_message_thread_seq_idx").on(table.threadId, table.seq)
|
|
558
578
|
]);
|
|
559
579
|
var agentToolCall2 = mysqlTable("agent_tool_call", {
|
|
560
580
|
proposalId: key("proposal_id"),
|
|
@@ -579,7 +599,11 @@ var agentToolCall2 = mysqlTable("agent_tool_call", {
|
|
|
579
599
|
remember: boolean("remember"),
|
|
580
600
|
decidedVia: key("decided_via")
|
|
581
601
|
}, (table) => [
|
|
582
|
-
index2("agent_tool_call_message_idx").on(table.messageId)
|
|
602
|
+
index2("agent_tool_call_message_idx").on(table.messageId),
|
|
603
|
+
// The approvals inbox: `pending_approval`, oldest first.
|
|
604
|
+
index2("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
|
|
605
|
+
index2("agent_tool_call_run_idx").on(table.runId),
|
|
606
|
+
index2("agent_tool_call_created_idx").on(table.createdAt)
|
|
583
607
|
]);
|
|
584
608
|
var agentQueuedMessage2 = mysqlTable("agent_queued_message", {
|
|
585
609
|
uiCapabilities: json("ui_capabilities").$type(),
|
|
@@ -621,7 +645,9 @@ var agentTokenUsage2 = mysqlTable("agent_token_usage", {
|
|
|
621
645
|
costSource: key("cost_source").$type(),
|
|
622
646
|
createdAt: ts("created_at").notNull()
|
|
623
647
|
}, (table) => [
|
|
624
|
-
index2("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
|
|
648
|
+
index2("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
649
|
+
index2("agent_token_usage_created_idx").on(table.createdAt),
|
|
650
|
+
index2("agent_token_usage_thread_idx").on(table.threadId)
|
|
625
651
|
]);
|
|
626
652
|
var agentGenuiCall2 = mysqlTable("agent_genui_call", {
|
|
627
653
|
id: key("id").primaryKey(),
|
|
@@ -681,6 +707,12 @@ var agentRun2 = mysqlTable("agent_run", {
|
|
|
681
707
|
agentName: key("agent_name"),
|
|
682
708
|
status: key("status").$type().notNull(),
|
|
683
709
|
durationMs: int("duration_ms"),
|
|
710
|
+
/** Turn start to the first `text` frame; null for a run that streamed none or did not complete. */
|
|
711
|
+
ttftMs: int("ttft_ms"),
|
|
712
|
+
/** The run's known spend (the sum of its model calls with a known cost); null when none had one. */
|
|
713
|
+
costUsd: double("cost_usd"),
|
|
714
|
+
/** The model the run's last model call resolved to. */
|
|
715
|
+
modelId: key("model_id"),
|
|
684
716
|
errorCode: key("error_code"),
|
|
685
717
|
errorMessage: longtext("error_message"),
|
|
686
718
|
retries: int("retries").notNull().default(0),
|
|
@@ -974,7 +1006,9 @@ var agentThread3 = pgTable("agent_thread", {
|
|
|
974
1006
|
updatedAt: ts2("updated_at").notNull(),
|
|
975
1007
|
deletedAt: ts2("deleted_at")
|
|
976
1008
|
}, (table) => [
|
|
977
|
-
index3("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
|
|
1009
|
+
index3("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
|
|
1010
|
+
// `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
|
|
1011
|
+
index3("agent_thread_active_stream_idx").on(table.activeStreamId)
|
|
978
1012
|
]);
|
|
979
1013
|
var agentMessage3 = pgTable("agent_message", {
|
|
980
1014
|
id: text2("id").primaryKey(),
|
|
@@ -1000,7 +1034,9 @@ var agentMessage3 = pgTable("agent_message", {
|
|
|
1000
1034
|
seq: integer2("seq"),
|
|
1001
1035
|
createdAt: ts2("created_at").notNull()
|
|
1002
1036
|
}, (table) => [
|
|
1003
|
-
index3("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
|
|
1037
|
+
index3("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
|
|
1038
|
+
// Transcript reads order a thread's messages by `seq`.
|
|
1039
|
+
index3("agent_message_thread_seq_idx").on(table.threadId, table.seq)
|
|
1004
1040
|
]);
|
|
1005
1041
|
var agentToolCall3 = pgTable("agent_tool_call", {
|
|
1006
1042
|
proposalId: text2("proposal_id"),
|
|
@@ -1025,7 +1061,11 @@ var agentToolCall3 = pgTable("agent_tool_call", {
|
|
|
1025
1061
|
remember: boolean2("remember"),
|
|
1026
1062
|
decidedVia: text2("decided_via")
|
|
1027
1063
|
}, (table) => [
|
|
1028
|
-
index3("agent_tool_call_message_idx").on(table.messageId)
|
|
1064
|
+
index3("agent_tool_call_message_idx").on(table.messageId),
|
|
1065
|
+
// The approvals inbox: `pending_approval`, oldest first.
|
|
1066
|
+
index3("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
|
|
1067
|
+
index3("agent_tool_call_run_idx").on(table.runId),
|
|
1068
|
+
index3("agent_tool_call_created_idx").on(table.createdAt)
|
|
1029
1069
|
]);
|
|
1030
1070
|
var agentQueuedMessage3 = pgTable("agent_queued_message", {
|
|
1031
1071
|
uiCapabilities: jsonb("ui_capabilities").$type(),
|
|
@@ -1067,7 +1107,9 @@ var agentTokenUsage3 = pgTable("agent_token_usage", {
|
|
|
1067
1107
|
costSource: text2("cost_source").$type(),
|
|
1068
1108
|
createdAt: ts2("created_at").notNull()
|
|
1069
1109
|
}, (table) => [
|
|
1070
|
-
index3("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
|
|
1110
|
+
index3("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
1111
|
+
index3("agent_token_usage_created_idx").on(table.createdAt),
|
|
1112
|
+
index3("agent_token_usage_thread_idx").on(table.threadId)
|
|
1071
1113
|
]);
|
|
1072
1114
|
var agentGenuiCall3 = pgTable("agent_genui_call", {
|
|
1073
1115
|
id: text2("id").primaryKey(),
|
|
@@ -1127,6 +1169,12 @@ var agentRun3 = pgTable("agent_run", {
|
|
|
1127
1169
|
agentName: text2("agent_name"),
|
|
1128
1170
|
status: text2("status").$type().notNull(),
|
|
1129
1171
|
durationMs: integer2("duration_ms"),
|
|
1172
|
+
/** Turn start to the first `text` frame; null for a run that streamed none or did not complete. */
|
|
1173
|
+
ttftMs: integer2("ttft_ms"),
|
|
1174
|
+
/** The run's known spend (the sum of its model calls with a known cost); null when none had one. */
|
|
1175
|
+
costUsd: doublePrecision("cost_usd"),
|
|
1176
|
+
/** The model the run's last model call resolved to. */
|
|
1177
|
+
modelId: text2("model_id"),
|
|
1130
1178
|
errorCode: text2("error_code"),
|
|
1131
1179
|
errorMessage: text2("error_message"),
|
|
1132
1180
|
retries: integer2("retries").notNull().default(0),
|
|
@@ -2340,12 +2388,49 @@ var DrizzleAgentStore = class {
|
|
|
2340
2388
|
}
|
|
2341
2389
|
async listThreads(actorRef, limit = 50) {
|
|
2342
2390
|
const threads = await this.db.select().from(this.t.agentThread).where(and2(eq2(this.t.agentThread.actorRef, actorRef), eq2(this.t.agentThread.transient, false), isNull2(this.t.agentThread.deletedAt))).orderBy(desc(this.t.agentThread.updatedAt)).limit(limit);
|
|
2343
|
-
const
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2391
|
+
const previews = await this.lastMessageContents(threads.map((thread) => thread.id));
|
|
2392
|
+
return threads.map((thread) => this.toSummary(thread, previews.get(thread.id)));
|
|
2393
|
+
}
|
|
2394
|
+
/**
|
|
2395
|
+
* The content of each thread's newest message ({@link messageOrderNewestFirst}), in a fixed two
|
|
2396
|
+
* reads for any number of threads: each thread's highest `seq`, then the rows holding it. Only a
|
|
2397
|
+
* thread whose every message predates `seq` is read on its own, by `created_at`.
|
|
2398
|
+
*/
|
|
2399
|
+
async lastMessageContents(threadIds) {
|
|
2400
|
+
const contents = /* @__PURE__ */ new Map();
|
|
2401
|
+
if (threadIds.length === 0) {
|
|
2402
|
+
return contents;
|
|
2403
|
+
}
|
|
2404
|
+
const message = this.t.agentMessage;
|
|
2405
|
+
const highest = await this.db.select({
|
|
2406
|
+
threadId: message.threadId,
|
|
2407
|
+
seq: max2(message.seq)
|
|
2408
|
+
}).from(message).where(inArray(message.threadId, [
|
|
2409
|
+
...threadIds
|
|
2410
|
+
])).groupBy(message.threadId);
|
|
2411
|
+
const numbered = highest.filter((row) => row.seq !== null);
|
|
2412
|
+
if (numbered.length > 0) {
|
|
2413
|
+
const rows = await this.db.select({
|
|
2414
|
+
threadId: message.threadId,
|
|
2415
|
+
content: message.content
|
|
2416
|
+
}).from(message).where(or2(...numbered.map((row) => and2(eq2(message.threadId, row.threadId), eq2(message.seq, Number(row.seq)))))).orderBy(...this.messageOrderNewestFirst());
|
|
2417
|
+
for (const row of rows) {
|
|
2418
|
+
if (!contents.has(row.threadId)) {
|
|
2419
|
+
contents.set(row.threadId, row.content);
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2347
2422
|
}
|
|
2348
|
-
|
|
2423
|
+
for (const row of highest) {
|
|
2424
|
+
if (row.seq === null) {
|
|
2425
|
+
const [last] = await this.db.select({
|
|
2426
|
+
content: message.content
|
|
2427
|
+
}).from(message).where(eq2(message.threadId, row.threadId)).orderBy(...this.messageOrderNewestFirst()).limit(1);
|
|
2428
|
+
if (last !== void 0) {
|
|
2429
|
+
contents.set(row.threadId, last.content);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
return contents;
|
|
2349
2434
|
}
|
|
2350
2435
|
async softDeleteThread(threadId) {
|
|
2351
2436
|
await this.db.update(this.t.agentThread).set({
|
|
@@ -2722,6 +2807,24 @@ var DrizzleAgentStore = class {
|
|
|
2722
2807
|
}).from(agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
|
|
2723
2808
|
return thread?.persona ?? null;
|
|
2724
2809
|
}
|
|
2810
|
+
async threadSettings(threadId) {
|
|
2811
|
+
const thread = this.t.agentThread;
|
|
2812
|
+
const [row] = await this.db.select({
|
|
2813
|
+
actorRef: thread.actorRef,
|
|
2814
|
+
defaultAgent: thread.defaultAgent,
|
|
2815
|
+
persona: thread.persona,
|
|
2816
|
+
model: thread.model
|
|
2817
|
+
}).from(thread).where(and2(eq2(thread.id, threadId), isNull2(thread.deletedAt)));
|
|
2818
|
+
if (row === void 0) {
|
|
2819
|
+
return null;
|
|
2820
|
+
}
|
|
2821
|
+
return {
|
|
2822
|
+
actorRef: row.actorRef,
|
|
2823
|
+
defaultAgent: row.defaultAgent ?? null,
|
|
2824
|
+
persona: row.persona ?? null,
|
|
2825
|
+
model: row.model ?? null
|
|
2826
|
+
};
|
|
2827
|
+
}
|
|
2725
2828
|
async defaultAgentForThread(threadId) {
|
|
2726
2829
|
const [thread] = await this.db.select({
|
|
2727
2830
|
defaultAgent: this.t.agentThread.defaultAgent
|
|
@@ -2742,6 +2845,9 @@ var DrizzleAgentStore = class {
|
|
|
2742
2845
|
agentName: run.agentName ?? null,
|
|
2743
2846
|
status: "running",
|
|
2744
2847
|
durationMs: null,
|
|
2848
|
+
ttftMs: null,
|
|
2849
|
+
costUsd: null,
|
|
2850
|
+
modelId: null,
|
|
2745
2851
|
errorCode: null,
|
|
2746
2852
|
errorMessage: null,
|
|
2747
2853
|
retries: 0,
|
|
@@ -2761,6 +2867,15 @@ var DrizzleAgentStore = class {
|
|
|
2761
2867
|
if (end.durationMs !== void 0) {
|
|
2762
2868
|
updates.durationMs = end.durationMs;
|
|
2763
2869
|
}
|
|
2870
|
+
if (end.ttftMs !== void 0) {
|
|
2871
|
+
updates.ttftMs = end.ttftMs;
|
|
2872
|
+
}
|
|
2873
|
+
if (end.costUsd !== void 0) {
|
|
2874
|
+
updates.costUsd = end.costUsd;
|
|
2875
|
+
}
|
|
2876
|
+
if (end.modelId !== void 0) {
|
|
2877
|
+
updates.modelId = end.modelId;
|
|
2878
|
+
}
|
|
2764
2879
|
if (end.errorCode !== void 0) {
|
|
2765
2880
|
updates.errorCode = end.errorCode;
|
|
2766
2881
|
}
|
|
@@ -3025,10 +3140,43 @@ var DrizzleAgentStore = class {
|
|
|
3025
3140
|
return this.usageBetween(actorRef, day, day);
|
|
3026
3141
|
}
|
|
3027
3142
|
async usageBetween(actorRef, fromDay, toDay) {
|
|
3028
|
-
const
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3143
|
+
const [totals] = await this.usageWindows(actorRef, [
|
|
3144
|
+
{
|
|
3145
|
+
fromDay,
|
|
3146
|
+
toDay
|
|
3147
|
+
}
|
|
3148
|
+
]);
|
|
3149
|
+
return totals ?? sumUsage([]);
|
|
3150
|
+
}
|
|
3151
|
+
/**
|
|
3152
|
+
* Every range summed by the database in one statement, each as a conditional aggregate over the
|
|
3153
|
+
* rows of the smallest span covering them all — the actor's `(actor_ref, created_at)` index serves
|
|
3154
|
+
* it, and no usage row crosses the wire.
|
|
3155
|
+
*/
|
|
3156
|
+
async usageWindows(actorRef, ranges) {
|
|
3157
|
+
if (ranges.length === 0) {
|
|
3158
|
+
return [];
|
|
3159
|
+
}
|
|
3160
|
+
const usage = this.t.agentTokenUsage;
|
|
3161
|
+
const bounds = ranges.map(({ fromDay, toDay }) => ({
|
|
3162
|
+
start: /* @__PURE__ */ new Date(`${fromDay}T00:00:00.000Z`),
|
|
3163
|
+
end: /* @__PURE__ */ new Date(`${toDay}T23:59:59.999Z`)
|
|
3164
|
+
}));
|
|
3165
|
+
const within = /* @__PURE__ */ __name((start, end) => and2(gte(usage.createdAt, start), lte2(usage.createdAt, end)), "within");
|
|
3166
|
+
const columns = {};
|
|
3167
|
+
bounds.forEach(({ start, end }, index4) => {
|
|
3168
|
+
columns[`tokens${index4}`] = sql3`sum(case when ${within(start, end)} then ${usage.inputTokens} + ${usage.outputTokens} else 0 end)`;
|
|
3169
|
+
columns[`cost${index4}`] = sql3`sum(case when ${within(start, end)} then ${usage.costUsd} else 0 end)`;
|
|
3170
|
+
columns[`estimated${index4}`] = sql3`sum(case when ${within(start, end)} and ${usage.costSource} = 'estimate' then ${usage.costUsd} else 0 end)`;
|
|
3171
|
+
});
|
|
3172
|
+
const from = new Date(Math.min(...bounds.map(({ start }) => start.getTime())));
|
|
3173
|
+
const to = new Date(Math.max(...bounds.map(({ end }) => end.getTime())));
|
|
3174
|
+
const [row] = await this.db.select(columns).from(usage).where(and2(eq2(usage.actorRef, actorRef), within(from, to)));
|
|
3175
|
+
return bounds.map((_, index4) => ({
|
|
3176
|
+
usedTokens: Number(row?.[`tokens${index4}`] ?? 0),
|
|
3177
|
+
costUsd: Number(row?.[`cost${index4}`] ?? 0),
|
|
3178
|
+
estimatedCostUsd: Number(row?.[`estimated${index4}`] ?? 0)
|
|
3179
|
+
}));
|
|
3032
3180
|
}
|
|
3033
3181
|
toSummary(thread, lastContent) {
|
|
3034
3182
|
return {
|
|
@@ -3246,6 +3394,11 @@ function toRecentRunRow(run) {
|
|
|
3246
3394
|
agentName: run.agentName ?? null,
|
|
3247
3395
|
status: run.status,
|
|
3248
3396
|
durationMs: run.durationMs ?? null,
|
|
3397
|
+
ttftMs: run.ttftMs ?? null,
|
|
3398
|
+
// MySQL's DOUBLE and Postgres' double precision come back as numbers; a driver that hands a
|
|
3399
|
+
// decimal back as a string is normalized here so the SPI row is always a number.
|
|
3400
|
+
costUsd: run.costUsd == null ? null : Number(run.costUsd),
|
|
3401
|
+
modelId: run.modelId ?? null,
|
|
3249
3402
|
errorCode: run.errorCode ?? null,
|
|
3250
3403
|
errorMessage: run.errorMessage ?? null,
|
|
3251
3404
|
retries: run.retries,
|
|
@@ -3319,7 +3472,18 @@ var DrizzleGovernanceQueries = class {
|
|
|
3319
3472
|
}
|
|
3320
3473
|
async usageInRange(range) {
|
|
3321
3474
|
const { start, end } = dayBoundsUtc(range);
|
|
3322
|
-
const
|
|
3475
|
+
const usage = this.t.agentTokenUsage;
|
|
3476
|
+
const rows = await this.db.select({
|
|
3477
|
+
modelId: usage.modelId,
|
|
3478
|
+
actorRef: usage.actorRef,
|
|
3479
|
+
threadId: usage.threadId,
|
|
3480
|
+
createdAt: usage.createdAt,
|
|
3481
|
+
inputTokens: usage.inputTokens,
|
|
3482
|
+
outputTokens: usage.outputTokens,
|
|
3483
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
3484
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
3485
|
+
costUsd: usage.costUsd
|
|
3486
|
+
}).from(usage).where(and3(gte2(this.t.agentTokenUsage.createdAt, start), lte3(this.t.agentTokenUsage.createdAt, end)));
|
|
3323
3487
|
return rows.map(toUsageInput);
|
|
3324
3488
|
}
|
|
3325
3489
|
async spendByModel(range) {
|
|
@@ -3344,7 +3508,11 @@ var DrizzleGovernanceQueries = class {
|
|
|
3344
3508
|
if (threadIds.length === 0) {
|
|
3345
3509
|
return [];
|
|
3346
3510
|
}
|
|
3347
|
-
const threads = await this.db.select(
|
|
3511
|
+
const threads = await this.db.select({
|
|
3512
|
+
id: this.t.agentThread.id,
|
|
3513
|
+
title: this.t.agentThread.title,
|
|
3514
|
+
actorRef: this.t.agentThread.actorRef
|
|
3515
|
+
}).from(this.t.agentThread).where(and3(inArray2(this.t.agentThread.id, threadIds), isNull3(this.t.agentThread.deletedAt)));
|
|
3348
3516
|
const threadsById = new Map(threads.map((thread) => [
|
|
3349
3517
|
thread.id,
|
|
3350
3518
|
{
|
|
@@ -3439,9 +3607,19 @@ var DrizzleGovernanceQueries = class {
|
|
|
3439
3607
|
const threads = await this.db.select().from(this.t.agentThread).where(isNull3(this.t.agentThread.deletedAt)).orderBy(desc2(this.t.agentThread.updatedAt), desc2(this.t.agentThread.id)).limit(limit);
|
|
3440
3608
|
return this.toThreadActivityRows(threads);
|
|
3441
3609
|
}
|
|
3610
|
+
/** The range's runs, with only the columns the rollups read. */
|
|
3442
3611
|
async runsInRange(range) {
|
|
3443
3612
|
const { start, end } = dayBoundsUtc(range);
|
|
3444
|
-
|
|
3613
|
+
const run = this.t.agentRun;
|
|
3614
|
+
return this.db.select({
|
|
3615
|
+
agentName: run.agentName,
|
|
3616
|
+
status: run.status,
|
|
3617
|
+
retries: run.retries,
|
|
3618
|
+
durationMs: run.durationMs,
|
|
3619
|
+
ttftMs: run.ttftMs,
|
|
3620
|
+
parentRunId: run.parentRunId,
|
|
3621
|
+
startedAt: run.startedAt
|
|
3622
|
+
}).from(run).where(and3(gte2(run.startedAt, start), lte3(run.startedAt, end)));
|
|
3445
3623
|
}
|
|
3446
3624
|
async runMetrics(range) {
|
|
3447
3625
|
const runs = await this.runsInRange(range);
|
|
@@ -3449,6 +3627,7 @@ var DrizzleGovernanceQueries = class {
|
|
|
3449
3627
|
let failed = 0;
|
|
3450
3628
|
let retries = 0;
|
|
3451
3629
|
const settledDurationsMs = [];
|
|
3630
|
+
const ttftsMs = [];
|
|
3452
3631
|
for (const run of runs) {
|
|
3453
3632
|
if (run.status === "completed") {
|
|
3454
3633
|
completed += 1;
|
|
@@ -3459,8 +3638,12 @@ var DrizzleGovernanceQueries = class {
|
|
|
3459
3638
|
if ((run.status === "completed" || run.status === "failed") && run.durationMs != null) {
|
|
3460
3639
|
settledDurationsMs.push(run.durationMs);
|
|
3461
3640
|
}
|
|
3641
|
+
if (run.status === "completed" && run.parentRunId == null && run.ttftMs != null) {
|
|
3642
|
+
ttftsMs.push(run.ttftMs);
|
|
3643
|
+
}
|
|
3462
3644
|
}
|
|
3463
3645
|
settledDurationsMs.sort((left, right) => left - right);
|
|
3646
|
+
ttftsMs.sort((left, right) => left - right);
|
|
3464
3647
|
return {
|
|
3465
3648
|
runs: runs.length,
|
|
3466
3649
|
completed,
|
|
@@ -3468,7 +3651,9 @@ var DrizzleGovernanceQueries = class {
|
|
|
3468
3651
|
successRate: runs.length === 0 ? 0 : completed / runs.length,
|
|
3469
3652
|
retries,
|
|
3470
3653
|
durationP50Ms: percentileMs(settledDurationsMs, 0.5),
|
|
3471
|
-
durationP95Ms: percentileMs(settledDurationsMs, 0.95)
|
|
3654
|
+
durationP95Ms: percentileMs(settledDurationsMs, 0.95),
|
|
3655
|
+
ttftP50Ms: percentileMs(ttftsMs, 0.5),
|
|
3656
|
+
ttftP95Ms: percentileMs(ttftsMs, 0.95)
|
|
3472
3657
|
};
|
|
3473
3658
|
}
|
|
3474
3659
|
async runsByAgent(range) {
|
|
@@ -3498,7 +3683,9 @@ var DrizzleGovernanceQueries = class {
|
|
|
3498
3683
|
}
|
|
3499
3684
|
async runErrors(range) {
|
|
3500
3685
|
const { start, end } = dayBoundsUtc(range);
|
|
3501
|
-
const runs = await this.db.select(
|
|
3686
|
+
const runs = await this.db.select({
|
|
3687
|
+
errorCode: this.t.agentRun.errorCode
|
|
3688
|
+
}).from(this.t.agentRun).where(and3(gte2(this.t.agentRun.startedAt, start), lte3(this.t.agentRun.startedAt, end), eq3(this.t.agentRun.status, "failed")));
|
|
3502
3689
|
const byError = /* @__PURE__ */ new Map();
|
|
3503
3690
|
for (const run of runs) {
|
|
3504
3691
|
const errorCode = run.errorCode ?? UNCLASSIFIED_ERROR_CODE;
|
|
@@ -3579,7 +3766,12 @@ var DrizzleGovernanceQueries = class {
|
|
|
3579
3766
|
*/
|
|
3580
3767
|
async toolStats(range) {
|
|
3581
3768
|
const { start, end } = dayBoundsUtc(range);
|
|
3582
|
-
const calls = await this.db.select(
|
|
3769
|
+
const calls = await this.db.select({
|
|
3770
|
+
toolName: this.t.agentToolCall.toolName,
|
|
3771
|
+
toolType: this.t.agentToolCall.toolType,
|
|
3772
|
+
status: this.t.agentToolCall.status,
|
|
3773
|
+
executionMs: this.t.agentToolCall.executionMs
|
|
3774
|
+
}).from(this.t.agentToolCall).where(and3(gte2(this.t.agentToolCall.createdAt, start), lte3(this.t.agentToolCall.createdAt, end)));
|
|
3583
3775
|
const byTool = /* @__PURE__ */ new Map();
|
|
3584
3776
|
for (const call of calls) {
|
|
3585
3777
|
const key2 = `${call.toolName} ${call.toolType}`;
|