@dudousxd/nestjs-agent-store-drizzle 0.1.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 ADDED
@@ -0,0 +1,784 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc3) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc3 = __getOwnPropDesc(from, key)) || desc3.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ DrizzleAgentStore: () => DrizzleAgentStore,
25
+ DrizzleAgentStoreModule: () => DrizzleAgentStoreModule,
26
+ DrizzleGovernanceQueries: () => DrizzleGovernanceQueries,
27
+ DrizzlePricingStore: () => DrizzlePricingStore,
28
+ agentMessage: () => agentMessage,
29
+ agentModelPricing: () => agentModelPricing,
30
+ agentSchema: () => agentSchema,
31
+ agentThread: () => agentThread,
32
+ agentTokenUsage: () => agentTokenUsage,
33
+ agentToolCall: () => agentToolCall,
34
+ ensureAgentSchema: () => ensureAgentSchema
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/schema.ts
39
+ var import_sqlite_core = require("drizzle-orm/sqlite-core");
40
+ var agentThread = (0, import_sqlite_core.sqliteTable)("agent_thread", {
41
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
42
+ actorRef: (0, import_sqlite_core.text)("actor_ref").notNull(),
43
+ tenantRef: (0, import_sqlite_core.text)("tenant_ref"),
44
+ title: (0, import_sqlite_core.text)("title").notNull(),
45
+ persona: (0, import_sqlite_core.text)("persona").notNull().default("default"),
46
+ transient: (0, import_sqlite_core.integer)("transient", {
47
+ mode: "boolean"
48
+ }).notNull().default(false),
49
+ activeStreamId: (0, import_sqlite_core.text)("active_stream_id"),
50
+ createdAt: (0, import_sqlite_core.integer)("created_at", {
51
+ mode: "timestamp_ms"
52
+ }).notNull(),
53
+ updatedAt: (0, import_sqlite_core.integer)("updated_at", {
54
+ mode: "timestamp_ms"
55
+ }).notNull(),
56
+ deletedAt: (0, import_sqlite_core.integer)("deleted_at", {
57
+ mode: "timestamp_ms"
58
+ })
59
+ }, (table) => [
60
+ (0, import_sqlite_core.index)("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
61
+ ]);
62
+ var agentMessage = (0, import_sqlite_core.sqliteTable)("agent_message", {
63
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
64
+ threadId: (0, import_sqlite_core.text)("thread_id").notNull().references(() => agentThread.id, {
65
+ onDelete: "cascade"
66
+ }),
67
+ role: (0, import_sqlite_core.text)("role").$type().notNull(),
68
+ content: (0, import_sqlite_core.text)("content").notNull(),
69
+ toolCalls: (0, import_sqlite_core.text)("tool_calls", {
70
+ mode: "json"
71
+ }).$type(),
72
+ toolResults: (0, import_sqlite_core.text)("tool_results", {
73
+ mode: "json"
74
+ }).$type(),
75
+ followUps: (0, import_sqlite_core.text)("follow_ups", {
76
+ mode: "json"
77
+ }).$type(),
78
+ usage: (0, import_sqlite_core.text)("usage", {
79
+ mode: "json"
80
+ }).$type(),
81
+ persona: (0, import_sqlite_core.text)("persona"),
82
+ createdAt: (0, import_sqlite_core.integer)("created_at", {
83
+ mode: "timestamp_ms"
84
+ }).notNull()
85
+ }, (table) => [
86
+ (0, import_sqlite_core.index)("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
87
+ ]);
88
+ var agentToolCall = (0, import_sqlite_core.sqliteTable)("agent_tool_call", {
89
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
90
+ messageId: (0, import_sqlite_core.text)("message_id").notNull().references(() => agentMessage.id, {
91
+ onDelete: "cascade"
92
+ }),
93
+ toolName: (0, import_sqlite_core.text)("tool_name").notNull(),
94
+ toolType: (0, import_sqlite_core.text)("tool_type").$type().notNull(),
95
+ input: (0, import_sqlite_core.text)("input", {
96
+ mode: "json"
97
+ }),
98
+ output: (0, import_sqlite_core.text)("output", {
99
+ mode: "json"
100
+ }),
101
+ status: (0, import_sqlite_core.text)("status").$type().notNull(),
102
+ executedByRef: (0, import_sqlite_core.text)("executed_by_ref"),
103
+ executionMs: (0, import_sqlite_core.integer)("execution_ms"),
104
+ error: (0, import_sqlite_core.text)("error"),
105
+ createdAt: (0, import_sqlite_core.integer)("created_at", {
106
+ mode: "timestamp_ms"
107
+ }).notNull(),
108
+ executedAt: (0, import_sqlite_core.integer)("executed_at", {
109
+ mode: "timestamp_ms"
110
+ })
111
+ });
112
+ var agentTokenUsage = (0, import_sqlite_core.sqliteTable)("agent_token_usage", {
113
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
114
+ threadId: (0, import_sqlite_core.text)("thread_id").notNull().references(() => agentThread.id, {
115
+ onDelete: "cascade"
116
+ }),
117
+ actorRef: (0, import_sqlite_core.text)("actor_ref").notNull(),
118
+ messageId: (0, import_sqlite_core.text)("message_id"),
119
+ modelId: (0, import_sqlite_core.text)("model_id").notNull(),
120
+ purpose: (0, import_sqlite_core.text)("purpose").$type().notNull(),
121
+ inputTokens: (0, import_sqlite_core.integer)("input_tokens").notNull(),
122
+ outputTokens: (0, import_sqlite_core.integer)("output_tokens").notNull(),
123
+ /** Subset of `inputTokens` written to the prompt cache this turn; null when not reported. */
124
+ cacheWriteTokens: (0, import_sqlite_core.integer)("cache_write_tokens"),
125
+ /** Subset of `inputTokens` served from the prompt cache this turn; null when not reported. */
126
+ cacheReadTokens: (0, import_sqlite_core.integer)("cache_read_tokens"),
127
+ /** Provider-reported actual USD cost for the turn; null when only tokens were reported. */
128
+ costUsd: (0, import_sqlite_core.real)("cost_usd"),
129
+ createdAt: (0, import_sqlite_core.integer)("created_at", {
130
+ mode: "timestamp_ms"
131
+ }).notNull()
132
+ }, (table) => [
133
+ (0, import_sqlite_core.index)("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
134
+ ]);
135
+ var agentModelPricing = (0, import_sqlite_core.sqliteTable)("agent_model_pricing", {
136
+ id: (0, import_sqlite_core.text)("id").primaryKey(),
137
+ modelId: (0, import_sqlite_core.text)("model_id").notNull(),
138
+ inputPricePer1m: (0, import_sqlite_core.real)("input_price_per_1m").notNull(),
139
+ outputPricePer1m: (0, import_sqlite_core.real)("output_price_per_1m").notNull(),
140
+ /** Per-1M price for cache-write input tokens; null → price them at the input rate. */
141
+ cacheWritePricePer1m: (0, import_sqlite_core.real)("cache_write_price_per_1m"),
142
+ /** Per-1M price for cache-read input tokens; null → price them at the input rate. */
143
+ cacheReadPricePer1m: (0, import_sqlite_core.real)("cache_read_price_per_1m"),
144
+ effectiveFrom: (0, import_sqlite_core.integer)("effective_from", {
145
+ mode: "timestamp_ms"
146
+ }).notNull(),
147
+ isCurrent: (0, import_sqlite_core.integer)("is_current", {
148
+ mode: "boolean"
149
+ }).notNull()
150
+ });
151
+ var agentSchema = {
152
+ agentThread,
153
+ agentMessage,
154
+ agentToolCall,
155
+ agentTokenUsage,
156
+ agentModelPricing
157
+ };
158
+
159
+ // src/ensure-schema.ts
160
+ var import_drizzle_orm = require("drizzle-orm");
161
+ var statements = [
162
+ `CREATE TABLE IF NOT EXISTS agent_thread (
163
+ id TEXT PRIMARY KEY NOT NULL,
164
+ actor_ref TEXT NOT NULL,
165
+ tenant_ref TEXT,
166
+ title TEXT NOT NULL,
167
+ persona TEXT NOT NULL DEFAULT 'default',
168
+ transient INTEGER NOT NULL DEFAULT 0,
169
+ active_stream_id TEXT,
170
+ created_at INTEGER NOT NULL,
171
+ updated_at INTEGER NOT NULL,
172
+ deleted_at INTEGER
173
+ )`,
174
+ `CREATE INDEX IF NOT EXISTS agent_thread_actor_updated_idx
175
+ ON agent_thread (actor_ref, updated_at)`,
176
+ `CREATE TABLE IF NOT EXISTS agent_message (
177
+ id TEXT PRIMARY KEY NOT NULL,
178
+ thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,
179
+ role TEXT NOT NULL,
180
+ content TEXT NOT NULL,
181
+ tool_calls TEXT,
182
+ tool_results TEXT,
183
+ follow_ups TEXT,
184
+ usage TEXT,
185
+ persona TEXT,
186
+ created_at INTEGER NOT NULL
187
+ )`,
188
+ `CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx
189
+ ON agent_message (thread_id, created_at)`,
190
+ `CREATE TABLE IF NOT EXISTS agent_tool_call (
191
+ id TEXT PRIMARY KEY NOT NULL,
192
+ message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,
193
+ tool_name TEXT NOT NULL,
194
+ tool_type TEXT NOT NULL,
195
+ input TEXT,
196
+ output TEXT,
197
+ status TEXT NOT NULL,
198
+ executed_by_ref TEXT,
199
+ execution_ms INTEGER,
200
+ error TEXT,
201
+ created_at INTEGER NOT NULL,
202
+ executed_at INTEGER
203
+ )`,
204
+ `CREATE TABLE IF NOT EXISTS agent_token_usage (
205
+ id TEXT PRIMARY KEY NOT NULL,
206
+ thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,
207
+ actor_ref TEXT NOT NULL,
208
+ message_id TEXT,
209
+ model_id TEXT NOT NULL,
210
+ purpose TEXT NOT NULL,
211
+ input_tokens INTEGER NOT NULL,
212
+ output_tokens INTEGER NOT NULL,
213
+ cache_write_tokens INTEGER,
214
+ cache_read_tokens INTEGER,
215
+ cost_usd REAL,
216
+ created_at INTEGER NOT NULL
217
+ )`,
218
+ `CREATE INDEX IF NOT EXISTS agent_token_usage_actor_created_idx
219
+ ON agent_token_usage (actor_ref, created_at)`,
220
+ `CREATE TABLE IF NOT EXISTS agent_model_pricing (
221
+ id TEXT PRIMARY KEY NOT NULL,
222
+ model_id TEXT NOT NULL,
223
+ input_price_per_1m REAL NOT NULL,
224
+ output_price_per_1m REAL NOT NULL,
225
+ cache_write_price_per_1m REAL,
226
+ cache_read_price_per_1m REAL,
227
+ effective_from INTEGER NOT NULL,
228
+ is_current INTEGER NOT NULL
229
+ )`
230
+ ];
231
+ async function ensureAgentSchema(db) {
232
+ for (const statement of statements) {
233
+ await db.run(import_drizzle_orm.sql.raw(statement));
234
+ }
235
+ }
236
+ __name(ensureAgentSchema, "ensureAgentSchema");
237
+
238
+ // src/drizzle-agent-store.ts
239
+ var import_drizzle_orm2 = require("drizzle-orm");
240
+ var DrizzleAgentStore = class {
241
+ static {
242
+ __name(this, "DrizzleAgentStore");
243
+ }
244
+ db;
245
+ constructor(db) {
246
+ this.db = db;
247
+ }
248
+ async createThread(input) {
249
+ const now = /* @__PURE__ */ new Date();
250
+ const thread = {
251
+ id: crypto.randomUUID(),
252
+ actorRef: input.actor.id,
253
+ tenantRef: input.actor.tenantRef ?? null,
254
+ title: input.title ?? "New chat",
255
+ persona: input.persona,
256
+ transient: input.transient ?? false,
257
+ activeStreamId: null,
258
+ createdAt: now,
259
+ updatedAt: now,
260
+ deletedAt: null
261
+ };
262
+ await this.db.insert(agentThread).values(thread);
263
+ return this.toSummary(thread);
264
+ }
265
+ async getThread(threadId) {
266
+ const [thread] = await this.db.select().from(agentThread).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.isNull)(agentThread.deletedAt)));
267
+ if (thread === void 0) {
268
+ return null;
269
+ }
270
+ const messages = await this.db.select().from(agentMessage).where((0, import_drizzle_orm2.eq)(agentMessage.threadId, threadId)).orderBy((0, import_drizzle_orm2.asc)(agentMessage.createdAt), (0, import_drizzle_orm2.asc)(agentMessage.id));
271
+ const last = messages[messages.length - 1];
272
+ return {
273
+ ...this.toSummary(thread, last?.content),
274
+ messages: messages.map((message) => this.toStoredMessage(message)),
275
+ ...thread.activeStreamId != null ? {
276
+ activeStreamId: thread.activeStreamId
277
+ } : {}
278
+ };
279
+ }
280
+ async listThreads(actorRef, limit = 50) {
281
+ const threads = await this.db.select().from(agentThread).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.actorRef, actorRef), (0, import_drizzle_orm2.eq)(agentThread.transient, false), (0, import_drizzle_orm2.isNull)(agentThread.deletedAt))).orderBy((0, import_drizzle_orm2.desc)(agentThread.updatedAt)).limit(limit);
282
+ const summaries = [];
283
+ for (const thread of threads) {
284
+ const [last] = await this.db.select().from(agentMessage).where((0, import_drizzle_orm2.eq)(agentMessage.threadId, thread.id)).orderBy((0, import_drizzle_orm2.desc)(agentMessage.createdAt), (0, import_drizzle_orm2.desc)(agentMessage.id)).limit(1);
285
+ summaries.push(this.toSummary(thread, last?.content));
286
+ }
287
+ return summaries;
288
+ }
289
+ async softDeleteThread(threadId) {
290
+ await this.db.update(agentThread).set({
291
+ deletedAt: /* @__PURE__ */ new Date()
292
+ }).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
293
+ }
294
+ async forkThread(threadId, fromMessageId) {
295
+ const [source] = await this.db.select().from(agentThread).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
296
+ if (source === void 0) {
297
+ throw new Error(`thread ${threadId} not found`);
298
+ }
299
+ const messages = await this.db.select().from(agentMessage).where((0, import_drizzle_orm2.eq)(agentMessage.threadId, threadId)).orderBy((0, import_drizzle_orm2.asc)(agentMessage.createdAt), (0, import_drizzle_orm2.asc)(agentMessage.id));
300
+ const cutoff = messages.findIndex((message) => message.id === fromMessageId);
301
+ const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;
302
+ const now = /* @__PURE__ */ new Date();
303
+ const fork = {
304
+ id: crypto.randomUUID(),
305
+ actorRef: source.actorRef,
306
+ tenantRef: source.tenantRef,
307
+ title: source.title,
308
+ persona: source.persona,
309
+ transient: false,
310
+ activeStreamId: null,
311
+ createdAt: now,
312
+ updatedAt: now,
313
+ deletedAt: null
314
+ };
315
+ await this.db.insert(agentThread).values(fork);
316
+ if (kept.length > 0) {
317
+ await this.db.insert(agentMessage).values(kept.map((message) => ({
318
+ id: crypto.randomUUID(),
319
+ threadId: fork.id,
320
+ role: message.role,
321
+ content: message.content,
322
+ toolCalls: message.toolCalls,
323
+ toolResults: message.toolResults,
324
+ followUps: message.followUps,
325
+ usage: message.usage,
326
+ persona: message.persona,
327
+ createdAt: message.createdAt
328
+ })));
329
+ }
330
+ return this.toSummary(fork);
331
+ }
332
+ async ownerOfThread(threadId) {
333
+ const [thread] = await this.db.select({
334
+ actorRef: agentThread.actorRef
335
+ }).from(agentThread).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.isNull)(agentThread.deletedAt)));
336
+ return thread?.actorRef ?? null;
337
+ }
338
+ async ownerOfToolCall(toolCallId) {
339
+ const [row] = await this.db.select({
340
+ actorRef: agentThread.actorRef
341
+ }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm2.eq)(agentToolCall.messageId, agentMessage.id)).innerJoin(agentThread, (0, import_drizzle_orm2.eq)(agentMessage.threadId, agentThread.id)).where((0, import_drizzle_orm2.eq)(agentToolCall.id, toolCallId));
342
+ return row?.actorRef ?? null;
343
+ }
344
+ async runForToolCall(toolCallId) {
345
+ const [row] = await this.db.select({
346
+ activeStreamId: agentThread.activeStreamId
347
+ }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm2.eq)(agentToolCall.messageId, agentMessage.id)).innerJoin(agentThread, (0, import_drizzle_orm2.eq)(agentMessage.threadId, agentThread.id)).where((0, import_drizzle_orm2.eq)(agentToolCall.id, toolCallId));
348
+ return row?.activeStreamId ?? null;
349
+ }
350
+ async ownerOfActiveStream(runId) {
351
+ const [thread] = await this.db.select({
352
+ actorRef: agentThread.actorRef
353
+ }).from(agentThread).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.activeStreamId, runId), (0, import_drizzle_orm2.isNull)(agentThread.deletedAt)));
354
+ return thread?.actorRef ?? null;
355
+ }
356
+ async setTitle(threadId, title) {
357
+ await this.db.update(agentThread).set({
358
+ title,
359
+ updatedAt: /* @__PURE__ */ new Date()
360
+ }).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
361
+ }
362
+ async setActiveStream(threadId, runId) {
363
+ await this.db.update(agentThread).set({
364
+ activeStreamId: runId
365
+ }).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
366
+ }
367
+ async appendMessage(input) {
368
+ const [thread] = await this.db.select().from(agentThread).where((0, import_drizzle_orm2.eq)(agentThread.id, input.threadId));
369
+ if (thread === void 0) {
370
+ throw new Error(`thread ${input.threadId} not found`);
371
+ }
372
+ const now = /* @__PURE__ */ new Date();
373
+ const message = {
374
+ id: crypto.randomUUID(),
375
+ threadId: input.threadId,
376
+ role: input.role,
377
+ content: input.content,
378
+ toolCalls: input.toolCalls ?? null,
379
+ toolResults: input.toolResults ?? null,
380
+ followUps: input.followUps ?? null,
381
+ usage: input.usage ?? null,
382
+ persona: input.persona ?? null,
383
+ createdAt: now
384
+ };
385
+ await this.db.insert(agentMessage).values(message);
386
+ await this.db.update(agentThread).set({
387
+ updatedAt: now
388
+ }).where((0, import_drizzle_orm2.eq)(agentThread.id, input.threadId));
389
+ return this.toStoredMessage(message);
390
+ }
391
+ async truncateFrom(threadId, messageId) {
392
+ const messages = await this.db.select().from(agentMessage).where((0, import_drizzle_orm2.eq)(agentMessage.threadId, threadId)).orderBy((0, import_drizzle_orm2.asc)(agentMessage.createdAt), (0, import_drizzle_orm2.asc)(agentMessage.id));
393
+ const cutoff = messages.findIndex((message) => message.id === messageId);
394
+ if (cutoff < 0) {
395
+ return;
396
+ }
397
+ const doomedIds = messages.slice(cutoff).map((message) => message.id);
398
+ await this.db.delete(agentToolCall).where((0, import_drizzle_orm2.inArray)(agentToolCall.messageId, doomedIds));
399
+ await this.db.delete(agentMessage).where((0, import_drizzle_orm2.inArray)(agentMessage.id, doomedIds));
400
+ }
401
+ async recordToolCall(input) {
402
+ await this.db.insert(agentToolCall).values({
403
+ id: input.toolCallId,
404
+ messageId: input.messageId,
405
+ toolName: input.toolName,
406
+ toolType: input.toolType,
407
+ input: input.input,
408
+ output: null,
409
+ status: input.status,
410
+ executedByRef: null,
411
+ executionMs: null,
412
+ error: null,
413
+ createdAt: /* @__PURE__ */ new Date(),
414
+ executedAt: null
415
+ });
416
+ }
417
+ async updateToolCall(input) {
418
+ const updates = {
419
+ status: input.status
420
+ };
421
+ if (input.output !== void 0) {
422
+ updates.output = input.output;
423
+ }
424
+ if (input.error !== void 0) {
425
+ updates.error = input.error;
426
+ }
427
+ if (input.executionMs !== void 0) {
428
+ updates.executionMs = input.executionMs;
429
+ }
430
+ if (input.executedByRef !== void 0) {
431
+ updates.executedByRef = input.executedByRef;
432
+ }
433
+ if (input.status === "executed" || input.status === "auto_executed") {
434
+ updates.executedAt = /* @__PURE__ */ new Date();
435
+ }
436
+ await this.db.update(agentToolCall).set(updates).where((0, import_drizzle_orm2.eq)(agentToolCall.id, input.toolCallId));
437
+ }
438
+ async recordUsage(input) {
439
+ await this.db.insert(agentTokenUsage).values({
440
+ id: crypto.randomUUID(),
441
+ threadId: input.threadId,
442
+ actorRef: input.actorRef,
443
+ messageId: input.messageId ?? null,
444
+ modelId: input.modelId,
445
+ purpose: input.purpose,
446
+ inputTokens: input.usage.inputTokens,
447
+ outputTokens: input.usage.outputTokens,
448
+ cacheWriteTokens: input.usage.cacheWriteTokens ?? null,
449
+ cacheReadTokens: input.usage.cacheReadTokens ?? null,
450
+ costUsd: input.costUsd ?? null,
451
+ createdAt: /* @__PURE__ */ new Date()
452
+ });
453
+ }
454
+ async quotaToday(actorRef, day) {
455
+ const start = /* @__PURE__ */ new Date(`${day}T00:00:00.000Z`);
456
+ const end = /* @__PURE__ */ new Date(`${day}T23:59:59.999Z`);
457
+ const rows = await this.db.select().from(agentTokenUsage).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentTokenUsage.actorRef, actorRef), (0, import_drizzle_orm2.gte)(agentTokenUsage.createdAt, start), (0, import_drizzle_orm2.lte)(agentTokenUsage.createdAt, end)));
458
+ const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);
459
+ return {
460
+ usedTokens
461
+ };
462
+ }
463
+ toSummary(thread, lastContent) {
464
+ return {
465
+ id: thread.id,
466
+ title: thread.title,
467
+ persona: thread.persona,
468
+ transient: thread.transient,
469
+ createdAt: thread.createdAt.toISOString(),
470
+ updatedAt: thread.updatedAt.toISOString(),
471
+ ...lastContent !== void 0 ? {
472
+ lastMessagePreview: lastContent.slice(0, 120)
473
+ } : {}
474
+ };
475
+ }
476
+ toStoredMessage(message) {
477
+ return {
478
+ id: message.id,
479
+ role: message.role,
480
+ content: message.content,
481
+ createdAt: message.createdAt.toISOString(),
482
+ ...message.toolCalls != null ? {
483
+ toolCalls: message.toolCalls
484
+ } : {},
485
+ ...message.toolResults != null ? {
486
+ toolResults: message.toolResults
487
+ } : {},
488
+ ...message.followUps != null ? {
489
+ followUps: message.followUps
490
+ } : {},
491
+ ...message.usage != null ? {
492
+ usage: message.usage
493
+ } : {}
494
+ };
495
+ }
496
+ };
497
+
498
+ // src/drizzle-governance-queries.ts
499
+ var import_drizzle_orm3 = require("drizzle-orm");
500
+ function estimateFromTokens(pricing, row) {
501
+ const price = pricing.get(row.modelId);
502
+ if (price === void 0) {
503
+ return 0;
504
+ }
505
+ const cacheWriteTokens = row.cacheWriteTokens ?? 0;
506
+ const cacheReadTokens = row.cacheReadTokens ?? 0;
507
+ const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;
508
+ return uncachedInputTokens / 1e6 * price.inputPricePer1m + cacheWriteTokens / 1e6 * (price.cacheWritePricePer1m ?? price.inputPricePer1m) + cacheReadTokens / 1e6 * (price.cacheReadPricePer1m ?? price.inputPricePer1m) + row.outputTokens / 1e6 * price.outputPricePer1m;
509
+ }
510
+ __name(estimateFromTokens, "estimateFromTokens");
511
+ function rowCost(pricing, row) {
512
+ return row.costUsd ?? estimateFromTokens(pricing, row);
513
+ }
514
+ __name(rowCost, "rowCost");
515
+ function dayBounds(range) {
516
+ return {
517
+ start: /* @__PURE__ */ new Date(`${range.fromDay}T00:00:00.000Z`),
518
+ end: /* @__PURE__ */ new Date(`${range.toDay}T23:59:59.999Z`)
519
+ };
520
+ }
521
+ __name(dayBounds, "dayBounds");
522
+ var DrizzleGovernanceQueries = class {
523
+ static {
524
+ __name(this, "DrizzleGovernanceQueries");
525
+ }
526
+ db;
527
+ constructor(db) {
528
+ this.db = db;
529
+ }
530
+ async loadPricing() {
531
+ const rows = await this.db.select().from(agentModelPricing).where((0, import_drizzle_orm3.eq)(agentModelPricing.isCurrent, true));
532
+ const pricing = /* @__PURE__ */ new Map();
533
+ for (const row of rows) {
534
+ pricing.set(row.modelId, {
535
+ inputPricePer1m: row.inputPricePer1m,
536
+ outputPricePer1m: row.outputPricePer1m,
537
+ cacheWritePricePer1m: row.cacheWritePricePer1m,
538
+ cacheReadPricePer1m: row.cacheReadPricePer1m
539
+ });
540
+ }
541
+ return pricing;
542
+ }
543
+ async usageInRange(range) {
544
+ const { start, end } = dayBounds(range);
545
+ const rows = await this.db.select().from(agentTokenUsage).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.gte)(agentTokenUsage.createdAt, start), (0, import_drizzle_orm3.lte)(agentTokenUsage.createdAt, end)));
546
+ return rows;
547
+ }
548
+ async spendByModel(range) {
549
+ const pricing = await this.loadPricing();
550
+ const rows = await this.usageInRange(range);
551
+ const byModel = /* @__PURE__ */ new Map();
552
+ for (const row of rows) {
553
+ const bucket = byModel.get(row.modelId) ?? {
554
+ requests: 0,
555
+ inputTokens: 0,
556
+ outputTokens: 0,
557
+ costUsd: 0
558
+ };
559
+ bucket.requests += 1;
560
+ bucket.inputTokens += row.inputTokens;
561
+ bucket.outputTokens += row.outputTokens;
562
+ bucket.costUsd += rowCost(pricing, row);
563
+ byModel.set(row.modelId, bucket);
564
+ }
565
+ const result = [];
566
+ for (const [modelId, bucket] of byModel) {
567
+ result.push({
568
+ modelId,
569
+ requests: bucket.requests,
570
+ inputTokens: bucket.inputTokens,
571
+ outputTokens: bucket.outputTokens,
572
+ costUsd: bucket.costUsd
573
+ });
574
+ }
575
+ result.sort((left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId));
576
+ return result;
577
+ }
578
+ async spendByActor(range) {
579
+ const pricing = await this.loadPricing();
580
+ const rows = await this.usageInRange(range);
581
+ const byActor = /* @__PURE__ */ new Map();
582
+ for (const row of rows) {
583
+ const bucket = byActor.get(row.actorRef) ?? {
584
+ requests: 0,
585
+ totalTokens: 0,
586
+ costUsd: 0
587
+ };
588
+ bucket.requests += 1;
589
+ bucket.totalTokens += row.inputTokens + row.outputTokens;
590
+ bucket.costUsd += rowCost(pricing, row);
591
+ byActor.set(row.actorRef, bucket);
592
+ }
593
+ const result = [];
594
+ for (const [actorRef, bucket] of byActor) {
595
+ result.push({
596
+ actorRef,
597
+ requests: bucket.requests,
598
+ totalTokens: bucket.totalTokens,
599
+ costUsd: bucket.costUsd
600
+ });
601
+ }
602
+ result.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
603
+ return result;
604
+ }
605
+ async usageTrend(range) {
606
+ const pricing = await this.loadPricing();
607
+ const rows = await this.usageInRange(range);
608
+ const byDay = /* @__PURE__ */ new Map();
609
+ for (const row of rows) {
610
+ const day = row.createdAt.toISOString().slice(0, 10);
611
+ const bucket = byDay.get(day) ?? {
612
+ totalTokens: 0,
613
+ costUsd: 0
614
+ };
615
+ bucket.totalTokens += row.inputTokens + row.outputTokens;
616
+ bucket.costUsd += rowCost(pricing, row);
617
+ byDay.set(day, bucket);
618
+ }
619
+ const result = [];
620
+ for (const [day, bucket] of byDay) {
621
+ result.push({
622
+ day,
623
+ totalTokens: bucket.totalTokens,
624
+ costUsd: bucket.costUsd
625
+ });
626
+ }
627
+ result.sort((left, right) => left.day.localeCompare(right.day));
628
+ return result;
629
+ }
630
+ async recentToolCalls(limit) {
631
+ const rows = await this.db.select({
632
+ toolCallId: agentToolCall.id,
633
+ toolName: agentToolCall.toolName,
634
+ toolType: agentToolCall.toolType,
635
+ status: agentToolCall.status,
636
+ threadId: agentMessage.threadId,
637
+ createdAt: agentToolCall.createdAt
638
+ }).from(agentToolCall).innerJoin(agentMessage, (0, import_drizzle_orm3.eq)(agentToolCall.messageId, agentMessage.id)).orderBy((0, import_drizzle_orm3.desc)(agentToolCall.createdAt), (0, import_drizzle_orm3.desc)(agentToolCall.id)).limit(limit);
639
+ return rows.map((row) => ({
640
+ toolCallId: row.toolCallId,
641
+ toolName: row.toolName,
642
+ toolType: row.toolType,
643
+ status: row.status,
644
+ threadId: row.threadId,
645
+ createdAt: row.createdAt.toISOString()
646
+ }));
647
+ }
648
+ async recentThreads(limit) {
649
+ const threads = await this.db.select().from(agentThread).where((0, import_drizzle_orm3.isNull)(agentThread.deletedAt)).orderBy((0, import_drizzle_orm3.desc)(agentThread.updatedAt), (0, import_drizzle_orm3.desc)(agentThread.id)).limit(limit);
650
+ const result = [];
651
+ for (const thread of threads) {
652
+ const [messageCountRow] = await this.db.select({
653
+ value: (0, import_drizzle_orm3.count)()
654
+ }).from(agentMessage).where((0, import_drizzle_orm3.eq)(agentMessage.threadId, thread.id));
655
+ const usageRows = await this.db.select().from(agentTokenUsage).where((0, import_drizzle_orm3.eq)(agentTokenUsage.threadId, thread.id));
656
+ const totalTokens = usageRows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);
657
+ result.push({
658
+ threadId: thread.id,
659
+ title: thread.title,
660
+ actorRef: thread.actorRef,
661
+ messageCount: messageCountRow?.value ?? 0,
662
+ totalTokens,
663
+ lastActivityAt: thread.updatedAt.toISOString()
664
+ });
665
+ }
666
+ return result;
667
+ }
668
+ };
669
+
670
+ // src/drizzle-pricing-store.ts
671
+ var import_drizzle_orm4 = require("drizzle-orm");
672
+ var DrizzlePricingStore = class {
673
+ static {
674
+ __name(this, "DrizzlePricingStore");
675
+ }
676
+ db;
677
+ constructor(db) {
678
+ this.db = db;
679
+ }
680
+ async upsertModelPrice(input) {
681
+ await this.db.update(agentModelPricing).set({
682
+ isCurrent: false
683
+ }).where((0, import_drizzle_orm4.and)((0, import_drizzle_orm4.eq)(agentModelPricing.modelId, input.modelId), (0, import_drizzle_orm4.eq)(agentModelPricing.isCurrent, true)));
684
+ await this.db.insert(agentModelPricing).values({
685
+ id: crypto.randomUUID(),
686
+ modelId: input.modelId,
687
+ inputPricePer1m: input.inputPricePer1m,
688
+ outputPricePer1m: input.outputPricePer1m,
689
+ cacheWritePricePer1m: input.cacheWritePricePer1m ?? null,
690
+ cacheReadPricePer1m: input.cacheReadPricePer1m ?? null,
691
+ effectiveFrom: /* @__PURE__ */ new Date(),
692
+ isCurrent: true
693
+ });
694
+ }
695
+ async listCurrentPrices() {
696
+ const rows = await this.db.select().from(agentModelPricing).where((0, import_drizzle_orm4.eq)(agentModelPricing.isCurrent, true));
697
+ return rows.map((row) => ({
698
+ modelId: row.modelId,
699
+ inputPricePer1m: row.inputPricePer1m,
700
+ outputPricePer1m: row.outputPricePer1m,
701
+ effectiveFrom: row.effectiveFrom.toISOString(),
702
+ ...row.cacheWritePricePer1m != null ? {
703
+ cacheWritePricePer1m: row.cacheWritePricePer1m
704
+ } : {},
705
+ ...row.cacheReadPricePer1m != null ? {
706
+ cacheReadPricePer1m: row.cacheReadPricePer1m
707
+ } : {}
708
+ }));
709
+ }
710
+ };
711
+
712
+ // src/drizzle-agent-store.module.ts
713
+ var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
714
+ var import_common = require("@nestjs/common");
715
+ function _ts_decorate(decorators, target, key, desc3) {
716
+ var c = arguments.length, r = c < 3 ? target : desc3 === null ? desc3 = Object.getOwnPropertyDescriptor(target, key) : desc3, d;
717
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc3);
718
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
719
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
720
+ }
721
+ __name(_ts_decorate, "_ts_decorate");
722
+ var DrizzleAgentStoreModule = class _DrizzleAgentStoreModule {
723
+ static {
724
+ __name(this, "DrizzleAgentStoreModule");
725
+ }
726
+ static forRoot(options) {
727
+ return {
728
+ module: _DrizzleAgentStoreModule,
729
+ global: true,
730
+ providers: [
731
+ {
732
+ provide: DrizzleAgentStore,
733
+ useFactory: /* @__PURE__ */ __name(() => new DrizzleAgentStore(options.db), "useFactory")
734
+ },
735
+ {
736
+ provide: import_nestjs_agent_core.AGENT_STORE,
737
+ useExisting: DrizzleAgentStore
738
+ },
739
+ {
740
+ provide: DrizzleGovernanceQueries,
741
+ useFactory: /* @__PURE__ */ __name(() => new DrizzleGovernanceQueries(options.db), "useFactory")
742
+ },
743
+ {
744
+ provide: import_nestjs_agent_core.AGENT_GOVERNANCE_QUERIES,
745
+ useExisting: DrizzleGovernanceQueries
746
+ },
747
+ {
748
+ provide: DrizzlePricingStore,
749
+ useFactory: /* @__PURE__ */ __name(() => new DrizzlePricingStore(options.db), "useFactory")
750
+ },
751
+ {
752
+ provide: import_nestjs_agent_core.AGENT_PRICING_STORE,
753
+ useExisting: DrizzlePricingStore
754
+ }
755
+ ],
756
+ exports: [
757
+ DrizzleAgentStore,
758
+ import_nestjs_agent_core.AGENT_STORE,
759
+ DrizzleGovernanceQueries,
760
+ import_nestjs_agent_core.AGENT_GOVERNANCE_QUERIES,
761
+ DrizzlePricingStore,
762
+ import_nestjs_agent_core.AGENT_PRICING_STORE
763
+ ]
764
+ };
765
+ }
766
+ };
767
+ DrizzleAgentStoreModule = _ts_decorate([
768
+ (0, import_common.Module)({})
769
+ ], DrizzleAgentStoreModule);
770
+ // Annotate the CommonJS export names for ESM import in node:
771
+ 0 && (module.exports = {
772
+ DrizzleAgentStore,
773
+ DrizzleAgentStoreModule,
774
+ DrizzleGovernanceQueries,
775
+ DrizzlePricingStore,
776
+ agentMessage,
777
+ agentModelPricing,
778
+ agentSchema,
779
+ agentThread,
780
+ agentTokenUsage,
781
+ agentToolCall,
782
+ ensureAgentSchema
783
+ });
784
+ //# sourceMappingURL=index.cjs.map