@dudousxd/nestjs-agent-store-drizzle 0.24.0 → 0.26.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.js CHANGED
@@ -40,6 +40,7 @@ var agentMessage = sqliteTable("agent_message", {
40
40
  onDelete: "cascade"
41
41
  }),
42
42
  role: text("role").$type().notNull(),
43
+ actionProposalOutcome: text("action_proposal_outcome"),
43
44
  content: text("content").notNull(),
44
45
  toolCalls: text("tool_calls", {
45
46
  mode: "json"
@@ -84,6 +85,7 @@ var agentMessage = sqliteTable("agent_message", {
84
85
  index("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
85
86
  ]);
86
87
  var agentToolCall = sqliteTable("agent_tool_call", {
88
+ proposalId: text("proposal_id"),
87
89
  id: text("id").primaryKey(),
88
90
  messageId: text("message_id").notNull().references(() => agentMessage.id, {
89
91
  onDelete: "cascade"
@@ -108,6 +110,10 @@ var agentToolCall = sqliteTable("agent_tool_call", {
108
110
  }),
109
111
  /** The run (turn) this call belongs to, for a trace deep-link; null for a pre-rollout row. */
110
112
  runId: text("run_id"),
113
+ /** Resolved per-call wording; null falls back to presentation templates. */
114
+ confirmation: text("confirmation", {
115
+ mode: "json"
116
+ }).$type(),
111
117
  /** Who had to approve it (`requester` or a role); null for a call no policy put to anyone. */
112
118
  approver: text("approver"),
113
119
  /** When the approval request lapses; null → never. */
@@ -124,6 +130,9 @@ var agentToolCall = sqliteTable("agent_tool_call", {
124
130
  index("agent_tool_call_message_idx").on(table.messageId)
125
131
  ]);
126
132
  var agentQueuedMessage = sqliteTable("agent_queued_message", {
133
+ uiCapabilities: text("ui_capabilities", {
134
+ mode: "json"
135
+ }).$type(),
127
136
  id: text("id").primaryKey(),
128
137
  threadId: text("thread_id").notNull().references(() => agentThread.id, {
129
138
  onDelete: "cascade"
@@ -301,7 +310,35 @@ var agentStreamFrame = sqliteTable("agent_stream_frame", {
301
310
  ]
302
311
  })
303
312
  ]);
313
+ var agentActionProposal = sqliteTable("agent_action_proposal", {
314
+ id: text("id").primaryKey(),
315
+ scopeKey: text("scope_key").notNull(),
316
+ decision: text("decision").$type().notNull(),
317
+ logicalSort: text("logical_sort").notNull(),
318
+ createFingerprint: text("create_fingerprint").notNull(),
319
+ proposal: text("proposal", {
320
+ mode: "json"
321
+ }).$type().notNull(),
322
+ version: integer("version").notNull().default(0),
323
+ executionStatus: text("execution_status").$type(),
324
+ leaseExpiresAt: integer("lease_expires_at"),
325
+ deliveryStatus: text("delivery_status"),
326
+ deliveryLeaseExpiresAt: integer("delivery_lease_expires_at"),
327
+ replacementGroupKey: text("replacement_group_key"),
328
+ outcomeIdKey: text("outcome_id_key"),
329
+ proposalExpiresAt: integer("proposal_expires_at"),
330
+ discoveryIndexVersion: integer("discovery_index_version").notNull().default(0),
331
+ createdAt: integer("created_at").notNull()
332
+ }, (table) => [
333
+ index("agent_action_proposal_execution_idx").on(table.discoveryIndexVersion, table.executionStatus, table.leaseExpiresAt, table.createdAt),
334
+ index("agent_action_proposal_expiry_idx").on(table.discoveryIndexVersion, table.decision, table.proposalExpiresAt, table.createdAt),
335
+ index("agent_action_proposal_replacement_idx").on(table.scopeKey, table.replacementGroupKey, table.decision),
336
+ index("agent_action_proposal_delivery_idx").on(table.deliveryStatus, table.deliveryLeaseExpiresAt, table.createdAt),
337
+ uniqueIndex("agent_action_proposal_outcome_idx").on(table.outcomeIdKey),
338
+ index("agent_action_proposal_scope_idx").on(table.scopeKey, table.createdAt, table.id)
339
+ ]);
304
340
  var agentSchema = {
341
+ agentActionProposal,
305
342
  agentThread,
306
343
  agentMessage,
307
344
  agentQueuedMessage,
@@ -327,7 +364,8 @@ import { MySqlDatabase } from "drizzle-orm/mysql-core";
327
364
  import { PgDatabase } from "drizzle-orm/pg-core";
328
365
 
329
366
  // src/schema-mysql.ts
330
- import { bigint, boolean, datetime, double, index as index2, int, json, longtext, mysqlTable, primaryKey as primaryKey2, uniqueIndex as uniqueIndex2, varchar } from "drizzle-orm/mysql-core";
367
+ import { canonicalActionProposalJson } from "@dudousxd/nestjs-agent-core";
368
+ import { bigint, boolean, customType, datetime, double, index as index2, int, json, longtext, mysqlTable, primaryKey as primaryKey2, uniqueIndex as uniqueIndex2, varchar } from "drizzle-orm/mysql-core";
331
369
  var ts = /* @__PURE__ */ __name((name) => datetime(name, {
332
370
  mode: "date",
333
371
  fsp: 3
@@ -359,6 +397,7 @@ var agentMessage2 = mysqlTable("agent_message", {
359
397
  onDelete: "cascade"
360
398
  }),
361
399
  role: key("role").$type().notNull(),
400
+ actionProposalOutcome: longtext("action_proposal_outcome"),
362
401
  content: longtext("content").notNull(),
363
402
  toolCalls: json("tool_calls").$type(),
364
403
  toolResults: json("tool_results").$type(),
@@ -379,6 +418,7 @@ var agentMessage2 = mysqlTable("agent_message", {
379
418
  index2("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
380
419
  ]);
381
420
  var agentToolCall2 = mysqlTable("agent_tool_call", {
421
+ proposalId: key("proposal_id"),
382
422
  id: key("id").primaryKey(),
383
423
  messageId: key("message_id").notNull().references(() => agentMessage2.id, {
384
424
  onDelete: "cascade"
@@ -394,6 +434,7 @@ var agentToolCall2 = mysqlTable("agent_tool_call", {
394
434
  createdAt: ts("created_at").notNull(),
395
435
  executedAt: ts("executed_at"),
396
436
  runId: key("run_id"),
437
+ confirmation: json("confirmation").$type(),
397
438
  approver: key("approver"),
398
439
  expiresAt: ts("expires_at"),
399
440
  remember: boolean("remember"),
@@ -402,6 +443,7 @@ var agentToolCall2 = mysqlTable("agent_tool_call", {
402
443
  index2("agent_tool_call_message_idx").on(table.messageId)
403
444
  ]);
404
445
  var agentQueuedMessage2 = mysqlTable("agent_queued_message", {
446
+ uiCapabilities: json("ui_capabilities").$type(),
405
447
  id: key("id").primaryKey(),
406
448
  threadId: key("thread_id").notNull().references(() => agentThread2.id, {
407
449
  onDelete: "cascade"
@@ -531,7 +573,52 @@ var agentStreamFrame2 = mysqlTable("agent_stream_frame", {
531
573
  ]
532
574
  })
533
575
  ]);
576
+ var proposalJson = customType({
577
+ dataType: /* @__PURE__ */ __name(() => "longtext", "dataType"),
578
+ toDriver: /* @__PURE__ */ __name((value) => canonicalActionProposalJson(value), "toDriver"),
579
+ fromDriver: /* @__PURE__ */ __name((value) => JSON.parse(value), "fromDriver")
580
+ });
581
+ var agentActionProposal2 = mysqlTable("agent_action_proposal", {
582
+ id: key("id").primaryKey(),
583
+ scopeKey: key("scope_key").notNull(),
584
+ decision: key("decision").$type().notNull(),
585
+ logicalSort: varchar("logical_sort", {
586
+ length: 1020
587
+ }).notNull(),
588
+ createFingerprint: longtext("create_fingerprint").notNull(),
589
+ proposal: proposalJson("proposal").notNull(),
590
+ version: bigint("version", {
591
+ mode: "number"
592
+ }).notNull().default(0),
593
+ executionStatus: key("execution_status").$type(),
594
+ leaseExpiresAt: bigint("lease_expires_at", {
595
+ mode: "number"
596
+ }),
597
+ deliveryStatus: key("delivery_status"),
598
+ deliveryLeaseExpiresAt: bigint("delivery_lease_expires_at", {
599
+ mode: "number"
600
+ }),
601
+ replacementGroupKey: key("replacement_group_key"),
602
+ outcomeIdKey: key("outcome_id_key"),
603
+ proposalExpiresAt: bigint("proposal_expires_at", {
604
+ mode: "number"
605
+ }),
606
+ discoveryIndexVersion: bigint("discovery_index_version", {
607
+ mode: "number"
608
+ }).notNull().default(0),
609
+ createdAt: bigint("created_at", {
610
+ mode: "number"
611
+ }).notNull()
612
+ }, (table) => [
613
+ index2("agent_action_proposal_execution_idx").on(table.discoveryIndexVersion, table.executionStatus, table.leaseExpiresAt, table.createdAt),
614
+ index2("agent_action_proposal_expiry_idx").on(table.discoveryIndexVersion, table.decision, table.proposalExpiresAt, table.createdAt),
615
+ index2("agent_action_proposal_replacement_idx").on(table.scopeKey, table.replacementGroupKey, table.decision),
616
+ index2("agent_action_proposal_delivery_idx").on(table.deliveryStatus, table.deliveryLeaseExpiresAt, table.createdAt),
617
+ uniqueIndex2("agent_action_proposal_outcome_idx").on(table.outcomeIdKey),
618
+ index2("agent_action_proposal_scope_idx").on(table.scopeKey, table.createdAt, table.id)
619
+ ]);
534
620
  var mysqlAgentSchema = {
621
+ agentActionProposal: agentActionProposal2,
535
622
  agentThread: agentThread2,
536
623
  agentMessage: agentMessage2,
537
624
  agentQueuedMessage: agentQueuedMessage2,
@@ -546,7 +633,8 @@ var mysqlAgentSchema = {
546
633
  };
547
634
 
548
635
  // src/schema-pg.ts
549
- import { bigint as bigint2, boolean as boolean2, doublePrecision, index as index3, integer as integer2, jsonb, pgTable, primaryKey as primaryKey3, text as text2, timestamp, uniqueIndex as uniqueIndex3 } from "drizzle-orm/pg-core";
636
+ import { canonicalActionProposalJson as canonicalActionProposalJson2 } from "@dudousxd/nestjs-agent-core";
637
+ import { bigint as bigint2, boolean as boolean2, customType as customType2, doublePrecision, index as index3, integer as integer2, jsonb, pgTable, primaryKey as primaryKey3, text as text2, timestamp, uniqueIndex as uniqueIndex3 } from "drizzle-orm/pg-core";
550
638
  var ts2 = /* @__PURE__ */ __name((name) => timestamp(name, {
551
639
  withTimezone: true,
552
640
  precision: 3,
@@ -576,6 +664,7 @@ var agentMessage3 = pgTable("agent_message", {
576
664
  onDelete: "cascade"
577
665
  }),
578
666
  role: text2("role").$type().notNull(),
667
+ actionProposalOutcome: text2("action_proposal_outcome"),
579
668
  content: text2("content").notNull(),
580
669
  toolCalls: jsonb("tool_calls").$type(),
581
670
  toolResults: jsonb("tool_results").$type(),
@@ -596,6 +685,7 @@ var agentMessage3 = pgTable("agent_message", {
596
685
  index3("agent_message_thread_created_idx").on(table.threadId, table.createdAt)
597
686
  ]);
598
687
  var agentToolCall3 = pgTable("agent_tool_call", {
688
+ proposalId: text2("proposal_id"),
599
689
  id: text2("id").primaryKey(),
600
690
  messageId: text2("message_id").notNull().references(() => agentMessage3.id, {
601
691
  onDelete: "cascade"
@@ -611,6 +701,7 @@ var agentToolCall3 = pgTable("agent_tool_call", {
611
701
  createdAt: ts2("created_at").notNull(),
612
702
  executedAt: ts2("executed_at"),
613
703
  runId: text2("run_id"),
704
+ confirmation: jsonb("confirmation").$type(),
614
705
  approver: text2("approver"),
615
706
  expiresAt: ts2("expires_at"),
616
707
  remember: boolean2("remember"),
@@ -619,6 +710,7 @@ var agentToolCall3 = pgTable("agent_tool_call", {
619
710
  index3("agent_tool_call_message_idx").on(table.messageId)
620
711
  ]);
621
712
  var agentQueuedMessage3 = pgTable("agent_queued_message", {
713
+ uiCapabilities: jsonb("ui_capabilities").$type(),
622
714
  id: text2("id").primaryKey(),
623
715
  threadId: text2("thread_id").notNull().references(() => agentThread3.id, {
624
716
  onDelete: "cascade"
@@ -748,7 +840,50 @@ var agentStreamFrame3 = pgTable("agent_stream_frame", {
748
840
  ]
749
841
  })
750
842
  ]);
843
+ var proposalJson2 = customType2({
844
+ dataType: /* @__PURE__ */ __name(() => "text", "dataType"),
845
+ toDriver: /* @__PURE__ */ __name((value) => canonicalActionProposalJson2(value), "toDriver"),
846
+ fromDriver: /* @__PURE__ */ __name((value) => JSON.parse(value), "fromDriver")
847
+ });
848
+ var agentActionProposal3 = pgTable("agent_action_proposal", {
849
+ id: text2("id").primaryKey(),
850
+ scopeKey: text2("scope_key").notNull(),
851
+ decision: text2("decision").$type().notNull(),
852
+ logicalSort: text2("logical_sort").notNull(),
853
+ createFingerprint: text2("create_fingerprint").notNull(),
854
+ proposal: proposalJson2("proposal").notNull(),
855
+ version: bigint2("version", {
856
+ mode: "number"
857
+ }).notNull().default(0),
858
+ executionStatus: text2("execution_status").$type(),
859
+ leaseExpiresAt: bigint2("lease_expires_at", {
860
+ mode: "number"
861
+ }),
862
+ deliveryStatus: text2("delivery_status"),
863
+ deliveryLeaseExpiresAt: bigint2("delivery_lease_expires_at", {
864
+ mode: "number"
865
+ }),
866
+ replacementGroupKey: text2("replacement_group_key"),
867
+ outcomeIdKey: text2("outcome_id_key"),
868
+ proposalExpiresAt: bigint2("proposal_expires_at", {
869
+ mode: "number"
870
+ }),
871
+ discoveryIndexVersion: bigint2("discovery_index_version", {
872
+ mode: "number"
873
+ }).notNull().default(0),
874
+ createdAt: bigint2("created_at", {
875
+ mode: "number"
876
+ }).notNull()
877
+ }, (table) => [
878
+ index3("agent_action_proposal_execution_idx").on(table.discoveryIndexVersion, table.executionStatus, table.leaseExpiresAt, table.createdAt),
879
+ index3("agent_action_proposal_expiry_idx").on(table.discoveryIndexVersion, table.decision, table.proposalExpiresAt, table.createdAt),
880
+ index3("agent_action_proposal_replacement_idx").on(table.scopeKey, table.replacementGroupKey, table.decision),
881
+ index3("agent_action_proposal_delivery_idx").on(table.deliveryStatus, table.deliveryLeaseExpiresAt, table.createdAt),
882
+ uniqueIndex3("agent_action_proposal_outcome_idx").on(table.outcomeIdKey),
883
+ index3("agent_action_proposal_scope_idx").on(table.scopeKey, table.createdAt, table.id)
884
+ ]);
751
885
  var pgAgentSchema = {
886
+ agentActionProposal: agentActionProposal3,
752
887
  agentThread: agentThread3,
753
888
  agentMessage: agentMessage3,
754
889
  agentQueuedMessage: agentQueuedMessage3,
@@ -1000,8 +1135,516 @@ async function heal(db, dialect) {
1000
1135
  __name(heal, "heal");
1001
1136
 
1002
1137
  // src/drizzle-agent-store.ts
1003
- import { toolCallApprovalFromRow } from "@dudousxd/nestjs-agent-core";
1004
- import { and, asc, desc, eq, gte, inArray, isNotNull, isNull, lte, max, min, or, sql as sql2 } from "drizzle-orm";
1138
+ import { canonicalActionProposalJson as canonicalActionProposalJson4, toolCallApprovalFromRow } from "@dudousxd/nestjs-agent-core";
1139
+ import { and as and2, asc as asc2, desc, eq as eq2, gte, inArray, isNotNull, isNull as isNull2, lte as lte2, max as max2, min, or as or2, sql as sql3 } from "drizzle-orm";
1140
+
1141
+ // src/drizzle-action-proposal-store.ts
1142
+ import { createHash, randomUUID } from "crypto";
1143
+ import { actionProposalOutcomeFenceValid, actionProposalOutcomeText, actionProposalScopeMatches, canonicalActionProposalJson as canonicalActionProposalJson3, claimActionProposalOutcome, initialActionProposal, transitionActionProposalClaim, transitionActionProposalDecision, transitionActionProposalLease, transitionActionProposalSettlement, transitionActionProposalSupersession, validateActionProposalDiscoveryIndexBatch, validateActionProposalExpiryBatch, validateActionProposalListQuery, validateActionProposalWorkerClaim } from "@dudousxd/nestjs-agent-core";
1144
+ import { and, asc, entityKind, eq, gt, isNull, lte, max, or, sql as sql2 } from "drizzle-orm";
1145
+
1146
+ // src/action-proposal-transaction-mode.ts
1147
+ function actionProposalTransactionMode(kind) {
1148
+ if (kind === "BetterSQLite3Database" || kind === "BetterSQLiteTransaction") return "sync";
1149
+ if (kind !== void 0 && [
1150
+ "NodePgDatabase",
1151
+ "NodePgTransaction",
1152
+ "PostgresJsDatabase",
1153
+ "PostgresJsTransaction",
1154
+ "MySql2Database",
1155
+ "MySql2Transaction",
1156
+ "LibSQLDatabase",
1157
+ "LibSQLTransaction"
1158
+ ].includes(kind)) return "async";
1159
+ return "unsupported";
1160
+ }
1161
+ __name(actionProposalTransactionMode, "actionProposalTransactionMode");
1162
+
1163
+ // src/drizzle-action-proposal-store.ts
1164
+ var DrizzleActionProposalStore = class {
1165
+ static {
1166
+ __name(this, "DrizzleActionProposalStore");
1167
+ }
1168
+ db;
1169
+ rawDb;
1170
+ actionProposalAdmissionSupported;
1171
+ synchronousSqlite;
1172
+ dialect;
1173
+ table;
1174
+ clock;
1175
+ constructor(db, options = {}) {
1176
+ this.rawDb = db;
1177
+ const kind = db.constructor[entityKind];
1178
+ const transactionMode = actionProposalTransactionMode(kind);
1179
+ this.synchronousSqlite = transactionMode === "sync";
1180
+ this.actionProposalAdmissionSupported = transactionMode !== "unsupported";
1181
+ this.dialect = agentDialectOf(db);
1182
+ this.table = agentTablesFor(this.dialect).agentActionProposal;
1183
+ this.db = asBuilder(db);
1184
+ this.clock = options.clock ?? Date.now;
1185
+ }
1186
+ async createActionProposal(input) {
1187
+ const proposal = initialActionProposal(input, this.clock());
1188
+ const row = {
1189
+ id: physicalId(input.id),
1190
+ scopeKey: scopeKey(input),
1191
+ decision: proposal.decision,
1192
+ logicalSort: logicalSort(input.id),
1193
+ createFingerprint: canonicalActionProposalJson3(input),
1194
+ proposal,
1195
+ ...discoveryMetadata(proposal),
1196
+ version: 0,
1197
+ createdAt: proposal.createdAt
1198
+ };
1199
+ const table = this.table;
1200
+ const insert = this.db.insert(table);
1201
+ const inserted = this.dialect === "mysql" ? mysqlAffectedRows(await insert.ignore().values(row)) : await affectedRows(this.dialect, insert.values(row).onConflictDoNothing(), table.id);
1202
+ const stored = await this.read(input, input.id);
1203
+ if (!stored) return {
1204
+ status: "conflict"
1205
+ };
1206
+ if (inserted === 1) return {
1207
+ status: "created",
1208
+ proposal: stored.proposal
1209
+ };
1210
+ return {
1211
+ status: stored.createFingerprint === row.createFingerprint ? "unchanged" : "conflict",
1212
+ proposal: stored.proposal
1213
+ };
1214
+ }
1215
+ createReplacingActionProposal(input) {
1216
+ if (!input.replacementKey) return this.createActionProposal(input);
1217
+ const proposal = initialActionProposal(input, this.clock());
1218
+ return this.transactionSteps((db) => this.replacementSteps(db, input, proposal));
1219
+ }
1220
+ async supersedeActionProposal(scope, id, command) {
1221
+ const replacement = await this.getActionProposal(scope, command.replacementProposalId);
1222
+ if (!replacement) return {
1223
+ status: "not_found"
1224
+ };
1225
+ return this.mutate(scope, id, (row, now) => transitionActionProposalSupersession(row, replacement, command, now));
1226
+ }
1227
+ *replacementSteps(db, input, proposal) {
1228
+ const table = this.table;
1229
+ const thread = agentTablesFor(this.dialect).agentThread;
1230
+ if (this.dialect === "sqlite") yield {
1231
+ kind: "write",
1232
+ query: db.update(thread).set({
1233
+ updatedAt: sql2`${thread.updatedAt}`
1234
+ }).where(eq(thread.id, input.threadId))
1235
+ };
1236
+ const threads = yield {
1237
+ kind: "read",
1238
+ query: lockQuery(db.select().from(thread).where(eq(thread.id, input.threadId)).limit(1), this.dialect)
1239
+ };
1240
+ const owner = threads[0];
1241
+ if (!owner || owner.id !== input.threadId || owner.deletedAt || owner.actorRef !== input.actorRef || owner.tenantRef !== input.tenantRef) return {
1242
+ status: "conflict"
1243
+ };
1244
+ const existingRows = yield {
1245
+ kind: "read",
1246
+ query: db.select().from(table).where(eq(table.id, physicalId(input.id))).limit(1)
1247
+ };
1248
+ const existing = existingRows[0];
1249
+ if (existing) {
1250
+ if (existing.proposal.id !== input.id || !actionProposalScopeMatches(existing.proposal, input)) return {
1251
+ status: "conflict"
1252
+ };
1253
+ return {
1254
+ status: existing.createFingerprint === canonicalActionProposalJson3(input) ? "unchanged" : "conflict",
1255
+ proposal: existing.proposal
1256
+ };
1257
+ }
1258
+ const groupKey = replacementGroupKey(input);
1259
+ if (groupKey === null) throw new Error("Missing explicit replacement identity");
1260
+ const pending = yield {
1261
+ kind: "read",
1262
+ query: lockQuery(db.select().from(table).where(and(eq(table.scopeKey, scopeKey(input)), eq(table.replacementGroupKey, groupKey), eq(table.decision, "pending"))), this.dialect)
1263
+ };
1264
+ const row = {
1265
+ id: physicalId(input.id),
1266
+ scopeKey: scopeKey(input),
1267
+ decision: proposal.decision,
1268
+ logicalSort: logicalSort(input.id),
1269
+ createFingerprint: canonicalActionProposalJson3(input),
1270
+ proposal,
1271
+ ...discoveryMetadata(proposal),
1272
+ version: 0,
1273
+ createdAt: proposal.createdAt
1274
+ };
1275
+ const insert = db.insert(table);
1276
+ const inserted = yield {
1277
+ kind: "read",
1278
+ query: this.dialect === "mysql" ? insert.ignore().values(row) : insert.values(row).onConflictDoNothing().returning({
1279
+ id: table.id
1280
+ })
1281
+ };
1282
+ const count3 = this.dialect === "mysql" ? mysqlAffectedRows(inserted) : inserted.length;
1283
+ if (count3 !== 1) return {
1284
+ status: "conflict"
1285
+ };
1286
+ for (const old of pending) {
1287
+ const result = transitionActionProposalSupersession(old.proposal, proposal, {
1288
+ replacementProposalId: proposal.id,
1289
+ actorRef: proposal.actorRef,
1290
+ via: "replacement"
1291
+ }, this.clock());
1292
+ if (!result.proposal || canonicalActionProposalJson3(result.proposal) === canonicalActionProposalJson3(old.proposal)) continue;
1293
+ const next = result.proposal;
1294
+ const update = db.update(table).set({
1295
+ proposal: next,
1296
+ decision: next.decision,
1297
+ ...discoveryMetadata(next),
1298
+ version: old.version + 1
1299
+ }).where(and(eq(table.id, old.id), eq(table.version, old.version)));
1300
+ const updated = yield {
1301
+ kind: "read",
1302
+ query: this.dialect === "mysql" ? update : update.returning({
1303
+ id: table.id
1304
+ })
1305
+ };
1306
+ if ((this.dialect === "mysql" ? mysqlAffectedRows(updated) : updated.length) !== 1) throw new Error("Replacement lost its locked proposal fence");
1307
+ }
1308
+ return {
1309
+ status: "created",
1310
+ proposal
1311
+ };
1312
+ }
1313
+ async getActionProposal(scope, id) {
1314
+ return (await this.read(scope, id))?.proposal ?? null;
1315
+ }
1316
+ async listActionProposals(scope, query = {}) {
1317
+ const limit = validateActionProposalListQuery(query);
1318
+ const rows = await this.db.select().from(this.table).where(and(eq(this.table.scopeKey, scopeKey(scope)), query.after === void 0 ? void 0 : or(gt(this.table.createdAt, query.after.createdAt), and(eq(this.table.createdAt, query.after.createdAt), gt(this.table.logicalSort, logicalSort(query.after.id)))), query.decision === void 0 ? void 0 : eq(this.table.decision, query.decision))).orderBy(asc(this.table.createdAt), asc(this.table.logicalSort)).limit(limit);
1319
+ return rows.map((row) => row.proposal).filter((proposal) => actionProposalScopeMatches(proposal, scope));
1320
+ }
1321
+ decideActionProposal(scope, id, command) {
1322
+ return this.mutate(scope, id, (row, now) => transitionActionProposalDecision(row, command, now));
1323
+ }
1324
+ claimActionProposal(scope, id, command) {
1325
+ return this.mutate(scope, id, (row, now) => transitionActionProposalClaim(row, command, now, randomUUID()));
1326
+ }
1327
+ extendActionProposalLease(scope, id, command) {
1328
+ return this.mutate(scope, id, (row, now) => transitionActionProposalLease(row, command, now));
1329
+ }
1330
+ settleActionProposal(scope, id, command) {
1331
+ return this.mutate(scope, id, (row, now) => transitionActionProposalSettlement(row, command, now));
1332
+ }
1333
+ async claimNextActionProposal(command) {
1334
+ const now = this.clock();
1335
+ validateActionProposalWorkerClaim(command, now);
1336
+ const table = this.table;
1337
+ const candidates = await this.db.select().from(table).where(and(eq(table.discoveryIndexVersion, 1), eq(table.decision, "approved"), or(eq(table.executionStatus, "queued"), and(eq(table.executionStatus, "executing"), lte(table.leaseExpiresAt, now))))).orderBy(asc(table.createdAt), asc(table.logicalSort)).limit(32);
1338
+ for (const candidate of candidates) {
1339
+ const result = await this.claimActionProposal(candidate.proposal, candidate.proposal.id, command);
1340
+ if (result.status === "applied" && result.proposal) return result.proposal;
1341
+ }
1342
+ return null;
1343
+ }
1344
+ async expireActionProposals(command) {
1345
+ const now = this.clock();
1346
+ validateActionProposalExpiryBatch(command, now);
1347
+ const table = this.table;
1348
+ const candidates = await this.db.select().from(table).where(and(eq(table.discoveryIndexVersion, 1), eq(table.decision, "pending"), lte(table.proposalExpiresAt, now))).orderBy(asc(table.createdAt), asc(table.logicalSort)).limit(command.limit);
1349
+ let expired = 0;
1350
+ for (const candidate of candidates) {
1351
+ const result = await this.decideActionProposal(candidate.proposal, candidate.proposal.id, {
1352
+ decision: "expired",
1353
+ actorRef: "system",
1354
+ via: "expiry"
1355
+ });
1356
+ if (result.status === "applied") expired++;
1357
+ }
1358
+ return expired;
1359
+ }
1360
+ async backfillActionProposalDiscoveryIndex(command) {
1361
+ validateActionProposalDiscoveryIndexBatch(command);
1362
+ const table = this.table;
1363
+ const candidates = await this.db.select().from(table).where(eq(table.discoveryIndexVersion, 0)).orderBy(asc(table.createdAt), asc(table.logicalSort)).limit(command.limit);
1364
+ let changed = 0;
1365
+ for (const row of candidates) {
1366
+ changed += await affectedRows(this.dialect, this.db.update(table).set({
1367
+ ...discoveryMetadata(row.proposal),
1368
+ version: row.version + 1
1369
+ }).where(and(eq(table.id, row.id), eq(table.scopeKey, row.scopeKey), eq(table.version, row.version), eq(table.discoveryIndexVersion, 0))), table.id);
1370
+ }
1371
+ return changed;
1372
+ }
1373
+ async rememberedActionProposalApprovals(scope) {
1374
+ const table = this.table;
1375
+ const rows = await this.db.select().from(table).where(and(eq(table.scopeKey, scopeKey(scope)), eq(table.decision, "approved"), or(eq(table.executionStatus, "succeeded"), eq(table.executionStatus, "failed"))));
1376
+ return [
1377
+ ...new Set(rows.filter((row) => actionProposalScopeMatches(row.proposal, scope) && row.proposal.decisionAudit?.remember === true).map((row) => row.proposal.toolName))
1378
+ ];
1379
+ }
1380
+ async getThreadActionProposalScope(threadId) {
1381
+ const thread = agentTablesFor(this.dialect).agentThread;
1382
+ const [row] = await this.db.select().from(thread).where(and(eq(thread.id, threadId), isNull(thread.deletedAt))).limit(1);
1383
+ return row?.id === threadId ? {
1384
+ actorRef: row.actorRef,
1385
+ tenantRef: row.tenantRef,
1386
+ threadId: row.id
1387
+ } : null;
1388
+ }
1389
+ async claimNextActionProposalOutcome(command) {
1390
+ const now = this.clock();
1391
+ validateActionProposalWorkerClaim(command, now);
1392
+ const table = this.table;
1393
+ const candidates = await this.db.select().from(table).where(and(eq(table.deliveryStatus, "pending"), or(isNull(table.deliveryLeaseExpiresAt), lte(table.deliveryLeaseExpiresAt, now)))).orderBy(asc(table.createdAt), asc(table.logicalSort)).limit(32);
1394
+ for (const row of candidates) {
1395
+ const result = await this.mutate(row.proposal, row.proposal.id, (proposal, time) => {
1396
+ const claimed2 = claimActionProposalOutcome(proposal, command, time, randomUUID());
1397
+ return claimed2 ? {
1398
+ status: "applied",
1399
+ proposal: claimed2
1400
+ } : {
1401
+ status: "conflict",
1402
+ proposal
1403
+ };
1404
+ });
1405
+ const claimed = result.proposal;
1406
+ if (result.status === "applied" && claimed?.outcome && claimed.outcomeDelivery?.lease) {
1407
+ return {
1408
+ outcome: claimed.outcome,
1409
+ lease: {
1410
+ outcomeId: claimed.outcome.id,
1411
+ token: claimed.outcomeDelivery.lease.token,
1412
+ generation: claimed.outcomeDelivery.generation
1413
+ }
1414
+ };
1415
+ }
1416
+ }
1417
+ return null;
1418
+ }
1419
+ async admitActionProposalOutcome(command) {
1420
+ return this.transactionSteps((db) => this.admissionSteps(db, command));
1421
+ }
1422
+ async transactionSteps(factory) {
1423
+ if (!this.actionProposalAdmissionSupported) throw new Error("Independent actions require a certified transactional Drizzle driver (better-sqlite3, node-postgres, mysql2 or libsql)");
1424
+ if (this.synchronousSqlite) {
1425
+ const database2 = this.rawDb;
1426
+ return database2.transaction((tx) => runSync(factory(asBuilder(tx))), {
1427
+ behavior: "immediate"
1428
+ });
1429
+ }
1430
+ const database = this.rawDb;
1431
+ return database.transaction(async (tx) => runAsync(factory(asBuilder(tx))));
1432
+ }
1433
+ *admissionSteps(db, command) {
1434
+ if (typeof command.outcomeId !== "string" || !command.outcomeId || typeof command.token !== "string" || !command.token || !Number.isSafeInteger(command.generation) || command.generation < 1) throw new TypeError("Invalid outcome fence");
1435
+ const table = this.table;
1436
+ const tables = agentTablesFor(this.dialect);
1437
+ if (this.dialect === "sqlite") yield {
1438
+ kind: "write",
1439
+ query: db.update(table).set({
1440
+ version: sql2`${table.version}`
1441
+ }).where(eq(table.outcomeIdKey, physicalId(command.outcomeId)))
1442
+ };
1443
+ const query = db.select().from(table).where(eq(table.outcomeIdKey, physicalId(command.outcomeId))).limit(1);
1444
+ const rows = yield {
1445
+ kind: "read",
1446
+ query: lockQuery(query, this.dialect)
1447
+ };
1448
+ const row = rows[0];
1449
+ if (!row || row.proposal.outcome?.id !== command.outcomeId) return {
1450
+ status: "not_found"
1451
+ };
1452
+ const proposal = row.proposal;
1453
+ const outcome = proposal.outcome;
1454
+ const delivery = proposal.outcomeDelivery;
1455
+ if (!outcome || !delivery) return {
1456
+ status: "not_found"
1457
+ };
1458
+ if (proposal.outcomeDelivery?.status === "admitted") return {
1459
+ status: "unchanged",
1460
+ ...proposal.outcomeDelivery.messageId !== void 0 ? {
1461
+ messageId: proposal.outcomeDelivery.messageId
1462
+ } : {}
1463
+ };
1464
+ if (proposal.outcomeDelivery?.status === "discarded") return {
1465
+ status: "discarded"
1466
+ };
1467
+ if (!actionProposalOutcomeFenceValid(proposal, command, this.clock())) return {
1468
+ status: "conflict"
1469
+ };
1470
+ const threadQuery = db.select().from(tables.agentThread).where(eq(tables.agentThread.id, proposal.threadId)).limit(1);
1471
+ const threads = yield {
1472
+ kind: "read",
1473
+ query: lockQuery(threadQuery, this.dialect)
1474
+ };
1475
+ const thread = threads[0];
1476
+ const now = this.clock();
1477
+ if (!actionProposalOutcomeFenceValid(proposal, command, now)) return {
1478
+ status: "conflict"
1479
+ };
1480
+ if (!thread || thread.id !== proposal.threadId || thread.deletedAt || thread.actorRef !== proposal.actorRef || thread.tenantRef !== proposal.tenantRef) {
1481
+ const discarded = {
1482
+ ...proposal,
1483
+ outcomeDelivery: {
1484
+ ...delivery,
1485
+ status: "discarded",
1486
+ lease: null
1487
+ },
1488
+ updatedAt: now
1489
+ };
1490
+ yield {
1491
+ kind: "write",
1492
+ query: db.update(table).set({
1493
+ proposal: discarded,
1494
+ ...discoveryMetadata(discarded),
1495
+ version: row.version + 1
1496
+ }).where(and(eq(table.id, row.id), eq(table.version, row.version)))
1497
+ };
1498
+ return {
1499
+ status: "discarded"
1500
+ };
1501
+ }
1502
+ if (thread.activeStreamId !== null) return {
1503
+ status: "busy"
1504
+ };
1505
+ const seqRows = yield {
1506
+ kind: "read",
1507
+ query: db.select({
1508
+ last: max(tables.agentMessage.seq)
1509
+ }).from(tables.agentMessage).where(eq(tables.agentMessage.threadId, thread.id))
1510
+ };
1511
+ const messageId = physicalId(command.outcomeId);
1512
+ yield {
1513
+ kind: "write",
1514
+ query: db.insert(tables.agentMessage).values({
1515
+ id: messageId,
1516
+ threadId: thread.id,
1517
+ role: "assistant",
1518
+ content: actionProposalOutcomeText(outcome),
1519
+ actionProposalOutcome: canonicalActionProposalJson3(outcome),
1520
+ ui: null,
1521
+ seq: Number(seqRows[0]?.last ?? 0) + 1,
1522
+ createdAt: new Date(now)
1523
+ })
1524
+ };
1525
+ yield {
1526
+ kind: "write",
1527
+ query: db.update(tables.agentThread).set({
1528
+ updatedAt: new Date(now)
1529
+ }).where(eq(tables.agentThread.id, thread.id))
1530
+ };
1531
+ const admitted = {
1532
+ ...proposal,
1533
+ outcomeDelivery: {
1534
+ ...delivery,
1535
+ status: "admitted",
1536
+ lease: null,
1537
+ messageId
1538
+ },
1539
+ updatedAt: now
1540
+ };
1541
+ const update = db.update(table).set({
1542
+ proposal: admitted,
1543
+ ...discoveryMetadata(admitted),
1544
+ version: row.version + 1
1545
+ }).where(and(eq(table.id, row.id), eq(table.version, row.version)));
1546
+ const changed = yield {
1547
+ kind: "read",
1548
+ query: this.dialect === "mysql" ? update : update.returning({
1549
+ id: table.id
1550
+ })
1551
+ };
1552
+ const count3 = this.dialect === "mysql" ? mysqlAffectedRows(changed) : changed.length;
1553
+ if (count3 !== 1) throw new Error("Outcome admission lost its locked proposal fence");
1554
+ return {
1555
+ status: "applied",
1556
+ messageId
1557
+ };
1558
+ }
1559
+ async read(scope, id) {
1560
+ const [row] = await this.db.select().from(this.table).where(and(eq(this.table.id, physicalId(id)), eq(this.table.scopeKey, scopeKey(scope)))).limit(1);
1561
+ return row && row.proposal.id === id && actionProposalScopeMatches(row.proposal, scope) ? row : void 0;
1562
+ }
1563
+ async mutate(scope, id, transition) {
1564
+ for (let attempt = 0; attempt < 32; attempt++) {
1565
+ const row2 = await this.read(scope, id);
1566
+ if (!row2) return {
1567
+ status: "not_found"
1568
+ };
1569
+ const result = transition(row2.proposal, this.clock());
1570
+ if (!result.proposal || canonicalActionProposalJson3(result.proposal) === canonicalActionProposalJson3(row2.proposal)) return result;
1571
+ const changed = await affectedRows(this.dialect, this.db.update(this.table).set({
1572
+ proposal: result.proposal,
1573
+ decision: result.proposal.decision,
1574
+ ...discoveryMetadata(result.proposal),
1575
+ version: row2.version + 1
1576
+ }).where(and(eq(this.table.id, physicalId(id)), eq(this.table.scopeKey, scopeKey(scope)), eq(this.table.version, row2.version))), this.table.id);
1577
+ if (changed === 1) return result;
1578
+ }
1579
+ const row = await this.read(scope, id);
1580
+ return row ? {
1581
+ status: "conflict",
1582
+ proposal: row.proposal
1583
+ } : {
1584
+ status: "not_found"
1585
+ };
1586
+ }
1587
+ };
1588
+ function scopeKey(scope) {
1589
+ return createHash("sha256").update(canonicalActionProposalJson3([
1590
+ scope.tenantRef,
1591
+ scope.actorRef,
1592
+ scope.threadId
1593
+ ])).digest("hex");
1594
+ }
1595
+ __name(scopeKey, "scopeKey");
1596
+ function physicalId(id) {
1597
+ return createHash("sha256").update(canonicalActionProposalJson3(id)).digest("hex");
1598
+ }
1599
+ __name(physicalId, "physicalId");
1600
+ function logicalSort(id) {
1601
+ let sort = "";
1602
+ for (let index4 = 0; index4 < id.length; index4++) sort += id.charCodeAt(index4).toString(16).padStart(4, "0");
1603
+ return sort;
1604
+ }
1605
+ __name(logicalSort, "logicalSort");
1606
+ function discoveryMetadata(proposal) {
1607
+ return {
1608
+ replacementGroupKey: replacementGroupKey(proposal),
1609
+ deliveryStatus: proposal.outcomeDelivery?.status ?? null,
1610
+ deliveryLeaseExpiresAt: proposal.outcomeDelivery?.lease?.expiresAt ?? null,
1611
+ outcomeIdKey: proposal.outcome ? physicalId(proposal.outcome.id) : null,
1612
+ executionStatus: proposal.execution?.status ?? null,
1613
+ leaseExpiresAt: proposal.execution?.lease?.expiresAt ?? null,
1614
+ proposalExpiresAt: proposal.expiresAt,
1615
+ discoveryIndexVersion: 1
1616
+ };
1617
+ }
1618
+ __name(discoveryMetadata, "discoveryMetadata");
1619
+ function lockQuery(query, dialect) {
1620
+ return dialect === "sqlite" ? query : query.for("update");
1621
+ }
1622
+ __name(lockQuery, "lockQuery");
1623
+ function runSync(steps) {
1624
+ let next = steps.next();
1625
+ while (!next.done) {
1626
+ const { kind, query } = next.value;
1627
+ const statement = query;
1628
+ next = steps.next(kind === "read" ? statement.all() : statement.run());
1629
+ }
1630
+ return next.value;
1631
+ }
1632
+ __name(runSync, "runSync");
1633
+ async function runAsync(steps) {
1634
+ let next = steps.next();
1635
+ while (!next.done) next = steps.next(await next.value.query);
1636
+ return next.value;
1637
+ }
1638
+ __name(runAsync, "runAsync");
1639
+ function replacementGroupKey(proposal) {
1640
+ return proposal.replacementKey ? physicalId(canonicalActionProposalJson3([
1641
+ proposal.toolName,
1642
+ proposal.replacementKey
1643
+ ])) : null;
1644
+ }
1645
+ __name(replacementGroupKey, "replacementGroupKey");
1646
+
1647
+ // src/drizzle-agent-store.ts
1005
1648
  function turnMessageColumns(message) {
1006
1649
  return {
1007
1650
  id: message.id,
@@ -1022,11 +1665,61 @@ var DrizzleAgentStore = class {
1022
1665
  db;
1023
1666
  dialect;
1024
1667
  t;
1025
- constructor(db) {
1668
+ proposals;
1669
+ constructor(db, options = {}) {
1670
+ this.proposals = new DrizzleActionProposalStore(db, options);
1026
1671
  this.dialect = agentDialectOf(db);
1027
1672
  this.t = agentTablesFor(this.dialect);
1028
1673
  this.db = asBuilder(db);
1029
1674
  }
1675
+ createActionProposal(...args) {
1676
+ return this.proposals.createActionProposal(...args);
1677
+ }
1678
+ getActionProposal(...args) {
1679
+ return this.proposals.getActionProposal(...args);
1680
+ }
1681
+ listActionProposals(...args) {
1682
+ return this.proposals.listActionProposals(...args);
1683
+ }
1684
+ decideActionProposal(...args) {
1685
+ return this.proposals.decideActionProposal(...args);
1686
+ }
1687
+ claimActionProposal(...args) {
1688
+ return this.proposals.claimActionProposal(...args);
1689
+ }
1690
+ extendActionProposalLease(...args) {
1691
+ return this.proposals.extendActionProposalLease(...args);
1692
+ }
1693
+ claimNextActionProposal(...args) {
1694
+ return this.proposals.claimNextActionProposal(...args);
1695
+ }
1696
+ expireActionProposals(...args) {
1697
+ return this.proposals.expireActionProposals(...args);
1698
+ }
1699
+ backfillActionProposalDiscoveryIndex(command) {
1700
+ return this.proposals.backfillActionProposalDiscoveryIndex(command);
1701
+ }
1702
+ settleActionProposal(...args) {
1703
+ return this.proposals.settleActionProposal(...args);
1704
+ }
1705
+ createReplacingActionProposal(...args) {
1706
+ return this.proposals.createReplacingActionProposal(...args);
1707
+ }
1708
+ supersedeActionProposal(...args) {
1709
+ return this.proposals.supersedeActionProposal(...args);
1710
+ }
1711
+ get actionProposalAdmissionSupported() {
1712
+ return this.proposals.actionProposalAdmissionSupported;
1713
+ }
1714
+ getThreadActionProposalScope(threadId) {
1715
+ return this.proposals.getThreadActionProposalScope(threadId);
1716
+ }
1717
+ claimNextActionProposalOutcome(...args) {
1718
+ return this.proposals.claimNextActionProposalOutcome(...args);
1719
+ }
1720
+ admitActionProposalOutcome(...args) {
1721
+ return this.proposals.admitActionProposalOutcome(...args);
1722
+ }
1030
1723
  async createThread(input) {
1031
1724
  const now = /* @__PURE__ */ new Date();
1032
1725
  const thread = {
@@ -1048,11 +1741,11 @@ var DrizzleAgentStore = class {
1048
1741
  return this.toSummary(thread);
1049
1742
  }
1050
1743
  async getThread(threadId) {
1051
- const [thread] = await this.db.select().from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
1744
+ const [thread] = await this.db.select().from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1052
1745
  if (thread === void 0) {
1053
1746
  return null;
1054
1747
  }
1055
- const messages = await this.db.select().from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1748
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1056
1749
  const last = messages[messages.length - 1];
1057
1750
  const approvals = await this.approvalsFor(messages.map((message) => message.id));
1058
1751
  return {
@@ -1087,14 +1780,14 @@ var DrizzleAgentStore = class {
1087
1780
  const [thread] = await this.db.select({
1088
1781
  title: this.t.agentThread.title,
1089
1782
  defaultAgent: this.t.agentThread.defaultAgent
1090
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, query.threadId), isNull(this.t.agentThread.deletedAt)));
1783
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, query.threadId), isNull2(this.t.agentThread.deletedAt)));
1091
1784
  if (thread === void 0) {
1092
1785
  return null;
1093
1786
  }
1094
1787
  const messages = await this.loadTurnWindow(query.threadId, query.messageLimit);
1095
1788
  const [answered] = await this.db.select({
1096
1789
  id: this.t.agentMessage.id
1097
- }).from(this.t.agentMessage).where(and(eq(this.t.agentMessage.threadId, query.threadId), eq(this.t.agentMessage.role, "assistant"))).limit(1);
1790
+ }).from(this.t.agentMessage).where(and2(eq2(this.t.agentMessage.threadId, query.threadId), eq2(this.t.agentMessage.role, "assistant"))).limit(1);
1098
1791
  return {
1099
1792
  title: thread.title,
1100
1793
  defaultAgent: thread.defaultAgent,
@@ -1110,15 +1803,15 @@ var DrizzleAgentStore = class {
1110
1803
  if (limit !== void 0 && limit <= 0) {
1111
1804
  return [];
1112
1805
  }
1113
- const window = this.db.select(turnMessageColumns(this.t.agentMessage)).from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrderNewestFirst());
1806
+ const window = this.db.select(turnMessageColumns(this.t.agentMessage)).from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrderNewestFirst());
1114
1807
  const rows = limit === void 0 ? await window : await window.limit(limit);
1115
1808
  return rows.reverse().map((row) => this.toStoredMessage(row));
1116
1809
  }
1117
1810
  async listThreads(actorRef, limit = 50) {
1118
- const threads = await this.db.select().from(this.t.agentThread).where(and(eq(this.t.agentThread.actorRef, actorRef), eq(this.t.agentThread.transient, false), isNull(this.t.agentThread.deletedAt))).orderBy(desc(this.t.agentThread.updatedAt)).limit(limit);
1811
+ 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);
1119
1812
  const summaries = [];
1120
1813
  for (const thread of threads) {
1121
- const [last] = await this.db.select().from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, thread.id)).orderBy(...this.messageOrderNewestFirst()).limit(1);
1814
+ const [last] = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, thread.id)).orderBy(...this.messageOrderNewestFirst()).limit(1);
1122
1815
  summaries.push(this.toSummary(thread, last?.content));
1123
1816
  }
1124
1817
  return summaries;
@@ -1126,14 +1819,14 @@ var DrizzleAgentStore = class {
1126
1819
  async softDeleteThread(threadId) {
1127
1820
  await this.db.update(this.t.agentThread).set({
1128
1821
  deletedAt: /* @__PURE__ */ new Date()
1129
- }).where(eq(this.t.agentThread.id, threadId));
1822
+ }).where(eq2(this.t.agentThread.id, threadId));
1130
1823
  }
1131
1824
  async forkThread(threadId, fromMessageId) {
1132
- const [source] = await this.db.select().from(this.t.agentThread).where(eq(this.t.agentThread.id, threadId));
1825
+ const [source] = await this.db.select().from(this.t.agentThread).where(eq2(this.t.agentThread.id, threadId));
1133
1826
  if (source === void 0) {
1134
1827
  throw new Error(`thread ${threadId} not found`);
1135
1828
  }
1136
- const messages = await this.db.select().from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1829
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1137
1830
  const cutoff = messages.findIndex((message) => message.id === fromMessageId);
1138
1831
  const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;
1139
1832
  const now = /* @__PURE__ */ new Date();
@@ -1176,6 +1869,7 @@ var DrizzleAgentStore = class {
1176
1869
  reasoning: message.reasoning,
1177
1870
  reasoningMs: message.reasoningMs,
1178
1871
  ui: message.ui,
1872
+ actionProposalOutcome: message.actionProposalOutcome,
1179
1873
  createdAt: message.createdAt
1180
1874
  })));
1181
1875
  }
@@ -1184,20 +1878,20 @@ var DrizzleAgentStore = class {
1184
1878
  async ownerOfThread(threadId) {
1185
1879
  const [thread] = await this.db.select({
1186
1880
  actorRef: this.t.agentThread.actorRef
1187
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
1881
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1188
1882
  return thread?.actorRef ?? null;
1189
1883
  }
1190
1884
  async ownerOfToolCall(toolCallId) {
1191
1885
  const [row] = await this.db.select({
1192
1886
  actorRef: this.t.agentThread.actorRef
1193
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq(this.t.agentMessage.threadId, this.t.agentThread.id)).where(eq(this.t.agentToolCall.id, toolCallId));
1887
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq2(this.t.agentMessage.threadId, this.t.agentThread.id)).where(eq2(this.t.agentToolCall.id, toolCallId));
1194
1888
  return row?.actorRef ?? null;
1195
1889
  }
1196
1890
  async runForToolCall(toolCallId) {
1197
1891
  const [row] = await this.db.select({
1198
1892
  runId: this.t.agentToolCall.runId,
1199
1893
  activeStreamId: this.t.agentThread.activeStreamId
1200
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq(this.t.agentMessage.threadId, this.t.agentThread.id)).where(eq(this.t.agentToolCall.id, toolCallId));
1894
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq2(this.t.agentMessage.threadId, this.t.agentThread.id)).where(eq2(this.t.agentToolCall.id, toolCallId));
1201
1895
  return row?.runId ?? row?.activeStreamId ?? null;
1202
1896
  }
1203
1897
  /**
@@ -1215,12 +1909,13 @@ var DrizzleAgentStore = class {
1215
1909
  messageId: this.t.agentToolCall.messageId,
1216
1910
  status: this.t.agentToolCall.status,
1217
1911
  approver: this.t.agentToolCall.approver,
1912
+ confirmation: this.t.agentToolCall.confirmation,
1218
1913
  expiresAt: this.t.agentToolCall.expiresAt,
1219
1914
  remember: this.t.agentToolCall.remember,
1220
1915
  executedByRef: this.t.agentToolCall.executedByRef,
1221
1916
  decidedVia: this.t.agentToolCall.decidedVia,
1222
1917
  error: this.t.agentToolCall.error
1223
- }).from(this.t.agentToolCall).where(and(inArray(this.t.agentToolCall.messageId, messageIds), isNotNull(this.t.agentToolCall.approver))).orderBy(asc(this.t.agentToolCall.createdAt), asc(this.t.agentToolCall.id));
1918
+ }).from(this.t.agentToolCall).where(and2(inArray(this.t.agentToolCall.messageId, messageIds), isNotNull(this.t.agentToolCall.approver))).orderBy(asc2(this.t.agentToolCall.createdAt), asc2(this.t.agentToolCall.id));
1224
1919
  for (const row of rows) {
1225
1920
  const approval = toolCallApprovalFromRow({
1226
1921
  ...row,
@@ -1239,13 +1934,20 @@ var DrizzleAgentStore = class {
1239
1934
  async rememberedApprovals(threadId) {
1240
1935
  const rows = await this.db.selectDistinct({
1241
1936
  toolName: this.t.agentToolCall.toolName
1242
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(and(eq(this.t.agentMessage.threadId, threadId), eq(this.t.agentToolCall.remember, true)));
1243
- return rows.map((row) => row.toolName);
1937
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(and2(eq2(this.t.agentMessage.threadId, threadId), eq2(this.t.agentToolCall.remember, true)));
1938
+ const scope = await this.getThreadActionProposalScope(threadId);
1939
+ const proposalNames = scope ? await this.proposals.rememberedActionProposalApprovals(scope) : [];
1940
+ return [
1941
+ .../* @__PURE__ */ new Set([
1942
+ ...rows.map((row) => row.toolName),
1943
+ ...proposalNames
1944
+ ])
1945
+ ];
1244
1946
  }
1245
1947
  async toolCallInput(toolCallId) {
1246
1948
  const [row] = await this.db.select({
1247
1949
  input: this.t.agentToolCall.input
1248
- }).from(this.t.agentToolCall).where(eq(this.t.agentToolCall.id, toolCallId));
1950
+ }).from(this.t.agentToolCall).where(eq2(this.t.agentToolCall.id, toolCallId));
1249
1951
  return row?.input ?? null;
1250
1952
  }
1251
1953
  async toolCallApproval(toolCallId) {
@@ -1253,7 +1955,7 @@ var DrizzleAgentStore = class {
1253
1955
  status: this.t.agentToolCall.status,
1254
1956
  approver: this.t.agentToolCall.approver,
1255
1957
  expiresAt: this.t.agentToolCall.expiresAt
1256
- }).from(this.t.agentToolCall).where(eq(this.t.agentToolCall.id, toolCallId));
1958
+ }).from(this.t.agentToolCall).where(eq2(this.t.agentToolCall.id, toolCallId));
1257
1959
  if (row === void 0) {
1258
1960
  return null;
1259
1961
  }
@@ -1266,26 +1968,26 @@ var DrizzleAgentStore = class {
1266
1968
  async ownerOfActiveStream(runId) {
1267
1969
  const [thread] = await this.db.select({
1268
1970
  actorRef: this.t.agentThread.actorRef
1269
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.activeStreamId, runId), isNull(this.t.agentThread.deletedAt)));
1971
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.activeStreamId, runId), isNull2(this.t.agentThread.deletedAt)));
1270
1972
  return thread?.actorRef ?? null;
1271
1973
  }
1272
1974
  async setTitle(threadId, title) {
1273
1975
  await this.db.update(this.t.agentThread).set({
1274
1976
  title,
1275
1977
  updatedAt: /* @__PURE__ */ new Date()
1276
- }).where(eq(this.t.agentThread.id, threadId));
1978
+ }).where(eq2(this.t.agentThread.id, threadId));
1277
1979
  }
1278
1980
  async promoteThread(threadId) {
1279
1981
  await this.db.update(this.t.agentThread).set({
1280
1982
  transient: false,
1281
1983
  updatedAt: /* @__PURE__ */ new Date()
1282
- }).where(and(eq(this.t.agentThread.id, threadId), eq(this.t.agentThread.transient, true)));
1984
+ }).where(and2(eq2(this.t.agentThread.id, threadId), eq2(this.t.agentThread.transient, true)));
1283
1985
  }
1284
1986
  /** Who holds the thread's stream right now, deleted or not. */
1285
1987
  async activeHolder(threadId) {
1286
1988
  const [thread] = await this.db.select({
1287
1989
  activeStreamId: this.t.agentThread.activeStreamId
1288
- }).from(this.t.agentThread).where(eq(this.t.agentThread.id, threadId));
1990
+ }).from(this.t.agentThread).where(eq2(this.t.agentThread.id, threadId));
1289
1991
  return thread?.activeStreamId ?? null;
1290
1992
  }
1291
1993
  /**
@@ -1297,16 +1999,16 @@ var DrizzleAgentStore = class {
1297
1999
  messageOrder() {
1298
2000
  const message = this.t.agentMessage;
1299
2001
  return [
1300
- asc(sql2`coalesce(${message.seq}, 0)`),
1301
- asc(message.createdAt),
1302
- asc(message.id)
2002
+ asc2(sql3`coalesce(${message.seq}, 0)`),
2003
+ asc2(message.createdAt),
2004
+ asc2(message.id)
1303
2005
  ];
1304
2006
  }
1305
2007
  /** {@link messageOrder}, newest first. */
1306
2008
  messageOrderNewestFirst() {
1307
2009
  const message = this.t.agentMessage;
1308
2010
  return [
1309
- desc(sql2`coalesce(${message.seq}, 0)`),
2011
+ desc(sql3`coalesce(${message.seq}, 0)`),
1310
2012
  desc(message.createdAt),
1311
2013
  desc(message.id)
1312
2014
  ];
@@ -1317,15 +2019,15 @@ var DrizzleAgentStore = class {
1317
2019
  */
1318
2020
  async nextMessageSeq(threadId) {
1319
2021
  const [row] = await this.db.select({
1320
- last: max(this.t.agentMessage.seq)
1321
- }).from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId));
2022
+ last: max2(this.t.agentMessage.seq)
2023
+ }).from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId));
1322
2024
  return Number(row?.last ?? 0) + 1;
1323
2025
  }
1324
2026
  /** The run streaming the thread, or `null` — a projection of the one column. */
1325
2027
  async activeRunForThread(threadId) {
1326
2028
  const [thread] = await this.db.select({
1327
2029
  activeStreamId: this.t.agentThread.activeStreamId
1328
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2030
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1329
2031
  return thread?.activeStreamId ?? null;
1330
2032
  }
1331
2033
  /**
@@ -1334,15 +2036,15 @@ var DrizzleAgentStore = class {
1334
2036
  */
1335
2037
  async claimActiveStream(threadId, runId, options = {}) {
1336
2038
  const holders = [
1337
- isNull(this.t.agentThread.activeStreamId),
1338
- eq(this.t.agentThread.activeStreamId, runId),
2039
+ isNull2(this.t.agentThread.activeStreamId),
2040
+ eq2(this.t.agentThread.activeStreamId, runId),
1339
2041
  ...options.replacing !== void 0 ? [
1340
- eq(this.t.agentThread.activeStreamId, options.replacing)
2042
+ eq2(this.t.agentThread.activeStreamId, options.replacing)
1341
2043
  ] : []
1342
2044
  ];
1343
2045
  const claimed = await affectedRows(this.dialect, this.db.update(this.t.agentThread).set({
1344
2046
  activeStreamId: runId
1345
- }).where(and(eq(this.t.agentThread.id, threadId), or(...holders))), this.t.agentThread.id);
2047
+ }).where(and2(eq2(this.t.agentThread.id, threadId), or2(...holders))), this.t.agentThread.id);
1346
2048
  if (claimed > 0) {
1347
2049
  return true;
1348
2050
  }
@@ -1351,21 +2053,22 @@ var DrizzleAgentStore = class {
1351
2053
  async releaseActiveStream(threadId, runId) {
1352
2054
  const released = await affectedRows(this.dialect, this.db.update(this.t.agentThread).set({
1353
2055
  activeStreamId: null
1354
- }).where(and(eq(this.t.agentThread.id, threadId), eq(this.t.agentThread.activeStreamId, runId))), this.t.agentThread.id);
2056
+ }).where(and2(eq2(this.t.agentThread.id, threadId), eq2(this.t.agentThread.activeStreamId, runId))), this.t.agentThread.id);
1355
2057
  return released > 0;
1356
2058
  }
1357
2059
  async enqueueMessage(input) {
1358
2060
  const now = /* @__PURE__ */ new Date();
1359
2061
  const [edge] = await this.db.select({
1360
2062
  first: min(this.t.agentQueuedMessage.position),
1361
- last: max(this.t.agentQueuedMessage.position)
1362
- }).from(this.t.agentQueuedMessage).where(eq(this.t.agentQueuedMessage.threadId, input.threadId));
2063
+ last: max2(this.t.agentQueuedMessage.position)
2064
+ }).from(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.threadId, input.threadId));
1363
2065
  const position = input.at === "head" ? (edge?.first ?? 1) - 1 : (edge?.last ?? -1) + 1;
1364
2066
  const row = {
1365
2067
  id: crypto.randomUUID(),
1366
2068
  threadId: input.threadId,
1367
2069
  actor: input.actor,
1368
2070
  content: input.content,
2071
+ uiCapabilities: input.uiCapabilities ?? null,
1369
2072
  attachments: input.attachments !== void 0 && input.attachments.length > 0 ? input.attachments : null,
1370
2073
  agentName: input.agentName ?? null,
1371
2074
  persona: input.persona ?? null,
@@ -1380,11 +2083,11 @@ var DrizzleAgentStore = class {
1380
2083
  return toQueuedMessage(row);
1381
2084
  }
1382
2085
  async listQueue(threadId) {
1383
- const rows = await this.db.select().from(this.t.agentQueuedMessage).where(eq(this.t.agentQueuedMessage.threadId, threadId)).orderBy(asc(this.t.agentQueuedMessage.position), asc(this.t.agentQueuedMessage.createdAt));
2086
+ const rows = await this.db.select().from(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.threadId, threadId)).orderBy(asc2(this.t.agentQueuedMessage.position), asc2(this.t.agentQueuedMessage.createdAt));
1384
2087
  return rows.map(toQueuedMessage);
1385
2088
  }
1386
2089
  async getQueuedMessage(id) {
1387
- const [row] = await this.db.select().from(this.t.agentQueuedMessage).where(eq(this.t.agentQueuedMessage.id, id));
2090
+ const [row] = await this.db.select().from(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.id, id));
1388
2091
  return row === void 0 ? null : toQueuedMessage(row);
1389
2092
  }
1390
2093
  async updateQueuedMessage(id, patch) {
@@ -1400,7 +2103,7 @@ var DrizzleAgentStore = class {
1400
2103
  if (patch.interrupt !== void 0) {
1401
2104
  updates.interrupt = patch.interrupt;
1402
2105
  }
1403
- await this.db.update(this.t.agentQueuedMessage).set(updates).where(eq(this.t.agentQueuedMessage.id, id));
2106
+ await this.db.update(this.t.agentQueuedMessage).set(updates).where(eq2(this.t.agentQueuedMessage.id, id));
1404
2107
  return this.getQueuedMessage(id);
1405
2108
  }
1406
2109
  /** Rewrites the thread's positions as 0..n-1 in the new order — a queue is a handful of rows. */
@@ -1415,32 +2118,32 @@ var DrizzleAgentStore = class {
1415
2118
  for (const [position, message] of order.entries()) {
1416
2119
  await this.db.update(this.t.agentQueuedMessage).set({
1417
2120
  position
1418
- }).where(eq(this.t.agentQueuedMessage.id, message.id));
2121
+ }).where(eq2(this.t.agentQueuedMessage.id, message.id));
1419
2122
  }
1420
2123
  return true;
1421
2124
  }
1422
2125
  async removeQueuedMessage(id) {
1423
- const removed = await affectedRows(this.dialect, this.db.delete(this.t.agentQueuedMessage).where(eq(this.t.agentQueuedMessage.id, id)), this.t.agentQueuedMessage.id);
2126
+ const removed = await affectedRows(this.dialect, this.db.delete(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.id, id)), this.t.agentQueuedMessage.id);
1424
2127
  return removed > 0;
1425
2128
  }
1426
2129
  async clearQueue(threadId) {
1427
- return affectedRows(this.dialect, this.db.delete(this.t.agentQueuedMessage).where(eq(this.t.agentQueuedMessage.threadId, threadId)), this.t.agentQueuedMessage.id);
2130
+ return affectedRows(this.dialect, this.db.delete(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.threadId, threadId)), this.t.agentQueuedMessage.id);
1428
2131
  }
1429
2132
  async queuePause(threadId) {
1430
2133
  const [thread] = await this.db.select({
1431
2134
  queuePause: this.t.agentThread.queuePause
1432
- }).from(this.t.agentThread).where(eq(this.t.agentThread.id, threadId));
2135
+ }).from(this.t.agentThread).where(eq2(this.t.agentThread.id, threadId));
1433
2136
  return thread?.queuePause ?? null;
1434
2137
  }
1435
2138
  async setQueuePause(threadId, pause) {
1436
2139
  await this.db.update(this.t.agentThread).set({
1437
2140
  queuePause: pause
1438
- }).where(eq(this.t.agentThread.id, threadId));
2141
+ }).where(eq2(this.t.agentThread.id, threadId));
1439
2142
  }
