@opengeni/db 3.6.0 → 3.7.4-canary.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 (92) hide show
  1. package/dist/automations.d.ts +4 -0
  2. package/dist/canonical-human-identities.js +3 -3
  3. package/dist/{chunk-UGDVSQ6U.js → chunk-3ZMN4EXC.js} +2 -2
  4. package/dist/{chunk-744DFC65.js → chunk-6FIVOJ3V.js} +96 -6
  5. package/dist/chunk-6FIVOJ3V.js.map +1 -0
  6. package/dist/{chunk-UJ2EW3QI.js → chunk-DXJ2WY6W.js} +427 -85
  7. package/dist/chunk-DXJ2WY6W.js.map +1 -0
  8. package/dist/{chunk-CDMMSUWJ.js → chunk-JP6IYGYI.js} +3 -3
  9. package/dist/{chunk-Q5YUGQVK.js → chunk-JS3AWDKZ.js} +3 -3
  10. package/dist/{chunk-G3732M3T.js → chunk-LHKB62GC.js} +2 -2
  11. package/dist/{chunk-2NT476HD.js → chunk-QL4AHBYD.js} +2 -2
  12. package/dist/{chunk-IW6O6G7R.js → chunk-VDXHLVDE.js} +2 -2
  13. package/dist/{chunk-WW7AJ5IC.js → chunk-ZTSJPFDH.js} +5 -7
  14. package/dist/chunk-ZTSJPFDH.js.map +1 -0
  15. package/dist/codex-token-resolver.d.ts +12 -1
  16. package/dist/company-profile-agent-admin.d.ts +4 -2
  17. package/dist/company-profile-agent-policy.d.ts +20 -0
  18. package/dist/company-profile-schema.d.ts +573 -0
  19. package/dist/editable-artifact-durable-export.js +2 -2
  20. package/dist/editable-artifacts.js +3 -3
  21. package/dist/index.d.ts +487 -20
  22. package/dist/index.js +9489 -6041
  23. package/dist/index.js.map +1 -1
  24. package/dist/managed-auth-session-sets.js +3 -3
  25. package/dist/managed-human-provisioning.d.ts +3 -3
  26. package/dist/memory-domain.d.ts +5 -3
  27. package/dist/model-catalog.d.ts +153 -0
  28. package/dist/pr-review.d.ts +9 -0
  29. package/dist/provision-roles.js +1 -1
  30. package/dist/runtime-posture.d.ts +7 -7
  31. package/dist/schema.d.ts +1069 -6
  32. package/dist/schema.js +17 -1
  33. package/dist/session-background-commands.js +3 -3
  34. package/dist/session-control.d.ts +75 -5
  35. package/dist/session-queue-commands.d.ts +19 -0
  36. package/dist/session-tenancy.js +3 -3
  37. package/dist/user-resource-authority.d.ts +8 -0
  38. package/dist/video-generation.js +3 -3
  39. package/dist/xai-subscription.d.ts +8 -0
  40. package/drizzle/0369_local_human_personal_authority.sql +350 -0
  41. package/drizzle/0370_workspace_member_management_scope.sql +98 -0
  42. package/drizzle/0371_workspace_member_candidate_inventory.sql +128 -0
  43. package/drizzle/0372_ordered_variable_set_runtime_authority.sql +287 -0
  44. package/drizzle/0373_sandbox_shared_preparation.sql +59 -0
  45. package/drizzle/0374_session_event_cursors.sql +315 -0
  46. package/drizzle/0375_session_recovery_observability.sql +73 -0
  47. package/drizzle/0376_organization_workspace_inventory.sql +88 -0
  48. package/drizzle/0377_scoped_rig_health_projection.sql +80 -0
  49. package/drizzle/0378_scoped_rig_health_audit_timestamp.sql +77 -0
  50. package/drizzle/0379_session_event_raw_lane_activation.sql +518 -0
  51. package/drizzle/0380_autonomous_company_profile_agent_policy.sql +829 -0
  52. package/drizzle/0381_organization_codex_subscription_inheritance.sql +720 -0
  53. package/drizzle/0382_organization_api_key_provenance.sql +91 -0
  54. package/drizzle/0383_codex_cooldown_reconciliation.sql +51 -0
  55. package/drizzle/0384_codex_cooldown_revision_guard_privileges.sql +6 -0
  56. package/drizzle/0385_connected_machine_legacy_tilde_workdirs.sql +25 -0
  57. package/drizzle/0386_local_organization_administration.sql +157 -0
  58. package/drizzle/0387_bound_host_export_session_payloads.sql +165 -0
  59. package/drizzle/0388_sandbox_provider_deadline_interactions.sql +491 -0
  60. package/drizzle/0389_model_catalog_and_gateway_custom_models.sql +241 -0
  61. package/package.json +6 -6
  62. package/src/automations.ts +9 -1
  63. package/src/codex-token-resolver.ts +26 -1
  64. package/src/company-brain-governed-writes.ts +30 -1
  65. package/src/company-profile-agent-admin.ts +68 -1
  66. package/src/company-profile-agent-policy.ts +126 -0
  67. package/src/company-profile-schema.ts +115 -1
  68. package/src/database.ts +3 -5
  69. package/src/index.ts +4473 -570
  70. package/src/insights.ts +21 -7
  71. package/src/managed-human-provisioning.ts +3 -3
  72. package/src/memory-domain.ts +9 -4
  73. package/src/model-catalog.ts +682 -0
  74. package/src/organization-membership-lifecycle.ts +0 -1
  75. package/src/pr-review.ts +19 -0
  76. package/src/provision-roles.ts +83 -4
  77. package/src/runtime-posture.ts +26 -0
  78. package/src/schema.ts +259 -10
  79. package/src/session-control.ts +347 -59
  80. package/src/session-queue-commands.ts +303 -122
  81. package/src/session-tool-call-settlement.ts +34 -7
  82. package/src/user-resource-authority.ts +56 -0
  83. package/src/xai-subscription.ts +66 -14
  84. package/dist/chunk-744DFC65.js.map +0 -1
  85. package/dist/chunk-UJ2EW3QI.js.map +0 -1
  86. package/dist/chunk-WW7AJ5IC.js.map +0 -1
  87. /package/dist/{chunk-UGDVSQ6U.js.map → chunk-3ZMN4EXC.js.map} +0 -0
  88. /package/dist/{chunk-CDMMSUWJ.js.map → chunk-JP6IYGYI.js.map} +0 -0
  89. /package/dist/{chunk-Q5YUGQVK.js.map → chunk-JS3AWDKZ.js.map} +0 -0
  90. /package/dist/{chunk-G3732M3T.js.map → chunk-LHKB62GC.js.map} +0 -0
  91. /package/dist/{chunk-2NT476HD.js.map → chunk-QL4AHBYD.js.map} +0 -0
  92. /package/dist/{chunk-IW6O6G7R.js.map → chunk-VDXHLVDE.js.map} +0 -0
