@dudousxd/nestjs-agent-store-drizzle 0.24.0 → 0.25.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,514 @@ 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
+ "MySql2Database",
1153
+ "MySql2Transaction",
1154
+ "LibSQLDatabase",
1155
+ "LibSQLTransaction"
1156
+ ].includes(kind)) return "async";
1157
+ return "unsupported";
1158
+ }
1159
+ __name(actionProposalTransactionMode, "actionProposalTransactionMode");
1160
+
1161
+ // src/drizzle-action-proposal-store.ts
1162
+ var DrizzleActionProposalStore = class {
1163
+ static {
1164
+ __name(this, "DrizzleActionProposalStore");
1165
+ }
1166
+ db;
1167
+ rawDb;
1168
+ actionProposalAdmissionSupported;
1169
+ synchronousSqlite;
1170
+ dialect;
1171
+ table;
1172
+ clock;
1173
+ constructor(db, options = {}) {
1174
+ this.rawDb = db;
1175
+ const kind = db.constructor[entityKind];
1176
+ const transactionMode = actionProposalTransactionMode(kind);
1177
+ this.synchronousSqlite = transactionMode === "sync";
1178
+ this.actionProposalAdmissionSupported = transactionMode !== "unsupported";
1179
+ this.dialect = agentDialectOf(db);
1180
+ this.table = agentTablesFor(this.dialect).agentActionProposal;
1181
+ this.db = asBuilder(db);
1182
+ this.clock = options.clock ?? Date.now;
1183
+ }
1184
+ async createActionProposal(input) {
1185
+ const proposal = initialActionProposal(input, this.clock());
1186
+ const row = {
1187
+ id: physicalId(input.id),
1188
+ scopeKey: scopeKey(input),
1189
+ decision: proposal.decision,
1190
+ logicalSort: logicalSort(input.id),
1191
+ createFingerprint: canonicalActionProposalJson3(input),
1192
+ proposal,
1193
+ ...discoveryMetadata(proposal),
1194
+ version: 0,
1195
+ createdAt: proposal.createdAt
1196
+ };
1197
+ const table = this.table;
1198
+ const insert = this.db.insert(table);
1199
+ const inserted = this.dialect === "mysql" ? mysqlAffectedRows(await insert.ignore().values(row)) : await affectedRows(this.dialect, insert.values(row).onConflictDoNothing(), table.id);
1200
+ const stored = await this.read(input, input.id);
1201
+ if (!stored) return {
1202
+ status: "conflict"
1203
+ };
1204
+ if (inserted === 1) return {
1205
+ status: "created",
1206
+ proposal: stored.proposal
1207
+ };
1208
+ return {
1209
+ status: stored.createFingerprint === row.createFingerprint ? "unchanged" : "conflict",
1210
+ proposal: stored.proposal
1211
+ };
1212
+ }
1213
+ createReplacingActionProposal(input) {
1214
+ if (!input.replacementKey) return this.createActionProposal(input);
1215
+ const proposal = initialActionProposal(input, this.clock());
1216
+ return this.transactionSteps((db) => this.replacementSteps(db, input, proposal));
1217
+ }
1218
+ async supersedeActionProposal(scope, id, command) {
1219
+ const replacement = await this.getActionProposal(scope, command.replacementProposalId);
1220
+ if (!replacement) return {
1221
+ status: "not_found"
1222
+ };
1223
+ return this.mutate(scope, id, (row, now) => transitionActionProposalSupersession(row, replacement, command, now));
1224
+ }
1225
+ *replacementSteps(db, input, proposal) {
1226
+ const table = this.table;
1227
+ const thread = agentTablesFor(this.dialect).agentThread;
1228
+ if (this.dialect === "sqlite") yield {
1229
+ kind: "write",
1230
+ query: db.update(thread).set({
1231
+ updatedAt: sql2`${thread.updatedAt}`
1232
+ }).where(eq(thread.id, input.threadId))
1233
+ };
1234
+ const threads = yield {
1235
+ kind: "read",
1236
+ query: lockQuery(db.select().from(thread).where(eq(thread.id, input.threadId)).limit(1), this.dialect)
1237
+ };
1238
+ const owner = threads[0];
1239
+ if (!owner || owner.id !== input.threadId || owner.deletedAt || owner.actorRef !== input.actorRef || owner.tenantRef !== input.tenantRef) return {
1240
+ status: "conflict"
1241
+ };
1242
+ const existingRows = yield {
1243
+ kind: "read",
1244
+ query: db.select().from(table).where(eq(table.id, physicalId(input.id))).limit(1)
1245
+ };
1246
+ const existing = existingRows[0];
1247
+ if (existing) {
1248
+ if (existing.proposal.id !== input.id || !actionProposalScopeMatches(existing.proposal, input)) return {
1249
+ status: "conflict"
1250
+ };
1251
+ return {
1252
+ status: existing.createFingerprint === canonicalActionProposalJson3(input) ? "unchanged" : "conflict",
1253
+ proposal: existing.proposal
1254
+ };
1255
+ }
1256
+ const groupKey = replacementGroupKey(input);
1257
+ if (groupKey === null) throw new Error("Missing explicit replacement identity");
1258
+ const pending = yield {
1259
+ kind: "read",
1260
+ query: lockQuery(db.select().from(table).where(and(eq(table.scopeKey, scopeKey(input)), eq(table.replacementGroupKey, groupKey), eq(table.decision, "pending"))), this.dialect)
1261
+ };
1262
+ const row = {
1263
+ id: physicalId(input.id),
1264
+ scopeKey: scopeKey(input),
1265
+ decision: proposal.decision,
1266
+ logicalSort: logicalSort(input.id),
1267
+ createFingerprint: canonicalActionProposalJson3(input),
1268
+ proposal,
1269
+ ...discoveryMetadata(proposal),
1270
+ version: 0,
1271
+ createdAt: proposal.createdAt
1272
+ };
1273
+ const insert = db.insert(table);
1274
+ const inserted = yield {
1275
+ kind: "read",
1276
+ query: this.dialect === "mysql" ? insert.ignore().values(row) : insert.values(row).onConflictDoNothing().returning({
1277
+ id: table.id
1278
+ })
1279
+ };
1280
+ const count3 = this.dialect === "mysql" ? mysqlAffectedRows(inserted) : inserted.length;
1281
+ if (count3 !== 1) return {
1282
+ status: "conflict"
1283
+ };
1284
+ for (const old of pending) {
1285
+ const result = transitionActionProposalSupersession(old.proposal, proposal, {
1286
+ replacementProposalId: proposal.id,
1287
+ actorRef: proposal.actorRef,
1288
+ via: "replacement"
1289
+ }, this.clock());
1290
+ if (!result.proposal || canonicalActionProposalJson3(result.proposal) === canonicalActionProposalJson3(old.proposal)) continue;
1291
+ const next = result.proposal;
1292
+ const update = db.update(table).set({
1293
+ proposal: next,
1294
+ decision: next.decision,
1295
+ ...discoveryMetadata(next),
1296
+ version: old.version + 1
1297
+ }).where(and(eq(table.id, old.id), eq(table.version, old.version)));
1298
+ const updated = yield {
1299
+ kind: "read",
1300
+ query: this.dialect === "mysql" ? update : update.returning({
1301
+ id: table.id
1302
+ })
1303
+ };
1304
+ if ((this.dialect === "mysql" ? mysqlAffectedRows(updated) : updated.length) !== 1) throw new Error("Replacement lost its locked proposal fence");
1305
+ }
1306
+ return {
1307
+ status: "created",
1308
+ proposal
1309
+ };
1310
+ }
1311
+ async getActionProposal(scope, id) {
1312
+ return (await this.read(scope, id))?.proposal ?? null;
1313
+ }
1314
+ async listActionProposals(scope, query = {}) {
1315
+ const limit = validateActionProposalListQuery(query);
1316
+ 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);
1317
+ return rows.map((row) => row.proposal).filter((proposal) => actionProposalScopeMatches(proposal, scope));
1318
+ }
1319
+ decideActionProposal(scope, id, command) {
1320
+ return this.mutate(scope, id, (row, now) => transitionActionProposalDecision(row, command, now));
1321
+ }
1322
+ claimActionProposal(scope, id, command) {
1323
+ return this.mutate(scope, id, (row, now) => transitionActionProposalClaim(row, command, now, randomUUID()));
1324
+ }
1325
+ extendActionProposalLease(scope, id, command) {
1326
+ return this.mutate(scope, id, (row, now) => transitionActionProposalLease(row, command, now));
1327
+ }
1328
+ settleActionProposal(scope, id, command) {
1329
+ return this.mutate(scope, id, (row, now) => transitionActionProposalSettlement(row, command, now));
1330
+ }
1331
+ async claimNextActionProposal(command) {
1332
+ const now = this.clock();
1333
+ validateActionProposalWorkerClaim(command, now);
1334
+ const table = this.table;
1335
+ 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);
1336
+ for (const candidate of candidates) {
1337
+ const result = await this.claimActionProposal(candidate.proposal, candidate.proposal.id, command);
1338
+ if (result.status === "applied" && result.proposal) return result.proposal;
1339
+ }
1340
+ return null;
1341
+ }
1342
+ async expireActionProposals(command) {
1343
+ const now = this.clock();
1344
+ validateActionProposalExpiryBatch(command, now);
1345
+ const table = this.table;
1346
+ 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);
1347
+ let expired = 0;
1348
+ for (const candidate of candidates) {
1349
+ const result = await this.decideActionProposal(candidate.proposal, candidate.proposal.id, {
1350
+ decision: "expired",
1351
+ actorRef: "system",
1352
+ via: "expiry"
1353
+ });
1354
+ if (result.status === "applied") expired++;
1355
+ }
1356
+ return expired;
1357
+ }
1358
+ async backfillActionProposalDiscoveryIndex(command) {
1359
+ validateActionProposalDiscoveryIndexBatch(command);
1360
+ const table = this.table;
1361
+ const candidates = await this.db.select().from(table).where(eq(table.discoveryIndexVersion, 0)).orderBy(asc(table.createdAt), asc(table.logicalSort)).limit(command.limit);
1362
+ let changed = 0;
1363
+ for (const row of candidates) {
1364
+ changed += await affectedRows(this.dialect, this.db.update(table).set({
1365
+ ...discoveryMetadata(row.proposal),
1366
+ version: row.version + 1
1367
+ }).where(and(eq(table.id, row.id), eq(table.scopeKey, row.scopeKey), eq(table.version, row.version), eq(table.discoveryIndexVersion, 0))), table.id);
1368
+ }
1369
+ return changed;
1370
+ }
1371
+ async rememberedActionProposalApprovals(scope) {
1372
+ const table = this.table;
1373
+ 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"))));
1374
+ return [
1375
+ ...new Set(rows.filter((row) => actionProposalScopeMatches(row.proposal, scope) && row.proposal.decisionAudit?.remember === true).map((row) => row.proposal.toolName))
1376
+ ];
1377
+ }
1378
+ async getThreadActionProposalScope(threadId) {
1379
+ const thread = agentTablesFor(this.dialect).agentThread;
1380
+ const [row] = await this.db.select().from(thread).where(and(eq(thread.id, threadId), isNull(thread.deletedAt))).limit(1);
1381
+ return row?.id === threadId ? {
1382
+ actorRef: row.actorRef,
1383
+ tenantRef: row.tenantRef,
1384
+ threadId: row.id
1385
+ } : null;
1386
+ }
1387
+ async claimNextActionProposalOutcome(command) {
1388
+ const now = this.clock();
1389
+ validateActionProposalWorkerClaim(command, now);
1390
+ const table = this.table;
1391
+ 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);
1392
+ for (const row of candidates) {
1393
+ const result = await this.mutate(row.proposal, row.proposal.id, (proposal, time) => {
1394
+ const claimed2 = claimActionProposalOutcome(proposal, command, time, randomUUID());
1395
+ return claimed2 ? {
1396
+ status: "applied",
1397
+ proposal: claimed2
1398
+ } : {
1399
+ status: "conflict",
1400
+ proposal
1401
+ };
1402
+ });
1403
+ const claimed = result.proposal;
1404
+ if (result.status === "applied" && claimed?.outcome && claimed.outcomeDelivery?.lease) {
1405
+ return {
1406
+ outcome: claimed.outcome,
1407
+ lease: {
1408
+ outcomeId: claimed.outcome.id,
1409
+ token: claimed.outcomeDelivery.lease.token,
1410
+ generation: claimed.outcomeDelivery.generation
1411
+ }
1412
+ };
1413
+ }
1414
+ }
1415
+ return null;
1416
+ }
1417
+ async admitActionProposalOutcome(command) {
1418
+ return this.transactionSteps((db) => this.admissionSteps(db, command));
1419
+ }
1420
+ async transactionSteps(factory) {
1421
+ if (!this.actionProposalAdmissionSupported) throw new Error("Independent actions require a certified transactional Drizzle driver (better-sqlite3, node-postgres, mysql2 or libsql)");
1422
+ if (this.synchronousSqlite) {
1423
+ const database2 = this.rawDb;
1424
+ return database2.transaction((tx) => runSync(factory(asBuilder(tx))), {
1425
+ behavior: "immediate"
1426
+ });
1427
+ }
1428
+ const database = this.rawDb;
1429
+ return database.transaction(async (tx) => runAsync(factory(asBuilder(tx))));
1430
+ }
1431
+ *admissionSteps(db, command) {
1432
+ 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");
1433
+ const table = this.table;
1434
+ const tables = agentTablesFor(this.dialect);
1435
+ if (this.dialect === "sqlite") yield {
1436
+ kind: "write",
1437
+ query: db.update(table).set({
1438
+ version: sql2`${table.version}`
1439
+ }).where(eq(table.outcomeIdKey, physicalId(command.outcomeId)))
1440
+ };
1441
+ const query = db.select().from(table).where(eq(table.outcomeIdKey, physicalId(command.outcomeId))).limit(1);
1442
+ const rows = yield {
1443
+ kind: "read",
1444
+ query: lockQuery(query, this.dialect)
1445
+ };
1446
+ const row = rows[0];
1447
+ if (!row || row.proposal.outcome?.id !== command.outcomeId) return {
1448
+ status: "not_found"
1449
+ };
1450
+ const proposal = row.proposal;
1451
+ const outcome = proposal.outcome;
1452
+ const delivery = proposal.outcomeDelivery;
1453
+ if (!outcome || !delivery) return {
1454
+ status: "not_found"
1455
+ };
1456
+ if (proposal.outcomeDelivery?.status === "admitted") return {
1457
+ status: "unchanged",
1458
+ ...proposal.outcomeDelivery.messageId !== void 0 ? {
1459
+ messageId: proposal.outcomeDelivery.messageId
1460
+ } : {}
1461
+ };
1462
+ if (proposal.outcomeDelivery?.status === "discarded") return {
1463
+ status: "discarded"
1464
+ };
1465
+ if (!actionProposalOutcomeFenceValid(proposal, command, this.clock())) return {
1466
+ status: "conflict"
1467
+ };
1468
+ const threadQuery = db.select().from(tables.agentThread).where(eq(tables.agentThread.id, proposal.threadId)).limit(1);
1469
+ const threads = yield {
1470
+ kind: "read",
1471
+ query: lockQuery(threadQuery, this.dialect)
1472
+ };
1473
+ const thread = threads[0];
1474
+ const now = this.clock();
1475
+ if (!actionProposalOutcomeFenceValid(proposal, command, now)) return {
1476
+ status: "conflict"
1477
+ };
1478
+ if (!thread || thread.id !== proposal.threadId || thread.deletedAt || thread.actorRef !== proposal.actorRef || thread.tenantRef !== proposal.tenantRef) {
1479
+ const discarded = {
1480
+ ...proposal,
1481
+ outcomeDelivery: {
1482
+ ...delivery,
1483
+ status: "discarded",
1484
+ lease: null
1485
+ },
1486
+ updatedAt: now
1487
+ };
1488
+ yield {
1489
+ kind: "write",
1490
+ query: db.update(table).set({
1491
+ proposal: discarded,
1492
+ ...discoveryMetadata(discarded),
1493
+ version: row.version + 1
1494
+ }).where(and(eq(table.id, row.id), eq(table.version, row.version)))
1495
+ };
1496
+ return {
1497
+ status: "discarded"
1498
+ };
1499
+ }
1500
+ if (thread.activeStreamId !== null) return {
1501
+ status: "busy"
1502
+ };
1503
+ const seqRows = yield {
1504
+ kind: "read",
1505
+ query: db.select({
1506
+ last: max(tables.agentMessage.seq)
1507
+ }).from(tables.agentMessage).where(eq(tables.agentMessage.threadId, thread.id))
1508
+ };
1509
+ const messageId = physicalId(command.outcomeId);
1510
+ yield {
1511
+ kind: "write",
1512
+ query: db.insert(tables.agentMessage).values({
1513
+ id: messageId,
1514
+ threadId: thread.id,
1515
+ role: "assistant",
1516
+ content: actionProposalOutcomeText(outcome),
1517
+ actionProposalOutcome: canonicalActionProposalJson3(outcome),
1518
+ ui: null,
1519
+ seq: Number(seqRows[0]?.last ?? 0) + 1,
1520
+ createdAt: new Date(now)
1521
+ })
1522
+ };
1523
+ yield {
1524
+ kind: "write",
1525
+ query: db.update(tables.agentThread).set({
1526
+ updatedAt: new Date(now)
1527
+ }).where(eq(tables.agentThread.id, thread.id))
1528
+ };
1529
+ const admitted = {
1530
+ ...proposal,
1531
+ outcomeDelivery: {
1532
+ ...delivery,
1533
+ status: "admitted",
1534
+ lease: null,
1535
+ messageId
1536
+ },
1537
+ updatedAt: now
1538
+ };
1539
+ const update = db.update(table).set({
1540
+ proposal: admitted,
1541
+ ...discoveryMetadata(admitted),
1542
+ version: row.version + 1
1543
+ }).where(and(eq(table.id, row.id), eq(table.version, row.version)));
1544
+ const changed = yield {
1545
+ kind: "read",
1546
+ query: this.dialect === "mysql" ? update : update.returning({
1547
+ id: table.id
1548
+ })
1549
+ };
1550
+ const count3 = this.dialect === "mysql" ? mysqlAffectedRows(changed) : changed.length;
1551
+ if (count3 !== 1) throw new Error("Outcome admission lost its locked proposal fence");
1552
+ return {
1553
+ status: "applied",
1554
+ messageId
1555
+ };
1556
+ }
1557
+ async read(scope, id) {
1558
+ 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);
1559
+ return row && row.proposal.id === id && actionProposalScopeMatches(row.proposal, scope) ? row : void 0;
1560
+ }
1561
+ async mutate(scope, id, transition) {
1562
+ for (let attempt = 0; attempt < 32; attempt++) {
1563
+ const row2 = await this.read(scope, id);
1564
+ if (!row2) return {
1565
+ status: "not_found"
1566
+ };
1567
+ const result = transition(row2.proposal, this.clock());
1568
+ if (!result.proposal || canonicalActionProposalJson3(result.proposal) === canonicalActionProposalJson3(row2.proposal)) return result;
1569
+ const changed = await affectedRows(this.dialect, this.db.update(this.table).set({
1570
+ proposal: result.proposal,
1571
+ decision: result.proposal.decision,
1572
+ ...discoveryMetadata(result.proposal),
1573
+ version: row2.version + 1
1574
+ }).where(and(eq(this.table.id, physicalId(id)), eq(this.table.scopeKey, scopeKey(scope)), eq(this.table.version, row2.version))), this.table.id);
1575
+ if (changed === 1) return result;
1576
+ }
1577
+ const row = await this.read(scope, id);
1578
+ return row ? {
1579
+ status: "conflict",
1580
+ proposal: row.proposal
1581
+ } : {
1582
+ status: "not_found"
1583
+ };
1584
+ }
1585
+ };
1586
+ function scopeKey(scope) {
1587
+ return createHash("sha256").update(canonicalActionProposalJson3([
1588
+ scope.tenantRef,
1589
+ scope.actorRef,
1590
+ scope.threadId
1591
+ ])).digest("hex");
1592
+ }
1593
+ __name(scopeKey, "scopeKey");
1594
+ function physicalId(id) {
1595
+ return createHash("sha256").update(canonicalActionProposalJson3(id)).digest("hex");
1596
+ }
1597
+ __name(physicalId, "physicalId");
1598
+ function logicalSort(id) {
1599
+ let sort = "";
1600
+ for (let index4 = 0; index4 < id.length; index4++) sort += id.charCodeAt(index4).toString(16).padStart(4, "0");
1601
+ return sort;
1602
+ }
1603
+ __name(logicalSort, "logicalSort");
1604
+ function discoveryMetadata(proposal) {
1605
+ return {
1606
+ replacementGroupKey: replacementGroupKey(proposal),
1607
+ deliveryStatus: proposal.outcomeDelivery?.status ?? null,
1608
+ deliveryLeaseExpiresAt: proposal.outcomeDelivery?.lease?.expiresAt ?? null,
1609
+ outcomeIdKey: proposal.outcome ? physicalId(proposal.outcome.id) : null,
1610
+ executionStatus: proposal.execution?.status ?? null,
1611
+ leaseExpiresAt: proposal.execution?.lease?.expiresAt ?? null,
1612
+ proposalExpiresAt: proposal.expiresAt,
1613
+ discoveryIndexVersion: 1
1614
+ };
1615
+ }
1616
+ __name(discoveryMetadata, "discoveryMetadata");
1617
+ function lockQuery(query, dialect) {
1618
+ return dialect === "sqlite" ? query : query.for("update");
1619
+ }
1620
+ __name(lockQuery, "lockQuery");
1621
+ function runSync(steps) {
1622
+ let next = steps.next();
1623
+ while (!next.done) {
1624
+ const { kind, query } = next.value;
1625
+ const statement = query;
1626
+ next = steps.next(kind === "read" ? statement.all() : statement.run());
1627
+ }
1628
+ return next.value;
1629
+ }
1630
+ __name(runSync, "runSync");
1631
+ async function runAsync(steps) {
1632
+ let next = steps.next();
1633
+ while (!next.done) next = steps.next(await next.value.query);
1634
+ return next.value;
1635
+ }
1636
+ __name(runAsync, "runAsync");
1637
+ function replacementGroupKey(proposal) {
1638
+ return proposal.replacementKey ? physicalId(canonicalActionProposalJson3([
1639
+ proposal.toolName,
1640
+ proposal.replacementKey
1641
+ ])) : null;
1642
+ }
1643
+ __name(replacementGroupKey, "replacementGroupKey");
1644
+
1645
+ // src/drizzle-agent-store.ts
1005
1646
  function turnMessageColumns(message) {
1006
1647
  return {
1007
1648
  id: message.id,
@@ -1022,11 +1663,61 @@ var DrizzleAgentStore = class {
1022
1663
  db;
1023
1664
  dialect;
1024
1665
  t;
1025
- constructor(db) {
1666
+ proposals;
1667
+ constructor(db, options = {}) {
1668
+ this.proposals = new DrizzleActionProposalStore(db, options);
1026
1669
  this.dialect = agentDialectOf(db);
1027
1670
  this.t = agentTablesFor(this.dialect);
1028
1671
  this.db = asBuilder(db);
1029
1672
  }
1673
+ createActionProposal(...args) {
1674
+ return this.proposals.createActionProposal(...args);
1675
+ }
1676
+ getActionProposal(...args) {
1677
+ return this.proposals.getActionProposal(...args);
1678
+ }
1679
+ listActionProposals(...args) {
1680
+ return this.proposals.listActionProposals(...args);
1681
+ }
1682
+ decideActionProposal(...args) {
1683
+ return this.proposals.decideActionProposal(...args);
1684
+ }
1685
+ claimActionProposal(...args) {
1686
+ return this.proposals.claimActionProposal(...args);
1687
+ }
1688
+ extendActionProposalLease(...args) {
1689
+ return this.proposals.extendActionProposalLease(...args);
1690
+ }
1691
+ claimNextActionProposal(...args) {
1692
+ return this.proposals.claimNextActionProposal(...args);
1693
+ }
1694
+ expireActionProposals(...args) {
1695
+ return this.proposals.expireActionProposals(...args);
1696
+ }
1697
+ backfillActionProposalDiscoveryIndex(command) {
1698
+ return this.proposals.backfillActionProposalDiscoveryIndex(command);
1699
+ }
1700
+ settleActionProposal(...args) {
1701
+ return this.proposals.settleActionProposal(...args);
1702
+ }
1703
+ createReplacingActionProposal(...args) {
1704
+ return this.proposals.createReplacingActionProposal(...args);
1705
+ }
1706
+ supersedeActionProposal(...args) {
1707
+ return this.proposals.supersedeActionProposal(...args);
1708
+ }
1709
+ get actionProposalAdmissionSupported() {
1710
+ return this.proposals.actionProposalAdmissionSupported;
1711
+ }
1712
+ getThreadActionProposalScope(threadId) {
1713
+ return this.proposals.getThreadActionProposalScope(threadId);
1714
+ }
1715
+ claimNextActionProposalOutcome(...args) {
1716
+ return this.proposals.claimNextActionProposalOutcome(...args);
1717
+ }
1718
+ admitActionProposalOutcome(...args) {
1719
+ return this.proposals.admitActionProposalOutcome(...args);
1720
+ }
1030
1721
  async createThread(input) {
1031
1722
  const now = /* @__PURE__ */ new Date();
1032
1723
  const thread = {
@@ -1048,11 +1739,11 @@ var DrizzleAgentStore = class {
1048
1739
  return this.toSummary(thread);
1049
1740
  }
1050
1741
  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)));
1742
+ const [thread] = await this.db.select().from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1052
1743
  if (thread === void 0) {
1053
1744
  return null;
1054
1745
  }
1055
- const messages = await this.db.select().from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1746
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1056
1747
  const last = messages[messages.length - 1];
1057
1748
  const approvals = await this.approvalsFor(messages.map((message) => message.id));
1058
1749
  return {
@@ -1087,14 +1778,14 @@ var DrizzleAgentStore = class {
1087
1778
  const [thread] = await this.db.select({
1088
1779
  title: this.t.agentThread.title,
1089
1780
  defaultAgent: this.t.agentThread.defaultAgent
1090
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, query.threadId), isNull(this.t.agentThread.deletedAt)));
1781
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, query.threadId), isNull2(this.t.agentThread.deletedAt)));
1091
1782
  if (thread === void 0) {
1092
1783
  return null;
1093
1784
  }
1094
1785
  const messages = await this.loadTurnWindow(query.threadId, query.messageLimit);
1095
1786
  const [answered] = await this.db.select({
1096
1787
  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);
1788
+ }).from(this.t.agentMessage).where(and2(eq2(this.t.agentMessage.threadId, query.threadId), eq2(this.t.agentMessage.role, "assistant"))).limit(1);
1098
1789
  return {
1099
1790
  title: thread.title,
1100
1791
  defaultAgent: thread.defaultAgent,
@@ -1110,15 +1801,15 @@ var DrizzleAgentStore = class {
1110
1801
  if (limit !== void 0 && limit <= 0) {
1111
1802
  return [];
1112
1803
  }
1113
- const window = this.db.select(turnMessageColumns(this.t.agentMessage)).from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrderNewestFirst());
1804
+ const window = this.db.select(turnMessageColumns(this.t.agentMessage)).from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrderNewestFirst());
1114
1805
  const rows = limit === void 0 ? await window : await window.limit(limit);
