@opengeni/db 0.23.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/{chunk-3UCHDMKG.js → chunk-7WTDI7Y3.js} +109 -2
  2. package/dist/chunk-7WTDI7Y3.js.map +1 -0
  3. package/dist/{chunk-L6ADMZHE.js → chunk-KW6U54V2.js} +3 -1
  4. package/dist/chunk-KW6U54V2.js.map +1 -0
  5. package/dist/connection-token-resolver.d.ts +24 -2
  6. package/dist/index.d.ts +68 -2
  7. package/dist/index.js +1168 -336
  8. package/dist/index.js.map +1 -1
  9. package/dist/preference-registry.d.ts +14 -0
  10. package/dist/provision-roles.js +1 -1
  11. package/dist/runtime-posture.d.ts +2 -2
  12. package/dist/schema.d.ts +262 -4
  13. package/dist/schema.js +3 -1
  14. package/dist/session-realtime-mirror.d.ts +22 -1
  15. package/dist/workspace-instruction-policies-schema.d.ts +68 -0
  16. package/dist/workspace-instruction-policies.d.ts +53 -7
  17. package/drizzle/0165_document_authority_foundation.sql +259 -0
  18. package/drizzle/0166_connection_disconnect_idempotency.sql +49 -0
  19. package/drizzle/0167_document_index_replay_authority.sql +61 -0
  20. package/drizzle/0168_workspace_instruction_policy_operation_receipts.sql +44 -0
  21. package/package.json +3 -3
  22. package/src/connection-token-resolver.ts +79 -16
  23. package/src/index.ts +419 -23
  24. package/src/preference-registry.ts +103 -0
  25. package/src/runtime-posture.ts +2 -0
  26. package/src/schema.ts +86 -0
  27. package/src/session-control.ts +48 -1
  28. package/src/session-queue-commands.ts +45 -11
  29. package/src/session-realtime-mirror.ts +117 -1
  30. package/src/session-realtime.ts +49 -1
  31. package/src/workspace-instruction-policies-schema.ts +30 -0
  32. package/src/workspace-instruction-policies.ts +438 -24
  33. package/dist/chunk-3UCHDMKG.js.map +0 -1
  34. package/dist/chunk-L6ADMZHE.js.map +0 -1
package/dist/index.js CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  codexRotationSettings,
12
12
  codexSubscriptionCredentials,
13
13
  composerDrafts,
14
+ connectionDisconnectOperations,
14
15
  connections,
15
16
  connectorActionPolicies,
16
17
  connectorActionRequests,
@@ -104,6 +105,7 @@ import {
104
105
  workspaceInstructionPolicyActivationEvents,
105
106
  workspaceInstructionPolicyHeads,
106
107
  workspaceInstructionPolicyRevisions,
108
+ workspaceInstructionPolicySnapshots,
107
109
  workspaceMemberships,
108
110
  workspaceModelPolicies,
109
111
  workspacePacks,
@@ -111,7 +113,7 @@ import {
111
113
  workspaceVariableSetVariables,
112
114
  workspaceVariableSets,
113
115
  workspaces
114
- } from "./chunk-3UCHDMKG.js";
116
+ } from "./chunk-7WTDI7Y3.js";
115
117
  import {
116
118
  migrate,
117
119
  runMigrations
@@ -131,7 +133,7 @@ import {
131
133
  inspectRuntimeDatabasePosture,
132
134
  provisionRoles,
133
135
  runtimeDatabaseReadyCheck
134
- } from "./chunk-L6ADMZHE.js";
136
+ } from "./chunk-KW6U54V2.js";
135
137
  import "./chunk-PZ5AY32C.js";
136
138
 
137
139
  // src/index.ts
@@ -144,7 +146,8 @@ import {
144
146
  canonicalModalCheckpointProviderBinding,
145
147
  decodeNativeSnapshotRef,
146
148
  parseWorkspaceArchiveDescriptor,
147
- stableJson as stableJson3
149
+ stableJson as stableJson3,
150
+ MODEL_ATTACHMENT_REFS_FIELD
148
151
  } from "@opengeni/contracts";
