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

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
@@ -502,29 +502,22 @@ var DrizzleAgentStore = class {
502
502
  };
503
503
 
504
504
  // src/drizzle-governance-queries.ts
505
+ var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
505
506
  var import_drizzle_orm3 = require("drizzle-orm");
506
- function estimateFromTokens(pricing, row) {
507
- const price = pricing.get(row.modelId);
508
- if (price === void 0) {
509
- return 0;
510
- }
511
- const cacheWriteTokens = row.cacheWriteTokens ?? 0;
512
- const cacheReadTokens = row.cacheReadTokens ?? 0;
513
- const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;
514
- return uncachedInputTokens / 1e6 * price.inputPricePer1m + cacheWriteTokens / 1e6 * (price.cacheWritePricePer1m ?? price.inputPricePer1m) + cacheReadTokens / 1e6 * (price.cacheReadPricePer1m ?? price.inputPricePer1m) + row.outputTokens / 1e6 * price.outputPricePer1m;
515
- }
516
- __name(estimateFromTokens, "estimateFromTokens");
517
- function rowCost(pricing, row) {
518
- return row.costUsd ?? estimateFromTokens(pricing, row);
519
- }
520
- __name(rowCost, "rowCost");
521
- function dayBounds(range) {
507
+ function toUsageInput(row) {
522
508
  return {
523
- start: /* @__PURE__ */ new Date(`${range.fromDay}T00:00:00.000Z`),
524
- end: /* @__PURE__ */ new Date(`${range.toDay}T23:59:59.999Z`)
509
+ modelId: row.modelId,
510
+ actorRef: row.actorRef,
511
+ threadId: row.threadId,
512
+ day: row.createdAt.toISOString().slice(0, 10),
513
+ inputTokens: row.inputTokens,
514
+ outputTokens: row.outputTokens,
515
+ cacheWriteTokens: row.cacheWriteTokens,
516
+ cacheReadTokens: row.cacheReadTokens,
517
+ costUsd: row.costUsd
525
518
  };
526
519
  }
527
- __name(dayBounds, "dayBounds");
520
+ __name(toUsageInput, "toUsageInput");
528
521
  var DrizzleGovernanceQueries = class {
529
522
  static {
530
523
  __name(this, "DrizzleGovernanceQueries");
@@ -549,69 +542,17 @@ var DrizzleGovernanceQueries = class {
549
542
  return pricing;
550
543
  }
551
544
  async usageInRange(range) {
552
- const { start, end } = dayBounds(range);
545
+ const { start, end } = (0, import_nestjs_agent_core.dayBoundsUtc)(range);
553
546
  const rows = await this.db.select().from(agentTokenUsage).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.gte)(agentTokenUsage.createdAt, start), (0, import_drizzle_orm3.lte)(agentTokenUsage.createdAt, end)));
554
- return rows;
547
+ return rows.map(toUsageInput);
555
548
  }
556
549
  async spendByModel(range) {
557
550
  const pricing = await this.loadPricing();
558
- const rows = await this.usageInRange(range);
559
- const byModel = /* @__PURE__ */ new Map();
560
- for (const row of rows) {
561
- const bucket = byModel.get(row.modelId) ?? {
562
- requests: 0,
563
- inputTokens: 0,
564
- outputTokens: 0,
565
- costUsd: 0
566
- };
567
- bucket.requests += 1;
568
- bucket.inputTokens += row.inputTokens;
569
- bucket.outputTokens += row.outputTokens;
570
- bucket.costUsd += rowCost(pricing, row);
571
- byModel.set(row.modelId, bucket);
572
- }
573
- const result = [];
574
- for (const [modelId, bucket] of byModel) {
575
- result.push({
576
- modelId,
577
- requests: bucket.requests,
578
- inputTokens: bucket.inputTokens,
579
- outputTokens: bucket.outputTokens,
580
- costUsd: bucket.costUsd
581
- });
582
- }
583
- result.sort((left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId));
584
- return result;
551
+ return (0, import_nestjs_agent_core.bucketByModel)(await this.usageInRange(range), pricing);
585
552
  }