1115
1806
  return rows.reverse().map((row) => this.toStoredMessage(row));
1116
1807
  }
1117
1808
  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);
1809
+ 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
1810
  const summaries = [];
1120
1811
  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);
1812
+ const [last] = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, thread.id)).orderBy(...this.messageOrderNewestFirst()).limit(1);
1122
1813
  summaries.push(this.toSummary(thread, last?.content));
1123
1814
  }
1124
1815
  return summaries;
@@ -1126,14 +1817,14 @@ var DrizzleAgentStore = class {
1126
1817
  async softDeleteThread(threadId) {
1127
1818
  await this.db.update(this.t.agentThread).set({
1128
1819
  deletedAt: /* @__PURE__ */ new Date()
1129
- }).where(eq(this.t.agentThread.id, threadId));
1820
+ }).where(eq2(this.t.agentThread.id, threadId));
1130
1821
  }
1131
1822
  async forkThread(threadId, fromMessageId) {
1132
- const [source] = await this.db.select().from(this.t.agentThread).where(eq(this.t.agentThread.id, threadId));
1823
+ const [source] = await this.db.select().from(this.t.agentThread).where(eq2(this.t.agentThread.id, threadId));
1133
1824
  if (source === void 0) {
1134
1825
  throw new Error(`thread ${threadId} not found`);
1135
1826
  }
1136
- const messages = await this.db.select().from(this.t.agentMessage).where(eq(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1827
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1137
1828
  const cutoff = messages.findIndex((message) => message.id === fromMessageId);
1138
1829
  const kept = cutoff >= 0 ? messages.slice(0, cutoff + 1) : messages;
1139
1830
  const now = /* @__PURE__ */ new Date();
@@ -1176,6 +1867,7 @@ var DrizzleAgentStore = class {
1176
1867
  reasoning: message.reasoning,
1177
1868
  reasoningMs: message.reasoningMs,
1178
1869
  ui: message.ui,
1870
+ actionProposalOutcome: message.actionProposalOutcome,
1179
1871
  createdAt: message.createdAt
1180
1872
  })));