1440
2143
  async setActiveStream(threadId, runId) {
1441
2144
  await this.db.update(this.t.agentThread).set({
1442
2145
  activeStreamId: runId
1443
- }).where(eq(this.t.agentThread.id, threadId));
2146
+ }).where(eq2(this.t.agentThread.id, threadId));
1444
2147
  }
1445
2148
  /**
1446
2149
  * Patch a thread's `title` and/or `defaultAgent`. Each field is only touched when PRESENT in
@@ -1466,7 +2169,7 @@ var DrizzleAgentStore = class {
1466
2169
  return;
1467
2170
  }
1468
2171
  updates.updatedAt = /* @__PURE__ */ new Date();
1469
- await this.db.update(this.t.agentThread).set(updates).where(eq(this.t.agentThread.id, threadId));
2172
+ await this.db.update(this.t.agentThread).set(updates).where(eq2(this.t.agentThread.id, threadId));
1470
2173
  }
1471
2174
  /**
1472
2175
  * The thread's default agent, projected — the caller wants one nullable scalar to decide which
@@ -1477,20 +2180,20 @@ var DrizzleAgentStore = class {
1477
2180
  async modelForThread(threadId) {
1478
2181
  const [thread] = await this.db.select({
1479
2182
  model: this.t.agentThread.model
1480
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2183
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1481
2184
  return thread?.model ?? null;
1482
2185
  }
1483
2186
  /** The thread's pinned persona, projected like {@link defaultAgentForThread}. */
