@dudousxd/nestjs-agent-store-drizzle 0.2.0 → 0.3.1

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 CHANGED
@@ -355,6 +355,12 @@ var DrizzleAgentStore = class {
355
355
  updatedAt: /* @__PURE__ */ new Date()
356
356
  }).where((0, import_drizzle_orm2.eq)(agentThread.id, threadId));
357
357
  }
358
+ async promoteThread(threadId) {
359
+ await this.db.update(agentThread).set({
360
+ transient: false,
361
+ updatedAt: /* @__PURE__ */ new Date()
362
+ }).where((0, import_drizzle_orm2.and)((0, import_drizzle_orm2.eq)(agentThread.id, threadId), (0, import_drizzle_orm2.eq)(agentThread.transient, true)));
363
+ }
358
364
  async setActiveStream(threadId, runId) {
359
365
  await this.db.update(agentThread).set({
360
366
  activeStreamId: runId
@@ -452,8 +458,10 @@ var DrizzleAgentStore = class {
452
458
  const end = /* @__PURE__ */ new Date(`${day}T23:59:59.999Z`);
453
459
  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)));
454
460
  const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);
461
+ const costUsd = rows.reduce((sum, row) => sum + (row.costUsd ?? 0), 0);
455
462
  return {
456
- usedTokens
463
+ usedTokens,
464
+ costUsd
457
465
  };
458
466
  }