1181
1873
  }
@@ -1184,20 +1876,20 @@ var DrizzleAgentStore = class {
1184
1876
  async ownerOfThread(threadId) {
1185
1877
  const [thread] = await this.db.select({
1186
1878
  actorRef: this.t.agentThread.actorRef
1187
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
1879
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1188
1880
  return thread?.actorRef ?? null;
1189
1881
  }
1190
1882
  async ownerOfToolCall(toolCallId) {
1191
1883
  const [row] = await this.db.select({
1192
1884
  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));
1885
+ }).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
1886
  return row?.actorRef ?? null;
1195
1887
  }
1196
1888
  async runForToolCall(toolCallId) {
1197
1889
  const [row] = await this.db.select({
1198
1890
  runId: this.t.agentToolCall.runId,
1199
1891
  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));
1892
+ }).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
1893
  return row?.runId ?? row?.activeStreamId ?? null;
1202
1894
  }
1203
1895
  /**
@@ -1215,12 +1907,13 @@ var DrizzleAgentStore = class {
1215
1907
  messageId: this.t.agentToolCall.messageId,
1216
1908
  status: this.t.agentToolCall.status,
1217
1909
  approver: this.t.agentToolCall.approver,
1910
+ confirmation: this.t.agentToolCall.confirmation,
1218
1911
  expiresAt: this.t.agentToolCall.expiresAt,
1219
1912
  remember: this.t.agentToolCall.remember,
1220
1913
  executedByRef: this.t.agentToolCall.executedByRef,
1221
1914
  decidedVia: this.t.agentToolCall.decidedVia,
1222
1915
  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));
1916
+ }).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
1917
  for (const row of rows) {
1225
1918
  const approval = toolCallApprovalFromRow({
1226
1919
  ...row,
@@ -1239,13 +1932,20 @@ var DrizzleAgentStore = class {
1239
1932
  async rememberedApprovals(threadId) {
1240
1933
  const rows = await this.db.selectDistinct({
1241
1934
  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);
1935
+ }).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)));
1936
+ const scope = await this.getThreadActionProposalScope(threadId);
1937
+ const proposalNames = scope ? await this.proposals.rememberedActionProposalApprovals(scope) : [];
1938
+ return [
1939
+ .../* @__PURE__ */ new Set([
1940
+ ...rows.map((row) => row.toolName),
1941
+ ...proposalNames
1942
+ ])
1943
+ ];
1244
1944
  }