1484
2187
  async personaForThread(threadId) {
1485
2188
  const [thread] = await this.db.select({
1486
2189
  persona: this.t.agentThread.persona
1487
- }).from(agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2190
+ }).from(agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1488
2191
  return thread?.persona ?? null;
1489
2192
  }
1490
2193
  async defaultAgentForThread(threadId) {
1491
2194
  const [thread] = await this.db.select({
1492
2195
  defaultAgent: this.t.agentThread.defaultAgent
1493
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2196
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1494
2197
  return thread?.defaultAgent ?? null;
1495
2198
  }
1496
2199
  /**
@@ -1532,16 +2235,16 @@ var DrizzleAgentStore = class {
1532
2235
  if (end.errorMessage !== void 0) {
1533
2236
  updates.errorMessage = end.errorMessage;
1534
2237
  }
1535
- await this.db.update(this.t.agentRun).set(updates).where(eq(this.t.agentRun.id, end.runId));
2238
+ await this.db.update(this.t.agentRun).set(updates).where(eq2(this.t.agentRun.id, end.runId));
1536
2239
  }
1537
2240
  /** Bump the run's llm-step retry counter. Atomic `retries = retries + 1`, no read-modify-write. */
1538
2241
  async bumpRunRetries(runId) {
1539
2242
  await this.db.update(this.t.agentRun).set({
1540
- retries: sql2`${this.t.agentRun.retries} + 1`
1541
- }).where(eq(this.t.agentRun.id, runId));
2243
+ retries: sql3`${this.t.agentRun.retries} + 1`
2244
+ }).where(eq2(this.t.agentRun.id, runId));
1542
2245
  }