459
467
  toSummary(thread, lastContent) {
@@ -522,18 +530,20 @@ var DrizzleGovernanceQueries = class {
522
530
  __name(this, "DrizzleGovernanceQueries");
523
531
  }
524
532
  db;
525
- constructor(db) {
533
+ pricingStore;
534
+ constructor(db, pricingStore) {
526
535
  this.db = db;
536
+ this.pricingStore = pricingStore;
527
537
  }
528
538
  async loadPricing() {
529
- const rows = await this.db.select().from(agentModelPricing).where((0, import_drizzle_orm3.eq)(agentModelPricing.isCurrent, true));
539
+ const prices = await this.pricingStore.listCurrentPrices();
530
540
  const pricing = /* @__PURE__ */ new Map();
531
- for (const row of rows) {
532
- pricing.set(row.modelId, {
533
- inputPricePer1m: row.inputPricePer1m,
534
- outputPricePer1m: row.outputPricePer1m,
535
- cacheWritePricePer1m: row.cacheWritePricePer1m,
536
- cacheReadPricePer1m: row.cacheReadPricePer1m
541
+ for (const price of prices) {
542
+ pricing.set(price.modelId, {
543
+ inputPricePer1m: price.inputPricePer1m,
544
+ outputPricePer1m: price.outputPricePer1m,
545
+ cacheWritePricePer1m: price.cacheWritePricePer1m ?? null,
546
+ cacheReadPricePer1m: price.cacheReadPricePer1m ?? null
537
547
  });
538
548
  }
539
549
  return pricing;
@@ -581,11 +591,13 @@ var DrizzleGovernanceQueries = class {
581
591
  const bucket = byActor.get(row.actorRef) ?? {
582
592
  requests: 0,
583
593
  totalTokens: 0,
584
- costUsd: 0
594
+ costUsd: 0,
595
+ threadIds: /* @__PURE__ */ new Set()
585
596
  };
586
597
  bucket.requests += 1;
587
598
  bucket.totalTokens += row.inputTokens + row.outputTokens;
588
599
  bucket.costUsd += rowCost(pricing, row);
600
+ bucket.threadIds.add(row.threadId);
589
601
  byActor.set(row.actorRef, bucket);
590
602
  }
591
603
  const result = [];
@@ -594,12 +606,61 @@ var DrizzleGovernanceQueries = class {
594
606
  actorRef,
595
607
  requests: bucket.requests,
596
608
  totalTokens: bucket.totalTokens,
597
- costUsd: bucket.costUsd
609
+ costUsd: bucket.costUsd,
610
+ threadCount: bucket.threadIds.size
598
611
  });
599
612
  }
600
613
  result.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
601
614
  return result;
602
615
  }
616
+ /**
617
+ * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a
618
+ * soft-deleted thread (`deletedAt` set) are excluded — the thread no longer surfaces as a
619
+ * governance target even though its ledger rows survive.
620
+ */
621
+ async spendByThread(range, limit) {
622
+ const pricing = await this.loadPricing();
623
+ const rows = await this.usageInRange(range);
624
+ const byThread = /* @__PURE__ */ new Map();
625
+ for (const row of rows) {
626
+ const bucket = byThread.get(row.threadId) ?? {
627
+ requests: 0,
628
+ totalTokens: 0,
629
+ costUsd: 0
630
+ };
631
+ bucket.requests += 1;
632
+ bucket.totalTokens += row.inputTokens + row.outputTokens;
633
+ bucket.costUsd += rowCost(pricing, row);
634
+ byThread.set(row.threadId, bucket);
635
+ }
636
+ if (byThread.size === 0) {
637
+ return [];
638
+ }
639
+ const threads = await this.db.select().from(agentThread).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.inArray)(agentThread.id, [
640
+ ...byThread.keys()
641
+ ]), (0, import_drizzle_orm3.isNull)(agentThread.deletedAt)));
642
+ const threadsById = new Map(threads.map((thread) => [
643
+ thread.id,
644
+ thread
645
+ ]));
646
+ const result = [];
647
+ for (const [threadId, bucket] of byThread) {
648
+ const thread = threadsById.get(threadId);
649
+ if (thread === void 0) {
650
+ continue;
651
+ }
652
+ result.push({
653
+ threadId,
654
+ title: thread.title,
655
+ actorRef: thread.actorRef,
656
+ requests: bucket.requests,
657
+ totalTokens: bucket.totalTokens,
658
+ costUsd: bucket.costUsd
659
+ });
660
+ }
661
+ result.sort((left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId));
662
+ return result.slice(0, limit);
663
+ }
603
664
  async usageTrend(range) {
604
665
  const pricing = await this.loadPricing();
605
666
  const rows = await this.usageInRange(range);
@@ -734,21 +795,29 @@ var DrizzleAgentStoreModule = class _DrizzleAgentStoreModule {
734
795
  provide: import_nestjs_agent_core.AGENT_STORE,
735
796
  useExisting: DrizzleAgentStore
736
797
  },
737
- {
738
- provide: DrizzleGovernanceQueries,
739
- useFactory: /* @__PURE__ */ __name(() => new DrizzleGovernanceQueries(options.db), "useFactory")
740
- },
741
- {
742
- provide: import_nestjs_agent_core.AGENT_GOVERNANCE_QUERIES,
743
- useExisting: DrizzleGovernanceQueries
744
- },
745
798
  {
746
799
  provide: DrizzlePricingStore,
747
800
  useFactory: /* @__PURE__ */ __name(() => new DrizzlePricingStore(options.db), "useFactory")
748
801
  },
749
- {
802
+ // AGENT_PRICING_STORE: the host's own store when supplied, else the default Drizzle one.
803
+ // DrizzleGovernanceQueries prices usage against whatever is bound here.
804
+ options.pricingStore ? {
805
+ provide: import_nestjs_agent_core.AGENT_PRICING_STORE,
806
+ useClass: options.pricingStore
807
+ } : {
750
808
  provide: import_nestjs_agent_core.AGENT_PRICING_STORE,
751
809
  useExisting: DrizzlePricingStore
810
+ },
811
+ {
812
+ provide: DrizzleGovernanceQueries,
813
+ useFactory: /* @__PURE__ */ __name((pricingStore) => new DrizzleGovernanceQueries(options.db, pricingStore), "useFactory"),
814
+ inject: [
815
+ import_nestjs_agent_core.AGENT_PRICING_STORE
816
+ ]
817
+ },
818
+ {
819
+ provide: import_nestjs_agent_core.AGENT_GOVERNANCE_QUERIES,
820
+ useExisting: DrizzleGovernanceQueries
752
821
  }
753
822
  ],
754
823
  exports: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/schema.ts","../src/ensure-schema.ts","../src/drizzle-agent-store.ts","../src/drizzle-governance-queries.ts","../src/drizzle-pricing-store.ts","../src/drizzle-agent-store.module.ts"],"sourcesContent":["export * from './schema.js';\nexport * from './ensure-schema.js';\nexport * from './drizzle-agent-store.js';\nexport * from './drizzle-governance-queries.js';\nexport * from './drizzle-pricing-store.js';\nexport * from './drizzle-agent-store.module.js';\n","import type {\n MessageRole,\n MessageUsage,\n ToolCallRequest,\n ToolCallStatus,\n ToolKind,\n ToolResult,\n UsagePurpose,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n type BaseSQLiteDatabase,\n index,\n integer,\n real,\n sqliteTable,\n text,\n} from 'drizzle-orm/sqlite-core';\n\n/**\n * Drizzle schema mirroring the MikroORM agent entities (same logical columns/relations):\n * threads, messages, tool calls, token usage and model pricing. Targets the SQLite core so the\n * db-test runs on an in-memory better-sqlite3; timestamps are stored as integer epoch-ms columns\n * (`{ mode: 'timestamp_ms' }`) which Drizzle round-trips to/from JS `Date`, and the model-facing\n * message extras (tool calls/results, follow-ups, usage) live in JSON `text` columns.\n */\n\n/**\n * A conversation thread. `deletedAt` drives soft delete: a deleted thread is hidden from\n * {@link import('./drizzle-agent-store.js').DrizzleAgentStore.getThread}/`listThreads` but its\n * row survives.\n */\nexport const agentThread = sqliteTable(\n 'agent_thread',\n {\n id: text('id').primaryKey(),\n actorRef: text('actor_ref').notNull(),\n tenantRef: text('tenant_ref'),\n title: text('title').notNull(),\n transient: integer('transient', { mode: 'boolean' }).notNull().default(false),\n activeStreamId: text('active_stream_id'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n deletedAt: integer('deleted_at', { mode: 'timestamp_ms' }),\n },\n (table) => [index('agent_thread_actor_updated_idx').on(table.actorRef, table.updatedAt)],\n);\n\n/**\n * One stored message in a thread. The model-facing extras (`toolCalls`/`toolResults`/\n * `followUps`/`usage`) are folded into nullable JSON columns so a single row round-trips to a\n * {@link import('@dudousxd/nestjs-agent-core').StoredMessage}. `threadId` cascades on delete.\n */\nexport const agentMessage = sqliteTable(\n 'agent_message',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n role: text('role').$type<MessageRole>().notNull(),\n content: text('content').notNull(),\n toolCalls: text('tool_calls', { mode: 'json' }).$type<ToolCallRequest[]>(),\n toolResults: text('tool_results', { mode: 'json' }).$type<ToolResult[]>(),\n followUps: text('follow_ups', { mode: 'json' }).$type<string[]>(),\n usage: text('usage', { mode: 'json' }).$type<MessageUsage>(),\n agentName: text('agent_name'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_message_thread_created_idx').on(table.threadId, table.createdAt)],\n);\n\n/** A tool call requested during an assistant turn. The pk is the model-supplied `toolCallId`. */\nexport const agentToolCall = sqliteTable('agent_tool_call', {\n id: text('id').primaryKey(),\n messageId: text('message_id')\n .notNull()\n .references(() => agentMessage.id, { onDelete: 'cascade' }),\n toolName: text('tool_name').notNull(),\n toolType: text('tool_type').$type<ToolKind>().notNull(),\n input: text('input', { mode: 'json' }),\n output: text('output', { mode: 'json' }),\n status: text('status').$type<ToolCallStatus>().notNull(),\n executedByRef: text('executed_by_ref'),\n executionMs: integer('execution_ms'),\n error: text('error'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n executedAt: integer('executed_at', { mode: 'timestamp_ms' }),\n});\n\n/** A token-usage ledger row, summed per actor per day by `quotaToday`. */\nexport const agentTokenUsage = sqliteTable(\n 'agent_token_usage',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n actorRef: text('actor_ref').notNull(),\n messageId: text('message_id'),\n modelId: text('model_id').notNull(),\n purpose: text('purpose').$type<UsagePurpose>().notNull(),\n inputTokens: integer('input_tokens').notNull(),\n outputTokens: integer('output_tokens').notNull(),\n /** Subset of `inputTokens` written to the prompt cache this turn; null when not reported. */\n cacheWriteTokens: integer('cache_write_tokens'),\n /** Subset of `inputTokens` served from the prompt cache this turn; null when not reported. */\n cacheReadTokens: integer('cache_read_tokens'),\n /** Provider-reported actual USD cost for the turn; null when only tokens were reported. */\n costUsd: real('cost_usd'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_token_usage_actor_created_idx').on(table.actorRef, table.createdAt)],\n);\n\n/** Per-model token pricing, versioned by `effectiveFrom`; `isCurrent` flags the live row. */\nexport const agentModelPricing = sqliteTable('agent_model_pricing', {\n id: text('id').primaryKey(),\n modelId: text('model_id').notNull(),\n inputPricePer1m: real('input_price_per_1m').notNull(),\n outputPricePer1m: real('output_price_per_1m').notNull(),\n /** Per-1M price for cache-write input tokens; null → price them at the input rate. */\n cacheWritePricePer1m: real('cache_write_price_per_1m'),\n /** Per-1M price for cache-read input tokens; null → price them at the input rate. */\n cacheReadPricePer1m: real('cache_read_price_per_1m'),\n effectiveFrom: integer('effective_from', { mode: 'timestamp_ms' }).notNull(),\n isCurrent: integer('is_current', { mode: 'boolean' }).notNull(),\n});\n\n/** The five agent tables as one schema object, ready for `drizzle(client, { schema })`. */\nexport const agentSchema = {\n agentThread,\n agentMessage,\n agentToolCall,\n agentTokenUsage,\n agentModelPricing,\n};\n\n/**\n * The dialect-portable Drizzle SQLite database handle the store operates on. Accepts any SQLite\n * driver (better-sqlite3, libsql, D1, …) in either sync or async result mode; the host app owns\n * the connection and passes the `drizzle(...)` instance in.\n */\nexport type AgentDrizzleDb = BaseSQLiteDatabase<'sync' | 'async', unknown>;\n\n/** A persisted thread row as Drizzle selects it. */\nexport type AgentThreadRow = typeof agentThread.$inferSelect;\n/** A persisted message row as Drizzle selects it. */\nexport type AgentMessageRow = typeof agentMessage.$inferSelect;\n","import { sql } from 'drizzle-orm';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/**\n * Idempotent `CREATE TABLE IF NOT EXISTS` DDL for the five agent tables, mirroring\n * {@link import('./schema.js').agentSchema}. SQLite dialect (the db-test driver); kept here rather\n * than relying on drizzle-kit so the package can stand up its schema with no migration files. Safe\n * to run on boot against a shared database — it never drops or alters existing columns.\n */\nconst statements: string[] = [\n `CREATE TABLE IF NOT EXISTS agent_thread (\n id TEXT PRIMARY KEY NOT NULL,\n actor_ref TEXT NOT NULL,\n tenant_ref TEXT,\n title TEXT NOT NULL,\n transient INTEGER NOT NULL DEFAULT 0,\n active_stream_id TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n deleted_at INTEGER\n )`,\n `CREATE INDEX IF NOT EXISTS agent_thread_actor_updated_idx\n ON agent_thread (actor_ref, updated_at)`,\n `CREATE TABLE IF NOT EXISTS agent_message (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n tool_calls TEXT,\n tool_results TEXT,\n follow_ups TEXT,\n usage TEXT,\n agent_name TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx\n ON agent_message (thread_id, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_tool_call (\n id TEXT PRIMARY KEY NOT NULL,\n message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n tool_type TEXT NOT NULL,\n input TEXT,\n output TEXT,\n status TEXT NOT NULL,\n executed_by_ref TEXT,\n execution_ms INTEGER,\n error TEXT,\n created_at INTEGER NOT NULL,\n executed_at INTEGER\n )`,\n `CREATE TABLE IF NOT EXISTS agent_token_usage (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n actor_ref TEXT NOT NULL,\n message_id TEXT,\n model_id TEXT NOT NULL,\n purpose TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n cache_write_tokens INTEGER,\n cache_read_tokens INTEGER,\n cost_usd REAL,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_token_usage_actor_created_idx\n ON agent_token_usage (actor_ref, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_model_pricing (\n id TEXT PRIMARY KEY NOT NULL,\n model_id TEXT NOT NULL,\n input_price_per_1m REAL NOT NULL,\n output_price_per_1m REAL NOT NULL,\n cache_write_price_per_1m REAL,\n cache_read_price_per_1m REAL,\n effective_from INTEGER NOT NULL,\n is_current INTEGER NOT NULL\n )`,\n];\n\n/** Runs the `CREATE TABLE IF NOT EXISTS` DDL above against the supplied Drizzle SQLite db. */\nexport async function ensureAgentSchema(db: AgentDrizzleDb): Promise<void> {\n for (const statement of statements) {\n await db.run(sql.raw(statement));\n }\n}\n","import type {\n AgentStore,\n AppendMessageInput,\n CreateThreadInput,\n RecordToolCallInput,\n RecordUsageInput,\n StoredMessage,\n ThreadDetail,\n ThreadSummary,\n UpdateToolCallInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, asc, desc, eq, gte, inArray, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n type AgentMessageRow,\n type AgentThreadRow,\n agentMessage,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/**\n * {@link AgentStore} backed by Drizzle ORM — a second adapter alongside the MikroORM one, proving\n * the store SPI is ORM-portable. A POJO receiving a Drizzle SQLite database handle (the host app\n * owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}\n * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.\n */\nexport class DrizzleAgentStore implements AgentStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async createThread(input: CreateThreadInput): Promise<ThreadSummary> {\n const now = new Date();\n const thread: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: input.actor.id,\n tenantRef: input.actor.tenantRef ?? null,\n title: input.title ?? 'New chat',\n transient: input.transient ?? false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(thread);\n return this.toSummary(thread);\n }\n\n async getThread(threadId: string): Promise<ThreadDetail | null> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n if (thread === undefined) {\n return null;\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const last = messages[messages.length - 1];\n return {\n ...this.toSummary(thread, last?.content),\n messages: messages.map((message) => this.toStoredMessage(message)),\n ...(thread.activeStreamId != null ? { activeStreamId: thread.activeStreamId } : {}),\n };\n }\n\n async listThreads(actorRef: string, limit = 50): Promise<ThreadSummary[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(\n and(\n eq(agentThread.actorRef, actorRef),\n eq(agentThread.transient, false),\n isNull(agentThread.deletedAt),\n ),\n )\n .orderBy(desc(agentThread.updatedAt))\n .limit(limit);\n const summaries: ThreadSummary[] = [];\n for (const thread of threads) {\n const [last] = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id))\n .orderBy(desc(agentMessage.createdAt), desc(agentMessage.id))\n .limit(1);\n summaries.push(this.toSummary(thread, last?.content));\n }\n return summaries;\n }\n\n async softDeleteThread(threadId: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ deletedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary> {\n const [source] = await this.db.select().from(agentThread).where(eq(agentThread.id, threadId));\n if (source === undefined) {\n throw new Error(`thread ${threadId} not found`);\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === fromMessageId);\n const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;\n const now = new Date();\n const fork: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: source.actorRef,\n tenantRef: source.tenantRef,\n title: source.title,\n transient: false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(fork);\n if (kept.length > 0) {\n await this.db.insert(agentMessage).values(\n kept.map((message) => ({\n id: crypto.randomUUID(),\n threadId: fork.id,\n role: message.role,\n content: message.content,\n toolCalls: message.toolCalls,\n toolResults: message.toolResults,\n followUps: message.followUps,\n usage: message.usage,\n agentName: message.agentName,\n createdAt: message.createdAt,\n })),\n );\n }\n return this.toSummary(fork);\n }\n\n async ownerOfThread(threadId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async ownerOfToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.actorRef ?? null;\n }\n\n async runForToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ activeStreamId: agentThread.activeStreamId })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.activeStreamId ?? null;\n }\n\n async ownerOfActiveStream(runId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.activeStreamId, runId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async setTitle(threadId: string, title: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ title, updatedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async setActiveStream(threadId: string, runId: string | null): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ activeStreamId: runId })\n .where(eq(agentThread.id, threadId));\n }\n\n async appendMessage(input: AppendMessageInput): Promise<StoredMessage> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(eq(agentThread.id, input.threadId));\n if (thread === undefined) {\n throw new Error(`thread ${input.threadId} not found`);\n }\n const now = new Date();\n const message: AgentMessageRow = {\n id: crypto.randomUUID(),\n threadId: input.threadId,\n role: input.role,\n content: input.content,\n toolCalls: input.toolCalls ?? null,\n toolResults: input.toolResults ?? null,\n followUps: input.followUps ?? null,\n usage: input.usage ?? null,\n agentName: input.agentName ?? null,\n createdAt: now,\n };\n await this.db.insert(agentMessage).values(message);\n await this.db\n .update(agentThread)\n .set({ updatedAt: now })\n .where(eq(agentThread.id, input.threadId));\n return this.toStoredMessage(message);\n }\n\n async truncateFrom(threadId: string, messageId: string): Promise<void> {\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === messageId);\n if (cutoff < 0) {\n return;\n }\n const doomedIds = messages.slice(cutoff).map((message) => message.id);\n await this.db.delete(agentToolCall).where(inArray(agentToolCall.messageId, doomedIds));\n await this.db.delete(agentMessage).where(inArray(agentMessage.id, doomedIds));\n }\n\n async recordToolCall(input: RecordToolCallInput): Promise<void> {\n await this.db.insert(agentToolCall).values({\n id: input.toolCallId,\n messageId: input.messageId,\n toolName: input.toolName,\n toolType: input.toolType,\n input: input.input,\n output: null,\n status: input.status,\n executedByRef: null,\n executionMs: null,\n error: null,\n createdAt: new Date(),\n executedAt: null,\n });\n }\n\n async updateToolCall(input: UpdateToolCallInput): Promise<void> {\n const updates: Partial<typeof agentToolCall.$inferInsert> = { status: input.status };\n if (input.output !== undefined) {\n updates.output = input.output;\n }\n if (input.error !== undefined) {\n updates.error = input.error;\n }\n if (input.executionMs !== undefined) {\n updates.executionMs = input.executionMs;\n }\n if (input.executedByRef !== undefined) {\n updates.executedByRef = input.executedByRef;\n }\n if (input.status === 'executed' || input.status === 'auto_executed') {\n updates.executedAt = new Date();\n }\n await this.db.update(agentToolCall).set(updates).where(eq(agentToolCall.id, input.toolCallId));\n }\n\n async recordUsage(input: RecordUsageInput): Promise<void> {\n await this.db.insert(agentTokenUsage).values({\n id: crypto.randomUUID(),\n threadId: input.threadId,\n actorRef: input.actorRef,\n messageId: input.messageId ?? null,\n modelId: input.modelId,\n purpose: input.purpose,\n inputTokens: input.usage.inputTokens,\n outputTokens: input.usage.outputTokens,\n cacheWriteTokens: input.usage.cacheWriteTokens ?? null,\n cacheReadTokens: input.usage.cacheReadTokens ?? null,\n costUsd: input.costUsd ?? null,\n createdAt: new Date(),\n });\n }\n\n async quotaToday(actorRef: string, day: string): Promise<{ usedTokens: number }> {\n const start = new Date(`${day}T00:00:00.000Z`);\n const end = new Date(`${day}T23:59:59.999Z`);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(\n and(\n eq(agentTokenUsage.actorRef, actorRef),\n gte(agentTokenUsage.createdAt, start),\n lte(agentTokenUsage.createdAt, end),\n ),\n );\n const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);\n return { usedTokens };\n }\n\n private toSummary(thread: AgentThreadRow, lastContent?: string): ThreadSummary {\n return {\n id: thread.id,\n title: thread.title,\n transient: thread.transient,\n createdAt: thread.createdAt.toISOString(),\n updatedAt: thread.updatedAt.toISOString(),\n ...(lastContent !== undefined ? { lastMessagePreview: lastContent.slice(0, 120) } : {}),\n };\n }\n\n private toStoredMessage(message: AgentMessageRow): StoredMessage {\n return {\n id: message.id,\n role: message.role,\n content: message.content,\n createdAt: message.createdAt.toISOString(),\n ...(message.toolCalls != null ? { toolCalls: message.toolCalls } : {}),\n ...(message.toolResults != null ? { toolResults: message.toolResults } : {}),\n ...(message.followUps != null ? { followUps: message.followUps } : {}),\n ...(message.usage != null ? { usage: message.usage } : {}),\n ...(message.agentName != null ? { agentName: message.agentName } : {}),\n };\n }\n}\n","import type {\n ActorSpendRow,\n AgentGovernanceQueries,\n GovernanceRange,\n ModelSpendRow,\n ThreadActivityRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, count, desc, eq, gte, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n agentMessage,\n agentModelPricing,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/** The current per-1M token prices for one model; cache rates fall back to the input rate. */\ninterface ModelPrice {\n inputPricePer1m: number;\n outputPricePer1m: number;\n cacheWritePricePer1m?: number | null;\n cacheReadPricePer1m?: number | null;\n}\n\n/**\n * Token-ledger estimate for one usage row against the current pricing row: the uncached input at the\n * input rate, cache-write/cache-read tokens at their own rates (falling back to the input rate when\n * unpriced), plus output at the output rate. An unpriced model contributes 0 (tokens still count).\n * Cache token counts are subsets of `inputTokens`, so the uncached remainder is the difference.\n */\nfunction estimateFromTokens(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n const price = pricing.get(row.modelId);\n if (price === undefined) {\n return 0;\n }\n const cacheWriteTokens = row.cacheWriteTokens ?? 0;\n const cacheReadTokens = row.cacheReadTokens ?? 0;\n const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;\n return (\n (uncachedInputTokens / 1_000_000) * price.inputPricePer1m +\n (cacheWriteTokens / 1_000_000) * (price.cacheWritePricePer1m ?? price.inputPricePer1m) +\n (cacheReadTokens / 1_000_000) * (price.cacheReadPricePer1m ?? price.inputPricePer1m) +\n (row.outputTokens / 1_000_000) * price.outputPricePer1m\n );\n}\n\n/**\n * The cost of one usage row: the provider-reported `costUsd` when present (gateways report real\n * spend), otherwise the cache-aware token estimate against the current pricing row.\n */\nfunction rowCost(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n return row.costUsd ?? estimateFromTokens(pricing, row);\n}\n\n/** Turns an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used by `quotaToday`. */\nfunction dayBounds(range: GovernanceRange): { start: Date; end: Date } {\n return {\n start: new Date(`${range.fromDay}T00:00:00.000Z`),\n end: new Date(`${range.toDay}T23:59:59.999Z`),\n };\n}\n\n/**\n * {@link AgentGovernanceQueries} backed by Drizzle ORM — the read/analytics half of the store SPI,\n * mirroring {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly. Cost is the token\n * ledger joined to the current pricing row per model (`agentModelPricing.isCurrent`); an unpriced\n * model contributes 0 cost. Aggregation is in-process (like `quotaToday`) so day-bucketing stays\n * dialect-portable.\n */\nexport class DrizzleGovernanceQueries implements AgentGovernanceQueries {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n private async loadPricing(): Promise<Map<string, ModelPrice>> {\n const rows = await this.db\n .select()\n .from(agentModelPricing)\n .where(eq(agentModelPricing.isCurrent, true));\n const pricing = new Map<string, ModelPrice>();\n for (const row of rows) {\n pricing.set(row.modelId, {\n inputPricePer1m: row.inputPricePer1m,\n outputPricePer1m: row.outputPricePer1m,\n cacheWritePricePer1m: row.cacheWritePricePer1m,\n cacheReadPricePer1m: row.cacheReadPricePer1m,\n });\n }\n return pricing;\n }\n\n private async usageInRange(\n range: GovernanceRange,\n ): Promise<(typeof agentTokenUsage.$inferSelect)[]> {\n const { start, end } = dayBounds(range);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(and(gte(agentTokenUsage.createdAt, start), lte(agentTokenUsage.createdAt, end)));\n return rows;\n }\n\n async spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byModel = new Map<\n string,\n { requests: number; inputTokens: number; outputTokens: number; costUsd: number }\n >();\n for (const row of rows) {\n const bucket = byModel.get(row.modelId) ?? {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n costUsd: 0,\n };\n bucket.requests += 1;\n bucket.inputTokens += row.inputTokens;\n bucket.outputTokens += row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byModel.set(row.modelId, bucket);\n }\n const result: ModelSpendRow[] = [];\n for (const [modelId, bucket] of byModel) {\n result.push({\n modelId,\n requests: bucket.requests,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId),\n );\n return result;\n }\n\n async spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byActor = new Map<string, { requests: number; totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byActor.get(row.actorRef) ?? { requests: 0, totalTokens: 0, costUsd: 0 };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byActor.set(row.actorRef, bucket);\n }\n const result: ActorSpendRow[] = [];\n for (const [actorRef, bucket] of byActor) {\n result.push({\n actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef),\n );\n return result;\n }\n\n async usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byDay = new Map<string, { totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const day = row.createdAt.toISOString().slice(0, 10);\n const bucket = byDay.get(day) ?? { totalTokens: 0, costUsd: 0 };\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byDay.set(day, bucket);\n }\n const result: UsageTrendPoint[] = [];\n for (const [day, bucket] of byDay) {\n result.push({ day, totalTokens: bucket.totalTokens, costUsd: bucket.costUsd });\n }\n result.sort((left, right) => left.day.localeCompare(right.day));\n return result;\n }\n\n async recentToolCalls(limit: number): Promise<ToolCallActivityRow[]> {\n const rows = await this.db\n .select({\n toolCallId: agentToolCall.id,\n toolName: agentToolCall.toolName,\n toolType: agentToolCall.toolType,\n status: agentToolCall.status,\n threadId: agentMessage.threadId,\n createdAt: agentToolCall.createdAt,\n })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .orderBy(desc(agentToolCall.createdAt), desc(agentToolCall.id))\n .limit(limit);\n return rows.map((row) => ({\n toolCallId: row.toolCallId,\n toolName: row.toolName,\n toolType: row.toolType,\n status: row.status,\n threadId: row.threadId,\n createdAt: row.createdAt.toISOString(),\n }));\n }\n\n async recentThreads(limit: number): Promise<ThreadActivityRow[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(isNull(agentThread.deletedAt))\n .orderBy(desc(agentThread.updatedAt), desc(agentThread.id))\n .limit(limit);\n const result: ThreadActivityRow[] = [];\n for (const thread of threads) {\n const [messageCountRow] = await this.db\n .select({ value: count() })\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id));\n const usageRows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(eq(agentTokenUsage.threadId, thread.id));\n const totalTokens = usageRows.reduce(\n (sum, row) => sum + row.inputTokens + row.outputTokens,\n 0,\n );\n result.push({\n threadId: thread.id,\n title: thread.title,\n actorRef: thread.actorRef,\n messageCount: messageCountRow?.value ?? 0,\n totalTokens,\n lastActivityAt: thread.updatedAt.toISOString(),\n });\n }\n return result;\n }\n}\n","import type {\n AgentPricingStore,\n CurrentModelPrice,\n ModelPriceInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, eq } from 'drizzle-orm';\nimport { type AgentDrizzleDb, agentModelPricing } from './schema.js';\n\n/**\n * {@link AgentPricingStore} backed by Drizzle ORM — the write side of the pricing table\n * {@link import('./drizzle-governance-queries.js').DrizzleGovernanceQueries} joins against. A POJO\n * receiving a Drizzle SQLite database handle (the host app owns the connection), mirroring\n * {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly (atomic supersede semantics).\n */\nexport class DrizzlePricingStore implements AgentPricingStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async upsertModelPrice(input: ModelPriceInput): Promise<void> {\n await this.db\n .update(agentModelPricing)\n .set({ isCurrent: false })\n .where(\n and(eq(agentModelPricing.modelId, input.modelId), eq(agentModelPricing.isCurrent, true)),\n );\n await this.db.insert(agentModelPricing).values({\n id: crypto.randomUUID(),\n modelId: input.modelId,\n inputPricePer1m: input.inputPricePer1m,\n outputPricePer1m: input.outputPricePer1m,\n cacheWritePricePer1m: input.cacheWritePricePer1m ?? null,\n cacheReadPricePer1m: input.cacheReadPricePer1m ?? null,\n effectiveFrom: new Date(),\n isCurrent: true,\n });\n }\n\n async listCurrentPrices(): Promise<CurrentModelPrice[]> {\n const rows = await this.db\n .select()\n .from(agentModelPricing)\n .where(eq(agentModelPricing.isCurrent, true));\n return rows.map((row) => ({\n modelId: row.modelId,\n inputPricePer1m: row.inputPricePer1m,\n outputPricePer1m: row.outputPricePer1m,\n effectiveFrom: row.effectiveFrom.toISOString(),\n ...(row.cacheWritePricePer1m != null\n ? { cacheWritePricePer1m: row.cacheWritePricePer1m }\n : {}),\n ...(row.cacheReadPricePer1m != null ? { cacheReadPricePer1m: row.cacheReadPricePer1m } : {}),\n }));\n }\n}\n","import {\n AGENT_GOVERNANCE_QUERIES,\n AGENT_PRICING_STORE,\n AGENT_STORE,\n} from '@dudousxd/nestjs-agent-core';\nimport { type DynamicModule, Module } from '@nestjs/common';\nimport { DrizzleAgentStore } from './drizzle-agent-store.js';\nimport { DrizzleGovernanceQueries } from './drizzle-governance-queries.js';\nimport { DrizzlePricingStore } from './drizzle-pricing-store.js';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/** Options for {@link DrizzleAgentStoreModule.forRoot}. The app owns and supplies the db handle. */\nexport interface DrizzleAgentStoreModuleOptions {\n /** A Drizzle SQLite database instance (`drizzle(client, { schema: agentSchema })`). */\n db: AgentDrizzleDb;\n}\n\n/**\n * Binds {@link DrizzleAgentStore} to the {@link AGENT_STORE} token consumed by\n * `@dudousxd/nestjs-agent`, plus {@link DrizzleGovernanceQueries} to\n * {@link AGENT_GOVERNANCE_QUERIES} (the read-model the dashboard/telescope surfaces consume) and\n * {@link DrizzlePricingStore} to {@link AGENT_PRICING_STORE} (the write side of that pricing table).\n * The host app supplies an already-opened Drizzle db — this module never opens a connection itself.\n *\n * The returned module is global, so {@link AGENT_STORE}, {@link AGENT_GOVERNANCE_QUERIES} and\n * {@link AGENT_PRICING_STORE} are visible app-wide — `AgentModule` resolves the store without an\n * explicit `store` option, and the dashboard/telescope resolve {@link AGENT_GOVERNANCE_QUERIES}\n * without the host re-binding it.\n *\n * ```ts\n * @Module({ imports: [DrizzleAgentStoreModule.forRoot({ db })] })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class DrizzleAgentStoreModule {\n static forRoot(options: DrizzleAgentStoreModuleOptions): DynamicModule {\n return {\n module: DrizzleAgentStoreModule,\n global: true,\n providers: [\n { provide: DrizzleAgentStore, useFactory: () => new DrizzleAgentStore(options.db) },\n { provide: AGENT_STORE, useExisting: DrizzleAgentStore },\n {\n provide: DrizzleGovernanceQueries,\n useFactory: () => new DrizzleGovernanceQueries(options.db),\n },\n { provide: AGENT_GOVERNANCE_QUERIES, useExisting: DrizzleGovernanceQueries },\n {\n provide: DrizzlePricingStore,\n useFactory: () => new DrizzlePricingStore(options.db),\n },\n { provide: AGENT_PRICING_STORE, useExisting: DrizzlePricingStore },\n ],\n exports: [\n DrizzleAgentStore,\n AGENT_STORE,\n DrizzleGovernanceQueries,\n AGENT_GOVERNANCE_QUERIES,\n DrizzlePricingStore,\n AGENT_PRICING_STORE,\n ],\n };\n }\n}\n"],"mappings":"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","names":["agentThread","sqliteTable","id","text","primaryKey","actorRef","notNull","tenantRef","title","transient","integer","mode","default","activeStreamId","createdAt","updatedAt","deletedAt","table","index","on","agentMessage","threadId","references","onDelete","role","$type","content","toolCalls","toolResults","followUps","usage","agentName","agentToolCall","messageId","toolName","toolType","input","output","status","executedByRef","executionMs","error","executedAt","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","real","agentModelPricing","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","isCurrent","agentSchema","statements","ensureAgentSchema","db","statement","run","sql","raw","import_drizzle_orm","DrizzleAgentStore","db","createThread","input","now","Date","thread","id","crypto","randomUUID","actorRef","actor","tenantRef","title","transient","activeStreamId","createdAt","updatedAt","deletedAt","insert","agentThread","values","toSummary","getThread","threadId","select","from","where","and","eq","isNull","undefined","messages","agentMessage","orderBy","asc","last","length","content","map","message","toStoredMessage","listThreads","limit","threads","desc","summaries","push","softDeleteThread","update","set","forkThread","fromMessageId","source","Error","cutoff","findIndex","kept","slice","fork","role","toolCalls","toolResults","followUps","usage","agentName","ownerOfThread","ownerOfToolCall","toolCallId","row","agentToolCall","innerJoin","messageId","runForToolCall","ownerOfActiveStream","runId","setTitle","setActiveStream","appendMessage","truncateFrom","doomedIds","delete","inArray","recordToolCall","toolName","toolType","output","status","executedByRef","executionMs","error","executedAt","updateToolCall","updates","recordUsage","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","quotaToday","day","start","end","rows","gte","lte","usedTokens","reduce","sum","lastContent","toISOString","lastMessagePreview","import_drizzle_orm","estimateFromTokens","pricing","row","price","get","modelId","undefined","cacheWriteTokens","cacheReadTokens","uncachedInputTokens","inputTokens","inputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","outputTokens","outputPricePer1m","rowCost","costUsd","dayBounds","range","start","Date","fromDay","end","toDay","DrizzleGovernanceQueries","db","loadPricing","rows","select","from","agentModelPricing","where","eq","isCurrent","Map","set","usageInRange","agentTokenUsage","and","gte","createdAt","lte","spendByModel","byModel","bucket","requests","result","push","sort","left","right","localeCompare","spendByActor","byActor","actorRef","totalTokens","usageTrend","byDay","day","toISOString","slice","recentToolCalls","limit","toolCallId","agentToolCall","id","toolName","toolType","status","threadId","agentMessage","innerJoin","messageId","orderBy","desc","map","recentThreads","threads","agentThread","isNull","deletedAt","updatedAt","thread","messageCountRow","value","count","usageRows","reduce","sum","title","messageCount","lastActivityAt","import_drizzle_orm","DrizzlePricingStore","db","upsertModelPrice","input","update","agentModelPricing","set","isCurrent","where","and","eq","modelId","insert","values","id","crypto","randomUUID","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","Date","listCurrentPrices","rows","select","from","map","row","toISOString","DrizzleAgentStoreModule","forRoot","options","module","global","providers","provide","DrizzleAgentStore","useFactory","db","AGENT_STORE","useExisting","DrizzleGovernanceQueries","AGENT_GOVERNANCE_QUERIES","DrizzlePricingStore","AGENT_PRICING_STORE","exports"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/schema.ts","../src/ensure-schema.ts","../src/drizzle-agent-store.ts","../src/drizzle-governance-queries.ts","../src/drizzle-pricing-store.ts","../src/drizzle-agent-store.module.ts"],"sourcesContent":["export * from './schema.js';\nexport * from './ensure-schema.js';\nexport * from './drizzle-agent-store.js';\nexport * from './drizzle-governance-queries.js';\nexport * from './drizzle-pricing-store.js';\nexport * from './drizzle-agent-store.module.js';\n","import type {\n MessageRole,\n MessageUsage,\n ToolCallRequest,\n ToolCallStatus,\n ToolKind,\n ToolResult,\n UsagePurpose,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n type BaseSQLiteDatabase,\n index,\n integer,\n real,\n sqliteTable,\n text,\n} from 'drizzle-orm/sqlite-core';\n\n/**\n * Drizzle schema mirroring the MikroORM agent entities (same logical columns/relations):\n * threads, messages, tool calls, token usage and model pricing. Targets the SQLite core so the\n * db-test runs on an in-memory better-sqlite3; timestamps are stored as integer epoch-ms columns\n * (`{ mode: 'timestamp_ms' }`) which Drizzle round-trips to/from JS `Date`, and the model-facing\n * message extras (tool calls/results, follow-ups, usage) live in JSON `text` columns.\n */\n\n/**\n * A conversation thread. `deletedAt` drives soft delete: a deleted thread is hidden from\n * {@link import('./drizzle-agent-store.js').DrizzleAgentStore.getThread}/`listThreads` but its\n * row survives.\n */\nexport const agentThread = sqliteTable(\n 'agent_thread',\n {\n id: text('id').primaryKey(),\n actorRef: text('actor_ref').notNull(),\n tenantRef: text('tenant_ref'),\n title: text('title').notNull(),\n transient: integer('transient', { mode: 'boolean' }).notNull().default(false),\n activeStreamId: text('active_stream_id'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n deletedAt: integer('deleted_at', { mode: 'timestamp_ms' }),\n },\n (table) => [index('agent_thread_actor_updated_idx').on(table.actorRef, table.updatedAt)],\n);\n\n/**\n * One stored message in a thread. The model-facing extras (`toolCalls`/`toolResults`/\n * `followUps`/`usage`) are folded into nullable JSON columns so a single row round-trips to a\n * {@link import('@dudousxd/nestjs-agent-core').StoredMessage}. `threadId` cascades on delete.\n */\nexport const agentMessage = sqliteTable(\n 'agent_message',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n role: text('role').$type<MessageRole>().notNull(),\n content: text('content').notNull(),\n toolCalls: text('tool_calls', { mode: 'json' }).$type<ToolCallRequest[]>(),\n toolResults: text('tool_results', { mode: 'json' }).$type<ToolResult[]>(),\n followUps: text('follow_ups', { mode: 'json' }).$type<string[]>(),\n usage: text('usage', { mode: 'json' }).$type<MessageUsage>(),\n agentName: text('agent_name'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_message_thread_created_idx').on(table.threadId, table.createdAt)],\n);\n\n/** A tool call requested during an assistant turn. The pk is the model-supplied `toolCallId`. */\nexport const agentToolCall = sqliteTable('agent_tool_call', {\n id: text('id').primaryKey(),\n messageId: text('message_id')\n .notNull()\n .references(() => agentMessage.id, { onDelete: 'cascade' }),\n toolName: text('tool_name').notNull(),\n toolType: text('tool_type').$type<ToolKind>().notNull(),\n input: text('input', { mode: 'json' }),\n output: text('output', { mode: 'json' }),\n status: text('status').$type<ToolCallStatus>().notNull(),\n executedByRef: text('executed_by_ref'),\n executionMs: integer('execution_ms'),\n error: text('error'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n executedAt: integer('executed_at', { mode: 'timestamp_ms' }),\n});\n\n/** A token-usage ledger row, summed per actor per day by `quotaToday`. */\nexport const agentTokenUsage = sqliteTable(\n 'agent_token_usage',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n actorRef: text('actor_ref').notNull(),\n messageId: text('message_id'),\n modelId: text('model_id').notNull(),\n purpose: text('purpose').$type<UsagePurpose>().notNull(),\n inputTokens: integer('input_tokens').notNull(),\n outputTokens: integer('output_tokens').notNull(),\n /** Subset of `inputTokens` written to the prompt cache this turn; null when not reported. */\n cacheWriteTokens: integer('cache_write_tokens'),\n /** Subset of `inputTokens` served from the prompt cache this turn; null when not reported. */\n cacheReadTokens: integer('cache_read_tokens'),\n /** Provider-reported actual USD cost for the turn; null when only tokens were reported. */\n costUsd: real('cost_usd'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_token_usage_actor_created_idx').on(table.actorRef, table.createdAt)],\n);\n\n/** Per-model token pricing, versioned by `effectiveFrom`; `isCurrent` flags the live row. */\nexport const agentModelPricing = sqliteTable('agent_model_pricing', {\n id: text('id').primaryKey(),\n modelId: text('model_id').notNull(),\n inputPricePer1m: real('input_price_per_1m').notNull(),\n outputPricePer1m: real('output_price_per_1m').notNull(),\n /** Per-1M price for cache-write input tokens; null → price them at the input rate. */\n cacheWritePricePer1m: real('cache_write_price_per_1m'),\n /** Per-1M price for cache-read input tokens; null → price them at the input rate. */\n cacheReadPricePer1m: real('cache_read_price_per_1m'),\n effectiveFrom: integer('effective_from', { mode: 'timestamp_ms' }).notNull(),\n isCurrent: integer('is_current', { mode: 'boolean' }).notNull(),\n});\n\n/** The five agent tables as one schema object, ready for `drizzle(client, { schema })`. */\nexport const agentSchema = {\n agentThread,\n agentMessage,\n agentToolCall,\n agentTokenUsage,\n agentModelPricing,\n};\n\n/**\n * The dialect-portable Drizzle SQLite database handle the store operates on. Accepts any SQLite\n * driver (better-sqlite3, libsql, D1, …) in either sync or async result mode; the host app owns\n * the connection and passes the `drizzle(...)` instance in.\n */\nexport type AgentDrizzleDb = BaseSQLiteDatabase<'sync' | 'async', unknown>;\n\n/** A persisted thread row as Drizzle selects it. */\nexport type AgentThreadRow = typeof agentThread.$inferSelect;\n/** A persisted message row as Drizzle selects it. */\nexport type AgentMessageRow = typeof agentMessage.$inferSelect;\n","import { sql } from 'drizzle-orm';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/**\n * Idempotent `CREATE TABLE IF NOT EXISTS` DDL for the five agent tables, mirroring\n * {@link import('./schema.js').agentSchema}. SQLite dialect (the db-test driver); kept here rather\n * than relying on drizzle-kit so the package can stand up its schema with no migration files. Safe\n * to run on boot against a shared database — it never drops or alters existing columns.\n */\nconst statements: string[] = [\n `CREATE TABLE IF NOT EXISTS agent_thread (\n id TEXT PRIMARY KEY NOT NULL,\n actor_ref TEXT NOT NULL,\n tenant_ref TEXT,\n title TEXT NOT NULL,\n transient INTEGER NOT NULL DEFAULT 0,\n active_stream_id TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n deleted_at INTEGER\n )`,\n `CREATE INDEX IF NOT EXISTS agent_thread_actor_updated_idx\n ON agent_thread (actor_ref, updated_at)`,\n `CREATE TABLE IF NOT EXISTS agent_message (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n tool_calls TEXT,\n tool_results TEXT,\n follow_ups TEXT,\n usage TEXT,\n agent_name TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx\n ON agent_message (thread_id, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_tool_call (\n id TEXT PRIMARY KEY NOT NULL,\n message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n tool_type TEXT NOT NULL,\n input TEXT,\n output TEXT,\n status TEXT NOT NULL,\n executed_by_ref TEXT,\n execution_ms INTEGER,\n error TEXT,\n created_at INTEGER NOT NULL,\n executed_at INTEGER\n )`,\n `CREATE TABLE IF NOT EXISTS agent_token_usage (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n actor_ref TEXT NOT NULL,\n message_id TEXT,\n model_id TEXT NOT NULL,\n purpose TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n cache_write_tokens INTEGER,\n cache_read_tokens INTEGER,\n cost_usd REAL,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_token_usage_actor_created_idx\n ON agent_token_usage (actor_ref, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_model_pricing (\n id TEXT PRIMARY KEY NOT NULL,\n model_id TEXT NOT NULL,\n input_price_per_1m REAL NOT NULL,\n output_price_per_1m REAL NOT NULL,\n cache_write_price_per_1m REAL,\n cache_read_price_per_1m REAL,\n effective_from INTEGER NOT NULL,\n is_current INTEGER NOT NULL\n )`,\n];\n\n/** Runs the `CREATE TABLE IF NOT EXISTS` DDL above against the supplied Drizzle SQLite db. */\nexport async function ensureAgentSchema(db: AgentDrizzleDb): Promise<void> {\n for (const statement of statements) {\n await db.run(sql.raw(statement));\n }\n}\n","import type {\n AgentStore,\n AppendMessageInput,\n CreateThreadInput,\n RecordToolCallInput,\n RecordUsageInput,\n StoredMessage,\n ThreadDetail,\n ThreadSummary,\n UpdateToolCallInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, asc, desc, eq, gte, inArray, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n type AgentMessageRow,\n type AgentThreadRow,\n agentMessage,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/**\n * {@link AgentStore} backed by Drizzle ORM — a second adapter alongside the MikroORM one, proving\n * the store SPI is ORM-portable. A POJO receiving a Drizzle SQLite database handle (the host app\n * owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}\n * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.\n */\nexport class DrizzleAgentStore implements AgentStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async createThread(input: CreateThreadInput): Promise<ThreadSummary> {\n const now = new Date();\n const thread: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: input.actor.id,\n tenantRef: input.actor.tenantRef ?? null,\n title: input.title ?? 'New chat',\n transient: input.transient ?? false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(thread);\n return this.toSummary(thread);\n }\n\n async getThread(threadId: string): Promise<ThreadDetail | null> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n if (thread === undefined) {\n return null;\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const last = messages[messages.length - 1];\n return {\n ...this.toSummary(thread, last?.content),\n messages: messages.map((message) => this.toStoredMessage(message)),\n ...(thread.activeStreamId != null ? { activeStreamId: thread.activeStreamId } : {}),\n };\n }\n\n async listThreads(actorRef: string, limit = 50): Promise<ThreadSummary[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(\n and(\n eq(agentThread.actorRef, actorRef),\n eq(agentThread.transient, false),\n isNull(agentThread.deletedAt),\n ),\n )\n .orderBy(desc(agentThread.updatedAt))\n .limit(limit);\n const summaries: ThreadSummary[] = [];\n for (const thread of threads) {\n const [last] = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id))\n .orderBy(desc(agentMessage.createdAt), desc(agentMessage.id))\n .limit(1);\n summaries.push(this.toSummary(thread, last?.content));\n }\n return summaries;\n }\n\n async softDeleteThread(threadId: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ deletedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary> {\n const [source] = await this.db.select().from(agentThread).where(eq(agentThread.id, threadId));\n if (source === undefined) {\n throw new Error(`thread ${threadId} not found`);\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === fromMessageId);\n const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;\n const now = new Date();\n const fork: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: source.actorRef,\n tenantRef: source.tenantRef,\n title: source.title,\n transient: false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(fork);\n if (kept.length > 0) {\n await this.db.insert(agentMessage).values(\n kept.map((message) => ({\n id: crypto.randomUUID(),\n threadId: fork.id,\n role: message.role,\n content: message.content,\n toolCalls: message.toolCalls,\n toolResults: message.toolResults,\n followUps: message.followUps,\n usage: message.usage,\n agentName: message.agentName,\n createdAt: message.createdAt,\n })),\n );\n }\n return this.toSummary(fork);\n }\n\n async ownerOfThread(threadId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async ownerOfToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.actorRef ?? null;\n }\n\n async runForToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ activeStreamId: agentThread.activeStreamId })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.activeStreamId ?? null;\n }\n\n async ownerOfActiveStream(runId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.activeStreamId, runId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async setTitle(threadId: string, title: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ title, updatedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async promoteThread(threadId: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ transient: false, updatedAt: new Date() })\n .where(and(eq(agentThread.id, threadId), eq(agentThread.transient, true)));\n }\n\n async setActiveStream(threadId: string, runId: string | null): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ activeStreamId: runId })\n .where(eq(agentThread.id, threadId));\n }\n\n async appendMessage(input: AppendMessageInput): Promise<StoredMessage> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(eq(agentThread.id, input.threadId));\n if (thread === undefined) {\n throw new Error(`thread ${input.threadId} not found`);\n }\n const now = new Date();\n const message: AgentMessageRow = {\n id: crypto.randomUUID(),\n threadId: input.threadId,\n role: input.role,\n content: input.content,\n toolCalls: input.toolCalls ?? null,\n toolResults: input.toolResults ?? null,\n followUps: input.followUps ?? null,\n usage: input.usage ?? null,\n agentName: input.agentName ?? null,\n createdAt: now,\n };\n await this.db.insert(agentMessage).values(message);\n await this.db\n .update(agentThread)\n .set({ updatedAt: now })\n .where(eq(agentThread.id, input.threadId));\n return this.toStoredMessage(message);\n }\n\n async truncateFrom(threadId: string, messageId: string): Promise<void> {\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === messageId);\n if (cutoff < 0) {\n return;\n }\n const doomedIds = messages.slice(cutoff).map((message) => message.id);\n await this.db.delete(agentToolCall).where(inArray(agentToolCall.messageId, doomedIds));\n await this.db.delete(agentMessage).where(inArray(agentMessage.id, doomedIds));\n }\n\n async recordToolCall(input: RecordToolCallInput): Promise<void> {\n await this.db.insert(agentToolCall).values({\n id: input.toolCallId,\n messageId: input.messageId,\n toolName: input.toolName,\n toolType: input.toolType,\n input: input.input,\n output: null,\n status: input.status,\n executedByRef: null,\n executionMs: null,\n error: null,\n createdAt: new Date(),\n executedAt: null,\n });\n }\n\n async updateToolCall(input: UpdateToolCallInput): Promise<void> {\n const updates: Partial<typeof agentToolCall.$inferInsert> = { status: input.status };\n if (input.output !== undefined) {\n updates.output = input.output;\n }\n if (input.error !== undefined) {\n updates.error = input.error;\n }\n if (input.executionMs !== undefined) {\n updates.executionMs = input.executionMs;\n }\n if (input.executedByRef !== undefined) {\n updates.executedByRef = input.executedByRef;\n }\n if (input.status === 'executed' || input.status === 'auto_executed') {\n updates.executedAt = new Date();\n }\n await this.db.update(agentToolCall).set(updates).where(eq(agentToolCall.id, input.toolCallId));\n }\n\n async recordUsage(input: RecordUsageInput): Promise<void> {\n await this.db.insert(agentTokenUsage).values({\n id: crypto.randomUUID(),\n threadId: input.threadId,\n actorRef: input.actorRef,\n messageId: input.messageId ?? null,\n modelId: input.modelId,\n purpose: input.purpose,\n inputTokens: input.usage.inputTokens,\n outputTokens: input.usage.outputTokens,\n cacheWriteTokens: input.usage.cacheWriteTokens ?? null,\n cacheReadTokens: input.usage.cacheReadTokens ?? null,\n costUsd: input.costUsd ?? null,\n createdAt: new Date(),\n });\n }\n\n async quotaToday(\n actorRef: string,\n day: string,\n ): Promise<{ usedTokens: number; costUsd: number }> {\n const start = new Date(`${day}T00:00:00.000Z`);\n const end = new Date(`${day}T23:59:59.999Z`);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(\n and(\n eq(agentTokenUsage.actorRef, actorRef),\n gte(agentTokenUsage.createdAt, start),\n lte(agentTokenUsage.createdAt, end),\n ),\n );\n const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);\n const costUsd = rows.reduce((sum, row) => sum + (row.costUsd ?? 0), 0);\n return { usedTokens, costUsd };\n }\n\n private toSummary(thread: AgentThreadRow, lastContent?: string): ThreadSummary {\n return {\n id: thread.id,\n title: thread.title,\n transient: thread.transient,\n createdAt: thread.createdAt.toISOString(),\n updatedAt: thread.updatedAt.toISOString(),\n ...(lastContent !== undefined ? { lastMessagePreview: lastContent.slice(0, 120) } : {}),\n };\n }\n\n private toStoredMessage(message: AgentMessageRow): StoredMessage {\n return {\n id: message.id,\n role: message.role,\n content: message.content,\n createdAt: message.createdAt.toISOString(),\n ...(message.toolCalls != null ? { toolCalls: message.toolCalls } : {}),\n ...(message.toolResults != null ? { toolResults: message.toolResults } : {}),\n ...(message.followUps != null ? { followUps: message.followUps } : {}),\n ...(message.usage != null ? { usage: message.usage } : {}),\n ...(message.agentName != null ? { agentName: message.agentName } : {}),\n };\n }\n}\n","import type {\n ActorSpendRow,\n AgentGovernanceQueries,\n AgentPricingStore,\n GovernanceRange,\n ModelSpendRow,\n ThreadActivityRow,\n ThreadSpendRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, count, desc, eq, gte, inArray, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n agentMessage,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/** The current per-1M token prices for one model; cache rates fall back to the input rate. */\ninterface ModelPrice {\n inputPricePer1m: number;\n outputPricePer1m: number;\n cacheWritePricePer1m?: number | null;\n cacheReadPricePer1m?: number | null;\n}\n\n/**\n * Token-ledger estimate for one usage row against the current pricing row: the uncached input at the\n * input rate, cache-write/cache-read tokens at their own rates (falling back to the input rate when\n * unpriced), plus output at the output rate. An unpriced model contributes 0 (tokens still count).\n * Cache token counts are subsets of `inputTokens`, so the uncached remainder is the difference.\n */\nfunction estimateFromTokens(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n const price = pricing.get(row.modelId);\n if (price === undefined) {\n return 0;\n }\n const cacheWriteTokens = row.cacheWriteTokens ?? 0;\n const cacheReadTokens = row.cacheReadTokens ?? 0;\n const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;\n return (\n (uncachedInputTokens / 1_000_000) * price.inputPricePer1m +\n (cacheWriteTokens / 1_000_000) * (price.cacheWritePricePer1m ?? price.inputPricePer1m) +\n (cacheReadTokens / 1_000_000) * (price.cacheReadPricePer1m ?? price.inputPricePer1m) +\n (row.outputTokens / 1_000_000) * price.outputPricePer1m\n );\n}\n\n/**\n * The cost of one usage row: the provider-reported `costUsd` when present (gateways report real\n * spend), otherwise the cache-aware token estimate against the current pricing row.\n */\nfunction rowCost(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n return row.costUsd ?? estimateFromTokens(pricing, row);\n}\n\n/** Turns an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used by `quotaToday`. */\nfunction dayBounds(range: GovernanceRange): { start: Date; end: Date } {\n return {\n start: new Date(`${range.fromDay}T00:00:00.000Z`),\n end: new Date(`${range.toDay}T23:59:59.999Z`),\n };\n}\n\n/**\n * {@link AgentGovernanceQueries} backed by Drizzle ORM — the read/analytics half of the store SPI,\n * mirroring {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly. Cost is the token\n * ledger priced against the current prices from the injected {@link AgentPricingStore}\n * (`AGENT_PRICING_STORE`), so a host that binds its own pricing store controls the cost every\n * governance surface reports. An unpriced model contributes 0 cost. Aggregation is in-process (like\n * `quotaToday`) so day-bucketing stays dialect-portable.\n */\nexport class DrizzleGovernanceQueries implements AgentGovernanceQueries {\n constructor(\n private readonly db: AgentDrizzleDb,\n private readonly pricingStore: AgentPricingStore,\n ) {}\n\n private async loadPricing(): Promise<Map<string, ModelPrice>> {\n const prices = await this.pricingStore.listCurrentPrices();\n const pricing = new Map<string, ModelPrice>();\n for (const price of prices) {\n pricing.set(price.modelId, {\n inputPricePer1m: price.inputPricePer1m,\n outputPricePer1m: price.outputPricePer1m,\n cacheWritePricePer1m: price.cacheWritePricePer1m ?? null,\n cacheReadPricePer1m: price.cacheReadPricePer1m ?? null,\n });\n }\n return pricing;\n }\n\n private async usageInRange(\n range: GovernanceRange,\n ): Promise<(typeof agentTokenUsage.$inferSelect)[]> {\n const { start, end } = dayBounds(range);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(and(gte(agentTokenUsage.createdAt, start), lte(agentTokenUsage.createdAt, end)));\n return rows;\n }\n\n async spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byModel = new Map<\n string,\n { requests: number; inputTokens: number; outputTokens: number; costUsd: number }\n >();\n for (const row of rows) {\n const bucket = byModel.get(row.modelId) ?? {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n costUsd: 0,\n };\n bucket.requests += 1;\n bucket.inputTokens += row.inputTokens;\n bucket.outputTokens += row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byModel.set(row.modelId, bucket);\n }\n const result: ModelSpendRow[] = [];\n for (const [modelId, bucket] of byModel) {\n result.push({\n modelId,\n requests: bucket.requests,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId),\n );\n return result;\n }\n\n async spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byActor = new Map<\n string,\n { requests: number; totalTokens: number; costUsd: number; threadIds: Set<string> }\n >();\n for (const row of rows) {\n const bucket = byActor.get(row.actorRef) ?? {\n requests: 0,\n totalTokens: 0,\n costUsd: 0,\n threadIds: new Set<string>(),\n };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n bucket.threadIds.add(row.threadId);\n byActor.set(row.actorRef, bucket);\n }\n const result: ActorSpendRow[] = [];\n for (const [actorRef, bucket] of byActor) {\n result.push({\n actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n threadCount: bucket.threadIds.size,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef),\n );\n return result;\n }\n\n /**\n * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a\n * soft-deleted thread (`deletedAt` set) are excluded — the thread no longer surfaces as a\n * governance target even though its ledger rows survive.\n */\n async spendByThread(range: GovernanceRange, limit: number): Promise<ThreadSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byThread = new Map<string, { requests: number; totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byThread.get(row.threadId) ?? { requests: 0, totalTokens: 0, costUsd: 0 };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byThread.set(row.threadId, bucket);\n }\n if (byThread.size === 0) {\n return [];\n }\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(and(inArray(agentThread.id, [...byThread.keys()]), isNull(agentThread.deletedAt)));\n const threadsById = new Map(threads.map((thread) => [thread.id, thread]));\n const result: ThreadSpendRow[] = [];\n for (const [threadId, bucket] of byThread) {\n const thread = threadsById.get(threadId);\n if (thread === undefined) {\n continue;\n }\n result.push({\n threadId,\n title: thread.title,\n actorRef: thread.actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId),\n );\n return result.slice(0, limit);\n }\n\n async usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byDay = new Map<string, { totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const day = row.createdAt.toISOString().slice(0, 10);\n const bucket = byDay.get(day) ?? { totalTokens: 0, costUsd: 0 };\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byDay.set(day, bucket);\n }\n const result: UsageTrendPoint[] = [];\n for (const [day, bucket] of byDay) {\n result.push({ day, totalTokens: bucket.totalTokens, costUsd: bucket.costUsd });\n }\n result.sort((left, right) => left.day.localeCompare(right.day));\n return result;\n }\n\n async recentToolCalls(limit: number): Promise<ToolCallActivityRow[]> {\n const rows = await this.db\n .select({\n toolCallId: agentToolCall.id,\n toolName: agentToolCall.toolName,\n toolType: agentToolCall.toolType,\n status: agentToolCall.status,\n threadId: agentMessage.threadId,\n createdAt: agentToolCall.createdAt,\n })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .orderBy(desc(agentToolCall.createdAt), desc(agentToolCall.id))\n .limit(limit);\n return rows.map((row) => ({\n toolCallId: row.toolCallId,\n toolName: row.toolName,\n toolType: row.toolType,\n status: row.status,\n threadId: row.threadId,\n createdAt: row.createdAt.toISOString(),\n }));\n }\n\n async recentThreads(limit: number): Promise<ThreadActivityRow[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(isNull(agentThread.deletedAt))\n .orderBy(desc(agentThread.updatedAt), desc(agentThread.id))\n .limit(limit);\n const result: ThreadActivityRow[] = [];\n for (const thread of threads) {\n const [messageCountRow] = await this.db\n .select({ value: count() })\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id));\n const usageRows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(eq(agentTokenUsage.threadId, thread.id));\n const totalTokens = usageRows.reduce(\n (sum, row) => sum + row.inputTokens + row.outputTokens,\n 0,\n );\n result.push({\n threadId: thread.id,\n title: thread.title,\n actorRef: thread.actorRef,\n messageCount: messageCountRow?.value ?? 0,\n totalTokens,\n lastActivityAt: thread.updatedAt.toISOString(),\n });\n }\n return result;\n }\n}\n","import type {\n AgentPricingStore,\n CurrentModelPrice,\n ModelPriceInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, eq } from 'drizzle-orm';\nimport { type AgentDrizzleDb, agentModelPricing } from './schema.js';\n\n/**\n * {@link AgentPricingStore} backed by Drizzle ORM — the write side of the pricing table\n * {@link import('./drizzle-governance-queries.js').DrizzleGovernanceQueries} joins against. A POJO\n * receiving a Drizzle SQLite database handle (the host app owns the connection), mirroring\n * {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly (atomic supersede semantics).\n */\nexport class DrizzlePricingStore implements AgentPricingStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async upsertModelPrice(input: ModelPriceInput): Promise<void> {\n await this.db\n .update(agentModelPricing)\n .set({ isCurrent: false })\n .where(\n and(eq(agentModelPricing.modelId, input.modelId), eq(agentModelPricing.isCurrent, true)),\n );\n await this.db.insert(agentModelPricing).values({\n id: crypto.randomUUID(),\n modelId: input.modelId,\n inputPricePer1m: input.inputPricePer1m,\n outputPricePer1m: input.outputPricePer1m,\n cacheWritePricePer1m: input.cacheWritePricePer1m ?? null,\n cacheReadPricePer1m: input.cacheReadPricePer1m ?? null,\n effectiveFrom: new Date(),\n isCurrent: true,\n });\n }\n\n async listCurrentPrices(): Promise<CurrentModelPrice[]> {\n const rows = await this.db\n .select()\n .from(agentModelPricing)\n .where(eq(agentModelPricing.isCurrent, true));\n return rows.map((row) => ({\n modelId: row.modelId,\n inputPricePer1m: row.inputPricePer1m,\n outputPricePer1m: row.outputPricePer1m,\n effectiveFrom: row.effectiveFrom.toISOString(),\n ...(row.cacheWritePricePer1m != null\n ? { cacheWritePricePer1m: row.cacheWritePricePer1m }\n : {}),\n ...(row.cacheReadPricePer1m != null ? { cacheReadPricePer1m: row.cacheReadPricePer1m } : {}),\n }));\n }\n}\n","import {\n AGENT_GOVERNANCE_QUERIES,\n AGENT_PRICING_STORE,\n AGENT_STORE,\n type AgentPricingStore,\n} from '@dudousxd/nestjs-agent-core';\nimport { type DynamicModule, Module, type Type } from '@nestjs/common';\nimport { DrizzleAgentStore } from './drizzle-agent-store.js';\nimport { DrizzleGovernanceQueries } from './drizzle-governance-queries.js';\nimport { DrizzlePricingStore } from './drizzle-pricing-store.js';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/** Options for {@link DrizzleAgentStoreModule.forRoot}. The app owns and supplies the db handle. */\nexport interface DrizzleAgentStoreModuleOptions {\n /** A Drizzle SQLite database instance (`drizzle(client, { schema: agentSchema })`). */\n db: AgentDrizzleDb;\n /**\n * Bind {@link AGENT_PRICING_STORE} (which {@link DrizzleGovernanceQueries} prices usage against) to\n * a host-supplied store instead of the default {@link DrizzlePricingStore} — make your OWN pricing\n * table the single source of cost truth without touching `agent_model_pricing`.\n */\n pricingStore?: Type<AgentPricingStore>;\n}\n\n/**\n * Binds {@link DrizzleAgentStore} to the {@link AGENT_STORE} token consumed by\n * `@dudousxd/nestjs-agent`, plus {@link DrizzleGovernanceQueries} to\n * {@link AGENT_GOVERNANCE_QUERIES} (the read-model the dashboard/telescope surfaces consume) and\n * {@link DrizzlePricingStore} to {@link AGENT_PRICING_STORE} (the write side of that pricing table).\n * The host app supplies an already-opened Drizzle db — this module never opens a connection itself.\n *\n * The returned module is global, so {@link AGENT_STORE}, {@link AGENT_GOVERNANCE_QUERIES} and\n * {@link AGENT_PRICING_STORE} are visible app-wide — `AgentModule` resolves the store without an\n * explicit `store` option, and the dashboard/telescope resolve {@link AGENT_GOVERNANCE_QUERIES}\n * without the host re-binding it.\n *\n * ```ts\n * @Module({ imports: [DrizzleAgentStoreModule.forRoot({ db })] })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class DrizzleAgentStoreModule {\n static forRoot(options: DrizzleAgentStoreModuleOptions): DynamicModule {\n return {\n module: DrizzleAgentStoreModule,\n global: true,\n providers: [\n { provide: DrizzleAgentStore, useFactory: () => new DrizzleAgentStore(options.db) },\n { provide: AGENT_STORE, useExisting: DrizzleAgentStore },\n {\n provide: DrizzlePricingStore,\n useFactory: () => new DrizzlePricingStore(options.db),\n },\n // AGENT_PRICING_STORE: the host's own store when supplied, else the default Drizzle one.\n // DrizzleGovernanceQueries prices usage against whatever is bound here.\n options.pricingStore\n ? { provide: AGENT_PRICING_STORE, useClass: options.pricingStore }\n : { provide: AGENT_PRICING_STORE, useExisting: DrizzlePricingStore },\n {\n provide: DrizzleGovernanceQueries,\n useFactory: (pricingStore: AgentPricingStore) =>\n new DrizzleGovernanceQueries(options.db, pricingStore),\n inject: [AGENT_PRICING_STORE],\n },\n { provide: AGENT_GOVERNANCE_QUERIES, useExisting: DrizzleGovernanceQueries },\n ],\n exports: [\n DrizzleAgentStore,\n AGENT_STORE,\n DrizzleGovernanceQueries,\n AGENT_GOVERNANCE_QUERIES,\n DrizzlePricingStore,\n AGENT_PRICING_STORE,\n ],\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;ACSA,yBAOO;AAeA,IAAMA,kBAAcC,gCACzB,gBACA;EACEC,QAAIC,yBAAK,IAAA,EAAMC,WAAU;EACzBC,cAAUF,yBAAK,WAAA,EAAaG,QAAO;EACnCC,eAAWJ,yBAAK,YAAA;EAChBK,WAAOL,yBAAK,OAAA,EAASG,QAAO;EAC5BG,eAAWC,4BAAQ,aAAa;IAAEC,MAAM;EAAU,CAAA,EAAGL,QAAO,EAAGM,QAAQ,KAAA;EACvEC,oBAAgBV,yBAAK,kBAAA;EACrBW,eAAWJ,4BAAQ,cAAc;IAAEC,MAAM;EAAe,CAAA,EAAGL,QAAO;EAClES,eAAWL,4BAAQ,cAAc;IAAEC,MAAM;EAAe,CAAA,EAAGL,QAAO;EAClEU,eAAWN,4BAAQ,cAAc;IAAEC,MAAM;EAAe,CAAA;AAC1D,GACA,CAACM,UAAU;MAACC,0BAAM,gCAAA,EAAkCC,GAAGF,MAAMZ,UAAUY,MAAMF,SAAS;CAAE;AAQnF,IAAMK,mBAAenB,gCAC1B,iBACA;EACEC,QAAIC,yBAAK,IAAA,EAAMC,WAAU;EACzBiB,cAAUlB,yBAAK,WAAA,EACZG,QAAO,EACPgB,WAAW,MAAMtB,YAAYE,IAAI;IAAEqB,UAAU;EAAU,CAAA;EAC1DC,UAAMrB,yBAAK,MAAA,EAAQsB,MAAK,EAAgBnB,QAAO;EAC/CoB,aAASvB,yBAAK,SAAA,EAAWG,QAAO;EAChCqB,eAAWxB,yBAAK,cAAc;IAAEQ,MAAM;EAAO,CAAA,EAAGc,MAAK;EACrDG,iBAAazB,yBAAK,gBAAgB;IAAEQ,MAAM;EAAO,CAAA,EAAGc,MAAK;EACzDI,eAAW1B,yBAAK,cAAc;IAAEQ,MAAM;EAAO,CAAA,EAAGc,MAAK;EACrDK,WAAO3B,yBAAK,SAAS;IAAEQ,MAAM;EAAO,CAAA,EAAGc,MAAK;EAC5CM,eAAW5B,yBAAK,YAAA;EAChBW,eAAWJ,4BAAQ,cAAc;IAAEC,MAAM;EAAe,CAAA,EAAGL,QAAO;AACpE,GACA,CAACW,UAAU;MAACC,0BAAM,kCAAA,EAAoCC,GAAGF,MAAMI,UAAUJ,MAAMH,SAAS;CAAE;AAIrF,IAAMkB,oBAAgB/B,gCAAY,mBAAmB;EAC1DC,QAAIC,yBAAK,IAAA,EAAMC,WAAU;EACzB6B,eAAW9B,yBAAK,YAAA,EACbG,QAAO,EACPgB,WAAW,MAAMF,aAAalB,IAAI;IAAEqB,UAAU;EAAU,CAAA;EAC3DW,cAAU/B,yBAAK,WAAA,EAAaG,QAAO;EACnC6B,cAAUhC,yBAAK,WAAA,EAAasB,MAAK,EAAanB,QAAO;EACrD8B,WAAOjC,yBAAK,SAAS;IAAEQ,MAAM;EAAO,CAAA;EACpC0B,YAAQlC,yBAAK,UAAU;IAAEQ,MAAM;EAAO,CAAA;EACtC2B,YAAQnC,yBAAK,QAAA,EAAUsB,MAAK,EAAmBnB,QAAO;EACtDiC,mBAAepC,yBAAK,iBAAA;EACpBqC,iBAAa9B,4BAAQ,cAAA;EACrB+B,WAAOtC,yBAAK,OAAA;EACZW,eAAWJ,4BAAQ,cAAc;IAAEC,MAAM;EAAe,CAAA,EAAGL,QAAO;EAClEoC,gBAAYhC,4BAAQ,eAAe;IAAEC,MAAM;EAAe,CAAA;AAC5D,CAAA;AAGO,IAAMgC,sBAAkB1C,gCAC7B,qBACA;EACEC,QAAIC,yBAAK,IAAA,EAAMC,WAAU;EACzBiB,cAAUlB,yBAAK,WAAA,EACZG,QAAO,EACPgB,WAAW,MAAMtB,YAAYE,IAAI;IAAEqB,UAAU;EAAU,CAAA;EAC1DlB,cAAUF,yBAAK,WAAA,EAAaG,QAAO;EACnC2B,eAAW9B,yBAAK,YAAA;EAChByC,aAASzC,yBAAK,UAAA,EAAYG,QAAO;EACjCuC,aAAS1C,yBAAK,SAAA,EAAWsB,MAAK,EAAiBnB,QAAO;EACtDwC,iBAAapC,4BAAQ,cAAA,EAAgBJ,QAAO;EAC5CyC,kBAAcrC,4BAAQ,eAAA,EAAiBJ,QAAO;;EAE9C0C,sBAAkBtC,4BAAQ,oBAAA;;EAE1BuC,qBAAiBvC,4BAAQ,mBAAA;;EAEzBwC,aAASC,yBAAK,UAAA;EACdrC,eAAWJ,4BAAQ,cAAc;IAAEC,MAAM;EAAe,CAAA,EAAGL,QAAO;AACpE,GACA,CAACW,UAAU;MAACC,0BAAM,qCAAA,EAAuCC,GAAGF,MAAMZ,UAAUY,MAAMH,SAAS;CAAE;AAIxF,IAAMsC,wBAAoBnD,gCAAY,uBAAuB;EAClEC,QAAIC,yBAAK,IAAA,EAAMC,WAAU;EACzBwC,aAASzC,yBAAK,UAAA,EAAYG,QAAO;EACjC+C,qBAAiBF,yBAAK,oBAAA,EAAsB7C,QAAO;EACnDgD,sBAAkBH,yBAAK,qBAAA,EAAuB7C,QAAO;;EAErDiD,0BAAsBJ,yBAAK,0BAAA;;EAE3BK,yBAAqBL,yBAAK,yBAAA;EAC1BM,mBAAe/C,4BAAQ,kBAAkB;IAAEC,MAAM;EAAe,CAAA,EAAGL,QAAO;EAC1EoD,eAAWhD,4BAAQ,cAAc;IAAEC,MAAM;EAAU,CAAA,EAAGL,QAAO;AAC/D,CAAA;AAGO,IAAMqD,cAAc;EACzB3D;EACAoB;EACAY;EACAW;EACAS;AACF;;;ACvIA,yBAAoB;AASpB,IAAMQ,aAAuB;EAC3B;;;;;;;;;;;EAWA;;EAEA;;;;;;;;;;;;EAYA;;EAEA;;;;;;;;;;;;;;EAcA;;;;;;;;;;;;;;EAcA;;EAEA;;;;;;;;;;;AAaF,eAAsBC,kBAAkBC,IAAkB;AACxD,aAAWC,aAAaH,YAAY;AAClC,UAAME,GAAGE,IAAIC,uBAAIC,IAAIH,SAAAA,CAAAA;EACvB;AACF;AAJsBF;;;ACrEtB,IAAAM,sBAA8D;AAiBvD,IAAMC,oBAAN,MAAMA;EAjBb,OAiBaA;;;;EACX,YAA6BC,IAAoB;SAApBA,KAAAA;EAAqB;EAElD,MAAMC,aAAaC,OAAkD;AACnE,UAAMC,MAAM,oBAAIC,KAAAA;AAChB,UAAMC,SAAyB;MAC7BC,IAAIC,OAAOC,WAAU;MACrBC,UAAUP,MAAMQ,MAAMJ;MACtBK,WAAWT,MAAMQ,MAAMC,aAAa;MACpCC,OAAOV,MAAMU,SAAS;MACtBC,WAAWX,MAAMW,aAAa;MAC9BC,gBAAgB;MAChBC,WAAWZ;MACXa,WAAWb;MACXc,WAAW;IACb;AACA,UAAM,KAAKjB,GAAGkB,OAAOC,WAAAA,EAAaC,OAAOf,MAAAA;AACzC,WAAO,KAAKgB,UAAUhB,MAAAA;EACxB;EAEA,MAAMiB,UAAUC,UAAgD;AAC9D,UAAM,CAAClB,MAAAA,IAAU,MAAM,KAAKL,GACzBwB,OAAM,EACNC,KAAKN,WAAAA,EACLO,UAAMC,6BAAIC,wBAAGT,YAAYb,IAAIiB,QAAAA,OAAWM,4BAAOV,YAAYF,SAAS,CAAA,CAAA;AACvE,QAAIZ,WAAWyB,QAAW;AACxB,aAAO;IACT;AACA,UAAMC,WAAW,MAAM,KAAK/B,GACzBwB,OAAM,EACNC,KAAKO,YAAAA,EACLN,UAAME,wBAAGI,aAAaT,UAAUA,QAAAA,CAAAA,EAChCU,YAAQC,yBAAIF,aAAajB,SAAS,OAAGmB,yBAAIF,aAAa1B,EAAE,CAAA;AAC3D,UAAM6B,OAAOJ,SAASA,SAASK,SAAS,CAAA;AACxC,WAAO;MACL,GAAG,KAAKf,UAAUhB,QAAQ8B,MAAME,OAAAA;MAChCN,UAAUA,SAASO,IAAI,CAACC,YAAY,KAAKC,gBAAgBD,OAAAA,CAAAA;MACzD,GAAIlC,OAAOS,kBAAkB,OAAO;QAAEA,gBAAgBT,OAAOS;MAAe,IAAI,CAAC;IACnF;EACF;EAEA,MAAM2B,YAAYhC,UAAkBiC,QAAQ,IAA8B;AACxE,UAAMC,UAAU,MAAM,KAAK3C,GACxBwB,OAAM,EACNC,KAAKN,WAAAA,EACLO,UACCC,6BACEC,wBAAGT,YAAYV,UAAUA,QAAAA,OACzBmB,wBAAGT,YAAYN,WAAW,KAAA,OAC1BgB,4BAAOV,YAAYF,SAAS,CAAA,CAAA,EAG/BgB,YAAQW,0BAAKzB,YAAYH,SAAS,CAAA,EAClC0B,MAAMA,KAAAA;AACT,UAAMG,YAA6B,CAAA;AACnC,eAAWxC,UAAUsC,SAAS;AAC5B,YAAM,CAACR,IAAAA,IAAQ,MAAM,KAAKnC,GACvBwB,OAAM,EACNC,KAAKO,YAAAA,EACLN,UAAME,wBAAGI,aAAaT,UAAUlB,OAAOC,EAAE,CAAA,EACzC2B,YAAQW,0BAAKZ,aAAajB,SAAS,OAAG6B,0BAAKZ,aAAa1B,EAAE,CAAA,EAC1DoC,MAAM,CAAA;AACTG,gBAAUC,KAAK,KAAKzB,UAAUhB,QAAQ8B,MAAME,OAAAA,CAAAA;IAC9C;AACA,WAAOQ;EACT;EAEA,MAAME,iBAAiBxB,UAAiC;AACtD,UAAM,KAAKvB,GACRgD,OAAO7B,WAAAA,EACP8B,IAAI;MAAEhC,WAAW,oBAAIb,KAAAA;IAAO,CAAA,EAC5BsB,UAAME,wBAAGT,YAAYb,IAAIiB,QAAAA,CAAAA;EAC9B;EAEA,MAAM2B,WAAW3B,UAAkB4B,eAA+C;AAChF,UAAM,CAACC,MAAAA,IAAU,MAAM,KAAKpD,GAAGwB,OAAM,EAAGC,KAAKN,WAAAA,EAAaO,UAAME,wBAAGT,YAAYb,IAAIiB,QAAAA,CAAAA;AACnF,QAAI6B,WAAWtB,QAAW;AACxB,YAAM,IAAIuB,MAAM,UAAU9B,QAAAA,YAAoB;IAChD;AACA,UAAMQ,WAAW,MAAM,KAAK/B,GACzBwB,OAAM,EACNC,KAAKO,YAAAA,EACLN,UAAME,wBAAGI,aAAaT,UAAUA,QAAAA,CAAAA,EAChCU,YAAQC,yBAAIF,aAAajB,SAAS,OAAGmB,yBAAIF,aAAa1B,EAAE,CAAA;AAC3D,UAAMgD,SAASvB,SAASwB,UAAU,CAAChB,YAAYA,QAAQjC,OAAO6C,aAAAA;AAC9D,UAAMK,OAAOF,UAAU,IAAIvB,SAAS0B,MAAM,GAAGH,SAAS,CAAA,IAAKvB;AAC3D,UAAM5B,MAAM,oBAAIC,KAAAA;AAChB,UAAMsD,OAAuB;MAC3BpD,IAAIC,OAAOC,WAAU;MACrBC,UAAU2C,OAAO3C;MACjBE,WAAWyC,OAAOzC;MAClBC,OAAOwC,OAAOxC;MACdC,WAAW;MACXC,gBAAgB;MAChBC,WAAWZ;MACXa,WAAWb;MACXc,WAAW;IACb;AACA,UAAM,KAAKjB,GAAGkB,OAAOC,WAAAA,EAAaC,OAAOsC,IAAAA;AACzC,QAAIF,KAAKpB,SAAS,GAAG;AACnB,YAAM,KAAKpC,GAAGkB,OAAOc,YAAAA,EAAcZ,OACjCoC,KAAKlB,IAAI,CAACC,aAAa;QACrBjC,IAAIC,OAAOC,WAAU;QACrBe,UAAUmC,KAAKpD;QACfqD,MAAMpB,QAAQoB;QACdtB,SAASE,QAAQF;QACjBuB,WAAWrB,QAAQqB;QACnBC,aAAatB,QAAQsB;QACrBC,WAAWvB,QAAQuB;QACnBC,OAAOxB,QAAQwB;QACfC,WAAWzB,QAAQyB;QACnBjD,WAAWwB,QAAQxB;MACrB,EAAA,CAAA;IAEJ;AACA,WAAO,KAAKM,UAAUqC,IAAAA;EACxB;EAEA,MAAMO,cAAc1C,UAA0C;AAC5D,UAAM,CAAClB,MAAAA,IAAU,MAAM,KAAKL,GACzBwB,OAAO;MAAEf,UAAUU,YAAYV;IAAS,CAAA,EACxCgB,KAAKN,WAAAA,EACLO,UAAMC,6BAAIC,wBAAGT,YAAYb,IAAIiB,QAAAA,OAAWM,4BAAOV,YAAYF,SAAS,CAAA,CAAA;AACvE,WAAOZ,QAAQI,YAAY;EAC7B;EAEA,MAAMyD,gBAAgBC,YAA4C;AAChE,UAAM,CAACC,GAAAA,IAAO,MAAM,KAAKpE,GACtBwB,OAAO;MAAEf,UAAUU,YAAYV;IAAS,CAAA,EACxCgB,KAAK4C,aAAAA,EACLC,UAAUtC,kBAAcJ,wBAAGyC,cAAcE,WAAWvC,aAAa1B,EAAE,CAAA,EACnEgE,UAAUnD,iBAAaS,wBAAGI,aAAaT,UAAUJ,YAAYb,EAAE,CAAA,EAC/DoB,UAAME,wBAAGyC,cAAc/D,IAAI6D,UAAAA,CAAAA;AAC9B,WAAOC,KAAK3D,YAAY;EAC1B;EAEA,MAAM+D,eAAeL,YAA4C;AAC/D,UAAM,CAACC,GAAAA,IAAO,MAAM,KAAKpE,GACtBwB,OAAO;MAAEV,gBAAgBK,YAAYL;IAAe,CAAA,EACpDW,KAAK4C,aAAAA,EACLC,UAAUtC,kBAAcJ,wBAAGyC,cAAcE,WAAWvC,aAAa1B,EAAE,CAAA,EACnEgE,UAAUnD,iBAAaS,wBAAGI,aAAaT,UAAUJ,YAAYb,EAAE,CAAA,EAC/DoB,UAAME,wBAAGyC,cAAc/D,IAAI6D,UAAAA,CAAAA;AAC9B,WAAOC,KAAKtD,kBAAkB;EAChC;EAEA,MAAM2D,oBAAoBC,OAAuC;AAC/D,UAAM,CAACrE,MAAAA,IAAU,MAAM,KAAKL,GACzBwB,OAAO;MAAEf,UAAUU,YAAYV;IAAS,CAAA,EACxCgB,KAAKN,WAAAA,EACLO,UAAMC,6BAAIC,wBAAGT,YAAYL,gBAAgB4D,KAAAA,OAAQ7C,4BAAOV,YAAYF,SAAS,CAAA,CAAA;AAChF,WAAOZ,QAAQI,YAAY;EAC7B;EAEA,MAAMkE,SAASpD,UAAkBX,OAA8B;AAC7D,UAAM,KAAKZ,GACRgD,OAAO7B,WAAAA,EACP8B,IAAI;MAAErC;MAAOI,WAAW,oBAAIZ,KAAAA;IAAO,CAAA,EACnCsB,UAAME,wBAAGT,YAAYb,IAAIiB,QAAAA,CAAAA;EAC9B;EAEA,MAAMqD,cAAcrD,UAAiC;AACnD,UAAM,KAAKvB,GACRgD,OAAO7B,WAAAA,EACP8B,IAAI;MAAEpC,WAAW;MAAOG,WAAW,oBAAIZ,KAAAA;IAAO,CAAA,EAC9CsB,UAAMC,6BAAIC,wBAAGT,YAAYb,IAAIiB,QAAAA,OAAWK,wBAAGT,YAAYN,WAAW,IAAA,CAAA,CAAA;EACvE;EAEA,MAAMgE,gBAAgBtD,UAAkBmD,OAAqC;AAC3E,UAAM,KAAK1E,GACRgD,OAAO7B,WAAAA,EACP8B,IAAI;MAAEnC,gBAAgB4D;IAAM,CAAA,EAC5BhD,UAAME,wBAAGT,YAAYb,IAAIiB,QAAAA,CAAAA;EAC9B;EAEA,MAAMuD,cAAc5E,OAAmD;AACrE,UAAM,CAACG,MAAAA,IAAU,MAAM,KAAKL,GACzBwB,OAAM,EACNC,KAAKN,WAAAA,EACLO,UAAME,wBAAGT,YAAYb,IAAIJ,MAAMqB,QAAQ,CAAA;AAC1C,QAAIlB,WAAWyB,QAAW;AACxB,YAAM,IAAIuB,MAAM,UAAUnD,MAAMqB,QAAQ,YAAY;IACtD;AACA,UAAMpB,MAAM,oBAAIC,KAAAA;AAChB,UAAMmC,UAA2B;MAC/BjC,IAAIC,OAAOC,WAAU;MACrBe,UAAUrB,MAAMqB;MAChBoC,MAAMzD,MAAMyD;MACZtB,SAASnC,MAAMmC;MACfuB,WAAW1D,MAAM0D,aAAa;MAC9BC,aAAa3D,MAAM2D,eAAe;MAClCC,WAAW5D,MAAM4D,aAAa;MAC9BC,OAAO7D,MAAM6D,SAAS;MACtBC,WAAW9D,MAAM8D,aAAa;MAC9BjD,WAAWZ;IACb;AACA,UAAM,KAAKH,GAAGkB,OAAOc,YAAAA,EAAcZ,OAAOmB,OAAAA;AAC1C,UAAM,KAAKvC,GACRgD,OAAO7B,WAAAA,EACP8B,IAAI;MAAEjC,WAAWb;IAAI,CAAA,EACrBuB,UAAME,wBAAGT,YAAYb,IAAIJ,MAAMqB,QAAQ,CAAA;AAC1C,WAAO,KAAKiB,gBAAgBD,OAAAA;EAC9B;EAEA,MAAMwC,aAAaxD,UAAkBgD,WAAkC;AACrE,UAAMxC,WAAW,MAAM,KAAK/B,GACzBwB,OAAM,EACNC,KAAKO,YAAAA,EACLN,UAAME,wBAAGI,aAAaT,UAAUA,QAAAA,CAAAA,EAChCU,YAAQC,yBAAIF,aAAajB,SAAS,OAAGmB,yBAAIF,aAAa1B,EAAE,CAAA;AAC3D,UAAMgD,SAASvB,SAASwB,UAAU,CAAChB,YAAYA,QAAQjC,OAAOiE,SAAAA;AAC9D,QAAIjB,SAAS,GAAG;AACd;IACF;AACA,UAAM0B,YAAYjD,SAAS0B,MAAMH,MAAAA,EAAQhB,IAAI,CAACC,YAAYA,QAAQjC,EAAE;AACpE,UAAM,KAAKN,GAAGiF,OAAOZ,aAAAA,EAAe3C,UAAMwD,6BAAQb,cAAcE,WAAWS,SAAAA,CAAAA;AAC3E,UAAM,KAAKhF,GAAGiF,OAAOjD,YAAAA,EAAcN,UAAMwD,6BAAQlD,aAAa1B,IAAI0E,SAAAA,CAAAA;EACpE;EAEA,MAAMG,eAAejF,OAA2C;AAC9D,UAAM,KAAKF,GAAGkB,OAAOmD,aAAAA,EAAejD,OAAO;MACzCd,IAAIJ,MAAMiE;MACVI,WAAWrE,MAAMqE;MACjBa,UAAUlF,MAAMkF;MAChBC,UAAUnF,MAAMmF;MAChBnF,OAAOA,MAAMA;MACboF,QAAQ;MACRC,QAAQrF,MAAMqF;MACdC,eAAe;MACfC,aAAa;MACbC,OAAO;MACP3E,WAAW,oBAAIX,KAAAA;MACfuF,YAAY;IACd,CAAA;EACF;EAEA,MAAMC,eAAe1F,OAA2C;AAC9D,UAAM2F,UAAsD;MAAEN,QAAQrF,MAAMqF;IAAO;AACnF,QAAIrF,MAAMoF,WAAWxD,QAAW;AAC9B+D,cAAQP,SAASpF,MAAMoF;IACzB;AACA,QAAIpF,MAAMwF,UAAU5D,QAAW;AAC7B+D,cAAQH,QAAQxF,MAAMwF;IACxB;AACA,QAAIxF,MAAMuF,gBAAgB3D,QAAW;AACnC+D,cAAQJ,cAAcvF,MAAMuF;IAC9B;AACA,QAAIvF,MAAMsF,kBAAkB1D,QAAW;AACrC+D,cAAQL,gBAAgBtF,MAAMsF;IAChC;AACA,QAAItF,MAAMqF,WAAW,cAAcrF,MAAMqF,WAAW,iBAAiB;AACnEM,cAAQF,aAAa,oBAAIvF,KAAAA;IAC3B;AACA,UAAM,KAAKJ,GAAGgD,OAAOqB,aAAAA,EAAepB,IAAI4C,OAAAA,EAASnE,UAAME,wBAAGyC,cAAc/D,IAAIJ,MAAMiE,UAAU,CAAA;EAC9F;EAEA,MAAM2B,YAAY5F,OAAwC;AACxD,UAAM,KAAKF,GAAGkB,OAAO6E,eAAAA,EAAiB3E,OAAO;MAC3Cd,IAAIC,OAAOC,WAAU;MACrBe,UAAUrB,MAAMqB;MAChBd,UAAUP,MAAMO;MAChB8D,WAAWrE,MAAMqE,aAAa;MAC9ByB,SAAS9F,MAAM8F;MACfC,SAAS/F,MAAM+F;MACfC,aAAahG,MAAM6D,MAAMmC;MACzBC,cAAcjG,MAAM6D,MAAMoC;MAC1BC,kBAAkBlG,MAAM6D,MAAMqC,oBAAoB;MAClDC,iBAAiBnG,MAAM6D,MAAMsC,mBAAmB;MAChDC,SAASpG,MAAMoG,WAAW;MAC1BvF,WAAW,oBAAIX,KAAAA;IACjB,CAAA;EACF;EAEA,MAAMmG,WACJ9F,UACA+F,KACkD;AAClD,UAAMC,QAAQ,oBAAIrG,KAAK,GAAGoG,GAAAA,gBAAmB;AAC7C,UAAME,MAAM,oBAAItG,KAAK,GAAGoG,GAAAA,gBAAmB;AAC3C,UAAMG,OAAO,MAAM,KAAK3G,GACrBwB,OAAM,EACNC,KAAKsE,eAAAA,EACLrE,UACCC,6BACEC,wBAAGmE,gBAAgBtF,UAAUA,QAAAA,OAC7BmG,yBAAIb,gBAAgBhF,WAAW0F,KAAAA,OAC/BI,yBAAId,gBAAgBhF,WAAW2F,GAAAA,CAAAA,CAAAA;AAGrC,UAAMI,aAAaH,KAAKI,OAAO,CAACC,KAAK5C,QAAQ4C,MAAM5C,IAAI8B,cAAc9B,IAAI+B,cAAc,CAAA;AACvF,UAAMG,UAAUK,KAAKI,OAAO,CAACC,KAAK5C,QAAQ4C,OAAO5C,IAAIkC,WAAW,IAAI,CAAA;AACpE,WAAO;MAAEQ;MAAYR;IAAQ;EAC/B;EAEQjF,UAAUhB,QAAwB4G,aAAqC;AAC7E,WAAO;MACL3G,IAAID,OAAOC;MACXM,OAAOP,OAAOO;MACdC,WAAWR,OAAOQ;MAClBE,WAAWV,OAAOU,UAAUmG,YAAW;MACvClG,WAAWX,OAAOW,UAAUkG,YAAW;MACvC,GAAID,gBAAgBnF,SAAY;QAAEqF,oBAAoBF,YAAYxD,MAAM,GAAG,GAAA;MAAK,IAAI,CAAC;IACvF;EACF;EAEQjB,gBAAgBD,SAAyC;AAC/D,WAAO;MACLjC,IAAIiC,QAAQjC;MACZqD,MAAMpB,QAAQoB;MACdtB,SAASE,QAAQF;MACjBtB,WAAWwB,QAAQxB,UAAUmG,YAAW;MACxC,GAAI3E,QAAQqB,aAAa,OAAO;QAAEA,WAAWrB,QAAQqB;MAAU,IAAI,CAAC;MACpE,GAAIrB,QAAQsB,eAAe,OAAO;QAAEA,aAAatB,QAAQsB;MAAY,IAAI,CAAC;MAC1E,GAAItB,QAAQuB,aAAa,OAAO;QAAEA,WAAWvB,QAAQuB;MAAU,IAAI,CAAC;MACpE,GAAIvB,QAAQwB,SAAS,OAAO;QAAEA,OAAOxB,QAAQwB;MAAM,IAAI,CAAC;MACxD,GAAIxB,QAAQyB,aAAa,OAAO;QAAEA,WAAWzB,QAAQyB;MAAU,IAAI,CAAC;IACtE;EACF;AACF;;;AC/UA,IAAAoD,sBAAgE;AAuBhE,SAASC,mBACPC,SACAC,KAAwC;AAExC,QAAMC,QAAQF,QAAQG,IAAIF,IAAIG,OAAO;AACrC,MAAIF,UAAUG,QAAW;AACvB,WAAO;EACT;AACA,QAAMC,mBAAmBL,IAAIK,oBAAoB;AACjD,QAAMC,kBAAkBN,IAAIM,mBAAmB;AAC/C,QAAMC,sBAAsBP,IAAIQ,cAAcH,mBAAmBC;AACjE,SACGC,sBAAsB,MAAaN,MAAMQ,kBACzCJ,mBAAmB,OAAcJ,MAAMS,wBAAwBT,MAAMQ,mBACrEH,kBAAkB,OAAcL,MAAMU,uBAAuBV,MAAMQ,mBACnET,IAAIY,eAAe,MAAaX,MAAMY;AAE3C;AAjBSf;AAuBT,SAASgB,QACPf,SACAC,KAAwC;AAExC,SAAOA,IAAIe,WAAWjB,mBAAmBC,SAASC,GAAAA;AACpD;AALSc;AAQT,SAASE,UAAUC,OAAsB;AACvC,SAAO;IACLC,OAAO,oBAAIC,KAAK,GAAGF,MAAMG,OAAO,gBAAgB;IAChDC,KAAK,oBAAIF,KAAK,GAAGF,MAAMK,KAAK,gBAAgB;EAC9C;AACF;AALSN;AAeF,IAAMO,2BAAN,MAAMA;EArEb,OAqEaA;;;;;EACX,YACmBC,IACAC,cACjB;SAFiBD,KAAAA;SACAC,eAAAA;EAChB;EAEH,MAAcC,cAAgD;AAC5D,UAAMC,SAAS,MAAM,KAAKF,aAAaG,kBAAiB;AACxD,UAAM7B,UAAU,oBAAI8B,IAAAA;AACpB,eAAW5B,SAAS0B,QAAQ;AAC1B5B,cAAQ+B,IAAI7B,MAAME,SAAS;QACzBM,iBAAiBR,MAAMQ;QACvBI,kBAAkBZ,MAAMY;QACxBH,sBAAsBT,MAAMS,wBAAwB;QACpDC,qBAAqBV,MAAMU,uBAAuB;MACpD,CAAA;IACF;AACA,WAAOZ;EACT;EAEA,MAAcgC,aACZd,OACkD;AAClD,UAAM,EAAEC,OAAOG,IAAG,IAAKL,UAAUC,KAAAA;AACjC,UAAMe,OAAO,MAAM,KAAKR,GACrBS,OAAM,EACNC,KAAKC,eAAAA,EACLC,UAAMC,6BAAIC,yBAAIH,gBAAgBI,WAAWrB,KAAAA,OAAQsB,yBAAIL,gBAAgBI,WAAWlB,GAAAA,CAAAA,CAAAA;AACnF,WAAOW;EACT;EAEA,MAAMS,aAAaxB,OAAkD;AACnE,UAAMlB,UAAU,MAAM,KAAK2B,YAAW;AACtC,UAAMM,OAAO,MAAM,KAAKD,aAAad,KAAAA;AACrC,UAAMyB,UAAU,oBAAIb,IAAAA;AAIpB,eAAW7B,OAAOgC,MAAM;AACtB,YAAMW,SAASD,QAAQxC,IAAIF,IAAIG,OAAO,KAAK;QACzCyC,UAAU;QACVpC,aAAa;QACbI,cAAc;QACdG,SAAS;MACX;AACA4B,aAAOC,YAAY;AACnBD,aAAOnC,eAAeR,IAAIQ;AAC1BmC,aAAO/B,gBAAgBZ,IAAIY;AAC3B+B,aAAO5B,WAAWD,QAAQf,SAASC,GAAAA;AACnC0C,cAAQZ,IAAI9B,IAAIG,SAASwC,MAAAA;IAC3B;AACA,UAAME,SAA0B,CAAA;AAChC,eAAW,CAAC1C,SAASwC,MAAAA,KAAWD,SAAS;AACvCG,aAAOC,KAAK;QACV3C;QACAyC,UAAUD,OAAOC;QACjBpC,aAAamC,OAAOnC;QACpBI,cAAc+B,OAAO/B;QACrBG,SAAS4B,OAAO5B;MAClB,CAAA;IACF;AACA8B,WAAOE,KACL,CAACC,MAAMC,UAAUA,MAAMlC,UAAUiC,KAAKjC,WAAWiC,KAAK7C,QAAQ+C,cAAcD,MAAM9C,OAAO,CAAA;AAE3F,WAAO0C;EACT;EAEA,MAAMM,aAAalC,OAAkD;AACnE,UAAMlB,UAAU,MAAM,KAAK2B,YAAW;AACtC,UAAMM,OAAO,MAAM,KAAKD,aAAad,KAAAA;AACrC,UAAMmC,UAAU,oBAAIvB,IAAAA;AAIpB,eAAW7B,OAAOgC,MAAM;AACtB,YAAMW,SAASS,QAAQlD,IAAIF,IAAIqD,QAAQ,KAAK;QAC1CT,UAAU;QACVU,aAAa;QACbvC,SAAS;QACTwC,WAAW,oBAAIC,IAAAA;MACjB;AACAb,aAAOC,YAAY;AACnBD,aAAOW,eAAetD,IAAIQ,cAAcR,IAAIY;AAC5C+B,aAAO5B,WAAWD,QAAQf,SAASC,GAAAA;AACnC2C,aAAOY,UAAUE,IAAIzD,IAAI0D,QAAQ;AACjCN,cAAQtB,IAAI9B,IAAIqD,UAAUV,MAAAA;IAC5B;AACA,UAAME,SAA0B,CAAA;AAChC,eAAW,CAACQ,UAAUV,MAAAA,KAAWS,SAAS;AACxCP,aAAOC,KAAK;QACVO;QACAT,UAAUD,OAAOC;QACjBU,aAAaX,OAAOW;QACpBvC,SAAS4B,OAAO5B;QAChB4C,aAAahB,OAAOY,UAAUK;MAChC,CAAA;IACF;AACAf,WAAOE,KACL,CAACC,MAAMC,UAAUA,MAAMlC,UAAUiC,KAAKjC,WAAWiC,KAAKK,SAASH,cAAcD,MAAMI,QAAQ,CAAA;AAE7F,WAAOR;EACT;;;;;;EAOA,MAAMgB,cAAc5C,OAAwB6C,OAA0C;AACpF,UAAM/D,UAAU,MAAM,KAAK2B,YAAW;AACtC,UAAMM,OAAO,MAAM,KAAKD,aAAad,KAAAA;AACrC,UAAM8C,WAAW,oBAAIlC,IAAAA;AACrB,eAAW7B,OAAOgC,MAAM;AACtB,YAAMW,SAASoB,SAAS7D,IAAIF,IAAI0D,QAAQ,KAAK;QAAEd,UAAU;QAAGU,aAAa;QAAGvC,SAAS;MAAE;AACvF4B,aAAOC,YAAY;AACnBD,aAAOW,eAAetD,IAAIQ,cAAcR,IAAIY;AAC5C+B,aAAO5B,WAAWD,QAAQf,SAASC,GAAAA;AACnC+D,eAASjC,IAAI9B,IAAI0D,UAAUf,MAAAA;IAC7B;AACA,QAAIoB,SAASH,SAAS,GAAG;AACvB,aAAO,CAAA;IACT;AACA,UAAMI,UAAU,MAAM,KAAKxC,GACxBS,OAAM,EACNC,KAAK+B,WAAAA,EACL7B,UAAMC,6BAAI6B,6BAAQD,YAAYE,IAAI;SAAIJ,SAASK,KAAI;KAAG,OAAGC,4BAAOJ,YAAYK,SAAS,CAAA,CAAA;AACxF,UAAMC,cAAc,IAAI1C,IAAImC,QAAQQ,IAAI,CAACC,WAAW;MAACA,OAAON;MAAIM;KAAO,CAAA;AACvE,UAAM5B,SAA2B,CAAA;AACjC,eAAW,CAACa,UAAUf,MAAAA,KAAWoB,UAAU;AACzC,YAAMU,SAASF,YAAYrE,IAAIwD,QAAAA;AAC/B,UAAIe,WAAWrE,QAAW;AACxB;MACF;AACAyC,aAAOC,KAAK;QACVY;QACAgB,OAAOD,OAAOC;QACdrB,UAAUoB,OAAOpB;QACjBT,UAAUD,OAAOC;QACjBU,aAAaX,OAAOW;QACpBvC,SAAS4B,OAAO5B;MAClB,CAAA;IACF;AACA8B,WAAOE,KACL,CAACC,MAAMC,UAAUA,MAAMlC,UAAUiC,KAAKjC,WAAWiC,KAAKU,SAASR,cAAcD,MAAMS,QAAQ,CAAA;AAE7F,WAAOb,OAAO8B,MAAM,GAAGb,KAAAA;EACzB;EAEA,MAAMc,WAAW3D,OAAoD;AACnE,UAAMlB,UAAU,MAAM,KAAK2B,YAAW;AACtC,UAAMM,OAAO,MAAM,KAAKD,aAAad,KAAAA;AACrC,UAAM4D,QAAQ,oBAAIhD,IAAAA;AAClB,eAAW7B,OAAOgC,MAAM;AACtB,YAAM8C,MAAM9E,IAAIuC,UAAUwC,YAAW,EAAGJ,MAAM,GAAG,EAAA;AACjD,YAAMhC,SAASkC,MAAM3E,IAAI4E,GAAAA,KAAQ;QAAExB,aAAa;QAAGvC,SAAS;MAAE;AAC9D4B,aAAOW,eAAetD,IAAIQ,cAAcR,IAAIY;AAC5C+B,aAAO5B,WAAWD,QAAQf,SAASC,GAAAA;AACnC6E,YAAM/C,IAAIgD,KAAKnC,MAAAA;IACjB;AACA,UAAME,SAA4B,CAAA;AAClC,eAAW,CAACiC,KAAKnC,MAAAA,KAAWkC,OAAO;AACjChC,aAAOC,KAAK;QAAEgC;QAAKxB,aAAaX,OAAOW;QAAavC,SAAS4B,OAAO5B;MAAQ,CAAA;IAC9E;AACA8B,WAAOE,KAAK,CAACC,MAAMC,UAAUD,KAAK8B,IAAI5B,cAAcD,MAAM6B,GAAG,CAAA;AAC7D,WAAOjC;EACT;EAEA,MAAMmC,gBAAgBlB,OAA+C;AACnE,UAAM9B,OAAO,MAAM,KAAKR,GACrBS,OAAO;MACNgD,YAAYC,cAAcf;MAC1BgB,UAAUD,cAAcC;MACxBC,UAAUF,cAAcE;MACxBC,QAAQH,cAAcG;MACtB3B,UAAU4B,aAAa5B;MACvBnB,WAAW2C,cAAc3C;IAC3B,CAAA,EACCL,KAAKgD,aAAAA,EACLK,UAAUD,kBAAcE,wBAAGN,cAAcO,WAAWH,aAAanB,EAAE,CAAA,EACnEuB,YAAQC,0BAAKT,cAAc3C,SAAS,OAAGoD,0BAAKT,cAAcf,EAAE,CAAA,EAC5DL,MAAMA,KAAAA;AACT,WAAO9B,KAAKwC,IAAI,CAACxE,SAAS;MACxBiF,YAAYjF,IAAIiF;MAChBE,UAAUnF,IAAImF;MACdC,UAAUpF,IAAIoF;MACdC,QAAQrF,IAAIqF;MACZ3B,UAAU1D,IAAI0D;MACdnB,WAAWvC,IAAIuC,UAAUwC,YAAW;IACtC,EAAA;EACF;EAEA,MAAMa,cAAc9B,OAA6C;AAC/D,UAAME,UAAU,MAAM,KAAKxC,GACxBS,OAAM,EACNC,KAAK+B,WAAAA,EACL7B,UAAMiC,4BAAOJ,YAAYK,SAAS,CAAA,EAClCoB,YAAQC,0BAAK1B,YAAY4B,SAAS,OAAGF,0BAAK1B,YAAYE,EAAE,CAAA,EACxDL,MAAMA,KAAAA;AACT,UAAMjB,SAA8B,CAAA;AACpC,eAAW4B,UAAUT,SAAS;AAC5B,YAAM,CAAC8B,eAAAA,IAAmB,MAAM,KAAKtE,GAClCS,OAAO;QAAE8D,WAAOC,2BAAAA;MAAQ,CAAA,EACxB9D,KAAKoD,YAAAA,EACLlD,UAAMoD,wBAAGF,aAAa5B,UAAUe,OAAON,EAAE,CAAA;AAC5C,YAAM8B,YAAY,MAAM,KAAKzE,GAC1BS,OAAM,EACNC,KAAKC,eAAAA,EACLC,UAAMoD,wBAAGrD,gBAAgBuB,UAAUe,OAAON,EAAE,CAAA;AAC/C,YAAMb,cAAc2C,UAAUC,OAC5B,CAACC,KAAKnG,QAAQmG,MAAMnG,IAAIQ,cAAcR,IAAIY,cAC1C,CAAA;AAEFiC,aAAOC,KAAK;QACVY,UAAUe,OAAON;QACjBO,OAAOD,OAAOC;QACdrB,UAAUoB,OAAOpB;QACjB+C,cAAcN,iBAAiBC,SAAS;QACxCzC;QACA+C,gBAAgB5B,OAAOoB,UAAUd,YAAW;MAC9C,CAAA;IACF;AACA,WAAOlC;EACT;AACF;;;AC1SA,IAAAyD,sBAAwB;AASjB,IAAMC,sBAAN,MAAMA;EATb,OASaA;;;;EACX,YAA6BC,IAAoB;SAApBA,KAAAA;EAAqB;EAElD,MAAMC,iBAAiBC,OAAuC;AAC5D,UAAM,KAAKF,GACRG,OAAOC,iBAAAA,EACPC,IAAI;MAAEC,WAAW;IAAM,CAAA,EACvBC,UACCC,6BAAIC,wBAAGL,kBAAkBM,SAASR,MAAMQ,OAAO,OAAGD,wBAAGL,kBAAkBE,WAAW,IAAA,CAAA,CAAA;AAEtF,UAAM,KAAKN,GAAGW,OAAOP,iBAAAA,EAAmBQ,OAAO;MAC7CC,IAAIC,OAAOC,WAAU;MACrBL,SAASR,MAAMQ;MACfM,iBAAiBd,MAAMc;MACvBC,kBAAkBf,MAAMe;MACxBC,sBAAsBhB,MAAMgB,wBAAwB;MACpDC,qBAAqBjB,MAAMiB,uBAAuB;MAClDC,eAAe,oBAAIC,KAAAA;MACnBf,WAAW;IACb,CAAA;EACF;EAEA,MAAMgB,oBAAkD;AACtD,UAAMC,OAAO,MAAM,KAAKvB,GACrBwB,OAAM,EACNC,KAAKrB,iBAAAA,EACLG,UAAME,wBAAGL,kBAAkBE,WAAW,IAAA,CAAA;AACzC,WAAOiB,KAAKG,IAAI,CAACC,SAAS;MACxBjB,SAASiB,IAAIjB;MACbM,iBAAiBW,IAAIX;MACrBC,kBAAkBU,IAAIV;MACtBG,eAAeO,IAAIP,cAAcQ,YAAW;MAC5C,GAAID,IAAIT,wBAAwB,OAC5B;QAAEA,sBAAsBS,IAAIT;MAAqB,IACjD,CAAC;MACL,GAAIS,IAAIR,uBAAuB,OAAO;QAAEA,qBAAqBQ,IAAIR;MAAoB,IAAI,CAAC;IAC5F,EAAA;EACF;AACF;;;ACpDA,+BAKO;AACP,oBAAsD;;;;;;;;AAoC/C,IAAMU,0BAAN,MAAMA,yBAAAA;SAAAA;;;EACX,OAAOC,QAAQC,SAAwD;AACrE,WAAO;MACLC,QAAQH;MACRI,QAAQ;MACRC,WAAW;QACT;UAAEC,SAASC;UAAmBC,YAAY,6BAAM,IAAID,kBAAkBL,QAAQO,EAAE,GAAtC;QAAwC;QAClF;UAAEH,SAASI;UAAaC,aAAaJ;QAAkB;QACvD;UACED,SAASM;UACTJ,YAAY,6BAAM,IAAII,oBAAoBV,QAAQO,EAAE,GAAxC;QACd;;;QAGAP,QAAQW,eACJ;UAAEP,SAASQ;UAAqBC,UAAUb,QAAQW;QAAa,IAC/D;UAAEP,SAASQ;UAAqBH,aAAaC;QAAoB;QACrE;UACEN,SAASU;UACTR,YAAY,wBAACK,iBACX,IAAIG,yBAAyBd,QAAQO,IAAII,YAAAA,GAD/B;UAEZI,QAAQ;YAACH;;QACX;QACA;UAAER,SAASY;UAA0BP,aAAaK;QAAyB;;MAE7EG,SAAS;QACPZ;QACAG;QACAM;QACAE;QACAN;QACAE;;IAEJ;EACF;AACF;;;;","names":["agentThread","sqliteTable","id","text","primaryKey","actorRef","notNull","tenantRef","title","transient","integer","mode","default","activeStreamId","createdAt","updatedAt","deletedAt","table","index","on","agentMessage","threadId","references","onDelete","role","$type","content","toolCalls","toolResults","followUps","usage","agentName","agentToolCall","messageId","toolName","toolType","input","output","status","executedByRef","executionMs","error","executedAt","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","real","agentModelPricing","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","isCurrent","agentSchema","statements","ensureAgentSchema","db","statement","run","sql","raw","import_drizzle_orm","DrizzleAgentStore","db","createThread","input","now","Date","thread","id","crypto","randomUUID","actorRef","actor","tenantRef","title","transient","activeStreamId","createdAt","updatedAt","deletedAt","insert","agentThread","values","toSummary","getThread","threadId","select","from","where","and","eq","isNull","undefined","messages","agentMessage","orderBy","asc","last","length","content","map","message","toStoredMessage","listThreads","limit","threads","desc","summaries","push","softDeleteThread","update","set","forkThread","fromMessageId","source","Error","cutoff","findIndex","kept","slice","fork","role","toolCalls","toolResults","followUps","usage","agentName","ownerOfThread","ownerOfToolCall","toolCallId","row","agentToolCall","innerJoin","messageId","runForToolCall","ownerOfActiveStream","runId","setTitle","promoteThread","setActiveStream","appendMessage","truncateFrom","doomedIds","delete","inArray","recordToolCall","toolName","toolType","output","status","executedByRef","executionMs","error","executedAt","updateToolCall","updates","recordUsage","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","quotaToday","day","start","end","rows","gte","lte","usedTokens","reduce","sum","lastContent","toISOString","lastMessagePreview","import_drizzle_orm","estimateFromTokens","pricing","row","price","get","modelId","undefined","cacheWriteTokens","cacheReadTokens","uncachedInputTokens","inputTokens","inputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","outputTokens","outputPricePer1m","rowCost","costUsd","dayBounds","range","start","Date","fromDay","end","toDay","DrizzleGovernanceQueries","db","pricingStore","loadPricing","prices","listCurrentPrices","Map","set","usageInRange","rows","select","from","agentTokenUsage","where","and","gte","createdAt","lte","spendByModel","byModel","bucket","requests","result","push","sort","left","right","localeCompare","spendByActor","byActor","actorRef","totalTokens","threadIds","Set","add","threadId","threadCount","size","spendByThread","limit","byThread","threads","agentThread","inArray","id","keys","isNull","deletedAt","threadsById","map","thread","title","slice","usageTrend","byDay","day","toISOString","recentToolCalls","toolCallId","agentToolCall","toolName","toolType","status","agentMessage","innerJoin","eq","messageId","orderBy","desc","recentThreads","updatedAt","messageCountRow","value","count","usageRows","reduce","sum","messageCount","lastActivityAt","import_drizzle_orm","DrizzlePricingStore","db","upsertModelPrice","input","update","agentModelPricing","set","isCurrent","where","and","eq","modelId","insert","values","id","crypto","randomUUID","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","Date","listCurrentPrices","rows","select","from","map","row","toISOString","DrizzleAgentStoreModule","forRoot","options","module","global","providers","provide","DrizzleAgentStore","useFactory","db","AGENT_STORE","useExisting","DrizzlePricingStore","pricingStore","AGENT_PRICING_STORE","useClass","DrizzleGovernanceQueries","inject","AGENT_GOVERNANCE_QUERIES","exports"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
2
2
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
3
- import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, GovernanceRange, ModelSpendRow, ActorSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, AgentPricingStore, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
- import { DynamicModule } from '@nestjs/common';
3
+ import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
+ import { Type, DynamicModule } from '@nestjs/common';
5
5
 
6
6
  /**
7
7
  * Drizzle schema mirroring the MikroORM agent entities (same logical columns/relations):
@@ -1987,6 +1987,7 @@ declare class DrizzleAgentStore implements AgentStore {
1987
1987
  runForToolCall(toolCallId: string): Promise<string | null>;
1988
1988
  ownerOfActiveStream(runId: string): Promise<string | null>;
1989
1989
  setTitle(threadId: string, title: string): Promise<void>;
1990
+ promoteThread(threadId: string): Promise<void>;
1990
1991
  setActiveStream(threadId: string, runId: string | null): Promise<void>;
1991
1992
  appendMessage(input: AppendMessageInput): Promise<StoredMessage>;
1992
1993
  truncateFrom(threadId: string, messageId: string): Promise<void>;
@@ -1995,6 +1996,7 @@ declare class DrizzleAgentStore implements AgentStore {
1995
1996
  recordUsage(input: RecordUsageInput): Promise<void>;
1996
1997
  quotaToday(actorRef: string, day: string): Promise<{
1997
1998
  usedTokens: number;
1999
+ costUsd: number;
1998
2000
  }>;
1999
2001
  private toSummary;
2000
2002
  private toStoredMessage;
@@ -2003,17 +2005,25 @@ declare class DrizzleAgentStore implements AgentStore {
2003
2005
  /**
2004
2006
  * {@link AgentGovernanceQueries} backed by Drizzle ORM — the read/analytics half of the store SPI,
2005
2007
  * mirroring {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly. Cost is the token
2006
- * ledger joined to the current pricing row per model (`agentModelPricing.isCurrent`); an unpriced
2007
- * model contributes 0 cost. Aggregation is in-process (like `quotaToday`) so day-bucketing stays
2008
- * dialect-portable.
2008
+ * ledger priced against the current prices from the injected {@link AgentPricingStore}
2009
+ * (`AGENT_PRICING_STORE`), so a host that binds its own pricing store controls the cost every
2010
+ * governance surface reports. An unpriced model contributes 0 cost. Aggregation is in-process (like
2011
+ * `quotaToday`) so day-bucketing stays dialect-portable.
2009
2012
  */