1245
1945
  async toolCallInput(toolCallId) {
1246
1946
  const [row] = await this.db.select({
1247
1947
  input: this.t.agentToolCall.input
1248
- }).from(this.t.agentToolCall).where(eq(this.t.agentToolCall.id, toolCallId));
1948
+ }).from(this.t.agentToolCall).where(eq2(this.t.agentToolCall.id, toolCallId));
1249
1949
  return row?.input ?? null;
1250
1950
  }
1251
1951
  async toolCallApproval(toolCallId) {
@@ -1253,7 +1953,7 @@ var DrizzleAgentStore = class {
1253
1953
  status: this.t.agentToolCall.status,
1254
1954
  approver: this.t.agentToolCall.approver,
1255
1955
  expiresAt: this.t.agentToolCall.expiresAt
1256
- }).from(this.t.agentToolCall).where(eq(this.t.agentToolCall.id, toolCallId));
1956
+ }).from(this.t.agentToolCall).where(eq2(this.t.agentToolCall.id, toolCallId));
1257
1957
  if (row === void 0) {
1258
1958
  return null;
1259
1959
  }
@@ -1266,26 +1966,26 @@ var DrizzleAgentStore = class {
1266
1966
  async ownerOfActiveStream(runId) {
1267
1967
  const [thread] = await this.db.select({
1268
1968
  actorRef: this.t.agentThread.actorRef
1269
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.activeStreamId, runId), isNull(this.t.agentThread.deletedAt)));
1969
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.activeStreamId, runId), isNull2(this.t.agentThread.deletedAt)));
1270
1970
  return thread?.actorRef ?? null;
1271
1971
  }
1272
1972
  async setTitle(threadId, title) {
1273
1973
  await this.db.update(this.t.agentThread).set({
1274
1974
  title,
1275
1975
  updatedAt: /* @__PURE__ */ new Date()
1276
- }).where(eq(this.t.agentThread.id, threadId));
1976
+ }).where(eq2(this.t.agentThread.id, threadId));
1277
1977
  }
1278
1978
  async promoteThread(threadId) {
1279
1979
  await this.db.update(this.t.agentThread).set({
1280
1980
  transient: false,
1281
1981
  updatedAt: /* @__PURE__ */ new Date()
1282
- }).where(and(eq(this.t.agentThread.id, threadId), eq(this.t.agentThread.transient, true)));
1982
+ }).where(and2(eq2(this.t.agentThread.id, threadId), eq2(this.t.agentThread.transient, true)));
1283
1983
  }
1284
1984
  /** Who holds the thread's stream right now, deleted or not. */
1285
1985
  async activeHolder(threadId) {
1286
1986
  const [thread] = await this.db.select({
1287
1987
  activeStreamId: this.t.agentThread.activeStreamId
1288
- }).from(this.t.agentThread).where(eq(this.t.agentThread.id, threadId));
1988
+ }).from(this.t.agentThread).where(eq2(this.t.agentThread.id, threadId));
1289
1989
  return thread?.activeStreamId ?? null;
1290
1990
  }
1291
1991
  /**
@@ -1297,16 +1997,16 @@ var DrizzleAgentStore = class {
1297
1997
  messageOrder() {
1298
1998
  const message = this.t.agentMessage;
1299
1999
  return [
1300
- asc(sql2`coalesce(${message.seq}, 0)`),
1301
- asc(message.createdAt),
1302
- asc(message.id)
2000
+ asc2(sql3`coalesce(${message.seq}, 0)`),
2001
+ asc2(message.createdAt),
2002
+ asc2(message.id)
1303
2003
  ];
1304
2004
  }
1305
2005
  /** {@link messageOrder}, newest first. */
1306
2006
  messageOrderNewestFirst() {
1307
2007
  const message = this.t.agentMessage;
1308
2008
  return [
1309
- desc(sql2`coalesce(${message.seq}, 0)`),
2009
+ desc(sql3`coalesce(${message.seq}, 0)`),
1310
2010
  desc(message.createdAt),
1311
2011
  desc(message.id)
1312
2012
  ];
@@ -1317,15 +2017,15 @@ var DrizzleAgentStore = class {
1317
2017
  */
1318
2018
  async nextMessageSeq(threadId) {
1319
2019
  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));
2020
+ last: max2(this.t.agentMessage.seq)
2021
+ }).from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId));
1322
2022
  return Number(row?.last ?? 0) + 1;
1323
2023
  }
1324
2024
  /** The run streaming the thread, or `null` — a projection of the one column. */