1543
2246
  async appendMessage(input) {
1544
- const [thread] = await this.db.select().from(this.t.agentThread).where(eq(this.t.agentThread.id, input.threadId));
2247
+ const [thread] = await this.db.select().from(this.t.agentThread).where(eq2(this.t.agentThread.id, input.threadId));
1545
2248
  if (thread === void 0) {
1546
2249
  throw new Error(`thread ${input.threadId} not found`);
1547
2250
  }
@@ -1551,6 +2254,7 @@ var DrizzleAgentStore = class {
1551
2254
  threadId: input.threadId,
1552
2255
  role: input.role,
1553
2256
  content: input.content,
2257
+ actionProposalOutcome: input.actionProposalOutcome ? canonicalActionProposalJson4(input.actionProposalOutcome) : null,
1554
2258
  toolCalls: input.toolCalls ?? null,
1555
2259
  toolResults: input.toolResults ?? null,
1556
2260
  attachments: input.attachments ?? null,
@@ -1569,32 +2273,32 @@ var DrizzleAgentStore = class {
1569
2273
  await this.db.insert(this.t.agentMessage).values(message);
1570
2274
  await this.db.update(this.t.agentThread).set({
1571
2275
  updatedAt: now
1572
- }).where(eq(this.t.agentThread.id, input.threadId));
2276
+ }).where(eq2(this.t.agentThread.id, input.threadId));
1573
2277
  return this.toStoredMessage(message);
1574
2278
  }