@@ -29,7 +29,7 @@ import {
29
29
  type TimelineAnnotation,
30
30
  type PersonalResourceAttachmentIntent,
31
31
  } from "@opengeni/contracts";
32
- import { and, asc, eq, inArray, sql } from "drizzle-orm";
32
+ import { and, asc, desc, eq, inArray, sql } from "drizzle-orm";
33
33
  import { setSubjectRlsContext, type Database, type SessionActivityDatabase } from "./database";
34
34
  import {
35
35
  fromPostgresLosslessJson,
@@ -44,10 +44,13 @@ import {
44
44
  canonicalSessionCommandHash,
45
45
  evaluateSessionControl,
46
46
  lockSessionEventWriteRows,
47
+ lockSessionPromptCommandOperation,
47
48
  lockWorkspaceInferenceControl,
48
49
  lockWorkspaceInferenceControlForAdmission,
50
+ getCompletedSessionPromptCommandReceipt,
49
51
  registerInternalUpdateWakeInTransaction,
50
52
  reserveSessionCommandReceipt,
53
+ reserveSessionPromptCommandReceipt,
51
54
  registerSessionWorkflowWakeInTransaction,
52
55
  type SessionCommandActor,
53
56
  type SessionCommandReceiptRow,
@@ -210,6 +213,122 @@ function mapSubmittedPromptTurn(row: typeof schema.sessionTurns.$inferSelect): S
210
213
  };
211
214
  }
212
215
 
