@opengeni/db 0.28.1 → 0.28.9

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 (52) hide show
  1. package/dist/{chunk-HT5T62CC.js → chunk-P6CUHXQZ.js} +651 -206
  2. package/dist/chunk-P6CUHXQZ.js.map +1 -0
  3. package/dist/{chunk-DBS5HPEW.js → chunk-VHBFHMPC.js} +7 -1
  4. package/dist/chunk-VHBFHMPC.js.map +1 -0
  5. package/dist/environment-crypto.d.ts +8 -4
  6. package/dist/index.d.ts +265 -20
  7. package/dist/index.js +3966 -2185
  8. package/dist/index.js.map +1 -1
  9. package/dist/lossless-columns.d.ts +58 -0
  10. package/dist/lossless-json.d.ts +39 -0
  11. package/dist/memory-domain.d.ts +3 -6
  12. package/dist/persistence-errors.d.ts +7 -14
  13. package/dist/provision-roles.js +1 -1
  14. package/dist/runtime-posture.d.ts +2 -2
  15. package/dist/schema.d.ts +1419 -271
  16. package/dist/schema.js +9 -1
  17. package/dist/session-realtime-terminal.d.ts +7 -0
  18. package/dist/transcription-recordings-schema.d.ts +44 -6
  19. package/dist/transcription-recordings.d.ts +1 -1
  20. package/drizzle/0065_enrollment_credential_generation.sql +10 -0
  21. package/drizzle/0140_retained_screenshot_artifacts.sql +192 -0
  22. package/drizzle/0176_lossless_canonical_json.sql +975 -0
  23. package/drizzle/0177_session_events_workspace_turn_type_index.sql +5 -0
  24. package/drizzle/0178_permissioned_secret_reads.sql +14 -0
  25. package/drizzle/0179_slack_private_shortcut_delivery_gate.sql +85 -0
  26. package/drizzle/0180_retained_screenshot_lifecycle_fences.sql +273 -0
  27. package/drizzle/0181_connected_machine_removal.sql +52 -0
  28. package/drizzle/0182_connected_machine_remove_session_default.sql +77 -0
  29. package/package.json +4 -4
  30. package/src/database.ts +7 -1
  31. package/src/environment-crypto.ts +22 -9
  32. package/src/index.ts +4253 -1601
  33. package/src/lossless-columns.ts +35 -0
  34. package/src/lossless-json.ts +322 -0
  35. package/src/memory-domain.ts +5 -44
  36. package/src/persistence-errors.ts +29 -34
  37. package/src/runtime-posture.ts +6 -0
  38. package/src/schema.ts +260 -38
  39. package/src/session-control.ts +125 -76
  40. package/src/session-queue-commands.ts +325 -234
  41. package/src/session-realtime-context.ts +18 -5
  42. package/src/session-realtime-ledger.ts +29 -7
  43. package/src/session-realtime-mirror.ts +4 -2
  44. package/src/session-realtime-terminal.ts +89 -21
  45. package/src/session-realtime.ts +3 -2
  46. package/src/session-tool-call-settlement.ts +29 -15
  47. package/src/transcription-recordings-schema.ts +5 -2
  48. package/src/transcription-recordings.ts +70 -40
  49. package/dist/chunk-DBS5HPEW.js.map +0 -1
  50. package/dist/chunk-HT5T62CC.js.map +0 -1
  51. package/dist/event-payload-sanitizer.d.ts +0 -32
  52. package/src/event-payload-sanitizer.ts +0 -377
@@ -13,7 +13,7 @@ import {
13
13
  } from "@opengeni/contracts";
14
14
  import { and, asc, eq, inArray, sql } from "drizzle-orm";
15
15
  import type { Database } from "./database";
16
- import { sanitizeEventPayload } from "./event-payload-sanitizer";
16
+ import { withLosslessContentWriteVersion } from "./lossless-json";
17
17
  import { closePendingSessionToolCallsInTransaction } from "./session-tool-call-settlement";