1575
2279
  async setMessageToolResults(messageId, results) {
1576
2280
  await this.db.update(this.t.agentMessage).set({
1577
2281
  toolResults: results
1578
- }).where(eq(this.t.agentMessage.id, messageId));
2282
+ }).where(eq2(this.t.agentMessage.id, messageId));
1579
2283
  }
1580
2284
  async setMessageUi(messageId, ui) {
1581
2285
  await this.db.update(this.t.agentMessage).set({
1582
2286
  ui: ui.length > 0 ? ui : null
1583
- }).where(eq(this.t.agentMessage.id, messageId));
2287
+ }).where(eq2(this.t.agentMessage.id, messageId));
1584
2288
  }
1585
2289
  async threadOfMessage(messageId) {
1586
2290
  const [row] = await this.db.select({
1587
2291
  threadId: this.t.agentMessage.threadId
1588
- }).from(this.t.agentMessage).where(eq(this.t.agentMessage.id, messageId)).limit(1);
2292
+ }).from(this.t.agentMessage).where(eq2(this.t.agentMessage.id, messageId)).limit(1);
1589
2293
  return row?.threadId ?? null;
1590
2294
  }
1591
2295
  async setMessageFeedback(messageId, feedback) {
1592
2296
  await this.db.update(this.t.agentMessage).set({
1593
2297
  feedback
1594
- }).where(eq(this.t.agentMessage.id, messageId));
2298
+ }).where(eq2(this.t.agentMessage.id, messageId));
1595
2299
  }
