@dudousxd/nestjs-agent-store-drizzle 0.32.0 → 0.33.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.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
2
- import { MessageRole, ToolCallRequest, ToolResult, MessageAttachment, MessageUsage, AgentUiComponent, MessageFeedback, AgentHostContext, Actor, PageContext, QueuePause, ActionProposal, GenuiValidity, GenuiErrorCategory, CostSource, ToolKind, ToolCallStatus, ToolConfirmation, UsagePurpose, AgentStore, ThreadTurnReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore, ActionProposalStoreOptions, ActionProposalSupersessionStore, CreateThreadInput, ThreadSummary, ThreadDetail, ThreadTurnQuery, ThreadTurnPage, ToolCallApprovalState, EnqueueMessageInput, QueuedMessage, QueuedMessagePatch, UpdateThreadInput, RecordRunStartInput, RecordRunEndInput, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, ToolCallOutcome, RecordUsageInput, RecordGenuiCallInput, UsageTotals, CreateActionProposal, CreateActionProposalResult, ActionProposalScope, ActionProposalMutationResult, ListActionProposals, ActionProposalDecisionCommand, ClaimActionProposal, ExtendActionProposalLease, SettleActionProposal, ActionProposalOutcomeLease, 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, GenuiStats, MemoryProvider, ListMemoriesInput, MemoryRecord, ForgetMemoryInput, StoreMemoryInput, ModelPriceInput, CurrentModelPrice, StreamFrameTable, StreamFrameRow, SqlTokenStreamSink, SqlTokenStreamSinkOptions, ConfirmTokenStore, ConfirmTokenClaim, ChannelStore, PoppyStore, PoppyConversationRecord, PoppyConversationPatch, PoppyEventBody, StoredPoppyEvent, PoppyMessageReceipt, PoppyMessageClaim, PoppyConnectionStore, PoppyConnectionRecord, PoppyPendingConnect } from '@dudousxd/nestjs-agent-core';
2
+ import { MessageRole, ToolCallRequest, ToolResult, MessageAttachment, MessageUsage, AgentUiComponent, MessageFeedback, AgentHostContext, Actor, PageContext, QueuePause, ActionProposal, GenuiValidity, GenuiErrorCategory, CostSource, ToolKind, ToolCallStatus, ToolConfirmation, UsagePurpose, AgentStore, ThreadTurnReader, ThreadSettingsReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore, ActionProposalStoreOptions, ActionProposalSupersessionStore, CreateThreadInput, ThreadSummary, ThreadDetail, ThreadTurnQuery, ThreadTurnPage, ToolCallApprovalState, EnqueueMessageInput, QueuedMessage, QueuedMessagePatch, UpdateThreadInput, ThreadSettings, RecordRunStartInput, RecordRunEndInput, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, ToolCallOutcome, RecordUsageInput, RecordGenuiCallInput, UsageTotals, CreateActionProposal, CreateActionProposalResult, ActionProposalScope, ActionProposalMutationResult, ListActionProposals, ActionProposalDecisionCommand, ClaimActionProposal, ExtendActionProposalLease, SettleActionProposal, ActionProposalOutcomeLease, 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, GenuiStats, MemoryProvider, ListMemoriesInput, MemoryRecord, ForgetMemoryInput, StoreMemoryInput, ModelPriceInput, CurrentModelPrice, StreamFrameTable, StreamFrameRow, SqlTokenStreamSink, SqlTokenStreamSinkOptions, ConfirmTokenStore, ConfirmTokenClaim, ChannelStore, PoppyStore, PoppyConversationRecord, PoppyConversationPatch, PoppyEventBody, StoredPoppyEvent, PoppyMessageReceipt, PoppyMessageClaim, PoppyConnectionStore, PoppyConnectionRecord, PoppyPendingConnect } from '@dudousxd/nestjs-agent-core';
3
3
  export { ThreadTurnPage, ThreadTurnQuery } from '@dudousxd/nestjs-agent-core';
4
4
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
5
5
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
@@ -9173,7 +9173,7 @@ declare function agentSchemaDdl(dialect: AgentDialect): string[];
9173
9173
  * MySQL (the host app owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}
9174
9174
  * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.
9175
9175
  */
9176
- declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore {
9176
+ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ThreadSettingsReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore {
9177
9177
  private readonly db;
9178
9178
  private readonly dialect;
9179
9179
  private readonly t;
@@ -9233,6 +9233,12 @@ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQue
9233
9233
  */
9234
9234
  private loadTurnWindow;
9235
9235
  listThreads(actorRef: string, limit?: number): Promise<ThreadSummary[]>;
9236
+ /**
9237
+ * The content of each thread's newest message ({@link messageOrderNewestFirst}), in a fixed two
9238
+ * reads for any number of threads: each thread's highest `seq`, then the rows holding it. Only a
9239
+ * thread whose every message predates `seq` is read on its own, by `created_at`.
9240
+ */
9241
+ private lastMessageContents;
9236
9242
  softDeleteThread(threadId: string): Promise<void>;
9237
9243
  forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary>;
9238
9244
  ownerOfThread(threadId: string): Promise<string | null>;
@@ -9304,6 +9310,7 @@ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQue
9304
9310
  modelForThread(threadId: string): Promise<string | null>;
9305
9311
  /** The thread's pinned persona, projected like {@link defaultAgentForThread}. */
9306
9312
  personaForThread(threadId: string): Promise<string | null>;
9313
+ threadSettings(threadId: string): Promise<ThreadSettings | null>;
9307
9314
  defaultAgentForThread(threadId: string): Promise<string | null>;
9308
9315
  /**
9309
9316
  * Persist the start of a run (turn). Replay-safe: called under a durable localStep.
@@ -9349,6 +9356,15 @@ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQue
9349
9356
  recordGenuiCalls(rows: readonly RecordGenuiCallInput[]): Promise<void>;
9350
9357
  quotaToday(actorRef: string, day: string): Promise<UsageTotals>;
9351
9358
  usageBetween(actorRef: string, fromDay: string, toDay: string): Promise<UsageTotals>;
9359
+ /**
9360
+ * Every range summed by the database in one statement, each as a conditional aggregate over the
9361
+ * rows of the smallest span covering them all — the actor's `(actor_ref, created_at)` index serves
9362
+ * it, and no usage row crosses the wire.
9363
+ */
9364
+ usageWindows(actorRef: string, ranges: readonly {
9365
+ fromDay: string;
9366
+ toDay: string;
9367
+ }[]): Promise<UsageTotals[]>;
9352
9368
  private toSummary;
9353
9369
  private toStoredMessage;
9354
9370
  }
@@ -9450,6 +9466,7 @@ declare class DrizzleGovernanceQueries implements AgentGovernanceQueries {
9450
9466
  /** Decorate an ordered thread list with its batched rollups, preserving the incoming order. */
9451
9467
  private toThreadActivityRows;
9452
9468
  recentThreads(limit: number): Promise<ThreadActivityRow[]>;
9469
+ /** The range's runs, with only the columns the rollups read. */
9453
9470
  private runsInRange;
9454
9471
  runMetrics(range: GovernanceRange): Promise<RunMetrics>;
9455
9472
  runsByAgent(range: GovernanceRange): Promise<RunAgentBreakdownRow[]>;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _dudousxd_nestjs_agent_core from '@dudousxd/nestjs-agent-core';
2
- import { MessageRole, ToolCallRequest, ToolResult, MessageAttachment, MessageUsage, AgentUiComponent, MessageFeedback, AgentHostContext, Actor, PageContext, QueuePause, ActionProposal, GenuiValidity, GenuiErrorCategory, CostSource, ToolKind, ToolCallStatus, ToolConfirmation, UsagePurpose, AgentStore, ThreadTurnReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore, ActionProposalStoreOptions, ActionProposalSupersessionStore, CreateThreadInput, ThreadSummary, ThreadDetail, ThreadTurnQuery, ThreadTurnPage, ToolCallApprovalState, EnqueueMessageInput, QueuedMessage, QueuedMessagePatch, UpdateThreadInput, RecordRunStartInput, RecordRunEndInput, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, ToolCallOutcome, RecordUsageInput, RecordGenuiCallInput, UsageTotals, CreateActionProposal, CreateActionProposalResult, ActionProposalScope, ActionProposalMutationResult, ListActionProposals, ActionProposalDecisionCommand, ClaimActionProposal, ExtendActionProposalLease, SettleActionProposal, ActionProposalOutcomeLease, 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, GenuiStats, MemoryProvider, ListMemoriesInput, MemoryRecord, ForgetMemoryInput, StoreMemoryInput, ModelPriceInput, CurrentModelPrice, StreamFrameTable, StreamFrameRow, SqlTokenStreamSink, SqlTokenStreamSinkOptions, ConfirmTokenStore, ConfirmTokenClaim, ChannelStore, PoppyStore, PoppyConversationRecord, PoppyConversationPatch, PoppyEventBody, StoredPoppyEvent, PoppyMessageReceipt, PoppyMessageClaim, PoppyConnectionStore, PoppyConnectionRecord, PoppyPendingConnect } from '@dudousxd/nestjs-agent-core';
2
+ import { MessageRole, ToolCallRequest, ToolResult, MessageAttachment, MessageUsage, AgentUiComponent, MessageFeedback, AgentHostContext, Actor, PageContext, QueuePause, ActionProposal, GenuiValidity, GenuiErrorCategory, CostSource, ToolKind, ToolCallStatus, ToolConfirmation, UsagePurpose, AgentStore, ThreadTurnReader, ThreadSettingsReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore, ActionProposalStoreOptions, ActionProposalSupersessionStore, CreateThreadInput, ThreadSummary, ThreadDetail, ThreadTurnQuery, ThreadTurnPage, ToolCallApprovalState, EnqueueMessageInput, QueuedMessage, QueuedMessagePatch, UpdateThreadInput, ThreadSettings, RecordRunStartInput, RecordRunEndInput, AppendMessageInput, StoredMessage, RecordToolCallInput, UpdateToolCallInput, ToolCallOutcome, RecordUsageInput, RecordGenuiCallInput, UsageTotals, CreateActionProposal, CreateActionProposalResult, ActionProposalScope, ActionProposalMutationResult, ListActionProposals, ActionProposalDecisionCommand, ClaimActionProposal, ExtendActionProposalLease, SettleActionProposal, ActionProposalOutcomeLease, 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, GenuiStats, MemoryProvider, ListMemoriesInput, MemoryRecord, ForgetMemoryInput, StoreMemoryInput, ModelPriceInput, CurrentModelPrice, StreamFrameTable, StreamFrameRow, SqlTokenStreamSink, SqlTokenStreamSinkOptions, ConfirmTokenStore, ConfirmTokenClaim, ChannelStore, PoppyStore, PoppyConversationRecord, PoppyConversationPatch, PoppyEventBody, StoredPoppyEvent, PoppyMessageReceipt, PoppyMessageClaim, PoppyConnectionStore, PoppyConnectionRecord, PoppyPendingConnect } from '@dudousxd/nestjs-agent-core';
3
3
  export { ThreadTurnPage, ThreadTurnQuery } from '@dudousxd/nestjs-agent-core';
4
4
  import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
5
5
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
@@ -9173,7 +9173,7 @@ declare function agentSchemaDdl(dialect: AgentDialect): string[];
9173
9173
  * MySQL (the host app owns the connection). Behaviour mirrors {@link import('@dudousxd/nestjs-agent-store-mikro-orm')}
9174
9174
  * exactly (fork/truncate/quota/active-stream/soft-delete semantics) so the two are interchangeable.
9175
9175
  */
9176
- declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore {
9176
+ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ThreadSettingsReader, ChatQueueStore, ActionProposalStore, ActionProposalWorkerStore, ActionProposalDiscoveryIndexStore, ActionProposalOutcomeStore {
9177
9177
  private readonly db;
9178
9178
  private readonly dialect;
9179
9179
  private readonly t;
@@ -9233,6 +9233,12 @@ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQue
9233
9233
  */
9234
9234
  private loadTurnWindow;
9235
9235
  listThreads(actorRef: string, limit?: number): Promise<ThreadSummary[]>;
9236
+ /**
9237
+ * The content of each thread's newest message ({@link messageOrderNewestFirst}), in a fixed two
9238
+ * reads for any number of threads: each thread's highest `seq`, then the rows holding it. Only a
9239
+ * thread whose every message predates `seq` is read on its own, by `created_at`.
9240
+ */
9241
+ private lastMessageContents;
9236
9242
  softDeleteThread(threadId: string): Promise<void>;
9237
9243
  forkThread(threadId: string, fromMessageId: string): Promise<ThreadSummary>;
9238
9244
  ownerOfThread(threadId: string): Promise<string | null>;
@@ -9304,6 +9310,7 @@ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQue
9304
9310
  modelForThread(threadId: string): Promise<string | null>;
9305
9311
  /** The thread's pinned persona, projected like {@link defaultAgentForThread}. */
9306
9312
  personaForThread(threadId: string): Promise<string | null>;
9313
+ threadSettings(threadId: string): Promise<ThreadSettings | null>;
9307
9314
  defaultAgentForThread(threadId: string): Promise<string | null>;
9308
9315
  /**
9309
9316
  * Persist the start of a run (turn). Replay-safe: called under a durable localStep.
@@ -9349,6 +9356,15 @@ declare class DrizzleAgentStore implements AgentStore, ThreadTurnReader, ChatQue
9349
9356
  recordGenuiCalls(rows: readonly RecordGenuiCallInput[]): Promise<void>;
9350
9357
  quotaToday(actorRef: string, day: string): Promise<UsageTotals>;
9351
9358
  usageBetween(actorRef: string, fromDay: string, toDay: string): Promise<UsageTotals>;
9359
+ /**
9360
+ * Every range summed by the database in one statement, each as a conditional aggregate over the
9361
+ * rows of the smallest span covering them all — the actor's `(actor_ref, created_at)` index serves
9362
+ * it, and no usage row crosses the wire.
9363
+ */
9364
+ usageWindows(actorRef: string, ranges: readonly {
9365
+ fromDay: string;
9366
+ toDay: string;
9367
+ }[]): Promise<UsageTotals[]>;
9352
9368
  private toSummary;
9353
9369
  private toStoredMessage;
9354
9370
  }
@@ -9450,6 +9466,7 @@ declare class DrizzleGovernanceQueries implements AgentGovernanceQueries {
9450
9466
  /** Decorate an ordered thread list with its batched rollups, preserving the incoming order. */
9451
9467
  private toThreadActivityRows;
9452
9468
  recentThreads(limit: number): Promise<ThreadActivityRow[]>;
9469
+ /** The range's runs, with only the columns the rollups read. */
9453
9470
  private runsInRange;
9454
9471
  runMetrics(range: GovernanceRange): Promise<RunMetrics>;
9455
9472
  runsByAgent(range: GovernanceRange): Promise<RunAgentBreakdownRow[]>;
package/dist/index.js CHANGED
@@ -32,7 +32,9 @@ var agentThread = sqliteTable("agent_thread", {
32
32
  mode: "timestamp_ms"
33
33
  })
34
34
  }, (table) => [
35
- index("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
35
+ index("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
36
+ // `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
37
+ index("agent_thread_active_stream_idx").on(table.activeStreamId)
36
38
  ]);
37
39
  var agentMessage = sqliteTable("agent_message", {
38
40
  id: text("id").primaryKey(),
@@ -82,7 +84,9 @@ var agentMessage = sqliteTable("agent_message", {
82
84
  mode: "timestamp_ms"
83
85
  }).notNull()
84
86
  }, (table) => [
85
- index("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
87
+ index("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
88
+ // Transcript reads order a thread's messages by `seq`.
89
+ index("agent_message_thread_seq_idx").on(table.threadId, table.seq)
86
90
  ]);
87
91
  var agentToolCall = sqliteTable("agent_tool_call", {
88
92
  proposalId: text("proposal_id"),
@@ -127,7 +131,11 @@ var agentToolCall = sqliteTable("agent_tool_call", {
127
131
  /** The surface the decision came through (`web`, `slack`, `remembered`, …). */
128
132
  decidedVia: text("decided_via")
129
133
  }, (table) => [
130
- index("agent_tool_call_message_idx").on(table.messageId)
134
+ index("agent_tool_call_message_idx").on(table.messageId),
135
+ // The approvals inbox: `pending_approval`, oldest first.
136
+ index("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
137
+ index("agent_tool_call_run_idx").on(table.runId),
138
+ index("agent_tool_call_created_idx").on(table.createdAt)
131
139
  ]);
132
140
  var agentQueuedMessage = sqliteTable("agent_queued_message", {
133
141
  uiCapabilities: text("ui_capabilities", {
@@ -191,7 +199,9 @@ var agentTokenUsage = sqliteTable("agent_token_usage", {
191
199
  mode: "timestamp_ms"
192
200
  }).notNull()
193
201
  }, (table) => [
194
- index("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
202
+ index("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
203
+ index("agent_token_usage_created_idx").on(table.createdAt),
204
+ index("agent_token_usage_thread_idx").on(table.threadId)
195
205
  ]);
196
206
  var agentGenuiCall = sqliteTable("agent_genui_call", {
197
207
  id: text("id").primaryKey(),
@@ -534,7 +544,9 @@ var agentThread2 = mysqlTable("agent_thread", {
534
544
  updatedAt: ts("updated_at").notNull(),
535
545
  deletedAt: ts("deleted_at")
536
546
  }, (table) => [
537
- index2("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
547
+ index2("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
548
+ // `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
549
+ index2("agent_thread_active_stream_idx").on(table.activeStreamId)
538
550
  ]);
539
551
  var agentMessage2 = mysqlTable("agent_message", {
540
552
  id: key("id").primaryKey(),
@@ -560,7 +572,9 @@ var agentMessage2 = mysqlTable("agent_message", {
560
572
  seq: int("seq"),
561
573
  createdAt: ts("created_at").notNull()
562
574
  }, (table) => [
563
- index2("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
575
+ index2("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
576
+ // Transcript reads order a thread's messages by `seq`.
577
+ index2("agent_message_thread_seq_idx").on(table.threadId, table.seq)
564
578
  ]);
565
579
  var agentToolCall2 = mysqlTable("agent_tool_call", {
566
580
  proposalId: key("proposal_id"),
@@ -585,7 +599,11 @@ var agentToolCall2 = mysqlTable("agent_tool_call", {
585
599
  remember: boolean("remember"),
586
600
  decidedVia: key("decided_via")
587
601
  }, (table) => [
588
- index2("agent_tool_call_message_idx").on(table.messageId)
602
+ index2("agent_tool_call_message_idx").on(table.messageId),
603
+ // The approvals inbox: `pending_approval`, oldest first.
604
+ index2("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
605
+ index2("agent_tool_call_run_idx").on(table.runId),
606
+ index2("agent_tool_call_created_idx").on(table.createdAt)
589
607
  ]);
590
608
  var agentQueuedMessage2 = mysqlTable("agent_queued_message", {
591
609
  uiCapabilities: json("ui_capabilities").$type(),
@@ -627,7 +645,9 @@ var agentTokenUsage2 = mysqlTable("agent_token_usage", {
627
645
  costSource: key("cost_source").$type(),
628
646
  createdAt: ts("created_at").notNull()
629
647
  }, (table) => [
630
- index2("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
648
+ index2("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
649
+ index2("agent_token_usage_created_idx").on(table.createdAt),
650
+ index2("agent_token_usage_thread_idx").on(table.threadId)
631
651
  ]);
632
652
  var agentGenuiCall2 = mysqlTable("agent_genui_call", {
633
653
  id: key("id").primaryKey(),
@@ -986,7 +1006,9 @@ var agentThread3 = pgTable("agent_thread", {
986
1006
  updatedAt: ts2("updated_at").notNull(),
987
1007
  deletedAt: ts2("deleted_at")
988
1008
  }, (table) => [
989
- index3("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt)
1009
+ index3("agent_thread_actor_updated_idx").on(table.actorRef, table.updatedAt),
1010
+ // `ownerOfActiveStream` reads by run id on every stream attach and reconnect.
1011
+ index3("agent_thread_active_stream_idx").on(table.activeStreamId)
990
1012
  ]);
991
1013
  var agentMessage3 = pgTable("agent_message", {
992
1014
  id: text2("id").primaryKey(),
@@ -1012,7 +1034,9 @@ var agentMessage3 = pgTable("agent_message", {
1012
1034
  seq: integer2("seq"),
1013
1035
  createdAt: ts2("created_at").notNull()
1014
1036
  }, (table) => [
1015
- index3("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
1037
+ index3("agent_message_thread_created_idx").on(table.threadId, table.createdAt),
1038
+ // Transcript reads order a thread's messages by `seq`.
1039
+ index3("agent_message_thread_seq_idx").on(table.threadId, table.seq)
1016
1040
  ]);
1017
1041
  var agentToolCall3 = pgTable("agent_tool_call", {
1018
1042
  proposalId: text2("proposal_id"),
@@ -1037,7 +1061,11 @@ var agentToolCall3 = pgTable("agent_tool_call", {
1037
1061
  remember: boolean2("remember"),
1038
1062
  decidedVia: text2("decided_via")
1039
1063
  }, (table) => [
1040
- index3("agent_tool_call_message_idx").on(table.messageId)
1064
+ index3("agent_tool_call_message_idx").on(table.messageId),
1065
+ // The approvals inbox: `pending_approval`, oldest first.
1066
+ index3("agent_tool_call_status_created_idx").on(table.status, table.createdAt),
1067
+ index3("agent_tool_call_run_idx").on(table.runId),
1068
+ index3("agent_tool_call_created_idx").on(table.createdAt)
1041
1069
  ]);
1042
1070
  var agentQueuedMessage3 = pgTable("agent_queued_message", {
1043
1071
  uiCapabilities: jsonb("ui_capabilities").$type(),
@@ -1079,7 +1107,9 @@ var agentTokenUsage3 = pgTable("agent_token_usage", {
1079
1107
  costSource: text2("cost_source").$type(),
1080
1108
  createdAt: ts2("created_at").notNull()
1081
1109
  }, (table) => [
1082
- index3("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt)
1110
+ index3("agent_token_usage_actor_created_idx").on(table.actorRef, table.createdAt),
1111
+ index3("agent_token_usage_created_idx").on(table.createdAt),
1112
+ index3("agent_token_usage_thread_idx").on(table.threadId)
1083
1113
  ]);
1084
1114
  var agentGenuiCall3 = pgTable("agent_genui_call", {
1085
1115
  id: text2("id").primaryKey(),
@@ -2358,12 +2388,49 @@ var DrizzleAgentStore = class {
2358
2388
  }
2359
2389
  async listThreads(actorRef, limit = 50) {
2360
2390
  const threads = await this.db.select().from(this.t.agentThread).where(and2(eq2(this.t.agentThread.actorRef, actorRef), eq2(this.t.agentThread.transient, false), isNull2(this.t.agentThread.deletedAt))).orderBy(desc(this.t.agentThread.updatedAt)).limit(limit);
2361
- const summaries = [];
2362
- for (const thread of threads) {
2363
- const [last] = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, thread.id)).orderBy(...this.messageOrderNewestFirst()).limit(1);
2364
- summaries.push(this.toSummary(thread, last?.content));
2391
+ const previews = await this.lastMessageContents(threads.map((thread) => thread.id));
2392
+ return threads.map((thread) => this.toSummary(thread, previews.get(thread.id)));
2393
+ }
2394
+ /**
2395
+ * The content of each thread's newest message ({@link messageOrderNewestFirst}), in a fixed two
2396
+ * reads for any number of threads: each thread's highest `seq`, then the rows holding it. Only a
2397
+ * thread whose every message predates `seq` is read on its own, by `created_at`.
2398
+ */
2399
+ async lastMessageContents(threadIds) {
2400
+ const contents = /* @__PURE__ */ new Map();
2401
+ if (threadIds.length === 0) {
2402
+ return contents;
2403
+ }
2404
+ const message = this.t.agentMessage;
2405
+ const highest = await this.db.select({
2406
+ threadId: message.threadId,
2407
+ seq: max2(message.seq)
2408
+ }).from(message).where(inArray(message.threadId, [
2409
+ ...threadIds
2410
+ ])).groupBy(message.threadId);
2411
+ const numbered = highest.filter((row) => row.seq !== null);
2412
+ if (numbered.length > 0) {
2413
+ const rows = await this.db.select({
2414
+ threadId: message.threadId,
2415
+ content: message.content
2416
+ }).from(message).where(or2(...numbered.map((row) => and2(eq2(message.threadId, row.threadId), eq2(message.seq, Number(row.seq)))))).orderBy(...this.messageOrderNewestFirst());
2417
+ for (const row of rows) {
2418
+ if (!contents.has(row.threadId)) {
2419
+ contents.set(row.threadId, row.content);
2420
+ }
2421
+ }
2422
+ }
2423
+ for (const row of highest) {
2424
+ if (row.seq === null) {
2425
+ const [last] = await this.db.select({
2426
+ content: message.content
2427
+ }).from(message).where(eq2(message.threadId, row.threadId)).orderBy(...this.messageOrderNewestFirst()).limit(1);
2428
+ if (last !== void 0) {
2429
+ contents.set(row.threadId, last.content);
2430
+ }
2431
+ }
2365
2432
  }
2366
- return summaries;
2433
+ return contents;
2367
2434
  }
2368
2435
  async softDeleteThread(threadId) {
2369
2436
  await this.db.update(this.t.agentThread).set({
@@ -2740,6 +2807,24 @@ var DrizzleAgentStore = class {
2740
2807
  }).from(agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
2741
2808
  return thread?.persona ?? null;
2742
2809
  }
2810
+ async threadSettings(threadId) {
2811
+ const thread = this.t.agentThread;
2812
+ const [row] = await this.db.select({
2813
+ actorRef: thread.actorRef,
2814
+ defaultAgent: thread.defaultAgent,
2815
+ persona: thread.persona,
2816
+ model: thread.model
2817
+ }).from(thread).where(and2(eq2(thread.id, threadId), isNull2(thread.deletedAt)));
2818
+ if (row === void 0) {
2819
+ return null;
2820
+ }
2821
+ return {
2822
+ actorRef: row.actorRef,
2823
+ defaultAgent: row.defaultAgent ?? null,
2824
+ persona: row.persona ?? null,
2825
+ model: row.model ?? null
2826
+ };
2827
+ }
2743
2828
  async defaultAgentForThread(threadId) {
2744
2829
  const [thread] = await this.db.select({
2745
2830
  defaultAgent: this.t.agentThread.defaultAgent
@@ -3055,10 +3140,43 @@ var DrizzleAgentStore = class {
3055
3140
  return this.usageBetween(actorRef, day, day);
3056
3141
  }
3057
3142
  async usageBetween(actorRef, fromDay, toDay) {
3058
- const start = /* @__PURE__ */ new Date(`${fromDay}T00:00:00.000Z`);
3059
- const end = /* @__PURE__ */ new Date(`${toDay}T23:59:59.999Z`);
3060
- const rows = await this.db.select().from(this.t.agentTokenUsage).where(and2(eq2(this.t.agentTokenUsage.actorRef, actorRef), gte(this.t.agentTokenUsage.createdAt, start), lte2(this.t.agentTokenUsage.createdAt, end)));
3061
- return sumUsage(rows);
3143
+ const [totals] = await this.usageWindows(actorRef, [
3144
+ {
3145
+ fromDay,
3146
+ toDay
3147
+ }
3148
+ ]);
3149
+ return totals ?? sumUsage([]);
3150
+ }
3151
+ /**
3152
+ * Every range summed by the database in one statement, each as a conditional aggregate over the
3153
+ * rows of the smallest span covering them all — the actor's `(actor_ref, created_at)` index serves
3154
+ * it, and no usage row crosses the wire.
3155
+ */
3156
+ async usageWindows(actorRef, ranges) {
3157
+ if (ranges.length === 0) {
3158
+ return [];
3159
+ }
3160
+ const usage = this.t.agentTokenUsage;
3161
+ const bounds = ranges.map(({ fromDay, toDay }) => ({
3162
+ start: /* @__PURE__ */ new Date(`${fromDay}T00:00:00.000Z`),
3163
+ end: /* @__PURE__ */ new Date(`${toDay}T23:59:59.999Z`)
3164
+ }));
3165
+ const within = /* @__PURE__ */ __name((start, end) => and2(gte(usage.createdAt, start), lte2(usage.createdAt, end)), "within");
3166
+ const columns = {};
3167
+ bounds.forEach(({ start, end }, index4) => {
3168
+ columns[`tokens${index4}`] = sql3`sum(case when ${within(start, end)} then ${usage.inputTokens} + ${usage.outputTokens} else 0 end)`;
3169
+ columns[`cost${index4}`] = sql3`sum(case when ${within(start, end)} then ${usage.costUsd} else 0 end)`;
3170
+ columns[`estimated${index4}`] = sql3`sum(case when ${within(start, end)} and ${usage.costSource} = 'estimate' then ${usage.costUsd} else 0 end)`;
3171
+ });
3172
+ const from = new Date(Math.min(...bounds.map(({ start }) => start.getTime())));
3173
+ const to = new Date(Math.max(...bounds.map(({ end }) => end.getTime())));
3174
+ const [row] = await this.db.select(columns).from(usage).where(and2(eq2(usage.actorRef, actorRef), within(from, to)));
3175
+ return bounds.map((_, index4) => ({
3176
+ usedTokens: Number(row?.[`tokens${index4}`] ?? 0),
3177
+ costUsd: Number(row?.[`cost${index4}`] ?? 0),
3178
+ estimatedCostUsd: Number(row?.[`estimated${index4}`] ?? 0)
3179
+ }));
3062
3180
  }
3063
3181
  toSummary(thread, lastContent) {
3064
3182
  return {
@@ -3354,7 +3472,18 @@ var DrizzleGovernanceQueries = class {
3354
3472
  }
3355
3473
  async usageInRange(range) {
3356
3474
  const { start, end } = dayBoundsUtc(range);
3357
- const rows = await this.db.select().from(this.t.agentTokenUsage).where(and3(gte2(this.t.agentTokenUsage.createdAt, start), lte3(this.t.agentTokenUsage.createdAt, end)));
3475
+ const usage = this.t.agentTokenUsage;
3476
+ const rows = await this.db.select({
3477
+ modelId: usage.modelId,
3478
+ actorRef: usage.actorRef,
3479
+ threadId: usage.threadId,
3480
+ createdAt: usage.createdAt,
3481
+ inputTokens: usage.inputTokens,
3482
+ outputTokens: usage.outputTokens,
3483
+ cacheWriteTokens: usage.cacheWriteTokens,
3484
+ cacheReadTokens: usage.cacheReadTokens,
3485
+ costUsd: usage.costUsd
3486
+ }).from(usage).where(and3(gte2(this.t.agentTokenUsage.createdAt, start), lte3(this.t.agentTokenUsage.createdAt, end)));
3358
3487
  return rows.map(toUsageInput);
3359
3488
  }
3360
3489
  async spendByModel(range) {
@@ -3379,7 +3508,11 @@ var DrizzleGovernanceQueries = class {
3379
3508
  if (threadIds.length === 0) {
3380
3509
  return [];
3381
3510
  }
3382
- const threads = await this.db.select().from(this.t.agentThread).where(and3(inArray2(this.t.agentThread.id, threadIds), isNull3(this.t.agentThread.deletedAt)));
3511
+ const threads = await this.db.select({
3512
+ id: this.t.agentThread.id,
3513
+ title: this.t.agentThread.title,
3514
+ actorRef: this.t.agentThread.actorRef
3515
+ }).from(this.t.agentThread).where(and3(inArray2(this.t.agentThread.id, threadIds), isNull3(this.t.agentThread.deletedAt)));
3383
3516
  const threadsById = new Map(threads.map((thread) => [
3384
3517
  thread.id,
3385
3518
  {
@@ -3474,9 +3607,19 @@ var DrizzleGovernanceQueries = class {
3474
3607
  const threads = await this.db.select().from(this.t.agentThread).where(isNull3(this.t.agentThread.deletedAt)).orderBy(desc2(this.t.agentThread.updatedAt), desc2(this.t.agentThread.id)).limit(limit);
3475
3608
  return this.toThreadActivityRows(threads);
3476
3609
  }
3610
+ /** The range's runs, with only the columns the rollups read. */
3477
3611
  async runsInRange(range) {
3478
3612
  const { start, end } = dayBoundsUtc(range);
3479
- return this.db.select().from(this.t.agentRun).where(and3(gte2(this.t.agentRun.startedAt, start), lte3(this.t.agentRun.startedAt, end)));
3613
+ const run = this.t.agentRun;
3614
+ return this.db.select({
3615
+ agentName: run.agentName,
3616
+ status: run.status,
3617
+ retries: run.retries,
3618
+ durationMs: run.durationMs,
3619
+ ttftMs: run.ttftMs,
3620
+ parentRunId: run.parentRunId,
3621
+ startedAt: run.startedAt
3622
+ }).from(run).where(and3(gte2(run.startedAt, start), lte3(run.startedAt, end)));
3480
3623
  }
3481
3624
  async runMetrics(range) {
3482
3625
  const runs = await this.runsInRange(range);
@@ -3540,7 +3683,9 @@ var DrizzleGovernanceQueries = class {
3540
3683
  }
3541
3684
  async runErrors(range) {
3542
3685
  const { start, end } = dayBoundsUtc(range);
3543
- const runs = await this.db.select().from(this.t.agentRun).where(and3(gte2(this.t.agentRun.startedAt, start), lte3(this.t.agentRun.startedAt, end), eq3(this.t.agentRun.status, "failed")));
3686
+ const runs = await this.db.select({
3687
+ errorCode: this.t.agentRun.errorCode
3688
+ }).from(this.t.agentRun).where(and3(gte2(this.t.agentRun.startedAt, start), lte3(this.t.agentRun.startedAt, end), eq3(this.t.agentRun.status, "failed")));
3544
3689
  const byError = /* @__PURE__ */ new Map();
3545
3690
  for (const run of runs) {
3546
3691
  const errorCode = run.errorCode ?? UNCLASSIFIED_ERROR_CODE;
@@ -3621,7 +3766,12 @@ var DrizzleGovernanceQueries = class {
3621
3766
  */
3622
3767
  async toolStats(range) {
3623
3768
  const { start, end } = dayBoundsUtc(range);
3624
- const calls = await this.db.select().from(this.t.agentToolCall).where(and3(gte2(this.t.agentToolCall.createdAt, start), lte3(this.t.agentToolCall.createdAt, end)));
3769
+ const calls = await this.db.select({
3770
+ toolName: this.t.agentToolCall.toolName,
3771
+ toolType: this.t.agentToolCall.toolType,
3772
+ status: this.t.agentToolCall.status,
3773
+ executionMs: this.t.agentToolCall.executionMs
3774
+ }).from(this.t.agentToolCall).where(and3(gte2(this.t.agentToolCall.createdAt, start), lte3(this.t.agentToolCall.createdAt, end)));
3625
3775
  const byTool = /* @__PURE__ */ new Map();
3626
3776
  for (const call of calls) {
3627
3777
  const key2 = `${call.toolName} ${call.toolType}`;