18
18
  import {
19
19
  assertAgentCommandAuthorityInTransaction,
@@ -45,6 +45,10 @@ import {
45
45
  type FrozenTurnInitiator,
46
46
  } from "./turn-initiator";
47
47
 
48
+ type SessionEventInsertWithPayload = typeof schema.sessionEvents.$inferInsert & {
49
+ payload: unknown;
50
+ };
51
+
48
52
  export type QueueCommandConflictCode =
49
53
  | "QUEUE_VERSION_CHANGED"
50
54
  | "QUEUE_PROMPT_STARTED"
@@ -294,18 +298,22 @@ export async function supersedeSessionCurrentDirectionInTransaction(
294
298
  const cancelledHumanInputEvents = await db
295
299
  .insert(schema.sessionEvents)
296
300
  .values(
297
- cancelledHumanInputs.map((request) => ({
298
- accountId: input.accountId,
299
- workspaceId: input.workspaceId,
300
- sessionId: input.sessionId,
301
- sequence: ++lastSequence,
302
- type: "user.humanInputResponse",
303
- turnId: current.id,
304
- turnGeneration: current.executionGeneration,
305
- turnAssociation: "current",
306
- payload: { requestId: request.id, response: { outcome: "cancelled" } },
307
- occurredAt: now,
308
- })),
301
+ withLosslessContentWriteVersion(
302
+ cancelledHumanInputs.map((request) => ({
303
+ accountId: input.accountId,
304
+ workspaceId: input.workspaceId,
305
+ sessionId: input.sessionId,
306
+ sequence: ++lastSequence,
307
+ type: "user.humanInputResponse",
308
+ turnId: current.id,
309
+ turnGeneration: current.executionGeneration,
310
+ turnAssociation: "current",
311
+ payload: { requestId: request.id, response: { outcome: "cancelled" } },
312
+ occurredAt: now,
313
+ })),
314
+ "payload",
315
+ "payloadCodecVersion",
316
+ ),
309
317
  )
310
318
  .returning();
311
319
  const requestsById = new Map(cancelledHumanInputs.map((request) => [request.id, request]));
@@ -639,21 +647,27 @@ export async function moveQueuedTurnInTransaction(
639
647
  );
640
648
  const [event] = await db
641
649
  .insert(schema.sessionEvents)
642
- .values({
643
- accountId: input.accountId,
644
- workspaceId: input.workspaceId,
645
- sessionId: input.sessionId,
646
- sequence: session.lastSequence + 1,
647
- type: "session.queue.changed",
648
- turnId: target.id,
649
- payload: {
650
- operation: "move",
651
- queueVersion,
652
- turnId: target.id,
653
- beforeTurnId: input.beforeTurnId,
654
- },
655
- occurredAt: new Date(),
656
- })
650
+ .values(
651
+ withLosslessContentWriteVersion(
652
+ {
653
+ accountId: input.accountId,
654
+ workspaceId: input.workspaceId,
655
+ sessionId: input.sessionId,
656
+ sequence: session.lastSequence + 1,
657
+ type: "session.queue.changed",
658
+ turnId: target.id,
659
+ payload: {
660
+ operation: "move",
661
+ queueVersion,
662
+ turnId: target.id,
663
+ beforeTurnId: input.beforeTurnId,
664
+ },
665
+ occurredAt: new Date(),
666
+ },
667
+ "payload",
668
+ "payloadCodecVersion",
669
+ ),
670
+ )
657
671
  .returning({ id: schema.sessionEvents.id });
658
672
  if (!event) throw new Error("Queue move event was not inserted");
659
673
  eventIds.push(event.id);
@@ -767,20 +781,26 @@ export async function deleteSessionQueueItemInTransaction(
767
781
  );
768
782
  const [event] = await db
769
783
  .insert(schema.sessionEvents)
770
- .values({
771
- accountId: input.accountId,
772
- workspaceId: input.workspaceId,
773
- sessionId: input.sessionId,
774
- sequence: session.lastSequence + 1,
775
- type: "session.queue.changed",
776
- turnId: turn.id,
777
- payload: {
778
- operation: "delete",
779
- queueVersion,
780
- turnId: turn.id,
781
- },
782
- occurredAt: now,
783
- })
784
+ .values(
785
+ withLosslessContentWriteVersion(
786
+ {
787
+ accountId: input.accountId,
788
+ workspaceId: input.workspaceId,
789
+ sessionId: input.sessionId,
790
+ sequence: session.lastSequence + 1,
791
+ type: "session.queue.changed",
792
+ turnId: turn.id,
793
+ payload: {
794
+ operation: "delete",
795
+ queueVersion,
796
+ turnId: turn.id,
797
+ },
798
+ occurredAt: now,
799
+ },
800
+ "payload",
801
+ "payloadCodecVersion",
802
+ ),
803
+ )
784
804
  .returning({ id: schema.sessionEvents.id });
785
805
  if (!event) throw new Error("Queue delete event was not inserted");
786
806
  await db
@@ -939,21 +959,27 @@ export async function editQueuedTurnInTransaction(
939
959
  );
940
960
  const [event] = await db
941
961
  .insert(schema.sessionEvents)
942
- .values({
943
- accountId: input.accountId,
944
- workspaceId: input.workspaceId,
945
- sessionId: input.sessionId,
946
- sequence: session.lastSequence + 1,
947
- type: "session.queue.changed",
948
- turnId: turn.id,
949
- payload: {
950
- operation: "edit",
951
- queueVersion,
952
- turnId: turn.id,
953
- draftRevision: nextDraftRevision,
954
- },
955
- occurredAt: now,
956
- })
962
+ .values(
963
+ withLosslessContentWriteVersion(
964
+ {
965
+ accountId: input.accountId,
966
+ workspaceId: input.workspaceId,
967
+ sessionId: input.sessionId,
968
+ sequence: session.lastSequence + 1,
969
+ type: "session.queue.changed",
970
+ turnId: turn.id,
971
+ payload: {
972
+ operation: "edit",
973
+ queueVersion,
974
+ turnId: turn.id,
975
+ draftRevision: nextDraftRevision,
976
+ },
977
+ occurredAt: now,
978
+ },
979
+ "payload",
980
+ "payloadCodecVersion",
981
+ ),
982
+ )
957
983
  .returning({ id: schema.sessionEvents.id });
958
984
  if (!event) throw new Error("Queue edit event was not inserted");
959
985
  await db
@@ -1118,7 +1144,7 @@ export async function steerQueuedTurnInTransaction(
1118
1144
  input.actor.type === "agent_attempt"
1119
1145
  ? `attempt:${input.actor.attemptId}`
1120
1146
  : input.actor.subjectId;
1121
- const eventValues: Array<typeof schema.sessionEvents.$inferInsert> = [];
1147
+ const eventValues: SessionEventInsertWithPayload[] = [];
1122
1148
  if (supersededTurnId && !liveCurrentTurnId) {
1123
1149
  eventValues.push({
1124
1150
  accountId: input.accountId,
@@ -1146,9 +1172,12 @@ export async function steerQueuedTurnInTransaction(
1146
1172
  },
1147
1173
  occurredAt: now,
1148
1174
  });
1149
- const eventRows = await db.insert(schema.sessionEvents).values(eventValues).returning({
1150
- id: schema.sessionEvents.id,
1151
- });
1175
+ const eventRows = await db
1176
+ .insert(schema.sessionEvents)
1177
+ .values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
1178
+ .returning({
1179
+ id: schema.sessionEvents.id,
1180
+ });
1152
1181
  await db
1153
1182
  .update(schema.sessions)
1154
1183
  .set({
@@ -1161,19 +1190,25 @@ export async function steerQueuedTurnInTransaction(
1161
1190
  updatedAt: now,
1162
1191
  })
1163
1192
  .where(eq(schema.sessions.id, input.sessionId));
1164
- await db.insert(schema.auditEvents).values({
1165
- accountId: input.accountId,
1166
- workspaceId: input.workspaceId,
1167
- subjectId: actor,
1168
- action: "session.queue.steer",
1169
- targetType: "session_turn",
1170
- targetId: target.id,
1171
- metadata: {
1172
- operationId: reserved.receipt.id,
1173
- replacedTurnId: supersededTurnId,
1174
- interruptionCount,
1175
- },
1176
- });
1193
+ await db.insert(schema.auditEvents).values(
1194
+ withLosslessContentWriteVersion(
1195
+ {
1196
+ accountId: input.accountId,
1197
+ workspaceId: input.workspaceId,
1198
+ subjectId: actor,
1199
+ action: "session.queue.steer",
1200
+ targetType: "session_turn",
1201
+ targetId: target.id,
1202
+ metadata: {
1203
+ operationId: reserved.receipt.id,
1204
+ replacedTurnId: supersededTurnId,
1205
+ interruptionCount,
1206
+ },
1207
+ },
1208
+ "metadata",
1209
+ "metadataCodecVersion",
1210
+ ),
1211
+ );
1177
1212
  const wakeRevision = await registerSessionWorkflowWakeInTransaction(db, {
1178
1213
  accountId: input.accountId,
1179
1214
  workspaceId: input.workspaceId,
@@ -1485,7 +1520,7 @@ export async function submitHumanPromptInTransaction(
1485
1520
  const turnId = crypto.randomUUID();
1486
1521
  const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
1487
1522
  let sequence = session.lastSequence;
1488
- const eventValues: Array<typeof schema.sessionEvents.$inferInsert> = [
1523
+ const eventValues: SessionEventInsertWithPayload[] = [
1489
1524
  {
1490
1525
  id: acceptedEventId,
1491
1526
  accountId: input.accountId,
@@ -1494,7 +1529,7 @@ export async function submitHumanPromptInTransaction(
1494
1529
  sequence: ++sequence,
1495
1530
  type: "user.message",
1496
1531
  clientEventId: input.operationKey,
1497
- payload: sanitizeEventPayload({
1532
+ payload: {
1498
1533
  text: input.messagePresentation?.text ?? input.text,
1499
1534
  ...(input.messagePresentation
1500
1535
  ? {
@@ -1510,54 +1545,60 @@ export async function submitHumanPromptInTransaction(
1510
1545
  ...(input.latencyMode ? { latencyMode: input.latencyMode } : {}),
1511
1546
  delivery: input.delivery,
1512
1547
  initiator: frozenInitiator.initiator,
1513
- }),
1548
+ },
1514
1549
  occurredAt: now,
1515
1550
  },
1516
1551
  ];
1517
1552
  const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
1518
1553
  const [turn] = await db
1519
1554
  .insert(schema.sessionTurns)
1520
- .values({
1521
- id: turnId,
1522
- accountId: input.accountId,
1523
- workspaceId: input.workspaceId,
1524
- sessionId: input.sessionId,
1525
- triggerEventId: acceptedEventId,
1526
- temporalWorkflowId: workflowId,
1527
- status: "queued",
1528
- source: input.source,
1529
- position: input.delivery === "steer" ? 0 : existingQueued.length + 1,
1530
- prompt: input.text,
1531
- turnInstructions:
1532
- editedSourceTurnInstructions !== undefined
1533
- ? editedSourceTurnInstructions
1534
- : (input.turnInstructions ?? null),
1535
- resources: input.resources,
1536
- tools: [],
1537
- toolsProvided: false,
1538
- model: input.model ?? session.model,
1539
- reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
1540
- latencyMode: input.turnExecutionPolicy?.latencyMode ?? input.latencyMode ?? "standard",
1541
- sandboxBackend: session.sandboxBackend,
1542
- metadata: input.turnExecutionPolicy
1543
- ? metadataWithTurnExecutionPolicyV1(input.turnMetadata ?? {}, input.turnExecutionPolicy)
1544
- : (input.turnMetadata ?? {}),
1545
- lineage: { actor: input.actor.type },
1546
- ...initiatorColumns(frozenInitiator),
1547
- initiatingHumanSubjectId: editedSourceTurn
1548
- ? (editedSourceTurn.initiatingHumanSubjectId ??
1549
- (editedSourceTurn.initiatorKind === "subject"
1550
- ? editedSourceTurn.initiatorSubjectId
1551
- : null))
1552
- : frozenInitiator.initiator.kind === "subject"
1553
- ? frozenInitiator.initiator.subjectId
1554
- : null,
1555
- personalConnectionDelegations: editedSourceTurn
1556
- ? editedSourceTurn.personalConnectionDelegations
1557
- : (input.personalConnectionDelegations ?? []),
1558
- createdAt: now,
1559
- updatedAt: now,
1560
- })
1555
+ .values(
1556
+ withLosslessContentWriteVersion(
1557
+ {
1558
+ id: turnId,
1559
+ accountId: input.accountId,
1560
+ workspaceId: input.workspaceId,
1561
+ sessionId: input.sessionId,
1562
+ triggerEventId: acceptedEventId,
1563
+ temporalWorkflowId: workflowId,
1564
+ status: "queued",
1565
+ source: input.source,
1566
+ position: input.delivery === "steer" ? 0 : existingQueued.length + 1,
1567
+ prompt: input.text,
1568
+ turnInstructions:
1569
+ editedSourceTurnInstructions !== undefined
1570
+ ? editedSourceTurnInstructions
1571
+ : (input.turnInstructions ?? null),
1572
+ resources: input.resources,
1573
+ tools: [],
1574
+ toolsProvided: false,
1575
+ model: input.model ?? session.model,
1576
+ reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
1577
+ latencyMode: input.turnExecutionPolicy?.latencyMode ?? input.latencyMode ?? "standard",
1578
+ sandboxBackend: session.sandboxBackend,
1579
+ metadata: input.turnExecutionPolicy
1580
+ ? metadataWithTurnExecutionPolicyV1(input.turnMetadata ?? {}, input.turnExecutionPolicy)
1581
+ : (input.turnMetadata ?? {}),
1582
+ lineage: { actor: input.actor.type },
1583
+ ...initiatorColumns(frozenInitiator),
1584
+ initiatingHumanSubjectId: editedSourceTurn
1585
+ ? (editedSourceTurn.initiatingHumanSubjectId ??
1586
+ (editedSourceTurn.initiatorKind === "subject"
1587
+ ? editedSourceTurn.initiatorSubjectId
1588
+ : null))
1589
+ : frozenInitiator.initiator.kind === "subject"
1590
+ ? frozenInitiator.initiator.subjectId
1591
+ : null,
1592
+ personalConnectionDelegations: editedSourceTurn
1593
+ ? editedSourceTurn.personalConnectionDelegations
1594
+ : (input.personalConnectionDelegations ?? []),
1595
+ createdAt: now,
1596
+ updatedAt: now,
1597
+ },
1598
+ "prompt",
1599
+ "promptCodecVersion",
1600
+ ),
1601
+ )
1561
1602
  .returning();
1562
1603
  if (!turn) throw new SessionControlInvariantError("Prompt turn was not inserted");
1563
1604
  eventValues.push({
@@ -1686,7 +1727,10 @@ export async function submitHumanPromptInTransaction(
1686
1727
  occurredAt: now,
1687
1728
  });
1688
1729
  }
1689
- const eventRows = await db.insert(schema.sessionEvents).values(eventValues).returning();
1730
+ const eventRows = await db
1731
+ .insert(schema.sessionEvents)
1732
+ .values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
1733
+ .returning();
1690
1734
  if (input.actor.type === "human") {
1691
1735
  const realtimeRouting =
1692
1736
  input.delivery === "steer"
@@ -1742,25 +1786,31 @@ export async function submitHumanPromptInTransaction(
1742
1786
  reason: input.delivery === "steer" ? "prompt_steer" : "prompt_send",
1743
1787
  controlRequested: input.delivery === "steer",
1744
1788
  });
1745
- await db.insert(schema.auditEvents).values({
1746
- accountId: input.accountId,
1747
- workspaceId: input.workspaceId,
1748
- subjectId:
1749
- input.actor.type === "agent_attempt"
1750
- ? `attempt:${input.actor.attemptId}`
1751
- : input.actor.subjectId,
1752
- action: input.delivery === "steer" ? "session.prompt.steer" : "session.prompt.send",
1753
- targetType: "session_turn",
1754
- targetId: turnId,
1755
- metadata: {
1756
- operationId: reserved.receipt.id,
1757
- replacedTurnId,
1758
- interruptionCount,
1759
- ...(input.turnExecutionPolicy
1760
- ? turnExecutionPolicyAuditMetadata(input.turnExecutionPolicy, turnId)
1761
- : {}),
1762
- },
1763
- });
1789
+ await db.insert(schema.auditEvents).values(
1790
+ withLosslessContentWriteVersion(
1791
+ {
1792
+ accountId: input.accountId,
1793
+ workspaceId: input.workspaceId,
1794
+ subjectId:
1795
+ input.actor.type === "agent_attempt"
1796
+ ? `attempt:${input.actor.attemptId}`
1797
+ : input.actor.subjectId,
1798
+ action: input.delivery === "steer" ? "session.prompt.steer" : "session.prompt.send",
1799
+ targetType: "session_turn",
1800
+ targetId: turnId,
1801
+ metadata: {
1802
+ operationId: reserved.receipt.id,
1803
+ replacedTurnId,
1804
+ interruptionCount,
1805
+ ...(input.turnExecutionPolicy
1806
+ ? turnExecutionPolicyAuditMetadata(input.turnExecutionPolicy, turnId)
1807
+ : {}),
1808
+ },
1809
+ },
1810
+ "metadata",
1811
+ "metadataCodecVersion",
1812
+ ),
1813
+ );
1764
1814
  const eventIds = eventRows.map((event) => event.id);
1765
1815
  const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
1766
1816
  controlRevision: resumed.revision,
@@ -1879,46 +1929,62 @@ export async function sendAgentMessageInTransaction(
1879
1929
  const now = new Date();
1880
1930
  const [update] = await db
1881
1931
  .insert(schema.sessionSystemUpdates)
1882
- .values({
1883
- accountId: input.accountId,
1884
- workspaceId: input.workspaceId,
1885
- sessionId: input.targetSessionId,
1886
- kind: "agent_message",
1887
- classification: "info",
1888
- sourceId: input.actor.sessionId,
1889
- dedupeKey: `agent-message:${reserved.receipt.id}`,
1890
- summary: input.text,
1891
- payload: {
1892
- type: "agent_message",
1893
- text: input.text,
1894
- operationId: reserved.receipt.id,
1895
- },
1896
- lineage: {
1897
- callerSessionId: input.actor.sessionId,
1898
- callerTurnId: input.actor.turnId,
1899
- callerAttemptId: input.actor.attemptId,
1900
- callerExecutionGeneration: input.actor.executionGeneration,
1901
- },
1902
- personalConnectionDelegations,
1903
- state: "pending",
1904
- })
1932
+ .values(
1933
+ withLosslessContentWriteVersion(
1934
+ withLosslessContentWriteVersion(
1935
+ {
1936
+ accountId: input.accountId,
1937
+ workspaceId: input.workspaceId,
1938
+ sessionId: input.targetSessionId,
1939
+ kind: "agent_message",
1940
+ classification: "info",
1941
+ sourceId: input.actor.sessionId,
1942
+ dedupeKey: `agent-message:${reserved.receipt.id}`,
1943
+ summary: input.text,
1944
+ payload: {
1945
+ type: "agent_message",
1946
+ text: input.text,
1947
+ operationId: reserved.receipt.id,
1948
+ },
1949
+ lineage: {
1950
+ callerSessionId: input.actor.sessionId,
1951
+ callerTurnId: input.actor.turnId,
1952
+ callerAttemptId: input.actor.attemptId,
1953
+ callerExecutionGeneration: input.actor.executionGeneration,
1954
+ },
1955
+ personalConnectionDelegations,
1956
+ state: "pending",
1957
+ },
1958
+ "summary",
1959
+ "summaryCodecVersion",
1960
+ ),
1961
+ "payload",
1962
+ "payloadCodecVersion",
1963
+ ),
1964
+ )
1905
1965
  .returning({ id: schema.sessionSystemUpdates.id });
1906
1966
  if (!update) throw new SessionControlInvariantError("Agent message was not inserted");
1907
1967
  const [event] = await db
1908
1968
  .insert(schema.sessionEvents)
1909
- .values({
1910
- accountId: input.accountId,
1911
- workspaceId: input.workspaceId,
1912
- sessionId: input.targetSessionId,
1913
- sequence: session.lastSequence + 1,
1914
- type: "system.update.pending",
1915
- payload: {
1916
- updateId: update.id,
1917
- kind: "agent_message",
1918
- sourceSessionId: input.actor.sessionId,
1919
- },
1920
- occurredAt: now,
1921
- })
1969
+ .values(
1970
+ withLosslessContentWriteVersion(
1971
+ {
1972
+ accountId: input.accountId,
1973
+ workspaceId: input.workspaceId,
1974
+ sessionId: input.targetSessionId,
1975
+ sequence: session.lastSequence + 1,
1976
+ type: "system.update.pending",
1977
+ payload: {
1978
+ updateId: update.id,
1979
+ kind: "agent_message",
1980
+ sourceSessionId: input.actor.sessionId,
1981
+ },
1982
+ occurredAt: now,
1983
+ },
1984
+ "payload",
1985
+ "payloadCodecVersion",
1986
+ ),
1987
+ )
1922
1988
  .returning({ id: schema.sessionEvents.id });
1923
1989
  if (!event) throw new SessionControlInvariantError("Agent message event was not inserted");
1924
1990
  const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
@@ -1939,21 +2005,27 @@ export async function sendAgentMessageInTransaction(
1939
2005
  updatedAt: now,
1940
2006
  })
1941
2007
  .where(eq(schema.sessions.id, input.targetSessionId));
1942
- await db.insert(schema.auditEvents).values({
1943
- accountId: input.accountId,
1944
- workspaceId: input.workspaceId,
1945
- subjectId: `attempt:${input.actor.attemptId}`,
1946
- action: "session.agent_message",
1947
- targetType: "session",
1948
- targetId: input.targetSessionId,
1949
- metadata: {
1950
- operationId: reserved.receipt.id,
1951
- callerSessionId: input.actor.sessionId,
1952
- callerTurnId: input.actor.turnId,
1953
- callerAttemptId: input.actor.attemptId,
1954
- callerExecutionGeneration: input.actor.executionGeneration,
1955
- },
1956
- });
2008
+ await db.insert(schema.auditEvents).values(
2009
+ withLosslessContentWriteVersion(
2010
+ {
2011
+ accountId: input.accountId,
2012
+ workspaceId: input.workspaceId,
2013
+ subjectId: `attempt:${input.actor.attemptId}`,
2014
+ action: "session.agent_message",
2015
+ targetType: "session",
2016
+ targetId: input.targetSessionId,
2017
+ metadata: {
2018
+ operationId: reserved.receipt.id,
2019
+ callerSessionId: input.actor.sessionId,
2020
+ callerTurnId: input.actor.turnId,
2021
+ callerAttemptId: input.actor.attemptId,
2022
+ callerExecutionGeneration: input.actor.executionGeneration,
2023
+ },
2024
+ },
2025
+ "metadata",
2026
+ "metadataCodecVersion",
2027
+ ),
2028
+ );
1957
2029
  const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
1958
2030
  result: {
1959
2031
  updateId: update.id,
@@ -2084,33 +2156,43 @@ export async function steerAgentSessionInTransaction(
2084
2156
  const now = new Date();
2085
2157
  const [update] = await db
2086
2158
  .insert(schema.sessionSystemUpdates)
2087
- .values({
2088
- accountId: input.accountId,
2089
- workspaceId: input.workspaceId,
2090
- sessionId: input.targetSessionId,
2091
- kind: "agent_steer_instruction",
2092
- classification: "action_required",
2093
- sourceId: input.actor.sessionId,
2094
- dedupeKey: `agent-steer:${reserved.receipt.id}`,
2095
- summary: input.instruction,
2096
- payload: {
2097
- type: "agent_steer_instruction",
2098
- instruction: input.instruction,
2099
- operationId: reserved.receipt.id,
2100
- },
2101
- lineage: {
2102
- callerSessionId: input.actor.sessionId,
2103
- callerTurnId: input.actor.turnId,
2104
- callerAttemptId: input.actor.attemptId,
2105
- callerExecutionGeneration: input.actor.executionGeneration,
2106
- },
2107
- personalConnectionDelegations,
2108
- state: "pending",
2109
- })
2159
+ .values(
2160
+ withLosslessContentWriteVersion(
2161
+ withLosslessContentWriteVersion(
2162
+ {
2163
+ accountId: input.accountId,
2164
+ workspaceId: input.workspaceId,
2165
+ sessionId: input.targetSessionId,
2166
+ kind: "agent_steer_instruction",
2167
+ classification: "action_required",
2168
+ sourceId: input.actor.sessionId,
2169
+ dedupeKey: `agent-steer:${reserved.receipt.id}`,
2170
+ summary: input.instruction,
2171
+ payload: {
2172
+ type: "agent_steer_instruction",
2173
+ instruction: input.instruction,
2174
+ operationId: reserved.receipt.id,
2175
+ },
2176
+ lineage: {
2177
+ callerSessionId: input.actor.sessionId,
2178
+ callerTurnId: input.actor.turnId,
2179
+ callerAttemptId: input.actor.attemptId,
2180
+ callerExecutionGeneration: input.actor.executionGeneration,
2181
+ },
2182
+ personalConnectionDelegations,
2183
+ state: "pending",
2184
+ },
2185
+ "summary",
2186
+ "summaryCodecVersion",
2187
+ ),
2188
+ "payload",
2189
+ "payloadCodecVersion",
2190
+ ),
2191
+ )
2110
2192
  .returning({ id: schema.sessionSystemUpdates.id });
2111
2193
  if (!update) throw new SessionControlInvariantError("Agent Steer instruction was not inserted");
2112
2194
  let sequence = supersession.lastSequence;
2113
- const events: Array<typeof schema.sessionEvents.$inferInsert> = [];
2195
+ const events: SessionEventInsertWithPayload[] = [];
2114
2196
  if (supersession.replacedTurn && !supersession.liveCurrentTurnId) {
2115
2197
  events.push({
2116
2198
  accountId: input.accountId,
@@ -2175,9 +2257,12 @@ export async function steerAgentSessionInTransaction(
2175
2257
  occurredAt: now,
2176
2258
  },
2177
2259
  );
2178
- const insertedEvents = await db.insert(schema.sessionEvents).values(events).returning({
2179
- id: schema.sessionEvents.id,
2180
- });
2260
+ const insertedEvents = await db
2261
+ .insert(schema.sessionEvents)
2262
+ .values(withLosslessContentWriteVersion(events, "payload", "payloadCodecVersion"))
2263
+ .returning({
2264
+ id: schema.sessionEvents.id,
2265
+ });
2181
2266
  const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
2182
2267
  const wakeRevision = await registerSessionWorkflowWakeInTransaction(db, {
2183
2268
  accountId: input.accountId,
@@ -2196,24 +2281,30 @@ export async function steerAgentSessionInTransaction(
2196
2281
  updatedAt: now,
2197
2282
  })
2198
2283
  .where(eq(schema.sessions.id, input.targetSessionId));
2199
- await db.insert(schema.auditEvents).values({
2200
- accountId: input.accountId,
2201
- workspaceId: input.workspaceId,
2202
- subjectId: `attempt:${input.actor.attemptId}`,
2203
- action: "session.agent_steer",
2204
- targetType: "session",
2205
- targetId: input.targetSessionId,
2206
- metadata: {
2207
- operationId: reserved.receipt.id,
2208
- callerSessionId: input.actor.sessionId,
2209
- callerTurnId: input.actor.turnId,
2210
- callerAttemptId: input.actor.attemptId,
2211
- callerExecutionGeneration: input.actor.executionGeneration,
2212
- controlRevision: resumed.revision,
2213
- interruptionCount: supersession.interruptionCount,
2214
- workspaceControlEventId: resumed.workspaceControlEventId,
2215
- },
2216
- });
2284
+ await db.insert(schema.auditEvents).values(
2285
+ withLosslessContentWriteVersion(
2286
+ {
2287
+ accountId: input.accountId,
2288
+ workspaceId: input.workspaceId,
2289
+ subjectId: `attempt:${input.actor.attemptId}`,
2290
+ action: "session.agent_steer",
2291
+ targetType: "session",
2292
+ targetId: input.targetSessionId,
2293
+ metadata: {
2294
+ operationId: reserved.receipt.id,
2295
+ callerSessionId: input.actor.sessionId,
2296
+ callerTurnId: input.actor.turnId,
2297
+ callerAttemptId: input.actor.attemptId,
2298
+ callerExecutionGeneration: input.actor.executionGeneration,
2299
+ controlRevision: resumed.revision,
2300
+ interruptionCount: supersession.interruptionCount,
2301
+ workspaceControlEventId: resumed.workspaceControlEventId,
2302
+ },
2303
+ },
2304
+ "metadata",
2305
+ "metadataCodecVersion",
2306
+ ),
2307
+ );
2217
2308
  const eventIds = insertedEvents.map((event) => event.id);
2218
2309
  const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
2219
2310
  controlRevision: resumed.revision,