1596
2300
  async truncateFrom(threadId, messageId) {
1597
- const messages = await this.db.select().from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
2301
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1598
2302
  const cutoff = messages.findIndex((message) => message.id === messageId);
1599
2303
  if (cutoff < 0) {
1600
2304
  return;
@@ -1606,6 +2310,7 @@ var DrizzleAgentStore = class {
1606
2310
  async recordToolCall(input) {
1607
2311
  await this.db.insert(this.t.agentToolCall).values({
1608
2312
  id: input.toolCallId,
2313
+ proposalId: input.proposalId ?? null,
1609
2314
  messageId: input.messageId,
1610
2315
  toolName: input.toolName,
1611
2316
  toolType: input.toolType,
@@ -1619,6 +2324,7 @@ var DrizzleAgentStore = class {
1619
2324
  executedAt: null,
1620
2325
  runId: input.runId ?? null,
1621
2326
  approver: input.approver ?? null,
2327
+ confirmation: input.confirmation ?? null,
1622
2328
  expiresAt: input.expiresAt !== void 0 ? new Date(input.expiresAt) : null,
1623
2329
  remember: null,
1624
2330
  decidedVia: null
@@ -1649,7 +2355,7 @@ var DrizzleAgentStore = class {
1649
2355
  if (input.status === "executed" || input.status === "auto_executed") {
1650
2356
  updates.executedAt = /* @__PURE__ */ new Date();
1651
2357
  }
1652
- await this.db.update(this.t.agentToolCall).set(updates).where(eq(this.t.agentToolCall.id, input.toolCallId));
2358
+ await this.db.update(this.t.agentToolCall).set(updates).where(eq2(this.t.agentToolCall.id, input.toolCallId));
1653
2359
  }
1654
2360
  async toolCallOutcomes(toolCallIds) {
1655
2361
  if (toolCallIds.length === 0) {
@@ -1675,7 +2381,7 @@ var DrizzleAgentStore = class {
1675
2381
  }));
1676
2382
  }
1677
2383
  async failUnsettledToolCalls(runId, error) {
1678
- const pending = and(eq(this.t.agentToolCall.runId, runId), eq(this.t.agentToolCall.status, "pending_approval"));
2384
+ const pending = and2(eq2(this.t.agentToolCall.runId, runId), eq2(this.t.agentToolCall.status, "pending_approval"));
1679
2385
  const rows = await this.db.select({
1680
2386
  id: this.t.agentToolCall.id
1681
2387
  }).from(this.t.agentToolCall).where(pending);
@@ -1708,10 +2414,10 @@ var DrizzleAgentStore = class {
1708
2414
  }
1709
2415
  const rows = await this.db.select({
1710
2416
  attachments: this.t.agentMessage.attachments
1711
- }).from(this.t.agentMessage).innerJoin(this.t.agentThread, eq(this.t.agentMessage.threadId, this.t.agentThread.id)).where(and(eq(this.t.agentThread.actorRef, actorRef), isNotNull(this.t.agentMessage.attachments)));
2417
+ }).from(this.t.agentMessage).innerJoin(this.t.agentThread, eq2(this.t.agentMessage.threadId, this.t.agentThread.id)).where(and2(eq2(this.t.agentThread.actorRef, actorRef), isNotNull(this.t.agentMessage.attachments)));
1712
2418
  const queued = await this.db.select({
1713
2419
  attachments: this.t.agentQueuedMessage.attachments
1714
- }).from(this.t.agentQueuedMessage).innerJoin(this.t.agentThread, eq(this.t.agentQueuedMessage.threadId, this.t.agentThread.id)).where(and(eq(this.t.agentThread.actorRef, actorRef), isNotNull(this.t.agentQueuedMessage.attachments)));
2420
+ }).from(this.t.agentQueuedMessage).innerJoin(this.t.agentThread, eq2(this.t.agentQueuedMessage.threadId, this.t.agentThread.id)).where(and2(eq2(this.t.agentThread.actorRef, actorRef), isNotNull(this.t.agentQueuedMessage.attachments)));
1715
2421
  const wanted = new Set(mediaIds);
1716
2422
  const found = /* @__PURE__ */ new Set();
1717
2423
  for (const row of [
@@ -1750,7 +2456,7 @@ var DrizzleAgentStore = class {
1750
2456
  async usageBetween(actorRef, fromDay, toDay) {
1751
2457
  const start = /* @__PURE__ */ new Date(`${fromDay}T00:00:00.000Z`);
1752
2458
  const end = /* @__PURE__ */ new Date(`${toDay}T23:59:59.999Z`);
1753
- const rows = await this.db.select().from(this.t.agentTokenUsage).where(and(eq(this.t.agentTokenUsage.actorRef, actorRef), gte(this.t.agentTokenUsage.createdAt, start), lte(this.t.agentTokenUsage.createdAt, end)));
2459
+ 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)));
1754
2460
  const usedTokens = rows.reduce((sum2, row) => sum2 + row.inputTokens + row.outputTokens, 0);
1755
2461
  const costUsd = rows.reduce((sum2, row) => sum2 + (row.costUsd ?? 0), 0);
1756
2462
  return {
@@ -1776,7 +2482,12 @@ var DrizzleAgentStore = class {
1776
2482
  };
1777
2483
  }
1778
2484
  toStoredMessage(message) {
2485
+ const outcome = message.actionProposalOutcome ? JSON.parse(message.actionProposalOutcome) : void 0;
1779
2486
  return {
2487
+ ...outcome ? {
2488
+ actionProposalOutcome: outcome,
2489
+ ui: outcome.ui
2490
+ } : {},
1780
2491
  id: message.id,
1781
2492
  role: message.role,
1782
2493
  content: message.content,
@@ -1822,6 +2533,9 @@ var DrizzleAgentStore = class {
1822
2533
  };
1823
2534
  function toQueuedMessage(row) {
1824
2535
  return {
2536
+ ...row.uiCapabilities !== null ? {
2537
+ uiCapabilities: row.uiCapabilities
2538
+ } : {},
1825
2539
  id: row.id,
1826
2540
  threadId: row.threadId,
1827
2541
  actor: row.actor,
@@ -1852,7 +2566,7 @@ __name(toQueuedMessage, "toQueuedMessage");
1852
2566
 
1853
2567
  // src/drizzle-governance-queries.ts
1854
2568
  import { bucketByActor, bucketByModel, bucketByThread, bucketUsageTrend, dayBoundsUtc, rollupThreadUsage, truncateDetailContent } from "@dudousxd/nestjs-agent-core";
1855
- import { and as and2, asc as asc2, count, desc as desc2, eq as eq2, gte as gte2, inArray as inArray2, isNull as isNull2, like, lte as lte2, sql as sql3, sum } from "drizzle-orm";
2569
+ import { and as and3, asc as asc3, count, desc as desc2, eq as eq3, gte as gte2, inArray as inArray2, isNull as isNull3, like, lte as lte3, sql as sql4, sum } from "drizzle-orm";
1856
2570
  var UNCLASSIFIED_ERROR_CODE = "unknown";
1857
2571
  var DEFAULT_AGENT_BUCKET = "(default)";
1858
2572
  var TOOL_CALL_STATUSES = [
@@ -1990,7 +2704,7 @@ var DrizzleGovernanceQueries = class {
1990
2704
  }
1991
2705
  async usageInRange(range) {
1992
2706
  const { start, end } = dayBoundsUtc(range);
1993
- const rows = await this.db.select().from(this.t.agentTokenUsage).where(and2(gte2(this.t.agentTokenUsage.createdAt, start), lte2(this.t.agentTokenUsage.createdAt, end)));
2707
+ const rows = await this.db.select().from(this.t.agentTokenUsage).where(and3(gte2(this.t.agentTokenUsage.createdAt, start), lte3(this.t.agentTokenUsage.createdAt, end)));
1994
2708
  return rows.map(toUsageInput);
1995
2709
  }
1996
2710
  async spendByModel(range) {
@@ -2015,7 +2729,7 @@ var DrizzleGovernanceQueries = class {
2015
2729
  if (threadIds.length === 0) {
2016
2730
  return [];
2017
2731
  }
2018
- const threads = await this.db.select().from(this.t.agentThread).where(and2(inArray2(this.t.agentThread.id, threadIds), isNull2(this.t.agentThread.deletedAt)));
2732
+ const threads = await this.db.select().from(this.t.agentThread).where(and3(inArray2(this.t.agentThread.id, threadIds), isNull3(this.t.agentThread.deletedAt)));
2019
2733
  const threadsById = new Map(threads.map((thread) => [
2020
2734
  thread.id,
2021
2735
  {
@@ -2041,7 +2755,7 @@ var DrizzleGovernanceQueries = class {
2041
2755
  threadId: this.t.agentMessage.threadId,
2042
2756
  createdAt: this.t.agentToolCall.createdAt,
2043
2757
  runId: this.t.agentToolCall.runId
2044
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).orderBy(desc2(this.t.agentToolCall.createdAt), desc2(this.t.agentToolCall.id)).limit(limit);
2758
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).orderBy(desc2(this.t.agentToolCall.createdAt), desc2(this.t.agentToolCall.id)).limit(limit);
2045
2759
  return rows.map((row) => ({
2046
2760
  toolCallId: row.toolCallId,
2047
2761
  toolName: row.toolName,
@@ -2107,12 +2821,12 @@ var DrizzleGovernanceQueries = class {
2107
2821
  });
2108
2822
  }
2109
2823
  async recentThreads(limit) {
2110
- const threads = await this.db.select().from(this.t.agentThread).where(isNull2(this.t.agentThread.deletedAt)).orderBy(desc2(this.t.agentThread.updatedAt), desc2(this.t.agentThread.id)).limit(limit);
2824
+ 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);
2111
2825
  return this.toThreadActivityRows(threads);
2112
2826
  }
2113
2827
  async runsInRange(range) {
2114
2828
  const { start, end } = dayBoundsUtc(range);
2115
- return this.db.select().from(this.t.agentRun).where(and2(gte2(this.t.agentRun.startedAt, start), lte2(this.t.agentRun.startedAt, end)));
2829
+ return this.db.select().from(this.t.agentRun).where(and3(gte2(this.t.agentRun.startedAt, start), lte3(this.t.agentRun.startedAt, end)));
2116
2830
  }
2117
2831
  async runMetrics(range) {
2118
2832
  const runs = await this.runsInRange(range);
@@ -2169,7 +2883,7 @@ var DrizzleGovernanceQueries = class {
2169
2883
  }
2170
2884
  async runErrors(range) {
2171
2885
  const { start, end } = dayBoundsUtc(range);
2172
- const runs = await this.db.select().from(this.t.agentRun).where(and2(gte2(this.t.agentRun.startedAt, start), lte2(this.t.agentRun.startedAt, end), eq2(this.t.agentRun.status, "failed")));
2886
+ 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")));
2173
2887
  const byError = /* @__PURE__ */ new Map();
2174
2888
  for (const run of runs) {
2175
2889
  const errorCode = run.errorCode ?? UNCLASSIFIED_ERROR_CODE;
@@ -2228,7 +2942,7 @@ var DrizzleGovernanceQueries = class {
2228
2942
  agentName: this.t.agentMessage.agentName,
2229
2943
  requestedAt: this.t.agentToolCall.createdAt,
2230
2944
  runId: this.t.agentToolCall.runId
2231
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq2(this.t.agentMessage.threadId, this.t.agentThread.id)).where(eq2(this.t.agentToolCall.status, "pending_approval")).orderBy(this.t.agentToolCall.createdAt, this.t.agentToolCall.id).limit(limit);
2945
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq3(this.t.agentMessage.threadId, this.t.agentThread.id)).where(eq3(this.t.agentToolCall.status, "pending_approval")).orderBy(this.t.agentToolCall.createdAt, this.t.agentToolCall.id).limit(limit);
2232
2946
  return rows.map((row) => ({
2233
2947
  toolCallId: row.toolCallId,
2234
2948
  toolName: row.toolName,
@@ -2250,7 +2964,7 @@ var DrizzleGovernanceQueries = class {
2250
2964
  */
2251
2965
  async toolStats(range) {
2252
2966
  const { start, end } = dayBoundsUtc(range);
2253
- const calls = await this.db.select().from(this.t.agentToolCall).where(and2(gte2(this.t.agentToolCall.createdAt, start), lte2(this.t.agentToolCall.createdAt, end)));
2967
+ const calls = await this.db.select().from(this.t.agentToolCall).where(and3(gte2(this.t.agentToolCall.createdAt, start), lte3(this.t.agentToolCall.createdAt, end)));
2254
2968
  const byTool = /* @__PURE__ */ new Map();
2255
2969
  for (const call of calls) {
2256
2970
  const key2 = `${call.toolName} ${call.toolType}`;
@@ -2300,10 +3014,10 @@ var DrizzleGovernanceQueries = class {
2300
3014
  if (filters?.toolType !== void 0 && !isToolKind(filters.toolType)) {
2301
3015
  return emptyPage(query);
2302
3016
  }
2303
- const whereClause = and2(filters?.toolName !== void 0 ? eq2(this.t.agentToolCall.toolName, filters.toolName) : void 0, filters?.toolType !== void 0 && isToolKind(filters.toolType) ? eq2(this.t.agentToolCall.toolType, filters.toolType) : void 0, filters?.status !== void 0 && isToolCallStatus(filters.status) ? eq2(this.t.agentToolCall.status, filters.status) : void 0, filters?.threadId !== void 0 ? eq2(this.t.agentMessage.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentToolCall.createdAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(this.t.agentToolCall.createdAt, dayEndUtc(filters.toDay)) : void 0);
3017
+ const whereClause = and3(filters?.toolName !== void 0 ? eq3(this.t.agentToolCall.toolName, filters.toolName) : void 0, filters?.toolType !== void 0 && isToolKind(filters.toolType) ? eq3(this.t.agentToolCall.toolType, filters.toolType) : void 0, filters?.status !== void 0 && isToolCallStatus(filters.status) ? eq3(this.t.agentToolCall.status, filters.status) : void 0, filters?.threadId !== void 0 ? eq3(this.t.agentMessage.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentToolCall.createdAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte3(this.t.agentToolCall.createdAt, dayEndUtc(filters.toDay)) : void 0);
2304
3018
  const [totalRow] = await this.db.select({
2305
3019
  value: count()
2306
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(whereClause);
3020
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(whereClause);
2307
3021
  const rows = await this.db.select({
2308
3022
  toolCallId: this.t.agentToolCall.id,
2309
3023
  toolName: this.t.agentToolCall.toolName,
@@ -2312,7 +3026,7 @@ var DrizzleGovernanceQueries = class {
2312
3026
  threadId: this.t.agentMessage.threadId,
2313
3027
  createdAt: this.t.agentToolCall.createdAt,
2314
3028
  runId: this.t.agentToolCall.runId
2315
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(whereClause).orderBy(desc2(this.t.agentToolCall.createdAt), desc2(this.t.agentToolCall.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
3029
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(whereClause).orderBy(desc2(this.t.agentToolCall.createdAt), desc2(this.t.agentToolCall.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
2316
3030
  return {
2317
3031
  rows: rows.map((row) => ({
2318
3032
  toolCallId: row.toolCallId,
@@ -2336,7 +3050,7 @@ var DrizzleGovernanceQueries = class {
2336
3050
  */
2337
3051
  async threadsPage(query) {
2338
3052
  const filters = query.where;
2339
- const whereClause = and2(isNull2(this.t.agentThread.deletedAt), filters?.actorRef !== void 0 ? eq2(this.t.agentThread.actorRef, filters.actorRef) : void 0, filters?.title !== void 0 ? like(sql3`lower(${this.t.agentThread.title})`, `%${filters.title.toLowerCase()}%`) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentThread.updatedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(this.t.agentThread.updatedAt, dayEndUtc(filters.toDay)) : void 0);
3053
+ const whereClause = and3(isNull3(this.t.agentThread.deletedAt), filters?.actorRef !== void 0 ? eq3(this.t.agentThread.actorRef, filters.actorRef) : void 0, filters?.title !== void 0 ? like(sql4`lower(${this.t.agentThread.title})`, `%${filters.title.toLowerCase()}%`) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentThread.updatedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte3(this.t.agentThread.updatedAt, dayEndUtc(filters.toDay)) : void 0);
2340
3054
  const [totalRow] = await this.db.select({
2341
3055
  value: count()
2342
3056
  }).from(this.t.agentThread).where(whereClause);
@@ -2358,7 +3072,7 @@ var DrizzleGovernanceQueries = class {
2358
3072
  if (filters?.status !== void 0 && !isRunStatus(filters.status)) {
2359
3073
  return emptyPage(query);
2360
3074
  }
2361
- const whereClause = and2(filters?.agentName !== void 0 ? eq2(this.t.agentRun.agentName, filters.agentName) : void 0, filters?.status !== void 0 && isRunStatus(filters.status) ? eq2(this.t.agentRun.status, filters.status) : void 0, filters?.errorCode !== void 0 ? eq2(this.t.agentRun.errorCode, filters.errorCode) : void 0, filters?.threadId !== void 0 ? eq2(this.t.agentRun.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentRun.startedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(this.t.agentRun.startedAt, dayEndUtc(filters.toDay)) : void 0);
3075
+ const whereClause = and3(filters?.agentName !== void 0 ? eq3(this.t.agentRun.agentName, filters.agentName) : void 0, filters?.status !== void 0 && isRunStatus(filters.status) ? eq3(this.t.agentRun.status, filters.status) : void 0, filters?.errorCode !== void 0 ? eq3(this.t.agentRun.errorCode, filters.errorCode) : void 0, filters?.threadId !== void 0 ? eq3(this.t.agentRun.threadId, filters.threadId) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentRun.startedAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte3(this.t.agentRun.startedAt, dayEndUtc(filters.toDay)) : void 0);
2362
3076
  const [totalRow] = await this.db.select({
2363
3077
  value: count()
2364
3078
  }).from(this.t.agentRun).where(whereClause);
@@ -2382,10 +3096,10 @@ var DrizzleGovernanceQueries = class {
2382
3096
  */
2383
3097
  async approvalsPage(query) {
2384
3098
  const filters = query.where;
2385
- const whereClause = and2(eq2(this.t.agentToolCall.status, "pending_approval"), filters?.toolName !== void 0 ? eq2(this.t.agentToolCall.toolName, filters.toolName) : void 0, filters?.threadId !== void 0 ? eq2(this.t.agentThread.id, filters.threadId) : void 0, filters?.actorRef !== void 0 ? eq2(this.t.agentThread.actorRef, filters.actorRef) : void 0, filters?.agentName !== void 0 ? eq2(this.t.agentMessage.agentName, filters.agentName) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentToolCall.createdAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte2(this.t.agentToolCall.createdAt, dayEndUtc(filters.toDay)) : void 0);
3099
+ const whereClause = and3(eq3(this.t.agentToolCall.status, "pending_approval"), filters?.toolName !== void 0 ? eq3(this.t.agentToolCall.toolName, filters.toolName) : void 0, filters?.threadId !== void 0 ? eq3(this.t.agentThread.id, filters.threadId) : void 0, filters?.actorRef !== void 0 ? eq3(this.t.agentThread.actorRef, filters.actorRef) : void 0, filters?.agentName !== void 0 ? eq3(this.t.agentMessage.agentName, filters.agentName) : void 0, filters?.fromDay !== void 0 ? gte2(this.t.agentToolCall.createdAt, dayStartUtc(filters.fromDay)) : void 0, filters?.toDay !== void 0 ? lte3(this.t.agentToolCall.createdAt, dayEndUtc(filters.toDay)) : void 0);
2386
3100
  const [totalRow] = await this.db.select({
2387
3101
  value: count()
2388
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq2(this.t.agentMessage.threadId, this.t.agentThread.id)).where(whereClause);
3102
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq3(this.t.agentMessage.threadId, this.t.agentThread.id)).where(whereClause);
2389
3103
  const rows = await this.db.select({
2390
3104
  toolCallId: this.t.agentToolCall.id,
2391
3105
  toolName: this.t.agentToolCall.toolName,
@@ -2396,7 +3110,7 @@ var DrizzleGovernanceQueries = class {
2396
3110
  agentName: this.t.agentMessage.agentName,
2397
3111
  requestedAt: this.t.agentToolCall.createdAt,
2398
3112
  runId: this.t.agentToolCall.runId
2399
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq2(this.t.agentMessage.threadId, this.t.agentThread.id)).where(whereClause).orderBy(asc2(this.t.agentToolCall.createdAt), asc2(this.t.agentToolCall.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
3113
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).innerJoin(this.t.agentThread, eq3(this.t.agentMessage.threadId, this.t.agentThread.id)).where(whereClause).orderBy(asc3(this.t.agentToolCall.createdAt), asc3(this.t.agentToolCall.id)).limit(query.pageSize).offset((query.page - 1) * query.pageSize);
2400
3114
  return {
2401
3115
  rows: rows.map((row) => ({
2402
3116
  toolCallId: row.toolCallId,
@@ -2423,11 +3137,11 @@ var DrizzleGovernanceQueries = class {
2423
3137
  const [row] = await this.db.select({
2424
3138
  run: this.t.agentRun,
2425
3139
  thread: this.t.agentThread
2426
- }).from(this.t.agentRun).innerJoin(this.t.agentThread, eq2(this.t.agentRun.threadId, this.t.agentThread.id)).where(eq2(this.t.agentRun.id, runId)).limit(1);
3140
+ }).from(this.t.agentRun).innerJoin(this.t.agentThread, eq3(this.t.agentRun.threadId, this.t.agentThread.id)).where(eq3(this.t.agentRun.id, runId)).limit(1);
2427
3141
  if (row === void 0) {
2428
3142
  return null;
2429
3143
  }
2430
- const toolCalls = await this.db.select().from(this.t.agentToolCall).where(eq2(this.t.agentToolCall.runId, runId)).orderBy(asc2(this.t.agentToolCall.createdAt), asc2(this.t.agentToolCall.id));
3144
+ const toolCalls = await this.db.select().from(this.t.agentToolCall).where(eq3(this.t.agentToolCall.runId, runId)).orderBy(asc3(this.t.agentToolCall.createdAt), asc3(this.t.agentToolCall.id));
2431
3145
  return {
2432
3146
  run: toRecentRunRow(row.run),
2433
3147
  thread: {
@@ -2446,27 +3160,27 @@ var DrizzleGovernanceQueries = class {
2446
3160
  * message. Soft-deleted threads are returned with `deleted: true`; an audit still needs them.
2447
3161
  */
2448
3162
  async threadDetail(query) {
2449
- const [thread] = await this.db.select().from(this.t.agentThread).where(eq2(this.t.agentThread.id, query.threadId)).limit(1);
3163
+ const [thread] = await this.db.select().from(this.t.agentThread).where(eq3(this.t.agentThread.id, query.threadId)).limit(1);
2450
3164
  if (thread === void 0) {
2451
3165
  return null;
2452
3166
  }
2453
3167
  const pricing = await this.loadPricing();
2454
- const usageRows = await this.db.select().from(this.t.agentTokenUsage).where(eq2(this.t.agentTokenUsage.threadId, thread.id));
3168
+ const usageRows = await this.db.select().from(this.t.agentTokenUsage).where(eq3(this.t.agentTokenUsage.threadId, thread.id));
2455
3169
  const usage = rollupThreadUsage(usageRows.map(toUsageInput), pricing);
2456
3170
  const [messageCountRow] = await this.db.select({
2457
3171
  value: count()
2458
- }).from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, thread.id));
2459
- const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, thread.id)).orderBy(
3172
+ }).from(this.t.agentMessage).where(eq3(this.t.agentMessage.threadId, thread.id));
3173
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq3(this.t.agentMessage.threadId, thread.id)).orderBy(
2460
3174
  // Append order (see DrizzleAgentStore's message order), newest first.
2461
- desc2(sql3`coalesce(${this.t.agentMessage.seq}, 0)`),
3175
+ desc2(sql4`coalesce(${this.t.agentMessage.seq}, 0)`),
2462
3176
  desc2(this.t.agentMessage.createdAt),
2463
3177
  desc2(this.t.agentMessage.id)
2464
3178
  ).limit(query.messageLimit);
2465
3179
  const toolCallCounts = await this.toolCallCountsByMessage(messages.map((message) => message.id));
2466
3180
  const [runTotalRow] = await this.db.select({
2467
3181
  value: count()
2468
- }).from(this.t.agentRun).where(eq2(this.t.agentRun.threadId, thread.id));
2469
- const runs = await this.db.select().from(this.t.agentRun).where(eq2(this.t.agentRun.threadId, thread.id)).orderBy(desc2(this.t.agentRun.startedAt), desc2(this.t.agentRun.id)).limit(query.runLimit);
3182
+ }).from(this.t.agentRun).where(eq3(this.t.agentRun.threadId, thread.id));
3183
+ const runs = await this.db.select().from(this.t.agentRun).where(eq3(this.t.agentRun.threadId, thread.id)).orderBy(desc2(this.t.agentRun.startedAt), desc2(this.t.agentRun.id)).limit(query.runLimit);
2470
3184
  return {
2471
3185
  thread: {
2472
3186
  threadId: thread.id,
@@ -2513,7 +3227,7 @@ var DrizzleGovernanceQueries = class {
2513
3227
 
2514
3228
  // src/drizzle-memory-provider.ts
2515
3229
  import { actorScope } from "@dudousxd/nestjs-agent-core";
2516
- import { and as and3, eq as eq3, inArray as inArray3 } from "drizzle-orm";
3230
+ import { and as and4, eq as eq4, inArray as inArray3 } from "drizzle-orm";
2517
3231
  function toRecord(row) {
2518
3232
  return {
2519
3233
  id: row.id,
@@ -2577,7 +3291,7 @@ var DrizzleMemoryProvider = class {
2577
3291
  * answer cannot be used to find out which memories exist about other people.
2578
3292
  */
2579
3293
  async forget({ id, ctx }) {
2580
- const deleted = await affectedRows(this.dialect, this.db.delete(this.t.agentMemory).where(and3(eq3(this.t.agentMemory.id, id), eq3(this.t.agentMemory.scope, actorScope(ctx.actor)))), this.t.agentMemory.id);
3294
+ const deleted = await affectedRows(this.dialect, this.db.delete(this.t.agentMemory).where(and4(eq4(this.t.agentMemory.id, id), eq4(this.t.agentMemory.scope, actorScope(ctx.actor)))), this.t.agentMemory.id);
2581
3295
  return deleted > 0;
2582
3296
  }
2583
3297
  /**
@@ -2626,7 +3340,7 @@ var DrizzleMemoryProvider = class {
2626
3340
  memory.scope,
2627
3341
  memory.key
2628
3342
  ], set);
2629
- [row] = await this.db.select().from(memory).where(and3(eq3(memory.scope, scope), eq3(memory.key, key2)));
3343
+ [row] = await this.db.select().from(memory).where(and4(eq4(memory.scope, scope), eq4(memory.key, key2)));
2630
3344
  } else {
2631
3345
  [row] = await insert.onConflictDoUpdate({
2632
3346
  target: [
@@ -2653,7 +3367,7 @@ var DrizzleMemoryProvider = class {
2653
3367
  const updated = await affectedRows(this.dialect, this.db.update(this.t.agentMemory).set({
2654
3368
  pinned,
2655
3369
  updatedAt: /* @__PURE__ */ new Date()
2656
- }).where(eq3(this.t.agentMemory.id, id)), this.t.agentMemory.id);
3370
+ }).where(eq4(this.t.agentMemory.id, id)), this.t.agentMemory.id);
2657
3371
  return updated > 0;
2658
3372
  }
2659
3373
  };
@@ -2666,7 +3380,7 @@ function assertAuthorMayWriteScope({ scope, origin, ctx }) {
2666
3380
  __name(assertAuthorMayWriteScope, "assertAuthorMayWriteScope");
2667
3381
 
2668
3382
  // src/drizzle-pricing-store.ts
2669
- import { and as and4, eq as eq4 } from "drizzle-orm";
3383
+ import { and as and5, eq as eq5 } from "drizzle-orm";
2670
3384
  var DrizzlePricingStore = class {
2671
3385
  static {
2672
3386
  __name(this, "DrizzlePricingStore");
@@ -2682,7 +3396,7 @@ var DrizzlePricingStore = class {
2682
3396
  async upsertModelPrice(input) {
2683
3397
  await this.db.update(this.t.agentModelPricing).set({
2684
3398
  isCurrent: false
2685
- }).where(and4(eq4(this.t.agentModelPricing.modelId, input.modelId), eq4(this.t.agentModelPricing.isCurrent, true)));
3399
+ }).where(and5(eq5(this.t.agentModelPricing.modelId, input.modelId), eq5(this.t.agentModelPricing.isCurrent, true)));
2686
3400
  await this.db.insert(this.t.agentModelPricing).values({
2687
3401
  id: crypto.randomUUID(),
2688
3402
  modelId: input.modelId,
@@ -2695,7 +3409,7 @@ var DrizzlePricingStore = class {
2695
3409
  });
2696
3410
  }
2697
3411
  async listCurrentPrices() {
2698
- const rows = await this.db.select().from(this.t.agentModelPricing).where(eq4(this.t.agentModelPricing.isCurrent, true));
3412
+ const rows = await this.db.select().from(this.t.agentModelPricing).where(eq5(this.t.agentModelPricing.isCurrent, true));
2699
3413
  return rows.map((row) => ({
2700
3414
  modelId: row.modelId,
2701
3415
  inputPricePer1m: row.inputPricePer1m,
@@ -2713,7 +3427,7 @@ var DrizzlePricingStore = class {
2713
3427
 
2714
3428
  // src/drizzle-token-stream-sink.ts
2715
3429
  import { SqlTokenStreamSink } from "@dudousxd/nestjs-agent-core";
2716
- import { and as and5, asc as asc3, eq as eq5, gt, inArray as inArray4, lt, max as max2, sql as sql4 } from "drizzle-orm";
3430
+ import { and as and6, asc as asc4, eq as eq6, gt as gt2, inArray as inArray4, lt, max as max3, sql as sql5 } from "drizzle-orm";
2717
3431
  var DrizzleStreamFrameTable = class {
2718
3432
  static {
2719
3433
  __name(this, "DrizzleStreamFrameTable");
@@ -2727,7 +3441,7 @@ var DrizzleStreamFrameTable = class {
2727
3441
  this.db = asBuilder(db);
2728
3442
  }
2729
3443
  async append(runId, row) {
2730
- await runSql(this.db, this.dialect, sql4`INSERT INTO agent_stream_frame (run_id, seq, frame, error, created_at)
3444
+ await runSql(this.db, this.dialect, sql5`INSERT INTO agent_stream_frame (run_id, seq, frame, error, created_at)
2731
3445
  SELECT ${runId}, COALESCE(MAX(seq), 0) + 1, ${row.frame}, ${row.error}, ${row.createdAt}
2732
3446
  FROM agent_stream_frame WHERE run_id = ${runId}`);
2733
3447
  }
@@ -2736,12 +3450,12 @@ var DrizzleStreamFrameTable = class {
2736
3450
  seq: this.t.agentStreamFrame.seq,
2737
3451
  frame: this.t.agentStreamFrame.frame,
2738
3452
  error: this.t.agentStreamFrame.error
2739
- }).from(this.t.agentStreamFrame).where(and5(eq5(this.t.agentStreamFrame.runId, runId), gt(this.t.agentStreamFrame.seq, after))).orderBy(asc3(this.t.agentStreamFrame.seq)).limit(limit);
3453
+ }).from(this.t.agentStreamFrame).where(and6(eq6(this.t.agentStreamFrame.runId, runId), gt2(this.t.agentStreamFrame.seq, after))).orderBy(asc4(this.t.agentStreamFrame.seq)).limit(limit);
2740
3454
  }
2741
3455
  async has(runId) {
2742
3456
  const rows = await this.db.select({
2743
3457
  seq: this.t.agentStreamFrame.seq
2744
- }).from(this.t.agentStreamFrame).where(eq5(this.t.agentStreamFrame.runId, runId)).limit(1);
3458
+ }).from(this.t.agentStreamFrame).where(eq6(this.t.agentStreamFrame.runId, runId)).limit(1);
2745
3459
  return rows.length > 0;
2746
3460
  }
2747
3461
  async remove(runIds) {
@@ -2753,7 +3467,7 @@ var DrizzleStreamFrameTable = class {
2753
3467
  async lapsedRuns(cutoff) {
2754
3468
  const rows = await this.db.select({
2755
3469
  runId: this.t.agentStreamFrame.runId
2756
- }).from(this.t.agentStreamFrame).groupBy(this.t.agentStreamFrame.runId).having(lt(max2(this.t.agentStreamFrame.createdAt), cutoff));
3470
+ }).from(this.t.agentStreamFrame).groupBy(this.t.agentStreamFrame.runId).having(lt(max3(this.t.agentStreamFrame.createdAt), cutoff));
2757
3471
  return rows.map((row) => row.runId);
2758
3472
  }
2759
3473
  isUniqueViolation(error) {
@@ -2770,7 +3484,7 @@ var DrizzleTokenStreamSink = class extends SqlTokenStreamSink {
2770
3484
  };
2771
3485
 
2772
3486
  // src/drizzle-confirm-token-store.ts
2773
- import { eq as eq6, lt as lt2 } from "drizzle-orm";
3487
+ import { eq as eq7, lt as lt2 } from "drizzle-orm";
2774
3488
  var DrizzleConfirmTokenStore = class {
2775
3489
  static {
2776
3490
  __name(this, "DrizzleConfirmTokenStore");
@@ -2800,7 +3514,7 @@ var DrizzleConfirmTokenStore = class {
2800
3514
  return inserted === 1;
2801
3515
  }
2802
3516
  async release(hash) {
2803
- await this.db.delete(this.t.agentConfirmToken).where(eq6(this.t.agentConfirmToken.hash, hash));
3517
+ await this.db.delete(this.t.agentConfirmToken).where(eq7(this.t.agentConfirmToken.hash, hash));
2804
3518
  }
2805
3519
  async purgeExpired(now = Date.now()) {
2806
3520
  const table = this.t.agentConfirmToken;
@@ -2811,7 +3525,7 @@ var DrizzleConfirmTokenStore = class {
2811
3525
  // src/drizzle-rag-ingestion-log.ts
2812
3526
  import { subscribe, unsubscribe } from "diagnostics_channel";
2813
3527
  import { Injectable, Logger } from "@nestjs/common";
2814
- import { and as and6, asc as asc4, count as count2, desc as desc3, eq as eq7, gt as gt2, lt as lt3, or as or2 } from "drizzle-orm";
3528
+ import { and as and7, asc as asc5, count as count2, desc as desc3, eq as eq8, gt as gt3, lt as lt3, or as or3 } from "drizzle-orm";
2815
3529
  function _ts_decorate(decorators, target, key2, desc4) {
2816
3530
  var c = arguments.length, r = c < 3 ? target : desc4 === null ? desc4 = Object.getOwnPropertyDescriptor(target, key2) : desc4, d;
2817
3531
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -2860,7 +3574,7 @@ function num(value) {
2860
3574
  __name(num, "num");
2861
3575
  var RAG_INGESTION_LOG_PAGE_ORDER = [
2862
3576
  desc3(ragIngestionLog.updatedAt),
2863
- asc4(ragIngestionLog.documentId)
3577
+ asc5(ragIngestionLog.documentId)
2864
3578
  ];
2865
3579
  var DEFAULT_PAGE_SIZE = 200;
2866
3580
  var DEFAULT_BATCH_SIZE = 200;
@@ -3010,17 +3724,17 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
3010
3724
  }
3011
3725
  /** The latest recorded outcome for one document, or null if it was never attempted. */
3012
3726
  async get(documentId) {
3013
- const [row] = await this.db.select().from(this.t.ragIngestionLog).where(eq7(this.t.ragIngestionLog.documentId, documentId));
3727
+ const [row] = await this.db.select().from(this.t.ragIngestionLog).where(eq8(this.t.ragIngestionLog.documentId, documentId));
3014
3728
  return row ?? null;
3015
3729
  }
3016
3730
  /** Forget one document's record. Returns whether a row was actually removed. */
3017
3731
  async remove(documentId) {
3018
- const removed = await affectedRows(this.dialect, this.db.delete(this.t.ragIngestionLog).where(eq7(this.t.ragIngestionLog.documentId, documentId)), this.t.ragIngestionLog.documentId);
3732
+ const removed = await affectedRows(this.dialect, this.db.delete(this.t.ragIngestionLog).where(eq8(this.t.ragIngestionLog.documentId, documentId)), this.t.ragIngestionLog.documentId);
3019
3733
  return removed > 0;
3020
3734
  }
3021
3735
  /** Forget every record for a collection — for when the collection itself is deleted. */
3022
3736
  async removeByCollection(collection) {
3023
- const removed = await affectedRows(this.dialect, this.db.delete(this.t.ragIngestionLog).where(eq7(this.t.ragIngestionLog.collection, collection)), this.t.ragIngestionLog.documentId);
3737
+ const removed = await affectedRows(this.dialect, this.db.delete(this.t.ragIngestionLog).where(eq8(this.t.ragIngestionLog.collection, collection)), this.t.ragIngestionLog.documentId);
3024
3738
  return removed;
3025
3739
  }
3026
3740
  /**
@@ -3050,7 +3764,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
3050
3764
  }
3051
3765
  }
3052
3766
  where(query) {
3053
- return and6(query.collection !== void 0 ? eq7(this.t.ragIngestionLog.collection, query.collection) : void 0, query.status !== void 0 ? eq7(this.t.ragIngestionLog.status, query.status) : void 0);
3767
+ return and7(query.collection !== void 0 ? eq8(this.t.ragIngestionLog.collection, query.collection) : void 0, query.status !== void 0 ? eq8(this.t.ragIngestionLog.status, query.status) : void 0);
3054
3768
  }
3055
3769
  /**
3056
3770
  * The coordinates filter AND'd with "strictly after `cursor` in
@@ -3065,7 +3779,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
3065
3779
  if (cursor === void 0) {
3066
3780
  return base;
3067
3781
  }
3068
- return and6(base, or2(lt3(this.t.ragIngestionLog.updatedAt, cursor.updatedAt), and6(eq7(this.t.ragIngestionLog.updatedAt, cursor.updatedAt), gt2(this.t.ragIngestionLog.documentId, cursor.documentId))));
3782
+ return and7(base, or3(lt3(this.t.ragIngestionLog.updatedAt, cursor.updatedAt), and7(eq8(this.t.ragIngestionLog.updatedAt, cursor.updatedAt), gt3(this.t.ragIngestionLog.documentId, cursor.documentId))));
3069
3783
  }
3070
3784
  /**
3071
3785
  * Upsert one outcome. Keyed by document id so the row always reflects the *current* state — a
@@ -3240,6 +3954,7 @@ DrizzleAgentStoreModule = _ts_decorate2([
3240
3954
  Module({})
3241
3955
  ], DrizzleAgentStoreModule);
3242
3956
  export {
3957
+ DrizzleActionProposalStore,
3243
3958
  DrizzleAgentStore,
3244
3959
  DrizzleAgentStoreModule,
3245
3960
  DrizzleConfirmTokenStore,
@@ -3250,6 +3965,7 @@ export {
3250
3965
  DrizzleStreamFrameTable,
3251
3966
  DrizzleTokenStreamSink,
3252
3967
  RAG_INGESTION_LOG_PAGE_ORDER,
3968
+ agentActionProposal,
3253
3969
  agentConfirmToken,
3254
3970
  agentDialectOf,
3255
3971
  agentMemory,