586
553
  async spendByActor(range) {
587
554
  const pricing = await this.loadPricing();
588
- const rows = await this.usageInRange(range);
589
- const byActor = /* @__PURE__ */ new Map();
590
- for (const row of rows) {
591
- const bucket = byActor.get(row.actorRef) ?? {
592
- requests: 0,
593
- totalTokens: 0,
594
- costUsd: 0,
595
- threadIds: /* @__PURE__ */ new Set()
596
- };
597
- bucket.requests += 1;
598
- bucket.totalTokens += row.inputTokens + row.outputTokens;
599
- bucket.costUsd += rowCost(pricing, row);
600
- bucket.threadIds.add(row.threadId);
601
- byActor.set(row.actorRef, bucket);
602
- }
603
- const result = [];
604
- for (const [actorRef, bucket] of byActor) {
605
- result.push({
606
- actorRef,
607
- requests: bucket.requests,
608
- totalTokens: bucket.totalTokens,
609
- costUsd: bucket.costUsd,
610
- threadCount: bucket.threadIds.size
611
- });
612
- }
613
- result.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
614
- return result;
555
+ return (0, import_nestjs_agent_core.bucketByActor)(await this.usageInRange(range), pricing);
615
556
  }
616
557
  /**
617
558
  * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a
@@ -621,70 +562,28 @@ var DrizzleGovernanceQueries = class {
621
562
  async spendByThread(range, limit) {
622
563
  const pricing = await this.loadPricing();
623
564
  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) {
565
+ const threadIds = [
566
+ ...new Set(rows.map((row) => row.threadId))
567
+ ];
568
+ if (threadIds.length === 0) {
637
569
  return [];
638
570
  }
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)));
571
+ const threads = await this.db.select().from(agentThread).where((0, import_drizzle_orm3.and)((0, import_drizzle_orm3.inArray)(agentThread.id, threadIds), (0, import_drizzle_orm3.isNull)(agentThread.deletedAt)));
642
572
  const threadsById = new Map(threads.map((thread) => [
643
573
  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,
574
+ {
654
575
  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);
576
+ actorRef: thread.actorRef
577
+ }
578
+ ]));
579
+ return (0, import_nestjs_agent_core.bucketByThread)(rows, pricing, threadsById, {
580
+ limit,
581
+ includeUnknownThreads: false
582
+ });
663
583
  }
664
584
  async usageTrend(range) {
665
585
  const pricing = await this.loadPricing();
666
- const rows = await this.usageInRange(range);
667
- const byDay = /* @__PURE__ */ new Map();
668
- for (const row of rows) {
669
- const day = row.createdAt.toISOString().slice(0, 10);
670
- const bucket = byDay.get(day) ?? {
671
- totalTokens: 0,
672
- costUsd: 0
673
- };
674
- bucket.totalTokens += row.inputTokens + row.outputTokens;
675
- bucket.costUsd += rowCost(pricing, row);
676
- byDay.set(day, bucket);
677
- }
678
- const result = [];
679
- for (const [day, bucket] of byDay) {
680
- result.push({
681
- day,
682
- totalTokens: bucket.totalTokens,
683
- costUsd: bucket.costUsd
684
- });
685
- }
686
- result.sort((left, right) => left.day.localeCompare(right.day));
687
- return result;
586
+ return (0, import_nestjs_agent_core.bucketUsageTrend)(await this.usageInRange(range), pricing);
688
587
  }