1325
2025
  async activeRunForThread(threadId) {
1326
2026
  const [thread] = await this.db.select({
1327
2027
  activeStreamId: this.t.agentThread.activeStreamId
1328
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2028
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1329
2029
  return thread?.activeStreamId ?? null;
1330
2030
  }
1331
2031
  /**
@@ -1334,15 +2034,15 @@ var DrizzleAgentStore = class {
1334
2034
  */
1335
2035
  async claimActiveStream(threadId, runId, options = {}) {
1336
2036
  const holders = [
1337
- isNull(this.t.agentThread.activeStreamId),
1338
- eq(this.t.agentThread.activeStreamId, runId),
2037
+ isNull2(this.t.agentThread.activeStreamId),
2038
+ eq2(this.t.agentThread.activeStreamId, runId),
1339
2039
  ...options.replacing !== void 0 ? [
1340
- eq(this.t.agentThread.activeStreamId, options.replacing)
2040
+ eq2(this.t.agentThread.activeStreamId, options.replacing)
1341
2041
  ] : []
1342
2042
  ];
1343
2043
  const claimed = await affectedRows(this.dialect, this.db.update(this.t.agentThread).set({
1344
2044
  activeStreamId: runId
1345
- }).where(and(eq(this.t.agentThread.id, threadId), or(...holders))), this.t.agentThread.id);
2045
+ }).where(and2(eq2(this.t.agentThread.id, threadId), or2(...holders))), this.t.agentThread.id);
1346
2046
  if (claimed > 0) {
1347
2047
  return true;
1348
2048
  }
@@ -1351,21 +2051,22 @@ var DrizzleAgentStore = class {
1351
2051
  async releaseActiveStream(threadId, runId) {
1352
2052
  const released = await affectedRows(this.dialect, this.db.update(this.t.agentThread).set({
1353
2053
  activeStreamId: null
1354
- }).where(and(eq(this.t.agentThread.id, threadId), eq(this.t.agentThread.activeStreamId, runId))), this.t.agentThread.id);
2054
+ }).where(and2(eq2(this.t.agentThread.id, threadId), eq2(this.t.agentThread.activeStreamId, runId))), this.t.agentThread.id);
1355
2055
  return released > 0;
1356
2056
  }
1357
2057
  async enqueueMessage(input) {
1358
2058
  const now = /* @__PURE__ */ new Date();
1359
2059
  const [edge] = await this.db.select({
1360
2060
  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));
2061
+ last: max2(this.t.agentQueuedMessage.position)
2062
+ }).from(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.threadId, input.threadId));
1363
2063
  const position = input.at === "head" ? (edge?.first ?? 1) - 1 : (edge?.last ?? -1) + 1;
1364
2064
  const row = {
1365
2065
  id: crypto.randomUUID(),
1366
2066
  threadId: input.threadId,
1367
2067
  actor: input.actor,
1368
2068
  content: input.content,
2069
+ uiCapabilities: input.uiCapabilities ?? null,
1369
2070
  attachments: input.attachments !== void 0 && input.attachments.length > 0 ? input.attachments : null,
1370
2071
  agentName: input.agentName ?? null,
1371
2072
  persona: input.persona ?? null,
@@ -1380,11 +2081,11 @@ var DrizzleAgentStore = class {
1380
2081
  return toQueuedMessage(row);
1381
2082
  }
1382
2083
  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));
2084
+ 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
2085
  return rows.map(toQueuedMessage);
1385
2086
  }
1386
2087
  async getQueuedMessage(id) {
1387
- const [row] = await this.db.select().from(this.t.agentQueuedMessage).where(eq(this.t.agentQueuedMessage.id, id));
2088
+ const [row] = await this.db.select().from(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.id, id));
1388
2089
  return row === void 0 ? null : toQueuedMessage(row);
1389
2090
  }
1390
2091
  async updateQueuedMessage(id, patch) {
@@ -1400,7 +2101,7 @@ var DrizzleAgentStore = class {
1400
2101
  if (patch.interrupt !== void 0) {
1401
2102
  updates.interrupt = patch.interrupt;
1402
2103
  }
1403
- await this.db.update(this.t.agentQueuedMessage).set(updates).where(eq(this.t.agentQueuedMessage.id, id));
2104
+ await this.db.update(this.t.agentQueuedMessage).set(updates).where(eq2(this.t.agentQueuedMessage.id, id));
1404
2105
  return this.getQueuedMessage(id);
1405
2106
  }
1406
2107
  /** Rewrites the thread's positions as 0..n-1 in the new order — a queue is a handful of rows. */
@@ -1415,32 +2116,32 @@ var DrizzleAgentStore = class {
1415
2116
  for (const [position, message] of order.entries()) {
1416
2117
  await this.db.update(this.t.agentQueuedMessage).set({
1417
2118
  position
1418
- }).where(eq(this.t.agentQueuedMessage.id, message.id));
2119
+ }).where(eq2(this.t.agentQueuedMessage.id, message.id));
1419
2120
  }
1420
2121
  return true;
1421
2122
  }
1422
2123
  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);
2124
+ const removed = await affectedRows(this.dialect, this.db.delete(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.id, id)), this.t.agentQueuedMessage.id);
1424
2125
  return removed > 0;
1425
2126
  }
1426
2127
  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);
2128
+ return affectedRows(this.dialect, this.db.delete(this.t.agentQueuedMessage).where(eq2(this.t.agentQueuedMessage.threadId, threadId)), this.t.agentQueuedMessage.id);
1428
2129
  }
1429
2130
  async queuePause(threadId) {
1430
2131
  const [thread] = await this.db.select({
1431
2132
  queuePause: this.t.agentThread.queuePause
1432
- }).from(this.t.agentThread).where(eq(this.t.agentThread.id, threadId));
2133
+ }).from(this.t.agentThread).where(eq2(this.t.agentThread.id, threadId));
1433
2134
  return thread?.queuePause ?? null;
1434
2135
  }
1435
2136
  async setQueuePause(threadId, pause) {
1436
2137
  await this.db.update(this.t.agentThread).set({
1437
2138
  queuePause: pause
1438
- }).where(eq(this.t.agentThread.id, threadId));
2139
+ }).where(eq2(this.t.agentThread.id, threadId));
1439
2140
  }
1440
2141
  async setActiveStream(threadId, runId) {
1441
2142
  await this.db.update(this.t.agentThread).set({
1442
2143
  activeStreamId: runId
1443
- }).where(eq(this.t.agentThread.id, threadId));
2144
+ }).where(eq2(this.t.agentThread.id, threadId));
1444
2145
  }
1445
2146
  /**
1446
2147
  * Patch a thread's `title` and/or `defaultAgent`. Each field is only touched when PRESENT in
@@ -1466,7 +2167,7 @@ var DrizzleAgentStore = class {
1466
2167
  return;
1467
2168
  }
1468
2169
  updates.updatedAt = /* @__PURE__ */ new Date();
1469
- await this.db.update(this.t.agentThread).set(updates).where(eq(this.t.agentThread.id, threadId));
2170
+ await this.db.update(this.t.agentThread).set(updates).where(eq2(this.t.agentThread.id, threadId));
1470
2171
  }
1471
2172
  /**
1472
2173
  * The thread's default agent, projected — the caller wants one nullable scalar to decide which
@@ -1477,20 +2178,20 @@ var DrizzleAgentStore = class {
1477
2178
  async modelForThread(threadId) {
1478
2179
  const [thread] = await this.db.select({
1479
2180
  model: this.t.agentThread.model
1480
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2181
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1481
2182
  return thread?.model ?? null;
1482
2183
  }
1483
2184
  /** The thread's pinned persona, projected like {@link defaultAgentForThread}. */
1484
2185
  async personaForThread(threadId) {
1485
2186
  const [thread] = await this.db.select({
1486
2187
  persona: this.t.agentThread.persona
1487
- }).from(agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2188
+ }).from(agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1488
2189
  return thread?.persona ?? null;
1489
2190
  }
1490
2191
  async defaultAgentForThread(threadId) {
1491
2192
  const [thread] = await this.db.select({
1492
2193
  defaultAgent: this.t.agentThread.defaultAgent
1493
- }).from(this.t.agentThread).where(and(eq(this.t.agentThread.id, threadId), isNull(this.t.agentThread.deletedAt)));
2194
+ }).from(this.t.agentThread).where(and2(eq2(this.t.agentThread.id, threadId), isNull2(this.t.agentThread.deletedAt)));
1494
2195
  return thread?.defaultAgent ?? null;
1495
2196
  }
1496
2197
  /**
@@ -1532,16 +2233,16 @@ var DrizzleAgentStore = class {
1532
2233
  if (end.errorMessage !== void 0) {
1533
2234
  updates.errorMessage = end.errorMessage;
1534
2235
  }
1535
- await this.db.update(this.t.agentRun).set(updates).where(eq(this.t.agentRun.id, end.runId));
2236
+ await this.db.update(this.t.agentRun).set(updates).where(eq2(this.t.agentRun.id, end.runId));
1536
2237
  }
1537
2238
  /** Bump the run's llm-step retry counter. Atomic `retries = retries + 1`, no read-modify-write. */
1538
2239
  async bumpRunRetries(runId) {
1539
2240
  await this.db.update(this.t.agentRun).set({
1540
- retries: sql2`${this.t.agentRun.retries} + 1`
1541
- }).where(eq(this.t.agentRun.id, runId));
2241
+ retries: sql3`${this.t.agentRun.retries} + 1`
2242
+ }).where(eq2(this.t.agentRun.id, runId));
1542
2243
  }