2010
2013
  declare class DrizzleGovernanceQueries implements AgentGovernanceQueries {
2011
2014
  private readonly db;
2012
- constructor(db: AgentDrizzleDb);
2015
+ private readonly pricingStore;
2016
+ constructor(db: AgentDrizzleDb, pricingStore: AgentPricingStore);
2013
2017
  private loadPricing;
2014
2018
  private usageInRange;
2015
2019
  spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]>;
2016
2020
  spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]>;
2021
+ /**
2022
+ * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a
2023
+ * soft-deleted thread (`deletedAt` set) are excluded — the thread no longer surfaces as a
2024
+ * governance target even though its ledger rows survive.
2025
+ */
2026
+ spendByThread(range: GovernanceRange, limit: number): Promise<ThreadSpendRow[]>;
2017
2027
  usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]>;
2018
2028
  recentToolCalls(limit: number): Promise<ToolCallActivityRow[]>;
2019
2029
  recentThreads(limit: number): Promise<ThreadActivityRow[]>;
@@ -2036,6 +2046,12 @@ declare class DrizzlePricingStore implements AgentPricingStore {
2036
2046
  interface DrizzleAgentStoreModuleOptions {
2037
2047
  /** A Drizzle SQLite database instance (`drizzle(client, { schema: agentSchema })`). */
2038
2048
  db: AgentDrizzleDb;
2049
+ /**
2050
+ * Bind {@link AGENT_PRICING_STORE} (which {@link DrizzleGovernanceQueries} prices usage against) to
2051
+ * a host-supplied store instead of the default {@link DrizzlePricingStore} — make your OWN pricing
2052
+ * table the single source of cost truth without touching `agent_model_pricing`.
2053
+ */
2054
+ pricingStore?: Type<AgentPricingStore>;
2039
2055
  }
2040
2056
  /**
2041
2057
  * Binds {@link DrizzleAgentStore} to the {@link AGENT_STORE} token consumed by
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
2
2
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
3
- import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, GovernanceRange, ModelSpendRow, ActorSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, AgentPricingStore, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
- import { DynamicModule } from '@nestjs/common';
3
+ import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
+ import { Type, DynamicModule } from '@nestjs/common';
5
5
 
6
6
  /**
7
7
  * Drizzle schema mirroring the MikroORM agent entities (same logical columns/relations):
@@ -1987,6 +1987,7 @@ declare class DrizzleAgentStore implements AgentStore {
1987
1987
  runForToolCall(toolCallId: string): Promise<string | null>;
1988
1988
  ownerOfActiveStream(runId: string): Promise<string | null>;
1989
1989
  setTitle(threadId: string, title: string): Promise<void>;
1990
+ promoteThread(threadId: string): Promise<void>;
1990
1991
  setActiveStream(threadId: string, runId: string | null): Promise<void>;
1991
1992
  appendMessage(input: AppendMessageInput): Promise<StoredMessage>;
1992
1993
  truncateFrom(threadId: string, messageId: string): Promise<void>;
@@ -1995,6 +1996,7 @@ declare class DrizzleAgentStore implements AgentStore {
1995
1996
  recordUsage(input: RecordUsageInput): Promise<void>;
1996
1997
  quotaToday(actorRef: string, day: string): Promise<{
1997
1998
  usedTokens: number;
1999
+ costUsd: number;
1998
2000
  }>;
1999
2001
  private toSummary;
2000
2002
  private toStoredMessage;
@@ -2003,17 +2005,25 @@ declare class DrizzleAgentStore implements AgentStore {
2003
2005
  /**
2004
2006
  * {@link AgentGovernanceQueries} backed by Drizzle ORM — the read/analytics half of the store SPI,
2005
2007
  * mirroring {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly. Cost is the token
2006
- * ledger joined to the current pricing row per model (`agentModelPricing.isCurrent`); an unpriced
2007
- * model contributes 0 cost. Aggregation is in-process (like `quotaToday`) so day-bucketing stays
2008
- * dialect-portable.
2008
+ * ledger priced against the current prices from the injected {@link AgentPricingStore}
2009
+ * (`AGENT_PRICING_STORE`), so a host that binds its own pricing store controls the cost every
2010
+ * governance surface reports. An unpriced model contributes 0 cost. Aggregation is in-process (like
2011
+ * `quotaToday`) so day-bucketing stays dialect-portable.
2009
2012
  */
2010
2013
  declare class DrizzleGovernanceQueries implements AgentGovernanceQueries {
2011
2014
  private readonly db;
2012
- constructor(db: AgentDrizzleDb);
2015
+ private readonly pricingStore;
2016
+ constructor(db: AgentDrizzleDb, pricingStore: AgentPricingStore);
2013
2017
  private loadPricing;
2014
2018
  private usageInRange;
2015
2019
  spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]>;
2016
2020
  spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]>;
