@dudousxd/nestjs-agent-store-drizzle 0.8.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
2
2
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
3
- import { MessageRole, ToolCallRequest, ToolResult, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, CreateThreadInput, ThreadSummary, ThreadDetail, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, PendingApprovalRow, ToolStatRow, GovernancePageQuery, ToolCallWhere, GovernancePage, ThreadWhere, RunWhere, ApprovalWhere, GovernanceRunDetail, GovernanceThreadDetailQuery, GovernanceThreadDetail, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
3
+ import { MessageRole, ToolCallRequest, ToolResult, MessageAttachment, MessageUsage, ToolKind, ToolCallStatus, UsagePurpose, AgentStore, ThreadTurnReader, CreateThreadInput, ThreadSummary, ThreadDetail, ThreadTurnQuery, ThreadTurnPage, UpdateThreadInput, RecordRunStartInput, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, RecordUsageInput, AgentGovernanceQueries, AgentPricingStore, GovernanceRange, ModelSpendRow, ActorSpendRow, ThreadSpendRow, UsageTrendPoint, ToolCallActivityRow, ThreadActivityRow, RunMetrics, RunAgentBreakdownRow, RunErrorBreakdownRow, RunTrendPoint, RecentRunRow, PendingApprovalRow, ToolStatRow, GovernancePageQuery, ToolCallWhere, GovernancePage, ThreadWhere, RunWhere, ApprovalWhere, GovernanceRunDetail, GovernanceThreadDetailQuery, GovernanceThreadDetail, ModelPriceInput, CurrentModelPrice } from '@dudousxd/nestjs-agent-core';
4
+ export { ThreadTurnPage, ThreadTurnQuery } from '@dudousxd/nestjs-agent-core';
5
+ import { TablesRelationalConfig } from 'drizzle-orm';
4
6
  import { Type, DynamicModule } from '@nestjs/common';
5
7
 
6
8
  /**
@@ -131,6 +133,25 @@ declare const agentThread: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
131
133
  }, {}, {
132
134
  length: number | undefined;
133
135
  }>;
136
+ defaultAgent: drizzle_orm_sqlite_core.SQLiteColumn<{
137
+ name: "default_agent";
138
+ tableName: "agent_thread";
139
+ dataType: "string";
140
+ columnType: "SQLiteText";
141
+ data: string;
142
+ driverParam: string;
143
+ notNull: false;
144
+ hasDefault: false;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: [string, ...string[]];
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {
153
+ length: number | undefined;
154
+ }>;
134
155
  createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
135
156
  name: "created_at";
136
157
  tableName: "agent_thread";
@@ -309,6 +330,25 @@ declare const agentMessage: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
309
330
  }, {}, {
310
331
  $type: ToolResult[];
311
332
  }>;
333
+ attachments: drizzle_orm_sqlite_core.SQLiteColumn<{
334
+ name: "attachments";
335
+ tableName: "agent_message";
336
+ dataType: "json";
337
+ columnType: "SQLiteTextJson";
338
+ data: MessageAttachment[];
339
+ driverParam: string;
340
+ notNull: false;
341
+ hasDefault: false;
342
+ isPrimaryKey: false;
343
+ isAutoincrement: false;
344
+ hasRuntimeDefault: false;
345
+ enumValues: undefined;
346
+ baseColumn: never;
347
+ identity: undefined;
348
+ generated: undefined;
349
+ }, {}, {
350
+ $type: MessageAttachment[];
351
+ }>;
312
352
  followUps: drizzle_orm_sqlite_core.SQLiteColumn<{
313
353
  name: "follow_ups";
314
354
  tableName: "agent_message";
@@ -366,6 +406,25 @@ declare const agentMessage: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
366
406
  }, {}, {
367
407
  length: number | undefined;
368
408
  }>;
409
+ runId: drizzle_orm_sqlite_core.SQLiteColumn<{
410
+ name: "run_id";
411
+ tableName: "agent_message";
412
+ dataType: "string";
413
+ columnType: "SQLiteText";
414
+ data: string;
415
+ driverParam: string;
416
+ notNull: false;
417
+ hasDefault: false;
418
+ isPrimaryKey: false;
419
+ isAutoincrement: false;
420
+ hasRuntimeDefault: false;
421
+ enumValues: [string, ...string[]];
422
+ baseColumn: never;
423
+ identity: undefined;
424
+ generated: undefined;
425
+ }, {}, {
426
+ length: number | undefined;
427
+ }>;
369
428
  createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
370
429
  name: "created_at";
371
430
  tableName: "agent_message";
@@ -386,7 +445,13 @@ declare const agentMessage: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
386
445
  };
387
446
  dialect: "sqlite";
388
447
  }>;
389
- /** A tool call requested during an assistant turn. The pk is the model-supplied `toolCallId`. */
448
+ /**
449
+ * A tool call requested during an assistant turn. The pk is the model-supplied `toolCallId`.
450
+ *
451
+ * `messageId` carries its own index rather than relying on the foreign key: MySQL indexes a foreign
452
+ * key column for you, Postgres does not — and every message-scoped read here filters on it (the
453
+ * thread reader's `IN (…)` over a turn's calls, and `truncateFrom`'s delete).
454
+ */
390
455
  declare const agentToolCall: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
391
456
  name: "agent_tool_call";
392
457
  schema: undefined;
@@ -1006,8 +1071,14 @@ declare const agentModelPricing: drizzle_orm_sqlite_core.SQLiteTableWithColumns<
1006
1071
  };
1007
1072
  dialect: "sqlite";
1008
1073
  }>;
1009
- /** A run's lifecycle status. Not part of the core SPI (that surfaces `string`) — internal only. */
1010
- type AgentRunStatus = 'running' | 'completed' | 'failed';
1074
+ /**
1075
+ * A run's lifecycle status. Not part of the core SPI (that surfaces `string`) — internal only.
1076
+ *
1077
+ * `cancelled` is a third TERMINAL, not a flavour of `failed`: someone asked the run to stop and it
1078
+ * did. A reliability read that folded it into `failed` would page whoever is on call for model
1079
+ * failures every time a user pressed Stop.
1080
+ */
1081
+ type AgentRunStatus = 'running' | 'completed' | 'failed' | 'cancelled';
1011
1082
  /**
1012
1083
  * One recorded run (turn) outcome — the durable half of what `aviary:agent:*` diagnostics report
1013
1084
  * ephemerally. Written by {@link import('./drizzle-agent-store.js').DrizzleAgentStore.recordRunStart}/
@@ -1241,6 +1312,25 @@ declare const agentRun: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
1241
1312
  }, {}, {
1242
1313
  length: number | undefined;
1243
1314
  }>;
1315
+ parentRunId: drizzle_orm_sqlite_core.SQLiteColumn<{
1316
+ name: "parent_run_id";
1317
+ tableName: "agent_run";
1318
+ dataType: "string";
1319
+ columnType: "SQLiteText";
1320
+ data: string;
1321
+ driverParam: string;
1322
+ notNull: false;
1323
+ hasDefault: false;
1324
+ isPrimaryKey: false;
1325
+ isAutoincrement: false;
1326
+ hasRuntimeDefault: false;
1327
+ enumValues: [string, ...string[]];
1328
+ baseColumn: never;
1329
+ identity: undefined;
1330
+ generated: undefined;
1331
+ }, {}, {
1332
+ length: number | undefined;
1333
+ }>;
1244
1334
  };
1245
1335
  dialect: "sqlite";
1246
1336
  }>;
@@ -1362,6 +1452,25 @@ declare const agentSchema: {
1362
1452
  }, {}, {
1363
1453
  length: number | undefined;
1364
1454
  }>;
1455
+ defaultAgent: drizzle_orm_sqlite_core.SQLiteColumn<{
1456
+ name: "default_agent";
1457
+ tableName: "agent_thread";
1458
+ dataType: "string";
1459
+ columnType: "SQLiteText";
1460
+ data: string;
1461
+ driverParam: string;
1462
+ notNull: false;
1463
+ hasDefault: false;
1464
+ isPrimaryKey: false;
1465
+ isAutoincrement: false;
1466
+ hasRuntimeDefault: false;
1467
+ enumValues: [string, ...string[]];
1468
+ baseColumn: never;
1469
+ identity: undefined;
1470
+ generated: undefined;
1471
+ }, {}, {
1472
+ length: number | undefined;
1473
+ }>;
1365
1474
  createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
1366
1475
  name: "created_at";
1367
1476
  tableName: "agent_thread";
@@ -1535,6 +1644,25 @@ declare const agentSchema: {
1535
1644
  }, {}, {
1536
1645
  $type: ToolResult[];
1537
1646
  }>;
1647
+ attachments: drizzle_orm_sqlite_core.SQLiteColumn<{
1648
+ name: "attachments";
1649
+ tableName: "agent_message";
1650
+ dataType: "json";
1651
+ columnType: "SQLiteTextJson";
1652
+ data: MessageAttachment[];
1653
+ driverParam: string;
1654
+ notNull: false;
1655
+ hasDefault: false;
1656
+ isPrimaryKey: false;
1657
+ isAutoincrement: false;
1658
+ hasRuntimeDefault: false;
1659
+ enumValues: undefined;
1660
+ baseColumn: never;
1661
+ identity: undefined;
1662
+ generated: undefined;
1663
+ }, {}, {
1664
+ $type: MessageAttachment[];
1665
+ }>;
1538
1666
  followUps: drizzle_orm_sqlite_core.SQLiteColumn<{
1539
1667
  name: "follow_ups";
1540
1668
  tableName: "agent_message";
@@ -1592,6 +1720,25 @@ declare const agentSchema: {
1592
1720
  }, {}, {
1593
1721
  length: number | undefined;
1594
1722
  }>;
1723
+ runId: drizzle_orm_sqlite_core.SQLiteColumn<{
1724
+ name: "run_id";
1725
+ tableName: "agent_message";
1726
+ dataType: "string";
1727
+ columnType: "SQLiteText";
1728
+ data: string;
1729
+ driverParam: string;
1730
+ notNull: false;
1731
+ hasDefault: false;
1732
+ isPrimaryKey: false;
1733
+ isAutoincrement: false;
1734
+ hasRuntimeDefault: false;
1735
+ enumValues: [string, ...string[]];
1736
+ baseColumn: never;
1737
+ identity: undefined;
1738
+ generated: undefined;
1739
+ }, {}, {
1740
+ length: number | undefined;
1741
+ }>;
1595
1742
  createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
1596
1743
  name: "created_at";
1597
1744
  tableName: "agent_message";
@@ -2454,6 +2601,25 @@ declare const agentSchema: {
2454
2601
  }, {}, {
2455
2602
  length: number | undefined;
2456
2603
  }>;
2604
+ parentRunId: drizzle_orm_sqlite_core.SQLiteColumn<{
2605
+ name: "parent_run_id";
2606
+ tableName: "agent_run";
2607
+ dataType: "string";
2608
+ columnType: "SQLiteText";
2609
+ data: string;
2610
+ driverParam: string;
2611
+ notNull: false;
2612
+ hasDefault: false;
2613
+ isPrimaryKey: false;
2614
+ isAutoincrement: false;
2615
+ hasRuntimeDefault: false;
2616
+ enumValues: [string, ...string[]];
2617
+ baseColumn: never;
2618
+ identity: undefined;
2619
+ generated: undefined;
2620
+ }, {}, {
2621
+ length: number | undefined;
2622
+ }>;
2457
2623
  };
2458
2624
  dialect: "sqlite";
2459
2625
  }>;
@@ -2463,7 +2629,7 @@ declare const agentSchema: {
2463
2629
  * driver (better-sqlite3, libsql, D1, …) in either sync or async result mode; the host app owns
2464
2630
  * the connection and passes the `drizzle(...)` instance in.
2465
2631
  */
2466
- type AgentDrizzleDb = BaseSQLiteDatabase<'sync' | 'async', unknown>;
2632
+ type AgentDrizzleDb = BaseSQLiteDatabase<'sync' | 'async', unknown, Record<string, unknown>, TablesRelationalConfig>;
2467
2633
  /** A persisted thread row as Drizzle selects it. */
2468
2634
  type AgentThreadRow = typeof agentThread.$inferSelect;
2469
2635
  /** A persisted message row as Drizzle selects it. */
@@ -2471,7 +2637,10 @@ type AgentMessageRow = typeof agentMessage.$inferSelect;
2471
2637
  /** A persisted run row as Drizzle selects it. */
2472
2638
  type AgentRunRow = typeof agentRun.$inferSelect;
2473
2639
 
2474
- /** Runs the `CREATE TABLE IF NOT EXISTS` DDL above against the supplied Drizzle SQLite db. */
2640
+ /**
2641
+ * Runs the `CREATE TABLE IF NOT EXISTS` DDL above against the supplied Drizzle SQLite db, then adds
2642
+ * any column missing from a table that already existed.
2643
+ */
2475
2644
  declare function ensureAgentSchema(db: AgentDrizzleDb): Promise<void>;
2476
2645
 
2477
2646
  /**
@@ -2480,11 +2649,30 @@ declare function ensureAgentSchema(db: AgentDrizzleDb): Promise<void>;
2480
2649
  * owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}
2481
2650
  * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.
2482
2651
  */
2483
- declare class DrizzleAgentStore implements AgentStore {
2652
+ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader {
2484
2653
  private readonly db;
2485
2654
  constructor(db: AgentDrizzleDb);
2486
2655
  createThread(input: CreateThreadInput): Promise<ThreadSummary>;
2487
2656
  getThread(threadId: string): Promise<ThreadDetail | null>;
2657
+ /**
2658
+ * The window a turn reads off a thread: its newest `messageLimit` messages (oldest first), the
2659
+ * title, the default agent, and whether the thread has EVER been answered.
2660
+ *
2661
+ * {@link getThread} is the wrong read for a turn. It materializes the transcript — every message,
2662
+ * every attachment, every tool output the thread ever recorded — and the run then journals what it
2663
+ * loaded, so a long thread pays for its whole history on every turn and again on every replay.
2664
+ *
2665
+ * `hasAssistantMessage` is answered over the WHOLE thread, not the returned page: it answers "has
2666
+ * this conversation been answered before?", and a thread whose window happens to hold only the
2667
+ * user's last questions has still been answered. `null` when the thread is unknown or
2668
+ * soft-deleted, same as {@link getThread}.
2669
+ */
2670
+ loadThreadForTurn(query: ThreadTurnQuery): Promise<ThreadTurnPage | null>;
2671
+ /**
2672
+ * The newest `limit` messages of a thread, oldest first, projected to the columns a model turn
2673
+ * reads. Read newest-first so the LIMIT is the database's job, then reversed for the prompt.
2674
+ */
2675
+ private loadTurnWindow;
2488
2676
  listThreads(actorRef: string, limit?: number): Promise<ThreadSummary[]>;
2489
2677
  softDeleteThread(threadId: string): Promise<void>;
2490
2678
  forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary>;
@@ -2495,18 +2683,30 @@ declare class DrizzleAgentStore implements AgentStore {
2495
2683
  setTitle(threadId: string, title: string): Promise<void>;
2496
2684
  promoteThread(threadId: string): Promise<void>;
2497
2685
  setActiveStream(threadId: string, runId: string | null): Promise<void>;
2498
- /** Persist the start of a run (turn). Replay-safe: called under a durable localStep. */
2499
- recordRunStart(run: {
2500
- runId: string;
2501
- threadId: string;
2502
- actorRef: string;
2503
- agentName?: string;
2504
- promptHash?: string;
2505
- }): Promise<void>;
2686
+ /**
2687
+ * Patch a thread's `title` and/or `defaultAgent`. Each field is only touched when PRESENT in
2688
+ * `patch` — `defaultAgent: null` clears it (falls back to the app default), while an omitted
2689
+ * `defaultAgent` leaves whatever is stored untouched. A no-op (including `updatedAt`) when the
2690
+ * patch is empty or the thread doesn't exist.
2691
+ */
2692
+ updateThread(threadId: string, patch: UpdateThreadInput): Promise<void>;
2693
+ /**
2694
+ * The thread's default agent, projected — the caller wants one nullable scalar to decide which
2695
+ * agent answers the next turn, and {@link getThread} would materialize the whole transcript to
2696
+ * hand it over. `null` when the thread is unknown, soft-deleted, or has no default set.
2697
+ */
2698
+ defaultAgentForThread(threadId: string): Promise<string | null>;
2699
+ /**
2700
+ * Persist the start of a run (turn). Replay-safe: called under a durable localStep.
2701
+ *
2702
+ * Takes the SPI's own {@link RecordRunStartInput} rather than a hand-copied shape: a field added
2703
+ * to the input is otherwise accepted and dropped, silently, by every adapter that re-declares it.
2704
+ */
2705
+ recordRunStart(run: RecordRunStartInput): Promise<void>;
2506
2706
  /** Settle a run's outcome. A no-op when the run is unknown (mirrors `setTitle`/`updateThread`). */
2507
2707
  recordRunEnd(end: {
2508
2708
  runId: string;
2509
- status: 'completed' | 'failed';
2709
+ status: 'completed' | 'failed' | 'cancelled';
2510
2710
  durationMs?: number;
2511
2711
  errorCode?: string;
2512
2712
  errorMessage?: string;
@@ -2514,9 +2714,24 @@ declare class DrizzleAgentStore implements AgentStore {
2514
2714
  /** Bump the run's llm-step retry counter. Atomic `retries = retries + 1`, no read-modify-write. */
2515
2715
  bumpRunRetries(runId: string): Promise<void>;
2516
2716
  appendMessage(input: AppendMessageInput): Promise<StoredMessage>;
2717
+ setMessageToolResults(messageId: string, results: ToolResult[]): Promise<void>;
2517
2718
  truncateFrom(threadId: string, messageId: string): Promise<void>;
2518
2719
  recordToolCall(input: RecordToolCallInput): Promise<void>;
2519
2720
  updateToolCall(input: UpdateToolCallInput): Promise<void>;
2721
+ /**
2722
+ * Of `mediaIds`, the ones a surviving message in one of this actor's threads still carries.
2723
+ *
2724
+ * Reads the `attachments` JSON back out and matches in memory rather than pushing the match into
2725
+ * SQL: the column holds an array of objects, and every dialect this adapter's sibling targets
2726
+ * spells that query differently (`jsonb` containment, `json_table`, `json_each`), while none of
2727
+ * them can use an index for it anyway. The scan is bounded by ONE actor's attachment-bearing
2728
+ * messages, which is a small set — attachments are rare, and a message without one is excluded
2729
+ * by the `is not null` before any JSON is parsed.
2730
+ *
2731
+ * Soft-deleted threads are deliberately included: their message rows survive, so the bytes they
2732
+ * point at are still reachable from stored state and are not garbage.
2733
+ */
2734
+ referencedMediaIds(actorRef: string, mediaIds: readonly string[]): Promise<string[]>;
2520
2735
  recordUsage(input: RecordUsageInput): Promise<void>;
2521
2736
  quotaToday(actorRef: string, day: string): Promise<{
2522
2737
  usedTokens: number;