216
+ async function loadSubmittedHumanPromptReplay(
217
+ db: Database,
218
+ input: {
219
+ workspaceId: string;
220
+ sessionId: string;
221
+ subjectId: string;
222
+ delivery: "send" | "steer";
223
+ expectedDraftRevision?: number | null;
224
+ receipt: SessionCommandReceiptRow;
225
+ },
226
+ ): Promise<SubmitHumanPromptResult> {
227
+ const turnId = String(input.receipt.result.turnId ?? "");
228
+ const acceptedEventId = String(input.receipt.result.acceptedEventId ?? "");
229
+ const eventIds = Array.isArray(input.receipt.result.eventIds)
230
+ ? input.receipt.result.eventIds.filter((id): id is string => typeof id === "string")
231
+ : [];
232
+ const wakeRevision = Number(input.receipt.result.wakeRevision ?? 0);
233
+ if (!turnId || !acceptedEventId || wakeRevision < 1) {
234
+ throw new SessionControlInvariantError("Replayed prompt receipt is incomplete");
235
+ }
236
+ const replayEvents = await db
237
+ .select()
238
+ .from(schema.sessionEvents)
239
+ .where(
240
+ and(
241
+ eq(schema.sessionEvents.workspaceId, input.workspaceId),
242
+ eq(schema.sessionEvents.sessionId, input.sessionId),
243
+ inArray(schema.sessionEvents.id, eventIds),
244
+ ),
245
+ )
246
+ .orderBy(asc(schema.sessionEvents.sequence));
247
+ const [replayTurn] = await db
248
+ .select()
249
+ .from(schema.sessionTurns)
250
+ .where(
251
+ and(
252
+ eq(schema.sessionTurns.workspaceId, input.workspaceId),
253
+ eq(schema.sessionTurns.sessionId, input.sessionId),
254
+ eq(schema.sessionTurns.id, turnId),
255
+ ),
256
+ )
257
+ .limit(1);
258
+ const events = replayEvents.map(mapSubmittedPromptEvent);
259
+ const accepted = events.find((event) => event.id === acceptedEventId);
260
+ if (!accepted || !replayTurn || events.length !== eventIds.length) {
261
+ throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
262
+ }
263
+ const replayDraft =
264
+ input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
265
+ ? null
266
+ : await getComposerDraftInTransaction(db, {
267
+ workspaceId: input.workspaceId,
268
+ sessionId: input.sessionId,
269
+ subjectId: input.subjectId,
270
+ });
271
+ return {
272
+ receipt: input.receipt,
273
+ routing:
274
+ input.receipt.result.routing === "accepted_for_execution" ||
275
+ input.receipt.result.routing === "queued_for_execution" ||
276
+ input.receipt.result.routing === "accepted_for_steering"
277
+ ? input.receipt.result.routing
278
+ : input.delivery === "steer"
279
+ ? "accepted_for_steering"
280
+ : // Pre-routing receipts cannot reconstruct admission-time activity
281
+ // or Pause truth. Queue is the only conservative placement; a
282
+ // later turn.started event moves it into chat without duplication.
283
+ "queued_for_execution",
284
+ queueVersion: Number(input.receipt.appliedQueueVersion),
285
+ accepted,
286
+ events,
287
+ turn: mapSubmittedPromptTurn(replayTurn),
288
+ draft: replayDraft,
289
+ acceptedEventId,
290
+ eventIds,
291
+ turnId,
292
+ wakeRevision,
293
+ interruptionCount: Number(input.receipt.result.interruptionCount ?? 0),
294
+ workspaceControlEventId:
295
+ typeof input.receipt.result.workspaceControlEventId === "string"
296
+ ? input.receipt.result.workspaceControlEventId
297
+ : null,
298
+ replay: true,
299
+ };
300
+ }
301
+
302
+ export async function replaySubmittedHumanPromptFromBoundaryReceipt(
303
+ db: Database,
304
+ input: {
305
+ workspaceId: string;
306
+ sessionId: string;
307
+ subjectId: string;
308
+ actor: SessionCommandActor;
309
+ operationKey: string;
310
+ delivery: "send" | "steer";
311
+ boundaryRequestHash: string;
312
+ expectedDraftRevision?: number | null;
313
+ /** Wait for an overlapping same-key transaction before checking committed replay truth. */
314
+ serializeOperation?: boolean;
315
+ },
316
+ ): Promise<SubmitHumanPromptResult | null> {
317
+ if (input.serializeOperation) {
318
+ await lockSessionPromptCommandOperation(db, input);
319
+ }
320
+ const receipt = await getCompletedSessionPromptCommandReceipt(db, {
321
+ workspaceId: input.workspaceId,
322
+ actor: input.actor,
323
+ action: input.delivery === "steer" ? "prompt.steer" : "prompt.send",
324
+ targetSessionId: input.sessionId,
325
+ operationKey: input.operationKey,
326
+ boundaryRequestHash: input.boundaryRequestHash,
327
+ });
328
+ if (!receipt) return null;
329
+ return await loadSubmittedHumanPromptReplay(db, { ...input, receipt });
330
+ }
331
+
213
332
  export type AgentInternalUpdateCommandResult = {
214
333
  receipt: SessionCommandReceiptRow;
215
334
  updateId: string;
@@ -345,11 +464,55 @@ async function lockSession(
345
464
 
346
465
  type SteerSupersessionResult = {
347
466
  interruptionCount: number;
467
+ steerTargetTurn: typeof schema.sessionTurns.$inferSelect | null;
348
468
  replacedTurn: typeof schema.sessionTurns.$inferSelect | null;
349
469
  liveCurrentTurnId: string | null;
470
+ deferredUntilCompaction: boolean;
350
471
  lastSequence: number;
351
472
  };
352
473
 
474
+ async function turnAttemptIsCompacting(
475
+ db: Database,
476
+ input: {
477
+ workspaceId: string;
478
+ sessionId: string;
479
+ turn: typeof schema.sessionTurns.$inferSelect;
480
+ },
481
+ ): Promise<boolean> {
482
+ // A standalone operator compaction is maintenance rather than replaceable
483
+ // direction. Once claimed, let it finish even before its provider-visible
484
+ // started landmark is appended.
485
+ if (input.turn.source === "compaction") return true;
486
+ if (!input.turn.activeAttemptId) return false;
487
+
488
+ // Automatic/proactive/overflow compaction happens inside an ordinary turn.
489
+ // The latest exact-attempt landmark is durable state: `started` means the
490
+ // checkpoint provider call is still in flight, while compacted/skipped opens
491
+ // ordinary Steer interruption again. Multiple compactions in one attempt are
492
+ // therefore handled by the newest lifecycle event rather than a historical
493
+ // existence test.
494
+ const [latest] = await db
495
+ .select({ type: schema.sessionEvents.type })
496
+ .from(schema.sessionEvents)
497
+ .where(
498
+ and(
499
+ eq(schema.sessionEvents.workspaceId, input.workspaceId),
500
+ eq(schema.sessionEvents.sessionId, input.sessionId),
501
+ eq(schema.sessionEvents.turnId, input.turn.id),
502
+ eq(schema.sessionEvents.turnGeneration, input.turn.executionGeneration),
503
+ eq(schema.sessionEvents.turnAttemptId, input.turn.activeAttemptId),
504
+ inArray(schema.sessionEvents.type, [
505
+ "session.context.compaction.started",
506
+ "session.context.compacted",
507
+ "session.context.compaction.skipped",
508
+ ]),
509
+ ),
510
+ )
511
+ .orderBy(desc(schema.sessionEvents.sequence), desc(schema.sessionEvents.id))
512
+ .limit(1);
513
+ return latest?.type === "session.context.compaction.started";
514
+ }
515
+
353
516
  /**
354
517
  * One canonical replacement transition shared by human row/new-prompt Steer
355
518
  * and Agent Steer. A live owner is interrupted and remains current until exact
@@ -371,8 +534,10 @@ export async function supersedeSessionCurrentDirectionInTransaction(
371
534
  if (!input.activeTurnId) {
372
535
  return {
373
536
  interruptionCount: 0,
537
+ steerTargetTurn: null,
374
538
  replacedTurn: null,
375
539
  liveCurrentTurnId: null,
540
+ deferredUntilCompaction: false,
376
541
  lastSequence: input.lastSequence,
377
542
  };
378
543
  }
@@ -391,6 +556,7 @@ export async function supersedeSessionCurrentDirectionInTransaction(
391
556
  workspaceId: input.workspaceId,
392
557
  controlLock: "already_locked",
393
558
  workspaceLock: "already_locked",
559
+ sessionIds: [input.sessionId],
394
560
  turnIds: [input.activeTurnId],
395
561
  attemptIds: preview?.activeAttemptId ? [preview.activeAttemptId] : [],
396
562
  });
@@ -410,6 +576,26 @@ export async function supersedeSessionCurrentDirectionInTransaction(
410
576
  `Running turn ${current.id} has no first-class attempt owner`,
411
577
  );
412
578
  }
579
+ if (
580
+ current.activeAttemptId &&
581
+ (await turnAttemptIsCompacting(db, {
582
+ workspaceId: input.workspaceId,
583
+ sessionId: input.sessionId,
584
+ turn: current,
585
+ }))
586
+ ) {
587
+ return {
588
+ interruptionCount: 0,
589
+ steerTargetTurn: current,
590
+ // An ordinary turn is superseded cooperatively as soon as its checkpoint
591
+ // settles. Standalone maintenance completes normally, then the Steer is
592
+ // already first in line.
593
+ replacedTurn: current.source === "compaction" ? null : current,
594
+ liveCurrentTurnId: current.id,
595
+ deferredUntilCompaction: true,
596
+ lastSequence: input.lastSequence,
597
+ };
598
+ }
413
599
  if (current.activeAttemptId) {
414
600
  if (current.status !== "running") {
415
601
  throw new SessionControlInvariantError(
@@ -431,8 +617,10 @@ export async function supersedeSessionCurrentDirectionInTransaction(
431
617
  .returning({ id: schema.sessionAttemptInterruptions.id });
432
618
  return {
433
619
  interruptionCount: interruption ? 1 : 0,
620
+ steerTargetTurn: current,
434
621
  replacedTurn: current,
435
622
  liveCurrentTurnId: current.id,
623
+ deferredUntilCompaction: false,
436
624
  lastSequence: input.lastSequence,
437
625
  };
438
626
  }
@@ -571,8 +759,10 @@ export async function supersedeSessionCurrentDirectionInTransaction(
571
759
  }
572
760
  return {
573
761
  interruptionCount: 0,
762
+ steerTargetTurn: current,
574
763
  replacedTurn: current,
575
764
  liveCurrentTurnId: null,
765
+ deferredUntilCompaction: false,
576
766
  lastSequence,
577
767
  };
578
768
  }
@@ -1388,9 +1578,11 @@ export async function steerQueuedTurnInTransaction(
1388
1578
  lastSequence: session.lastSequence,
1389
1579
  });
1390
1580
  const interruptionCount = supersession.interruptionCount;
1581
+ const steerTargetTurn = supersession.steerTargetTurn;
1391
1582
  const supersededTurnId = supersession.replacedTurn?.id ?? null;
1392
1583
  const supersededAttemptId = supersession.replacedTurn?.activeAttemptId ?? null;
1393
1584
  const liveCurrentTurnId = supersession.liveCurrentTurnId;
1585
+ const deferredUntilCompaction = supersession.deferredUntilCompaction;
1394
1586
 
1395
1587
  const withoutTarget = rows.filter((row) => row.id !== target.id);
1396
1588
  const ordered = [target, ...withoutTarget];
@@ -1412,6 +1604,7 @@ export async function steerQueuedTurnInTransaction(
1412
1604
  replacedTurnId: supersededTurnId,
1413
1605
  replacedAttemptId: supersededAttemptId,
1414
1606
  interruptionCount,
1607
+ ...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
1415
1608
  },
1416
1609
  updatedAt: now,
1417
1610
  })
@@ -1440,12 +1633,16 @@ export async function steerQueuedTurnInTransaction(
1440
1633
  sessionId: input.sessionId,
1441
1634
  sequence: ++sequence,
1442
1635
  type: "session.control.steer_requested",
1443
- turnId: supersededTurnId ?? target.id,
1636
+ turnId: steerTargetTurn?.id ?? target.id,
1637
+ turnGeneration: steerTargetTurn?.executionGeneration ?? null,
1638
+ turnAttemptId: steerTargetTurn?.activeAttemptId ?? null,
1639
+ turnAssociation: steerTargetTurn ? "current" : null,
1444
1640
  payload: {
1445
1641
  operationId: reserved.receipt.id,
1446
1642
  targetTurnId: target.id,
1447
1643
  replacedTurnId: supersededTurnId,
1448
- stopping: liveCurrentTurnId !== null,
1644
+ stopping: liveCurrentTurnId !== null && !deferredUntilCompaction,
1645
+ ...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
1449
1646
  },
1450
1647
  occurredAt: now,
1451
1648
  });
@@ -1480,6 +1677,7 @@ export async function steerQueuedTurnInTransaction(
1480
1677
  operationId: reserved.receipt.id,
1481
1678
  replacedTurnId: supersededTurnId,
1482
1679
  interruptionCount,
1680
+ deferredUntilCompaction,
1483
1681
  },
1484
1682
  },
1485
1683
  "metadata",
@@ -1501,6 +1699,7 @@ export async function steerQueuedTurnInTransaction(
1501
1699
  result: {
1502
1700
  interruptionCount,
1503
1701
  supersededTurnId,
1702
+ deferredUntilCompaction,
1504
1703
  wakeRevision,
1505
1704
  workspaceControlEventId: resumed.workspaceControlEventId,
1506
1705
  },
@@ -1528,6 +1727,8 @@ export async function submitHumanPromptInTransaction(
1528
1727
  subjectLabel?: string;
1529
1728
  actor: SessionCommandActor;
1530
1729
  operationKey: string;
1730
+ /** Stable parsed boundary-request identity used before mutable enrichment. */
1731
+ boundaryRequestHash?: string;
1531
1732
  delivery: "send" | "steer";
1532
1733
  controlEtag?: string | null;
1533
1734
  expectedDraftRevision?: number | null;
@@ -1562,6 +1763,9 @@ export async function submitHumanPromptInTransaction(
1562
1763
  id: string;
1563
1764
  headersEncrypted: Record<string, string>;
1564
1765
  }>;
1766
+ /** Trusted database-only admission seam. It runs only after a completed
1767
+ * operation replay has been ruled out; throwing rolls the prompt back. */
1768
+ beforeFreshPromptCommit?: (tx: Database) => Promise<void>;
1565
1769
  /** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
1566
1770
  controlLockTimeoutMs?: number;
1567
1771
  },
@@ -1628,91 +1832,41 @@ export async function submitHumanPromptInTransaction(
1628
1832
  }
1629
1833
  : {}),
1630
1834
  });
1631
- const reserved = await reserveSessionCommandReceipt(db, {
1632
- accountId: input.accountId,
1633
- workspaceId: input.workspaceId,
1634
- actor: input.actor,
1635
- action: input.delivery === "steer" ? "prompt.steer" : "prompt.send",
1636
- targetSessionId: input.sessionId,
1637
- targetTurnId: null,
1638
- operationKey: input.operationKey,
1639
- canonicalRequestHash: requestHash,
1640
- });
1835
+ const action = input.delivery === "steer" ? "prompt.steer" : "prompt.send";
1836
+ const reserved = input.boundaryRequestHash
1837
+ ? await reserveSessionPromptCommandReceipt(db, {
1838
+ accountId: input.accountId,
1839
+ workspaceId: input.workspaceId,
1840
+ actor: input.actor,
1841
+ action,
1842
+ targetSessionId: input.sessionId,
1843
+ operationKey: input.operationKey,
1844
+ canonicalRequestHash: requestHash,
1845
+ boundaryRequestHash: input.boundaryRequestHash,
1846
+ })
1847
+ : await reserveSessionCommandReceipt(db, {
1848
+ accountId: input.accountId,
1849
+ workspaceId: input.workspaceId,
1850
+ actor: input.actor,
1851
+ action,
1852
+ targetSessionId: input.sessionId,
1853
+ targetTurnId: null,
1854
+ operationKey: input.operationKey,
1855
+ canonicalRequestHash: requestHash,
1856
+ });
1641
1857
  if (reserved.replay && reserved.receipt.appliedQueueVersion !== null) {
1642
- const turnId = String(reserved.receipt.result.turnId ?? "");
1643
- const acceptedEventId = String(reserved.receipt.result.acceptedEventId ?? "");
1644
- const eventIds = Array.isArray(reserved.receipt.result.eventIds)
1645
- ? reserved.receipt.result.eventIds.filter((id): id is string => typeof id === "string")
1646
- : [];
1647
- const wakeRevision = Number(reserved.receipt.result.wakeRevision ?? 0);
1648
- if (!turnId || !acceptedEventId || wakeRevision < 1) {
1649
- throw new SessionControlInvariantError("Replayed prompt receipt is incomplete");
1650
- }
1651
- const replayEvents = await db
1652
- .select()
1653
- .from(schema.sessionEvents)
1654
- .where(
1655
- and(
1656
- eq(schema.sessionEvents.workspaceId, input.workspaceId),
1657
- eq(schema.sessionEvents.sessionId, input.sessionId),
1658
- inArray(schema.sessionEvents.id, eventIds),
1659
- ),
1660
- )
1661
- .orderBy(asc(schema.sessionEvents.sequence));
1662
- const [replayTurn] = await db
1663
- .select()
1664
- .from(schema.sessionTurns)
1665
- .where(
1666
- and(
1667
- eq(schema.sessionTurns.workspaceId, input.workspaceId),
1668
- eq(schema.sessionTurns.sessionId, input.sessionId),
1669
- eq(schema.sessionTurns.id, turnId),
1670
- ),
1671
- )
1672
- .limit(1);
1673
- const events = replayEvents.map(mapSubmittedPromptEvent);
1674
- const accepted = events.find((event) => event.id === acceptedEventId);
1675
- if (!accepted || !replayTurn || events.length !== eventIds.length) {
1676
- throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
1677
- }
1678
- const replayDraft =
1679
- input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1680
- ? null
1681
- : await getComposerDraftInTransaction(db, {
1682
- workspaceId: input.workspaceId,
1683
- sessionId: input.sessionId,
1684
- subjectId: input.subjectId,
1685
- });
1686
- return {
1858
+ return await loadSubmittedHumanPromptReplay(db, {
1859
+ workspaceId: input.workspaceId,
1860
+ sessionId: input.sessionId,
1861
+ subjectId: input.subjectId,
1862
+ delivery: input.delivery,
1863
+ ...(input.expectedDraftRevision !== undefined
1864
+ ? { expectedDraftRevision: input.expectedDraftRevision }
1865
+ : {}),
1687
1866
  receipt: reserved.receipt,
1688
- routing:
1689
- reserved.receipt.result.routing === "accepted_for_execution" ||
1690
- reserved.receipt.result.routing === "queued_for_execution" ||
1691
- reserved.receipt.result.routing === "accepted_for_steering"
1692
- ? reserved.receipt.result.routing
1693
- : input.delivery === "steer"
1694
- ? "accepted_for_steering"
1695
- : // Pre-routing receipts cannot reconstruct admission-time activity
1696
- // or Pause truth. Queue is the only conservative placement; a
1697
- // later turn.started event moves it into chat without duplication.
1698
- "queued_for_execution",
1699
- queueVersion: Number(reserved.receipt.appliedQueueVersion),
1700
- accepted,
1701
- events,
1702
- turn: mapSubmittedPromptTurn(replayTurn),
1703
- draft: replayDraft,
1704
- acceptedEventId,
1705
- eventIds,
1706
- turnId,
1707
- wakeRevision,
1708
- interruptionCount: Number(reserved.receipt.result.interruptionCount ?? 0),
1709
- workspaceControlEventId:
1710
- typeof reserved.receipt.result.workspaceControlEventId === "string"
1711
- ? reserved.receipt.result.workspaceControlEventId
1712
- : null,
1713
- replay: true,
1714
- };
1867
+ });
1715
1868
  }
1869
+ await input.beforeFreshPromptCommit?.(db);
1716
1870
 
1717
1871
  const before = await evaluateSessionControl(db, input.workspaceId, input.sessionId, {
1718
1872
  workspaceControl,
@@ -1730,12 +1884,37 @@ export async function submitHumanPromptInTransaction(
1730
1884
  );
1731
1885
  }
1732
1886
 
1733
- // Send is queue admission, never a hidden control mutation. A paused Send
1734
- // remains inert behind the existing gate until the user explicitly resumes.
1735
- // Steer is the intentional exception: it replaces the current direction and
1736
- // therefore activates the selected branch atomically.
1887
+ const draft =
1888
+ input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1889
+ ? null
1890
+ : await getComposerDraftInTransaction(db, {
1891
+ workspaceId: input.workspaceId,
1892
+ sessionId: input.sessionId,
1893
+ subjectId: input.subjectId,
1894
+ lock: true,
1895
+ });
1896
+ const isQueueEditSubmission = draft?.sourceTurnId !== null && draft?.sourceTurnId !== undefined;
1897
+
1898
+ // A normal Send received while the active branch is waiting in
1899
+ // `requires_action` is the human choosing to continue conversationally
1900
+ // instead of through the pending decision surface. Promote only that active
1901
+ // wait to Steer semantics so the frozen wait is cancelled and the new prompt
1902
+ // runs next. A queue-edit submission preserves the identity and placement of
1903
+ // already accepted queued work, so it must never cancel an unrelated active
1904
+ // wait. An explicitly paused branch remains inert until Resume or an explicit
1905
+ // Steer; running, recovering, and capacity-waiting work also retain ordinary
1906
+ // queue semantics.
1907
+ const effectiveDelivery =
1908
+ input.delivery === "send" &&
1909
+ (input.actor.type === "human" || input.actor.type === "operator") &&
1910
+ !isQueueEditSubmission &&
1911
+ before.state === "active" &&
1912
+ session.status === "requires_action" &&
1913
+ session.activeTurnId !== null
1914
+ ? "steer"
1915
+ : input.delivery;
1737
1916
  const resumed =
1738
- input.delivery === "send"
1917
+ effectiveDelivery === "send"
1739
1918
  ? {
1740
1919
  revision: before.controlVersion,
1741
1920
  control: before,
@@ -1753,16 +1932,6 @@ export async function submitHumanPromptInTransaction(
1753
1932
  observedControlEtag: input.controlEtag ?? null,
1754
1933
  admission,
1755
1934
  });
1756
-
1757
- const draft =
1758
- input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1759
- ? null
1760
- : await getComposerDraftInTransaction(db, {
1761
- workspaceId: input.workspaceId,
1762
- sessionId: input.sessionId,
1763
- subjectId: input.subjectId,
1764
- lock: true,
1765
- });
1766
1935
  if (input.expectedDraftRevision !== null && input.expectedDraftRevision !== undefined) {
1767
1936
  const actualRevision = draft?.revision ?? 0;
1768
1937
  if (actualRevision !== input.expectedDraftRevision) {
@@ -1928,7 +2097,7 @@ export async function submitHumanPromptInTransaction(
1928
2097
  : (input.modelContext ?? null);
1929
2098
  const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
1930
2099
  const routing: SessionPromptRouting =
1931
- input.delivery === "steer"
2100
+ effectiveDelivery === "steer"
1932
2101
  ? "accepted_for_steering"
1933
2102
  : before.state === "paused" || session.activeTurnId || existingQueued.length > 0
1934
2103
  ? "queued_for_execution"
@@ -1959,7 +2128,7 @@ export async function submitHumanPromptInTransaction(
1959
2128
  ...(input.model ? { model: input.model } : {}),
1960
2129
  ...(input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {}),
1961
2130
  ...(input.latencyMode ? { latencyMode: input.latencyMode } : {}),
1962
- delivery: input.delivery,
2131
+ delivery: effectiveDelivery,
1963
2132
  routing,
1964
2133
  initiator: frozenInitiator.initiator,
1965
2134
  },
@@ -1980,7 +2149,7 @@ export async function submitHumanPromptInTransaction(
1980
2149
  status: "queued",
1981
2150
  source: input.source,
1982
2151
  promptRouting: routing,
1983
- position: input.delivery === "steer" ? 0 : existingQueued.length + 1,
2152
+ position: effectiveDelivery === "steer" ? 0 : existingQueued.length + 1,
1984
2153
  prompt: input.text,
1985
2154
  annotations,
1986
2155
  modelContext: effectiveModelContext,
@@ -2072,7 +2241,7 @@ export async function submitHumanPromptInTransaction(
2072
2241
  });
2073
2242
 
2074
2243
  const supersession =
2075
- input.delivery === "steer"
2244
+ effectiveDelivery === "steer"
2076
2245
  ? await supersedeSessionCurrentDirectionInTransaction(db, {
2077
2246
  accountId: input.accountId,
2078
2247
  workspaceId: input.workspaceId,
@@ -2085,8 +2254,10 @@ export async function submitHumanPromptInTransaction(
2085
2254
  })
2086
2255
  : {
2087
2256
  interruptionCount: 0,
2257
+ steerTargetTurn: null,
2088
2258
  replacedTurn: null,
2089
2259
  liveCurrentTurnId: null,
2260
+ deferredUntilCompaction: false,
2090
2261
  lastSequence: session.lastSequence,
2091
2262
  };
2092
2263
  // Ownerless Steer settlement may have appended interrupted tool results.
@@ -2094,9 +2265,11 @@ export async function submitHumanPromptInTransaction(
2094
2265
  sequence = supersession.lastSequence;
2095
2266
  for (const event of eventValues) event.sequence = ++sequence;
2096
2267
  const interruptionCount = supersession.interruptionCount;
2268
+ const steerTargetTurn = supersession.steerTargetTurn;
2097
2269
  const replacedTurnId = supersession.replacedTurn?.id ?? null;
2098
2270
  const replacedAttemptId = supersession.replacedTurn?.activeAttemptId ?? null;
2099
2271
  const liveCurrentTurnId = supersession.liveCurrentTurnId;
2272
+ const deferredUntilCompaction = supersession.deferredUntilCompaction;
2100
2273
  // Durable provenance for the queue projection. Until the superseded attempt
2101
2274
  // loses inference, user-visible output, and workspace-persistence authority,
2102
2275
  // its exact first-class attempt has no quiescence receipt. Pairing that
@@ -2104,7 +2277,7 @@ export async function submitHumanPromptInTransaction(
2104
2277
  // attempt…" truthfully across refresh/reconnect, even though logical
2105
2278
  // settlement has already cleared sessions.active_turn_id. Do not infer this
2106
2279
  // state from a local request spinner or queue position.
2107
- if (input.delivery === "steer") {
2280
+ if (effectiveDelivery === "steer") {
2108
2281
  const [updatedTurn] = await db
2109
2282
  .update(schema.sessionTurns)
2110
2283
  .set({
@@ -2114,6 +2287,7 @@ export async function submitHumanPromptInTransaction(
2114
2287
  replacedTurnId,
2115
2288
  replacedAttemptId,
2116
2289
  interruptionCount,
2290
+ ...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
2117
2291
  },
2118
2292
  updatedAt: now,
2119
2293
  })
@@ -2130,8 +2304,8 @@ export async function submitHumanPromptInTransaction(
2130
2304
  }
2131
2305
  committedTurn = updatedTurn;
2132
2306
  }
2133
- if (supersession.replacedTurn) {
2134
- const current = supersession.replacedTurn;
2307
+ if (steerTargetTurn) {
2308
+ const current = steerTargetTurn;
2135
2309
  if (!liveCurrentTurnId) {
2136
2310
  eventValues.push({
2137
2311
  accountId: input.accountId,
@@ -2157,8 +2331,9 @@ export async function submitHumanPromptInTransaction(
2157
2331
  payload: {
2158
2332
  operationId: reserved.receipt.id,
2159
2333
  targetTurnId: turnId,
2160
- replacedTurnId: current.id,
2161
- stopping: liveCurrentTurnId !== null,
2334
+ replacedTurnId,
2335
+ stopping: liveCurrentTurnId !== null && !deferredUntilCompaction,
2336
+ ...(deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
2162
2337
  },
2163
2338
  occurredAt: now,
2164
2339
  });
@@ -2188,7 +2363,7 @@ export async function submitHumanPromptInTransaction(
2188
2363
  }
2189
2364
 
2190
2365
  const ordered =
2191
- input.delivery === "steer" ? [turn, ...existingQueued] : [...existingQueued, turn];
2366
+ effectiveDelivery === "steer" ? [turn, ...existingQueued] : [...existingQueued, turn];
2192
2367
  await normalizeQueuePositions(
2193
2368
  db,
2194
2369
  input.workspaceId,
@@ -2196,7 +2371,7 @@ export async function submitHumanPromptInTransaction(
2196
2371
  ordered.map((row) => row.id),
2197
2372
  );
2198
2373
  const noCurrentAfter =
2199
- input.delivery === "steer" ? liveCurrentTurnId === null : !session.activeTurnId;
2374
+ effectiveDelivery === "steer" ? liveCurrentTurnId === null : !session.activeTurnId;
2200
2375
  const nextStatus = noCurrentAfter ? "queued" : session.status;
2201
2376
  if (nextStatus !== session.status) {
2202
2377
  eventValues.push({
@@ -2223,12 +2398,12 @@ export async function submitHumanPromptInTransaction(
2223
2398
  turnId,
2224
2399
  channel: null,
2225
2400
  text: renderRealtimeHumanInputContext({
2226
- delivery: input.delivery,
2401
+ delivery: effectiveDelivery,
2227
2402
  routing,
2228
2403
  text: renderTimelineAnnotationsForModel(input.text, annotations),
2229
2404
  }),
2230
2405
  payload: {
2231
- delivery: input.delivery,
2406
+ delivery: effectiveDelivery,
2232
2407
  routing,
2233
2408
  acceptedEventId,
2234
2409
  instruction: "OpenGeni accepted and routed this user input; do not delegate it again.",
@@ -2242,7 +2417,7 @@ export async function submitHumanPromptInTransaction(
2242
2417
  .set({
2243
2418
  resources: mergeResourceRefs(session.resources as ResourceRef[], input.resources),
2244
2419
  tools: session.tools,
2245
- activeTurnId: input.delivery === "steer" ? liveCurrentTurnId : session.activeTurnId,
2420
+ activeTurnId: effectiveDelivery === "steer" ? liveCurrentTurnId : session.activeTurnId,
2246
2421
  status: nextStatus,
2247
2422
  queueVersion,
2248
2423
  queueHeadPosition: 0,
@@ -2276,8 +2451,8 @@ export async function submitHumanPromptInTransaction(
2276
2451
  workspaceId: input.workspaceId,
2277
2452
  sessionId: input.sessionId,
2278
2453
  temporalWorkflowId: workflowId,
2279
- reason: input.delivery === "steer" ? "prompt_steer" : "prompt_send",
2280
- controlRequested: input.delivery === "steer",
2454
+ reason: effectiveDelivery === "steer" ? "prompt_steer" : "prompt_send",
2455
+ controlRequested: effectiveDelivery === "steer",
2281
2456
  });
2282
2457
  await db.insert(schema.auditEvents).values(
2283
2458
  withLosslessContentWriteVersion(
@@ -2288,13 +2463,14 @@ export async function submitHumanPromptInTransaction(
2288
2463
  input.actor.type === "agent_attempt"
2289
2464
  ? `attempt:${input.actor.attemptId}`
2290
2465
  : input.actor.subjectId,
2291
- action: input.delivery === "steer" ? "session.prompt.steer" : "session.prompt.send",
2466
+ action: effectiveDelivery === "steer" ? "session.prompt.steer" : "session.prompt.send",
2292
2467
  targetType: "session_turn",
2293
2468
  targetId: turnId,
2294
2469
  metadata: {
2295
2470
  operationId: reserved.receipt.id,
2296
2471
  replacedTurnId,
2297
2472
  interruptionCount,
2473
+ deferredUntilCompaction,
2298
2474
  ...(input.turnExecutionPolicy
2299
2475
  ? turnExecutionPolicyAuditMetadata(input.turnExecutionPolicy, turnId)
2300
2476
  : {}),
@@ -2332,12 +2508,14 @@ export async function submitHumanPromptInTransaction(
2332
2508
  turnVersion: turn.version,
2333
2509
  ...(nextDraft ? { draftRevision: nextDraft.revision } : {}),
2334
2510
  result: {
2511
+ ...(input.boundaryRequestHash ? { boundaryRequestHash: input.boundaryRequestHash } : {}),
2335
2512
  turnId,
2336
2513
  acceptedEventId,
2337
2514
  eventIds,
2338
2515
  wakeRevision,
2339
2516
  interruptionCount,
2340
2517
  replacedTurnId,
2518
+ deferredUntilCompaction,
2341
2519
  workspaceControlEventId: resumed.workspaceControlEventId,
2342
2520
  routing,
2343
2521
  ...(input.turnExecutionPolicy
@@ -2815,16 +2993,17 @@ export async function steerAgentSessionInTransaction(
2815
2993
  sessionId: input.targetSessionId,
2816
2994
  sequence: ++sequence,
2817
2995
  type: "session.control.steer_requested",
2818
- turnId: supersession.replacedTurn?.id ?? null,
2819
- turnGeneration: supersession.replacedTurn?.executionGeneration ?? null,
2820
- turnAttemptId: supersession.replacedTurn?.activeAttemptId ?? null,
2821
- turnAssociation: supersession.replacedTurn ? "current" : null,
2996
+ turnId: supersession.steerTargetTurn?.id ?? null,
2997
+ turnGeneration: supersession.steerTargetTurn?.executionGeneration ?? null,
2998
+ turnAttemptId: supersession.steerTargetTurn?.activeAttemptId ?? null,
2999
+ turnAssociation: supersession.steerTargetTurn ? "current" : null,
2822
3000
  payload: {
2823
3001
  operationId: reserved.receipt.id,
2824
3002
  targetUpdateId: update.id,
2825
3003
  replacedTurnId: supersession.replacedTurn?.id ?? null,
2826
3004
  actorSessionId: input.actor.sessionId,
2827
- stopping: supersession.liveCurrentTurnId !== null,
3005
+ stopping: supersession.liveCurrentTurnId !== null && !supersession.deferredUntilCompaction,
3006
+ ...(supersession.deferredUntilCompaction ? { deferredUntilCompaction: true } : {}),
2828
3007
  },
2829
3008
  occurredAt: now,
2830
3009
  },
@@ -2912,6 +3091,7 @@ export async function steerAgentSessionInTransaction(
2912
3091
  callerExecutionGeneration: input.actor.executionGeneration,
2913
3092
  controlRevision: resumed.revision,
2914
3093
  interruptionCount: supersession.interruptionCount,
3094
+ deferredUntilCompaction: supersession.deferredUntilCompaction,
2915
3095
  workspaceControlEventId: resumed.workspaceControlEventId,
2916
3096
  },
2917
3097
  },
@@ -2928,6 +3108,7 @@ export async function steerAgentSessionInTransaction(
2928
3108
  wakeRevision,
2929
3109
  workflowId,
2930
3110
  interruptionCount: supersession.interruptionCount,
3111
+ deferredUntilCompaction: supersession.deferredUntilCompaction,
2931
3112
  },
2932
3113
  });
2933
3114
  return {