689
588
  async recentToolCalls(limit) {
690
589
  const rows = await this.db.select({
@@ -769,7 +668,7 @@ var DrizzlePricingStore = class {
769
668
  };
770
669
 
771
670
  // src/drizzle-agent-store.module.ts
772
- var import_nestjs_agent_core = require("@dudousxd/nestjs-agent-core");
671
+ var import_nestjs_agent_core2 = require("@dudousxd/nestjs-agent-core");
773
672
  var import_common = require("@nestjs/common");
774
673
  function _ts_decorate(decorators, target, key, desc3) {
775
674
  var c = arguments.length, r = c < 3 ? target : desc3 === null ? desc3 = Object.getOwnPropertyDescriptor(target, key) : desc3, d;
@@ -792,7 +691,7 @@ var DrizzleAgentStoreModule = class _DrizzleAgentStoreModule {
792
691
  useFactory: /* @__PURE__ */ __name(() => new DrizzleAgentStore(options.db), "useFactory")
793
692
  },
794
693
  {
795
- provide: import_nestjs_agent_core.AGENT_STORE,
694
+ provide: import_nestjs_agent_core2.AGENT_STORE,
796
695
  useExisting: DrizzleAgentStore
797
696
  },
798
697
  {
@@ -802,31 +701,31 @@ var DrizzleAgentStoreModule = class _DrizzleAgentStoreModule {
802
701
  // AGENT_PRICING_STORE: the host's own store when supplied, else the default Drizzle one.
803
702
  // DrizzleGovernanceQueries prices usage against whatever is bound here.
804
703
  options.pricingStore ? {
805
- provide: import_nestjs_agent_core.AGENT_PRICING_STORE,
704
+ provide: import_nestjs_agent_core2.AGENT_PRICING_STORE,
806
705
  useClass: options.pricingStore
807
706
  } : {
808
- provide: import_nestjs_agent_core.AGENT_PRICING_STORE,
707
+ provide: import_nestjs_agent_core2.AGENT_PRICING_STORE,
809
708
  useExisting: DrizzlePricingStore
810
709
  },
811
710
  {
812
711
  provide: DrizzleGovernanceQueries,
813
712
  useFactory: /* @__PURE__ */ __name((pricingStore) => new DrizzleGovernanceQueries(options.db, pricingStore), "useFactory"),
814
713
  inject: [
815
- import_nestjs_agent_core.AGENT_PRICING_STORE
714
+ import_nestjs_agent_core2.AGENT_PRICING_STORE
816
715
  ]
817
716
  },
818
717
  {
819
- provide: import_nestjs_agent_core.AGENT_GOVERNANCE_QUERIES,
718
+ provide: import_nestjs_agent_core2.AGENT_GOVERNANCE_QUERIES,
820
719
  useExisting: DrizzleGovernanceQueries
821
720
  }
822
721
  ],
823
722
  exports: [
824
723
  DrizzleAgentStore,
825
- import_nestjs_agent_core.AGENT_STORE,
724
+ import_nestjs_agent_core2.AGENT_STORE,
826
725
  DrizzleGovernanceQueries,
827
- import_nestjs_agent_core.AGENT_GOVERNANCE_QUERIES,
726
+ import_nestjs_agent_core2.AGENT_GOVERNANCE_QUERIES,
828
727
  DrizzlePricingStore,
829
- import_nestjs_agent_core.AGENT_PRICING_STORE
728
+ import_nestjs_agent_core2.AGENT_PRICING_STORE
830
729
  ]
831
730
  };
832
731
  }
@@ -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 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":["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"]}
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 GovernanceUsageInput,\n ModelPrice,\n ModelSpendRow,\n ThreadActivityRow,\n ThreadMeta,\n ThreadSpendRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n bucketByActor,\n bucketByModel,\n bucketByThread,\n bucketUsageTrend,\n dayBoundsUtc,\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/** Map a Drizzle usage row onto the shared bucketer input (day derived from `createdAt`). */\nfunction toUsageInput(row: typeof agentTokenUsage.$inferSelect): GovernanceUsageInput {\n return {\n modelId: row.modelId,\n actorRef: row.actorRef,\n threadId: row.threadId,\n day: row.createdAt.toISOString().slice(0, 10),\n inputTokens: row.inputTokens,\n outputTokens: row.outputTokens,\n cacheWriteTokens: row.cacheWriteTokens,\n cacheReadTokens: row.cacheReadTokens,\n costUsd: row.costUsd,\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(range: GovernanceRange): Promise<GovernanceUsageInput[]> {\n const { start, end } = dayBoundsUtc(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.map(toUsageInput);\n }\n\n async spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]> {\n const pricing = await this.loadPricing();\n return bucketByModel(await this.usageInRange(range), pricing);\n }\n\n async spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]> {\n const pricing = await this.loadPricing();\n return bucketByActor(await this.usageInRange(range), pricing);\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 threadIds = [...new Set(rows.map((row) => row.threadId))];\n if (threadIds.length === 0) {\n return [];\n }\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(and(inArray(agentThread.id, threadIds), isNull(agentThread.deletedAt)));\n const threadsById = new Map<string, ThreadMeta>(\n threads.map((thread) => [thread.id, { title: thread.title, actorRef: thread.actorRef }]),\n );\n return bucketByThread(rows, pricing, threadsById, { limit, includeUnknownThreads: false });\n }\n\n async usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]> {\n const pricing = await this.loadPricing();\n return bucketUsageTrend(await this.usageInRange(range), pricing);\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":["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","toUsageInput","row","modelId","actorRef","threadId","day","createdAt","toISOString","slice","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","DrizzleGovernanceQueries","db","pricingStore","loadPricing","prices","listCurrentPrices","pricing","Map","price","set","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","usageInRange","range","start","end","dayBoundsUtc","rows","select","from","agentTokenUsage","where","and","gte","lte","map","spendByModel","bucketByModel","spendByActor","bucketByActor","spendByThread","limit","threadIds","Set","length","threads","agentThread","inArray","id","isNull","deletedAt","threadsById","thread","title","bucketByThread","includeUnknownThreads","usageTrend","bucketUsageTrend","recentToolCalls","toolCallId","agentToolCall","toolName","toolType","status","agentMessage","innerJoin","eq","messageId","orderBy","desc","recentThreads","updatedAt","result","messageCountRow","value","count","usageRows","totalTokens","reduce","sum","push","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","import_nestjs_agent_core","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.js CHANGED
@@ -468,29 +468,22 @@ var DrizzleAgentStore = class {
468
468
  };
469
469
 
470
470
  // src/drizzle-governance-queries.ts
471
+ import { bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc } from "@dudousxd/nestjs-agent-core";
471
472
  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";
472
- function estimateFromTokens(pricing, row) {
473
- const price = pricing.get(row.modelId);
474
- if (price === void 0) {
475
- return 0;
476
- }
477
- const cacheWriteTokens = row.cacheWriteTokens ?? 0;
478
- const cacheReadTokens = row.cacheReadTokens ?? 0;
479
- const uncachedInputTokens = row.inputTokens - cacheWriteTokens - cacheReadTokens;
480
- return uncachedInputTokens / 1e6 * price.inputPricePer1m + cacheWriteTokens / 1e6 * (price.cacheWritePricePer1m ?? price.inputPricePer1m) + cacheReadTokens / 1e6 * (price.cacheReadPricePer1m ?? price.inputPricePer1m) + row.outputTokens / 1e6 * price.outputPricePer1m;
481
- }
482
- __name(estimateFromTokens, "estimateFromTokens");
483
- function rowCost(pricing, row) {
484
- return row.costUsd ?? estimateFromTokens(pricing, row);
485
- }
486
- __name(rowCost, "rowCost");
487
- function dayBounds(range) {
473
+ function toUsageInput(row) {
488
474
  return {
489
- start: /* @__PURE__ */ new Date(`${range.fromDay}T00:00:00.000Z`),
490
- end: /* @__PURE__ */ new Date(`${range.toDay}T23:59:59.999Z`)
475
+ modelId: row.modelId,
476
+ actorRef: row.actorRef,
477
+ threadId: row.threadId,
478
+ day: row.createdAt.toISOString().slice(0, 10),
479
+ inputTokens: row.inputTokens,
480
+ outputTokens: row.outputTokens,
481
+ cacheWriteTokens: row.cacheWriteTokens,
482
+ cacheReadTokens: row.cacheReadTokens,
483
+ costUsd: row.costUsd
491
484
  };
492
485
  }
493
- __name(dayBounds, "dayBounds");
486
+ __name(toUsageInput, "toUsageInput");
494
487
  var DrizzleGovernanceQueries = class {
495
488
  static {
496
489
  __name(this, "DrizzleGovernanceQueries");
@@ -515,69 +508,17 @@ var DrizzleGovernanceQueries = class {
515
508
  return pricing;
516
509
  }
517
510
  async usageInRange(range) {
518
- const { start, end } = dayBounds(range);
511
+ const { start, end } = dayBoundsUtc(range);
519
512
  const rows = await this.db.select().from(agentTokenUsage).where(and2(gte2(agentTokenUsage.createdAt, start), lte2(agentTokenUsage.createdAt, end)));
520
- return rows;
513
+ return rows.map(toUsageInput);
521
514
  }
522
515
  async spendByModel(range) {
523
516
  const pricing = await this.loadPricing();
524
- const rows = await this.usageInRange(range);
525
- const byModel = /* @__PURE__ */ new Map();
526
- for (const row of rows) {
527
- const bucket = byModel.get(row.modelId) ?? {
528
- requests: 0,
529
- inputTokens: 0,
530
- outputTokens: 0,
531
- costUsd: 0
532
- };
533
- bucket.requests += 1;
534
- bucket.inputTokens += row.inputTokens;
535
- bucket.outputTokens += row.outputTokens;
536
- bucket.costUsd += rowCost(pricing, row);
537
- byModel.set(row.modelId, bucket);
538
- }
539
- const result = [];
540
- for (const [modelId, bucket] of byModel) {
541
- result.push({
542
- modelId,
543
- requests: bucket.requests,
544
- inputTokens: bucket.inputTokens,
545
- outputTokens: bucket.outputTokens,
546
- costUsd: bucket.costUsd
547
- });
548
- }
549
- result.sort((left, right) => right.costUsd - left.costUsd || left.modelId.localeCompare(right.modelId));
550
- return result;
517
+ return bucketByModel(await this.usageInRange(range), pricing);
551
518
  }
552
519
  async spendByActor(range) {
553
520
  const pricing = await this.loadPricing();
554
- const rows = await this.usageInRange(range);
555
- const byActor = /* @__PURE__ */ new Map();
556
- for (const row of rows) {
557
- const bucket = byActor.get(row.actorRef) ?? {
558
- requests: 0,
559
- totalTokens: 0,
560
- costUsd: 0,
561
- threadIds: /* @__PURE__ */ new Set()
562
- };
563
- bucket.requests += 1;
564
- bucket.totalTokens += row.inputTokens + row.outputTokens;
565
- bucket.costUsd += rowCost(pricing, row);
566
- bucket.threadIds.add(row.threadId);
567
- byActor.set(row.actorRef, bucket);
568
- }
569
- const result = [];
570
- for (const [actorRef, bucket] of byActor) {
571
- result.push({
572
- actorRef,
573
- requests: bucket.requests,
574
- totalTokens: bucket.totalTokens,
575
- costUsd: bucket.costUsd,
576
- threadCount: bucket.threadIds.size
577
- });
578
- }
579
- result.sort((left, right) => right.costUsd - left.costUsd || left.actorRef.localeCompare(right.actorRef));
580
- return result;
521
+ return bucketByActor(await this.usageInRange(range), pricing);
581
522
  }
582
523
  /**
583
524
  * Top threads by spend within the range, highest cost first, capped at `limit`. Usage rows for a
@@ -587,70 +528,28 @@ var DrizzleGovernanceQueries = class {
587
528
  async spendByThread(range, limit) {
588
529
  const pricing = await this.loadPricing();
589
530
  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) {
531
+ const threadIds = [
532
+ ...new Set(rows.map((row) => row.threadId))
533
+ ];
534
+ if (threadIds.length === 0) {
603
535
  return [];
604
536
  }
605
- const threads = await this.db.select().from(agentThread).where(and2(inArray2(agentThread.id, [
606
- ...byThread.keys()
607
- ]), isNull2(agentThread.deletedAt)));
537
+ const threads = await this.db.select().from(agentThread).where(and2(inArray2(agentThread.id, threadIds), isNull2(agentThread.deletedAt)));
608
538
  const threadsById = new Map(threads.map((thread) => [
609
539
  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,
540
+ {
620
541
  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);
542
+ actorRef: thread.actorRef
543
+ }
544
+ ]));
545
+ return bucketByThread(rows, pricing, threadsById, {
546
+ limit,
547
+ includeUnknownThreads: false
548
+ });
629
549
  }
630
550
  async usageTrend(range) {
631
551
  const pricing = await this.loadPricing();
632
- const rows = await this.usageInRange(range);
633
- const byDay = /* @__PURE__ */ new Map();
634
- for (const row of rows) {
635
- const day = row.createdAt.toISOString().slice(0, 10);
636
- const bucket = byDay.get(day) ?? {
637
- totalTokens: 0,
638
- costUsd: 0
639
- };
640
- bucket.totalTokens += row.inputTokens + row.outputTokens;
641
- bucket.costUsd += rowCost(pricing, row);
642
- byDay.set(day, bucket);
643
- }
644
- const result = [];
645
- for (const [day, bucket] of byDay) {
646
- result.push({
647
- day,
648
- totalTokens: bucket.totalTokens,
649
- costUsd: bucket.costUsd
650
- });
651
- }
652
- result.sort((left, right) => left.day.localeCompare(right.day));
653
- return result;
552
+ return bucketUsageTrend(await this.usageInRange(range), pricing);
654
553
  }
655
554
  async recentToolCalls(limit) {
656
555
  const rows = await this.db.select({
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 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"]}
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 GovernanceUsageInput,\n ModelPrice,\n ModelSpendRow,\n ThreadActivityRow,\n ThreadMeta,\n ThreadSpendRow,\n ToolCallActivityRow,\n UsageTrendPoint,\n} from '@dudousxd/nestjs-agent-core';\nimport {\n bucketByActor,\n bucketByModel,\n bucketByThread,\n bucketUsageTrend,\n dayBoundsUtc,\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/** Map a Drizzle usage row onto the shared bucketer input (day derived from `createdAt`). */\nfunction toUsageInput(row: typeof agentTokenUsage.$inferSelect): GovernanceUsageInput {\n return {\n modelId: row.modelId,\n actorRef: row.actorRef,\n threadId: row.threadId,\n day: row.createdAt.toISOString().slice(0, 10),\n inputTokens: row.inputTokens,\n outputTokens: row.outputTokens,\n cacheWriteTokens: row.cacheWriteTokens,\n cacheReadTokens: row.cacheReadTokens,\n costUsd: row.costUsd,\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(range: GovernanceRange): Promise<GovernanceUsageInput[]> {\n const { start, end } = dayBoundsUtc(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.map(toUsageInput);\n }\n\n async spendByModel(range: GovernanceRange): Promise<ModelSpendRow[]> {\n const pricing = await this.loadPricing();\n return bucketByModel(await this.usageInRange(range), pricing);\n }\n\n async spendByActor(range: GovernanceRange): Promise<ActorSpendRow[]> {\n const pricing = await this.loadPricing();\n return bucketByActor(await this.usageInRange(range), pricing);\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 threadIds = [...new Set(rows.map((row) => row.threadId))];\n if (threadIds.length === 0) {\n return [];\n }\n const threads = await this.db\n .select()\n .from(agentThread)\n .where(and(inArray(agentThread.id, threadIds), isNull(agentThread.deletedAt)));\n const threadsById = new Map<string, ThreadMeta>(\n threads.map((thread) => [thread.id, { title: thread.title, actorRef: thread.actorRef }]),\n );\n return bucketByThread(rows, pricing, threadsById, { limit, includeUnknownThreads: false });\n }\n\n async usageTrend(range: GovernanceRange): Promise<UsageTrendPoint[]> {\n const pricing = await this.loadPricing();\n return bucketUsageTrend(await this.usageInRange(range), pricing);\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","bucketByActor","bucketByModel","bucketByThread","bucketUsageTrend","dayBoundsUtc","and","count","desc","eq","gte","inArray","isNull","lte","toUsageInput","row","modelId","actorRef","threadId","day","createdAt","toISOString","slice","inputTokens","outputTokens","cacheWriteTokens","cacheReadTokens","costUsd","DrizzleGovernanceQueries","db","pricingStore","loadPricing","prices","listCurrentPrices","pricing","Map","price","set","inputPricePer1m","outputPricePer1m","cacheWritePricePer1m","cacheReadPricePer1m","usageInRange","range","start","end","dayBoundsUtc","rows","select","from","agentTokenUsage","where","and","gte","lte","map","spendByModel","bucketByModel","spendByActor","bucketByActor","spendByThread","limit","threadIds","Set","length","threads","agentThread","inArray","id","isNull","deletedAt","threadsById","thread","title","bucketByThread","includeUnknownThreads","usageTrend","bucketUsageTrend","recentToolCalls","toolCallId","agentToolCall","toolName","toolType","status","agentMessage","innerJoin","eq","messageId","orderBy","desc","recentThreads","updatedAt","result","messageCountRow","value","count","usageRows","totalTokens","reduce","sum","push","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.3.1",
3
+ "version": "0.3.2",
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.3.1"
27
+ "@dudousxd/nestjs-agent-core": "0.3.2"
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.3.1"
41
+ "@dudousxd/nestjs-agent-core": "0.3.2"
42
42
  },
43
43
  "scripts": {
44
44
  "build": "tsup",