@dudousxd/nestjs-agent-store-drizzle 0.33.0 → 0.35.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 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1031 -36
- package/dist/index.d.ts +1031 -36
- package/dist/index.js +220 -23
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -240,7 +240,7 @@ var agentQueuedMessage = (0, import_sqlite_core.sqliteTable)("agent_queued_messa
|
|
|
240
240
|
]);
|
|
241
241
|
var agentTokenUsage = (0, import_sqlite_core.sqliteTable)("agent_token_usage", {
|
|
242
242
|
id: (0, import_sqlite_core.text)("id").primaryKey(),
|
|
243
|
-
threadId: (0, import_sqlite_core.text)("thread_id").
|
|
243
|
+
threadId: (0, import_sqlite_core.text)("thread_id").references(() => agentThread.id, {
|
|
244
244
|
onDelete: "cascade"
|
|
245
245
|
}),
|
|
246
246
|
actorRef: (0, import_sqlite_core.text)("actor_ref").notNull(),
|
|
@@ -257,13 +257,28 @@ var agentTokenUsage = (0, import_sqlite_core.sqliteTable)("agent_token_usage", {
|
|
|
257
257
|
costUsd: (0, import_sqlite_core.real)("cost_usd"),
|
|
258
258
|
/** Where `cost_usd` came from: `'provider'` (reported) or `'estimate'` (tokens × the price row); null on rows from before it existed (reported). */
|
|
259
259
|
costSource: (0, import_sqlite_core.text)("cost_source").$type(),
|
|
260
|
+
/** The run the row belongs to. */
|
|
261
|
+
runId: (0, import_sqlite_core.text)("run_id"),
|
|
262
|
+
/** What the spend was for: `agent:<name>` for an agent turn, the app's own otherwise; null → `agent`. */
|
|
263
|
+
feature: (0, import_sqlite_core.text)("feature"),
|
|
264
|
+
provider: (0, import_sqlite_core.text)("provider"),
|
|
265
|
+
tenantRef: (0, import_sqlite_core.text)("tenant_ref"),
|
|
266
|
+
/** Units a row bills by when they are not tokens. */
|
|
267
|
+
audioSeconds: (0, import_sqlite_core.real)("audio_seconds"),
|
|
268
|
+
characters: (0, import_sqlite_core.integer)("characters"),
|
|
269
|
+
requests: (0, import_sqlite_core.integer)("requests"),
|
|
270
|
+
/** The caller's own JSON, never read by the library. */
|
|
271
|
+
metadata: (0, import_sqlite_core.text)("metadata", {
|
|
272
|
+
mode: "json"
|
|
273
|
+
}).$type(),
|
|
260
274
|
createdAt: (0, import_sqlite_core.integer)("created_at", {
|
|
261
275
|
mode: "timestamp_ms"
|
|
262
276
|
}).notNull()
|
|
263
277
|
}, (table) => [
|
|
264
278
|
(0, import_sqlite_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
265
279
|
(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)
|
|
280
|
+
(0, import_sqlite_core.index)("agent_token_usage_thread_idx").on(table.threadId),
|
|
281
|
+
(0, import_sqlite_core.index)("agent_token_usage_feature_created_idx").on(table.feature, table.createdAt)
|
|
267
282
|
]);
|
|
268
283
|
var agentGenuiCall = (0, import_sqlite_core.sqliteTable)("agent_genui_call", {
|
|
269
284
|
id: (0, import_sqlite_core.text)("id").primaryKey(),
|
|
@@ -345,7 +360,17 @@ var agentRun = (0, import_sqlite_core.sqliteTable)("agent_run", {
|
|
|
345
360
|
* for a detached child, which outlives its parent's turn and so is paired by nothing in the
|
|
346
361
|
* transcript.
|
|
347
362
|
*/
|
|
348
|
-
parentRunId: (0, import_sqlite_core.text)("parent_run_id")
|
|
363
|
+
parentRunId: (0, import_sqlite_core.text)("parent_run_id"),
|
|
364
|
+
/** Enqueue → body start (ms); null when not read. */
|
|
365
|
+
queueMs: (0, import_sqlite_core.integer)("queue_ms"),
|
|
366
|
+
/** Where the completed run's time went: model and tool totals, counts, and the per-step list. */
|
|
367
|
+
modelMs: (0, import_sqlite_core.integer)("model_ms"),
|
|
368
|
+
toolsMs: (0, import_sqlite_core.integer)("tools_ms"),
|
|
369
|
+
modelCalls: (0, import_sqlite_core.integer)("model_calls"),
|
|
370
|
+
toolCalls: (0, import_sqlite_core.integer)("tool_calls"),
|
|
371
|
+
timings: (0, import_sqlite_core.text)("timings", {
|
|
372
|
+
mode: "json"
|
|
373
|
+
}).$type()
|
|
349
374
|
}, (table) => [
|
|
350
375
|
(0, import_sqlite_core.index)("agent_run_started_idx").on(table.startedAt)
|
|
351
376
|
]);
|
|
@@ -691,7 +716,7 @@ var agentQueuedMessage2 = (0, import_mysql_core.mysqlTable)("agent_queued_messag
|
|
|
691
716
|
]);
|
|
692
717
|
var agentTokenUsage2 = (0, import_mysql_core.mysqlTable)("agent_token_usage", {
|
|
693
718
|
id: key("id").primaryKey(),
|
|
694
|
-
threadId: key("thread_id").
|
|
719
|
+
threadId: key("thread_id").references(() => agentThread2.id, {
|
|
695
720
|
onDelete: "cascade"
|
|
696
721
|
}),
|
|
697
722
|
actorRef: key("actor_ref").notNull(),
|
|
@@ -705,11 +730,26 @@ var agentTokenUsage2 = (0, import_mysql_core.mysqlTable)("agent_token_usage", {
|
|
|
705
730
|
costUsd: (0, import_mysql_core.double)("cost_usd"),
|
|
706
731
|
/** Where `cost_usd` came from: `'provider'` (reported) or `'estimate'` (tokens × the price row); null on rows from before it existed (reported). */
|
|
707
732
|
costSource: key("cost_source").$type(),
|
|
733
|
+
/** The run the row belongs to. */
|
|
734
|
+
runId: key("run_id"),
|
|
735
|
+
/** What the spend was for: `agent:<name>` for an agent turn, the app's own otherwise; null → `agent`. */
|
|
736
|
+
feature: key("feature"),
|
|
737
|
+
provider: key("provider"),
|
|
738
|
+
tenantRef: key("tenant_ref"),
|
|
739
|
+
/** Units a row bills by when they are not tokens. */
|
|
740
|
+
audioSeconds: (0, import_mysql_core.double)("audio_seconds"),
|
|
741
|
+
characters: (0, import_mysql_core.bigint)("characters", {
|
|
742
|
+
mode: "number"
|
|
743
|
+
}),
|
|
744
|
+
requests: (0, import_mysql_core.int)("requests"),
|
|
745
|
+
/** The caller's own JSON, never read by the library. */
|
|
746
|
+
metadata: (0, import_mysql_core.json)("metadata").$type(),
|
|
708
747
|
createdAt: ts("created_at").notNull()
|
|
709
748
|
}, (table) => [
|
|
710
749
|
(0, import_mysql_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
711
750
|
(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)
|
|
751
|
+
(0, import_mysql_core.index)("agent_token_usage_thread_idx").on(table.threadId),
|
|
752
|
+
(0, import_mysql_core.index)("agent_token_usage_feature_created_idx").on(table.feature, table.createdAt)
|
|
713
753
|
]);
|
|
714
754
|
var agentGenuiCall2 = (0, import_mysql_core.mysqlTable)("agent_genui_call", {
|
|
715
755
|
id: key("id").primaryKey(),
|
|
@@ -781,7 +821,15 @@ var agentRun2 = (0, import_mysql_core.mysqlTable)("agent_run", {
|
|
|
781
821
|
startedAt: ts("started_at").notNull(),
|
|
782
822
|
settledAt: ts("settled_at"),
|
|
783
823
|
promptHash: key("prompt_hash"),
|
|
784
|
-
parentRunId: key("parent_run_id")
|
|
824
|
+
parentRunId: key("parent_run_id"),
|
|
825
|
+
/** Enqueue → body start (ms); null when not read. */
|
|
826
|
+
queueMs: (0, import_mysql_core.int)("queue_ms"),
|
|
827
|
+
/** Where the completed run's time went: model and tool totals, counts, and the per-step list. */
|
|
828
|
+
modelMs: (0, import_mysql_core.int)("model_ms"),
|
|
829
|
+
toolsMs: (0, import_mysql_core.int)("tools_ms"),
|
|
830
|
+
modelCalls: (0, import_mysql_core.int)("model_calls"),
|
|
831
|
+
toolCalls: (0, import_mysql_core.int)("tool_calls"),
|
|
832
|
+
timings: (0, import_mysql_core.json)("timings").$type()
|
|
785
833
|
}, (table) => [
|
|
786
834
|
(0, import_mysql_core.index)("agent_run_started_idx").on(table.startedAt)
|
|
787
835
|
]);
|
|
@@ -1153,7 +1201,7 @@ var agentQueuedMessage3 = (0, import_pg_core.pgTable)("agent_queued_message", {
|
|
|
1153
1201
|
]);
|
|
1154
1202
|
var agentTokenUsage3 = (0, import_pg_core.pgTable)("agent_token_usage", {
|
|
1155
1203
|
id: (0, import_pg_core.text)("id").primaryKey(),
|
|
1156
|
-
threadId: (0, import_pg_core.text)("thread_id").
|
|
1204
|
+
threadId: (0, import_pg_core.text)("thread_id").references(() => agentThread3.id, {
|
|
1157
1205
|
onDelete: "cascade"
|
|
1158
1206
|
}),
|
|
1159
1207
|
actorRef: (0, import_pg_core.text)("actor_ref").notNull(),
|
|
@@ -1167,11 +1215,26 @@ var agentTokenUsage3 = (0, import_pg_core.pgTable)("agent_token_usage", {
|
|
|
1167
1215
|
costUsd: (0, import_pg_core.doublePrecision)("cost_usd"),
|
|
1168
1216
|
/** Where `cost_usd` came from: `'provider'` (reported) or `'estimate'` (tokens × the price row); null on rows from before it existed (reported). */
|
|
1169
1217
|
costSource: (0, import_pg_core.text)("cost_source").$type(),
|
|
1218
|
+
/** The run the row belongs to. */
|
|
1219
|
+
runId: (0, import_pg_core.text)("run_id"),
|
|
1220
|
+
/** What the spend was for: `agent:<name>` for an agent turn, the app's own otherwise; null → `agent`. */
|
|
1221
|
+
feature: (0, import_pg_core.text)("feature"),
|
|
1222
|
+
provider: (0, import_pg_core.text)("provider"),
|
|
1223
|
+
tenantRef: (0, import_pg_core.text)("tenant_ref"),
|
|
1224
|
+
/** Units a row bills by when they are not tokens. */
|
|
1225
|
+
audioSeconds: (0, import_pg_core.doublePrecision)("audio_seconds"),
|
|
1226
|
+
characters: (0, import_pg_core.bigint)("characters", {
|
|
1227
|
+
mode: "number"
|
|
1228
|
+
}),
|
|
1229
|
+
requests: (0, import_pg_core.integer)("requests"),
|
|
1230
|
+
/** The caller's own JSON, never read by the library. */
|
|
1231
|
+
metadata: (0, import_pg_core.jsonb)("metadata").$type(),
|
|
1170
1232
|
createdAt: ts2("created_at").notNull()
|
|
1171
1233
|
}, (table) => [
|
|
1172
1234
|
(0, import_pg_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
1173
1235
|
(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)
|
|
1236
|
+
(0, import_pg_core.index)("agent_token_usage_thread_idx").on(table.threadId),
|
|
1237
|
+
(0, import_pg_core.index)("agent_token_usage_feature_created_idx").on(table.feature, table.createdAt)
|
|
1175
1238
|
]);
|
|
1176
1239
|
var agentGenuiCall3 = (0, import_pg_core.pgTable)("agent_genui_call", {
|
|
1177
1240
|
id: (0, import_pg_core.text)("id").primaryKey(),
|
|
@@ -1243,7 +1306,15 @@ var agentRun3 = (0, import_pg_core.pgTable)("agent_run", {
|
|
|
1243
1306
|
startedAt: ts2("started_at").notNull(),
|
|
1244
1307
|
settledAt: ts2("settled_at"),
|
|
1245
1308
|
promptHash: (0, import_pg_core.text)("prompt_hash"),
|
|
1246
|
-
parentRunId: (0, import_pg_core.text)("parent_run_id")
|
|
1309
|
+
parentRunId: (0, import_pg_core.text)("parent_run_id"),
|
|
1310
|
+
/** Enqueue → body start (ms); null when not read. */
|
|
1311
|
+
queueMs: (0, import_pg_core.integer)("queue_ms"),
|
|
1312
|
+
/** Where the completed run's time went: model and tool totals, counts, and the per-step list. */
|
|
1313
|
+
modelMs: (0, import_pg_core.integer)("model_ms"),
|
|
1314
|
+
toolsMs: (0, import_pg_core.integer)("tools_ms"),
|
|
1315
|
+
modelCalls: (0, import_pg_core.integer)("model_calls"),
|
|
1316
|
+
toolCalls: (0, import_pg_core.integer)("tool_calls"),
|
|
1317
|
+
timings: (0, import_pg_core.jsonb)("timings").$type()
|
|
1247
1318
|
}, (table) => [
|
|
1248
1319
|
(0, import_pg_core.index)("agent_run_started_idx").on(table.startedAt)
|
|
1249
1320
|
]);
|
|
@@ -1701,10 +1772,60 @@ function specs(dialect) {
|
|
|
1701
1772
|
}
|
|
1702
1773
|
__name(specs, "specs");
|
|
1703
1774
|
async function existingColumns(db, dialect, table) {
|
|
1704
|
-
|
|
1705
|
-
return new Set(rows.map((row) => String(row.name)));
|
|
1775
|
+
return new Set((await columnNullability(db, dialect, table)).keys());
|
|
1706
1776
|
}
|
|
1707
1777
|
__name(existingColumns, "existingColumns");
|
|
1778
|
+
async function columnNullability(db, dialect, table) {
|
|
1779
|
+
if (dialect === "sqlite") {
|
|
1780
|
+
const rows2 = await querySql(db, dialect, import_drizzle_orm2.sql.raw(`PRAGMA table_info("${table}")`));
|
|
1781
|
+
return new Map(rows2.map((row) => [
|
|
1782
|
+
String(row.name),
|
|
1783
|
+
Number(row.notnull) === 0
|
|
1784
|
+
]));
|
|
1785
|
+
}
|
|
1786
|
+
const rows = await querySql(db, dialect, import_drizzle_orm2.sql`select column_name as name, is_nullable as nullable from information_schema.columns where table_schema = ${import_drizzle_orm2.sql.raw(dialect === "mysql" ? "database()" : "current_schema()")} and table_name = ${table}`);
|
|
1787
|
+
return new Map(rows.map((row) => [
|
|
1788
|
+
String(row.name ?? row.NAME),
|
|
1789
|
+
String(row.nullable ?? row.NULLABLE).toUpperCase() === "YES"
|
|
1790
|
+
]));
|
|
1791
|
+
}
|
|
1792
|
+
__name(columnNullability, "columnNullability");
|
|
1793
|
+
async function relaxNotNull(db, dialect, spec, column, all) {
|
|
1794
|
+
const q = /* @__PURE__ */ __name((identifier) => quote(dialect, identifier), "q");
|
|
1795
|
+
if (dialect === "postgres") {
|
|
1796
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`ALTER TABLE ${q(spec.name)} ALTER COLUMN ${q(column.name)} DROP NOT NULL`));
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
if (dialect === "mysql") {
|
|
1800
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`ALTER TABLE ${q(spec.name)} MODIFY ${columnDefinition(dialect, column)}`));
|
|
1801
|
+
return;
|
|
1802
|
+
}
|
|
1803
|
+
if (all.some((other) => other.foreignKeys.some((key2) => key2.table === spec.name && other !== spec))) {
|
|
1804
|
+
throw new Error(`agent schema: cannot make ${spec.name}.${column.name} nullable on SQLite \u2014 other tables reference ${spec.name}`);
|
|
1805
|
+
}
|
|
1806
|
+
const scratch = `${spec.name}__rebuild`;
|
|
1807
|
+
const present = [
|
|
1808
|
+
...(await columnNullability(db, dialect, spec.name)).keys()
|
|
1809
|
+
];
|
|
1810
|
+
const list = present.map(q).join(", ");
|
|
1811
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw("SAVEPOINT agent_schema_rebuild"));
|
|
1812
|
+
try {
|
|
1813
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`DROP TABLE IF EXISTS ${q(scratch)}`));
|
|
1814
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(createTableSql(dialect, {
|
|
1815
|
+
...spec,
|
|
1816
|
+
name: scratch
|
|
1817
|
+
})));
|
|
1818
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`INSERT INTO ${q(scratch)} (${list}) SELECT ${list} FROM ${q(spec.name)}`));
|
|
1819
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`DROP TABLE ${q(spec.name)}`));
|
|
1820
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`ALTER TABLE ${q(scratch)} RENAME TO ${q(spec.name)}`));
|
|
1821
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw("RELEASE SAVEPOINT agent_schema_rebuild"));
|
|
1822
|
+
} catch (error) {
|
|
1823
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw("ROLLBACK TO SAVEPOINT agent_schema_rebuild")).catch(() => void 0);
|
|
1824
|
+
await runSql(db, dialect, import_drizzle_orm2.sql.raw("RELEASE SAVEPOINT agent_schema_rebuild")).catch(() => void 0);
|
|
1825
|
+
throw error;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
__name(relaxNotNull, "relaxNotNull");
|
|
1708
1829
|
async function indexExists(db, dialect, table, index4) {
|
|
1709
1830
|
let query;
|
|
1710
1831
|
if (dialect === "sqlite") {
|
|
@@ -1718,7 +1839,8 @@ async function indexExists(db, dialect, table, index4) {
|
|
|
1718
1839
|
}
|
|
1719
1840
|
__name(indexExists, "indexExists");
|
|
1720
1841
|
async function heal(db, dialect) {
|
|
1721
|
-
|
|
1842
|
+
const all = specs(dialect);
|
|
1843
|
+
for (const spec of all) {
|
|
1722
1844
|
await runSql(db, dialect, import_drizzle_orm2.sql.raw(createTableSql(dialect, spec)));
|
|
1723
1845
|
const present = await existingColumns(db, dialect, spec.name);
|
|
1724
1846
|
for (const column of spec.columns) {
|
|
@@ -1726,6 +1848,13 @@ async function heal(db, dialect) {
|
|
|
1726
1848
|
await runSql(db, dialect, import_drizzle_orm2.sql.raw(`ALTER TABLE ${quote(dialect, spec.name)} ADD COLUMN ${columnDefinition(dialect, column)}`));
|
|
1727
1849
|
}
|
|
1728
1850
|
}
|
|
1851
|
+
const nullable3 = await columnNullability(db, dialect, spec.name);
|
|
1852
|
+
for (const column of spec.columns) {
|
|
1853
|
+
if (column.notNull || spec.primaryKey.includes(column.name)) continue;
|
|
1854
|
+
if (nullable3.get(column.name) === false) {
|
|
1855
|
+
await relaxNotNull(db, dialect, spec, column, all);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1729
1858
|
for (const index4 of spec.indexes) {
|
|
1730
1859
|
if (!await indexExists(db, dialect, spec.name, index4.name)) {
|
|
1731
1860
|
await runSql(db, dialect, import_drizzle_orm2.sql.raw(createIndexSql(dialect, spec.name, index4)));
|
|
@@ -2499,7 +2628,7 @@ var DrizzleAgentStore = class {
|
|
|
2499
2628
|
deletedAt: /* @__PURE__ */ new Date()
|
|
2500
2629
|
}).where((0, import_drizzle_orm4.eq)(this.t.agentThread.id, threadId));
|
|
2501
2630
|
}
|
|
2502
|
-
async forkThread(threadId, fromMessageId) {
|
|
2631
|
+
async forkThread(threadId, fromMessageId, options = {}) {
|
|
2503
2632
|
const [source] = await this.db.select().from(this.t.agentThread).where((0, import_drizzle_orm4.eq)(this.t.agentThread.id, threadId));
|
|
2504
2633
|
if (source === void 0) {
|
|
2505
2634
|
throw new Error(`thread ${threadId} not found`);
|
|
@@ -2510,8 +2639,8 @@ var DrizzleAgentStore = class {
|
|
|
2510
2639
|
const now = /* @__PURE__ */ new Date();
|
|
2511
2640
|
const fork = {
|
|
2512
2641
|
id: crypto.randomUUID(),
|
|
2513
|
-
actorRef: source.actorRef,
|
|
2514
|
-
tenantRef: source.tenantRef,
|
|
2642
|
+
actorRef: options.actorRef ?? source.actorRef,
|
|
2643
|
+
tenantRef: options.tenantRef !== void 0 ? options.tenantRef : source.tenantRef,
|
|
2515
2644
|
title: source.title,
|
|
2516
2645
|
transient: false,
|
|
2517
2646
|
activeStreamId: null,
|
|
@@ -2916,7 +3045,13 @@ var DrizzleAgentStore = class {
|
|
|
2916
3045
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2917
3046
|
settledAt: null,
|
|
2918
3047
|
promptHash: run.promptHash ?? null,
|
|
2919
|
-
parentRunId: run.parentRunId ?? null
|
|
3048
|
+
parentRunId: run.parentRunId ?? null,
|
|
3049
|
+
queueMs: run.queueMs !== void 0 ? Math.max(0, Math.round(run.queueMs)) : null,
|
|
3050
|
+
modelMs: null,
|
|
3051
|
+
toolsMs: null,
|
|
3052
|
+
modelCalls: null,
|
|
3053
|
+
toolCalls: null,
|
|
3054
|
+
timings: null
|
|
2920
3055
|
};
|
|
2921
3056
|
await this.db.insert(this.t.agentRun).values(runRow);
|
|
2922
3057
|
}
|
|
@@ -2944,6 +3079,13 @@ var DrizzleAgentStore = class {
|
|
|
2944
3079
|
if (end.errorMessage !== void 0) {
|
|
2945
3080
|
updates.errorMessage = end.errorMessage;
|
|
2946
3081
|
}
|
|
3082
|
+
if (end.timings !== void 0) {
|
|
3083
|
+
updates.modelMs = Math.round(end.timings.modelMs);
|
|
3084
|
+
updates.toolsMs = Math.round(end.timings.toolsMs);
|
|
3085
|
+
updates.modelCalls = end.timings.modelCalls;
|
|
3086
|
+
updates.toolCalls = end.timings.toolCalls;
|
|
3087
|
+
updates.timings = end.timings.steps;
|
|
3088
|
+
}
|
|
2947
3089
|
await this.db.update(this.t.agentRun).set(updates).where((0, import_drizzle_orm4.eq)(this.t.agentRun.id, end.runId));
|
|
2948
3090
|
}
|
|
2949
3091
|
/** Bump the run's llm-step retry counter. Atomic `retries = retries + 1`, no read-modify-write. */
|
|
@@ -3146,9 +3288,17 @@ var DrizzleAgentStore = class {
|
|
|
3146
3288
|
async recordUsage(input) {
|
|
3147
3289
|
await this.db.insert(this.t.agentTokenUsage).values({
|
|
3148
3290
|
id: crypto.randomUUID(),
|
|
3149
|
-
threadId: input.threadId,
|
|
3291
|
+
threadId: input.threadId ?? null,
|
|
3150
3292
|
actorRef: input.actorRef,
|
|
3151
3293
|
messageId: input.messageId ?? null,
|
|
3294
|
+
runId: input.runId ?? null,
|
|
3295
|
+
feature: input.feature ?? null,
|
|
3296
|
+
provider: input.provider ?? null,
|
|
3297
|
+
tenantRef: input.tenantRef ?? null,
|
|
3298
|
+
audioSeconds: input.audioSeconds ?? null,
|
|
3299
|
+
characters: input.characters ?? null,
|
|
3300
|
+
requests: input.requests ?? null,
|
|
3301
|
+
metadata: input.metadata ?? null,
|
|
3152
3302
|
modelId: input.modelId,
|
|
3153
3303
|
purpose: input.purpose,
|
|
3154
3304
|
inputTokens: input.usage.inputTokens,
|
|
@@ -3466,10 +3616,26 @@ function toRecentRunRow(run) {
|
|
|
3466
3616
|
retries: run.retries,
|
|
3467
3617
|
startedAt: run.startedAt.toISOString(),
|
|
3468
3618
|
promptHash: run.promptHash ?? null,
|
|
3469
|
-
parentRunId: run.parentRunId ?? null
|
|
3619
|
+
parentRunId: run.parentRunId ?? null,
|
|
3620
|
+
queueMs: run.queueMs ?? null,
|
|
3621
|
+
modelMs: run.modelMs ?? null,
|
|
3622
|
+
toolsMs: run.toolsMs ?? null,
|
|
3623
|
+
modelCalls: run.modelCalls ?? null,
|
|
3624
|
+
toolCalls: run.toolCalls ?? null
|
|
3470
3625
|
};
|
|
3471
3626
|
}
|
|
3472
3627
|
__name(toRecentRunRow, "toRecentRunRow");
|
|
3628
|
+
function toRunTimings(run) {
|
|
3629
|
+
if (!Array.isArray(run.timings)) return null;
|
|
3630
|
+
return {
|
|
3631
|
+
modelMs: run.modelMs ?? 0,
|
|
3632
|
+
toolsMs: run.toolsMs ?? 0,
|
|
3633
|
+
modelCalls: run.modelCalls ?? 0,
|
|
3634
|
+
toolCalls: run.toolCalls ?? 0,
|
|
3635
|
+
steps: run.timings
|
|
3636
|
+
};
|
|
3637
|
+
}
|
|
3638
|
+
__name(toRunTimings, "toRunTimings");
|
|
3473
3639
|
function toRunToolCallRow(toolCall) {
|
|
3474
3640
|
return {
|
|
3475
3641
|
toolCallId: toolCall.id,
|
|
@@ -3485,6 +3651,12 @@ function toRunToolCallRow(toolCall) {
|
|
|
3485
3651
|
__name(toRunToolCallRow, "toRunToolCallRow");
|
|
3486
3652
|
function toUsageInput(row) {
|
|
3487
3653
|
return {
|
|
3654
|
+
feature: row.feature ?? null,
|
|
3655
|
+
purpose: row.purpose ?? null,
|
|
3656
|
+
costSource: row.costSource ?? null,
|
|
3657
|
+
audioSeconds: row.audioSeconds == null ? null : Number(row.audioSeconds),
|
|
3658
|
+
characters: row.characters == null ? null : Number(row.characters),
|
|
3659
|
+
requests: row.requests ?? null,
|
|
3488
3660
|
modelId: row.modelId,
|
|
3489
3661
|
actorRef: row.actorRef,
|
|
3490
3662
|
threadId: row.threadId,
|
|
@@ -3532,7 +3704,12 @@ var DrizzleGovernanceQueries = class {
|
|
|
3532
3704
|
}
|
|
3533
3705
|
return pricing;
|
|
3534
3706
|
}
|
|
3535
|
-
|
|
3707
|
+
/**
|
|
3708
|
+
* The usage rows in range, with only what the bucketers read: `requests` always (a recorded row
|
|
3709
|
+
* counts as its own requests in every rollup), and the feature/unit columns only for the
|
|
3710
|
+
* per-feature reads that group by them.
|
|
3711
|
+
*/
|
|
3712
|
+
async usageInRange(range, withFeature = false) {
|
|
3536
3713
|
const { start, end } = (0, import_nestjs_agent_core5.dayBoundsUtc)(range);
|
|
3537
3714
|
const usage = this.t.agentTokenUsage;
|
|
3538
3715
|
const rows = await this.db.select({
|
|
@@ -3544,7 +3721,15 @@ var DrizzleGovernanceQueries = class {
|
|
|
3544
3721
|
outputTokens: usage.outputTokens,
|
|
3545
3722
|
cacheWriteTokens: usage.cacheWriteTokens,
|
|
3546
3723
|
cacheReadTokens: usage.cacheReadTokens,
|
|
3547
|
-
costUsd: usage.costUsd
|
|
3724
|
+
costUsd: usage.costUsd,
|
|
3725
|
+
requests: usage.requests,
|
|
3726
|
+
...withFeature ? {
|
|
3727
|
+
feature: usage.feature,
|
|
3728
|
+
purpose: usage.purpose,
|
|
3729
|
+
costSource: usage.costSource,
|
|
3730
|
+
audioSeconds: usage.audioSeconds,
|
|
3731
|
+
characters: usage.characters
|
|
3732
|
+
} : {}
|
|
3548
3733
|
}).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)));
|
|
3549
3734
|
return rows.map(toUsageInput);
|
|
3550
3735
|
}
|
|
@@ -3552,6 +3737,14 @@ var DrizzleGovernanceQueries = class {
|
|
|
3552
3737
|
const pricing = await this.loadPricing();
|
|
3553
3738
|
return (0, import_nestjs_agent_core5.bucketByModel)(await this.usageInRange(range), pricing);
|
|
3554
3739
|
}
|
|
3740
|
+
async spendByFeature(range) {
|
|
3741
|
+
const pricing = await this.loadPricing();
|
|
3742
|
+
return (0, import_nestjs_agent_core5.bucketByFeature)(await this.usageInRange(range, true), pricing);
|
|
3743
|
+
}
|
|
3744
|
+
async usageBreakdown(range, filter) {
|
|
3745
|
+
const pricing = await this.loadPricing();
|
|
3746
|
+
return (0, import_nestjs_agent_core5.bucketUsageBreakdown)(await this.usageInRange(range, true), pricing, filter);
|
|
3747
|
+
}
|
|
3555
3748
|
async spendByActor(range) {
|
|
3556
3749
|
const pricing = await this.loadPricing();
|
|
3557
3750
|
return (0, import_nestjs_agent_core5.bucketByActor)(await this.usageInRange(range), pricing);
|
|
@@ -3565,7 +3758,9 @@ var DrizzleGovernanceQueries = class {
|
|
|
3565
3758
|
const pricing = await this.loadPricing();
|
|
3566
3759
|
const rows = await this.usageInRange(range);
|
|
3567
3760
|
const threadIds = [
|
|
3568
|
-
...new Set(rows.
|
|
3761
|
+
...new Set(rows.flatMap((row) => row.threadId === null ? [] : [
|
|
3762
|
+
row.threadId
|
|
3763
|
+
]))
|
|
3569
3764
|
];
|
|
3570
3765
|
if (threadIds.length === 0) {
|
|
3571
3766
|
return [];
|
|
@@ -3643,6 +3838,7 @@ var DrizzleGovernanceQueries = class {
|
|
|
3643
3838
|
outputTokens: (0, import_drizzle_orm5.sum)(this.t.agentTokenUsage.outputTokens)
|
|
3644
3839
|
}).from(this.t.agentTokenUsage).where((0, import_drizzle_orm5.inArray)(this.t.agentTokenUsage.threadId, threadIds)).groupBy(this.t.agentTokenUsage.threadId);
|
|
3645
3840
|
for (const row of usageTotals) {
|
|
3841
|
+
if (row.threadId === null) continue;
|
|
3646
3842
|
const bucket = rollups.get(row.threadId);
|
|
3647
3843
|
if (bucket !== void 0) {
|
|
3648
3844
|
bucket.totalTokens = Number(row.inputTokens ?? 0) + Number(row.outputTokens ?? 0);
|
|
@@ -4019,7 +4215,8 @@ var DrizzleGovernanceQueries = class {
|
|
|
4019
4215
|
actorRef: row.thread.actorRef,
|
|
4020
4216
|
deleted: row.thread.deletedAt != null
|
|
4021
4217
|
},
|
|
4022
|
-
toolCalls: toolCalls.map(toRunToolCallRow)
|
|
4218
|
+
toolCalls: toolCalls.map(toRunToolCallRow),
|
|
4219
|
+
timings: toRunTimings(row.run)
|
|
4023
4220
|
};
|
|
4024
4221
|
}
|
|
4025
4222
|
/**
|