1543
2244
  async appendMessage(input) {
1544
- const [thread] = await this.db.select().from(this.t.agentThread).where(eq(this.t.agentThread.id, input.threadId));
2245
+ const [thread] = await this.db.select().from(this.t.agentThread).where(eq2(this.t.agentThread.id, input.threadId));
1545
2246
  if (thread === void 0) {
1546
2247
  throw new Error(`thread ${input.threadId} not found`);
1547
2248
  }
@@ -1551,6 +2252,7 @@ var DrizzleAgentStore = class {
1551
2252
  threadId: input.threadId,
1552
2253
  role: input.role,
1553
2254
  content: input.content,
2255
+ actionProposalOutcome: input.actionProposalOutcome ? canonicalActionProposalJson4(input.actionProposalOutcome) : null,
1554
2256
  toolCalls: input.toolCalls ?? null,
1555
2257
  toolResults: input.toolResults ?? null,
1556
2258
  attachments: input.attachments ?? null,
@@ -1569,32 +2271,32 @@ var DrizzleAgentStore = class {
1569
2271
  await this.db.insert(this.t.agentMessage).values(message);
1570
2272
  await this.db.update(this.t.agentThread).set({
1571
2273
  updatedAt: now
1572
- }).where(eq(this.t.agentThread.id, input.threadId));
2274
+ }).where(eq2(this.t.agentThread.id, input.threadId));
1573
2275
  return this.toStoredMessage(message);
1574
2276
  }
1575
2277
  async setMessageToolResults(messageId, results) {
1576
2278
  await this.db.update(this.t.agentMessage).set({
1577
2279
  toolResults: results
1578
- }).where(eq(this.t.agentMessage.id, messageId));
2280
+ }).where(eq2(this.t.agentMessage.id, messageId));
1579
2281
  }
1580
2282
  async setMessageUi(messageId, ui) {
1581
2283
  await this.db.update(this.t.agentMessage).set({
1582
2284
  ui: ui.length > 0 ? ui : null
1583
- }).where(eq(this.t.agentMessage.id, messageId));
2285
+ }).where(eq2(this.t.agentMessage.id, messageId));
1584
2286
  }
1585
2287
  async threadOfMessage(messageId) {
1586
2288
  const [row] = await this.db.select({
1587
2289
  threadId: this.t.agentMessage.threadId
1588
- }).from(this.t.agentMessage).where(eq(this.t.agentMessage.id, messageId)).limit(1);
2290
+ }).from(this.t.agentMessage).where(eq2(this.t.agentMessage.id, messageId)).limit(1);
1589
2291
  return row?.threadId ?? null;
1590
2292
  }
1591
2293
  async setMessageFeedback(messageId, feedback) {
1592
2294
  await this.db.update(this.t.agentMessage).set({
1593
2295
  feedback
1594
- }).where(eq(this.t.agentMessage.id, messageId));
2296
+ }).where(eq2(this.t.agentMessage.id, messageId));
1595
2297
  }
1596
2298
  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());
2299
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq2(this.t.agentMessage.threadId, threadId)).orderBy(...this.messageOrder());
1598
2300
  const cutoff = messages.findIndex((message) => message.id === messageId);
1599
2301
  if (cutoff < 0) {
1600
2302
  return;
@@ -1606,6 +2308,7 @@ var DrizzleAgentStore = class {
1606
2308
  async recordToolCall(input) {
1607
2309
  await this.db.insert(this.t.agentToolCall).values({
1608
2310
  id: input.toolCallId,
2311
+ proposalId: input.proposalId ?? null,
1609
2312
  messageId: input.messageId,
1610
2313
  toolName: input.toolName,
1611
2314
  toolType: input.toolType,
@@ -1619,6 +2322,7 @@ var DrizzleAgentStore = class {
1619
2322
  executedAt: null,
1620
2323
  runId: input.runId ?? null,
1621
2324
  approver: input.approver ?? null,
2325
+ confirmation: input.confirmation ?? null,
1622
2326
  expiresAt: input.expiresAt !== void 0 ? new Date(input.expiresAt) : null,
1623
2327
  remember: null,
1624
2328
  decidedVia: null
@@ -1649,7 +2353,7 @@ var DrizzleAgentStore = class {
1649
2353
  if (input.status === "executed" || input.status === "auto_executed") {
1650
2354
  updates.executedAt = /* @__PURE__ */ new Date();
1651
2355
  }
1652
- await this.db.update(this.t.agentToolCall).set(updates).where(eq(this.t.agentToolCall.id, input.toolCallId));
2356
+ await this.db.update(this.t.agentToolCall).set(updates).where(eq2(this.t.agentToolCall.id, input.toolCallId));
1653
2357
  }
1654
2358
  async toolCallOutcomes(toolCallIds) {
1655
2359
  if (toolCallIds.length === 0) {
@@ -1675,7 +2379,7 @@ var DrizzleAgentStore = class {
1675
2379
  }));
1676
2380
  }
1677
2381
  async failUnsettledToolCalls(runId, error) {
1678
- const pending = and(eq(this.t.agentToolCall.runId, runId), eq(this.t.agentToolCall.status, "pending_approval"));
2382
+ const pending = and2(eq2(this.t.agentToolCall.runId, runId), eq2(this.t.agentToolCall.status, "pending_approval"));
1679
2383
  const rows = await this.db.select({
1680
2384
  id: this.t.agentToolCall.id
1681
2385
  }).from(this.t.agentToolCall).where(pending);
@@ -1708,10 +2412,10 @@ var DrizzleAgentStore = class {
1708
2412
  }
1709
2413
  const rows = await this.db.select({
1710
2414
  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)));
2415
+ }).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
2416
  const queued = await this.db.select({
1713
2417
  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)));
2418
+ }).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
2419
  const wanted = new Set(mediaIds);
1716
2420
  const found = /* @__PURE__ */ new Set();