2021
+ /**
2022
+ * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a
2023
+ * soft-deleted thread (`deletedAt` set) are excluded — the thread no longer surfaces as a
2024
+ * governance target even though its ledger rows survive.
2025
+ */
2026
+ spendByThread(range: GovernanceRange, limit: number): Promise<ThreadSpendRow[]>;
2017
2027
  usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]>;
2018
2028
  recentToolCalls(limit: number): Promise<ToolCallActivityRow[]>;
2019
2029
  recentThreads(limit: number): Promise<ThreadActivityRow[]>;
@@ -2036,6 +2046,12 @@ declare class DrizzlePricingStore implements AgentPricingStore {
2036
2046
  interface DrizzleAgentStoreModuleOptions {
2037
2047
  /** A Drizzle SQLite database instance (`drizzle(client, { schema: agentSchema })`). */
2038
2048
  db: AgentDrizzleDb;
2049
+ /**
2050
+ * Bind {@link AGENT_PRICING_STORE} (which {@link DrizzleGovernanceQueries} prices usage against) to
2051
+ * a host-supplied store instead of the default {@link DrizzlePricingStore} — make your OWN pricing
2052
+ * table the single source of cost truth without touching `agent_model_pricing`.
2053
+ */
2054
+ pricingStore?: Type<AgentPricingStore>;
2039
2055
  }
2040
2056
  /**
2041
2057
  * Binds {@link DrizzleAgentStore} to the {@link AGENT_STORE} token consumed by
package/dist/index.js CHANGED
@@ -321,6 +321,12 @@ var DrizzleAgentStore = class {
321
321
  updatedAt: /* @__PURE__ */ new Date()
322
322
  }).where(eq(agentThread.id, threadId));