149
152
  import {
150
153
  approvalIdentifier,
@@ -191,17 +194,17 @@ import {
191
194
  desc as desc8,
192
195
  eq as eq17,
193
196
  getTableColumns,
194
- gt as gt4,
197
+ gt as gt5,
195
198
  gte as gte2,
196
199
  inArray as inArray11,
197
200
  isNotNull,
198
201
  ilike,
199
- isNull as isNull5,
202
+ isNull as isNull6,
200
203
  lt as lt4,
201
204
  lte as lte2,
202
205
  ne,
203
206
  notInArray,
204
- or as or4,
207
+ or as or6,
205
208
  sql as sql14
206
209
  } from "drizzle-orm";
207
210
 
@@ -1162,13 +1165,199 @@ async function closePendingSessionToolCallsInTransaction(tx, input) {
1162
1165
  }
1163
1166
 
1164
1167
  // src/session-control.ts
1165
- import { createHash } from "crypto";
1168
+ import { createHash as createHash2 } from "crypto";
1166
1169
  import {
1167
1170
  boundWorkspaceControlEvent,
1168
1171
  McpPersonalConnectionDelegations,
1169
1172
  workspaceControlUtf8Bytes
1170
1173
  } from "@opengeni/contracts";
1171
- import { and as and4, eq as eq4, inArray, sql as sql2 } from "drizzle-orm";
1174
+ import { and as and5, eq as eq5, inArray, sql as sql3 } from "drizzle-orm";
1175
+
1176
+ // src/session-realtime-mirror.ts
1177
+ import { createHash } from "crypto";
1178
+ import { and as and4, desc, eq as eq4, gt, sql as sql2 } from "drizzle-orm";
1179
+ var SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES = 131072;
1180
+ var SESSION_REALTIME_MIRROR_MAX_PAYLOAD_BYTES = 131072;
1181
+ var TRUNCATION_MARKER = "\n\u2026realtime context truncated\u2026";
1182
+ function deterministicUuid(seed) {
1183
+ const bytes = createHash("sha256").update(seed, "utf8").digest().subarray(0, 16);
1184
+ bytes[6] = (bytes[6] ?? 0) & 15 | 80;
1185
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
1186
+ const hex = bytes.toString("hex");
1187
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
1188
+ }
1189
+ function takeUtf8Head(value, maximumBytes) {
1190
+ const bytes = Buffer.from(value, "utf8");
1191
+ if (bytes.length <= maximumBytes) return value;
1192
+ let end = maximumBytes;
1193
+ while (end > 0 && (bytes[end] & 192) === 128) end -= 1;
1194
+ return bytes.subarray(0, end).toString("utf8");
1195
+ }
1196
+ function boundedText(value) {
1197
+ if (Buffer.byteLength(value, "utf8") <= SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES) return value;
1198
+ const markerBytes = Buffer.byteLength(TRUNCATION_MARKER, "utf8");
1199
+ return `${takeUtf8Head(value, SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES - markerBytes)}${TRUNCATION_MARKER}`;
1200
+ }
1201
+ function boundedPayload(value) {
1202
+ const payload = sanitizeEventPayload(value);
1203
+ if (Buffer.byteLength(JSON.stringify(payload), "utf8") > SESSION_REALTIME_MIRROR_MAX_PAYLOAD_BYTES) {
1204
+ throw new Error("Realtime mirror payload exceeds the durable ledger limit");
1205
+ }
1206
+ return payload;
1207
+ }
1208
+ async function mirrorSessionRealtimeContextInTransaction(db, input) {
1209
+ const now = input.now ?? /* @__PURE__ */ new Date();
1210
+ const modes = await db.select().from(sessionRealtimeModes).where(
1211
+ and4(
1212
+ eq4(sessionRealtimeModes.accountId, input.accountId),
1213
+ eq4(sessionRealtimeModes.workspaceId, input.workspaceId),
1214
+ eq4(sessionRealtimeModes.sessionId, input.sessionId),
1215
+ eq4(sessionRealtimeModes.state, "active"),
1216
+ gt(sessionRealtimeModes.leaseExpiresAt, now)
1217
+ )
1218
+ ).orderBy(desc(sessionRealtimeModes.startedAt)).for("update").limit(2);
1219
+ if (modes.length === 0) return null;
1220
+ if (modes.length !== 1) {
1221
+ throw new Error(`Session ${input.sessionId} has multiple active realtime modes`);
1222
+ }
1223
+ const mode = modes[0];
1224
+ const operationId = deterministicUuid(
1225
+ `opengeni:session-realtime-mirror:${mode.id}:${input.sourceKind}:${input.sourceId}`
1226
+ );
1227
+ const [existing] = await db.select().from(sessionRealtimeEntries).where(
1228
+ and4(
1229
+ eq4(sessionRealtimeEntries.realtimeId, mode.id),
1230
+ eq4(sessionRealtimeEntries.operationId, operationId)
1231
+ )
1232
+ ).limit(1);
1233
+ if (existing) return { entry: existing, replay: true };
1234
+ const [sequenceRow] = await db.select({ next: sql2`coalesce(max(${sessionRealtimeEntries.sequence}), 0) + 1` }).from(sessionRealtimeEntries).where(eq4(sessionRealtimeEntries.realtimeId, mode.id));
1235
+ const payload = boundedPayload({
1236
+ ...input.payload ?? {},
1237
+ source: input.sourceKind,
1238
+ sourceId: input.sourceId,
1239
+ channel: input.channel,
1240
+ ...input.turnId ? { sourceTurnId: input.turnId } : {}
1241
+ });
1242
+ const [entry] = await db.insert(sessionRealtimeEntries).values({
1243
+ accountId: input.accountId,
1244
+ workspaceId: input.workspaceId,
1245
+ sessionId: input.sessionId,
1246
+ realtimeId: mode.id,
1247
+ operationId,
1248
+ connectionEpoch: mode.connectionEpoch,
1249
+ sequence: Number(sequenceRow?.next ?? 1),
1250
+ direction: "provider_out",
1251
+ kind: "session_update",
1252
+ text: boundedText(input.text),
1253
+ payload,
1254
+ createdAt: now,
1255
+ updatedAt: now
1256
+ }).returning();
1257
+ if (!entry) throw new Error("Failed to append realtime session context");
1258
+ return { entry, replay: false };
1259
+ }
1260
+ function renderRealtimeHumanInputContext(input) {
1261
+ return [
1262
+ "<session_user_message>",
1263
+ ` <status>${input.routing}</status>`,
1264
+ ` <delivery>${input.delivery}</delivery>`,
1265
+ ` <text>${escapeXmlText(input.text)}</text>`,
1266
+ " <instruction>Already routed by OpenGeni; do not delegate this message again.</instruction>",
1267
+ "</session_user_message>"
1268
+ ].join("\n");
1269
+ }
1270
+ function renderRealtimeHumanInputRequestContext(input) {
1271
+ const lines = ["<session_human_input_request>", " <status>waiting_for_user</status>"];
1272
+ for (const request of input.requests) {
1273
+ lines.push(
1274
+ " <request>",
1275
+ ` <id>${escapeXmlText(request.id)}</id>`,
1276
+ ` <allow_skip>${String(request.allowSkip)}</allow_skip>`,
1277
+ ` <expires_at>${escapeXmlText(renderExpiry(request.expiresAt))}</expires_at>`
1278
+ );
1279
+ for (const question of request.questions) {
1280
+ lines.push(
1281
+ " <question>",
1282
+ ` <id>${escapeXmlText(question.id)}</id>`,
1283
+ ` <kind>${escapeXmlText(question.kind)}</kind>`,
1284
+ ` <required>${String(question.required)}</required>`
1285
+ );
1286
+ if (question.label) lines.push(` <label>${escapeXmlText(question.label)}</label>`);
1287
+ lines.push(` <prompt>${escapeXmlText(question.prompt)}</prompt>`);
1288
+ if (question.helpText) {
1289
+ lines.push(` <help_text>${escapeXmlText(question.helpText)}</help_text>`);
1290
+ }
1291
+ if (question.options.length > 0) {
1292
+ lines.push(" <options>");
1293
+ for (const option of question.options) {
1294
+ lines.push(
1295
+ " <option>",
1296
+ ` <id>${escapeXmlText(option.id)}</id>`,
1297
+ ` <label>${escapeXmlText(option.label)}</label>`
1298
+ );
1299
+ if (option.description) {
1300
+ lines.push(` <description>${escapeXmlText(option.description)}</description>`);
1301
+ }
1302
+ lines.push(" </option>");
1303
+ }
1304
+ lines.push(" </options>");
1305
+ }
1306
+ lines.push(
1307
+ ` <allow_other>${String(question.allowOther)}</allow_other>`,
1308
+ " </question>"
1309
+ );
1310
+ }
1311
+ lines.push(" </request>");
1312
+ }
1313
+ lines.push(
1314
+ " <instruction>The current work is waiting for the user's input. Ask the questions naturally, one at a time when useful, without changing their meaning or answering for the user. The user may answer in the visible form or answer conversationally here. If the user answers here, delegate exactly once with a complete message containing the relevant question and the user's answer. If the user changes direction instead, delegate that new direction normally. Do not claim the work resumed until a later session update confirms it.</instruction>",
1315
+ "</session_human_input_request>"
1316
+ );
1317
+ return lines.join("\n");
1318
+ }
1319
+ function renderRealtimeHumanInputResponseContext(input) {
1320
+ const lines = [
1321
+ "<session_human_input_response>",
1322
+ ` <request_id>${escapeXmlText(input.requestId)}</request_id>`,
1323
+ ` <outcome>${escapeXmlText(input.response.outcome)}</outcome>`
1324
+ ];
1325
+ if (input.response.outcome === "answered") {
1326
+ const questions = new Map(input.questions.map((question) => [question.id, question]));
1327
+ lines.push(" <answers>");
1328
+ for (const answer of input.response.answers) {
1329
+ const question = questions.get(answer.questionId);
1330
+ const optionLabels = new Map(
1331
+ question?.options.map((option) => [option.id, option.label]) ?? []
1332
+ );
1333
+ lines.push(
1334
+ " <answer>",
1335
+ ` <question_id>${escapeXmlText(answer.questionId)}</question_id>`
1336
+ );
1337
+ if (question) lines.push(` <question>${escapeXmlText(question.prompt)}</question>`);
1338
+ for (const value of answer.values) {
1339
+ lines.push(` <value>${escapeXmlText(optionLabels.get(value) ?? value)}</value>`);
1340
+ }
1341
+ if (answer.other) lines.push(` <other>${escapeXmlText(answer.other)}</other>`);
1342
+ lines.push(" </answer>");
1343
+ }
1344
+ lines.push(" </answers>");
1345
+ }
1346
+ lines.push(
1347
+ input.response.outcome === "answered" || input.response.outcome === "skipped" ? " <instruction>This structured response was accepted through the session UI and the same work can resume. Treat it as authoritative user context, do not delegate it again, and acknowledge briefly only if useful.</instruction>" : " <instruction>This pending question is no longer active. Do not ask it again unless the user raises it.</instruction>",
1348
+ "</session_human_input_response>"
1349
+ );
1350
+ return lines.join("\n");
1351
+ }
1352
+ function renderExpiry(value) {
1353
+ if (value === null || value === void 0) return "none";
1354
+ return value instanceof Date ? value.toISOString() : value;
1355
+ }
1356
+ function escapeXmlText(value) {
1357
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
1358
+ }
1359
+
1360
+ // src/session-control.ts
1172
1361
  var SESSION_ANCESTRY_LIMIT = 1e4;
1173
1362
  var NO_SETTLEMENT_ATTEMPTS = {
1174
1363
  attemptCount: 0,
@@ -1239,7 +1428,7 @@ async function assertAgentCommandAuthorityInTransaction(db, input) {
1239
1428
  if (!lockedSessions.some((row) => row.id === input.targetSessionId)) {
1240
1429
  throw new SessionControlInvariantError(`Target session not found: ${input.targetSessionId}`);
1241
1430
  }
1242
- const rows = await db.execute(sql2`
1431
+ const rows = await db.execute(sql3`
1243
1432
  select
1244
1433
  attempt.id as "attemptId",
1245
1434
  attempt.state as "attemptState",
@@ -1281,7 +1470,7 @@ async function assertAgentCommandAuthorityInTransaction(db, input) {
1281
1470
  throw new AgentCommandAuthorityError("SELF_STEER", "An agent cannot steer its own session");
1282
1471
  }
1283
1472
  if (input.action !== "pause") return;
1284
- const ancestry = await db.execute(sql2`
1473
+ const ancestry = await db.execute(sql3`
1285
1474
  with recursive caller_ancestry(id, parent_id, depth, path, cycle) as (
1286
1475
  select session.id, session.parent_session_id, 0, array[session.id], false
1287
1476
  from ${sessions} session
@@ -1333,17 +1522,17 @@ function canonicalize(value) {
1333
1522
  return value;
1334
1523
  }
1335
1524
  function canonicalSessionCommandHash(value) {
1336
- return createHash("sha256").update(JSON.stringify(canonicalize(value))).digest("hex");
1525
+ return createHash2("sha256").update(JSON.stringify(canonicalize(value))).digest("hex");
1337
1526
  }
1338
1527
  function controlEtag(value) {
1339
1528
  return `sc1:${canonicalSessionCommandHash(value)}`;
1340
1529
  }
1341
1530
  function lockClause(mode) {
1342
- if (mode === "none") return sql2.empty();
1343
- return mode === "update" ? sql2.raw("for update") : sql2.raw("for share");
1531
+ if (mode === "none") return sql3.empty();
1532
+ return mode === "update" ? sql3.raw("for update") : sql3.raw("for share");
1344
1533
  }
1345
1534
  async function lockWorkspaceInferenceControl(db, workspaceId, mode) {
1346
- const rows = await db.execute(sql2`
1535
+ const rows = await db.execute(sql3`
1347
1536
  select
1348
1537
  workspace_id as "workspaceId",
1349
1538
  account_id as "accountId",
@@ -1370,27 +1559,27 @@ async function lockSessionEventWriteRows(db, input) {
1370
1559
  const control = controlLock === "share" || controlLock === "update" ? await lockWorkspaceInferenceControl(db, input.workspaceId, controlLock) : null;
1371
1560
  let workspace = null;
1372
1561
  if ((input.workspaceLock ?? "key_share") === "key_share") {
1373
- const [lockedWorkspace] = await db.select().from(workspaces).where(eq4(workspaces.id, input.workspaceId)).for("key share").limit(1);
1562
+ const [lockedWorkspace] = await db.select().from(workspaces).where(eq5(workspaces.id, input.workspaceId)).for("key share").limit(1);
1374
1563
  workspace = lockedWorkspace ?? null;
1375
1564
  }
1376
1565
  const sessionIds = [...new Set(input.sessionIds ?? [])].sort();
1377
1566
  const sessions2 = sessionIds.length > 0 ? await db.select().from(sessions).where(
1378
- and4(
1379
- eq4(sessions.workspaceId, input.workspaceId),
1567
+ and5(
1568
+ eq5(sessions.workspaceId, input.workspaceId),
1380
1569
  inArray(sessions.id, sessionIds)
1381
1570
  )
1382
1571
  ).orderBy(sessions.id).for("update") : [];
1383
1572
  const turnIds = [...new Set(input.turnIds ?? [])].sort();
1384
1573
  const turns = turnIds.length > 0 ? await db.select().from(sessionTurns).where(
1385
- and4(
1386
- eq4(sessionTurns.workspaceId, input.workspaceId),
1574
+ and5(
1575
+ eq5(sessionTurns.workspaceId, input.workspaceId),
1387
1576
  inArray(sessionTurns.id, turnIds)
1388
1577
  )
1389
1578
  ).orderBy(sessionTurns.id).for("update") : [];
1390
1579
  const attemptIds = [...new Set(input.attemptIds ?? [])].sort();
1391
1580
  const attempts = attemptIds.length > 0 ? await db.select().from(sessionTurnAttempts).where(
1392
- and4(
1393
- eq4(sessionTurnAttempts.workspaceId, input.workspaceId),
1581
+ and5(
1582
+ eq5(sessionTurnAttempts.workspaceId, input.workspaceId),
1394
1583
  inArray(sessionTurnAttempts.id, attemptIds)
1395
1584
  )
1396
1585
  ).orderBy(sessionTurnAttempts.id).for("update") : [];
@@ -1403,9 +1592,9 @@ async function registerSessionTurnAttemptClaim(db, input) {
1403
1592
  }).onConflictDoNothing({ target: sessionTurnAttempts.id }).returning();
1404
1593
  if (inserted) return inserted;
1405
1594
  const [existing] = await db.select().from(sessionTurnAttempts).where(
1406
- and4(
1407
- eq4(sessionTurnAttempts.workspaceId, input.workspaceId),
1408
- eq4(sessionTurnAttempts.id, input.id)
1595
+ and5(
1596
+ eq5(sessionTurnAttempts.workspaceId, input.workspaceId),
1597
+ eq5(sessionTurnAttempts.id, input.id)
1409
1598
  )
1410
1599
  ).for("update").limit(1);
1411
1600
  if (!existing || existing.accountId !== input.accountId || existing.sessionId !== input.sessionId || existing.turnId !== input.turnId || existing.executionGeneration !== input.executionGeneration || existing.temporalWorkflowId !== input.temporalWorkflowId || existing.temporalWorkflowRunId !== input.temporalWorkflowRunId || existing.temporalActivityId !== input.temporalActivityId || JSON.stringify(existing.connectorActionPolicies) !== JSON.stringify(input.connectorActionPolicies) || existing.state === "closed") {
@@ -1417,9 +1606,9 @@ async function registerSessionTurnAttemptClaim(db, input) {
1417
1606
  }
1418
1607
  async function closeSessionTurnAttemptInTransaction(db, input) {
1419
1608
  const [attempt] = await db.select().from(sessionTurnAttempts).where(
1420
- and4(
1421
- eq4(sessionTurnAttempts.workspaceId, input.workspaceId),
1422
- eq4(sessionTurnAttempts.id, input.id)
1609
+ and5(
1610
+ eq5(sessionTurnAttempts.workspaceId, input.workspaceId),
1611
+ eq5(sessionTurnAttempts.id, input.id)
1423
1612
  )
1424
1613
  ).for("update").limit(1);
1425
1614
  if (!attempt || attempt.accountId !== input.accountId || attempt.sessionId !== input.sessionId || attempt.turnId !== input.turnId || attempt.executionGeneration !== input.executionGeneration) {
@@ -1450,10 +1639,10 @@ async function closeSessionTurnAttemptInTransaction(db, input) {
1450
1639
  closedAt: now,
1451
1640
  updatedAt: now
1452
1641
  }).where(
1453
- and4(
1454
- eq4(sessionTurnAttempts.workspaceId, input.workspaceId),
1455
- eq4(sessionTurnAttempts.id, input.id),
1456
- sql2`${sessionTurnAttempts.state} in ('claimed', 'running')`
1642
+ and5(
1643
+ eq5(sessionTurnAttempts.workspaceId, input.workspaceId),
1644
+ eq5(sessionTurnAttempts.id, input.id),
1645
+ sql3`${sessionTurnAttempts.state} in ('claimed', 'running')`
1457
1646
  )
1458
1647
  ).returning({ id: sessionTurnAttempts.id });
1459
1648
  if (!closed) {
@@ -1465,14 +1654,14 @@ function targetValues(sessionIds) {
1465
1654
  if (sessionIds.length === 0) {
1466
1655
  throw new SessionControlInvariantError("At least one target session is required");
1467
1656
  }
1468
- return sql2.join(
1469
- sessionIds.map((id) => sql2`(${id}::uuid)`),
1470
- sql2`, `
1657
+ return sql3.join(
1658
+ sessionIds.map((id) => sql3`(${id}::uuid)`),
1659
+ sql3`, `
1471
1660
  );
1472
1661
  }
1473
1662
  var TARGET_PATH_PROJECTION_LIMIT = 128;
1474
1663
  async function loadTargetAncestryRows(db, workspaceId, sessionIds) {
1475
- return await db.execute(sql2`
1664
+ return await db.execute(sql3`
1476
1665
  with recursive targets(id) as (values ${targetValues(sessionIds)}),
1477
1666
  ancestry as (
1478
1667
  select
@@ -1535,7 +1724,7 @@ async function loadTargetAncestryRows(db, workspaceId, sessionIds) {
1535
1724
  `);
1536
1725
  }
1537
1726
  async function loadAncestryNodes(db, workspaceId, sessionIds) {
1538
- const rows = await db.execute(sql2`
1727
+ const rows = await db.execute(sql3`
1539
1728
  with recursive targets(id) as (values ${targetValues(sessionIds)}),
1540
1729
  ancestry_ids(id) as (
1541
1730
  select session.id
@@ -1728,7 +1917,7 @@ function projectEffectiveControl(workspace, targetId, rows, settlementAttempts)
1728
1917
  };
1729
1918
  }
1730
1919
  async function settlementAttemptCounts(db, workspaceId, sessionIds) {
1731
- const rows = await db.execute(sql2`
1920
+ const rows = await db.execute(sql3`
1732
1921
  with recursive targets(id) as (values ${targetValues(sessionIds)}),
1733
1922
  interruptions as (
1734
1923
  select
@@ -1875,7 +2064,7 @@ async function evaluateSessionDiscoveryControls(db, workspaceId, sessionIds) {
1875
2064
  if (workspace.workspaceState === "paused" && workspacePauseRevision === null) {
1876
2065
  throw new SessionControlInvariantError("Paused workspace is missing its pause revision");
1877
2066
  }
1878
- const rows = await db.execute(sql2`
2067
+ const rows = await db.execute(sql3`
1879
2068
  with recursive targets(id) as (values ${targetValues(uniqueIds)}),
1880
2069
  ancestry as (
1881
2070
  select
@@ -2042,22 +2231,22 @@ async function evaluateSessionControl(db, workspaceId, sessionId, options = {})
2042
2231
  async function findCommandReceipt(db, input) {
2043
2232
  const actorSubjectId = input.actor.type === "agent_attempt" ? null : input.actor.subjectId;
2044
2233
  const actorAttemptId = input.actor.type === "agent_attempt" ? input.actor.attemptId : null;
2045
- const identity = input.identityScope === "goal_operation" ? and4(
2046
- eq4(sessionCommandReceipts.workspaceId, input.workspaceId),
2047
- eq4(sessionCommandReceipts.actorType, "agent_attempt"),
2048
- eq4(sessionCommandReceipts.action, input.action),
2049
- eq4(sessionCommandReceipts.targetSessionId, input.targetSessionId),
2050
- sql2`${sessionCommandReceipts.targetTurnId} is null`,
2051
- eq4(sessionCommandReceipts.operationKey, input.operationKey)
2052
- ) : and4(
2053
- eq4(sessionCommandReceipts.workspaceId, input.workspaceId),
2054
- eq4(sessionCommandReceipts.actorType, input.actor.type),
2055
- sql2`${sessionCommandReceipts.actorSubjectId} is not distinct from ${actorSubjectId}`,
2056
- sql2`${sessionCommandReceipts.actorAttemptId} is not distinct from ${actorAttemptId}::uuid`,
2057
- eq4(sessionCommandReceipts.action, input.action),
2058
- sql2`${sessionCommandReceipts.targetSessionId} is not distinct from ${input.targetSessionId}::uuid`,
2059
- sql2`${sessionCommandReceipts.targetTurnId} is not distinct from ${input.targetTurnId}::uuid`,
2060
- eq4(sessionCommandReceipts.operationKey, input.operationKey)
2234
+ const identity = input.identityScope === "goal_operation" ? and5(
2235
+ eq5(sessionCommandReceipts.workspaceId, input.workspaceId),
2236
+ eq5(sessionCommandReceipts.actorType, "agent_attempt"),
2237
+ eq5(sessionCommandReceipts.action, input.action),
2238
+ eq5(sessionCommandReceipts.targetSessionId, input.targetSessionId),
2239
+ sql3`${sessionCommandReceipts.targetTurnId} is null`,
2240
+ eq5(sessionCommandReceipts.operationKey, input.operationKey)
2241
+ ) : and5(
2242
+ eq5(sessionCommandReceipts.workspaceId, input.workspaceId),
2243
+ eq5(sessionCommandReceipts.actorType, input.actor.type),
2244
+ sql3`${sessionCommandReceipts.actorSubjectId} is not distinct from ${actorSubjectId}`,
2245
+ sql3`${sessionCommandReceipts.actorAttemptId} is not distinct from ${actorAttemptId}::uuid`,
2246
+ eq5(sessionCommandReceipts.action, input.action),
2247
+ sql3`${sessionCommandReceipts.targetSessionId} is not distinct from ${input.targetSessionId}::uuid`,
2248
+ sql3`${sessionCommandReceipts.targetTurnId} is not distinct from ${input.targetTurnId}::uuid`,
2249
+ eq5(sessionCommandReceipts.operationKey, input.operationKey)
2061
2250
  );
2062
2251
  const rows = await db.select().from(sessionCommandReceipts).where(identity).for("update");
2063
2252
  return rows[0] ?? null;
@@ -2108,9 +2297,9 @@ function nextRevision(workspace) {
2108
2297
  }
2109
2298
  async function advanceWorkspaceRevision(db, workspaceId, revision) {
2110
2299
  const rows = await db.update(workspaceInferenceControls).set({ revision, updatedAt: /* @__PURE__ */ new Date() }).where(
2111
- and4(
2112
- eq4(workspaceInferenceControls.workspaceId, workspaceId),
2113
- eq4(workspaceInferenceControls.revision, revision - 1)
2300
+ and5(
2301
+ eq5(workspaceInferenceControls.workspaceId, workspaceId),
2302
+ eq5(workspaceInferenceControls.revision, revision - 1)
2114
2303
  )
2115
2304
  ).returning({ workspaceId: workspaceInferenceControls.workspaceId });
2116
2305
  if (rows.length !== 1) {
@@ -2120,7 +2309,7 @@ async function advanceWorkspaceRevision(db, workspaceId, revision) {
2120
2309
  }
2121
2310
  }
2122
2311
  async function registerContinuableWakes(db, input) {
2123
- const rows = await db.execute(sql2`
2312
+ const rows = await db.execute(sql3`
2124
2313
  with eligible as (
2125
2314
  select *
2126
2315
  from opengeni_private.list_continuable_sessions(
@@ -2162,7 +2351,7 @@ async function registerWorkspaceWakes(db, input) {
2162
2351
  });
2163
2352
  }
2164
2353
  async function registerInterruptionWakes(db, input) {
2165
- const rows = await db.execute(sql2`
2354
+ const rows = await db.execute(sql3`
2166
2355
  with eligible as (
2167
2356
  select distinct
2168
2357
  session.id as session_id,
@@ -2198,11 +2387,11 @@ async function registerInterruptionWakes(db, input) {
2198
2387
  }
2199
2388
  async function registerCancellationWakes(db, input) {
2200
2389
  if (input.sessionIds.length === 0) return 0;
2201
- const sessionIds = sql2.join(
2202
- input.sessionIds.map((id) => sql2`${id}::uuid`),
2203
- sql2`, `
2390
+ const sessionIds = sql3.join(
2391
+ input.sessionIds.map((id) => sql3`${id}::uuid`),
2392
+ sql3`, `
2204
2393
  );
2205
- const rows = await db.execute(sql2`
2394
+ const rows = await db.execute(sql3`
2206
2395
  with eligible as (
2207
2396
  select
2208
2397
  session.id as session_id,
@@ -2244,7 +2433,7 @@ async function registerSessionWorkflowWakeInTransaction(db, input) {
2244
2433
  target: sessionWorkflowWakeOutbox.sessionId,
2245
2434
  set: {
2246
2435
  temporalWorkflowId: input.temporalWorkflowId,
2247
- wakeRevision: sql2`${sessionWorkflowWakeOutbox.wakeRevision} + 1`,
2436
+ wakeRevision: sql3`${sessionWorkflowWakeOutbox.wakeRevision} + 1`,
2248
2437
  reason: input.reason,
2249
2438
  attempts: 0,
2250
2439
  nextAttemptAt: /* @__PURE__ */ new Date(),
@@ -2259,9 +2448,9 @@ async function registerSessionWorkflowWakeInTransaction(db, input) {
2259
2448
  }
2260
2449
  async function registerInternalUpdateWakeInTransaction(db, input) {
2261
2450
  const [existing] = await db.select().from(sessionWorkflowWakeOutbox).where(
2262
- and4(
2263
- eq4(sessionWorkflowWakeOutbox.workspaceId, input.workspaceId),
2264
- eq4(sessionWorkflowWakeOutbox.sessionId, input.sessionId)
2451
+ and5(
2452
+ eq5(sessionWorkflowWakeOutbox.workspaceId, input.workspaceId),
2453
+ eq5(sessionWorkflowWakeOutbox.sessionId, input.sessionId)
2265
2454
  )
2266
2455
  ).for("update").limit(1);
2267
2456
  if (existing && existing.wakeRevision > existing.deliveredRevision) {
@@ -2271,7 +2460,7 @@ async function registerInternalUpdateWakeInTransaction(db, input) {
2271
2460
  nextAttemptAt: /* @__PURE__ */ new Date(),
2272
2461
  lastError: null,
2273
2462
  updatedAt: /* @__PURE__ */ new Date()
2274
- }).where(eq4(sessionWorkflowWakeOutbox.sessionId, input.sessionId));
2463
+ }).where(eq5(sessionWorkflowWakeOutbox.sessionId, input.sessionId));
2275
2464
  return { wakeRevision: existing.wakeRevision, shouldSignal: false };
2276
2465
  }
2277
2466
  return {
@@ -2283,7 +2472,7 @@ async function registerInternalUpdateWakeInTransaction(db, input) {
2283
2472
  };
2284
2473
  }
2285
2474
  async function interruptDescendantAttempts(db, input) {
2286
- const rows = await db.execute(sql2`
2475
+ const rows = await db.execute(sql3`
2287
2476
  with recursive live_attempts as (
2288
2477
  select attempt.id, attempt.account_id, attempt.workspace_id, attempt.session_id
2289
2478
  from ${sessionTurnAttempts} attempt
@@ -2331,7 +2520,7 @@ async function interruptDescendantAttempts(db, input) {
2331
2520
  return Number(rows[0]?.count ?? 0);
2332
2521
  }
2333
2522
  async function interruptWorkspaceAttempts(db, input) {
2334
- const rows = await db.execute(sql2`
2523
+ const rows = await db.execute(sql3`
2335
2524
  with inserted as (
2336
2525
  insert into ${sessionAttemptInterruptions} (
2337
2526
  account_id, workspace_id, session_id, operation_id, attempt_id,
@@ -2358,12 +2547,12 @@ async function updateSessionCommandReceiptResult(db, receiptId, input) {
2358
2547
  ...input.draftRevision !== void 0 ? { appliedDraftRevision: input.draftRevision } : {},
2359
2548
  result: input.result,
2360
2549
  updatedAt: /* @__PURE__ */ new Date()
2361
- }).where(eq4(sessionCommandReceipts.id, receiptId)).returning();
2550
+ }).where(eq5(sessionCommandReceipts.id, receiptId)).returning();
2362
2551
  if (!receipt) throw new SessionControlInvariantError("Command receipt disappeared");
2363
2552
  return receipt;
2364
2553
  }
2365
2554
  async function loadSessionSubtreeIds(db, workspaceId, rootSessionId) {
2366
- const rows = await db.execute(sql2`
2555
+ const rows = await db.execute(sql3`
2367
2556
  with recursive subtree(id, root_parent_session_id, depth, path, cycle) as (
2368
2557
  select session.id, session.parent_session_id, 0::integer, array[session.id]::uuid[], false
2369
2558
  from ${sessions} session
@@ -2400,8 +2589,8 @@ var TERMINAL_CANCELLATION_LIVE_TURN_STATUSES = [
2400
2589
  ];
2401
2590
  async function loadCancellationTurnIds(db, workspaceId, sessionIds) {
2402
2591
  const rows = await db.select({ id: sessionTurns.id }).from(sessionTurns).where(
2403
- and4(
2404
- eq4(sessionTurns.workspaceId, workspaceId),
2592
+ and5(
2593
+ eq5(sessionTurns.workspaceId, workspaceId),
2405
2594
  inArray(sessionTurns.sessionId, sessionIds),
2406
2595
  inArray(sessionTurns.status, TERMINAL_CANCELLATION_LIVE_TURN_STATUSES)
2407
2596
  )
@@ -2420,10 +2609,10 @@ async function enqueueCancelledChildOutboxInTransaction(db, input) {
2420
2609
  let personalConnectionDelegations = [];
2421
2610
  if (input.rootSession.parentTurnId) {
2422
2611
  const [parentTurn] = await db.select({ delegations: sessionTurns.personalConnectionDelegations }).from(sessionTurns).where(
2423
- and4(
2424
- eq4(sessionTurns.workspaceId, input.workspaceId),
2425
- eq4(sessionTurns.sessionId, parentSessionId),
2426
- eq4(sessionTurns.id, input.rootSession.parentTurnId)
2612
+ and5(
2613
+ eq5(sessionTurns.workspaceId, input.workspaceId),
2614
+ eq5(sessionTurns.sessionId, parentSessionId),
2615
+ eq5(sessionTurns.id, input.rootSession.parentTurnId)
2427
2616
  )
2428
2617
  ).limit(1);
2429
2618
  if (parentTurn) {
@@ -2465,7 +2654,7 @@ async function enqueueCancelledChildOutboxInTransaction(db, input) {
2465
2654
  });
2466
2655
  }
2467
2656
  async function assertSessionBranchIsNotCancelled(db, workspaceId, sessionId) {
2468
- const rows = await db.execute(sql2`
2657
+ const rows = await db.execute(sql3`
2469
2658
  with recursive ancestry(id, parent_id, status, depth, path, cycle) as (
2470
2659
  select session.id, session.parent_session_id, session.status, 0::integer,
2471
2660
  array[session.id]::uuid[], false
@@ -2540,7 +2729,7 @@ async function cancelSessionSubtreeInTransaction(db, input) {
2540
2729
  activeAttemptId: null,
2541
2730
  cancelledBy: input.actor,
2542
2731
  cancelReason: input.reason ?? "session_cancelled",
2543
- version: sql2`${sessionTurns.version} + 1`,
2732
+ version: sql3`${sessionTurns.version} + 1`,
2544
2733
  finishedAt: now,
2545
2734
  updatedAt: now
2546
2735
  }).where(inArray(sessionTurns.id, immediatelyCancelledTurnIds));
@@ -2551,29 +2740,30 @@ async function cancelSessionSubtreeInTransaction(db, input) {
2551
2740
  respondedAt: now,
2552
2741
  updatedAt: now
2553
2742
  }).where(
2554
- and4(
2555
- eq4(sessionHumanInputRequests.workspaceId, input.workspaceId),
2743
+ and5(
2744
+ eq5(sessionHumanInputRequests.workspaceId, input.workspaceId),
2556
2745
  inArray(sessionHumanInputRequests.turnId, immediatelyCancelledTurnIds),
2557
- eq4(sessionHumanInputRequests.status, "pending")
2746
+ eq5(sessionHumanInputRequests.status, "pending")
2558
2747
  )
2559
2748
  ).returning({
2560
2749
  id: sessionHumanInputRequests.id,
2561
2750
  sessionId: sessionHumanInputRequests.sessionId,
2562
- turnId: sessionHumanInputRequests.turnId
2751
+ turnId: sessionHumanInputRequests.turnId,
2752
+ questions: sessionHumanInputRequests.questions
2563
2753
  });
2564
2754
  await db.update(codexCapacityWaiters).set({ status: "superseded", lastWakeReason: "session_cancelled", updatedAt: now }).where(
2565
- and4(
2566
- eq4(codexCapacityWaiters.workspaceId, input.workspaceId),
2755
+ and5(
2756
+ eq5(codexCapacityWaiters.workspaceId, input.workspaceId),
2567
2757
  inArray(codexCapacityWaiters.blockedTurnId, immediatelyCancelledTurnIds),
2568
- eq4(codexCapacityWaiters.status, "waiting")
2758
+ eq5(codexCapacityWaiters.status, "waiting")
2569
2759
  )
2570
2760
  );
2571
2761
  }
2572
2762
  const cancelledSystemUpdates = await db.update(sessionSystemUpdates).set({ state: "cancelled" }).where(
2573
- and4(
2574
- eq4(sessionSystemUpdates.workspaceId, input.workspaceId),
2763
+ and5(
2764
+ eq5(sessionSystemUpdates.workspaceId, input.workspaceId),
2575
2765
  inArray(sessionSystemUpdates.sessionId, input.sessionIds),
2576
- eq4(sessionSystemUpdates.state, "pending")
2766
+ eq5(sessionSystemUpdates.state, "pending")
2577
2767
  )
2578
2768
  ).returning({
2579
2769
  id: sessionSystemUpdates.id,
@@ -2674,19 +2864,51 @@ async function cancelSessionSubtreeInTransaction(db, input) {
2674
2864
  }
2675
2865
  const inserted = eventValues.length > 0 ? await db.insert(sessionEvents).values(eventValues).returning({
2676
2866
  id: sessionEvents.id,
2677
- sequence: sessionEvents.sequence
2867
+ sequence: sessionEvents.sequence,
2868
+ type: sessionEvents.type,
2869
+ turnId: sessionEvents.turnId,
2870
+ payload: sessionEvents.payload
2678
2871
  }) : [];
2872
+ const cancelledHumanInputsById = new Map(
2873
+ cancelledHumanInputs.filter((request) => request.sessionId === session.id).map((request) => [request.id, request])
2874
+ );
2875
+ for (const event of inserted) {
2876
+ if (event.type !== "user.humanInputResponse") continue;
2877
+ const payload = event.payload;
2878
+ const request = typeof payload.requestId === "string" ? cancelledHumanInputsById.get(payload.requestId) : null;
2879
+ if (!request) continue;
2880
+ await mirrorSessionRealtimeContextInTransaction(db, {
2881
+ accountId: input.accountId,
2882
+ workspaceId: input.workspaceId,
2883
+ sessionId: session.id,
2884
+ sourceKind: "human_input_response",
2885
+ sourceId: event.id,
2886
+ turnId: event.turnId,
2887
+ channel: null,
2888
+ text: renderRealtimeHumanInputResponseContext({
2889
+ requestId: request.id,
2890
+ questions: request.questions,
2891
+ response: { outcome: "cancelled" }
2892
+ }),
2893
+ payload: {
2894
+ requestId: request.id,
2895
+ outcome: "cancelled",
2896
+ sourceEventId: event.id
2897
+ },
2898
+ now
2899
+ });
2900
+ }
2679
2901
  const liveTurnId = session.activeTurnId && liveTurnIds.has(session.activeTurnId) ? session.activeTurnId : null;
2680
2902
  await db.update(sessions).set({
2681
2903
  status: "cancelled",
2682
2904
  activeTurnId: liveTurnId,
2683
- queueVersion: sql2`${sessions.queueVersion} + 1`,
2905
+ queueVersion: sql3`${sessions.queueVersion} + 1`,
2684
2906
  queueHeadPosition: 0,
2685
2907
  queueTailPosition: 0,
2686
2908
  lastSequence: sequence,
2687
2909
  updatedAt: now
2688
2910
  }).where(
2689
- and4(eq4(sessions.workspaceId, input.workspaceId), eq4(sessions.id, session.id))
2911
+ and5(eq5(sessions.workspaceId, input.workspaceId), eq5(sessions.id, session.id))
2690
2912
  );
2691
2913
  const eventIds = [...preinsertedEvents, ...inserted].sort((left, right) => left.sequence - right.sequence).map((event) => event.id);
2692
2914
  if (session.id === input.rootSessionId) eventIds.unshift(input.rootControlEventId);
@@ -2810,9 +3032,9 @@ async function mutateSessionControlInTransaction(db, input) {
2810
3032
  updatedAt: /* @__PURE__ */ new Date()
2811
3033
  }
2812
3034
  ).where(
2813
- and4(
2814
- eq4(sessions.workspaceId, input.workspaceId),
2815
- input.action === "cancel" ? inArray(sessions.id, cancellationSessionIds) : eq4(sessions.id, input.sessionId)
3035
+ and5(
3036
+ eq5(sessions.workspaceId, input.workspaceId),
3037
+ input.action === "cancel" ? inArray(sessions.id, cancellationSessionIds) : eq5(sessions.id, input.sessionId)
2816
3038
  )
2817
3039
  ).returning({
2818
3040
  id: sessions.id,
@@ -2869,7 +3091,7 @@ async function mutateSessionControlInTransaction(db, input) {
2869
3091
  }).returning({ id: sessionEvents.id });
2870
3092
  if (!controlEvent)
2871
3093
  throw new SessionControlInvariantError("Session control event was not inserted");
2872
- await db.update(sessions).set({ lastSequence: updated.lastSequence + 1, updatedAt: /* @__PURE__ */ new Date() }).where(eq4(sessions.id, input.sessionId));
3094
+ await db.update(sessions).set({ lastSequence: updated.lastSequence + 1, updatedAt: /* @__PURE__ */ new Date() }).where(eq5(sessions.id, input.sessionId));
2873
3095
  await db.insert(auditEvents).values({
2874
3096
  accountId: input.accountId,
2875
3097
  workspaceId: input.workspaceId,
@@ -2963,9 +3185,9 @@ async function autoResumeSessionBranchInTransaction(db, input) {
2963
3185
  directControlChangedAt: /* @__PURE__ */ new Date(),
2964
3186
  updatedAt: /* @__PURE__ */ new Date()
2965
3187
  }).where(
2966
- and4(
2967
- eq4(sessions.workspaceId, input.workspaceId),
2968
- eq4(sessions.id, input.sessionId)
3188
+ and5(
3189
+ eq5(sessions.workspaceId, input.workspaceId),
3190
+ eq5(sessions.id, input.sessionId)
2969
3191
  )
2970
3192
  );
2971
3193
  const workspaceControlEventId = await insertWorkspaceControlEventInTransaction(db, {
@@ -3035,9 +3257,9 @@ async function mutateWorkspaceControlInTransaction(db, input) {
3035
3257
  changedAt: /* @__PURE__ */ new Date(),
3036
3258
  updatedAt: /* @__PURE__ */ new Date()
3037
3259
  }).where(
3038
- and4(
3039
- eq4(workspaceInferenceControls.workspaceId, input.workspaceId),
3040
- eq4(workspaceInferenceControls.revision, currentRevision)
3260
+ and5(
3261
+ eq5(workspaceInferenceControls.workspaceId, input.workspaceId),
3262
+ eq5(workspaceInferenceControls.revision, currentRevision)
3041
3263
  )
3042
3264
  ).returning({ workspaceId: workspaceInferenceControls.workspaceId });
3043
3265
  if (!updated) {
@@ -3114,7 +3336,7 @@ async function insertWorkspaceControlEventInTransaction(db, input) {
3114
3336
 
3115
3337
  // src/session-realtime.ts
3116
3338
  import { createHash as createHash4, timingSafeEqual } from "crypto";
3117
- import { and as and9, asc as asc4, eq as eq9, inArray as inArray4 } from "drizzle-orm";
3339
+ import { and as and9, asc as asc4, eq as eq9, gt as gt3, inArray as inArray4, isNull as isNull2, or } from "drizzle-orm";
3118
3340
 
3119
3341
  // src/session-realtime-context.ts
3120
3342
  import { createHash as createHash3 } from "crypto";
@@ -3134,115 +3356,17 @@ import {
3134
3356
  import { and as and7, asc as asc2, eq as eq7, inArray as inArray2, sql as sql4 } from "drizzle-orm";
3135
3357
 
3136
3358
  // src/session-realtime-state.ts
3137
- import { and as and5, eq as eq5, gt } from "drizzle-orm";
3359
+ import { and as and6, eq as eq6, gt as gt2 } from "drizzle-orm";
3138
3360
  async function sessionRealtimeIsActiveInTransaction(db, workspaceId, sessionId, now = /* @__PURE__ */ new Date()) {
3139
3361
  const [row] = await db.select({ id: sessionRealtimeModes.id }).from(sessionRealtimeModes).where(
3140
- and5(
3141
- eq5(sessionRealtimeModes.workspaceId, workspaceId),
3142
- eq5(sessionRealtimeModes.sessionId, sessionId),
3143
- eq5(sessionRealtimeModes.state, "active"),
3144
- gt(sessionRealtimeModes.leaseExpiresAt, now)
3145
- )
3146
- ).limit(1);
3147
- return Boolean(row);
3148
- }
3149
-
3150
- // src/session-realtime-mirror.ts
3151
- import { createHash as createHash2 } from "crypto";
3152
- import { and as and6, desc, eq as eq6, gt as gt2, sql as sql3 } from "drizzle-orm";
3153
- var SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES = 131072;
3154
- var SESSION_REALTIME_MIRROR_MAX_PAYLOAD_BYTES = 131072;
3155
- var TRUNCATION_MARKER = "\n\u2026realtime context truncated\u2026";
3156
- function deterministicUuid(seed) {
3157
- const bytes = createHash2("sha256").update(seed, "utf8").digest().subarray(0, 16);
3158
- bytes[6] = (bytes[6] ?? 0) & 15 | 80;
3159
- bytes[8] = (bytes[8] ?? 0) & 63 | 128;
3160
- const hex = bytes.toString("hex");
3161
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
3162
- }
3163
- function takeUtf8Head(value, maximumBytes) {
3164
- const bytes = Buffer.from(value, "utf8");
3165
- if (bytes.length <= maximumBytes) return value;
3166
- let end = maximumBytes;
3167
- while (end > 0 && (bytes[end] & 192) === 128) end -= 1;
3168
- return bytes.subarray(0, end).toString("utf8");
3169
- }
3170
- function boundedText(value) {
3171
- if (Buffer.byteLength(value, "utf8") <= SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES) return value;
3172
- const markerBytes = Buffer.byteLength(TRUNCATION_MARKER, "utf8");
3173
- return `${takeUtf8Head(value, SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES - markerBytes)}${TRUNCATION_MARKER}`;
3174
- }
3175
- function boundedPayload(value) {
3176
- const payload = sanitizeEventPayload(value);
3177
- if (Buffer.byteLength(JSON.stringify(payload), "utf8") > SESSION_REALTIME_MIRROR_MAX_PAYLOAD_BYTES) {
3178
- throw new Error("Realtime mirror payload exceeds the durable ledger limit");
3179
- }
3180
- return payload;
3181
- }
3182
- async function mirrorSessionRealtimeContextInTransaction(db, input) {
3183
- const now = input.now ?? /* @__PURE__ */ new Date();
3184
- const modes = await db.select().from(sessionRealtimeModes).where(
3185
3362
  and6(
3186
- eq6(sessionRealtimeModes.accountId, input.accountId),
3187
- eq6(sessionRealtimeModes.workspaceId, input.workspaceId),
3188
- eq6(sessionRealtimeModes.sessionId, input.sessionId),
3363
+ eq6(sessionRealtimeModes.workspaceId, workspaceId),
3364
+ eq6(sessionRealtimeModes.sessionId, sessionId),
3189
3365
  eq6(sessionRealtimeModes.state, "active"),
3190
3366
  gt2(sessionRealtimeModes.leaseExpiresAt, now)
3191
3367
  )
3192
- ).orderBy(desc(sessionRealtimeModes.startedAt)).for("update").limit(2);
3193
- if (modes.length === 0) return null;
3194
- if (modes.length !== 1) {
3195
- throw new Error(`Session ${input.sessionId} has multiple active realtime modes`);
3196
- }
3197
- const mode = modes[0];
3198
- const operationId = deterministicUuid(
3199
- `opengeni:session-realtime-mirror:${mode.id}:${input.sourceKind}:${input.sourceId}`
3200
- );
3201
- const [existing] = await db.select().from(sessionRealtimeEntries).where(
3202
- and6(
3203
- eq6(sessionRealtimeEntries.realtimeId, mode.id),
3204
- eq6(sessionRealtimeEntries.operationId, operationId)
3205
- )
3206
3368
  ).limit(1);
3207
- if (existing) return { entry: existing, replay: true };
3208
- const [sequenceRow] = await db.select({ next: sql3`coalesce(max(${sessionRealtimeEntries.sequence}), 0) + 1` }).from(sessionRealtimeEntries).where(eq6(sessionRealtimeEntries.realtimeId, mode.id));
3209
- const payload = boundedPayload({
3210
- ...input.payload ?? {},
3211
- source: input.sourceKind,
3212
- sourceId: input.sourceId,
3213
- channel: input.channel,
3214
- ...input.turnId ? { sourceTurnId: input.turnId } : {}
3215
- });
3216
- const [entry] = await db.insert(sessionRealtimeEntries).values({
3217
- accountId: input.accountId,
3218
- workspaceId: input.workspaceId,
3219
- sessionId: input.sessionId,
3220
- realtimeId: mode.id,
3221
- operationId,
3222
- connectionEpoch: mode.connectionEpoch,
3223
- sequence: Number(sequenceRow?.next ?? 1),
3224
- direction: "provider_out",
3225
- kind: "session_update",
3226
- text: boundedText(input.text),
3227
- payload,
3228
- createdAt: now,
3229
- updatedAt: now
3230
- }).returning();
3231
- if (!entry) throw new Error("Failed to append realtime session context");
3232
- return { entry, replay: false };
3233
- }
3234
- function renderRealtimeHumanInputContext(input) {
3235
- return [
3236
- "<session_user_message>",
3237
- ` <status>${input.routing}</status>`,
3238
- ` <delivery>${input.delivery}</delivery>`,
3239
- ` <text>${escapeXmlText(input.text)}</text>`,
3240
- " <instruction>Already routed by OpenGeni; do not delegate this message again.</instruction>",
3241
- "</session_user_message>"
3242
- ].join("\n");
3243
- }
3244
- function escapeXmlText(value) {
3245
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
3369
+ return Boolean(row);
3246
3370
  }
3247
3371
 
3248
3372
  // src/session-queue-commands.ts
@@ -3370,10 +3494,13 @@ async function supersedeSessionCurrentDirectionInTransaction(db, input) {
3370
3494
  eq7(sessionHumanInputRequests.turnId, current.id),
3371
3495
  eq7(sessionHumanInputRequests.status, "pending")
3372
3496
  )
3373
- ).returning({ id: sessionHumanInputRequests.id });
3497
+ ).returning({
3498
+ id: sessionHumanInputRequests.id,
3499
+ questions: sessionHumanInputRequests.questions
3500
+ });
3374
3501
  let lastSequence = closedTools.sequence;
3375
3502
  if (cancelledHumanInputs.length > 0) {
3376
- await db.insert(sessionEvents).values(
3503
+ const cancelledHumanInputEvents = await db.insert(sessionEvents).values(
3377
3504
  cancelledHumanInputs.map((request) => ({
3378
3505
  accountId: input.accountId,
3379
3506
  workspaceId: input.workspaceId,
@@ -3386,7 +3513,33 @@ async function supersedeSessionCurrentDirectionInTransaction(db, input) {
3386
3513
  payload: { requestId: request.id, response: { outcome: "cancelled" } },
3387
3514
  occurredAt: now
3388
3515
  }))
3389
- );
3516
+ ).returning();
3517
+ const requestsById = new Map(cancelledHumanInputs.map((request) => [request.id, request]));
3518
+ for (const event of cancelledHumanInputEvents) {
3519
+ const payload = event.payload;
3520
+ const request = typeof payload.requestId === "string" ? requestsById.get(payload.requestId) : null;
3521
+ if (!request) continue;
3522
+ await mirrorSessionRealtimeContextInTransaction(db, {
3523
+ accountId: input.accountId,
3524
+ workspaceId: input.workspaceId,
3525
+ sessionId: input.sessionId,
3526
+ sourceKind: "human_input_response",
3527
+ sourceId: event.id,
3528
+ turnId: current.id,
3529
+ channel: null,
3530
+ text: renderRealtimeHumanInputResponseContext({
3531
+ requestId: request.id,
3532
+ questions: request.questions,
3533
+ response: { outcome: "cancelled" }
3534
+ }),
3535
+ payload: {
3536
+ requestId: request.id,
3537
+ outcome: "cancelled",
3538
+ sourceEventId: event.id
3539
+ },
3540
+ now
3541
+ });
3542
+ }
3390
3543
  }
3391
3544
  await db.update(sessionTurns).set({
3392
3545
  status: "superseded",
@@ -5435,6 +5588,46 @@ async function beginSessionRealtimeInTransaction(db, input) {
5435
5588
  now
5436
5589
  );
5437
5590
  eventIds.push(event.id);
5591
+ const pendingHumanInputs = await db.select({
5592
+ id: sessionHumanInputRequests.id,
5593
+ turnId: sessionHumanInputRequests.turnId,
5594
+ questions: sessionHumanInputRequests.questions,
5595
+ allowSkip: sessionHumanInputRequests.allowSkip,
5596
+ expiresAt: sessionHumanInputRequests.expiresAt
5597
+ }).from(sessionHumanInputRequests).where(
5598
+ and9(
5599
+ eq9(sessionHumanInputRequests.accountId, input.accountId),
5600
+ eq9(sessionHumanInputRequests.workspaceId, input.workspaceId),
5601
+ eq9(sessionHumanInputRequests.sessionId, input.sessionId),
5602
+ eq9(sessionHumanInputRequests.status, "pending"),
5603
+ or(
5604
+ isNull2(sessionHumanInputRequests.expiresAt),
5605
+ gt3(sessionHumanInputRequests.expiresAt, now)
5606
+ )
5607
+ )
5608
+ ).orderBy(
5609
+ asc4(sessionHumanInputRequests.createdAt),
5610
+ asc4(sessionHumanInputRequests.id)
5611
+ );
5612
+ if (pendingHumanInputs.length > 0) {
5613
+ const sourceTurnIds = new Set(pendingHumanInputs.map((request) => request.turnId));
5614
+ await mirrorSessionRealtimeContextInTransaction(db, {
5615
+ accountId: input.accountId,
5616
+ workspaceId: input.workspaceId,
5617
+ sessionId: input.sessionId,
5618
+ sourceKind: "human_input_request",
5619
+ sourceId: `startup:${pendingHumanInputs.map((request) => request.id).join(":")}`,
5620
+ turnId: sourceTurnIds.size === 1 ? pendingHumanInputs[0].turnId : null,
5621
+ channel: "speakable",
5622
+ text: renderRealtimeHumanInputRequestContext({ requests: pendingHumanInputs }),
5623
+ payload: {
5624
+ status: "waiting_for_user",
5625
+ requestIds: pendingHumanInputs.map((request) => request.id),
5626
+ trigger: "realtime_start"
5627
+ },
5628
+ now
5629
+ });
5630
+ }
5438
5631
  return {
5439
5632
  mode: mapRealtimeMode(row),
5440
5633
  replay: false,
@@ -5566,7 +5759,7 @@ async function settleExpiredSessionRealtimeInTransaction(db, session, now = /* @
5566
5759
  // src/session-realtime-ledger.ts
5567
5760
  import { createHash as createHash6 } from "crypto";
5568
5761
  import { LatencyMode, ReasoningEffort as ReasoningEffort2 } from "@opengeni/contracts";
5569
- import { and as and11, asc as asc5, desc as desc3, eq as eq11, inArray as inArray6, isNull as isNull2, or, sql as sql7 } from "drizzle-orm";
5762
+ import { and as and11, asc as asc5, desc as desc3, eq as eq11, inArray as inArray6, isNull as isNull3, or as or2, sql as sql7 } from "drizzle-orm";
5570
5763
 
5571
5764
  // src/session-realtime-terminal.ts
5572
5765
  import { createHash as createHash5 } from "crypto";
@@ -6016,7 +6209,7 @@ async function claimSessionRealtimeConnectionInTransaction(db, input) {
6016
6209
  and11(
6017
6210
  eq11(sessionRealtimeEntries.realtimeId, input.realtimeId),
6018
6211
  eq11(sessionRealtimeEntries.direction, "provider_out"),
6019
- isNull2(sessionRealtimeEntries.providerAckedAt)
6212
+ isNull3(sessionRealtimeEntries.providerAckedAt)
6020
6213
  )
6021
6214
  ).orderBy(asc5(sessionRealtimeEntries.sequence)).limit(SESSION_REALTIME_STARTUP_MAX_ENTRIES);
6022
6215
  const startupFenceSequence = startupEntries.at(-1)?.sequence ?? 0;
@@ -6048,7 +6241,7 @@ async function startupEntriesForConnection(db, connection) {
6048
6241
  and11(
6049
6242
  eq11(sessionRealtimeEntries.realtimeId, connection.realtimeId),
6050
6243
  eq11(sessionRealtimeEntries.direction, "provider_out"),
6051
- isNull2(sessionRealtimeEntries.providerAckedAt),
6244
+ isNull3(sessionRealtimeEntries.providerAckedAt),
6052
6245
  sql7`${sessionRealtimeEntries.sequence} <= ${connection.startupFenceSequence}`
6053
6246
  )
6054
6247
  ).orderBy(asc5(sessionRealtimeEntries.sequence)).limit(SESSION_REALTIME_STARTUP_MAX_ENTRIES);
@@ -6470,7 +6663,7 @@ async function materializeRealtimeUpdates(db, input, accountId, allocateSequence
6470
6663
  eq11(sessionSystemUpdates.sessionId, input.sessionId),
6471
6664
  inArray6(sessionSystemUpdates.state, ["pending", "deferred"]),
6472
6665
  inArray6(sessionSystemUpdates.kind, ["agent_message", "child_terminal_result"]),
6473
- isNull2(sessionRealtimeEntries.id)
6666
+ isNull3(sessionRealtimeEntries.id)
6474
6667
  )
6475
6668
  ).orderBy(asc5(sessionSystemUpdates.createdAt), asc5(sessionSystemUpdates.id)).limit(SESSION_REALTIME_LEDGER_MAX_OUTBOUND);
6476
6669
  const updates = rows.map(({ update }) => update);
@@ -6579,7 +6772,7 @@ async function syncSessionRealtimeLedgerInTransaction(db, input, hooks = {}) {
6579
6772
  }).where(
6580
6773
  and11(
6581
6774
  eq11(sessionRealtimeConnections.id, connection.id),
6582
- isNull2(sessionRealtimeConnections.startupAcknowledgedAt)
6775
+ isNull3(sessionRealtimeConnections.startupAcknowledgedAt)
6583
6776
  )
6584
6777
  ).returning({ id: sessionRealtimeConnections.id });
6585
6778
  if (!acknowledged) {
@@ -6616,7 +6809,7 @@ async function syncSessionRealtimeLedgerInTransaction(db, input, hooks = {}) {
6616
6809
  const [existing] = await db.select().from(sessionRealtimeEntries).where(
6617
6810
  and11(
6618
6811
  eq11(sessionRealtimeEntries.realtimeId, input.realtimeId),
6619
- incoming.kind === "delegation_call" && incoming.delegationItemId ? or(
6812
+ incoming.kind === "delegation_call" && incoming.delegationItemId ? or2(
6620
6813
  eq11(sessionRealtimeEntries.operationId, incoming.operationId),
6621
6814
  and11(
6622
6815
  eq11(sessionRealtimeEntries.kind, "delegation_call"),
@@ -6695,7 +6888,7 @@ async function syncSessionRealtimeLedgerInTransaction(db, input, hooks = {}) {
6695
6888
  eq11(sessionRealtimeEntries.sessionId, input.sessionId),
6696
6889
  eq11(sessionRealtimeEntries.realtimeId, input.realtimeId),
6697
6890
  eq11(sessionRealtimeEntries.direction, "provider_out"),
6698
- isNull2(sessionRealtimeEntries.clientAckedAt),
6891
+ isNull3(sessionRealtimeEntries.clientAckedAt),
6699
6892
  sql7`${sessionRealtimeEntries.sequence} <= ${clientAck}`
6700
6893
  )
6701
6894
  );
@@ -6730,7 +6923,7 @@ async function syncSessionRealtimeLedgerInTransaction(db, input, hooks = {}) {
6730
6923
  sessionRealtimeEntries.id,
6731
6924
  ackable.map((entry) => entry.id)
6732
6925
  ),
6733
- isNull2(sessionRealtimeEntries.providerAckedAt)
6926
+ isNull3(sessionRealtimeEntries.providerAckedAt)
6734
6927
  )
6735
6928
  );
6736
6929
  }
@@ -6740,7 +6933,7 @@ async function syncSessionRealtimeLedgerInTransaction(db, input, hooks = {}) {
6740
6933
  eq11(sessionRealtimeEntries.sessionId, input.sessionId),
6741
6934
  eq11(sessionRealtimeEntries.realtimeId, input.realtimeId),
6742
6935
  eq11(sessionRealtimeEntries.direction, "provider_out"),
6743
- isNull2(sessionRealtimeEntries.providerAckedAt)
6936
+ isNull3(sessionRealtimeEntries.providerAckedAt)
6744
6937
  )
6745
6938
  ).orderBy(
6746
6939
  sql7`case when ${sessionRealtimeEntries.clientAckedAt} is null then 0 else 1 end`,
@@ -7300,13 +7493,14 @@ function renderMemoryEntry(record) {
7300
7493
  import { sql as sql15 } from "drizzle-orm";
7301
7494
 
7302
7495
  // src/workspace-instruction-policies.ts
7303
- import { createHash as createHash8 } from "crypto";
7496
+ import { createHash as createHash8, randomUUID } from "crypto";
7304
7497
  import {
7498
+ PreferenceRegistrySnapshot,
7305
7499
  ResolvedWorkspaceInstructionPolicySnapshot,
7306
7500
  WORKSPACE_INSTRUCTION_POLICY_CONTENT_MAX_CHARS,
7307
7501
  WorkspaceInstructionPolicySnapshot
7308
7502
  } from "@opengeni/contracts";
7309
- import { and as and12, asc as asc6, desc as desc4, eq as eq12, inArray as inArray7, isNull as isNull3, lt, sql as sql8 } from "drizzle-orm";
7503
+ import { and as and12, asc as asc6, desc as desc4, eq as eq12, inArray as inArray7, isNull as isNull4, lt, or as or3, sql as sql8 } from "drizzle-orm";
7310
7504
  var WorkspaceInstructionPolicyConflictError = class extends Error {
7311
7505
  constructor(currentHead) {
7312
7506
  super("The active workspace instruction policy changed in another request");
@@ -7315,6 +7509,13 @@ var WorkspaceInstructionPolicyConflictError = class extends Error {
7315
7509
  name = "WorkspaceInstructionPolicyConflictError";
7316
7510
  code = "WORKSPACE_INSTRUCTION_POLICY_CONFLICT";
7317
7511
  };
7512
+ var WorkspaceInstructionPolicyOperationReuseError = class extends Error {
7513
+ name = "WorkspaceInstructionPolicyOperationReuseError";
7514
+ code = "WORKSPACE_INSTRUCTION_POLICY_OPERATION_REUSED";
7515
+ constructor() {
7516
+ super("The workspace instruction-policy operation id was already used for another request");
7517
+ }
7518
+ };
7318
7519
  var WorkspaceInstructionPolicyNotFoundError = class extends Error {
7319
7520
  name = "WorkspaceInstructionPolicyNotFoundError";
7320
7521
  constructor(message = "Workspace instruction-policy revision was not found") {
@@ -7336,12 +7537,169 @@ var WorkspaceInstructionPolicySnapshotAuthorityError = class extends Error {
7336
7537
  function contentHash(content) {
7337
7538
  return createHash8("sha256").update(content, "utf8").digest("hex");
7338
7539
  }
7540
+ function hasOwnField(value, field) {
7541
+ return Object.prototype.hasOwnProperty.call(value, field);
7542
+ }
7543
+ function operationRequestFingerprint(operation, fields) {
7544
+ const canonicalRequest = JSON.stringify([
7545
+ "workspace_instruction_policy_operation",
7546
+ 1,
7547
+ operation,
7548
+ fields
7549
+ ]);
7550
+ return createHash8("sha256").update(canonicalRequest, "utf8").digest("hex");
7551
+ }
7552
+ function draftRequestFingerprint(input) {
7553
+ return operationRequestFingerprint("create_draft", [
7554
+ ["accountId", true, input.accountId],
7555
+ ["workspaceId", true, input.workspaceId],
7556
+ ["kind", true, input.kind],
7557
+ ["scope", true, input.scope],
7558
+ ["roleKey", true, input.roleKey],
7559
+ ["content", true, input.content],
7560
+ ["provenanceSource", true, input.provenanceSource],
7561
+ ["provenanceSourceId", true, input.provenanceSourceId],
7562
+ ["supersedesRevisionId", true, input.supersedesRevisionId],
7563
+ ["createdBySubjectId", true, input.createdBySubjectId]
7564
+ ]);
7565
+ }
7566
+ function importLegacyRequestFingerprint(input) {
7567
+ return operationRequestFingerprint("import_legacy", [
7568
+ ["accountId", true, input.accountId],
7569
+ ["workspaceId", true, input.workspaceId],
7570
+ ["createdBySubjectId", true, input.createdBySubjectId],
7571
+ ["supersedesRevisionId", true, input.supersedesRevisionId]
7572
+ ]);
7573
+ }
7574
+ function activeRevisionRequestFingerprint(input) {
7575
+ const expectedCurrentRevisionIdPresent = hasOwnField(input, "expectedCurrentRevisionId");
7576
+ const expectedActivationVersionPresent = hasOwnField(input, "expectedActivationVersion");
7577
+ return operationRequestFingerprint(`change_active_revision:${input.type}`, [
7578
+ ["accountId", true, input.accountId],
7579
+ ["workspaceId", true, input.workspaceId],
7580
+ ["targetRevisionId", true, input.targetRevisionId],
7581
+ [
7582
+ "expectedCurrentRevisionId",
7583
+ expectedCurrentRevisionIdPresent,
7584
+ input.expectedCurrentRevisionId ?? null
7585
+ ],
7586
+ [
7587
+ "expectedActivationVersion",
7588
+ expectedActivationVersionPresent,
7589
+ input.expectedActivationVersion ?? null
7590
+ ],
7591
+ ["actorSubjectId", true, input.actorSubjectId],
7592
+ ["reason", true, input.reason]
7593
+ ]);
7594
+ }
7339
7595
  function iso(value) {
7340
7596
  return (value instanceof Date ? value : new Date(value)).toISOString();
7341
7597
  }
7598
+ async function getWorkspaceStateAcceptedAttemptGovernance(db, input) {
7599
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
7600
+ const initiatingSubject = sql8`coalesce(
7601
+ ${sessionTurns.initiatingHumanSubjectId},
7602
+ case when ${sessionTurns.initiatorKind} = 'subject'
7603
+ then ${sessionTurns.initiatorSubjectId}
7604
+ end
7605
+ )`;
7606
+ const [attempt] = await scopedDb.select({
7607
+ attemptId: sessionTurnAttempts.id,
7608
+ executionGeneration: sessionTurnAttempts.executionGeneration,
7609
+ acceptedAt: sessionTurns.createdAt
7610
+ }).from(sessionTurnAttempts).innerJoin(
7611
+ sessionTurns,
7612
+ and12(
7613
+ eq12(sessionTurns.accountId, sessionTurnAttempts.accountId),
7614
+ eq12(sessionTurns.workspaceId, sessionTurnAttempts.workspaceId),
7615
+ eq12(sessionTurns.sessionId, sessionTurnAttempts.sessionId),
7616
+ eq12(sessionTurns.id, sessionTurnAttempts.turnId)
7617
+ )
7618
+ ).where(
7619
+ and12(
7620
+ eq12(sessionTurnAttempts.accountId, input.accountId),
7621
+ eq12(sessionTurnAttempts.workspaceId, input.workspaceId),
7622
+ eq12(sessionTurnAttempts.id, input.attemptId),
7623
+ eq12(initiatingSubject, input.subjectId)
7624
+ )
7625
+ ).limit(1);
7626
+ if (!attempt) return null;
7627
+ const [policyRows, preferenceRows] = await Promise.all([
7628
+ scopedDb.select().from(workspaceInstructionPolicySnapshots).where(
7629
+ and12(
7630
+ eq12(workspaceInstructionPolicySnapshots.accountId, input.accountId),
7631
+ eq12(workspaceInstructionPolicySnapshots.workspaceId, input.workspaceId),
7632
+ eq12(workspaceInstructionPolicySnapshots.attemptId, input.attemptId),
7633
+ eq12(
7634
+ workspaceInstructionPolicySnapshots.executionGeneration,
7635
+ attempt.executionGeneration
7636
+ )
7637
+ )
7638
+ ).limit(1),
7639
+ scopedDb.select().from(preferenceRegistrySnapshots).where(
7640
+ and12(
7641
+ eq12(preferenceRegistrySnapshots.accountId, input.accountId),
7642
+ eq12(preferenceRegistrySnapshots.workspaceId, input.workspaceId),
7643
+ eq12(preferenceRegistrySnapshots.attemptId, input.attemptId),
7644
+ eq12(preferenceRegistrySnapshots.executionGeneration, attempt.executionGeneration),
7645
+ eq12(preferenceRegistrySnapshots.initiatingHumanSubjectId, input.subjectId)
7646
+ )
7647
+ ).limit(1)
7648
+ ]);
7649
+ const policyRow = policyRows[0] ?? null;
7650
+ const preferenceRow = preferenceRows[0] ?? null;
7651
+ return {
7652
+ attemptId: attempt.attemptId,
7653
+ executionGeneration: attempt.executionGeneration,
7654
+ acceptedAt: iso(attempt.acceptedAt),
7655
+ policySnapshot: policyRow ? WorkspaceInstructionPolicySnapshot.parse({
7656
+ id: policyRow.id,
7657
+ workspaceId: policyRow.workspaceId,
7658
+ sessionId: policyRow.sessionId,
7659
+ turnId: policyRow.turnId,
7660
+ attemptId: policyRow.attemptId,
7661
+ executionGeneration: policyRow.executionGeneration,
7662
+ policyRole: policyRow.policyRole,
7663
+ roleSource: policyRow.roleSource,
7664
+ entries: policyRow.entries,
7665
+ entryHash: policyRow.entryHash,
7666
+ createdAt: iso(policyRow.createdAt)
7667
+ }) : null,
7668
+ preferenceSnapshot: preferenceRow ? (() => {
7669
+ const snapshot = PreferenceRegistrySnapshot.parse({
7670
+ id: preferenceRow.id,
7671
+ workspaceId: preferenceRow.workspaceId,
7672
+ sessionId: preferenceRow.sessionId,
7673
+ turnId: preferenceRow.turnId,
7674
+ attemptId: preferenceRow.attemptId,
7675
+ executionGeneration: preferenceRow.executionGeneration,
7676
+ initiatingHumanSubjectId: preferenceRow.initiatingHumanSubjectId,
7677
+ descriptorHash: preferenceRow.descriptorHash,
7678
+ descriptors: preferenceRow.descriptors,
7679
+ truncated: preferenceRow.truncated,
7680
+ createdAt: iso(preferenceRow.createdAt)
7681
+ });
7682
+ return {
7683
+ id: snapshot.id,
7684
+ descriptorHash: snapshot.descriptorHash,
7685
+ descriptors: snapshot.descriptors.map((descriptor) => ({
7686
+ id: descriptor.id,
7687
+ revisionId: descriptor.revisionId,
7688
+ contentHash: descriptor.contentHash,
7689
+ activeVersion: descriptor.activeVersion,
7690
+ scope: descriptor.scope
7691
+ })),
7692
+ truncated: snapshot.truncated,
7693
+ createdAt: snapshot.createdAt
7694
+ };
7695
+ })() : null
7696
+ };
7697
+ });
7698
+ }
7342
7699
  function revisionFromRow(row) {
7343
7700
  return {
7344
7701
  id: row.id,
7702
+ operationId: row.operationId ?? row.id,
7345
7703
  accountId: row.accountId,
7346
7704
  workspaceId: row.workspaceId,
7347
7705
  revision: row.revision,
@@ -7375,6 +7733,7 @@ function headFromRow(row) {
7375
7733
  function eventFromRow(row) {
7376
7734
  return {
7377
7735
  id: row.id,
7736
+ operationId: row.operationId ?? row.id,
7378
7737
  accountId: row.accountId,
7379
7738
  workspaceId: row.workspaceId,
7380
7739
  kind: row.kind,
@@ -7397,12 +7756,25 @@ function eventFromRow(row) {
7397
7756
  createdAt: iso(row.createdAt)
7398
7757
  };
7399
7758
  }
7759
+ function headFromEventRow(row) {
7760
+ return {
7761
+ workspaceId: row.workspaceId,
7762
+ kind: row.kind,
7763
+ scope: row.scope,
7764
+ roleKey: row.roleKey,
7765
+ revisionId: row.newRevisionId,
7766
+ revision: row.newRevision,
7767
+ contentHash: row.newContentHash,
7768
+ activationVersion: row.activationVersion,
7769
+ activatedAt: iso(row.createdAt)
7770
+ };
7771
+ }
7400
7772
  function headTargetConditions(workspaceId, target) {
7401
7773
  return [
7402
7774
  eq12(workspaceInstructionPolicyHeads.workspaceId, workspaceId),
7403
7775
  eq12(workspaceInstructionPolicyHeads.kind, target.kind),
7404
7776
  eq12(workspaceInstructionPolicyHeads.scope, target.scope),
7405
- target.roleKey === null ? isNull3(workspaceInstructionPolicyHeads.roleKey) : eq12(workspaceInstructionPolicyHeads.roleKey, target.roleKey)
7777
+ target.roleKey === null ? isNull4(workspaceInstructionPolicyHeads.roleKey) : eq12(workspaceInstructionPolicyHeads.roleKey, target.roleKey)
7406
7778
  ];
7407
7779
  }
7408
7780
  function eventTargetConditions(workspaceId, target) {
@@ -7410,7 +7782,7 @@ function eventTargetConditions(workspaceId, target) {
7410
7782
  eq12(workspaceInstructionPolicyActivationEvents.workspaceId, workspaceId),
7411
7783
  eq12(workspaceInstructionPolicyActivationEvents.kind, target.kind),
7412
7784
  eq12(workspaceInstructionPolicyActivationEvents.scope, target.scope),
7413
- target.roleKey === null ? isNull3(workspaceInstructionPolicyActivationEvents.roleKey) : eq12(workspaceInstructionPolicyActivationEvents.roleKey, target.roleKey)
7785
+ target.roleKey === null ? isNull4(workspaceInstructionPolicyActivationEvents.roleKey) : eq12(workspaceInstructionPolicyActivationEvents.roleKey, target.roleKey)
7414
7786
  ];
7415
7787
  }
7416
7788
  async function lockWorkspace(db, input) {
@@ -7434,6 +7806,36 @@ async function getRevisionInTransaction(db, workspaceId, revisionId) {
7434
7806
  ).limit(1);
7435
7807
  return row ?? null;
7436
7808
  }
7809
+ async function getRevisionByOperationInTransaction(db, workspaceId, operationId) {
7810
+ const [row] = await db.select().from(workspaceInstructionPolicyRevisions).where(
7811
+ and12(
7812
+ eq12(workspaceInstructionPolicyRevisions.workspaceId, workspaceId),
7813
+ or3(
7814
+ eq12(workspaceInstructionPolicyRevisions.operationId, operationId),
7815
+ and12(
7816
+ isNull4(workspaceInstructionPolicyRevisions.operationId),
7817
+ eq12(workspaceInstructionPolicyRevisions.id, operationId)
7818
+ )
7819
+ )
7820
+ )
7821
+ ).limit(1);
7822
+ return row ?? null;
7823
+ }
7824
+ async function getEventByOperationInTransaction(db, workspaceId, operationId) {
7825
+ const [row] = await db.select().from(workspaceInstructionPolicyActivationEvents).where(
7826
+ and12(
7827
+ eq12(workspaceInstructionPolicyActivationEvents.workspaceId, workspaceId),
7828
+ or3(
7829
+ eq12(workspaceInstructionPolicyActivationEvents.operationId, operationId),
7830
+ and12(
7831
+ isNull4(workspaceInstructionPolicyActivationEvents.operationId),
7832
+ eq12(workspaceInstructionPolicyActivationEvents.id, operationId)
7833
+ )
7834
+ )
7835
+ )
7836
+ ).limit(1);
7837
+ return row ?? null;
7838
+ }
7437
7839
  async function getHeadInTransaction(db, workspaceId, target) {
7438
7840
  const [row] = await db.select().from(workspaceInstructionPolicyHeads).where(and12(...headTargetConditions(workspaceId, target))).for("update").limit(1);
7439
7841
  return row ?? null;
@@ -7441,7 +7843,24 @@ async function getHeadInTransaction(db, workspaceId, target) {
7441
7843
  function sameTarget(left, right) {
7442
7844
  return left.kind === right.kind && left.scope === right.scope && left.roleKey === right.roleKey;
7443
7845
  }
7846
+ function draftReceiptMatches(row, input) {
7847
+ return row.createdBySubjectId === input.createdBySubjectId && row.kind === input.kind && row.scope === input.scope && row.roleKey === input.roleKey && row.content === input.content && row.provenanceSource === input.provenanceSource && row.provenanceSourceId === input.provenanceSourceId && row.supersedesRevisionId === input.supersedesRevisionId;
7848
+ }
7444
7849
  async function createDraftInTransaction(db, input) {
7850
+ if (await getEventByOperationInTransaction(db, input.workspaceId, input.operationId)) {
7851
+ throw new WorkspaceInstructionPolicyOperationReuseError();
7852
+ }
7853
+ const existing = await getRevisionByOperationInTransaction(
7854
+ db,
7855
+ input.workspaceId,
7856
+ input.operationId
7857
+ );
7858
+ if (existing) {
7859
+ if (existing.requestFingerprint === null ? !draftReceiptMatches(existing, input) : existing.requestFingerprint !== input.requestFingerprint) {
7860
+ throw new WorkspaceInstructionPolicyOperationReuseError();
7861
+ }
7862
+ return revisionFromRow(existing);
7863
+ }
7445
7864
  if (input.supersedesRevisionId !== null) {
7446
7865
  const superseded = await getRevisionInTransaction(
7447
7866
  db,
@@ -7455,6 +7874,8 @@ async function createDraftInTransaction(db, input) {
7455
7874
  }
7456
7875
  }
7457
7876
  const [created] = await db.insert(workspaceInstructionPolicyRevisions).values({
7877
+ operationId: input.operationId,
7878
+ requestFingerprint: input.requestFingerprint,
7458
7879
  accountId: input.accountId,
7459
7880
  workspaceId: input.workspaceId,
7460
7881
  kind: input.kind,
@@ -7471,21 +7892,42 @@ async function createDraftInTransaction(db, input) {
7471
7892
  return revisionFromRow(created);
7472
7893
  }
7473
7894
  async function createWorkspaceInstructionPolicyDraft(db, input) {
7895
+ const request = { ...input, operationId: input.operationId ?? randomUUID() };
7896
+ const normalized = { ...request, requestFingerprint: draftRequestFingerprint(request) };
7474
7897
  return await withRlsContext(
7475
7898
  db,
7476
7899
  { accountId: input.accountId, workspaceId: input.workspaceId },
7477
7900
  async (scopedDb) => {
7478
7901
  await lockWorkspace(scopedDb, input);
7479
- return await createDraftInTransaction(scopedDb, input);
7902
+ return await createDraftInTransaction(scopedDb, normalized);
7480
7903
  }
7481
7904
  );
7482
7905
  }
7483
7906
  async function importLegacyWorkspaceInstructionPolicyDraft(db, input) {
7907
+ const request = { ...input, operationId: input.operationId ?? randomUUID() };
7908
+ const normalized = {
7909
+ ...request,
7910
+ requestFingerprint: importLegacyRequestFingerprint(request)
7911
+ };
7484
7912
  return await withRlsContext(
7485
7913
  db,
7486
7914
  { accountId: input.accountId, workspaceId: input.workspaceId },
7487
7915
  async (scopedDb) => {
7488
7916
  const workspace = await lockWorkspace(scopedDb, input);
7917
+ if (await getEventByOperationInTransaction(scopedDb, input.workspaceId, normalized.operationId)) {
7918
+ throw new WorkspaceInstructionPolicyOperationReuseError();
7919
+ }
7920
+ const existing = await getRevisionByOperationInTransaction(
7921
+ scopedDb,
7922
+ input.workspaceId,
7923
+ normalized.operationId
7924
+ );
7925
+ if (existing) {
7926
+ if (existing.requestFingerprint === null ? existing.createdBySubjectId !== input.createdBySubjectId || existing.kind !== "charter" || existing.scope !== "global" || existing.roleKey !== null || existing.provenanceSource !== "legacy_import" || existing.provenanceSourceId !== "workspaces.agent_instructions" || existing.supersedesRevisionId !== input.supersedesRevisionId : existing.requestFingerprint !== normalized.requestFingerprint) {
7927
+ throw new WorkspaceInstructionPolicyOperationReuseError();
7928
+ }
7929
+ return revisionFromRow(existing);
7930
+ }
7489
7931
  if (workspace.agentInstructions === null) {
7490
7932
  throw new WorkspaceInstructionPolicyLegacyUnavailableError();
7491
7933
  }
@@ -7495,7 +7937,7 @@ async function importLegacyWorkspaceInstructionPolicyDraft(db, input) {
7495
7937
  );
7496
7938
  }
7497
7939
  return await createDraftInTransaction(scopedDb, {
7498
- ...input,
7940
+ ...normalized,
7499
7941
  kind: "charter",
7500
7942
  scope: "global",
7501
7943
  roleKey: null,
@@ -7518,7 +7960,7 @@ function listFilterConditions(workspaceId, query) {
7518
7960
  }
7519
7961
  if (query.roleKey !== void 0) {
7520
7962
  conditions.push(
7521
- query.roleKey === null ? isNull3(workspaceInstructionPolicyRevisions.roleKey) : eq12(workspaceInstructionPolicyRevisions.roleKey, query.roleKey)
7963
+ query.roleKey === null ? isNull4(workspaceInstructionPolicyRevisions.roleKey) : eq12(workspaceInstructionPolicyRevisions.roleKey, query.roleKey)
7522
7964
  );
7523
7965
  }
7524
7966
  if (query.afterRevision !== void 0) {
@@ -7619,11 +8061,27 @@ async function diffWorkspaceInstructionPolicyRevisions(db, workspaceId, input) {
7619
8061
  });
7620
8062
  }
7621
8063
  async function changeActiveRevision(db, input) {
8064
+ const requestFingerprint = activeRevisionRequestFingerprint(input);
7622
8065
  return await withRlsContext(
7623
8066
  db,
7624
8067
  { accountId: input.accountId, workspaceId: input.workspaceId },
7625
8068
  async (scopedDb) => {
7626
8069
  await lockWorkspace(scopedDb, input);
8070
+ if (await getRevisionByOperationInTransaction(scopedDb, input.workspaceId, input.operationId)) {
8071
+ throw new WorkspaceInstructionPolicyOperationReuseError();
8072
+ }
8073
+ const existingEvent = await getEventByOperationInTransaction(
8074
+ scopedDb,
8075
+ input.workspaceId,
8076
+ input.operationId
8077
+ );
8078
+ if (existingEvent) {
8079
+ const legacyRequestMatches = hasOwnField(input, "expectedCurrentRevisionId") && !hasOwnField(input, "expectedActivationVersion") && existingEvent.type === input.type && existingEvent.newRevisionId === input.targetRevisionId && existingEvent.oldRevisionId === input.expectedCurrentRevisionId && existingEvent.actorSubjectId === input.actorSubjectId && existingEvent.reason === input.reason;
8080
+ if (existingEvent.requestFingerprint === null ? !legacyRequestMatches : existingEvent.requestFingerprint !== requestFingerprint) {
8081
+ throw new WorkspaceInstructionPolicyOperationReuseError();
8082
+ }
8083
+ return { head: headFromEventRow(existingEvent), event: eventFromRow(existingEvent) };
8084
+ }
7627
8085
  const targetRow = await getRevisionInTransaction(
7628
8086
  scopedDb,
7629
8087
  input.workspaceId,
@@ -7638,7 +8096,7 @@ async function changeActiveRevision(db, input) {
7638
8096
  };
7639
8097
  const currentRow = await getHeadInTransaction(scopedDb, input.workspaceId, targetIdentity);
7640
8098
  const currentHead = currentRow ? headFromRow(currentRow) : null;
7641
- if ((currentHead?.revisionId ?? null) !== input.expectedCurrentRevisionId) {
8099
+ if ((currentHead?.revisionId ?? null) !== input.expectedCurrentRevisionId || input.expectedActivationVersion !== void 0 && (currentHead?.activationVersion ?? 0) !== input.expectedActivationVersion) {
7642
8100
  throw new WorkspaceInstructionPolicyConflictError(currentHead);
7643
8101
  }
7644
8102
  if (currentHead?.revisionId === target.id) {
@@ -7667,6 +8125,8 @@ async function changeActiveRevision(db, input) {
7667
8125
  const activationVersion = (currentHead?.activationVersion ?? 0) + 1;
7668
8126
  const createdAt = /* @__PURE__ */ new Date();
7669
8127
  const [eventRow] = await scopedDb.insert(workspaceInstructionPolicyActivationEvents).values({
8128
+ operationId: input.operationId,
8129
+ requestFingerprint,
7670
8130
  accountId: input.accountId,
7671
8131
  workspaceId: input.workspaceId,
7672
8132
  ...targetIdentity,
@@ -7712,12 +8172,17 @@ async function changeActiveRevision(db, input) {
7712
8172
  async function activateWorkspaceInstructionPolicyRevision(db, input) {
7713
8173
  return await changeActiveRevision(db, {
7714
8174
  ...input,
8175
+ operationId: input.operationId ?? randomUUID(),
7715
8176
  targetRevisionId: input.revisionId,
7716
8177
  type: "activate"
7717
8178
  });
7718
8179
  }
7719
8180
  async function rollbackWorkspaceInstructionPolicyRevision(db, input) {
7720
- return await changeActiveRevision(db, { ...input, type: "rollback" });
8181
+ return await changeActiveRevision(db, {
8182
+ ...input,
8183
+ operationId: input.operationId ?? randomUUID(),
8184
+ type: "rollback"
8185
+ });
7721
8186
  }
7722
8187
  async function getOrCreateWorkspaceInstructionPolicySnapshot(db, claims) {
7723
8188
  try {
@@ -7800,16 +8265,17 @@ import {
7800
8265
  PREFERENCE_REGISTRY_DESCRIPTOR_MAX_COUNT,
7801
8266
  PREFERENCE_REGISTRY_DESCRIPTOR_MAX_UTF8_BYTES,
7802
8267
  PREFERENCE_REGISTRY_TITLE_MAX_CHARS,
8268
+ PreferenceRegistryDescriptor,
7803
8269
  PreferenceRegistryDetailResponse,
7804
8270
  PreferenceRegistryEvent,
7805
8271
  PreferenceRegistryFullContent,
7806
8272
  PreferenceRegistryListResponse,
7807
8273
  PreferenceRegistryRecord,
7808
8274
  PreferenceRegistryRevisionSummary,
7809
- PreferenceRegistrySnapshot,
8275
+ PreferenceRegistrySnapshot as PreferenceRegistrySnapshot2,
7810
8276
  PreferenceRegistryScopeTarget
7811
8277
  } from "@opengeni/contracts";
7812
- import { and as and13, asc as asc7, desc as desc5, eq as eq13, gt as gt3, inArray as inArray8, isNull as isNull4, lte, or as or2, sql as sql9 } from "drizzle-orm";
8278
+ import { and as and13, asc as asc7, desc as desc5, eq as eq13, gt as gt4, inArray as inArray8, isNull as isNull5, lte, or as or4, sql as sql9 } from "drizzle-orm";
7813
8279
  var importedSources = /* @__PURE__ */ new Set([
7814
8280
  "knowledge_proposal",
7815
8281
  "imported_document",
@@ -8120,9 +8586,9 @@ async function listPreferenceRegistryScoped(db, input) {
8120
8586
  if (input.status === "active") {
8121
8587
  conditions.push(
8122
8588
  eq13(preferenceRegistryPreferences.status, "active"),
8123
- or2(
8124
- isNull4(preferenceRegistryRevisions.expiresAt),
8125
- gt3(preferenceRegistryRevisions.expiresAt, now)
8589
+ or4(
8590
+ isNull5(preferenceRegistryRevisions.expiresAt),
8591
+ gt4(preferenceRegistryRevisions.expiresAt, now)
8126
8592
  )
8127
8593
  );
8128
8594
  } else if (input.status === "expired") {
@@ -8162,6 +8628,81 @@ async function listPreferenceRegistry(db, input) {
8162
8628
  return await listPreferenceRegistryScoped(scopedDb, input);
8163
8629
  });
8164
8630
  }
8631
+ async function getCurrentPreferenceRegistryGovernanceMetadata(db, input) {
8632
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
8633
+ const rows = await scopedDb.select({
8634
+ preference: preferenceRegistryPreferences,
8635
+ revision: preferenceRegistryRevisions
8636
+ }).from(preferenceRegistryPreferences).innerJoin(
8637
+ preferenceRegistryRevisions,
8638
+ and13(
8639
+ eq13(
8640
+ preferenceRegistryRevisions.id,
8641
+ preferenceRegistryPreferences.activeRevisionId
8642
+ ),
8643
+ eq13(
8644
+ preferenceRegistryRevisions.accountId,
8645
+ preferenceRegistryPreferences.accountId
8646
+ )
8647
+ )
8648
+ ).where(
8649
+ and13(
8650
+ eq13(preferenceRegistryPreferences.status, "active"),
8651
+ or4(
8652
+ isNull5(preferenceRegistryRevisions.expiresAt),
8653
+ gt4(preferenceRegistryRevisions.expiresAt, sql9`transaction_timestamp()`)
8654
+ )
8655
+ )
8656
+ ).orderBy(
8657
+ sql9`case ${preferenceRegistryPreferences.scope}
8658
+ when 'organization' then 0
8659
+ when 'workspace' then 1
8660
+ when 'user' then 2
8661
+ else 3
8662
+ end`,
8663
+ desc5(preferenceRegistryRevisions.precedenceRank),
8664
+ asc7(preferenceRegistryPreferences.stableKey),
8665
+ asc7(preferenceRegistryPreferences.id)
8666
+ ).limit(PREFERENCE_REGISTRY_DESCRIPTOR_MAX_COUNT + 1);
8667
+ const bounded = boundPreferenceRegistryDescriptors(
8668
+ rows.map(
8669
+ ({ preference, revision }) => PreferenceRegistryDescriptor.parse({
8670
+ id: preference.id,
8671
+ stableKey: preference.stableKey,
8672
+ title: revision.title,
8673
+ description: revision.description,
8674
+ scope: preference.scope,
8675
+ activeVersion: preference.activationVersion,
8676
+ revisionId: revision.id,
8677
+ contentHash: revision.contentHash,
8678
+ precedence: {
8679
+ tier: preference.scope,
8680
+ rank: revision.precedenceRank,
8681
+ conflictStrategy: revision.conflictStrategy,
8682
+ conflictsWith: revision.conflictsWith
8683
+ },
8684
+ provenance: {
8685
+ source: revision.provenanceSource,
8686
+ sourceIdHash: revision.provenanceSourceId ? contentHash2(revision.provenanceSourceId) : null,
8687
+ trust: revision.trust
8688
+ },
8689
+ expiresAt: revision.expiresAt ? iso2(revision.expiresAt) : null,
8690
+ retrievalHandle: `preference://${preference.id}/revisions/${revision.id}?sha256=${revision.contentHash}`
8691
+ })
8692
+ )
8693
+ );
8694
+ return {
8695
+ descriptors: bounded.descriptors.map((descriptor) => ({
8696
+ id: descriptor.id,
8697
+ revisionId: descriptor.revisionId,
8698
+ contentHash: descriptor.contentHash,
8699
+ activeVersion: descriptor.activeVersion,
8700
+ scope: descriptor.scope
8701
+ })),
8702
+ truncated: bounded.truncated
8703
+ };
8704
+ });
8705
+ }
8165
8706
  async function listPreferenceRegistryForAttempt(db, input) {
8166
8707
  return await withPreferenceRegistryAttemptAuthority(db, input, async (scopedDb) => {
8167
8708
  return await listPreferenceRegistryScoped(scopedDb, input);
@@ -8382,9 +8923,9 @@ async function supersedePreferenceRegistry(db, input) {
8382
8923
  and13(
8383
8924
  eq13(preferenceRegistryRevisions.id, replacement.activeRevisionId),
8384
8925
  eq13(preferenceRegistryRevisions.preferenceId, replacement.id),
8385
- or2(
8386
- isNull4(preferenceRegistryRevisions.expiresAt),
8387
- gt3(preferenceRegistryRevisions.expiresAt, sql9`transaction_timestamp()`)
8926
+ or4(
8927
+ isNull5(preferenceRegistryRevisions.expiresAt),
8928
+ gt4(preferenceRegistryRevisions.expiresAt, sql9`transaction_timestamp()`)
8388
8929
  )
8389
8930
  )
8390
8931
  ).limit(1);
@@ -8586,7 +9127,7 @@ async function getOrCreatePreferenceRegistrySnapshot(db, claims) {
8586
9127
  "Preference snapshot authority conflicts with the accepted human attempt"
8587
9128
  );
8588
9129
  }
8589
- return PreferenceRegistrySnapshot.parse({
9130
+ return PreferenceRegistrySnapshot2.parse({
8590
9131
  ...snapshot,
8591
9132
  createdAt: iso2(snapshot.createdAt)
8592
9133
  });
@@ -11970,7 +12511,7 @@ var defaultDeps2 = {
11970
12511
  var inflight2 = /* @__PURE__ */ new Map();
11971
12512
  var REFRESH_WINDOW_MS = 6e4;
11972
12513
  var CONNECTION_REFRESH_TIMEOUT_MS = 1e4;
11973
- function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
12514
+ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2, options = {}) {
11974
12515
  const load = async (input) => {
11975
12516
  const subjectOwned = input.connectionRef.subjectScope === "subject";
11976
12517
  if (subjectOwned && !input.subjectId) {
@@ -12033,6 +12574,7 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
12033
12574
  status: "ok",
12034
12575
  headers,
12035
12576
  connectionId: cred.id,
12577
+ connectionVersion: cred.version,
12036
12578
  expiresAt: cred.expiresAt
12037
12579
  };
12038
12580
  };
@@ -12041,7 +12583,7 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
12041
12583
  if (!key) {
12042
12584
  throw new Error("OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured");
12043
12585
  }
12044
- const refreshed = await deps.refresh(cred, ref, settings);
12586
+ const refreshed = await deps.refresh(cred, ref, settings, options.refreshTransport);
12045
12587
  const refreshRecord = {
12046
12588
  id: cred.id,
12047
12589
  version: cred.version,
@@ -12117,17 +12659,29 @@ function buildConnectionTokenResolver(db, settings, deps = defaultDeps2) {
12117
12659
  cred = await refreshSingleFlight(cred, ref);
12118
12660
  } catch (error) {
12119
12661
  if (isPermanentRefreshError(error)) {
12120
- await deps.setStatus(
12121
- db,
12122
- input.workspaceId,
12123
- "needs_reauth",
12124
- error instanceof Error ? error.message : String(error),
12125
- {
12662
+ let handled = false;
12663
+ if (options.transitionPermanentRefreshFailure) {
12664
+ try {
12665
+ handled = await options.transitionPermanentRefreshFailure({
12666
+ workspaceId: cred.workspaceId,
12667
+ connectionId: cred.id,
12668
+ connectionVersion: cred.version,
12669
+ subjectId: cred.subjectId,
12670
+ providerDomain: cred.providerDomain,
12671
+ httpStatus: error.httpStatus,
12672
+ oauthErrorCode: error.oauthErrorCode
12673
+ });
12674
+ } catch {
12675
+ handled = false;
12676
+ }
12677
+ }
12678
+ if (!handled) {
12679
+ await deps.setStatus(db, input.workspaceId, "needs_reauth", error.message, {
12126
12680
  id: cred.id,
12127
12681
  version: cred.version,
12128
12682
  subjectId: cred.subjectId
12129
- }
12130
- ).catch(() => void 0);
12683
+ }).catch(() => void 0);
12684
+ }
12131
12685
  }
12132
12686
  return authNeeded(ref, "refresh_failed", cred.id);
12133
12687
  }
@@ -12182,10 +12736,12 @@ function canonicalResource(value) {
12182
12736
  }
12183
12737
  var ConnectionRefreshHttpError = class extends Error {
12184
12738
  httpStatus;
12185
- constructor(httpStatus) {
12739
+ oauthErrorCode;
12740
+ constructor(httpStatus, oauthErrorCode = null) {
12186
12741
  super(`connection refresh failed with HTTP ${httpStatus}`);
12187
12742
  this.name = "ConnectionRefreshHttpError";
12188
12743
  this.httpStatus = httpStatus;
12744
+ this.oauthErrorCode = oauthErrorCode;
12189
12745
  }
12190
12746
  };
12191
12747
  function isPermanentRefreshError(error) {
@@ -12317,8 +12873,10 @@ async function refreshOAuthConnectionCredential(cred, ref, settings, transportOp
12317
12873
  throw new ConnectionRefreshHttpError(response.status);
12318
12874
  }
12319
12875
  if (!response.ok) {
12320
- await cancelResponseBody(response);
12321
- throw new ConnectionRefreshHttpError(response.status);
12876
+ throw new ConnectionRefreshHttpError(
12877
+ response.status,
12878
+ await readOAuthRefreshErrorCode(response)
12879
+ );
12322
12880
  }
12323
12881
  const payload = await readResponseJsonBounded(
12324
12882
  response,
@@ -12347,6 +12905,20 @@ async function refreshOAuthConnectionCredential(cred, ref, settings, transportOp
12347
12905
  ...scopeText ? { grantedScopes: scopeText.split(/\s+/).filter(Boolean) } : {}
12348
12906
  };
12349
12907
  }
12908
+ async function readOAuthRefreshErrorCode(response) {
12909
+ try {
12910
+ const payload = await readResponseJsonBounded(
12911
+ response,
12912
+ OAUTH_MAX_RESPONSE_BYTES,
12913
+ "OAuth refresh error response"
12914
+ );
12915
+ const code = stringValue(payload.error);
12916
+ return code && /^[a-z0-9_.-]{1,64}$/i.test(code) ? code : null;
12917
+ } catch {
12918
+ await cancelResponseBody(response);
12919
+ return null;
12920
+ }
12921
+ }
12350
12922
  function expiresAtFromTokenResponse(payload, fallback) {
12351
12923
  const expiresAt = stringValue(payload.expires_at);
12352
12924
  if (expiresAt) {
@@ -12380,7 +12952,7 @@ async function cancelResponseBody(response) {
12380
12952
  }
12381
12953
 
12382
12954
  // src/workspace-artifacts.ts
12383
- import { and as and16, desc as desc7, eq as eq16, lt as lt3, or as or3, sql as sql13 } from "drizzle-orm";
12955
+ import { and as and16, desc as desc7, eq as eq16, lt as lt3, or as or5, sql as sql13 } from "drizzle-orm";
12384
12956
  var WorkspaceArtifactNotFoundError = class extends Error {
12385
12957
  name = "WorkspaceArtifactNotFoundError";
12386
12958
  };
@@ -12475,7 +13047,7 @@ async function listWorkspaceArtifacts(db, workspaceId, options = {}) {
12475
13047
  const cursor = options.cursor ? decodeListCursor(options.cursor) : null;
12476
13048
  const visibility = cursor ? and16(
12477
13049
  eq16(workspaceArtifacts.workspaceId, workspaceId),
12478
- or3(
13050
+ or5(
12479
13051
  lt3(workspaceArtifacts.updatedAt, cursor.updatedAt),
12480
13052
  and16(
12481
13053
  eq16(workspaceArtifacts.updatedAt, cursor.updatedAt),
@@ -13345,6 +13917,29 @@ async function withWorkspaceUsageLock(db, workspaceId, fn) {
13345
13917
  return await fn(scopedDb);
13346
13918
  });
13347
13919
  }
13920
+ async function resolveDocumentIndexAuthority(db, input) {
13921
+ const rows = await rawRows(
13922
+ db,
13923
+ sql14`
13924
+ select authority_kind, authority_workspace_id, authority_subject_id
13925
+ from opengeni_private.resolve_document_index_authority(
13926
+ ${input.accountId},
13927
+ ${input.workspaceId},
13928
+ ${input.documentId}
13929
+ )
13930
+ `
13931
+ );
13932
+ const row = rows[0];
13933
+ if (!row) return null;
13934
+ if (row.authority_kind !== "organization" && row.authority_kind !== "workspace" && row.authority_kind !== "personal") {
13935
+ throw new Error(`Stored document authority kind is invalid: ${row.authority_kind}`);
13936
+ }
13937
+ return {
13938
+ authorityKind: row.authority_kind,
13939
+ authorityWorkspaceId: row.authority_workspace_id,
13940
+ authoritySubjectId: row.authority_subject_id
13941
+ };
13942
+ }
13348
13943
  async function withAccountRls(db, accountId, fn) {
13349
13944
  return await withRlsContext(db, { accountId, workspaceId: null }, fn);
13350
13945
  }
@@ -13967,7 +14562,7 @@ async function upsertGitHubInstallation(db, input) {
13967
14562
  },
13968
14563
  // This legacy metadata helper cannot mutate an owner-authorized row.
13969
14564
  // New bindings use bindAuthorizedGitHubInstallationRepositories.
13970
- setWhere: isNull5(githubInstallations.authorityNonce)
14565
+ setWhere: isNull6(githubInstallations.authorityNonce)
13971
14566
  }).returning();
13972
14567
  if (!row) {
13973
14568
  throw new Error("Failed to upsert GitHub installation");
@@ -14010,7 +14605,7 @@ async function bindGitHubInstallationRepositories(db, input) {
14010
14605
  updatedAt: /* @__PURE__ */ new Date()
14011
14606
  },
14012
14607
  // Preserve the immutable authority + allowlist audit boundary.
14013
- setWhere: isNull5(githubInstallations.authorityNonce)
14608
+ setWhere: isNull6(githubInstallations.authorityNonce)
14014
14609
  }).returning();
14015
14610
  if (!row) {
14016
14611
  throw new Error("Failed to bind GitHub installation");
@@ -14463,7 +15058,7 @@ async function sumUsageQuantity(db, input) {
14463
15058
  eq17(usageEvents.eventType, input.eventType),
14464
15059
  ...input.accountId ? [eq17(usageEvents.accountId, input.accountId)] : [],
14465
15060
  ...input.workspaceId ? [eq17(usageEvents.workspaceId, input.workspaceId)] : [],
14466
- ...input.since ? [gt4(usageEvents.occurredAt, input.since)] : []
15061
+ ...input.since ? [gt5(usageEvents.occurredAt, input.since)] : []
14467
15062
  ];
14468
15063
  const [{ total } = { total: 0 }] = await scopedDb.select({
14469
15064
  total: sql14`coalesce(sum(${usageEvents.quantity}), 0)`
@@ -14619,6 +15214,20 @@ async function countScheduledTasksForWorkspace(db, workspaceId) {
14619
15214
  return Number(count);
14620
15215
  });
14621
15216
  }
15217
+ var ConnectionDisconnectIdempotencyError = class extends Error {
15218
+ code = "IDEMPOTENCY_KEY_REUSED";
15219
+ constructor() {
15220
+ super("The disconnect idempotency key was already used with different input");
15221
+ this.name = "ConnectionDisconnectIdempotencyError";
15222
+ }
15223
+ };
15224
+ var ConnectionDisconnectGenerationError = class extends Error {
15225
+ code = "CONNECTION_GENERATION_CHANGED";
15226
+ constructor() {
15227
+ super("The disconnect operation belongs to an older connection generation");
15228
+ this.name = "ConnectionDisconnectGenerationError";
15229
+ }
15230
+ };
14622
15231
  async function createFileUpload(db, input) {
14623
15232
  return await withRlsContext(
14624
15233
  db,
@@ -14674,6 +15283,25 @@ async function requireFile(db, workspaceId, fileId) {
14674
15283
  }
14675
15284
  return file;
14676
15285
  }
15286
+ async function getFiles(db, workspaceId, fileIds) {
15287
+ const ids = [...new Set(fileIds)];
15288
+ if (ids.length === 0) return [];
15289
+ return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
15290
+ const rows = await scopedDb.select().from(files).where(and17(eq17(files.workspaceId, workspaceId), inArray11(files.id, ids)));
15291
+ return rows.map(mapFile);
15292
+ });
15293
+ }
15294
+ function durableUserHistoryItem(prompt, resources) {
15295
+ const attachmentRefs = resources.filter(
15296
+ (resource) => resource.kind === "file"
15297
+ );
15298
+ return sanitizeModelPayload({
15299
+ type: "message",
15300
+ role: "user",
15301
+ content: prompt,
15302
+ ...attachmentRefs.length > 0 ? { [MODEL_ATTACHMENT_REFS_FIELD]: attachmentRefs } : {}
15303
+ });
15304
+ }
14677
15305
  async function getRetainedFileArtifact(db, workspaceId, fileId) {
14678
15306
  return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
14679
15307
  const [row] = await scopedDb.select({
@@ -15251,11 +15879,11 @@ async function upsertCapabilityCatalogItem(db, input) {
15251
15879
  async function listCapabilityCatalogItems(db, workspaceId) {
15252
15880
  return await withWorkspaceRls(db, workspaceId, async (scopedDb) => {
15253
15881
  const rows = await scopedDb.select().from(capabilityCatalogItems).where(
15254
- or4(
15882
+ or6(
15255
15883
  eq17(capabilityCatalogItems.workspaceId, workspaceId),
15256
15884
  and17(
15257
- isNull5(capabilityCatalogItems.workspaceId),
15258
- or4(
15885
+ isNull6(capabilityCatalogItems.workspaceId),
15886
+ or6(
15259
15887
  ne(capabilityCatalogItems.source, registryCapabilitySource),
15260
15888
  eq17(capabilityCatalogItems.stale, false)
15261
15889
  )
@@ -15277,9 +15905,9 @@ async function getCapabilityCatalogItem(db, workspaceId, capabilityId) {
15277
15905
  const [row] = await scopedDb.select().from(capabilityCatalogItems).where(
15278
15906
  and17(
15279
15907
  eq17(capabilityCatalogItems.id, capabilityId),
15280
- or4(
15908
+ or6(
15281
15909
  eq17(capabilityCatalogItems.workspaceId, workspaceId),
15282
- isNull5(capabilityCatalogItems.workspaceId)
15910
+ isNull6(capabilityCatalogItems.workspaceId)
15283
15911
  )
15284
15912
  )
15285
15913
  ).orderBy(asc8(sql14`(${capabilityCatalogItems.workspaceId} is null)`)).limit(1);
@@ -15387,12 +16015,12 @@ async function listEnabledMcpCapabilityServers(db, workspaceId) {
15387
16015
  }).from(capabilityInstallations).innerJoin(
15388
16016
  capabilityCatalogItems,
15389
16017
  and17(
15390
- or4(
16018
+ or6(
15391
16019
  eq17(
15392
16020
  capabilityInstallations.workspaceId,
15393
16021
  capabilityCatalogItems.workspaceId
15394
16022
  ),
15395
- isNull5(capabilityCatalogItems.workspaceId)
16023
+ isNull6(capabilityCatalogItems.workspaceId)
15396
16024
  ),
15397
16025
  eq17(capabilityInstallations.capabilityId, capabilityCatalogItems.id)
15398
16026
  )
@@ -15501,10 +16129,10 @@ var connectionMetadataColumns = {
15501
16129
  updatedAt: connections.updatedAt
15502
16130
  };
15503
16131
  function connectionSubjectVisibility(subjectId) {
15504
- return subjectId ? or4(isNull5(connections.subjectId), eq17(connections.subjectId, subjectId)) : isNull5(connections.subjectId);
16132
+ return subjectId ? or6(isNull6(connections.subjectId), eq17(connections.subjectId, subjectId)) : isNull6(connections.subjectId);
15505
16133
  }
15506
16134
  function connectionExactSubject(subjectId) {
15507
- return subjectId ? eq17(connections.subjectId, subjectId) : isNull5(connections.subjectId);
16135
+ return subjectId ? eq17(connections.subjectId, subjectId) : isNull6(connections.subjectId);
15508
16136
  }
15509
16137
  function personalSlackCanonicalConnectionOrder() {
15510
16138
  return [
@@ -15617,6 +16245,124 @@ async function updateConnection(db, input) {
15617
16245
  async (scopedDb) => await updateConnectionInScope(scopedDb, input)
15618
16246
  );
15619
16247
  }
16248
+ async function transitionConnectionStateInScope(db, input) {
16249
+ const [row] = await db.update(connections).set({
16250
+ ...input.status !== void 0 ? { status: input.status } : {},
16251
+ metadata: input.metadata,
16252
+ ...input.lastError !== void 0 ? { lastError: input.lastError } : {},
16253
+ version: sql14`${connections.version} + 1`,
16254
+ ...input.updatedBySubjectId !== void 0 ? { updatedBySubjectId: input.updatedBySubjectId } : {},
16255
+ updatedAt: /* @__PURE__ */ new Date()
16256
+ }).where(
16257
+ and17(
16258
+ eq17(connections.workspaceId, input.workspaceId),
16259
+ eq17(connections.id, input.connectionId),
16260
+ connectionSubjectVisibility(input.visibleToSubjectId),
16261
+ eq17(connections.version, input.expectedVersion)
16262
+ )
16263
+ ).returning(connectionMetadataColumns);
16264
+ return row ? mapConnectionMetadata(row) : null;
16265
+ }
16266
+ async function transitionConnectionState(db, input) {
16267
+ return await withConnectionSubjectRls(
16268
+ db,
16269
+ input.workspaceId,
16270
+ input.visibleToSubjectId,
16271
+ async (scopedDb) => await transitionConnectionStateInScope(scopedDb, input)
16272
+ );
16273
+ }
16274
+ var connectionDisconnectOperationColumns = {
16275
+ accountId: connectionDisconnectOperations.accountId,
16276
+ workspaceId: connectionDisconnectOperations.workspaceId,
16277
+ connectionId: connectionDisconnectOperations.connectionId,
16278
+ subjectId: connectionDisconnectOperations.subjectId,
16279
+ idempotencyKey: connectionDisconnectOperations.idempotencyKey,
16280
+ expectedVersion: connectionDisconnectOperations.expectedVersion,
16281
+ resultVersion: connectionDisconnectOperations.resultVersion
16282
+ };
16283
+ async function disconnectConnectionIdempotently(db, input) {
16284
+ return await withConnectionSubjectRls(
16285
+ db,
16286
+ input.workspaceId,
16287
+ input.subjectId,
16288
+ async (scopedDb) => {
16289
+ const [connectionRow] = await scopedDb.select(connectionMetadataColumns).from(connections).where(
16290
+ and17(
16291
+ eq17(connections.accountId, input.accountId),
16292
+ eq17(connections.workspaceId, input.workspaceId),
16293
+ eq17(connections.id, input.connectionId),
16294
+ eq17(connections.subjectId, input.subjectId)
16295
+ )
16296
+ ).for("update");
16297
+ if (!connectionRow) return null;
16298
+ const connection = mapConnectionMetadata(connectionRow);
16299
+ const [replayed] = await scopedDb.select(connectionDisconnectOperationColumns).from(connectionDisconnectOperations).where(
16300
+ and17(
16301
+ eq17(connectionDisconnectOperations.workspaceId, input.workspaceId),
16302
+ eq17(connectionDisconnectOperations.subjectId, input.subjectId),
16303
+ eq17(connectionDisconnectOperations.idempotencyKey, input.idempotencyKey)
16304
+ )
16305
+ ).limit(1);
16306
+ if (replayed) {
16307
+ if (replayed.accountId !== input.accountId || replayed.connectionId !== input.connectionId || replayed.expectedVersion !== input.expectedVersion) {
16308
+ throw new ConnectionDisconnectIdempotencyError();
16309
+ }
16310
+ if (connection.version !== replayed.resultVersion) {
16311
+ throw new ConnectionDisconnectGenerationError();
16312
+ }
16313
+ return connection;
16314
+ }
16315
+ if (connection.version !== input.expectedVersion) {
16316
+ throw new ConnectionDisconnectGenerationError();
16317
+ }
16318
+ const [inserted] = await scopedDb.insert(connectionDisconnectOperations).values({
16319
+ accountId: input.accountId,
16320
+ workspaceId: input.workspaceId,
16321
+ connectionId: input.connectionId,
16322
+ subjectId: input.subjectId,
16323
+ idempotencyKey: input.idempotencyKey,
16324
+ expectedVersion: input.expectedVersion,
16325
+ resultVersion: input.expectedVersion + 1
16326
+ }).onConflictDoNothing().returning(connectionDisconnectOperationColumns);
16327
+ if (!inserted) {
16328
+ const [conflictingKey] = await scopedDb.select(connectionDisconnectOperationColumns).from(connectionDisconnectOperations).where(
16329
+ and17(
16330
+ eq17(connectionDisconnectOperations.workspaceId, input.workspaceId),
16331
+ eq17(connectionDisconnectOperations.subjectId, input.subjectId),
16332
+ eq17(connectionDisconnectOperations.idempotencyKey, input.idempotencyKey)
16333
+ )
16334
+ ).limit(1);
16335
+ if (!conflictingKey || conflictingKey.accountId !== input.accountId || conflictingKey.connectionId !== input.connectionId || conflictingKey.expectedVersion !== input.expectedVersion) {
16336
+ throw new ConnectionDisconnectIdempotencyError();
16337
+ }
16338
+ if (connection.version !== conflictingKey.resultVersion) {
16339
+ throw new ConnectionDisconnectGenerationError();
16340
+ }
16341
+ return connection;
16342
+ }
16343
+ const [updated] = await scopedDb.update(connections).set({
16344
+ status: "revoked",
16345
+ metadata: input.metadata,
16346
+ ...input.lastError !== void 0 ? { lastError: input.lastError } : {},
16347
+ version: sql14`${connections.version} + 1`,
16348
+ ...input.updatedBySubjectId !== void 0 ? { updatedBySubjectId: input.updatedBySubjectId } : {},
16349
+ updatedAt: /* @__PURE__ */ new Date()
16350
+ }).where(
16351
+ and17(
16352
+ eq17(connections.accountId, input.accountId),
16353
+ eq17(connections.workspaceId, input.workspaceId),
16354
+ eq17(connections.id, input.connectionId),
16355
+ eq17(connections.subjectId, input.subjectId),
16356
+ eq17(connections.version, input.expectedVersion)
16357
+ )
16358
+ ).returning(connectionMetadataColumns);
16359
+ if (!updated) {
16360
+ throw new ConnectionDisconnectGenerationError();
16361
+ }
16362
+ return mapConnectionMetadata(updated);
16363
+ }
16364
+ );
16365
+ }
15620
16366
  async function revokeConnectionInScope(db, workspaceId, connectionId, updatedBySubjectId, expectedVersion) {
15621
16367
  const [row] = await db.update(connections).set({
15622
16368
  status: "revoked",
@@ -15645,12 +16391,18 @@ async function revokeConnectionInScope(db, workspaceId, connectionId, updatedByS
15645
16391
  ).returning(connectionMetadataColumns);
15646
16392
  return row ? mapConnectionMetadata(row) : null;
15647
16393
  }
15648
- async function revokeConnection(db, workspaceId, connectionId, updatedBySubjectId) {
16394
+ async function revokeConnection(db, workspaceId, connectionId, updatedBySubjectId, expectedVersion) {
15649
16395
  return await withConnectionSubjectRls(
15650
16396
  db,
15651
16397
  workspaceId,
15652
16398
  updatedBySubjectId,
15653
- async (scopedDb) => await revokeConnectionInScope(scopedDb, workspaceId, connectionId, updatedBySubjectId)
16399
+ async (scopedDb) => await revokeConnectionInScope(
16400
+ scopedDb,
16401
+ workspaceId,
16402
+ connectionId,
16403
+ updatedBySubjectId,
16404
+ expectedVersion
16405
+ )
15654
16406
  );
15655
16407
  }
15656
16408
  async function resolveSlackInstallationRoute(db, slackTeamId) {
@@ -15715,7 +16467,7 @@ async function enqueueSlackInteractionInbox(db, input) {
15715
16467
  const [existing] = await scopedDb.select().from(slackInteractionInbox).where(
15716
16468
  and17(
15717
16469
  eq17(slackInteractionInbox.connectionId, input.connectionId),
15718
- or4(
16470
+ or6(
15719
16471
  eq17(slackInteractionInbox.providerEventId, input.providerEventId),
15720
16472
  eq17(slackInteractionInbox.providerMessageId, input.providerMessageId)
15721
16473
  )
@@ -15929,7 +16681,7 @@ async function bindSlackInteractionSession(db, input) {
15929
16681
  eq17(slackInteractions.id, input.id),
15930
16682
  eq17(slackInteractions.owningSubjectId, input.owningSubjectId),
15931
16683
  eq17(slackInteractions.sessionReservationId, input.sessionId),
15932
- isNull5(slackInteractions.sessionId)
16684
+ isNull6(slackInteractions.sessionId)
15933
16685
  )
15934
16686
  ).returning();
15935
16687
  if (row) return mapSlackInteraction(row);
@@ -16431,8 +17183,8 @@ async function claimSlackBotPostOperation(db, input) {
16431
17183
  }).where(
16432
17184
  and17(
16433
17185
  eq17(slackBotPostOperations.id, existing.id),
16434
- or4(
16435
- isNull5(slackBotPostOperations.claimHolderId),
17186
+ or6(
17187
+ isNull6(slackBotPostOperations.claimHolderId),
16436
17188
  lte2(slackBotPostOperations.claimExpiresAt, sql14`now()`)
16437
17189
  )
16438
17190
  )
@@ -16628,7 +17380,7 @@ async function markSlackBotDeleteOperationProviderStarted(db, input) {
16628
17380
  eq17(slackBotDeleteOperations.connectionId, input.connectionId),
16629
17381
  eq17(slackBotDeleteOperations.operationId, input.operationId),
16630
17382
  eq17(slackBotDeleteOperations.claimHolderId, input.claimHolderId),
16631
- or4(
17383
+ or6(
16632
17384
  eq17(slackBotDeleteOperations.status, "pending"),
16633
17385
  eq17(slackBotDeleteOperations.status, "outcome_unknown")
16634
17386
  )
@@ -16736,7 +17488,7 @@ async function loadConnectionCredentialForBroker(db, settings, input) {
16736
17488
  "connection credential present but OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is not configured"
16737
17489
  );
16738
17490
  }
16739
- const subjectPredicate = input.allowSubjectOwned ? connectionExactSubject(input.subjectId) : isNull5(connections.subjectId);
17491
+ const subjectPredicate = input.allowSubjectOwned ? connectionExactSubject(input.subjectId) : isNull6(connections.subjectId);
16740
17492
  const conditions = [
16741
17493
  eq17(connections.workspaceId, input.workspaceId),
16742
17494
  subjectPredicate
@@ -20219,7 +20971,7 @@ async function withCodexCapacityMutation(db, input, mutate) {
20219
20971
  eq17(codexCapacityWaiters.workspaceId, input.workspaceId),
20220
20972
  eq17(codexCapacityWaiters.status, "waiting"),
20221
20973
  ...input.policyHash !== void 0 ? [
20222
- input.policyHash === null ? isNull5(codexCapacityWaiters.policyHash) : eq17(codexCapacityWaiters.policyHash, input.policyHash)
20974
+ input.policyHash === null ? isNull6(codexCapacityWaiters.policyHash) : eq17(codexCapacityWaiters.policyHash, input.policyHash)
20223
20975
  ] : []
20224
20976
  )
20225
20977
  ).returning();
@@ -20312,7 +21064,7 @@ async function supersedeCodexCapacityWaitInTransaction(tx, input) {
20312
21064
  eq17(sessionTurns.workspaceId, input.session.workspaceId),
20313
21065
  eq17(sessionTurns.id, input.blockedTurn.id),
20314
21066
  eq17(sessionTurns.status, "waiting_capacity"),
20315
- isNull5(sessionTurns.activeAttemptId),
21067
+ isNull6(sessionTurns.activeAttemptId),
20316
21068
  eq17(sessionTurns.executionGeneration, input.waiter.blockedTurnGeneration)
20317
21069
  )
20318
21070
  ).returning({ id: sessionTurns.id });
@@ -20590,7 +21342,7 @@ async function reconcileCodexCapacityWait(db, input, decide, policy) {
20590
21342
  eq17(sessionTurns.workspaceId, input.workspaceId),
20591
21343
  eq17(sessionTurns.id, blockedTurn.id),
20592
21344
  eq17(sessionTurns.status, "waiting_capacity"),
20593
- isNull5(sessionTurns.activeAttemptId),
21345
+ isNull6(sessionTurns.activeAttemptId),
20594
21346
  eq17(sessionTurns.executionGeneration, waiter.blockedTurnGeneration)
20595
21347
  )
20596
21348
  ).returning({ id: sessionTurns.id });
@@ -21411,7 +22163,7 @@ async function setInitialActiveCodexCredential(db, workspaceId, credentialId) {
21411
22163
  const rows = await scopedDb.update(codexRotationSettings).set({ activeCredentialId: credentialId, updatedAt: /* @__PURE__ */ new Date() }).where(
21412
22164
  and17(
21413
22165
  eq17(codexRotationSettings.workspaceId, workspaceId),
21414
- isNull5(codexRotationSettings.activeCredentialId)
22166
+ isNull6(codexRotationSettings.activeCredentialId)
21415
22167
  )
21416
22168
  ).returning({ id: codexRotationSettings.id });
21417
22169
  return rows.length > 0;
@@ -21560,8 +22312,8 @@ async function setSessionCodexPin(db, workspaceId, sessionId, pinnedCredentialId
21560
22312
  ];
21561
22313
  if (options.expected) {
21562
22314
  conditions.push(
21563
- options.expected.pinnedCredentialId === null ? isNull5(sessions.codexPinnedCredentialId) : eq17(sessions.codexPinnedCredentialId, options.expected.pinnedCredentialId),
21564
- options.expected.pinSource === null ? isNull5(sessions.codexPinSource) : eq17(sessions.codexPinSource, options.expected.pinSource)
22315
+ options.expected.pinnedCredentialId === null ? isNull6(sessions.codexPinnedCredentialId) : eq17(sessions.codexPinnedCredentialId, options.expected.pinnedCredentialId),
22316
+ options.expected.pinSource === null ? isNull6(sessions.codexPinSource) : eq17(sessions.codexPinSource, options.expected.pinSource)
21565
22317
  );
21566
22318
  }
21567
22319
  const updated = await scopedDb.update(sessions).set({
@@ -22911,7 +23663,7 @@ async function listSessionSpawnDenials(db, workspaceId, options = {}) {
22911
23663
  const rows = await scopedDb.select().from(sessionSpawnDenials).where(
22912
23664
  and17(
22913
23665
  eq17(sessionSpawnDenials.workspaceId, workspaceId),
22914
- options.parentSessionId === void 0 ? void 0 : options.parentSessionId === null ? isNull5(sessionSpawnDenials.parentSessionId) : eq17(sessionSpawnDenials.parentSessionId, options.parentSessionId)
23666
+ options.parentSessionId === void 0 ? void 0 : options.parentSessionId === null ? isNull6(sessionSpawnDenials.parentSessionId) : eq17(sessionSpawnDenials.parentSessionId, options.parentSessionId)
22915
23667
  )
22916
23668
  ).orderBy(desc8(sessionSpawnDenials.createdAt), desc8(sessionSpawnDenials.id)).limit(Math.max(1, Math.min(options.limit ?? 100, 1e3)));
22917
23669
  return rows.map(mapSessionSpawnDenial);
@@ -23229,7 +23981,7 @@ function sessionFilters(options) {
23229
23981
  if (Object.prototype.hasOwnProperty.call(options, "parentSessionId")) {
23230
23982
  const parentSessionId = options.parentSessionId;
23231
23983
  if (parentSessionId === null) {
23232
- filters.push(isNull5(sessions.parentSessionId));
23984
+ filters.push(isNull6(sessions.parentSessionId));
23233
23985
  } else if (parentSessionId !== void 0) {
23234
23986
  filters.push(eq17(sessions.parentSessionId, parentSessionId));
23235
23987
  }
@@ -23238,7 +23990,7 @@ function sessionFilters(options) {
23238
23990
  if (search) {
23239
23991
  const pattern = `%${search.replaceAll("\\", "\\\\").replaceAll("%", "\\%").replaceAll("_", "\\_")}%`;
23240
23992
  filters.push(
23241
- or4(ilike(sessions.title, pattern), ilike(sessions.initialMessage, pattern))
23993
+ or6(ilike(sessions.title, pattern), ilike(sessions.initialMessage, pattern))
23242
23994
  );
23243
23995
  }
23244
23996
  return filters;
@@ -23271,7 +24023,7 @@ function sessionAuthorizationScopeFilter(scope) {
23271
24023
  )
23272
24024
  select id from authorized_sessions
23273
24025
  )` : sql14`false`;
23274
- return or4(exact, descendants);
24026
+ return or6(exact, descendants);
23275
24027
  }
23276
24028
  async function sessionIdsCoveredByAuthorizationRoots(db, workspaceId, sessionIds, scope) {
23277
24029
  if (sessionIds.length === 0) return /* @__PURE__ */ new Set();
@@ -23453,7 +24205,7 @@ async function listSessionsForSubject(db, workspaceId, options) {
23453
24205
  ).where(
23454
24206
  and17(
23455
24207
  ...filters,
23456
- or4(isNull5(sessionPins.id), eq17(sessionPins.pinned, false))
24208
+ or6(isNull6(sessionPins.id), eq17(sessionPins.pinned, false))
23457
24209
  )
23458
24210
  ).orderBy(desc8(sessions.updatedAt), desc8(sessions.id)).limit(limit);
23459
24211
  pageIds = ordinaryIdRows.map((row) => row.id);
@@ -23466,14 +24218,14 @@ async function listSessionsForSubject(db, workspaceId, options) {
23466
24218
  lte2(sessionListSnapshots.expiresAt, now)
23467
24219
  )
23468
24220
  );
23469
- const snapshotSearchFilter = searchFilter ? eq17(sessionListSnapshots.search, searchFilter) : isNull5(sessionListSnapshots.search);
24221
+ const snapshotSearchFilter = searchFilter ? eq17(sessionListSnapshots.search, searchFilter) : isNull6(sessionListSnapshots.search);
23470
24222
  const [reusableSnapshot] = await tx.select().from(sessionListSnapshots).where(
23471
24223
  and17(
23472
24224
  eq17(sessionListSnapshots.workspaceId, workspaceId),
23473
24225
  eq17(sessionListSnapshots.subjectId, options.subjectId),
23474
24226
  eq17(sessionListSnapshots.parentSessionFilter, parentFilter),
23475
24227
  snapshotSearchFilter,
23476
- gt4(
24228
+ gt5(
23477
24229
  sessionListSnapshots.createdAt,
23478
24230
  new Date(now.getTime() - SESSION_LIST_SNAPSHOT_REUSE_MS)
23479
24231
  )
@@ -23494,7 +24246,7 @@ async function listSessionsForSubject(db, workspaceId, options) {
23494
24246
  ).where(
23495
24247
  and17(
23496
24248
  ...filters,
23497
- or4(isNull5(sessionPins.id), eq17(sessionPins.pinned, false))
24249
+ or6(isNull6(sessionPins.id), eq17(sessionPins.pinned, false))
23498
24250
  )
23499
24251
  ).orderBy(desc8(sessions.updatedAt), desc8(sessions.id)).limit(SESSION_LIST_SNAPSHOT_MAX_IDS + 1);
23500
24252
  if (ordinaryIdRows.length > SESSION_LIST_SNAPSHOT_MAX_IDS) {
@@ -23568,7 +24320,7 @@ async function listSessionsForSubject(db, workspaceId, options) {
23568
24320
  eq17(sessions.workspaceId, workspaceId),
23569
24321
  inArray11(sessions.id, pageIds),
23570
24322
  ...options.authorizationScope ? [sessionAuthorizationScopeFilter(options.authorizationScope)] : [],
23571
- or4(isNull5(sessionPins.id), eq17(sessionPins.pinned, false))
24323
+ or6(isNull6(sessionPins.id), eq17(sessionPins.pinned, false))
23572
24324
  )
23573
24325
  );
23574
24326
  const ordinaryById = new Map(ordinaryRows.map((row) => [row.session.id, row]));
@@ -23758,7 +24510,7 @@ async function listSessions(db, workspaceId, limitOrOptions = 50) {
23758
24510
  if (Object.prototype.hasOwnProperty.call(options, "parentSessionId")) {
23759
24511
  const parentSessionId = options.parentSessionId;
23760
24512
  if (parentSessionId === null) {
23761
- filters.push(isNull5(sessions.parentSessionId));
24513
+ filters.push(isNull6(sessions.parentSessionId));
23762
24514
  } else if (parentSessionId !== void 0) {
23763
24515
  filters.push(eq17(sessions.parentSessionId, parentSessionId));
23764
24516
  }
@@ -23899,11 +24651,11 @@ async function listSessionDiscoverySummaries(db, workspaceId, options) {
23899
24651
  if (orderBy === "createdAt" && options.cursor && (cursorSortRevision !== "0" || options.cursor.snapshotRevision !== "0")) {
23900
24652
  throw new Error("sessions_list created-order cursor cannot carry activity revisions");
23901
24653
  }
23902
- const cursorPredicate = options.cursor ? orderBy === "updatedAt" ? or4(
24654
+ const cursorPredicate = options.cursor ? orderBy === "updatedAt" ? or6(
23903
24655
  sql14`${sessions.activityRevision} < ${cursorSortRevision}::text::bigint`,
23904
24656
  and17(
23905
24657
  sql14`${sessions.activityRevision} = ${cursorSortRevision}::text::bigint`,
23906
- or4(
24658
+ or6(
23907
24659
  sql14`${sessions.updatedAt} < ${options.cursor.sortAt}::text::timestamptz`,
23908
24660
  and17(
23909
24661
  sql14`${sessions.updatedAt} = ${options.cursor.sortAt}::text::timestamptz`,
@@ -23911,7 +24663,7 @@ async function listSessionDiscoverySummaries(db, workspaceId, options) {
23911
24663
  )
23912
24664
  )
23913
24665
  )
23914
- ) : or4(
24666
+ ) : or6(
23915
24667
  // Cast through text deliberately. postgres.js otherwise infers a
23916
24668
  // timestamptz parameter and serializes this exact cursor string via
23917
24669
  // JS Date, which discards PostgreSQL's sub-millisecond precision.
@@ -24282,16 +25034,16 @@ async function listSessionEventPage(db, workspaceId, sessionId, options = {}) {
24282
25034
  const filters = [
24283
25035
  eq17(sessionEvents.workspaceId, workspaceId),
24284
25036
  eq17(sessionEvents.sessionId, sessionId),
24285
- gt4(sessionEvents.sequence, after)
25037
+ gt5(sessionEvents.sequence, after)
24286
25038
  ];
24287
25039
  if (options.authoritativeLatest) {
24288
25040
  filters.push(
24289
25041
  and17(
24290
- or4(
24291
- isNull5(sessionEvents.turnAssociation),
25042
+ or6(
25043
+ isNull6(sessionEvents.turnAssociation),
24292
25044
  eq17(sessionEvents.turnAssociation, "current")
24293
25045
  ),
24294
- isNull5(sessionEvents.duplicateOfEventId)
25046
+ isNull6(sessionEvents.duplicateOfEventId)
24295
25047
  )
24296
25048
  );
24297
25049
  }
@@ -24306,7 +25058,7 @@ async function listSessionEventPage(db, workspaceId, sessionId, options = {}) {
24306
25058
  filters.push(lt4(sessionEvents.sequence, cursor));
24307
25059
  }
24308
25060
  } else if (cursor !== void 0) {
24309
- filters.push(gt4(sessionEvents.sequence, cursor));
25061
+ filters.push(gt5(sessionEvents.sequence, cursor));
24310
25062
  }
24311
25063
  if (direction === "after" && before !== void 0 && before <= POSTGRES_INT_MAX) {
24312
25064
  filters.push(lt4(sessionEvents.sequence, before));
@@ -24489,7 +25241,7 @@ async function listSessionEvents(db, workspaceId, sessionId, afterOrOptions = 0,
24489
25241
  const filters = [
24490
25242
  eq17(sessionEvents.workspaceId, workspaceId),
24491
25243
  eq17(sessionEvents.sessionId, sessionId),
24492
- gt4(sessionEvents.sequence, after)
25244
+ gt5(sessionEvents.sequence, after)
24493
25245
  ];
24494
25246
  if (typeFilters.includeTypes.length > 0) {
24495
25247
  filters.push(inArray11(sessionEvents.type, typeFilters.includeTypes));
@@ -24623,7 +25375,7 @@ async function listWorkspaceControlEvents(db, workspaceId, after = 0, limit = 50
24623
25375
  const rows = await scopedDb.select().from(workspaceControlEvents).where(
24624
25376
  and17(
24625
25377
  eq17(workspaceControlEvents.workspaceId, workspaceId),
24626
- gt4(workspaceControlEvents.revision, cursor)
25378
+ gt5(workspaceControlEvents.revision, cursor)
24627
25379
  )
24628
25380
  ).orderBy(asc8(workspaceControlEvents.revision)).limit(boundedLimit);
24629
25381
  return rows.map(mapWorkspaceControlEvent);
@@ -24769,21 +25521,6 @@ function validateAnsweredHumanInput(questions, answers) {
24769
25521
  `Text question ${question.id} accepts one value`
24770
25522
  );
24771
25523
  }
24772
- const value = values[0] ?? "";
24773
- const minLength = question.validation?.minLength;
24774
- const maxLength = question.validation?.maxLength;
24775
- if (minLength != null && value.length < minLength) {
24776
- throw new HumanInputResponseValidationError(
24777
- "INVALID_RESPONSE",
24778
- `Question ${question.id} is shorter than its minimum length`
24779
- );
24780
- }
24781
- if (maxLength != null && value.length > maxLength) {
24782
- throw new HumanInputResponseValidationError(
24783
- "INVALID_RESPONSE",
24784
- `Question ${question.id} exceeds its maximum length`
24785
- );
24786
- }
24787
25524
  continue;
24788
25525
  }
24789
25526
  if (other && !question.allowOther) {
@@ -24856,7 +25593,7 @@ async function hasAcceptedRequiresActionAdvance(tx, input) {
24856
25593
  eq17(sessionEvents.turnId, input.turnId),
24857
25594
  eq17(sessionEvents.turnGeneration, input.turnGeneration),
24858
25595
  inArray11(sessionEvents.type, ["user.approvalDecision", "user.humanInputResponse"]),
24859
- gt4(sessionEvents.sequence, trigger.sequence)
25596
+ gt5(sessionEvents.sequence, trigger.sequence)
24860
25597
  )
24861
25598
  ).limit(1);
24862
25599
  return accepted !== void 0;
@@ -24994,6 +25731,26 @@ async function acceptSessionHumanInputResponse(db, input) {
24994
25731
  occurredAt: now
24995
25732
  }).returning();
24996
25733
  if (!event) throw new Error("Failed to append human-input response");
25734
+ await mirrorSessionRealtimeContextInTransaction(tx, {
25735
+ accountId: session.accountId,
25736
+ workspaceId: input.workspaceId,
25737
+ sessionId: input.sessionId,
25738
+ sourceKind: "human_input_response",
25739
+ sourceId: event.id,
25740
+ turnId: turn.id,
25741
+ channel: response.outcome === "answered" || response.outcome === "skipped" ? "speakable" : null,
25742
+ text: renderRealtimeHumanInputResponseContext({
25743
+ requestId: request.id,
25744
+ questions: request.questions,
25745
+ response
25746
+ }),
25747
+ payload: {
25748
+ requestId: request.id,
25749
+ outcome: response.outcome,
25750
+ sourceEventId: event.id
25751
+ },
25752
+ now
25753
+ });
24997
25754
  await tx.update(sessions).set({ lastSequence: session.lastSequence + 1, updatedAt: now }).where(eq17(sessions.id, session.id));
24998
25755
  const workflowWakeRevision = await enqueueSessionWorkflowWakeInTransaction(
24999
25756
  tx,
@@ -26054,7 +26811,7 @@ function exactPtyIdentityPredicates(identity) {
26054
26811
  eq17(sandboxPtySessions.providerBackend, identity.providerBackend),
26055
26812
  eq17(sandboxPtySessions.providerInstanceId, identity.providerInstanceId),
26056
26813
  eq17(sandboxPtySessions.routeKind, identity.routeKind),
26057
- identity.routeTargetId === null ? isNull5(sandboxPtySessions.routeTargetId) : eq17(sandboxPtySessions.routeTargetId, identity.routeTargetId),
26814
+ identity.routeTargetId === null ? isNull6(sandboxPtySessions.routeTargetId) : eq17(sandboxPtySessions.routeTargetId, identity.routeTargetId),
26058
26815
  eq17(sandboxPtySessions.routeEpoch, identity.routeEpoch)
26059
26816
  ];
26060
26817
  }
@@ -28079,7 +28836,7 @@ async function settleExactLostProviderWorkspaceBlockersTx(tx, input) {
28079
28836
  eq17(sandboxWorkspaceMutationAdmissions.sandboxGroupId, input.sandboxGroupId),
28080
28837
  eq17(sandboxWorkspaceMutationAdmissions.leaseEpoch, input.lostEpoch),
28081
28838
  eq17(sandboxWorkspaceMutationAdmissions.providerInstanceId, input.lostInstanceId),
28082
- isNull5(sandboxWorkspaceMutationAdmissions.settledAt)
28839
+ isNull6(sandboxWorkspaceMutationAdmissions.settledAt)
28083
28840
  )
28084
28841
  ).returning({ id: sandboxWorkspaceMutationAdmissions.id });
28085
28842
  const closedPtys = await tx.update(sandboxPtySessions).set({ status: "closed", closedAt: /* @__PURE__ */ new Date() }).where(
@@ -29711,8 +30468,8 @@ async function retainWorkspaceMutationProcess(db, input) {
29711
30468
  and17(
29712
30469
  eq17(sandboxRetainedProcesses.id, process.id),
29713
30470
  eq17(sandboxRetainedProcesses.state, "active"),
29714
- isNull5(sandboxRetainedProcesses.providerBindingKey),
29715
- isNull5(sandboxRetainedProcesses.providerBinding)
30471
+ isNull6(sandboxRetainedProcesses.providerBindingKey),
30472
+ isNull6(sandboxRetainedProcesses.providerBinding)
29716
30473
  )
29717
30474
  ).returning();
29718
30475
  if (!bound) {
@@ -29917,8 +30674,8 @@ async function bindRetainedProcessProviderIdentity(db, input) {
29917
30674
  eq17(sandboxRetainedProcesses.id, process.id),
29918
30675
  eq17(sandboxRetainedProcesses.state, "active"),
29919
30676
  eq17(sandboxRetainedProcesses.reconcileClaimId, input.claimId),
29920
- isNull5(sandboxRetainedProcesses.providerBindingKey),
29921
- isNull5(sandboxRetainedProcesses.providerBinding)
30677
+ isNull6(sandboxRetainedProcesses.providerBindingKey),
30678
+ isNull6(sandboxRetainedProcesses.providerBinding)
29922
30679
  )
29923
30680
  ).returning();
29924
30681
  if (!updated) {
@@ -31893,7 +32650,7 @@ async function setEnrollmentDisplayState(db, input) {
31893
32650
  // Only write on a CHANGE to EITHER field — an unchanged display state must
31894
32651
  // not churn a write on every reconnect Hello. `IS DISTINCT FROM` is the
31895
32652
  // null-safe inequality (a plain `ne` skips NULL rows).
31896
- or4(
32653
+ or6(
31897
32654
  ne(enrollments.hasDisplay, input.hasDisplay),
31898
32655
  sql14`${enrollments.desktopUnavailableReason} IS DISTINCT FROM ${input.desktopUnavailableReason}`
31899
32656
  )
@@ -32588,7 +33345,7 @@ async function forceDrainOverLimitViewerOnlyBoxes(db, input) {
32588
33345
  and17(
32589
33346
  eq17(usageEvents.workspaceId, input.workspaceId),
32590
33347
  eq17(usageEvents.eventType, "sandbox.warm_seconds"),
32591
- gt4(usageEvents.occurredAt, since)
33348
+ gt5(usageEvents.occurredAt, since)
32592
33349
  )
32593
33350
  );
32594
33351
  if (Number(total) >= input.maxWarmSecondsPerWorkspace) {
@@ -34575,7 +35332,7 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
34575
35332
  "acknowledged",
34576
35333
  "settled"
34577
35334
  ]),
34578
- isNull5(sessionTurnAttempts.quiescedAt)
35335
+ isNull6(sessionTurnAttempts.quiescedAt)
34579
35336
  )
34580
35337
  ).orderBy(desc8(sessionAttemptInterruptions.requestedAt)).limit(1);
34581
35338
  if (unquiescedInterruption) {
@@ -34623,7 +35380,7 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
34623
35380
  eq17(sessions.accountId, session.accountId),
34624
35381
  eq17(sessions.workspaceId, workspaceId),
34625
35382
  eq17(sessions.id, sessionId),
34626
- isNull5(sessions.activeTurnId)
35383
+ isNull6(sessions.activeTurnId)
34627
35384
  )
34628
35385
  ).returning({ id: sessions.id });
34629
35386
  if (!claimedSession) {
@@ -35328,11 +36085,10 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
35328
36085
  sessionId,
35329
36086
  turnId: row.id,
35330
36087
  position: Number(historyPosition),
35331
- item: sanitizeModelPayload({
35332
- type: "message",
35333
- role: "user",
35334
- content: row.prompt
35335
- }),
36088
+ item: durableUserHistoryItem(
36089
+ row.prompt,
36090
+ Array.isArray(row.resources) ? row.resources : []
36091
+ ),
35336
36092
  producerCodexCredentialId: null
35337
36093
  });
35338
36094
  const providerDelegatedTurn = isSessionRealtimeDelegationTurnMetadata(row.metadata);
@@ -35449,7 +36205,7 @@ async function markSessionAttemptQuiesced(db, input) {
35449
36205
  and17(
35450
36206
  eq17(sessionTurnAttempts.workspaceId, input.workspaceId),
35451
36207
  eq17(sessionTurnAttempts.id, input.attemptId),
35452
- isNull5(sessionTurnAttempts.quiescedAt)
36208
+ isNull6(sessionTurnAttempts.quiescedAt)
35453
36209
  )
35454
36210
  ).returning({ id: sessionTurnAttempts.id });
35455
36211
  if (!marked) {
@@ -35987,7 +36743,7 @@ async function peekSessionWork(db, workspaceId, sessionId) {
35987
36743
  "user.approvalDecision",
35988
36744
  "user.humanInputResponse"
35989
36745
  ]),
35990
- gt4(sessionEvents.sequence, currentTrigger.sequence)
36746
+ gt5(sessionEvents.sequence, currentTrigger.sequence)
35991
36747
  )
35992
36748
  ).orderBy(desc8(sessionEvents.sequence), desc8(sessionEvents.id)).limit(1);
35993
36749
  if (actionResponse) {
@@ -36452,11 +37208,11 @@ async function applySessionTurnSettlement(db, workspaceId, input, hooks = {}) {
36452
37208
  activeTurnId: session.activeTurnId
36453
37209
  };
36454
37210
  }
37211
+ const humanInputRequests = input.runState?.humanInputRequests ?? [];
36455
37212
  if (input.runState) {
36456
37213
  if (input.turnStatus !== "requires_action" || input.sessionStatus !== "requires_action") {
36457
37214
  throw new Error("A frozen run state requires a requires_action settlement");
36458
37215
  }
36459
- const humanInputRequests = input.runState.humanInputRequests ?? [];
36460
37216
  for (const request of humanInputRequests) {
36461
37217
  const parsedQuestions = request.questions.map(
36462
37218
  (question) => HumanInputQuestionContract.parse(question)
@@ -36656,7 +37412,10 @@ async function applySessionTurnSettlement(db, workspaceId, input, hooks = {}) {
36656
37412
  eq17(sessionHumanInputRequests.turnId, input.turnId),
36657
37413
  eq17(sessionHumanInputRequests.status, "pending")
36658
37414
  )
36659
- ).returning({ id: sessionHumanInputRequests.id }) : [];
37415
+ ).returning({
37416
+ id: sessionHumanInputRequests.id,
37417
+ questions: sessionHumanInputRequests.questions
37418
+ }) : [];
36660
37419
  const terminalHumanInputEvents = terminalHumanInputRows.map(
36661
37420
  (request) => ({
36662
37421
  type: "user.humanInputResponse",
@@ -36721,6 +37480,69 @@ async function applySessionTurnSettlement(db, workspaceId, input, hooks = {}) {
36721
37480
  };
36722
37481
  });
36723
37482
  const inserted = values.length > 0 ? await tx.insert(sessionEvents).values(values).returning() : [];
37483
+ const requestedEvents = inserted.filter(
37484
+ (event) => event.type === "session.humanInput.requested"
37485
+ );
37486
+ if (requestedEvents.length > 0) {
37487
+ const requestedIds = new Set(
37488
+ requestedEvents.flatMap((event) => {
37489
+ const request = sessionEventPayloadRecord(event.payload).request;
37490
+ if (!request || typeof request !== "object" || Array.isArray(request)) return [];
37491
+ const id = request.id;
37492
+ return typeof id === "string" ? [id] : [];
37493
+ })
37494
+ );
37495
+ const requests = humanInputRequests.filter((request) => requestedIds.has(request.id));
37496
+ if (requests.length !== requestedIds.size) {
37497
+ throw new Error("Human-input realtime projection lost its durable request contract");
37498
+ }
37499
+ await mirrorSessionRealtimeContextInTransaction(tx, {
37500
+ accountId: session.accountId,
37501
+ workspaceId,
37502
+ sessionId: input.sessionId,
37503
+ sourceKind: "human_input_request",
37504
+ sourceId: requestedEvents.map((event) => event.id).join(":"),
37505
+ turnId: input.turnId,
37506
+ channel: "speakable",
37507
+ text: renderRealtimeHumanInputRequestContext({ requests }),
37508
+ payload: {
37509
+ status: "waiting_for_user",
37510
+ requestIds: requests.map((request) => request.id),
37511
+ sourceEventIds: requestedEvents.map((event) => event.id)
37512
+ },
37513
+ now
37514
+ });
37515
+ }
37516
+ const terminalHumanInputById = new Map(
37517
+ terminalHumanInputRows.map((request) => [request.id, request])
37518
+ );
37519
+ for (const event of inserted) {
37520
+ if (event.type !== "user.humanInputResponse") continue;
37521
+ const payload = sessionEventPayloadRecord(event.payload);
37522
+ const requestId = typeof payload.requestId === "string" ? payload.requestId : null;
37523
+ const request = requestId ? terminalHumanInputById.get(requestId) : null;
37524
+ if (!request) continue;
37525
+ await mirrorSessionRealtimeContextInTransaction(tx, {
37526
+ accountId: session.accountId,
37527
+ workspaceId,
37528
+ sessionId: input.sessionId,
37529
+ sourceKind: "human_input_response",
37530
+ sourceId: event.id,
37531
+ turnId: input.turnId,
37532
+ channel: null,
37533
+ text: renderRealtimeHumanInputResponseContext({
37534
+ requestId: request.id,
37535
+ questions: request.questions,
37536
+ response: { outcome: "cancelled" }
37537
+ }),
37538
+ payload: {
37539
+ requestId: request.id,
37540
+ outcome: "cancelled",
37541
+ sourceEventId: event.id
37542
+ },
37543
+ now
37544
+ });
37545
+ }
36724
37546
  const terminal = isTerminalSessionTurnStatus(input.turnStatus);
36725
37547
  if (isTerminalSessionTurnStatus(input.turnStatus)) {
36726
37548
  const terminalType = terminalSessionTurnEventType(input.turnStatus);
@@ -37217,7 +38039,7 @@ async function requestSessionTurnRecovery(db, workspaceId, input) {
37217
38039
  sessionHistoryItems.producerCodexCredentialId,
37218
38040
  input.providerArtifactInvalidation.codexCredentialId
37219
38041
  ),
37220
- isNull5(sessionHistoryItems.providerArtifactInvalidatedAt),
38042
+ isNull6(sessionHistoryItems.providerArtifactInvalidatedAt),
37221
38043
  sql14`${sessionHistoryItems.item} ->> 'type' in ('reasoning', 'compaction')`
37222
38044
  )
37223
38045
  ).returning({ id: sessionHistoryItems.id });
@@ -37231,7 +38053,7 @@ async function requestSessionTurnRecovery(db, workspaceId, input) {
37231
38053
  agentRunStates.frozenCodexCredentialId,
37232
38054
  input.providerArtifactInvalidation.codexCredentialId
37233
38055
  ),
37234
- isNull5(agentRunStates.providerArtifactInvalidatedAt)
38056
+ isNull6(agentRunStates.providerArtifactInvalidatedAt)
37235
38057
  )
37236
38058
  ).orderBy(desc8(agentRunStates.stateVersion)).limit(1);
37237
38059
  const invalidatedRunState = latestRunState ? await tx.update(agentRunStates).set({
@@ -37241,7 +38063,7 @@ async function requestSessionTurnRecovery(db, workspaceId, input) {
37241
38063
  }).where(
37242
38064
  and17(
37243
38065
  eq17(agentRunStates.id, latestRunState.id),
37244
- isNull5(agentRunStates.providerArtifactInvalidatedAt)
38066
+ isNull6(agentRunStates.providerArtifactInvalidatedAt)
37245
38067
  )
37246
38068
  ).returning({ id: agentRunStates.id }) : [];
37247
38069
  providerArtifactsInvalidated = invalidatedHistory.length + invalidatedRunState.length;
@@ -38029,7 +38851,7 @@ async function markSessionWorkflowWakeDelivered(db, input) {
38029
38851
  and17(
38030
38852
  eq17(sessionTurnAttempts.workspaceId, input.workspaceId),
38031
38853
  eq17(sessionTurnAttempts.sessionId, input.sessionId),
38032
- isNull5(sessionTurnAttempts.quiescedAt),
38854
+ isNull6(sessionTurnAttempts.quiescedAt),
38033
38855
  inArray11(sessionAttemptInterruptions.state, ["settled", "rejected_stale"])
38034
38856
  )
38035
38857
  ).limit(1);
@@ -39744,6 +40566,8 @@ export {
39744
40566
  CODEX_CREDENTIAL_LEASE_TTL_MS,
39745
40567
  CODEX_RESET_REDEMPTION_OUTCOMES,
39746
40568
  CODEX_ROTATION_STRATEGIES,
40569
+ ConnectionDisconnectGenerationError,
40570
+ ConnectionDisconnectIdempotencyError,
39747
40571
  ConnectionRefreshHttpError,
39748
40572
  FORCE_RLS_TABLES,
39749
40573
  GitHubInstallationAuthorityCommitError,
@@ -39852,6 +40676,7 @@ export {
39852
40676
  WorkspaceInstructionPolicyInvalidOperationError,
39853
40677
  WorkspaceInstructionPolicyLegacyUnavailableError,
39854
40678
  WorkspaceInstructionPolicyNotFoundError,
40679
+ WorkspaceInstructionPolicyOperationReuseError,
39855
40680
  WorkspaceInstructionPolicySnapshotAuthorityError,
39856
40681
  abandonCodexResetRedemptionBeforeProvider,
39857
40682
  abandonRecordingForTurnAttempt,
@@ -40053,6 +40878,8 @@ export {
40053
40878
  disableHostExportConsumer,
40054
40879
  disconnectAllCodexAccounts,
40055
40880
  disconnectCodexAccount,
40881
+ disconnectConnectionIdempotently,
40882
+ durableUserHistoryItem,
40056
40883
  editQueuedTurnInTransaction,
40057
40884
  enableCapabilityInstallation,
40058
40885
  enablePackInstallation,
@@ -40101,11 +40928,13 @@ export {
40101
40928
  getCodexRotationSettings,
40102
40929
  getComposerDraftInTransaction,
40103
40930
  getConnectionMetadata,
40931
+ getCurrentPreferenceRegistryGovernanceMetadata,
40104
40932
  getDeviceEnrollmentRequestByDeviceCode,
40105
40933
  getEligibleKnowledgeClaim,
40106
40934
  getEnrollment,
40107
40935
  getFile,
40108
40936
  getFileUpload,
40937
+ getFiles,
40109
40938
  getHostExportConsumerStatus,
40110
40939
  getHumanInputResumeForEvent,
40111
40940
  getKnowledgeMemory,
@@ -40188,6 +41017,7 @@ export {
40188
41017
  getWorkspaceInstructionPolicyRevision,
40189
41018
  getWorkspaceModelPolicy,
40190
41019
  getWorkspacePack,
41020
+ getWorkspaceStateAcceptedAttemptGovernance,
40191
41021
  grantWorkspaceAccess,
40192
41022
  hasAuditableGitHubInstallationAuthority,
40193
41023
  hasCreditLedgerEntry,
@@ -40422,6 +41252,7 @@ export {
40422
41252
  reserveSessionCommandReceipt,
40423
41253
  reserveToolspaceCallForAttempt,
40424
41254
  resolveConnectorActionPolicy,
41255
+ resolveDocumentIndexAuthority,
40425
41256
  resolveSlackInstallationRoute,
40426
41257
  resolveWorkspaceMemoryBlock,
40427
41258
  restoreKnowledgeSourceObject,
@@ -40514,6 +41345,7 @@ export {
40514
41345
  syncSessionRealtimeLedgerInTransaction,
40515
41346
  touchEnrollmentLastSeen,
40516
41347
  touchLeaseHolder,
41348
+ transitionConnectionState,
40517
41349
  updateCodexAllocatorEligibility,
40518
41350
  updateCodexRotationSettings,
40519
41351
  updateConnection,