1717
2421
  for (const row of [
@@ -1750,7 +2454,7 @@ var DrizzleAgentStore = class {
1750
2454
  async usageBetween(actorRef, fromDay, toDay) {
1751
2455
  const start = /* @__PURE__ */ new Date(`${fromDay}T00:00:00.000Z`);
1752
2456
  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)));
2457
+ 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
2458
  const usedTokens = rows.reduce((sum2, row) => sum2 + row.inputTokens + row.outputTokens, 0);
1755
2459
  const costUsd = rows.reduce((sum2, row) => sum2 + (row.costUsd ?? 0), 0);
1756
2460
  return {
@@ -1776,7 +2480,12 @@ var DrizzleAgentStore = class {
1776
2480
  };
1777
2481
  }
1778
2482
  toStoredMessage(message) {
2483
+ const outcome = message.actionProposalOutcome ? JSON.parse(message.actionProposalOutcome) : void 0;
1779
2484
  return {
2485
+ ...outcome ? {
2486
+ actionProposalOutcome: outcome,
2487
+ ui: outcome.ui
2488
+ } : {},
1780
2489
  id: message.id,
1781
2490
  role: message.role,
1782
2491
  content: message.content,
@@ -1822,6 +2531,9 @@ var DrizzleAgentStore = class {
1822
2531
  };
1823
2532
  function toQueuedMessage(row) {
1824
2533
  return {
2534
+ ...row.uiCapabilities !== null ? {
2535
+ uiCapabilities: row.uiCapabilities
2536
+ } : {},
1825
2537
  id: row.id,
1826
2538
  threadId: row.threadId,
1827
2539
  actor: row.actor,
@@ -1852,7 +2564,7 @@ __name(toQueuedMessage, "toQueuedMessage");
1852
2564
 
1853
2565
  // src/drizzle-governance-queries.ts
1854
2566
  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";
2567
+ 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
2568
  var UNCLASSIFIED_ERROR_CODE = "unknown";
1857
2569
  var DEFAULT_AGENT_BUCKET = "(default)";
1858
2570
  var TOOL_CALL_STATUSES = [
@@ -1990,7 +2702,7 @@ var DrizzleGovernanceQueries = class {
1990
2702
  }
1991
2703
  async usageInRange(range) {
1992
2704
  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)));
2705
+ 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
2706
  return rows.map(toUsageInput);
1995
2707
  }
1996
2708
  async spendByModel(range) {
@@ -2015,7 +2727,7 @@ var DrizzleGovernanceQueries = class {
2015
2727
  if (threadIds.length === 0) {
2016
2728
  return [];
2017
2729
  }
2018
- const threads = await this.db.select().from(this.t.agentThread).where(and2(inArray2(this.t.agentThread.id, threadIds), isNull2(this.t.agentThread.deletedAt)));
2730
+ const threads = await this.db.select().from(this.t.agentThread).where(and3(inArray2(this.t.agentThread.id, threadIds), isNull3(this.t.agentThread.deletedAt)));
2019
2731
  const threadsById = new Map(threads.map((thread) => [
2020
2732
  thread.id,
2021
2733
  {
@@ -2041,7 +2753,7 @@ var DrizzleGovernanceQueries = class {
2041
2753
  threadId: this.t.agentMessage.threadId,
2042
2754
  createdAt: this.t.agentToolCall.createdAt,
2043
2755
  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);
2756
+ }).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
2757
  return rows.map((row) => ({
2046
2758
  toolCallId: row.toolCallId,
2047
2759
  toolName: row.toolName,
@@ -2107,12 +2819,12 @@ var DrizzleGovernanceQueries = class {
2107
2819
  });
2108
2820
  }
2109
2821
  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);
2822
+ 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
2823
  return this.toThreadActivityRows(threads);
2112
2824
  }
2113
2825
  async runsInRange(range) {
2114
2826
  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)));
2827
+ return this.db.select().from(this.t.agentRun).where(and3(gte2(this.t.agentRun.startedAt, start), lte3(this.t.agentRun.startedAt, end)));
2116
2828
  }
2117
2829
  async runMetrics(range) {
2118
2830
  const runs = await this.runsInRange(range);
@@ -2169,7 +2881,7 @@ var DrizzleGovernanceQueries = class {
2169
2881
  }
2170
2882
  async runErrors(range) {
2171
2883
  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")));
2884
+ 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
2885
  const byError = /* @__PURE__ */ new Map();
2174
2886
  for (const run of runs) {
2175
2887
  const errorCode = run.errorCode ?? UNCLASSIFIED_ERROR_CODE;
@@ -2228,7 +2940,7 @@ var DrizzleGovernanceQueries = class {
2228
2940
  agentName: this.t.agentMessage.agentName,
2229
2941
  requestedAt: this.t.agentToolCall.createdAt,
2230
2942
  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);
2943
+ }).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
2944
  return rows.map((row) => ({
2233
2945
  toolCallId: row.toolCallId,
2234
2946
  toolName: row.toolName,
@@ -2250,7 +2962,7 @@ var DrizzleGovernanceQueries = class {
2250
2962
  */
2251
2963
  async toolStats(range) {
2252
2964
  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)));
2965
+ 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
2966
  const byTool = /* @__PURE__ */ new Map();
2255
2967
  for (const call of calls) {
2256
2968
  const key2 = `${call.toolName} ${call.toolType}`;
@@ -2300,10 +3012,10 @@ var DrizzleGovernanceQueries = class {
2300
3012
  if (filters?.toolType !== void 0 && !isToolKind(filters.toolType)) {
2301
3013
  return emptyPage(query);
2302
3014
  }
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);
3015
+ 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
3016
  const [totalRow] = await this.db.select({
2305
3017
  value: count()
2306
- }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq2(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(whereClause);
3018
+ }).from(this.t.agentToolCall).innerJoin(this.t.agentMessage, eq3(this.t.agentToolCall.messageId, this.t.agentMessage.id)).where(whereClause);
2307
3019
  const rows = await this.db.select({
2308
3020
  toolCallId: this.t.agentToolCall.id,
2309
3021
  toolName: this.t.agentToolCall.toolName,
@@ -2312,7 +3024,7 @@ var DrizzleGovernanceQueries = class {
2312
3024
  threadId: this.t.agentMessage.threadId,
2313
3025
  createdAt: this.t.agentToolCall.createdAt,
2314
3026
  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);
3027
+ }).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
3028
  return {
2317
3029
  rows: rows.map((row) => ({
2318
3030
  toolCallId: row.toolCallId,
@@ -2336,7 +3048,7 @@ var DrizzleGovernanceQueries = class {
2336
3048
  */
2337
3049
  async threadsPage(query) {
2338
3050
  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);
3051
+ 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
3052
  const [totalRow] = await this.db.select({
2341
3053
  value: count()
2342
3054
  }).from(this.t.agentThread).where(whereClause);
@@ -2358,7 +3070,7 @@ var DrizzleGovernanceQueries = class {
2358
3070
  if (filters?.status !== void 0 && !isRunStatus(filters.status)) {
2359
3071
  return emptyPage(query);
2360
3072
  }
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);
3073
+ 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
3074
  const [totalRow] = await this.db.select({
2363
3075
  value: count()
2364
3076
  }).from(this.t.agentRun).where(whereClause);
@@ -2382,10 +3094,10 @@ var DrizzleGovernanceQueries = class {
2382
3094
  */
2383
3095
  async approvalsPage(query) {
2384
3096
  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);
3097
+ 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
3098
  const [totalRow] = await this.db.select({
2387
3099
  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);
3100
+ }).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
3101
  const rows = await this.db.select({
2390
3102
  toolCallId: this.t.agentToolCall.id,
2391
3103
  toolName: this.t.agentToolCall.toolName,
@@ -2396,7 +3108,7 @@ var DrizzleGovernanceQueries = class {
2396
3108
  agentName: this.t.agentMessage.agentName,
2397
3109
  requestedAt: this.t.agentToolCall.createdAt,
2398
3110
  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);
3111
+ }).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
3112
  return {
2401
3113
  rows: rows.map((row) => ({
2402
3114
  toolCallId: row.toolCallId,
@@ -2423,11 +3135,11 @@ var DrizzleGovernanceQueries = class {
2423
3135
  const [row] = await this.db.select({
2424
3136
  run: this.t.agentRun,
2425
3137
  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);
3138
+ }).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
3139
  if (row === void 0) {
2428
3140
  return null;
2429
3141
  }
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));
3142
+ 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
3143
  return {
2432
3144
  run: toRecentRunRow(row.run),
2433
3145
  thread: {
@@ -2446,27 +3158,27 @@ var DrizzleGovernanceQueries = class {
2446
3158
  * message. Soft-deleted threads are returned with `deleted: true`; an audit still needs them.
2447
3159
  */
2448
3160
  async threadDetail(query) {
2449
- const [thread] = await this.db.select().from(this.t.agentThread).where(eq2(this.t.agentThread.id, query.threadId)).limit(1);
3161
+ const [thread] = await this.db.select().from(this.t.agentThread).where(eq3(this.t.agentThread.id, query.threadId)).limit(1);
2450
3162
  if (thread === void 0) {
2451
3163
  return null;
2452
3164
  }
2453
3165
  const pricing = await this.loadPricing();
2454
- const usageRows = await this.db.select().from(this.t.agentTokenUsage).where(eq2(this.t.agentTokenUsage.threadId, thread.id));
3166
+ const usageRows = await this.db.select().from(this.t.agentTokenUsage).where(eq3(this.t.agentTokenUsage.threadId, thread.id));
2455
3167
  const usage = rollupThreadUsage(usageRows.map(toUsageInput), pricing);
2456
3168
  const [messageCountRow] = await this.db.select({
2457
3169
  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(
3170
+ }).from(this.t.agentMessage).where(eq3(this.t.agentMessage.threadId, thread.id));
3171
+ const messages = await this.db.select().from(this.t.agentMessage).where(eq3(this.t.agentMessage.threadId, thread.id)).orderBy(
2460
3172
  // Append order (see DrizzleAgentStore's message order), newest first.
2461
- desc2(sql3`coalesce(${this.t.agentMessage.seq}, 0)`),
3173
+ desc2(sql4`coalesce(${this.t.agentMessage.seq}, 0)`),
2462
3174
  desc2(this.t.agentMessage.createdAt),
2463
3175
  desc2(this.t.agentMessage.id)
2464
3176
  ).limit(query.messageLimit);
2465
3177
  const toolCallCounts = await this.toolCallCountsByMessage(messages.map((message) => message.id));
2466
3178
  const [runTotalRow] = await this.db.select({
2467
3179
  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);
3180
+ }).from(this.t.agentRun).where(eq3(this.t.agentRun.threadId, thread.id));
3181
+ 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
3182
  return {
2471
3183
  thread: {
2472
3184
  threadId: thread.id,
@@ -2513,7 +3225,7 @@ var DrizzleGovernanceQueries = class {
2513
3225
 
2514
3226
  // src/drizzle-memory-provider.ts
2515
3227
  import { actorScope } from "@dudousxd/nestjs-agent-core";
2516
- import { and as and3, eq as eq3, inArray as inArray3 } from "drizzle-orm";
3228
+ import { and as and4, eq as eq4, inArray as inArray3 } from "drizzle-orm";
2517
3229
  function toRecord(row) {
2518
3230
  return {
2519
3231
  id: row.id,
@@ -2577,7 +3289,7 @@ var DrizzleMemoryProvider = class {
2577
3289
  * answer cannot be used to find out which memories exist about other people.
2578
3290
  */
2579
3291
  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);
3292
+ 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
3293
  return deleted > 0;
2582
3294
  }
2583
3295
  /**
@@ -2626,7 +3338,7 @@ var DrizzleMemoryProvider = class {
2626
3338
  memory.scope,
2627
3339
  memory.key
2628
3340
  ], set);
2629
- [row] = await this.db.select().from(memory).where(and3(eq3(memory.scope, scope), eq3(memory.key, key2)));
3341
+ [row] = await this.db.select().from(memory).where(and4(eq4(memory.scope, scope), eq4(memory.key, key2)));
2630
3342
  } else {
2631
3343
  [row] = await insert.onConflictDoUpdate({
2632
3344
  target: [
@@ -2653,7 +3365,7 @@ var DrizzleMemoryProvider = class {
2653
3365
  const updated = await affectedRows(this.dialect, this.db.update(this.t.agentMemory).set({
2654
3366
  pinned,
2655
3367
  updatedAt: /* @__PURE__ */ new Date()
2656
- }).where(eq3(this.t.agentMemory.id, id)), this.t.agentMemory.id);
3368
+ }).where(eq4(this.t.agentMemory.id, id)), this.t.agentMemory.id);
2657
3369
  return updated > 0;
2658
3370
  }
2659
3371
  };
@@ -2666,7 +3378,7 @@ function assertAuthorMayWriteScope({ scope, origin, ctx }) {
2666
3378
  __name(assertAuthorMayWriteScope, "assertAuthorMayWriteScope");
2667
3379
 
2668
3380
  // src/drizzle-pricing-store.ts
2669
- import { and as and4, eq as eq4 } from "drizzle-orm";
3381
+ import { and as and5, eq as eq5 } from "drizzle-orm";
2670
3382
  var DrizzlePricingStore = class {
2671
3383
  static {
2672
3384
  __name(this, "DrizzlePricingStore");
@@ -2682,7 +3394,7 @@ var DrizzlePricingStore = class {
2682
3394
  async upsertModelPrice(input) {
2683
3395
  await this.db.update(this.t.agentModelPricing).set({
2684
3396
  isCurrent: false
2685
- }).where(and4(eq4(this.t.agentModelPricing.modelId, input.modelId), eq4(this.t.agentModelPricing.isCurrent, true)));
3397
+ }).where(and5(eq5(this.t.agentModelPricing.modelId, input.modelId), eq5(this.t.agentModelPricing.isCurrent, true)));
2686
3398
  await this.db.insert(this.t.agentModelPricing).values({
2687
3399
  id: crypto.randomUUID(),
2688
3400
  modelId: input.modelId,
@@ -2695,7 +3407,7 @@ var DrizzlePricingStore = class {
2695
3407
  });
2696
3408
  }
2697
3409
  async listCurrentPrices() {
2698
- const rows = await this.db.select().from(this.t.agentModelPricing).where(eq4(this.t.agentModelPricing.isCurrent, true));
3410
+ const rows = await this.db.select().from(this.t.agentModelPricing).where(eq5(this.t.agentModelPricing.isCurrent, true));
2699
3411
  return rows.map((row) => ({
2700
3412
  modelId: row.modelId,
2701
3413
  inputPricePer1m: row.inputPricePer1m,
@@ -2713,7 +3425,7 @@ var DrizzlePricingStore = class {
2713
3425
 
2714
3426
  // src/drizzle-token-stream-sink.ts
2715
3427
  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";
3428
+ 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
3429
  var DrizzleStreamFrameTable = class {
2718
3430
  static {
2719
3431
  __name(this, "DrizzleStreamFrameTable");
@@ -2727,7 +3439,7 @@ var DrizzleStreamFrameTable = class {
2727
3439
  this.db = asBuilder(db);
2728
3440
  }
2729
3441
  async append(runId, row) {
2730
- await runSql(this.db, this.dialect, sql4`INSERT INTO agent_stream_frame (run_id, seq, frame, error, created_at)
3442
+ await runSql(this.db, this.dialect, sql5`INSERT INTO agent_stream_frame (run_id, seq, frame, error, created_at)
2731
3443
  SELECT ${runId}, COALESCE(MAX(seq), 0) + 1, ${row.frame}, ${row.error}, ${row.createdAt}
2732
3444
  FROM agent_stream_frame WHERE run_id = ${runId}`);
2733
3445
  }
@@ -2736,12 +3448,12 @@ var DrizzleStreamFrameTable = class {
2736
3448
  seq: this.t.agentStreamFrame.seq,
2737
3449
  frame: this.t.agentStreamFrame.frame,
2738
3450
  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);
3451
+ }).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
3452
  }
2741
3453
  async has(runId) {
2742
3454
  const rows = await this.db.select({
2743
3455
  seq: this.t.agentStreamFrame.seq
2744
- }).from(this.t.agentStreamFrame).where(eq5(this.t.agentStreamFrame.runId, runId)).limit(1);
3456
+ }).from(this.t.agentStreamFrame).where(eq6(this.t.agentStreamFrame.runId, runId)).limit(1);
2745
3457
  return rows.length > 0;
2746
3458
  }
2747
3459
  async remove(runIds) {
@@ -2753,7 +3465,7 @@ var DrizzleStreamFrameTable = class {
2753
3465
  async lapsedRuns(cutoff) {
2754
3466
  const rows = await this.db.select({
2755
3467
  runId: this.t.agentStreamFrame.runId
2756
- }).from(this.t.agentStreamFrame).groupBy(this.t.agentStreamFrame.runId).having(lt(max2(this.t.agentStreamFrame.createdAt), cutoff));
3468
+ }).from(this.t.agentStreamFrame).groupBy(this.t.agentStreamFrame.runId).having(lt(max3(this.t.agentStreamFrame.createdAt), cutoff));
2757
3469
  return rows.map((row) => row.runId);
2758
3470
  }
2759
3471
  isUniqueViolation(error) {
@@ -2770,7 +3482,7 @@ var DrizzleTokenStreamSink = class extends SqlTokenStreamSink {
2770
3482
  };
2771
3483
 
2772
3484
  // src/drizzle-confirm-token-store.ts
2773
- import { eq as eq6, lt as lt2 } from "drizzle-orm";
3485
+ import { eq as eq7, lt as lt2 } from "drizzle-orm";
2774
3486
  var DrizzleConfirmTokenStore = class {
2775
3487
  static {
2776
3488
  __name(this, "DrizzleConfirmTokenStore");
@@ -2800,7 +3512,7 @@ var DrizzleConfirmTokenStore = class {
2800
3512
  return inserted === 1;
2801
3513
  }
2802
3514
  async release(hash) {
2803
- await this.db.delete(this.t.agentConfirmToken).where(eq6(this.t.agentConfirmToken.hash, hash));
3515
+ await this.db.delete(this.t.agentConfirmToken).where(eq7(this.t.agentConfirmToken.hash, hash));
2804
3516
  }
2805
3517
  async purgeExpired(now = Date.now()) {
2806
3518
  const table = this.t.agentConfirmToken;
@@ -2811,7 +3523,7 @@ var DrizzleConfirmTokenStore = class {
2811
3523
  // src/drizzle-rag-ingestion-log.ts
2812
3524
  import { subscribe, unsubscribe } from "diagnostics_channel";
2813
3525
  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";
3526
+ 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
3527
  function _ts_decorate(decorators, target, key2, desc4) {
2816
3528
  var c = arguments.length, r = c < 3 ? target : desc4 === null ? desc4 = Object.getOwnPropertyDescriptor(target, key2) : desc4, d;
2817
3529
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -2860,7 +3572,7 @@ function num(value) {
2860
3572
  __name(num, "num");
2861
3573
  var RAG_INGESTION_LOG_PAGE_ORDER = [
2862
3574
  desc3(ragIngestionLog.updatedAt),
2863
- asc4(ragIngestionLog.documentId)
3575
+ asc5(ragIngestionLog.documentId)
2864
3576
  ];
2865
3577
  var DEFAULT_PAGE_SIZE = 200;
2866
3578
  var DEFAULT_BATCH_SIZE = 200;
@@ -3010,17 +3722,17 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
3010
3722
  }
3011
3723
  /** The latest recorded outcome for one document, or null if it was never attempted. */
3012
3724
  async get(documentId) {
3013
- const [row] = await this.db.select().from(this.t.ragIngestionLog).where(eq7(this.t.ragIngestionLog.documentId, documentId));
3725
+ const [row] = await this.db.select().from(this.t.ragIngestionLog).where(eq8(this.t.ragIngestionLog.documentId, documentId));
3014
3726
  return row ?? null;
3015
3727
  }
3016
3728
  /** Forget one document's record. Returns whether a row was actually removed. */
3017
3729
  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);
3730
+ const removed = await affectedRows(this.dialect, this.db.delete(this.t.ragIngestionLog).where(eq8(this.t.ragIngestionLog.documentId, documentId)), this.t.ragIngestionLog.documentId);
3019
3731
  return removed > 0;
3020
3732
  }
3021
3733
  /** Forget every record for a collection — for when the collection itself is deleted. */
3022
3734
  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);
3735
+ const removed = await affectedRows(this.dialect, this.db.delete(this.t.ragIngestionLog).where(eq8(this.t.ragIngestionLog.collection, collection)), this.t.ragIngestionLog.documentId);
3024
3736
  return removed;
3025
3737
  }
3026
3738
  /**
@@ -3050,7 +3762,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
3050
3762
  }
3051
3763
  }
3052
3764
  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);
3765
+ 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
3766
  }
3055
3767
  /**
3056
3768
  * The coordinates filter AND'd with "strictly after `cursor` in
@@ -3065,7 +3777,7 @@ var DrizzleRagIngestionLog = class _DrizzleRagIngestionLog {
3065
3777
  if (cursor === void 0) {
3066
3778
  return base;
3067
3779
  }
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))));
3780
+ 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
3781
  }
3070
3782
  /**
3071
3783
  * Upsert one outcome. Keyed by document id so the row always reflects the *current* state — a
@@ -3240,6 +3952,7 @@ DrizzleAgentStoreModule = _ts_decorate2([
3240
3952
  Module({})
3241
3953
  ], DrizzleAgentStoreModule);
3242
3954
  export {
3955
+ DrizzleActionProposalStore,
3243
3956
  DrizzleAgentStore,
3244
3957
  DrizzleAgentStoreModule,
3245
3958
  DrizzleConfirmTokenStore,
@@ -3250,6 +3963,7 @@ export {
3250
3963
  DrizzleStreamFrameTable,
3251
3964
  DrizzleTokenStreamSink,
3252
3965
  RAG_INGESTION_LOG_PAGE_ORDER,
3966
+ agentActionProposal,
3253
3967
  agentConfirmToken,
3254
3968
  agentDialectOf,
3255
3969
  agentMemory,