323
323
  }
324
+ async promoteThread(threadId) {
325
+ await this.db.update(agentThread).set({
326
+ transient: false,
327
+ updatedAt: /* @__PURE__ */ new Date()
328
+ }).where(and(eq(agentThread.id, threadId), eq(agentThread.transient, true)));
329
+ }
324
330
  async setActiveStream(threadId, runId) {
325
331
  await this.db.update(agentThread).set({
326
332
  activeStreamId: runId
@@ -418,8 +424,10 @@ var DrizzleAgentStore = class {
418
424
  const end = /* @__PURE__ */ new Date(`${day}T23:59:59.999Z`);
419
425
  const rows = await this.db.select().from(agentTokenUsage).where(and(eq(agentTokenUsage.actorRef, actorRef), gte(agentTokenUsage.createdAt, start), lte(agentTokenUsage.createdAt, end)));
420
426
  const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);
427
+ const costUsd = rows.reduce((sum, row) => sum + (row.costUsd ?? 0), 0);
421
428
  return {
422
- usedTokens
429
+ usedTokens,
430
+ costUsd
423
431
  };
424
432
  }
425
433
  toSummary(thread, lastContent) {
@@ -460,7 +468,7 @@ var DrizzleAgentStore = class {
460
468
  };
461
469
 
462
470
  // src/drizzle-governance-queries.ts
463
- import { and as and2, count, desc as desc2, eq as eq2, gte as gte2, isNull as isNull2, lte as lte2 } from "drizzle-orm";
471
+ import { and as and2, count, desc as desc2, eq as eq2, gte as gte2, inArray as inArray2, isNull as isNull2, lte as lte2 } from "drizzle-orm";
464
472
  function estimateFromTokens(pricing, row) {
465
473
  const price = pricing.get(row.modelId);
466
474
  if (price === void 0) {
@@ -488,18 +496,20 @@ var DrizzleGovernanceQueries = class {
488
496
  __name(this, "DrizzleGovernanceQueries");
489
497
  }
490
498
  db;
491
- constructor(db) {
499
+ pricingStore;
500
+ constructor(db, pricingStore) {
492
501
  this.db = db;
502
+ this.pricingStore = pricingStore;
493
503
  }
494
504
  async loadPricing() {
495
- const rows = await this.db.select().from(agentModelPricing).where(eq2(agentModelPricing.isCurrent, true));
505
+ const prices = await this.pricingStore.listCurrentPrices();
496
506
  const pricing = /* @__PURE__ */ new Map();
497
- for (const row of rows) {
498
- pricing.set(row.modelId, {
499
- inputPricePer1m: row.inputPricePer1m,
500
- outputPricePer1m: row.outputPricePer1m,
501
- cacheWritePricePer1m: row.cacheWritePricePer1m,
502
- cacheReadPricePer1m: row.cacheReadPricePer1m
507
+ for (const price of prices) {
508
+ pricing.set(price.modelId, {
509
+ inputPricePer1m: price.inputPricePer1m,
510
+ outputPricePer1m: price.outputPricePer1m,
511
+ cacheWritePricePer1m: price.cacheWritePricePer1m ?? null,
512
+ cacheReadPricePer1m: price.cacheReadPricePer1m ?? null
503
513
  });
504
514
  }
505
515
  return pricing;
@@ -547,11 +557,13 @@ var DrizzleGovernanceQueries = class {
547
557
  const bucket = byActor.get(row.actorRef) ?? {
548
558
  requests: 0,
549
559
  totalTokens: 0,
550
- costUsd: 0
560
+ costUsd: 0,
561
+ threadIds: /* @__PURE__ */ new Set()
551
562
  };
552
563
  bucket.requests += 1;
553
564
  bucket.totalTokens += row.inputTokens + row.outputTokens;
554
565
  bucket.costUsd += rowCost(pricing, row);
566
+ bucket.threadIds.add(row.threadId);
555
567
  byActor.set(row.actorRef, bucket);
556
568
  }
557
569
  const result = [];
@@ -560,12 +572,61 @@ var DrizzleGovernanceQueries = class {
560
572
  actorRef,
561
573
  requests: bucket.requests,
562
574
  totalTokens: bucket.totalTokens,
563
- costUsd: bucket.costUsd
575
+ costUsd: bucket.costUsd,
576
+ threadCount: bucket.threadIds.size
564
577
  });
565
578
  }
566
579
  result.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
567
580
  return result;
568
581
  }
582
+ /**
583
+ * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a
584
+ * soft-deleted thread (`deletedAt` set) are excluded — the thread no longer surfaces as a
585
+ * governance target even though its ledger rows survive.
586
+ */
587
+ async spendByThread(range, limit) {
588
+ const pricing = await this.loadPricing();
589
+ const rows = await this.usageInRange(range);
590
+ const byThread = /* @__PURE__ */ new Map();
591
+ for (const row of rows) {
592
+ const bucket = byThread.get(row.threadId) ?? {
593
+ requests: 0,
594
+ totalTokens: 0,
595
+ costUsd: 0
596
+ };
597
+ bucket.requests += 1;
598
+ bucket.totalTokens += row.inputTokens + row.outputTokens;
599
+ bucket.costUsd += rowCost(pricing, row);
600
+ byThread.set(row.threadId, bucket);
601
+ }
602
+ if (byThread.size === 0) {
603
+ return [];
604
+ }
605
+ const threads = await this.db.select().from(agentThread).where(and2(inArray2(agentThread.id, [
606
+ ...byThread.keys()
607
+ ]), isNull2(agentThread.deletedAt)));
608
+ const threadsById = new Map(threads.map((thread) => [
609
+ thread.id,
610
+ thread
611
+ ]));
612
+ const result = [];
613
+ for (const [threadId, bucket] of byThread) {
614
+ const thread = threadsById.get(threadId);
615
+ if (thread === void 0) {
616
+ continue;
617
+ }
618
+ result.push({
619
+ threadId,
620
+ title: thread.title,
621
+ actorRef: thread.actorRef,
622
+ requests: bucket.requests,
623
+ totalTokens: bucket.totalTokens,
624
+ costUsd: bucket.costUsd
625
+ });
626
+ }
627
+ result.sort((left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId));
628
+ return result.slice(0, limit);
629
+ }
569
630
  async usageTrend(range) {
570
631
  const pricing = await this.loadPricing();
571
632
  const rows = await this.usageInRange(range);
@@ -700,21 +761,29 @@ var DrizzleAgentStoreModule = class _DrizzleAgentStoreModule {
700
761
  provide: AGENT_STORE,
701
762
  useExisting: DrizzleAgentStore
702
763
  },
703
- {
704
- provide: DrizzleGovernanceQueries,
705
- useFactory: /* @__PURE__ */ __name(() => new DrizzleGovernanceQueries(options.db), "useFactory")
706
- },
707
- {
708
- provide: AGENT_GOVERNANCE_QUERIES,
709
- useExisting: DrizzleGovernanceQueries
710
- },
711
764
  {
712
765
  provide: DrizzlePricingStore,
713
766
  useFactory: /* @__PURE__ */ __name(() => new DrizzlePricingStore(options.db), "useFactory")
714
767
  },
715
- {
768
+ // AGENT_PRICING_STORE: the host's own store when supplied, else the default Drizzle one.
769
+ // DrizzleGovernanceQueries prices usage against whatever is bound here.
770
+ options.pricingStore ? {
771
+ provide: AGENT_PRICING_STORE,
772
+ useClass: options.pricingStore
773
+ } : {
716
774
  provide: AGENT_PRICING_STORE,
717
775
  useExisting: DrizzlePricingStore
776
+ },
777
+ {
778
+ provide: DrizzleGovernanceQueries,
779
+ useFactory: /* @__PURE__ */ __name((pricingStore) => new DrizzleGovernanceQueries(options.db, pricingStore), "useFactory"),
780
+ inject: [
781
+ AGENT_PRICING_STORE
782
+ ]
783
+ },
784
+ {
785
+ provide: AGENT_GOVERNANCE_QUERIES,
786
+ useExisting: DrizzleGovernanceQueries
718
787
  }
719
788
  ],
720
789
  exports: [
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/schema.ts","../src/ensure-schema.ts","../src/drizzle-agent-store.ts","../src/drizzle-governance-queries.ts","../src/drizzle-pricing-store.ts","../src/drizzle-agent-store.module.ts"],"sourcesContent":["import type {\n MessageRole,\n MessageUsage,\n ToolCallRequest,\n ToolCallStatus,\n ToolKind,\n ToolResult,\n UsagePurpose,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n type BaseSQLiteDatabase,\n index,\n integer,\n real,\n sqliteTable,\n text,\n} from 'drizzle-orm/sqlite-core';\n\n/**\n * Drizzle schema mirroring the MikroORM agent entities (same logical columns/relations):\n * threads, messages, tool calls, token usage and model pricing. Targets the SQLite core so the\n * db-test runs on an in-memory better-sqlite3; timestamps are stored as integer epoch-ms columns\n * (`{ mode: 'timestamp_ms' }`) which Drizzle round-trips to/from JS `Date`, and the model-facing\n * message extras (tool calls/results, follow-ups, usage) live in JSON `text` columns.\n */\n\n/**\n * A conversation thread. `deletedAt` drives soft delete: a deleted thread is hidden from\n * {@link import('./drizzle-agent-store.js').DrizzleAgentStore.getThread}/`listThreads` but its\n * row survives.\n */\nexport const agentThread = sqliteTable(\n 'agent_thread',\n {\n id: text('id').primaryKey(),\n actorRef: text('actor_ref').notNull(),\n tenantRef: text('tenant_ref'),\n title: text('title').notNull(),\n transient: integer('transient', { mode: 'boolean' }).notNull().default(false),\n activeStreamId: text('active_stream_id'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n deletedAt: integer('deleted_at', { mode: 'timestamp_ms' }),\n },\n (table) => [index('agent_thread_actor_updated_idx').on(table.actorRef, table.updatedAt)],\n);\n\n/**\n * One stored message in a thread. The model-facing extras (`toolCalls`/`toolResults`/\n * `followUps`/`usage`) are folded into nullable JSON columns so a single row round-trips to a\n * {@link import('@dudousxd/nestjs-agent-core').StoredMessage}. `threadId` cascades on delete.\n */\nexport const agentMessage = sqliteTable(\n 'agent_message',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n role: text('role').$type<MessageRole>().notNull(),\n content: text('content').notNull(),\n toolCalls: text('tool_calls', { mode: 'json' }).$type<ToolCallRequest[]>(),\n toolResults: text('tool_results', { mode: 'json' }).$type<ToolResult[]>(),\n followUps: text('follow_ups', { mode: 'json' }).$type<string[]>(),\n usage: text('usage', { mode: 'json' }).$type<MessageUsage>(),\n agentName: text('agent_name'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_message_thread_created_idx').on(table.threadId, table.createdAt)],\n);\n\n/** A tool call requested during an assistant turn. The pk is the model-supplied `toolCallId`. */\nexport const agentToolCall = sqliteTable('agent_tool_call', {\n id: text('id').primaryKey(),\n messageId: text('message_id')\n .notNull()\n .references(() => agentMessage.id, { onDelete: 'cascade' }),\n toolName: text('tool_name').notNull(),\n toolType: text('tool_type').$type<ToolKind>().notNull(),\n input: text('input', { mode: 'json' }),\n output: text('output', { mode: 'json' }),\n status: text('status').$type<ToolCallStatus>().notNull(),\n executedByRef: text('executed_by_ref'),\n executionMs: integer('execution_ms'),\n error: text('error'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n executedAt: integer('executed_at', { mode: 'timestamp_ms' }),\n});\n\n/** A token-usage ledger row, summed per actor per day by `quotaToday`. */\nexport const agentTokenUsage = sqliteTable(\n 'agent_token_usage',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n actorRef: text('actor_ref').notNull(),\n messageId: text('message_id'),\n modelId: text('model_id').notNull(),\n purpose: text('purpose').$type<UsagePurpose>().notNull(),\n inputTokens: integer('input_tokens').notNull(),\n outputTokens: integer('output_tokens').notNull(),\n /** Subset of `inputTokens` written to the prompt cache this turn; null when not reported. */\n cacheWriteTokens: integer('cache_write_tokens'),\n /** Subset of `inputTokens` served from the prompt cache this turn; null when not reported. */\n cacheReadTokens: integer('cache_read_tokens'),\n /** Provider-reported actual USD cost for the turn; null when only tokens were reported. */\n costUsd: real('cost_usd'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_token_usage_actor_created_idx').on(table.actorRef, table.createdAt)],\n);\n\n/** Per-model token pricing, versioned by `effectiveFrom`; `isCurrent` flags the live row. */\nexport const agentModelPricing = sqliteTable('agent_model_pricing', {\n id: text('id').primaryKey(),\n modelId: text('model_id').notNull(),\n inputPricePer1m: real('input_price_per_1m').notNull(),\n outputPricePer1m: real('output_price_per_1m').notNull(),\n /** Per-1M price for cache-write input tokens; null → price them at the input rate. */\n cacheWritePricePer1m: real('cache_write_price_per_1m'),\n /** Per-1M price for cache-read input tokens; null → price them at the input rate. */\n cacheReadPricePer1m: real('cache_read_price_per_1m'),\n effectiveFrom: integer('effective_from', { mode: 'timestamp_ms' }).notNull(),\n isCurrent: integer('is_current', { mode: 'boolean' }).notNull(),\n});\n\n/** The five agent tables as one schema object, ready for `drizzle(client, { schema })`. */\nexport const agentSchema = {\n agentThread,\n agentMessage,\n agentToolCall,\n agentTokenUsage,\n agentModelPricing,\n};\n\n/**\n * The dialect-portable Drizzle SQLite database handle the store operates on. Accepts any SQLite\n * driver (better-sqlite3, libsql, D1, …) in either sync or async result mode; the host app owns\n * the connection and passes the `drizzle(...)` instance in.\n */\nexport type AgentDrizzleDb = BaseSQLiteDatabase<'sync' | 'async', unknown>;\n\n/** A persisted thread row as Drizzle selects it. */\nexport type AgentThreadRow = typeof agentThread.$inferSelect;\n/** A persisted message row as Drizzle selects it. */\nexport type AgentMessageRow = typeof agentMessage.$inferSelect;\n","import { sql } from 'drizzle-orm';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/**\n * Idempotent `CREATE TABLE IF NOT EXISTS` DDL for the five agent tables, mirroring\n * {@link import('./schema.js').agentSchema}. SQLite dialect (the db-test driver); kept here rather\n * than relying on drizzle-kit so the package can stand up its schema with no migration files. Safe\n * to run on boot against a shared database — it never drops or alters existing columns.\n */\nconst statements: string[] = [\n `CREATE TABLE IF NOT EXISTS agent_thread (\n id TEXT PRIMARY KEY NOT NULL,\n actor_ref TEXT NOT NULL,\n tenant_ref TEXT,\n title TEXT NOT NULL,\n transient INTEGER NOT NULL DEFAULT 0,\n active_stream_id TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n deleted_at INTEGER\n )`,\n `CREATE INDEX IF NOT EXISTS agent_thread_actor_updated_idx\n ON agent_thread (actor_ref, updated_at)`,\n `CREATE TABLE IF NOT EXISTS agent_message (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n tool_calls TEXT,\n tool_results TEXT,\n follow_ups TEXT,\n usage TEXT,\n agent_name TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx\n ON agent_message (thread_id, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_tool_call (\n id TEXT PRIMARY KEY NOT NULL,\n message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n tool_type TEXT NOT NULL,\n input TEXT,\n output TEXT,\n status TEXT NOT NULL,\n executed_by_ref TEXT,\n execution_ms INTEGER,\n error TEXT,\n created_at INTEGER NOT NULL,\n executed_at INTEGER\n )`,\n `CREATE TABLE IF NOT EXISTS agent_token_usage (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n actor_ref TEXT NOT NULL,\n message_id TEXT,\n model_id TEXT NOT NULL,\n purpose TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n cache_write_tokens INTEGER,\n cache_read_tokens INTEGER,\n cost_usd REAL,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_token_usage_actor_created_idx\n ON agent_token_usage (actor_ref, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_model_pricing (\n id TEXT PRIMARY KEY NOT NULL,\n model_id TEXT NOT NULL,\n input_price_per_1m REAL NOT NULL,\n output_price_per_1m REAL NOT NULL,\n cache_write_price_per_1m REAL,\n cache_read_price_per_1m REAL,\n effective_from INTEGER NOT NULL,\n is_current INTEGER NOT NULL\n )`,\n];\n\n/** Runs the `CREATE TABLE IF NOT EXISTS` DDL above against the supplied Drizzle SQLite db. */\nexport async function ensureAgentSchema(db: AgentDrizzleDb): Promise<void> {\n for (const statement of statements) {\n await db.run(sql.raw(statement));\n }\n}\n","import type {\n AgentStore,\n AppendMessageInput,\n CreateThreadInput,\n RecordToolCallInput,\n RecordUsageInput,\n StoredMessage,\n ThreadDetail,\n ThreadSummary,\n UpdateToolCallInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, asc, desc, eq, gte, inArray, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n type AgentMessageRow,\n type AgentThreadRow,\n agentMessage,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/**\n * {@link AgentStore} backed by Drizzle ORM — a second adapter alongside the MikroORM one, proving\n * the store SPI is ORM-portable. A POJO receiving a Drizzle SQLite database handle (the host app\n * owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}\n * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.\n */\nexport class DrizzleAgentStore implements AgentStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async createThread(input: CreateThreadInput): Promise<ThreadSummary> {\n const now = new Date();\n const thread: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: input.actor.id,\n tenantRef: input.actor.tenantRef ?? null,\n title: input.title ?? 'New chat',\n transient: input.transient ?? false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(thread);\n return this.toSummary(thread);\n }\n\n async getThread(threadId: string): Promise<ThreadDetail | null> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n if (thread === undefined) {\n return null;\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const last = messages[messages.length - 1];\n return {\n ...this.toSummary(thread, last?.content),\n messages: messages.map((message) => this.toStoredMessage(message)),\n ...(thread.activeStreamId != null ? { activeStreamId: thread.activeStreamId } : {}),\n };\n }\n\n async listThreads(actorRef: string, limit = 50): Promise<ThreadSummary[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(\n and(\n eq(agentThread.actorRef, actorRef),\n eq(agentThread.transient, false),\n isNull(agentThread.deletedAt),\n ),\n )\n .orderBy(desc(agentThread.updatedAt))\n .limit(limit);\n const summaries: ThreadSummary[] = [];\n for (const thread of threads) {\n const [last] = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id))\n .orderBy(desc(agentMessage.createdAt), desc(agentMessage.id))\n .limit(1);\n summaries.push(this.toSummary(thread, last?.content));\n }\n return summaries;\n }\n\n async softDeleteThread(threadId: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ deletedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary> {\n const [source] = await this.db.select().from(agentThread).where(eq(agentThread.id, threadId));\n if (source === undefined) {\n throw new Error(`thread ${threadId} not found`);\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === fromMessageId);\n const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;\n const now = new Date();\n const fork: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: source.actorRef,\n tenantRef: source.tenantRef,\n title: source.title,\n transient: false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(fork);\n if (kept.length > 0) {\n await this.db.insert(agentMessage).values(\n kept.map((message) => ({\n id: crypto.randomUUID(),\n threadId: fork.id,\n role: message.role,\n content: message.content,\n toolCalls: message.toolCalls,\n toolResults: message.toolResults,\n followUps: message.followUps,\n usage: message.usage,\n agentName: message.agentName,\n createdAt: message.createdAt,\n })),\n );\n }\n return this.toSummary(fork);\n }\n\n async ownerOfThread(threadId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async ownerOfToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.actorRef ?? null;\n }\n\n async runForToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ activeStreamId: agentThread.activeStreamId })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.activeStreamId ?? null;\n }\n\n async ownerOfActiveStream(runId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.activeStreamId, runId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async setTitle(threadId: string, title: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ title, updatedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async setActiveStream(threadId: string, runId: string | null): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ activeStreamId: runId })\n .where(eq(agentThread.id, threadId));\n }\n\n async appendMessage(input: AppendMessageInput): Promise<StoredMessage> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(eq(agentThread.id, input.threadId));\n if (thread === undefined) {\n throw new Error(`thread ${input.threadId} not found`);\n }\n const now = new Date();\n const message: AgentMessageRow = {\n id: crypto.randomUUID(),\n threadId: input.threadId,\n role: input.role,\n content: input.content,\n toolCalls: input.toolCalls ?? null,\n toolResults: input.toolResults ?? null,\n followUps: input.followUps ?? null,\n usage: input.usage ?? null,\n agentName: input.agentName ?? null,\n createdAt: now,\n };\n await this.db.insert(agentMessage).values(message);\n await this.db\n .update(agentThread)\n .set({ updatedAt: now })\n .where(eq(agentThread.id, input.threadId));\n return this.toStoredMessage(message);\n }\n\n async truncateFrom(threadId: string, messageId: string): Promise<void> {\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === messageId);\n if (cutoff < 0) {\n return;\n }\n const doomedIds = messages.slice(cutoff).map((message) => message.id);\n await this.db.delete(agentToolCall).where(inArray(agentToolCall.messageId, doomedIds));\n await this.db.delete(agentMessage).where(inArray(agentMessage.id, doomedIds));\n }\n\n async recordToolCall(input: RecordToolCallInput): Promise<void> {\n await this.db.insert(agentToolCall).values({\n id: input.toolCallId,\n messageId: input.messageId,\n toolName: input.toolName,\n toolType: input.toolType,\n input: input.input,\n output: null,\n status: input.status,\n executedByRef: null,\n executionMs: null,\n error: null,\n createdAt: new Date(),\n executedAt: null,\n });\n }\n\n async updateToolCall(input: UpdateToolCallInput): Promise<void> {\n const updates: Partial<typeof agentToolCall.$inferInsert> = { status: input.status };\n if (input.output !== undefined) {\n updates.output = input.output;\n }\n if (input.error !== undefined) {\n updates.error = input.error;\n }\n if (input.executionMs !== undefined) {\n updates.executionMs = input.executionMs;\n }\n if (input.executedByRef !== undefined) {\n updates.executedByRef = input.executedByRef;\n }\n if (input.status === 'executed' || input.status === 'auto_executed') {\n updates.executedAt = new Date();\n }\n await this.db.update(agentToolCall).set(updates).where(eq(agentToolCall.id, input.toolCallId));\n }\n\n async recordUsage(input: RecordUsageInput): Promise<void> {\n await this.db.insert(agentTokenUsage).values({\n id: crypto.randomUUID(),\n threadId: input.threadId,\n actorRef: input.actorRef,\n messageId: input.messageId ?? null,\n modelId: input.modelId,\n purpose: input.purpose,\n inputTokens: input.usage.inputTokens,\n outputTokens: input.usage.outputTokens,\n cacheWriteTokens: input.usage.cacheWriteTokens ?? null,\n cacheReadTokens: input.usage.cacheReadTokens ?? null,\n costUsd: input.costUsd ?? null,\n createdAt: new Date(),\n });\n }\n\n async quotaToday(actorRef: string, day: string): Promise<{ usedTokens: number }> {\n const start = new Date(`${day}T00:00:00.000Z`);\n const end = new Date(`${day}T23:59:59.999Z`);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(\n and(\n eq(agentTokenUsage.actorRef, actorRef),\n gte(agentTokenUsage.createdAt, start),\n lte(agentTokenUsage.createdAt, end),\n ),\n );\n const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);\n return { usedTokens };\n }\n\n private toSummary(thread: AgentThreadRow, lastContent?: string): ThreadSummary {\n return {\n id: thread.id,\n title: thread.title,\n transient: thread.transient,\n createdAt: thread.createdAt.toISOString(),\n updatedAt: thread.updatedAt.toISOString(),\n ...(lastContent !== undefined ? { lastMessagePreview: lastContent.slice(0, 120) } : {}),\n };\n }\n\n private toStoredMessage(message: AgentMessageRow): StoredMessage {\n return {\n id: message.id,\n role: message.role,\n content: message.content,\n createdAt: message.createdAt.toISOString(),\n ...(message.toolCalls != null ? { toolCalls: message.toolCalls } : {}),\n ...(message.toolResults != null ? { toolResults: message.toolResults } : {}),\n ...(message.followUps != null ? { followUps: message.followUps } : {}),\n ...(message.usage != null ? { usage: message.usage } : {}),\n ...(message.agentName != null ? { agentName: message.agentName } : {}),\n };\n }\n}\n","import type {\n ActorSpendRow,\n AgentGovernanceQueries,\n GovernanceRange,\n ModelSpendRow,\n ThreadActivityRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, count, desc, eq, gte, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n agentMessage,\n agentModelPricing,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/** The current per-1M token prices for one model; cache rates fall back to the input rate. */\ninterface ModelPrice {\n inputPricePer1m: number;\n outputPricePer1m: number;\n cacheWritePricePer1m?: number | null;\n cacheReadPricePer1m?: number | null;\n}\n\n/**\n * Token-ledger estimate for one usage row against the current pricing row: the uncached input at the\n * input rate, cache-write/cache-read tokens at their own rates (falling back to the input rate when\n * unpriced), plus output at the output rate. An unpriced model contributes 0 (tokens still count).\n * Cache token counts are subsets of `inputTokens`, so the uncached remainder is the difference.\n */\nfunction estimateFromTokens(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n const price = pricing.get(row.modelId);\n if (price === undefined) {\n return 0;\n }\n const cacheWriteTokens = row.cacheWriteTokens ?? 0;\n const cacheReadTokens = row.cacheReadTokens ?? 0;\n const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;\n return (\n (uncachedInputTokens / 1_000_000) * price.inputPricePer1m +\n (cacheWriteTokens / 1_000_000) * (price.cacheWritePricePer1m ?? price.inputPricePer1m) +\n (cacheReadTokens / 1_000_000) * (price.cacheReadPricePer1m ?? price.inputPricePer1m) +\n (row.outputTokens / 1_000_000) * price.outputPricePer1m\n );\n}\n\n/**\n * The cost of one usage row: the provider-reported `costUsd` when present (gateways report real\n * spend), otherwise the cache-aware token estimate against the current pricing row.\n */\nfunction rowCost(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n return row.costUsd ?? estimateFromTokens(pricing, row);\n}\n\n/** Turns an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used by `quotaToday`. */\nfunction dayBounds(range: GovernanceRange): { start: Date; end: Date } {\n return {\n start: new Date(`${range.fromDay}T00:00:00.000Z`),\n end: new Date(`${range.toDay}T23:59:59.999Z`),\n };\n}\n\n/**\n * {@link AgentGovernanceQueries} backed by Drizzle ORM — the read/analytics half of the store SPI,\n * mirroring {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly. Cost is the token\n * ledger joined to the current pricing row per model (`agentModelPricing.isCurrent`); an unpriced\n * model contributes 0 cost. Aggregation is in-process (like `quotaToday`) so day-bucketing stays\n * dialect-portable.\n */\nexport class DrizzleGovernanceQueries implements AgentGovernanceQueries {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n private async loadPricing(): Promise<Map<string, ModelPrice>> {\n const rows = await this.db\n .select()\n .from(agentModelPricing)\n .where(eq(agentModelPricing.isCurrent, true));\n const pricing = new Map<string, ModelPrice>();\n for (const row of rows) {\n pricing.set(row.modelId, {\n inputPricePer1m: row.inputPricePer1m,\n outputPricePer1m: row.outputPricePer1m,\n cacheWritePricePer1m: row.cacheWritePricePer1m,\n cacheReadPricePer1m: row.cacheReadPricePer1m,\n });\n }\n return pricing;\n }\n\n private async usageInRange(\n range: GovernanceRange,\n ): Promise<(typeof agentTokenUsage.$inferSelect)[]> {\n const { start, end } = dayBounds(range);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(and(gte(agentTokenUsage.createdAt, start), lte(agentTokenUsage.createdAt, end)));\n return rows;\n }\n\n async spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byModel = new Map<\n string,\n { requests: number; inputTokens: number; outputTokens: number; costUsd: number }\n >();\n for (const row of rows) {\n const bucket = byModel.get(row.modelId) ?? {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n costUsd: 0,\n };\n bucket.requests += 1;\n bucket.inputTokens += row.inputTokens;\n bucket.outputTokens += row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byModel.set(row.modelId, bucket);\n }\n const result: ModelSpendRow[] = [];\n for (const [modelId, bucket] of byModel) {\n result.push({\n modelId,\n requests: bucket.requests,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId),\n );\n return result;\n }\n\n async spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byActor = new Map<string, { requests: number; totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byActor.get(row.actorRef) ?? { requests: 0, totalTokens: 0, costUsd: 0 };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byActor.set(row.actorRef, bucket);\n }\n const result: ActorSpendRow[] = [];\n for (const [actorRef, bucket] of byActor) {\n result.push({\n actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef),\n );\n return result;\n }\n\n async usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byDay = new Map<string, { totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const day = row.createdAt.toISOString().slice(0, 10);\n const bucket = byDay.get(day) ?? { totalTokens: 0, costUsd: 0 };\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byDay.set(day, bucket);\n }\n const result: UsageTrendPoint[] = [];\n for (const [day, bucket] of byDay) {\n result.push({ day, totalTokens: bucket.totalTokens, costUsd: bucket.costUsd });\n }\n result.sort((left, right) => left.day.localeCompare(right.day));\n return result;\n }\n\n async recentToolCalls(limit: number): Promise<ToolCallActivityRow[]> {\n const rows = await this.db\n .select({\n toolCallId: agentToolCall.id,\n toolName: agentToolCall.toolName,\n toolType: agentToolCall.toolType,\n status: agentToolCall.status,\n threadId: agentMessage.threadId,\n createdAt: agentToolCall.createdAt,\n })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .orderBy(desc(agentToolCall.createdAt), desc(agentToolCall.id))\n .limit(limit);\n return rows.map((row) => ({\n toolCallId: row.toolCallId,\n toolName: row.toolName,\n toolType: row.toolType,\n status: row.status,\n threadId: row.threadId,\n createdAt: row.createdAt.toISOString(),\n }));\n }\n\n async recentThreads(limit: number): Promise<ThreadActivityRow[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(isNull(agentThread.deletedAt))\n .orderBy(desc(agentThread.updatedAt), desc(agentThread.id))\n .limit(limit);\n const result: ThreadActivityRow[] = [];\n for (const thread of threads) {\n const [messageCountRow] = await this.db\n .select({ value: count() })\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id));\n const usageRows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(eq(agentTokenUsage.threadId, thread.id));\n const totalTokens = usageRows.reduce(\n (sum, row) => sum + row.inputTokens + row.outputTokens,\n 0,\n );\n result.push({\n threadId: thread.id,\n title: thread.title,\n actorRef: thread.actorRef,\n messageCount: messageCountRow?.value ?? 0,\n totalTokens,\n lastActivityAt: thread.updatedAt.toISOString(),\n });\n }\n return result;\n }\n}\n","import type {\n AgentPricingStore,\n CurrentModelPrice,\n ModelPriceInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, eq } from 'drizzle-orm';\nimport { type AgentDrizzleDb, agentModelPricing } from './schema.js';\n\n/**\n * {@link AgentPricingStore} backed by Drizzle ORM — the write side of the pricing table\n * {@link import('./drizzle-governance-queries.js').DrizzleGovernanceQueries} joins against. A POJO\n * receiving a Drizzle SQLite database handle (the host app owns the connection), mirroring\n * {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly (atomic supersede semantics).\n */\nexport class DrizzlePricingStore implements AgentPricingStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async upsertModelPrice(input: ModelPriceInput): Promise<void> {\n await this.db\n .update(agentModelPricing)\n .set({ isCurrent: false })\n .where(\n and(eq(agentModelPricing.modelId, input.modelId), eq(agentModelPricing.isCurrent, true)),\n );\n await this.db.insert(agentModelPricing).values({\n id: crypto.randomUUID(),\n modelId: input.modelId,\n inputPricePer1m: input.inputPricePer1m,\n outputPricePer1m: input.outputPricePer1m,\n cacheWritePricePer1m: input.cacheWritePricePer1m ?? null,\n cacheReadPricePer1m: input.cacheReadPricePer1m ?? null,\n effectiveFrom: new Date(),\n isCurrent: true,\n });\n }\n\n async listCurrentPrices(): Promise<CurrentModelPrice[]> {\n const rows = await this.db\n .select()\n .from(agentModelPricing)\n .where(eq(agentModelPricing.isCurrent, true));\n return rows.map((row) => ({\n modelId: row.modelId,\n inputPricePer1m: row.inputPricePer1m,\n outputPricePer1m: row.outputPricePer1m,\n effectiveFrom: row.effectiveFrom.toISOString(),\n ...(row.cacheWritePricePer1m != null\n ? { cacheWritePricePer1m: row.cacheWritePricePer1m }\n : {}),\n ...(row.cacheReadPricePer1m != null ? { cacheReadPricePer1m: row.cacheReadPricePer1m } : {}),\n }));\n }\n}\n","import {\n AGENT_GOVERNANCE_QUERIES,\n AGENT_PRICING_STORE,\n AGENT_STORE,\n} from '@dudousxd/nestjs-agent-core';\nimport { type DynamicModule, Module } from '@nestjs/common';\nimport { DrizzleAgentStore } from './drizzle-agent-store.js';\nimport { DrizzleGovernanceQueries } from './drizzle-governance-queries.js';\nimport { DrizzlePricingStore } from './drizzle-pricing-store.js';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/** Options for {@link DrizzleAgentStoreModule.forRoot}. The app owns and supplies the db handle. */\nexport interface DrizzleAgentStoreModuleOptions {\n /** A Drizzle SQLite database instance (`drizzle(client, { schema: agentSchema })`). */\n db: AgentDrizzleDb;\n}\n\n/**\n * Binds {@link DrizzleAgentStore} to the {@link AGENT_STORE} token consumed by\n * `@dudousxd/nestjs-agent`, plus {@link DrizzleGovernanceQueries} to\n * {@link AGENT_GOVERNANCE_QUERIES} (the read-model the dashboard/telescope surfaces consume) and\n * {@link DrizzlePricingStore} to {@link AGENT_PRICING_STORE} (the write side of that pricing table).\n * The host app supplies an already-opened Drizzle db — this module never opens a connection itself.\n *\n * The returned module is global, so {@link AGENT_STORE}, {@link AGENT_GOVERNANCE_QUERIES} and\n * {@link AGENT_PRICING_STORE} are visible app-wide — `AgentModule` resolves the store without an\n * explicit `store` option, and the dashboard/telescope resolve {@link AGENT_GOVERNANCE_QUERIES}\n * without the host re-binding it.\n *\n * ```ts\n * @Module({ imports: [DrizzleAgentStoreModule.forRoot({ db })] })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class DrizzleAgentStoreModule {\n static forRoot(options: DrizzleAgentStoreModuleOptions): DynamicModule {\n return {\n module: DrizzleAgentStoreModule,\n global: true,\n providers: [\n { provide: DrizzleAgentStore, useFactory: () => new DrizzleAgentStore(options.db) },\n { provide: AGENT_STORE, useExisting: DrizzleAgentStore },\n {\n provide: DrizzleGovernanceQueries,\n useFactory: () => new DrizzleGovernanceQueries(options.db),\n },\n { provide: AGENT_GOVERNANCE_QUERIES, useExisting: DrizzleGovernanceQueries },\n {\n provide: DrizzlePricingStore,\n useFactory: () => new DrizzlePricingStore(options.db),\n },\n { provide: AGENT_PRICING_STORE, useExisting: DrizzlePricingStore },\n ],\n exports: [\n DrizzleAgentStore,\n AGENT_STORE,\n DrizzleGovernanceQueries,\n AGENT_GOVERNANCE_QUERIES,\n DrizzlePricingStore,\n AGENT_PRICING_STORE,\n ],\n };\n }\n}\n"],"mappings":"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","names":["index","integer","real","sqliteTable","text","agentThread","id","primaryKey","actorRef","notNull","tenantRef","title","transient","mode","default","activeStreamId","createdAt","updatedAt","deletedAt","table","on","agentMessage","threadId","references","onDelete","role","$type","content","toolCalls","toolResults","followUps","usage","agentName","agentToolCall","messageId","toolName","toolType","input","output","status","executedByRef","executionMs","error","executedAt","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","agentModelPricing","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","isCurrent","agentSchema","sql","statements","ensureAgentSchema","db","statement","run","sql","raw","and","asc","desc","eq","gte","inArray","isNull","lte","DrizzleAgentStore","db","createThread","input","now","Date","thread","id","crypto","randomUUID","actorRef","actor","tenantRef","title","transient","activeStreamId","createdAt","updatedAt","deletedAt","insert","agentThread","values","toSummary","getThread","threadId","select","from","where","and","eq","isNull","undefined","messages","agentMessage","orderBy","asc","last","length","content","map","message","toStoredMessage","listThreads","limit","threads","desc","summaries","push","softDeleteThread","update","set","forkThread","fromMessageId","source","Error","cutoff","findIndex","kept","slice","fork","role","toolCalls","toolResults","followUps","usage","agentName","ownerOfThread","ownerOfToolCall","toolCallId","row","agentToolCall","innerJoin","messageId","runForToolCall","ownerOfActiveStream","runId","setTitle","setActiveStream","appendMessage","truncateFrom","doomedIds","delete","inArray","recordToolCall","toolName","toolType","output","status","executedByRef","executionMs","error","executedAt","updateToolCall","updates","recordUsage","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","quotaToday","day","start","end","rows","gte","lte","usedTokens","reduce","sum","lastContent","toISOString","lastMessagePreview","and","count","desc","eq","gte","isNull","lte","estimateFromTokens","pricing","row","price","get","modelId","undefined","cacheWriteTokens","cacheReadTokens","uncachedInputTokens","inputTokens","inputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","outputTokens","outputPricePer1m","rowCost","costUsd","dayBounds","range","start","Date","fromDay","end","toDay","DrizzleGovernanceQueries","db","loadPricing","rows","select","from","agentModelPricing","where","eq","isCurrent","Map","set","usageInRange","agentTokenUsage","and","gte","createdAt","lte","spendByModel","byModel","bucket","requests","result","push","sort","left","right","localeCompare","spendByActor","byActor","actorRef","totalTokens","usageTrend","byDay","day","toISOString","slice","recentToolCalls","limit","toolCallId","agentToolCall","id","toolName","toolType","status","threadId","agentMessage","innerJoin","messageId","orderBy","desc","map","recentThreads","threads","agentThread","isNull","deletedAt","updatedAt","thread","messageCountRow","value","count","usageRows","reduce","sum","title","messageCount","lastActivityAt","and","eq","DrizzlePricingStore","db","upsertModelPrice","input","update","agentModelPricing","set","isCurrent","where","and","eq","modelId","insert","values","id","crypto","randomUUID","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","Date","listCurrentPrices","rows","select","from","map","row","toISOString","AGENT_GOVERNANCE_QUERIES","AGENT_PRICING_STORE","AGENT_STORE","Module","DrizzleAgentStoreModule","forRoot","options","module","global","providers","provide","DrizzleAgentStore","useFactory","db","AGENT_STORE","useExisting","DrizzleGovernanceQueries","AGENT_GOVERNANCE_QUERIES","DrizzlePricingStore","AGENT_PRICING_STORE","exports"]}
1
+ {"version":3,"sources":["../src/schema.ts","../src/ensure-schema.ts","../src/drizzle-agent-store.ts","../src/drizzle-governance-queries.ts","../src/drizzle-pricing-store.ts","../src/drizzle-agent-store.module.ts"],"sourcesContent":["import type {\n MessageRole,\n MessageUsage,\n ToolCallRequest,\n ToolCallStatus,\n ToolKind,\n ToolResult,\n UsagePurpose,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n type BaseSQLiteDatabase,\n index,\n integer,\n real,\n sqliteTable,\n text,\n} from 'drizzle-orm/sqlite-core';\n\n/**\n * Drizzle schema mirroring the MikroORM agent entities (same logical columns/relations):\n * threads, messages, tool calls, token usage and model pricing. Targets the SQLite core so the\n * db-test runs on an in-memory better-sqlite3; timestamps are stored as integer epoch-ms columns\n * (`{ mode: 'timestamp_ms' }`) which Drizzle round-trips to/from JS `Date`, and the model-facing\n * message extras (tool calls/results, follow-ups, usage) live in JSON `text` columns.\n */\n\n/**\n * A conversation thread. `deletedAt` drives soft delete: a deleted thread is hidden from\n * {@link import('./drizzle-agent-store.js').DrizzleAgentStore.getThread}/`listThreads` but its\n * row survives.\n */\nexport const agentThread = sqliteTable(\n 'agent_thread',\n {\n id: text('id').primaryKey(),\n actorRef: text('actor_ref').notNull(),\n tenantRef: text('tenant_ref'),\n title: text('title').notNull(),\n transient: integer('transient', { mode: 'boolean' }).notNull().default(false),\n activeStreamId: text('active_stream_id'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n updatedAt: integer('updated_at', { mode: 'timestamp_ms' }).notNull(),\n deletedAt: integer('deleted_at', { mode: 'timestamp_ms' }),\n },\n (table) => [index('agent_thread_actor_updated_idx').on(table.actorRef, table.updatedAt)],\n);\n\n/**\n * One stored message in a thread. The model-facing extras (`toolCalls`/`toolResults`/\n * `followUps`/`usage`) are folded into nullable JSON columns so a single row round-trips to a\n * {@link import('@dudousxd/nestjs-agent-core').StoredMessage}. `threadId` cascades on delete.\n */\nexport const agentMessage = sqliteTable(\n 'agent_message',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n role: text('role').$type<MessageRole>().notNull(),\n content: text('content').notNull(),\n toolCalls: text('tool_calls', { mode: 'json' }).$type<ToolCallRequest[]>(),\n toolResults: text('tool_results', { mode: 'json' }).$type<ToolResult[]>(),\n followUps: text('follow_ups', { mode: 'json' }).$type<string[]>(),\n usage: text('usage', { mode: 'json' }).$type<MessageUsage>(),\n agentName: text('agent_name'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_message_thread_created_idx').on(table.threadId, table.createdAt)],\n);\n\n/** A tool call requested during an assistant turn. The pk is the model-supplied `toolCallId`. */\nexport const agentToolCall = sqliteTable('agent_tool_call', {\n id: text('id').primaryKey(),\n messageId: text('message_id')\n .notNull()\n .references(() => agentMessage.id, { onDelete: 'cascade' }),\n toolName: text('tool_name').notNull(),\n toolType: text('tool_type').$type<ToolKind>().notNull(),\n input: text('input', { mode: 'json' }),\n output: text('output', { mode: 'json' }),\n status: text('status').$type<ToolCallStatus>().notNull(),\n executedByRef: text('executed_by_ref'),\n executionMs: integer('execution_ms'),\n error: text('error'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n executedAt: integer('executed_at', { mode: 'timestamp_ms' }),\n});\n\n/** A token-usage ledger row, summed per actor per day by `quotaToday`. */\nexport const agentTokenUsage = sqliteTable(\n 'agent_token_usage',\n {\n id: text('id').primaryKey(),\n threadId: text('thread_id')\n .notNull()\n .references(() => agentThread.id, { onDelete: 'cascade' }),\n actorRef: text('actor_ref').notNull(),\n messageId: text('message_id'),\n modelId: text('model_id').notNull(),\n purpose: text('purpose').$type<UsagePurpose>().notNull(),\n inputTokens: integer('input_tokens').notNull(),\n outputTokens: integer('output_tokens').notNull(),\n /** Subset of `inputTokens` written to the prompt cache this turn; null when not reported. */\n cacheWriteTokens: integer('cache_write_tokens'),\n /** Subset of `inputTokens` served from the prompt cache this turn; null when not reported. */\n cacheReadTokens: integer('cache_read_tokens'),\n /** Provider-reported actual USD cost for the turn; null when only tokens were reported. */\n costUsd: real('cost_usd'),\n createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull(),\n },\n (table) => [index('agent_token_usage_actor_created_idx').on(table.actorRef, table.createdAt)],\n);\n\n/** Per-model token pricing, versioned by `effectiveFrom`; `isCurrent` flags the live row. */\nexport const agentModelPricing = sqliteTable('agent_model_pricing', {\n id: text('id').primaryKey(),\n modelId: text('model_id').notNull(),\n inputPricePer1m: real('input_price_per_1m').notNull(),\n outputPricePer1m: real('output_price_per_1m').notNull(),\n /** Per-1M price for cache-write input tokens; null → price them at the input rate. */\n cacheWritePricePer1m: real('cache_write_price_per_1m'),\n /** Per-1M price for cache-read input tokens; null → price them at the input rate. */\n cacheReadPricePer1m: real('cache_read_price_per_1m'),\n effectiveFrom: integer('effective_from', { mode: 'timestamp_ms' }).notNull(),\n isCurrent: integer('is_current', { mode: 'boolean' }).notNull(),\n});\n\n/** The five agent tables as one schema object, ready for `drizzle(client, { schema })`. */\nexport const agentSchema = {\n agentThread,\n agentMessage,\n agentToolCall,\n agentTokenUsage,\n agentModelPricing,\n};\n\n/**\n * The dialect-portable Drizzle SQLite database handle the store operates on. Accepts any SQLite\n * driver (better-sqlite3, libsql, D1, …) in either sync or async result mode; the host app owns\n * the connection and passes the `drizzle(...)` instance in.\n */\nexport type AgentDrizzleDb = BaseSQLiteDatabase<'sync' | 'async', unknown>;\n\n/** A persisted thread row as Drizzle selects it. */\nexport type AgentThreadRow = typeof agentThread.$inferSelect;\n/** A persisted message row as Drizzle selects it. */\nexport type AgentMessageRow = typeof agentMessage.$inferSelect;\n","import { sql } from 'drizzle-orm';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/**\n * Idempotent `CREATE TABLE IF NOT EXISTS` DDL for the five agent tables, mirroring\n * {@link import('./schema.js').agentSchema}. SQLite dialect (the db-test driver); kept here rather\n * than relying on drizzle-kit so the package can stand up its schema with no migration files. Safe\n * to run on boot against a shared database — it never drops or alters existing columns.\n */\nconst statements: string[] = [\n `CREATE TABLE IF NOT EXISTS agent_thread (\n id TEXT PRIMARY KEY NOT NULL,\n actor_ref TEXT NOT NULL,\n tenant_ref TEXT,\n title TEXT NOT NULL,\n transient INTEGER NOT NULL DEFAULT 0,\n active_stream_id TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n deleted_at INTEGER\n )`,\n `CREATE INDEX IF NOT EXISTS agent_thread_actor_updated_idx\n ON agent_thread (actor_ref, updated_at)`,\n `CREATE TABLE IF NOT EXISTS agent_message (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n content TEXT NOT NULL,\n tool_calls TEXT,\n tool_results TEXT,\n follow_ups TEXT,\n usage TEXT,\n agent_name TEXT,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_message_thread_created_idx\n ON agent_message (thread_id, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_tool_call (\n id TEXT PRIMARY KEY NOT NULL,\n message_id TEXT NOT NULL REFERENCES agent_message(id) ON DELETE CASCADE,\n tool_name TEXT NOT NULL,\n tool_type TEXT NOT NULL,\n input TEXT,\n output TEXT,\n status TEXT NOT NULL,\n executed_by_ref TEXT,\n execution_ms INTEGER,\n error TEXT,\n created_at INTEGER NOT NULL,\n executed_at INTEGER\n )`,\n `CREATE TABLE IF NOT EXISTS agent_token_usage (\n id TEXT PRIMARY KEY NOT NULL,\n thread_id TEXT NOT NULL REFERENCES agent_thread(id) ON DELETE CASCADE,\n actor_ref TEXT NOT NULL,\n message_id TEXT,\n model_id TEXT NOT NULL,\n purpose TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n cache_write_tokens INTEGER,\n cache_read_tokens INTEGER,\n cost_usd REAL,\n created_at INTEGER NOT NULL\n )`,\n `CREATE INDEX IF NOT EXISTS agent_token_usage_actor_created_idx\n ON agent_token_usage (actor_ref, created_at)`,\n `CREATE TABLE IF NOT EXISTS agent_model_pricing (\n id TEXT PRIMARY KEY NOT NULL,\n model_id TEXT NOT NULL,\n input_price_per_1m REAL NOT NULL,\n output_price_per_1m REAL NOT NULL,\n cache_write_price_per_1m REAL,\n cache_read_price_per_1m REAL,\n effective_from INTEGER NOT NULL,\n is_current INTEGER NOT NULL\n )`,\n];\n\n/** Runs the `CREATE TABLE IF NOT EXISTS` DDL above against the supplied Drizzle SQLite db. */\nexport async function ensureAgentSchema(db: AgentDrizzleDb): Promise<void> {\n for (const statement of statements) {\n await db.run(sql.raw(statement));\n }\n}\n","import type {\n AgentStore,\n AppendMessageInput,\n CreateThreadInput,\n RecordToolCallInput,\n RecordUsageInput,\n StoredMessage,\n ThreadDetail,\n ThreadSummary,\n UpdateToolCallInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, asc, desc, eq, gte, inArray, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n type AgentMessageRow,\n type AgentThreadRow,\n agentMessage,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/**\n * {@link AgentStore} backed by Drizzle ORM — a second adapter alongside the MikroORM one, proving\n * the store SPI is ORM-portable. A POJO receiving a Drizzle SQLite database handle (the host app\n * owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}\n * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.\n */\nexport class DrizzleAgentStore implements AgentStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async createThread(input: CreateThreadInput): Promise<ThreadSummary> {\n const now = new Date();\n const thread: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: input.actor.id,\n tenantRef: input.actor.tenantRef ?? null,\n title: input.title ?? 'New chat',\n transient: input.transient ?? false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(thread);\n return this.toSummary(thread);\n }\n\n async getThread(threadId: string): Promise<ThreadDetail | null> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n if (thread === undefined) {\n return null;\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const last = messages[messages.length - 1];\n return {\n ...this.toSummary(thread, last?.content),\n messages: messages.map((message) => this.toStoredMessage(message)),\n ...(thread.activeStreamId != null ? { activeStreamId: thread.activeStreamId } : {}),\n };\n }\n\n async listThreads(actorRef: string, limit = 50): Promise<ThreadSummary[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(\n and(\n eq(agentThread.actorRef, actorRef),\n eq(agentThread.transient, false),\n isNull(agentThread.deletedAt),\n ),\n )\n .orderBy(desc(agentThread.updatedAt))\n .limit(limit);\n const summaries: ThreadSummary[] = [];\n for (const thread of threads) {\n const [last] = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id))\n .orderBy(desc(agentMessage.createdAt), desc(agentMessage.id))\n .limit(1);\n summaries.push(this.toSummary(thread, last?.content));\n }\n return summaries;\n }\n\n async softDeleteThread(threadId: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ deletedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary> {\n const [source] = await this.db.select().from(agentThread).where(eq(agentThread.id, threadId));\n if (source === undefined) {\n throw new Error(`thread ${threadId} not found`);\n }\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === fromMessageId);\n const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;\n const now = new Date();\n const fork: AgentThreadRow = {\n id: crypto.randomUUID(),\n actorRef: source.actorRef,\n tenantRef: source.tenantRef,\n title: source.title,\n transient: false,\n activeStreamId: null,\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n };\n await this.db.insert(agentThread).values(fork);\n if (kept.length > 0) {\n await this.db.insert(agentMessage).values(\n kept.map((message) => ({\n id: crypto.randomUUID(),\n threadId: fork.id,\n role: message.role,\n content: message.content,\n toolCalls: message.toolCalls,\n toolResults: message.toolResults,\n followUps: message.followUps,\n usage: message.usage,\n agentName: message.agentName,\n createdAt: message.createdAt,\n })),\n );\n }\n return this.toSummary(fork);\n }\n\n async ownerOfThread(threadId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.id, threadId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async ownerOfToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.actorRef ?? null;\n }\n\n async runForToolCall(toolCallId: string): Promise<string | null> {\n const [row] = await this.db\n .select({ activeStreamId: agentThread.activeStreamId })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .innerJoin(agentThread, eq(agentMessage.threadId, agentThread.id))\n .where(eq(agentToolCall.id, toolCallId));\n return row?.activeStreamId ?? null;\n }\n\n async ownerOfActiveStream(runId: string): Promise<string | null> {\n const [thread] = await this.db\n .select({ actorRef: agentThread.actorRef })\n .from(agentThread)\n .where(and(eq(agentThread.activeStreamId, runId), isNull(agentThread.deletedAt)));\n return thread?.actorRef ?? null;\n }\n\n async setTitle(threadId: string, title: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ title, updatedAt: new Date() })\n .where(eq(agentThread.id, threadId));\n }\n\n async promoteThread(threadId: string): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ transient: false, updatedAt: new Date() })\n .where(and(eq(agentThread.id, threadId), eq(agentThread.transient, true)));\n }\n\n async setActiveStream(threadId: string, runId: string | null): Promise<void> {\n await this.db\n .update(agentThread)\n .set({ activeStreamId: runId })\n .where(eq(agentThread.id, threadId));\n }\n\n async appendMessage(input: AppendMessageInput): Promise<StoredMessage> {\n const [thread] = await this.db\n .select()\n .from(agentThread)\n .where(eq(agentThread.id, input.threadId));\n if (thread === undefined) {\n throw new Error(`thread ${input.threadId} not found`);\n }\n const now = new Date();\n const message: AgentMessageRow = {\n id: crypto.randomUUID(),\n threadId: input.threadId,\n role: input.role,\n content: input.content,\n toolCalls: input.toolCalls ?? null,\n toolResults: input.toolResults ?? null,\n followUps: input.followUps ?? null,\n usage: input.usage ?? null,\n agentName: input.agentName ?? null,\n createdAt: now,\n };\n await this.db.insert(agentMessage).values(message);\n await this.db\n .update(agentThread)\n .set({ updatedAt: now })\n .where(eq(agentThread.id, input.threadId));\n return this.toStoredMessage(message);\n }\n\n async truncateFrom(threadId: string, messageId: string): Promise<void> {\n const messages = await this.db\n .select()\n .from(agentMessage)\n .where(eq(agentMessage.threadId, threadId))\n .orderBy(asc(agentMessage.createdAt), asc(agentMessage.id));\n const cutoff = messages.findIndex((message) => message.id === messageId);\n if (cutoff < 0) {\n return;\n }\n const doomedIds = messages.slice(cutoff).map((message) => message.id);\n await this.db.delete(agentToolCall).where(inArray(agentToolCall.messageId, doomedIds));\n await this.db.delete(agentMessage).where(inArray(agentMessage.id, doomedIds));\n }\n\n async recordToolCall(input: RecordToolCallInput): Promise<void> {\n await this.db.insert(agentToolCall).values({\n id: input.toolCallId,\n messageId: input.messageId,\n toolName: input.toolName,\n toolType: input.toolType,\n input: input.input,\n output: null,\n status: input.status,\n executedByRef: null,\n executionMs: null,\n error: null,\n createdAt: new Date(),\n executedAt: null,\n });\n }\n\n async updateToolCall(input: UpdateToolCallInput): Promise<void> {\n const updates: Partial<typeof agentToolCall.$inferInsert> = { status: input.status };\n if (input.output !== undefined) {\n updates.output = input.output;\n }\n if (input.error !== undefined) {\n updates.error = input.error;\n }\n if (input.executionMs !== undefined) {\n updates.executionMs = input.executionMs;\n }\n if (input.executedByRef !== undefined) {\n updates.executedByRef = input.executedByRef;\n }\n if (input.status === 'executed' || input.status === 'auto_executed') {\n updates.executedAt = new Date();\n }\n await this.db.update(agentToolCall).set(updates).where(eq(agentToolCall.id, input.toolCallId));\n }\n\n async recordUsage(input: RecordUsageInput): Promise<void> {\n await this.db.insert(agentTokenUsage).values({\n id: crypto.randomUUID(),\n threadId: input.threadId,\n actorRef: input.actorRef,\n messageId: input.messageId ?? null,\n modelId: input.modelId,\n purpose: input.purpose,\n inputTokens: input.usage.inputTokens,\n outputTokens: input.usage.outputTokens,\n cacheWriteTokens: input.usage.cacheWriteTokens ?? null,\n cacheReadTokens: input.usage.cacheReadTokens ?? null,\n costUsd: input.costUsd ?? null,\n createdAt: new Date(),\n });\n }\n\n async quotaToday(\n actorRef: string,\n day: string,\n ): Promise<{ usedTokens: number; costUsd: number }> {\n const start = new Date(`${day}T00:00:00.000Z`);\n const end = new Date(`${day}T23:59:59.999Z`);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(\n and(\n eq(agentTokenUsage.actorRef, actorRef),\n gte(agentTokenUsage.createdAt, start),\n lte(agentTokenUsage.createdAt, end),\n ),\n );\n const usedTokens = rows.reduce((sum, row) => sum + row.inputTokens + row.outputTokens, 0);\n const costUsd = rows.reduce((sum, row) => sum + (row.costUsd ?? 0), 0);\n return { usedTokens, costUsd };\n }\n\n private toSummary(thread: AgentThreadRow, lastContent?: string): ThreadSummary {\n return {\n id: thread.id,\n title: thread.title,\n transient: thread.transient,\n createdAt: thread.createdAt.toISOString(),\n updatedAt: thread.updatedAt.toISOString(),\n ...(lastContent !== undefined ? { lastMessagePreview: lastContent.slice(0, 120) } : {}),\n };\n }\n\n private toStoredMessage(message: AgentMessageRow): StoredMessage {\n return {\n id: message.id,\n role: message.role,\n content: message.content,\n createdAt: message.createdAt.toISOString(),\n ...(message.toolCalls != null ? { toolCalls: message.toolCalls } : {}),\n ...(message.toolResults != null ? { toolResults: message.toolResults } : {}),\n ...(message.followUps != null ? { followUps: message.followUps } : {}),\n ...(message.usage != null ? { usage: message.usage } : {}),\n ...(message.agentName != null ? { agentName: message.agentName } : {}),\n };\n }\n}\n","import type {\n ActorSpendRow,\n AgentGovernanceQueries,\n AgentPricingStore,\n GovernanceRange,\n ModelSpendRow,\n ThreadActivityRow,\n ThreadSpendRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, count, desc, eq, gte, inArray, isNull, lte } from 'drizzle-orm';\nimport {\n type AgentDrizzleDb,\n agentMessage,\n agentThread,\n agentTokenUsage,\n agentToolCall,\n} from './schema.js';\n\n/** The current per-1M token prices for one model; cache rates fall back to the input rate. */\ninterface ModelPrice {\n inputPricePer1m: number;\n outputPricePer1m: number;\n cacheWritePricePer1m?: number | null;\n cacheReadPricePer1m?: number | null;\n}\n\n/**\n * Token-ledger estimate for one usage row against the current pricing row: the uncached input at the\n * input rate, cache-write/cache-read tokens at their own rates (falling back to the input rate when\n * unpriced), plus output at the output rate. An unpriced model contributes 0 (tokens still count).\n * Cache token counts are subsets of `inputTokens`, so the uncached remainder is the difference.\n */\nfunction estimateFromTokens(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n const price = pricing.get(row.modelId);\n if (price === undefined) {\n return 0;\n }\n const cacheWriteTokens = row.cacheWriteTokens ?? 0;\n const cacheReadTokens = row.cacheReadTokens ?? 0;\n const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;\n return (\n (uncachedInputTokens / 1_000_000) * price.inputPricePer1m +\n (cacheWriteTokens / 1_000_000) * (price.cacheWritePricePer1m ?? price.inputPricePer1m) +\n (cacheReadTokens / 1_000_000) * (price.cacheReadPricePer1m ?? price.inputPricePer1m) +\n (row.outputTokens / 1_000_000) * price.outputPricePer1m\n );\n}\n\n/**\n * The cost of one usage row: the provider-reported `costUsd` when present (gateways report real\n * spend), otherwise the cache-aware token estimate against the current pricing row.\n */\nfunction rowCost(\n pricing: Map<string, ModelPrice>,\n row: typeof agentTokenUsage.$inferSelect,\n): number {\n return row.costUsd ?? estimateFromTokens(pricing, row);\n}\n\n/** Turns an inclusive `YYYY-MM-DD` day range into the UTC datetime bounds used by `quotaToday`. */\nfunction dayBounds(range: GovernanceRange): { start: Date; end: Date } {\n return {\n start: new Date(`${range.fromDay}T00:00:00.000Z`),\n end: new Date(`${range.toDay}T23:59:59.999Z`),\n };\n}\n\n/**\n * {@link AgentGovernanceQueries} backed by Drizzle ORM — the read/analytics half of the store SPI,\n * mirroring {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly. Cost is the token\n * ledger priced against the current prices from the injected {@link AgentPricingStore}\n * (`AGENT_PRICING_STORE`), so a host that binds its own pricing store controls the cost every\n * governance surface reports. An unpriced model contributes 0 cost. Aggregation is in-process (like\n * `quotaToday`) so day-bucketing stays dialect-portable.\n */\nexport class DrizzleGovernanceQueries implements AgentGovernanceQueries {\n constructor(\n private readonly db: AgentDrizzleDb,\n private readonly pricingStore: AgentPricingStore,\n ) {}\n\n private async loadPricing(): Promise<Map<string, ModelPrice>> {\n const prices = await this.pricingStore.listCurrentPrices();\n const pricing = new Map<string, ModelPrice>();\n for (const price of prices) {\n pricing.set(price.modelId, {\n inputPricePer1m: price.inputPricePer1m,\n outputPricePer1m: price.outputPricePer1m,\n cacheWritePricePer1m: price.cacheWritePricePer1m ?? null,\n cacheReadPricePer1m: price.cacheReadPricePer1m ?? null,\n });\n }\n return pricing;\n }\n\n private async usageInRange(\n range: GovernanceRange,\n ): Promise<(typeof agentTokenUsage.$inferSelect)[]> {\n const { start, end } = dayBounds(range);\n const rows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(and(gte(agentTokenUsage.createdAt, start), lte(agentTokenUsage.createdAt, end)));\n return rows;\n }\n\n async spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byModel = new Map<\n string,\n { requests: number; inputTokens: number; outputTokens: number; costUsd: number }\n >();\n for (const row of rows) {\n const bucket = byModel.get(row.modelId) ?? {\n requests: 0,\n inputTokens: 0,\n outputTokens: 0,\n costUsd: 0,\n };\n bucket.requests += 1;\n bucket.inputTokens += row.inputTokens;\n bucket.outputTokens += row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byModel.set(row.modelId, bucket);\n }\n const result: ModelSpendRow[] = [];\n for (const [modelId, bucket] of byModel) {\n result.push({\n modelId,\n requests: bucket.requests,\n inputTokens: bucket.inputTokens,\n outputTokens: bucket.outputTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId),\n );\n return result;\n }\n\n async spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byActor = new Map<\n string,\n { requests: number; totalTokens: number; costUsd: number; threadIds: Set<string> }\n >();\n for (const row of rows) {\n const bucket = byActor.get(row.actorRef) ?? {\n requests: 0,\n totalTokens: 0,\n costUsd: 0,\n threadIds: new Set<string>(),\n };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n bucket.threadIds.add(row.threadId);\n byActor.set(row.actorRef, bucket);\n }\n const result: ActorSpendRow[] = [];\n for (const [actorRef, bucket] of byActor) {\n result.push({\n actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n threadCount: bucket.threadIds.size,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef),\n );\n return result;\n }\n\n /**\n * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a\n * soft-deleted thread (`deletedAt` set) are excluded — the thread no longer surfaces as a\n * governance target even though its ledger rows survive.\n */\n async spendByThread(range: GovernanceRange, limit: number): Promise<ThreadSpendRow[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byThread = new Map<string, { requests: number; totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const bucket = byThread.get(row.threadId) ?? { requests: 0, totalTokens: 0, costUsd: 0 };\n bucket.requests += 1;\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byThread.set(row.threadId, bucket);\n }\n if (byThread.size === 0) {\n return [];\n }\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(and(inArray(agentThread.id, [...byThread.keys()]), isNull(agentThread.deletedAt)));\n const threadsById = new Map(threads.map((thread) => [thread.id, thread]));\n const result: ThreadSpendRow[] = [];\n for (const [threadId, bucket] of byThread) {\n const thread = threadsById.get(threadId);\n if (thread === undefined) {\n continue;\n }\n result.push({\n threadId,\n title: thread.title,\n actorRef: thread.actorRef,\n requests: bucket.requests,\n totalTokens: bucket.totalTokens,\n costUsd: bucket.costUsd,\n });\n }\n result.sort(\n (left, right) => right.costUsd - left.costUsd || left.threadId.localeCompare(right.threadId),\n );\n return result.slice(0, limit);\n }\n\n async usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]> {\n const pricing = await this.loadPricing();\n const rows = await this.usageInRange(range);\n const byDay = new Map<string, { totalTokens: number; costUsd: number }>();\n for (const row of rows) {\n const day = row.createdAt.toISOString().slice(0, 10);\n const bucket = byDay.get(day) ?? { totalTokens: 0, costUsd: 0 };\n bucket.totalTokens += row.inputTokens + row.outputTokens;\n bucket.costUsd += rowCost(pricing, row);\n byDay.set(day, bucket);\n }\n const result: UsageTrendPoint[] = [];\n for (const [day, bucket] of byDay) {\n result.push({ day, totalTokens: bucket.totalTokens, costUsd: bucket.costUsd });\n }\n result.sort((left, right) => left.day.localeCompare(right.day));\n return result;\n }\n\n async recentToolCalls(limit: number): Promise<ToolCallActivityRow[]> {\n const rows = await this.db\n .select({\n toolCallId: agentToolCall.id,\n toolName: agentToolCall.toolName,\n toolType: agentToolCall.toolType,\n status: agentToolCall.status,\n threadId: agentMessage.threadId,\n createdAt: agentToolCall.createdAt,\n })\n .from(agentToolCall)\n .innerJoin(agentMessage, eq(agentToolCall.messageId, agentMessage.id))\n .orderBy(desc(agentToolCall.createdAt), desc(agentToolCall.id))\n .limit(limit);\n return rows.map((row) => ({\n toolCallId: row.toolCallId,\n toolName: row.toolName,\n toolType: row.toolType,\n status: row.status,\n threadId: row.threadId,\n createdAt: row.createdAt.toISOString(),\n }));\n }\n\n async recentThreads(limit: number): Promise<ThreadActivityRow[]> {\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(isNull(agentThread.deletedAt))\n .orderBy(desc(agentThread.updatedAt), desc(agentThread.id))\n .limit(limit);\n const result: ThreadActivityRow[] = [];\n for (const thread of threads) {\n const [messageCountRow] = await this.db\n .select({ value: count() })\n .from(agentMessage)\n .where(eq(agentMessage.threadId, thread.id));\n const usageRows = await this.db\n .select()\n .from(agentTokenUsage)\n .where(eq(agentTokenUsage.threadId, thread.id));\n const totalTokens = usageRows.reduce(\n (sum, row) => sum + row.inputTokens + row.outputTokens,\n 0,\n );\n result.push({\n threadId: thread.id,\n title: thread.title,\n actorRef: thread.actorRef,\n messageCount: messageCountRow?.value ?? 0,\n totalTokens,\n lastActivityAt: thread.updatedAt.toISOString(),\n });\n }\n return result;\n }\n}\n","import type {\n AgentPricingStore,\n CurrentModelPrice,\n ModelPriceInput,\n} from '@dudousxd/nestjs-agent-core';\nimport { and, eq } from 'drizzle-orm';\nimport { type AgentDrizzleDb, agentModelPricing } from './schema.js';\n\n/**\n * {@link AgentPricingStore} backed by Drizzle ORM — the write side of the pricing table\n * {@link import('./drizzle-governance-queries.js').DrizzleGovernanceQueries} joins against. A POJO\n * receiving a Drizzle SQLite database handle (the host app owns the connection), mirroring\n * {@link import('@dudousxd/nestjs-agent-store-mikro-orm')} exactly (atomic supersede semantics).\n */\nexport class DrizzlePricingStore implements AgentPricingStore {\n constructor(private readonly db: AgentDrizzleDb) {}\n\n async upsertModelPrice(input: ModelPriceInput): Promise<void> {\n await this.db\n .update(agentModelPricing)\n .set({ isCurrent: false })\n .where(\n and(eq(agentModelPricing.modelId, input.modelId), eq(agentModelPricing.isCurrent, true)),\n );\n await this.db.insert(agentModelPricing).values({\n id: crypto.randomUUID(),\n modelId: input.modelId,\n inputPricePer1m: input.inputPricePer1m,\n outputPricePer1m: input.outputPricePer1m,\n cacheWritePricePer1m: input.cacheWritePricePer1m ?? null,\n cacheReadPricePer1m: input.cacheReadPricePer1m ?? null,\n effectiveFrom: new Date(),\n isCurrent: true,\n });\n }\n\n async listCurrentPrices(): Promise<CurrentModelPrice[]> {\n const rows = await this.db\n .select()\n .from(agentModelPricing)\n .where(eq(agentModelPricing.isCurrent, true));\n return rows.map((row) => ({\n modelId: row.modelId,\n inputPricePer1m: row.inputPricePer1m,\n outputPricePer1m: row.outputPricePer1m,\n effectiveFrom: row.effectiveFrom.toISOString(),\n ...(row.cacheWritePricePer1m != null\n ? { cacheWritePricePer1m: row.cacheWritePricePer1m }\n : {}),\n ...(row.cacheReadPricePer1m != null ? { cacheReadPricePer1m: row.cacheReadPricePer1m } : {}),\n }));\n }\n}\n","import {\n AGENT_GOVERNANCE_QUERIES,\n AGENT_PRICING_STORE,\n AGENT_STORE,\n type AgentPricingStore,\n} from '@dudousxd/nestjs-agent-core';\nimport { type DynamicModule, Module, type Type } from '@nestjs/common';\nimport { DrizzleAgentStore } from './drizzle-agent-store.js';\nimport { DrizzleGovernanceQueries } from './drizzle-governance-queries.js';\nimport { DrizzlePricingStore } from './drizzle-pricing-store.js';\nimport type { AgentDrizzleDb } from './schema.js';\n\n/** Options for {@link DrizzleAgentStoreModule.forRoot}. The app owns and supplies the db handle. */\nexport interface DrizzleAgentStoreModuleOptions {\n /** A Drizzle SQLite database instance (`drizzle(client, { schema: agentSchema })`). */\n db: AgentDrizzleDb;\n /**\n * Bind {@link AGENT_PRICING_STORE} (which {@link DrizzleGovernanceQueries} prices usage against) to\n * a host-supplied store instead of the default {@link DrizzlePricingStore} — make your OWN pricing\n * table the single source of cost truth without touching `agent_model_pricing`.\n */\n pricingStore?: Type<AgentPricingStore>;\n}\n\n/**\n * Binds {@link DrizzleAgentStore} to the {@link AGENT_STORE} token consumed by\n * `@dudousxd/nestjs-agent`, plus {@link DrizzleGovernanceQueries} to\n * {@link AGENT_GOVERNANCE_QUERIES} (the read-model the dashboard/telescope surfaces consume) and\n * {@link DrizzlePricingStore} to {@link AGENT_PRICING_STORE} (the write side of that pricing table).\n * The host app supplies an already-opened Drizzle db — this module never opens a connection itself.\n *\n * The returned module is global, so {@link AGENT_STORE}, {@link AGENT_GOVERNANCE_QUERIES} and\n * {@link AGENT_PRICING_STORE} are visible app-wide — `AgentModule` resolves the store without an\n * explicit `store` option, and the dashboard/telescope resolve {@link AGENT_GOVERNANCE_QUERIES}\n * without the host re-binding it.\n *\n * ```ts\n * @Module({ imports: [DrizzleAgentStoreModule.forRoot({ db })] })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class DrizzleAgentStoreModule {\n static forRoot(options: DrizzleAgentStoreModuleOptions): DynamicModule {\n return {\n module: DrizzleAgentStoreModule,\n global: true,\n providers: [\n { provide: DrizzleAgentStore, useFactory: () => new DrizzleAgentStore(options.db) },\n { provide: AGENT_STORE, useExisting: DrizzleAgentStore },\n {\n provide: DrizzlePricingStore,\n useFactory: () => new DrizzlePricingStore(options.db),\n },\n // AGENT_PRICING_STORE: the host's own store when supplied, else the default Drizzle one.\n // DrizzleGovernanceQueries prices usage against whatever is bound here.\n options.pricingStore\n ? { provide: AGENT_PRICING_STORE, useClass: options.pricingStore }\n : { provide: AGENT_PRICING_STORE, useExisting: DrizzlePricingStore },\n {\n provide: DrizzleGovernanceQueries,\n useFactory: (pricingStore: AgentPricingStore) =>\n new DrizzleGovernanceQueries(options.db, pricingStore),\n inject: [AGENT_PRICING_STORE],\n },\n { provide: AGENT_GOVERNANCE_QUERIES, useExisting: DrizzleGovernanceQueries },\n ],\n exports: [\n DrizzleAgentStore,\n AGENT_STORE,\n DrizzleGovernanceQueries,\n AGENT_GOVERNANCE_QUERIES,\n DrizzlePricingStore,\n AGENT_PRICING_STORE,\n ],\n };\n }\n}\n"],"mappings":"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","names":["index","integer","real","sqliteTable","text","agentThread","id","primaryKey","actorRef","notNull","tenantRef","title","transient","mode","default","activeStreamId","createdAt","updatedAt","deletedAt","table","on","agentMessage","threadId","references","onDelete","role","$type","content","toolCalls","toolResults","followUps","usage","agentName","agentToolCall","messageId","toolName","toolType","input","output","status","executedByRef","executionMs","error","executedAt","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","agentModelPricing","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","isCurrent","agentSchema","sql","statements","ensureAgentSchema","db","statement","run","sql","raw","and","asc","desc","eq","gte","inArray","isNull","lte","DrizzleAgentStore","db","createThread","input","now","Date","thread","id","crypto","randomUUID","actorRef","actor","tenantRef","title","transient","activeStreamId","createdAt","updatedAt","deletedAt","insert","agentThread","values","toSummary","getThread","threadId","select","from","where","and","eq","isNull","undefined","messages","agentMessage","orderBy","asc","last","length","content","map","message","toStoredMessage","listThreads","limit","threads","desc","summaries","push","softDeleteThread","update","set","forkThread","fromMessageId","source","Error","cutoff","findIndex","kept","slice","fork","role","toolCalls","toolResults","followUps","usage","agentName","ownerOfThread","ownerOfToolCall","toolCallId","row","agentToolCall","innerJoin","messageId","runForToolCall","ownerOfActiveStream","runId","setTitle","promoteThread","setActiveStream","appendMessage","truncateFrom","doomedIds","delete","inArray","recordToolCall","toolName","toolType","output","status","executedByRef","executionMs","error","executedAt","updateToolCall","updates","recordUsage","agentTokenUsage","modelId","purpose","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","quotaToday","day","start","end","rows","gte","lte","usedTokens","reduce","sum","lastContent","toISOString","lastMessagePreview","and","count","desc","eq","gte","inArray","isNull","lte","estimateFromTokens","pricing","row","price","get","modelId","undefined","cacheWriteTokens","cacheReadTokens","uncachedInputTokens","inputTokens","inputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","outputTokens","outputPricePer1m","rowCost","costUsd","dayBounds","range","start","Date","fromDay","end","toDay","DrizzleGovernanceQueries","db","pricingStore","loadPricing","prices","listCurrentPrices","Map","set","usageInRange","rows","select","from","agentTokenUsage","where","and","gte","createdAt","lte","spendByModel","byModel","bucket","requests","result","push","sort","left","right","localeCompare","spendByActor","byActor","actorRef","totalTokens","threadIds","Set","add","threadId","threadCount","size","spendByThread","limit","byThread","threads","agentThread","inArray","id","keys","isNull","deletedAt","threadsById","map","thread","title","slice","usageTrend","byDay","day","toISOString","recentToolCalls","toolCallId","agentToolCall","toolName","toolType","status","agentMessage","innerJoin","eq","messageId","orderBy","desc","recentThreads","updatedAt","messageCountRow","value","count","usageRows","reduce","sum","messageCount","lastActivityAt","and","eq","DrizzlePricingStore","db","upsertModelPrice","input","update","agentModelPricing","set","isCurrent","where","and","eq","modelId","insert","values","id","crypto","randomUUID","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","effectiveFrom","Date","listCurrentPrices","rows","select","from","map","row","toISOString","AGENT_GOVERNANCE_QUERIES","AGENT_PRICING_STORE","AGENT_STORE","Module","DrizzleAgentStoreModule","forRoot","options","module","global","providers","provide","DrizzleAgentStore","useFactory","db","AGENT_STORE","useExisting","DrizzlePricingStore","pricingStore","AGENT_PRICING_STORE","useClass","DrizzleGovernanceQueries","inject","AGENT_GOVERNANCE_QUERIES","exports"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dudousxd/nestjs-agent-store-drizzle",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "nestjs-agent Drizzle ORM agent store (threads, messages, tool calls, usage)",
5
5
  "license": "MIT",
6
6
  "author": "Davide Carvalho",
@@ -24,7 +24,7 @@
24
24
  "dist"
25
25
  ],
26
26
  "dependencies": {
27
- "@dudousxd/nestjs-agent-core": "0.2.0"
27
+ "@dudousxd/nestjs-agent-core": "0.3.1"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@nestjs/common": "^10.0.0 || ^11.0.0",
@@ -38,7 +38,7 @@
38
38
  "tsup": "8.3.5",
39
39
  "typescript": "5.9.3",
40
40
  "vitest": "2.1.9",
41
- "@dudousxd/nestjs-agent-core": "0.2.0"
41
+ "@dudousxd/nestjs-agent-core": "0.3.1"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsup",