@dudousxd/nestjs-agent-store-drizzle 0.34.0 → 0.36.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 +228 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1082 -19
- package/dist/index.d.ts +1082 -19
- package/dist/index.js +239 -33
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -178,7 +178,7 @@ var agentQueuedMessage = sqliteTable("agent_queued_message", {
|
|
|
178
178
|
]);
|
|
179
179
|
var agentTokenUsage = sqliteTable("agent_token_usage", {
|
|
180
180
|
id: text("id").primaryKey(),
|
|
181
|
-
threadId: text("thread_id").
|
|
181
|
+
threadId: text("thread_id").references(() => agentThread.id, {
|
|
182
182
|
onDelete: "cascade"
|
|
183
183
|
}),
|
|
184
184
|
actorRef: text("actor_ref").notNull(),
|
|
@@ -195,13 +195,32 @@ var agentTokenUsage = sqliteTable("agent_token_usage", {
|
|
|
195
195
|
costUsd: real("cost_usd"),
|
|
196
196
|
/** Where `cost_usd` came from: `'provider'` (reported) or `'estimate'` (tokens × the price row); null on rows from before it existed (reported). */
|
|
197
197
|
costSource: text("cost_source").$type(),
|
|
198
|
+
/** The run the row belongs to. */
|
|
199
|
+
runId: text("run_id"),
|
|
200
|
+
/** What the spend was for: `agent:<name>` for an agent turn, the app's own otherwise; null → `agent`. */
|
|
201
|
+
feature: text("feature"),
|
|
202
|
+
provider: text("provider"),
|
|
203
|
+
tenantRef: text("tenant_ref"),
|
|
204
|
+
/** Units a row bills by when they are not tokens. */
|
|
205
|
+
audioSeconds: real("audio_seconds"),
|
|
206
|
+
characters: integer("characters"),
|
|
207
|
+
requests: integer("requests"),
|
|
208
|
+
/** The caller's own JSON, never read by the library. */
|
|
209
|
+
metadata: text("metadata", {
|
|
210
|
+
mode: "json"
|
|
211
|
+
}).$type(),
|
|
212
|
+
/** `false` keeps the row out of the agent's quota windows (`recordUsage({ countsTowardsQuota: false })`). */
|
|
213
|
+
countsTowardsQuota: integer("counts_towards_quota", {
|
|
214
|
+
mode: "boolean"
|
|
215
|
+
}).notNull().default(true),
|
|
198
216
|
createdAt: integer("created_at", {
|
|
199
217
|
mode: "timestamp_ms"
|
|
200
218
|
}).notNull()
|
|
201
219
|
}, (table) => [
|
|
202
220
|
index("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
203
221
|
index("agent_token_usage_created_idx").on(table.createdAt),
|
|
204
|
-
index("agent_token_usage_thread_idx").on(table.threadId)
|
|
222
|
+
index("agent_token_usage_thread_idx").on(table.threadId),
|
|
223
|
+
index("agent_token_usage_feature_created_idx").on(table.feature, table.createdAt)
|
|
205
224
|
]);
|
|
206
225
|
var agentGenuiCall = sqliteTable("agent_genui_call", {
|
|
207
226
|
id: text("id").primaryKey(),
|
|
@@ -283,7 +302,17 @@ var agentRun = sqliteTable("agent_run", {
|
|
|
283
302
|
* for a detached child, which outlives its parent's turn and so is paired by nothing in the
|
|
284
303
|
* transcript.
|
|
285
304
|
*/
|
|
286
|
-
parentRunId: text("parent_run_id")
|
|
305
|
+
parentRunId: text("parent_run_id"),
|
|
306
|
+
/** Enqueue → body start (ms); null when not read. */
|
|
307
|
+
queueMs: integer("queue_ms"),
|
|
308
|
+
/** Where the completed run's time went: model and tool totals, counts, and the per-step list. */
|
|
309
|
+
modelMs: integer("model_ms"),
|
|
310
|
+
toolsMs: integer("tools_ms"),
|
|
311
|
+
modelCalls: integer("model_calls"),
|
|
312
|
+
toolCalls: integer("tool_calls"),
|
|
313
|
+
timings: text("timings", {
|
|
314
|
+
mode: "json"
|
|
315
|
+
}).$type()
|
|
287
316
|
}, (table) => [
|
|
288
317
|
index("agent_run_started_idx").on(table.startedAt)
|
|
289
318
|
]);
|
|
@@ -629,7 +658,7 @@ var agentQueuedMessage2 = mysqlTable("agent_queued_message", {
|
|
|
629
658
|
]);
|
|
630
659
|
var agentTokenUsage2 = mysqlTable("agent_token_usage", {
|
|
631
660
|
id: key("id").primaryKey(),
|
|
632
|
-
threadId: key("thread_id").
|
|
661
|
+
threadId: key("thread_id").references(() => agentThread2.id, {
|
|
633
662
|
onDelete: "cascade"
|
|
634
663
|
}),
|
|
635
664
|
actorRef: key("actor_ref").notNull(),
|
|
@@ -643,11 +672,28 @@ var agentTokenUsage2 = mysqlTable("agent_token_usage", {
|
|
|
643
672
|
costUsd: double("cost_usd"),
|
|
644
673
|
/** Where `cost_usd` came from: `'provider'` (reported) or `'estimate'` (tokens × the price row); null on rows from before it existed (reported). */
|
|
645
674
|
costSource: key("cost_source").$type(),
|
|
675
|
+
/** The run the row belongs to. */
|
|
676
|
+
runId: key("run_id"),
|
|
677
|
+
/** What the spend was for: `agent:<name>` for an agent turn, the app's own otherwise; null → `agent`. */
|
|
678
|
+
feature: key("feature"),
|
|
679
|
+
provider: key("provider"),
|
|
680
|
+
tenantRef: key("tenant_ref"),
|
|
681
|
+
/** Units a row bills by when they are not tokens. */
|
|
682
|
+
audioSeconds: double("audio_seconds"),
|
|
683
|
+
characters: bigint("characters", {
|
|
684
|
+
mode: "number"
|
|
685
|
+
}),
|
|
686
|
+
requests: int("requests"),
|
|
687
|
+
/** The caller's own JSON, never read by the library. */
|
|
688
|
+
metadata: json("metadata").$type(),
|
|
689
|
+
/** `false` keeps the row out of the agent's quota windows (`recordUsage({ countsTowardsQuota: false })`). */
|
|
690
|
+
countsTowardsQuota: boolean("counts_towards_quota").notNull().default(true),
|
|
646
691
|
createdAt: ts("created_at").notNull()
|
|
647
692
|
}, (table) => [
|
|
648
693
|
index2("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
649
694
|
index2("agent_token_usage_created_idx").on(table.createdAt),
|
|
650
|
-
index2("agent_token_usage_thread_idx").on(table.threadId)
|
|
695
|
+
index2("agent_token_usage_thread_idx").on(table.threadId),
|
|
696
|
+
index2("agent_token_usage_feature_created_idx").on(table.feature, table.createdAt)
|
|
651
697
|
]);
|
|
652
698
|
var agentGenuiCall2 = mysqlTable("agent_genui_call", {
|
|
653
699
|
id: key("id").primaryKey(),
|
|
@@ -719,7 +765,15 @@ var agentRun2 = mysqlTable("agent_run", {
|
|
|
719
765
|
startedAt: ts("started_at").notNull(),
|
|
720
766
|
settledAt: ts("settled_at"),
|
|
721
767
|
promptHash: key("prompt_hash"),
|
|
722
|
-
parentRunId: key("parent_run_id")
|
|
768
|
+
parentRunId: key("parent_run_id"),
|
|
769
|
+
/** Enqueue → body start (ms); null when not read. */
|
|
770
|
+
queueMs: int("queue_ms"),
|
|
771
|
+
/** Where the completed run's time went: model and tool totals, counts, and the per-step list. */
|
|
772
|
+
modelMs: int("model_ms"),
|
|
773
|
+
toolsMs: int("tools_ms"),
|
|
774
|
+
modelCalls: int("model_calls"),
|
|
775
|
+
toolCalls: int("tool_calls"),
|
|
776
|
+
timings: json("timings").$type()
|
|
723
777
|
}, (table) => [
|
|
724
778
|
index2("agent_run_started_idx").on(table.startedAt)
|
|
725
779
|
]);
|
|
@@ -1091,7 +1145,7 @@ var agentQueuedMessage3 = pgTable("agent_queued_message", {
|
|
|
1091
1145
|
]);
|
|
1092
1146
|
var agentTokenUsage3 = pgTable("agent_token_usage", {
|
|
1093
1147
|
id: text2("id").primaryKey(),
|
|
1094
|
-
threadId: text2("thread_id").
|
|
1148
|
+
threadId: text2("thread_id").references(() => agentThread3.id, {
|
|
1095
1149
|
onDelete: "cascade"
|
|
1096
1150
|
}),
|
|
1097
1151
|
actorRef: text2("actor_ref").notNull(),
|
|
@@ -1105,11 +1159,28 @@ var agentTokenUsage3 = pgTable("agent_token_usage", {
|
|
|
1105
1159
|
costUsd: doublePrecision("cost_usd"),
|
|
1106
1160
|
/** Where `cost_usd` came from: `'provider'` (reported) or `'estimate'` (tokens × the price row); null on rows from before it existed (reported). */
|
|
1107
1161
|
costSource: text2("cost_source").$type(),
|
|
1162
|
+
/** The run the row belongs to. */
|
|
1163
|
+
runId: text2("run_id"),
|
|
1164
|
+
/** What the spend was for: `agent:<name>` for an agent turn, the app's own otherwise; null → `agent`. */
|
|
1165
|
+
feature: text2("feature"),
|
|
1166
|
+
provider: text2("provider"),
|
|
1167
|
+
tenantRef: text2("tenant_ref"),
|
|
1168
|
+
/** Units a row bills by when they are not tokens. */
|
|
1169
|
+
audioSeconds: doublePrecision("audio_seconds"),
|
|
1170
|
+
characters: bigint2("characters", {
|
|
1171
|
+
mode: "number"
|
|
1172
|
+
}),
|
|
1173
|
+
requests: integer2("requests"),
|
|
1174
|
+
/** The caller's own JSON, never read by the library. */
|
|
1175
|
+
metadata: jsonb("metadata").$type(),
|
|
1176
|
+
/** `false` keeps the row out of the agent's quota windows (`recordUsage({ countsTowardsQuota: false })`). */
|
|
1177
|
+
countsTowardsQuota: boolean2("counts_towards_quota").notNull().default(true),
|
|
1108
1178
|
createdAt: ts2("created_at").notNull()
|
|
1109
1179
|
}, (table) => [
|
|
1110
1180
|
index3("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
|
|
1111
1181
|
index3("agent_token_usage_created_idx").on(table.createdAt),
|
|
1112
|
-
index3("agent_token_usage_thread_idx").on(table.threadId)
|
|
1182
|
+
index3("agent_token_usage_thread_idx").on(table.threadId),
|
|
1183
|
+
index3("agent_token_usage_feature_created_idx").on(table.feature, table.createdAt)
|
|
1113
1184
|
]);
|
|
1114
1185
|
var agentGenuiCall3 = pgTable("agent_genui_call", {
|
|
1115
1186
|
id: text2("id").primaryKey(),
|
|
@@ -1181,7 +1252,15 @@ var agentRun3 = pgTable("agent_run", {
|
|
|
1181
1252
|
startedAt: ts2("started_at").notNull(),
|
|
1182
1253
|
settledAt: ts2("settled_at"),
|
|
1183
1254
|
promptHash: text2("prompt_hash"),
|
|
1184
|
-
parentRunId: text2("parent_run_id")
|
|
1255
|
+
parentRunId: text2("parent_run_id"),
|
|
1256
|
+
/** Enqueue → body start (ms); null when not read. */
|
|
1257
|
+
queueMs: integer2("queue_ms"),
|
|
1258
|
+
/** Where the completed run's time went: model and tool totals, counts, and the per-step list. */
|
|
1259
|
+
modelMs: integer2("model_ms"),
|
|
1260
|
+
toolsMs: integer2("tools_ms"),
|
|
1261
|
+
modelCalls: integer2("model_calls"),
|
|
1262
|
+
toolCalls: integer2("tool_calls"),
|
|
1263
|
+
timings: jsonb("timings").$type()
|
|
1185
1264
|
}, (table) => [
|
|
1186
1265
|
index3("agent_run_started_idx").on(table.startedAt)
|
|
1187
1266
|
]);
|
|
@@ -1639,10 +1718,60 @@ function specs(dialect) {
|
|
|
1639
1718
|
}
|
|
1640
1719
|
__name(specs, "specs");
|
|
1641
1720
|
async function existingColumns(db, dialect, table) {
|
|
1642
|
-
|
|
1643
|
-
return new Set(rows.map((row) => String(row.name)));
|
|
1721
|
+
return new Set((await columnNullability(db, dialect, table)).keys());
|
|
1644
1722
|
}
|
|
1645
1723
|
__name(existingColumns, "existingColumns");
|
|
1724
|
+
async function columnNullability(db, dialect, table) {
|
|
1725
|
+
if (dialect === "sqlite") {
|
|
1726
|
+
const rows2 = await querySql(db, dialect, sql.raw(`PRAGMA table_info("${table}")`));
|
|
1727
|
+
return new Map(rows2.map((row) => [
|
|
1728
|
+
String(row.name),
|
|
1729
|
+
Number(row.notnull) === 0
|
|
1730
|
+
]));
|
|
1731
|
+
}
|
|
1732
|
+
const rows = await querySql(db, dialect, sql`select column_name as name, is_nullable as nullable from information_schema.columns where table_schema = ${sql.raw(dialect === "mysql" ? "database()" : "current_schema()")} and table_name = ${table}`);
|
|
1733
|
+
return new Map(rows.map((row) => [
|
|
1734
|
+
String(row.name ?? row.NAME),
|
|
1735
|
+
String(row.nullable ?? row.NULLABLE).toUpperCase() === "YES"
|
|
1736
|
+
]));
|
|
1737
|
+
}
|
|
1738
|
+
__name(columnNullability, "columnNullability");
|
|
1739
|
+
async function relaxNotNull(db, dialect, spec, column, all) {
|
|
1740
|
+
const q = /* @__PURE__ */ __name((identifier) => quote(dialect, identifier), "q");
|
|
1741
|
+
if (dialect === "postgres") {
|
|
1742
|
+
await runSql(db, dialect, sql.raw(`ALTER TABLE ${q(spec.name)} ALTER COLUMN ${q(column.name)} DROP NOT NULL`));
|
|
1743
|
+
return;
|
|
1744
|
+
}
|
|
1745
|
+
if (dialect === "mysql") {
|
|
1746
|
+
await runSql(db, dialect, sql.raw(`ALTER TABLE ${q(spec.name)} MODIFY ${columnDefinition(dialect, column)}`));
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
if (all.some((other) => other.foreignKeys.some((key2) => key2.table === spec.name && other !== spec))) {
|
|
1750
|
+
throw new Error(`agent schema: cannot make ${spec.name}.${column.name} nullable on SQLite \u2014 other tables reference ${spec.name}`);
|
|
1751
|
+
}
|
|
1752
|
+
const scratch = `${spec.name}__rebuild`;
|
|
1753
|
+
const present = [
|
|
1754
|
+
...(await columnNullability(db, dialect, spec.name)).keys()
|
|
1755
|
+
];
|
|
1756
|
+
const list = present.map(q).join(", ");
|
|
1757
|
+
await runSql(db, dialect, sql.raw("SAVEPOINT agent_schema_rebuild"));
|
|
1758
|
+
try {
|
|
1759
|
+
await runSql(db, dialect, sql.raw(`DROP TABLE IF EXISTS ${q(scratch)}`));
|
|
1760
|
+
await runSql(db, dialect, sql.raw(createTableSql(dialect, {
|
|
1761
|
+
...spec,
|
|
1762
|
+
name: scratch
|
|
1763
|
+
})));
|
|
1764
|
+
await runSql(db, dialect, sql.raw(`INSERT INTO ${q(scratch)} (${list}) SELECT ${list} FROM ${q(spec.name)}`));
|
|
1765
|
+
await runSql(db, dialect, sql.raw(`DROP TABLE ${q(spec.name)}`));
|
|
1766
|
+
await runSql(db, dialect, sql.raw(`ALTER TABLE ${q(scratch)} RENAME TO ${q(spec.name)}`));
|
|
1767
|
+
await runSql(db, dialect, sql.raw("RELEASE SAVEPOINT agent_schema_rebuild"));
|
|
1768
|
+
} catch (error) {
|
|
1769
|
+
await runSql(db, dialect, sql.raw("ROLLBACK TO SAVEPOINT agent_schema_rebuild")).catch(() => void 0);
|
|
1770
|
+
await runSql(db, dialect, sql.raw("RELEASE SAVEPOINT agent_schema_rebuild")).catch(() => void 0);
|
|
1771
|
+
throw error;
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
__name(relaxNotNull, "relaxNotNull");
|
|
1646
1775
|
async function indexExists(db, dialect, table, index4) {
|
|
1647
1776
|
let query;
|
|
1648
1777
|
if (dialect === "sqlite") {
|
|
@@ -1656,7 +1785,8 @@ async function indexExists(db, dialect, table, index4) {
|
|
|
1656
1785
|
}
|
|
1657
1786
|
__name(indexExists, "indexExists");
|
|
1658
1787
|
async function heal(db, dialect) {
|
|
1659
|
-
|
|
1788
|
+
const all = specs(dialect);
|
|
1789
|
+
for (const spec of all) {
|
|
1660
1790
|
await runSql(db, dialect, sql.raw(createTableSql(dialect, spec)));
|
|
1661
1791
|
const present = await existingColumns(db, dialect, spec.name);
|
|
1662
1792
|
for (const column of spec.columns) {
|
|
@@ -1664,6 +1794,13 @@ async function heal(db, dialect) {
|
|
|
1664
1794
|
await runSql(db, dialect, sql.raw(`ALTER TABLE ${quote(dialect, spec.name)} ADD COLUMN ${columnDefinition(dialect, column)}`));
|
|
1665
1795
|
}
|
|
1666
1796
|
}
|
|
1797
|
+
const nullable3 = await columnNullability(db, dialect, spec.name);
|
|
1798
|
+
for (const column of spec.columns) {
|
|
1799
|
+
if (column.notNull || spec.primaryKey.includes(column.name)) continue;
|
|
1800
|
+
if (nullable3.get(column.name) === false) {
|
|
1801
|
+
await relaxNotNull(db, dialect, spec, column, all);
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1667
1804
|
for (const index4 of spec.indexes) {
|
|
1668
1805
|
if (!await indexExists(db, dialect, spec.name, index4.name)) {
|
|
1669
1806
|
await runSql(db, dialect, sql.raw(createIndexSql(dialect, spec.name, index4)));
|
|
@@ -2854,7 +2991,13 @@ var DrizzleAgentStore = class {
|
|
|
2854
2991
|
startedAt: /* @__PURE__ */ new Date(),
|
|
2855
2992
|
settledAt: null,
|
|
2856
2993
|
promptHash: run.promptHash ?? null,
|
|
2857
|
-
parentRunId: run.parentRunId ?? null
|
|
2994
|
+
parentRunId: run.parentRunId ?? null,
|
|
2995
|
+
queueMs: run.queueMs !== void 0 ? Math.max(0, Math.round(run.queueMs)) : null,
|
|
2996
|
+
modelMs: null,
|
|
2997
|
+
toolsMs: null,
|
|
2998
|
+
modelCalls: null,
|
|
2999
|
+
toolCalls: null,
|
|
3000
|
+
timings: null
|
|
2858
3001
|
};
|
|
2859
3002
|
await this.db.insert(this.t.agentRun).values(runRow);
|
|
2860
3003
|
}
|
|
@@ -2882,6 +3025,13 @@ var DrizzleAgentStore = class {
|
|
|
2882
3025
|
if (end.errorMessage !== void 0) {
|
|
2883
3026
|
updates.errorMessage = end.errorMessage;
|
|
2884
3027
|
}
|
|
3028
|
+
if (end.timings !== void 0) {
|
|
3029
|
+
updates.modelMs = Math.round(end.timings.modelMs);
|
|
3030
|
+
updates.toolsMs = Math.round(end.timings.toolsMs);
|
|
3031
|
+
updates.modelCalls = end.timings.modelCalls;
|
|
3032
|
+
updates.toolCalls = end.timings.toolCalls;
|
|
3033
|
+
updates.timings = end.timings.steps;
|
|
3034
|
+
}
|
|
2885
3035
|
await this.db.update(this.t.agentRun).set(updates).where(eq2(this.t.agentRun.id, end.runId));
|
|
2886
3036
|
}
|
|
2887
3037
|
/** Bump the run's llm-step retry counter. Atomic `retries = retries + 1`, no read-modify-write. */
|
|
@@ -3084,9 +3234,18 @@ var DrizzleAgentStore = class {
|
|
|
3084
3234
|
async recordUsage(input) {
|
|
3085
3235
|
await this.db.insert(this.t.agentTokenUsage).values({
|
|
3086
3236
|
id: crypto.randomUUID(),
|
|
3087
|
-
threadId: input.threadId,
|
|
3237
|
+
threadId: input.threadId ?? null,
|
|
3088
3238
|
actorRef: input.actorRef,
|
|
3089
3239
|
messageId: input.messageId ?? null,
|
|
3240
|
+
runId: input.runId ?? null,
|
|
3241
|
+
feature: input.feature ?? null,
|
|
3242
|
+
provider: input.provider ?? null,
|
|
3243
|
+
tenantRef: input.tenantRef ?? null,
|
|
3244
|
+
audioSeconds: input.audioSeconds ?? null,
|
|
3245
|
+
characters: input.characters ?? null,
|
|
3246
|
+
requests: input.requests ?? null,
|
|
3247
|
+
metadata: input.metadata ?? null,
|
|
3248
|
+
countsTowardsQuota: input.countsTowardsQuota !== false,
|
|
3090
3249
|
modelId: input.modelId,
|
|
3091
3250
|
purpose: input.purpose,
|
|
3092
3251
|
inputTokens: input.usage.inputTokens,
|
|
@@ -3171,7 +3330,7 @@ var DrizzleAgentStore = class {
|
|
|
3171
3330
|
});
|
|
3172
3331
|
const from = new Date(Math.min(...bounds.map(({ start }) => start.getTime())));
|
|
3173
3332
|
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)));
|
|
3333
|
+
const [row] = await this.db.select(columns).from(usage).where(and2(eq2(usage.actorRef, actorRef), within(from, to), eq2(usage.countsTowardsQuota, true)));
|
|
3175
3334
|
return bounds.map((_, index4) => ({
|
|
3176
3335
|
usedTokens: Number(row?.[`tokens${index4}`] ?? 0),
|
|
3177
3336
|
costUsd: Number(row?.[`cost${index4}`] ?? 0),
|
|
@@ -3282,8 +3441,8 @@ function toQueuedMessage(row) {
|
|
|
3282
3441
|
__name(toQueuedMessage, "toQueuedMessage");
|
|
3283
3442
|
|
|
3284
3443
|
// src/drizzle-governance-queries.ts
|
|
3285
|
-
import { bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, rollupThreadUsage, summarizeGenuiCalls, truncateDetailContent } from "@dudousxd/nestjs-agent-core";
|
|
3286
|
-
import { and as and3, asc as asc3, count, desc as desc2, eq as eq3, gte as gte2, inArray as inArray2, isNull as isNull3, like, lte as lte3, sql as sql4, sum } from "drizzle-orm";
|
|
3444
|
+
import { bucketByActor, bucketByFeature, bucketByModel, bucketByThread, bucketUsageBreakdown, bucketUsageTrend, dayBoundsUtc, rollupThreadUsage, summarizeGenuiCalls, truncateDetailContent, usageRangeBounds } from "@dudousxd/nestjs-agent-core";
|
|
3445
|
+
import { and as and3, asc as asc3, count, desc as desc2, eq as eq3, gte as gte2, inArray as inArray2, isNull as isNull3, like, lt, lte as lte3, sql as sql4, sum } from "drizzle-orm";
|
|
3287
3446
|
var UNCLASSIFIED_ERROR_CODE = "unknown";
|
|
3288
3447
|
var DEFAULT_AGENT_BUCKET = "(default)";
|
|
3289
3448
|
var TOOL_CALL_STATUSES = [
|
|
@@ -3404,10 +3563,26 @@ function toRecentRunRow(run) {
|
|
|
3404
3563
|
retries: run.retries,
|
|
3405
3564
|
startedAt: run.startedAt.toISOString(),
|
|
3406
3565
|
promptHash: run.promptHash ?? null,
|
|
3407
|
-
parentRunId: run.parentRunId ?? null
|
|
3566
|
+
parentRunId: run.parentRunId ?? null,
|
|
3567
|
+
queueMs: run.queueMs ?? null,
|
|
3568
|
+
modelMs: run.modelMs ?? null,
|
|
3569
|
+
toolsMs: run.toolsMs ?? null,
|
|
3570
|
+
modelCalls: run.modelCalls ?? null,
|
|
3571
|
+
toolCalls: run.toolCalls ?? null
|
|
3408
3572
|
};
|
|
3409
3573
|
}
|
|
3410
3574
|
__name(toRecentRunRow, "toRecentRunRow");
|
|
3575
|
+
function toRunTimings(run) {
|
|
3576
|
+
if (!Array.isArray(run.timings)) return null;
|
|
3577
|
+
return {
|
|
3578
|
+
modelMs: run.modelMs ?? 0,
|
|
3579
|
+
toolsMs: run.toolsMs ?? 0,
|
|
3580
|
+
modelCalls: run.modelCalls ?? 0,
|
|
3581
|
+
toolCalls: run.toolCalls ?? 0,
|
|
3582
|
+
steps: run.timings
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
__name(toRunTimings, "toRunTimings");
|
|
3411
3586
|
function toRunToolCallRow(toolCall) {
|
|
3412
3587
|
return {
|
|
3413
3588
|
toolCallId: toolCall.id,
|
|
@@ -3423,6 +3598,12 @@ function toRunToolCallRow(toolCall) {
|
|
|
3423
3598
|
__name(toRunToolCallRow, "toRunToolCallRow");
|
|
3424
3599
|
function toUsageInput(row) {
|
|
3425
3600
|
return {
|
|
3601
|
+
feature: row.feature ?? null,
|
|
3602
|
+
purpose: row.purpose ?? null,
|
|
3603
|
+
costSource: row.costSource ?? null,
|
|
3604
|
+
audioSeconds: row.audioSeconds == null ? null : Number(row.audioSeconds),
|
|
3605
|
+
characters: row.characters == null ? null : Number(row.characters),
|
|
3606
|
+
requests: row.requests ?? null,
|
|
3426
3607
|
modelId: row.modelId,
|
|
3427
3608
|
actorRef: row.actorRef,
|
|
3428
3609
|
threadId: row.threadId,
|
|
@@ -3470,8 +3651,13 @@ var DrizzleGovernanceQueries = class {
|
|
|
3470
3651
|
}
|
|
3471
3652
|
return pricing;
|
|
3472
3653
|
}
|
|
3473
|
-
|
|
3474
|
-
|
|
3654
|
+
/**
|
|
3655
|
+
* The usage rows in range, with only what the bucketers read: `requests` always (a recorded row
|
|
3656
|
+
* counts as its own requests in every rollup), and the feature/unit columns only for the
|
|
3657
|
+
* per-feature reads that group by them.
|
|
3658
|
+
*/
|
|
3659
|
+
async usageInRange(range, withFeature = false) {
|
|
3660
|
+
const { start, end } = usageRangeBounds(range);
|
|
3475
3661
|
const usage = this.t.agentTokenUsage;
|
|
3476
3662
|
const rows = await this.db.select({
|
|
3477
3663
|
modelId: usage.modelId,
|
|
@@ -3482,14 +3668,30 @@ var DrizzleGovernanceQueries = class {
|
|
|
3482
3668
|
outputTokens: usage.outputTokens,
|
|
3483
3669
|
cacheWriteTokens: usage.cacheWriteTokens,
|
|
3484
3670
|
cacheReadTokens: usage.cacheReadTokens,
|
|
3485
|
-
costUsd: usage.costUsd
|
|
3486
|
-
|
|
3671
|
+
costUsd: usage.costUsd,
|
|
3672
|
+
requests: usage.requests,
|
|
3673
|
+
...withFeature ? {
|
|
3674
|
+
feature: usage.feature,
|
|
3675
|
+
purpose: usage.purpose,
|
|
3676
|
+
costSource: usage.costSource,
|
|
3677
|
+
audioSeconds: usage.audioSeconds,
|
|
3678
|
+
characters: usage.characters
|
|
3679
|
+
} : {}
|
|
3680
|
+
}).from(usage).where(and3(gte2(this.t.agentTokenUsage.createdAt, start), lt(this.t.agentTokenUsage.createdAt, end)));
|
|
3487
3681
|
return rows.map(toUsageInput);
|
|
3488
3682
|
}
|
|
3489
3683
|
async spendByModel(range) {
|
|
3490
3684
|
const pricing = await this.loadPricing();
|
|
3491
3685
|
return bucketByModel(await this.usageInRange(range), pricing);
|
|
3492
3686
|
}
|
|
3687
|
+
async spendByFeature(range) {
|
|
3688
|
+
const pricing = await this.loadPricing();
|
|
3689
|
+
return bucketByFeature(await this.usageInRange(range, true), pricing);
|
|
3690
|
+
}
|
|
3691
|
+
async usageBreakdown(range, filter) {
|
|
3692
|
+
const pricing = await this.loadPricing();
|
|
3693
|
+
return bucketUsageBreakdown(await this.usageInRange(range, true), pricing, filter);
|
|
3694
|
+
}
|
|
3493
3695
|
async spendByActor(range) {
|
|
3494
3696
|
const pricing = await this.loadPricing();
|
|
3495
3697
|
return bucketByActor(await this.usageInRange(range), pricing);
|
|
@@ -3503,7 +3705,9 @@ var DrizzleGovernanceQueries = class {
|
|
|
3503
3705
|
const pricing = await this.loadPricing();
|
|
3504
3706
|
const rows = await this.usageInRange(range);
|
|
3505
3707
|
const threadIds = [
|
|
3506
|
-
...new Set(rows.
|
|
3708
|
+
...new Set(rows.flatMap((row) => row.threadId === null ? [] : [
|
|
3709
|
+
row.threadId
|
|
3710
|
+
]))
|
|
3507
3711
|
];
|
|
3508
3712
|
if (threadIds.length === 0) {
|
|
3509
3713
|
return [];
|
|
@@ -3581,6 +3785,7 @@ var DrizzleGovernanceQueries = class {
|
|
|
3581
3785
|
outputTokens: sum(this.t.agentTokenUsage.outputTokens)
|
|
3582
3786
|
}).from(this.t.agentTokenUsage).where(inArray2(this.t.agentTokenUsage.threadId, threadIds)).groupBy(this.t.agentTokenUsage.threadId);
|
|
3583
3787
|
for (const row of usageTotals) {
|
|
3788
|
+
if (row.threadId === null) continue;
|
|
3584
3789
|
const bucket = rollups.get(row.threadId);
|
|
3585
3790
|
if (bucket !== void 0) {
|
|
3586
3791
|
bucket.totalTokens = Number(row.inputTokens ?? 0) + Number(row.outputTokens ?? 0);
|
|
@@ -3957,7 +4162,8 @@ var DrizzleGovernanceQueries = class {
|
|
|
3957
4162
|
actorRef: row.thread.actorRef,
|
|
3958
4163
|
deleted: row.thread.deletedAt != null
|
|
3959
4164
|
},
|
|
3960
|
-
toolCalls: toolCalls.map(toRunToolCallRow)
|
|
4165
|
+
toolCalls: toolCalls.map(toRunToolCallRow),
|
|
4166
|
+
timings: toRunTimings(row.run)
|
|
3961
4167
|
};
|
|
3962
4168
|
}
|
|
3963
4169
|
/**
|
|
@@ -4241,7 +4447,7 @@ var DrizzlePricingStore = class {
|
|
|
4241
4447
|
|
|
4242
4448
|
// src/drizzle-token-stream-sink.ts
|
|
4243
4449
|
import { SqlTokenStreamSink } from "@dudousxd/nestjs-agent-core";
|
|
4244
|
-
import { and as and6, asc as asc4, eq as eq6, gt as gt2, inArray as inArray4, lt, max as max3, sql as sql5 } from "drizzle-orm";
|
|
4450
|
+
import { and as and6, asc as asc4, eq as eq6, gt as gt2, inArray as inArray4, lt as lt2, max as max3, sql as sql5 } from "drizzle-orm";
|
|
4245
4451
|
var DrizzleStreamFrameTable = class {
|
|
4246
4452
|
static {
|
|
4247
4453
|
__name(this, "DrizzleStreamFrameTable");
|
|
@@ -4281,7 +4487,7 @@ var DrizzleStreamFrameTable = class {
|
|
|
4281
4487
|
async lapsedRuns(cutoff) {
|
|
4282
4488
|
const rows = await this.db.select({
|
|
4283
4489
|
runId: this.t.agentStreamFrame.runId
|
|
4284
|
-
}).from(this.t.agentStreamFrame).groupBy(this.t.agentStreamFrame.runId).having(
|
|
4490
|
+
}).from(this.t.agentStreamFrame).groupBy(this.t.agentStreamFrame.runId).having(lt2(max3(this.t.agentStreamFrame.createdAt), cutoff));
|
|
4285
4491
|
return rows.map((row) => row.runId);
|
|
4286
4492
|
}
|
|
4287
4493
|
isUniqueViolation(error) {
|
|
@@ -4298,7 +4504,7 @@ var DrizzleTokenStreamSink = class extends SqlTokenStreamSink {
|
|
|
4298
4504
|
};
|
|
4299
4505
|
|
|
4300
4506
|
// src/drizzle-confirm-token-store.ts
|
|
4301
|
-
import { eq as eq7, lt as
|
|
4507
|
+
import { eq as eq7, lt as lt3 } from "drizzle-orm";
|
|
4302
4508
|
var DrizzleConfirmTokenStore = class {
|
|
4303
4509
|
static {
|
|
4304
4510
|
__name(this, "DrizzleConfirmTokenStore");
|
|
@@ -4332,7 +4538,7 @@ var DrizzleConfirmTokenStore = class {
|
|
|
4332
4538
|
}
|
|
4333
4539
|
async purgeExpired(now = Date.now()) {
|
|
4334
4540
|
const table = this.t.agentConfirmToken;
|
|
4335
|
-
return affectedRows(this.dialect, this.db.delete(table).where(
|
|
4541
|
+
return affectedRows(this.dialect, this.db.delete(table).where(lt3(table.expiresAt, now)), table.hash);
|
|
4336
4542
|
}
|
|
4337
4543
|
};
|
|
4338
4544
|
|
|
@@ -4410,7 +4616,7 @@ var DrizzleChannelStore = class {
|
|
|
4410
4616
|
|
|
4411
4617
|
// src/drizzle-poppy-store.ts
|
|
4412
4618
|
import { newEventId } from "@dudousxd/nestjs-agent-core";
|
|
4413
|
-
import { and as and8, desc as desc3, eq as eq9, gt as gt4, isNull as isNull4, lt as
|
|
4619
|
+
import { and as and8, desc as desc3, eq as eq9, gt as gt4, isNull as isNull4, lt as lt4, lte as lte5, or as or3 } from "drizzle-orm";
|
|
4414
4620
|
var MAX_APPEND_ATTEMPTS = 50;
|
|
4415
4621
|
var sleep = /* @__PURE__ */ __name((ms) => new Promise((resolve) => setTimeout(resolve, ms)), "sleep");
|
|
4416
4622
|
var nullable = /* @__PURE__ */ __name((value) => value == null ? null : String(value), "nullable");
|
|
@@ -4595,13 +4801,13 @@ var DrizzlePoppyStore = class {
|
|
|
4595
4801
|
if (!last) return;
|
|
4596
4802
|
const [dropped] = await this.db.select({
|
|
4597
4803
|
seq: table.seq
|
|
4598
|
-
}).from(table).where(and8(eq9(table.conversationId, conversationId),
|
|
4804
|
+
}).from(table).where(and8(eq9(table.conversationId, conversationId), lt4(table.createdAt, before), lt4(table.seq, toInt(last.seq)))).orderBy(desc3(table.seq)).limit(1);
|
|
4599
4805
|
if (!dropped) return;
|
|
4600
4806
|
const upTo = toInt(dropped.seq);
|
|
4601
4807
|
const conversations = this.t.agentPoppyConversation;
|
|
4602
4808
|
await this.db.update(conversations).set({
|
|
4603
4809
|
prunedSeq: upTo
|
|
4604
|
-
}).where(and8(eq9(conversations.id, conversationId),
|
|
4810
|
+
}).where(and8(eq9(conversations.id, conversationId), lt4(conversations.prunedSeq, upTo)));
|
|
4605
4811
|
await this.db.delete(table).where(and8(eq9(table.conversationId, conversationId), lte5(table.seq, upTo)));
|
|
4606
4812
|
}
|
|
4607
4813
|
async claimMessage(owner, messageId, receipt) {
|
|
@@ -4789,7 +4995,7 @@ __name(toConnection, "toConnection");
|
|
|
4789
4995
|
// src/drizzle-rag-ingestion-log.ts
|
|
4790
4996
|
import { subscribe, unsubscribe } from "diagnostics_channel";
|
|
4791
4997
|
import { Injectable, Logger } from "@nestjs/common";
|
|
4792
|
-
import { and as and10, asc as asc6, count as count2, desc as desc4, eq as eq11, gt as gt5, lt as
|
|
4998
|
+
import { and as and10, asc as asc6, count as count2, desc as desc4, eq as eq11, gt as gt5, lt as lt5, or as or4 } from "drizzle-orm";
|
|
4793
4999
|
function _ts_decorate(decorators, target, key2, desc5) {
|
|
4794
5000
|
var c = arguments.length, r = c < 3 ? target : desc5 === null ? desc5 = Object.getOwnPropertyDescriptor(target, key2) : desc5, d;
|
|
4795
5001
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
|
|
@@ -5043,7 +5249,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
|
|
|
5043
5249
|
if (cursor === void 0) {
|
|
5044
5250
|
return base;
|
|
5045
5251
|
}
|
|
5046
|
-
return and10(base, or4(
|
|
5252
|
+
return and10(base, or4(lt5(this.t.ragIngestionLog.updatedAt, cursor.updatedAt), and10(eq11(this.t.ragIngestionLog.updatedAt, cursor.updatedAt), gt5(this.t.ragIngestionLog.documentId, cursor.documentId))));
|
|
5047
5253
|
}
|
|
5048
5254
|
/**
|
|
5049
5255
|
* Upsert one outcome. Keyed by document id so the row always reflects the *current* state — a
|