@opengeni/db 0.28.1 → 0.31.1

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 (187) hide show
  1. package/dist/attached-browser-devices.d.ts +42 -0
  2. package/dist/attempt-tool-catalogs.d.ts +16 -0
  3. package/dist/browser-auth.d.ts +91 -0
  4. package/dist/browser-identities.d.ts +128 -0
  5. package/dist/browser-sessions.d.ts +272 -0
  6. package/dist/browser-state-artifacts.d.ts +17 -0
  7. package/dist/capability-components.d.ts +37 -0
  8. package/dist/capability-integrations.d.ts +192 -0
  9. package/dist/chunk-F5FT7BEZ.js +3535 -0
  10. package/dist/chunk-F5FT7BEZ.js.map +1 -0
  11. package/dist/chunk-ISI2TIUG.js +639 -0
  12. package/dist/chunk-ISI2TIUG.js.map +1 -0
  13. package/dist/chunk-MWDVXQOL.js +11639 -0
  14. package/dist/chunk-MWDVXQOL.js.map +1 -0
  15. package/dist/chunk-NBE6CHRI.js +955 -0
  16. package/dist/chunk-NBE6CHRI.js.map +1 -0
  17. package/dist/{chunk-DBS5HPEW.js → chunk-YHZXQ7HP.js} +760 -11
  18. package/dist/chunk-YHZXQ7HP.js.map +1 -0
  19. package/dist/codemode-operations.d.ts +117 -0
  20. package/dist/codex-token-resolver.d.ts +2 -2
  21. package/dist/company-profile-schema.d.ts +798 -0
  22. package/dist/company-profile.d.ts +268 -0
  23. package/dist/computer-sessions.d.ts +109 -0
  24. package/dist/connection-token-resolver.d.ts +9 -4
  25. package/dist/database.d.ts +52 -3
  26. package/dist/editable-artifact-durable-export.d.ts +153 -0
  27. package/dist/editable-artifact-durable-export.js +788 -0
  28. package/dist/editable-artifact-durable-export.js.map +1 -0
  29. package/dist/editable-artifact-materialization.d.ts +123 -0
  30. package/dist/editable-artifacts-schema.d.ts +4152 -0
  31. package/dist/editable-artifacts.d.ts +610 -0
  32. package/dist/editable-artifacts.js +26 -0
  33. package/dist/editable-artifacts.js.map +1 -0
  34. package/dist/environment-crypto.d.ts +8 -4
  35. package/dist/generated-images.d.ts +139 -0
  36. package/dist/index.d.ts +958 -126
  37. package/dist/index.js +31204 -12172
  38. package/dist/index.js.map +1 -1
  39. package/dist/insights.d.ts +51 -4
  40. package/dist/integration-bindings.d.ts +70 -0
  41. package/dist/integration-features.d.ts +99 -0
  42. package/dist/interaction-revisions.d.ts +3 -0
  43. package/dist/interaction-schema.d.ts +5372 -0
  44. package/dist/knowledge-source-sync-schema.d.ts +1679 -0
  45. package/dist/knowledge-source-sync.d.ts +274 -0
  46. package/dist/lossless-columns.d.ts +58 -0
  47. package/dist/lossless-json.d.ts +39 -0
  48. package/dist/memory-domain.d.ts +3 -6
  49. package/dist/memory-governance.d.ts +2 -2
  50. package/dist/memory-slack-delivery.d.ts +101 -0
  51. package/dist/new-session-drafts.d.ts +2 -2
  52. package/dist/pack-components.d.ts +76 -0
  53. package/dist/pack-installations.d.ts +86 -0
  54. package/dist/persistence-errors.d.ts +7 -14
  55. package/dist/plugin-packages.d.ts +126 -0
  56. package/dist/preference-registry.d.ts +1 -1
  57. package/dist/provision-roles.d.ts +9 -1
  58. package/dist/provision-roles.js +1 -1
  59. package/dist/runtime-posture.d.ts +18 -6
  60. package/dist/schema.d.ts +19122 -8731
  61. package/dist/schema.js +173 -1
  62. package/dist/scoped-knowledge.d.ts +97 -1
  63. package/dist/session-control.d.ts +4 -4
  64. package/dist/session-queue-commands.d.ts +19 -11
  65. package/dist/session-realtime-context.d.ts +2 -2
  66. package/dist/session-realtime-ledger.d.ts +4 -4
  67. package/dist/session-realtime-mirror.d.ts +2 -2
  68. package/dist/session-realtime-state.d.ts +1 -1
  69. package/dist/session-realtime-terminal.d.ts +8 -1
  70. package/dist/session-realtime.d.ts +7 -7
  71. package/dist/session-tool-call-settlement.d.ts +1 -1
  72. package/dist/slack-user-link-access.d.ts +54 -0
  73. package/dist/transcription-recordings-schema.d.ts +44 -6
  74. package/dist/transcription-recordings.d.ts +3 -3
  75. package/dist/turn-initiator.d.ts +2 -2
  76. package/dist/video-generation.d.ts +216 -0
  77. package/dist/video-generation.js +66 -0
  78. package/dist/video-generation.js.map +1 -0
  79. package/dist/workspace-artifacts.d.ts +1 -1
  80. package/dist/workspace-instruction-policies.d.ts +1 -1
  81. package/dist/workspace-learning-policy-schema.d.ts +932 -0
  82. package/dist/workspace-learning-policy.d.ts +161 -0
  83. package/drizzle/0065_enrollment_credential_generation.sql +10 -0
  84. package/drizzle/0140_retained_screenshot_artifacts.sql +192 -0
  85. package/drizzle/0176_lossless_canonical_json.sql +975 -0
  86. package/drizzle/0177_session_events_workspace_turn_type_index.sql +5 -0
  87. package/drizzle/0178_permissioned_secret_reads.sql +14 -0
  88. package/drizzle/0179_slack_private_shortcut_delivery_gate.sql +85 -0
  89. package/drizzle/0180_retained_screenshot_lifecycle_fences.sql +273 -0
  90. package/drizzle/0181_connected_machine_removal.sql +52 -0
  91. package/drizzle/0182_connected_machine_remove_session_default.sql +77 -0
  92. package/drizzle/0183_model_call_provider_cost_estimates.sql +39 -0
  93. package/drizzle/0184_sandbox_drain_teardown_fence.sql +682 -0
  94. package/drizzle/0185_temporal_schedule_cleanup_outbox.sql +168 -0
  95. package/drizzle/0186_sandbox_capture_provider_contract.sql +400 -0
  96. package/drizzle/0187_generated_image_artifacts.sql +173 -0
  97. package/drizzle/0188_image_generation_retention_failure.sql +25 -0
  98. package/drizzle/0189_retained_session_image_formats.sql +13 -0
  99. package/drizzle/0190_timeline_annotations.sql +31 -0
  100. package/drizzle/0191_editable_artifact_engine.sql +3853 -0
  101. package/drizzle/0192_editable_artifact_live_tickets.sql +338 -0
  102. package/drizzle/0193_editable_artifact_authorization.sql +190 -0
  103. package/drizzle/0194_editable_artifact_durable_exports.sql +160 -0
  104. package/drizzle/0195_editable_artifact_import_authorization.sql +203 -0
  105. package/drizzle/0196_rig_provider_images.sql +152 -0
  106. package/drizzle/0197_knowledge_source_sync_schedules.sql +523 -0
  107. package/drizzle/0198_memory_slack_publication_delivery.sql +393 -0
  108. package/drizzle/0199_workspace_learning_policy.sql +980 -0
  109. package/drizzle/0201_company_profile_authority.sql +849 -0
  110. package/drizzle/0202_document_index_checkpoints.sql +85 -0
  111. package/drizzle/0203_durable_video_generation.sql +353 -0
  112. package/drizzle/0204_video_generation_funding.sql +44 -0
  113. package/drizzle/0205_attempt_tool_catalogs.sql +230 -0
  114. package/drizzle/0206_browser_sessions.sql +646 -0
  115. package/drizzle/0207_browser_identities.sql +379 -0
  116. package/drizzle/0208_attached_browser_devices.sql +165 -0
  117. package/drizzle/0209_computer_sessions.sql +575 -0
  118. package/drizzle/0210_browser_auth_network_interventions.sql +441 -0
  119. package/drizzle/0211_editable_artifact_session_links.sql +58 -0
  120. package/drizzle/0212_slack_installation_bindings.sql +348 -0
  121. package/drizzle/0213_slack_user_link_access_requests.sql +177 -0
  122. package/drizzle/0214_session_activity_commit_gate.sql +262 -0
  123. package/drizzle/0215_capabilities_platform.sql +980 -0
  124. package/drizzle/0216_pack_component_ownership.sql +235 -0
  125. package/drizzle/0217_capability_definition_delete_authority.sql +32 -0
  126. package/package.json +18 -5
  127. package/src/attached-browser-devices.ts +371 -0
  128. package/src/attempt-tool-catalogs.ts +131 -0
  129. package/src/browser-auth.ts +1896 -0
  130. package/src/browser-identities.ts +1168 -0
  131. package/src/browser-sessions.ts +2005 -0
  132. package/src/browser-state-artifacts.ts +59 -0
  133. package/src/capability-components.ts +166 -0
  134. package/src/capability-integrations.ts +1663 -0
  135. package/src/codemode-operations.ts +674 -0
  136. package/src/company-profile-schema.ts +143 -0
  137. package/src/company-profile.ts +968 -0
  138. package/src/computer-sessions.ts +1130 -0
  139. package/src/connection-token-resolver.ts +270 -25
  140. package/src/database.ts +434 -24
  141. package/src/editable-artifact-durable-export.ts +1201 -0
  142. package/src/editable-artifact-materialization.ts +893 -0
  143. package/src/editable-artifacts-schema.ts +879 -0
  144. package/src/editable-artifacts.ts +5404 -0
  145. package/src/environment-crypto.ts +22 -9
  146. package/src/generated-images.ts +740 -0
  147. package/src/index.ts +10117 -2730
  148. package/src/insights.ts +160 -13
  149. package/src/integration-bindings.ts +455 -0
  150. package/src/integration-features.ts +859 -0
  151. package/src/interaction-revisions.ts +40 -0
  152. package/src/interaction-schema.ts +1303 -0
  153. package/src/knowledge-source-sync-schema.ts +192 -0
  154. package/src/knowledge-source-sync.ts +1922 -0
  155. package/src/lossless-columns.ts +35 -0
  156. package/src/lossless-json.ts +322 -0
  157. package/src/memory-domain.ts +5 -44
  158. package/src/memory-slack-delivery.ts +801 -0
  159. package/src/pack-components.ts +954 -0
  160. package/src/pack-installations.ts +929 -0
  161. package/src/persistence-errors.ts +26 -34
  162. package/src/plugin-packages.ts +1186 -0
  163. package/src/provision-roles.ts +302 -1
  164. package/src/runtime-posture-cli.ts +9 -0
  165. package/src/runtime-posture.ts +514 -5
  166. package/src/schema.ts +5177 -2957
  167. package/src/scoped-knowledge-schema.ts +1 -1
  168. package/src/scoped-knowledge.ts +655 -3
  169. package/src/session-control.ts +133 -81
  170. package/src/session-queue-commands.ts +511 -247
  171. package/src/session-realtime-context.ts +20 -7
  172. package/src/session-realtime-ledger.ts +32 -10
  173. package/src/session-realtime-mirror.ts +4 -2
  174. package/src/session-realtime-terminal.ts +89 -21
  175. package/src/session-realtime.ts +10 -9
  176. package/src/session-tool-call-settlement.ts +38 -15
  177. package/src/slack-user-link-access.ts +702 -0
  178. package/src/transcription-recordings-schema.ts +5 -2
  179. package/src/transcription-recordings.ts +70 -40
  180. package/src/video-generation.ts +1452 -0
  181. package/src/workspace-learning-policy-schema.ts +139 -0
  182. package/src/workspace-learning-policy.ts +595 -0
  183. package/dist/chunk-DBS5HPEW.js.map +0 -1
  184. package/dist/chunk-HT5T62CC.js +0 -6803
  185. package/dist/chunk-HT5T62CC.js.map +0 -1
  186. package/dist/event-payload-sanitizer.d.ts +0 -32
  187. package/src/event-payload-sanitizer.ts +0 -377
@@ -3,7 +3,8 @@ import { createHash } from "node:crypto";
3
3
  import { ReasoningEffort } from "@opengeni/contracts";
4
4
  import { and, asc, desc, eq, inArray, isNull, sql } from "drizzle-orm";
5
5
 
6
- import type { Database } from "./database";
6
+ import type { Database, SessionActivityDatabase } from "./database";
7
+ import { fromPostgresLosslessJson, fromPostgresLosslessText } from "./lossless-json";
7
8
  import * as schema from "./schema";
8
9
  import { submitHumanPromptInTransaction } from "./session-queue-commands";
9
10
 
@@ -177,7 +178,7 @@ function mapProjection(
177
178
  * delegation into the same canonical Steer-or-start path used by a human.
178
179
  */
179
180
  export async function flushSessionRealtimeTranscriptTailInTransaction(
180
- db: Database,
181
+ db: SessionActivityDatabase,
181
182
  input: {
182
183
  accountId: string;
183
184
  workspaceId: string;
@@ -233,7 +234,9 @@ export async function flushSessionRealtimeTranscriptTailInTransaction(
233
234
  sequence: schema.sessionRealtimeEntries.sequence,
234
235
  role: schema.sessionRealtimeEntries.role,
235
236
  text: schema.sessionRealtimeEntries.text,
237
+ textCodecVersion: schema.sessionRealtimeEntries.textCodecVersion,
236
238
  payload: schema.sessionRealtimeEntries.payload,
239
+ payloadCodecVersion: schema.sessionRealtimeEntries.payloadCodecVersion,
237
240
  })
238
241
  .from(schema.sessionRealtimeEntries)
239
242
  .where(
@@ -248,7 +251,12 @@ export async function flushSessionRealtimeTranscriptTailInTransaction(
248
251
  ),
249
252
  )
250
253
  .orderBy(asc(schema.sessionRealtimeEntries.sequence), asc(schema.sessionRealtimeEntries.id));
251
- const rendered = renderSessionRealtimeTail(rows);
254
+ const decodedRows = rows.map((row) => ({
255
+ ...row,
256
+ text: row.text === null ? null : fromPostgresLosslessText(row.text, row.textCodecVersion),
257
+ payload: fromPostgresLosslessJson(row.payload, row.payloadCodecVersion),
258
+ }));
259
+ const rendered = renderSessionRealtimeTail(decodedRows);
252
260
  if (!rendered.context) return null;
253
261
 
254
262
  const [session] = await db
@@ -290,7 +298,7 @@ export async function flushSessionRealtimeTranscriptTailInTransaction(
290
298
  source: SESSION_REALTIME_TAIL_SOURCE,
291
299
  realtimeId: mode.id,
292
300
  lastDelegationItemId: latestDelegation?.delegationItemId ?? null,
293
- sourceEntryIds: rows.map((entry) => entry.id),
301
+ sourceEntryIds: decodedRows.map((entry) => entry.id),
294
302
  },
295
303
  },
296
304
  source: "api",
@@ -346,7 +354,9 @@ export async function listSessionRealtimeContinuityEntriesInTransaction(
346
354
  sequence: schema.sessionRealtimeEntries.sequence,
347
355
  role: schema.sessionRealtimeEntries.role,
348
356
  text: schema.sessionRealtimeEntries.text,
357
+ textCodecVersion: schema.sessionRealtimeEntries.textCodecVersion,
349
358
  payload: schema.sessionRealtimeEntries.payload,
359
+ payloadCodecVersion: schema.sessionRealtimeEntries.payloadCodecVersion,
350
360
  createdAt: schema.sessionRealtimeEntries.createdAt,
351
361
  modeStartedAt: schema.sessionRealtimeModes.startedAt,
352
362
  })
@@ -371,10 +381,13 @@ export async function listSessionRealtimeContinuityEntriesInTransaction(
371
381
  )
372
382
  .limit(maximumEntries);
373
383
  return rows.reverse().flatMap((row) => {
374
- const turnId = row.payload.turnId;
384
+ const text =
385
+ row.text === null ? null : fromPostgresLosslessText(row.text, row.textCodecVersion);
386
+ const payload = fromPostgresLosslessJson(row.payload, row.payloadCodecVersion);
387
+ const turnId = payload.turnId;
375
388
  if (
376
389
  (row.role !== "user" && row.role !== "assistant") ||
377
- typeof row.text !== "string" ||
390
+ typeof text !== "string" ||
378
391
  typeof turnId !== "string"
379
392
  ) {
380
393
  return [];
@@ -384,7 +397,7 @@ export async function listSessionRealtimeContinuityEntriesInTransaction(
384
397
  realtimeId: row.realtimeId,
385
398
  sequence: row.sequence,
386
399
  role: row.role,
387
- text: takeUtf8Head(row.text, 16_000),
400
+ text: takeUtf8Head(text, 16_000),
388
401
  turnId,
389
402
  createdAt: row.createdAt.toISOString(),
390
403
  },
@@ -3,8 +3,12 @@ import { createHash } from "node:crypto";
3
3
  import { LatencyMode, ReasoningEffort, type SessionRealtimeMode } from "@opengeni/contracts";
4
4
  import { and, asc, desc, eq, inArray, isNull, or, sql } from "drizzle-orm";
5
5
 
6
- import { sanitizeEventPayload } from "./event-payload-sanitizer";
7
- import type { Database } from "./database";
6
+ import type { Database, SessionActivityDatabase } from "./database";
7
+ import {
8
+ fromPostgresLosslessJson,
9
+ fromPostgresLosslessText,
10
+ LOSSLESS_CONTENT_CODEC_VERSION,
11
+ } from "./lossless-json";
8
12
  import * as schema from "./schema";
9
13
  import {
10
14
  assertSessionRealtimeOwnerInTransaction,
@@ -259,8 +263,8 @@ function mapEntry(row: EntryRow): SessionRealtimeLedgerEntry {
259
263
  sourceUpdateId: row.sourceUpdateId,
260
264
  historyItemId: row.historyItemId,
261
265
  turnId: row.turnId,
262
- text: row.text,
263
- payload: row.payload,
266
+ text: row.text === null ? null : fromPostgresLosslessText(row.text, row.textCodecVersion),
267
+ payload: fromPostgresLosslessJson(row.payload, row.payloadCodecVersion),
264
268
  clientAckedAt: row.clientAckedAt?.toISOString() ?? null,
265
269
  providerAckedAt: row.providerAckedAt?.toISOString() ?? null,
266
270
  createdAt: row.createdAt.toISOString(),
@@ -288,7 +292,7 @@ function assertBoundedString(
288
292
  }
289
293
 
290
294
  function boundedPayload(input: Record<string, unknown> | undefined): Record<string, unknown> {
291
- const payload = sanitizeEventPayload(input ?? {});
295
+ const payload = input ?? {};
292
296
  if (
293
297
  Buffer.byteLength(JSON.stringify(payload), "utf8") > SESSION_REALTIME_LEDGER_MAX_PAYLOAD_BYTES
294
298
  ) {
@@ -1019,6 +1023,9 @@ function inboundReplayMatches(
1019
1023
  text: string | null,
1020
1024
  payload: Record<string, unknown>,
1021
1025
  ): boolean {
1026
+ const storedText =
1027
+ row.text === null ? null : fromPostgresLosslessText(row.text, row.textCodecVersion);
1028
+ const storedPayload = fromPostgresLosslessJson(row.payload, row.payloadCodecVersion);
1022
1029
  return (
1023
1030
  row.direction === "provider_in" &&
1024
1031
  row.kind === input.kind &&
@@ -1026,8 +1033,9 @@ function inboundReplayMatches(
1026
1033
  row.providerEventId === (input.providerEventId ?? null) &&
1027
1034
  row.delegationItemId === (input.delegationItemId ?? null) &&
1028
1035
  row.sourceUpdateId === null &&
1029
- row.text === text &&
1030
- JSON.stringify(canonicalJsonValue(row.payload)) === JSON.stringify(canonicalJsonValue(payload))
1036
+ storedText === text &&
1037
+ JSON.stringify(canonicalJsonValue(storedPayload)) ===
1038
+ JSON.stringify(canonicalJsonValue(payload))
1031
1039
  );
1032
1040
  }
1033
1041
 
@@ -1055,17 +1063,19 @@ async function appendInvalidDelegationFailure(
1055
1063
  kind: "error",
1056
1064
  delegationItemId: incoming.delegationItemId ?? null,
1057
1065
  text: failure.message,
1066
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1058
1067
  payload: {
1059
1068
  code: failure.code,
1060
1069
  callOperationId: incoming.operationId,
1061
1070
  },
1071
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1062
1072
  createdAt: now,
1063
1073
  updatedAt: now,
1064
1074
  });
1065
1075
  }
1066
1076
 
1067
1077
  async function admitRealtimeDelegationInTransaction(
1068
- db: Database,
1078
+ db: SessionActivityDatabase,
1069
1079
  input: Pick<
1070
1080
  SyncSessionRealtimeLedgerInput,
1071
1081
  "workspaceId" | "sessionId" | "realtimeId" | "connectionEpoch" | "ownerSubjectId"
@@ -1189,7 +1199,11 @@ async function materializeRealtimeUpdates(
1189
1199
  )
1190
1200
  .orderBy(asc(schema.sessionSystemUpdates.createdAt), asc(schema.sessionSystemUpdates.id))
1191
1201
  .limit(SESSION_REALTIME_LEDGER_MAX_OUTBOUND);
1192
- const updates = rows.map(({ update }) => update);
1202
+ const updates = rows.map(({ update }) => ({
1203
+ ...update,
1204
+ summary: fromPostgresLosslessText(update.summary, update.summaryCodecVersion),
1205
+ payload: fromPostgresLosslessJson(update.payload, update.payloadCodecVersion),
1206
+ }));
1193
1207
  if (updates.length === 0) return;
1194
1208
  await db.insert(schema.sessionRealtimeEntries).values(
1195
1209
  updates.map((update) => ({
@@ -1204,6 +1218,7 @@ async function materializeRealtimeUpdates(
1204
1218
  kind: "session_update",
1205
1219
  sourceUpdateId: update.id,
1206
1220
  text: update.summary,
1221
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1207
1222
  payload: boundedPayload({
1208
1223
  updateId: update.id,
1209
1224
  kind: update.kind,
@@ -1213,6 +1228,7 @@ async function materializeRealtimeUpdates(
1213
1228
  payload: update.payload,
1214
1229
  lineage: update.lineage,
1215
1230
  }),
1231
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1216
1232
  createdAt: now,
1217
1233
  updatedAt: now,
1218
1234
  })),
@@ -1252,7 +1268,7 @@ function assertProviderAckSequences(values: number[] | undefined, maximum: numbe
1252
1268
  }
1253
1269
 
1254
1270
  export async function syncSessionRealtimeLedgerInTransaction(
1255
- db: Database,
1271
+ db: SessionActivityDatabase,
1256
1272
  input: SyncSessionRealtimeLedgerInput,
1257
1273
  hooks: SyncSessionRealtimeLedgerHooks = {},
1258
1274
  ): Promise<SyncSessionRealtimeLedgerResult> {
@@ -1404,7 +1420,9 @@ export async function syncSessionRealtimeLedgerInTransaction(
1404
1420
  delegationItemId: incoming.delegationItemId ?? null,
1405
1421
  historyItemId: null,
1406
1422
  text,
1423
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1407
1424
  payload,
1425
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1408
1426
  createdAt: now,
1409
1427
  updatedAt: now,
1410
1428
  })
@@ -1612,7 +1630,9 @@ export async function appendSessionRealtimeOutboundInTransaction(
1612
1630
  kind: input.kind,
1613
1631
  delegationItemId: input.delegationItemId,
1614
1632
  text,
1633
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1615
1634
  payload,
1635
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1616
1636
  createdAt: now,
1617
1637
  updatedAt: now,
1618
1638
  })
@@ -1757,6 +1777,7 @@ export async function projectSessionRealtimeDelegationProgressInTransaction(
1757
1777
  delegationItemId: call.delegationItemId,
1758
1778
  turnId: input.turnId,
1759
1779
  text: chunk,
1780
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1760
1781
  payload: boundedPayload({
1761
1782
  route: "delegation_context",
1762
1783
  channel: "commentary",
@@ -1772,6 +1793,7 @@ export async function projectSessionRealtimeDelegationProgressInTransaction(
1772
1793
  chunkIndex,
1773
1794
  chunkCount: chunks.length,
1774
1795
  }),
1796
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
1775
1797
  createdAt: now,
1776
1798
  updatedAt: now,
1777
1799
  })),
@@ -3,8 +3,8 @@ import { createHash } from "node:crypto";
3
3
  import type { HumanInputQuestion, HumanInputResponse } from "@opengeni/contracts";
4
4
  import { and, desc, eq, gt, sql } from "drizzle-orm";
5
5
 
6
- import { sanitizeEventPayload } from "./event-payload-sanitizer";
7
6
  import type { Database } from "./database";
7
+ import { LOSSLESS_CONTENT_CODEC_VERSION } from "./lossless-json";
8
8
  import * as schema from "./schema";
9
9
 
10
10
  const SESSION_REALTIME_MIRROR_MAX_TEXT_BYTES = 131_072;
@@ -59,7 +59,7 @@ function boundedText(value: string): string {
59
59
  }
60
60
 
61
61
  function boundedPayload(value: Record<string, unknown>): Record<string, unknown> {
62
- const payload = sanitizeEventPayload(value);
62
+ const payload = value;
63
63
  if (
64
64
  Buffer.byteLength(JSON.stringify(payload), "utf8") > SESSION_REALTIME_MIRROR_MAX_PAYLOAD_BYTES
65
65
  ) {
@@ -137,7 +137,9 @@ export async function mirrorSessionRealtimeContextInTransaction(
137
137
  direction: "provider_out",
138
138
  kind: "session_update",
139
139
  text: boundedText(input.text),
140
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
140
141
  payload,
142
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
141
143
  createdAt: now,
142
144
  updatedAt: now,
143
145
  })
@@ -1,9 +1,18 @@
1
1
  import { createHash } from "node:crypto";
2
2
 
3
+ import {
4
+ retainedOutputUnavailable,
5
+ validateRetainedOutputEvidence,
6
+ type RetainedOutputEvidence,
7
+ } from "@opengeni/contracts";
3
8
  import { and, eq, inArray, sql } from "drizzle-orm";
4
9
 
5
- import { sanitizeEventPayload } from "./event-payload-sanitizer";
6
10
  import type { Database } from "./database";
11
+ import {
12
+ fromPostgresLosslessJson,
13
+ fromPostgresLosslessText,
14
+ LOSSLESS_CONTENT_CODEC_VERSION,
15
+ } from "./lossless-json";
7
16
  import { mirrorSessionRealtimeContextInTransaction } from "./session-realtime-mirror";
8
17
  import * as schema from "./schema";
9
18
 
@@ -17,9 +26,11 @@ export type ProjectSessionRealtimeDelegationTerminalInput = {
17
26
  turnId: string;
18
27
  turnStatus: "completed" | "failed" | "cancelled" | "superseded";
19
28
  terminalEvent: {
29
+ id: string | null;
20
30
  type: "turn.completed" | "turn.failed" | "turn.cancelled" | "turn.superseded";
21
31
  payload: Record<string, unknown>;
22
32
  };
33
+ retainedOutputEvidence?: unknown;
23
34
  now?: Date;
24
35
  };
25
36
 
@@ -71,20 +82,48 @@ function deterministicTerminalOperationId(turnId: string): string {
71
82
  }
72
83
 
73
84
  function boundedPayload(input: Record<string, unknown> | undefined): Record<string, unknown> {
74
- const payload = sanitizeEventPayload(input ?? {});
85
+ const payload = input ?? {};
75
86
  if (Buffer.byteLength(JSON.stringify(payload), "utf8") > MAX_PAYLOAD_BYTES) {
76
87
  throw new Error("Realtime payload exceeds the durable ledger limit");
77
88
  }
78
89
  return payload;
79
90
  }
80
91
 
81
- function assertBoundedText(value: string, label: string): void {
82
- if (Buffer.byteLength(value, "utf8") > MAX_TEXT_BYTES) {
83
- throw new Error(`${label} exceeds the durable realtime ledger limit`);
84
- }
92
+ function payloadBytes(value: Record<string, unknown>): number {
93
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
94
+ }
95
+
96
+ function fitsRealtimePayload(value: Record<string, unknown>): boolean {
97
+ return payloadBytes(value) <= MAX_PAYLOAD_BYTES;
98
+ }
99
+
100
+ function retainedEvidence(value: unknown): RetainedOutputEvidence {
101
+ return validateRetainedOutputEvidence(value) ?? retainedOutputUnavailable();
102
+ }
103
+
104
+ function terminalReference(
105
+ input: ProjectSessionRealtimeDelegationTerminalInput,
106
+ terminal: Record<string, unknown>,
107
+ ): Record<string, unknown> {
108
+ const output = typeof terminal.output === "string" ? terminal.output : null;
109
+ return {
110
+ canonicalEvent: {
111
+ id: input.terminalEvent.id,
112
+ type: input.terminalEvent.type,
113
+ },
114
+ truncation: {
115
+ truncated: true,
116
+ reason: "realtime_ledger_limit",
117
+ originalBytes: payloadBytes(terminal),
118
+ outputBytes: output === null ? null : Buffer.byteLength(output, "utf8"),
119
+ fullEvidence: retainedEvidence(input.retainedOutputEvidence),
120
+ },
121
+ };
85
122
  }
86
123
 
87
- function terminalProjection(input: ProjectSessionRealtimeDelegationTerminalInput): {
124
+ export function buildSessionRealtimeDelegationTerminalProjection(
125
+ input: ProjectSessionRealtimeDelegationTerminalInput,
126
+ ): {
88
127
  kind: "delegation_result" | "error";
89
128
  text: string;
90
129
  payload: Record<string, unknown>;
@@ -95,19 +134,33 @@ function terminalProjection(input: ProjectSessionRealtimeDelegationTerminalInput
95
134
  `Realtime delegation terminal event ${input.terminalEvent.type} does not match ${input.turnStatus}`,
96
135
  );
97
136
  }
98
- const terminal = boundedPayload(input.terminalEvent.payload);
137
+ const terminal = input.terminalEvent.payload;
99
138
  if (input.turnStatus === "completed") {
100
139
  const output =
101
140
  typeof terminal.output === "string" ? terminal.output : "Delegated turn completed.";
102
- assertBoundedText(output, "Delegation result");
141
+ const exactPayload = {
142
+ status: input.turnStatus,
143
+ turnId: input.turnId,
144
+ terminalEventId: input.terminalEvent.id,
145
+ terminalEventType: input.terminalEvent.type,
146
+ terminal,
147
+ };
148
+ if (Buffer.byteLength(output, "utf8") <= MAX_TEXT_BYTES && fitsRealtimePayload(exactPayload)) {
149
+ return {
150
+ kind: "delegation_result",
151
+ text: output,
152
+ payload: exactPayload,
153
+ };
154
+ }
103
155
  return {
104
156
  kind: "delegation_result",
105
- text: output,
157
+ text: "Delegated turn completed. The full result remains in the canonical session event.",
106
158
  payload: boundedPayload({
107
159
  status: input.turnStatus,
108
160
  turnId: input.turnId,
161
+ terminalEventId: input.terminalEvent.id,
109
162
  terminalEventType: input.terminalEvent.type,
110
- terminal,
163
+ terminal: terminalReference(input, terminal),
111
164
  }),
112
165
  };
113
166
  }
@@ -119,16 +172,31 @@ function terminalProjection(input: ProjectSessionRealtimeDelegationTerminalInput
119
172
  typeof terminal.error === "string" && terminal.error.length > 0
120
173
  ? terminal.error
121
174
  : `Delegated turn ${input.turnStatus}.`;
122
- assertBoundedText(message, "Delegation error");
175
+ const exactPayload = {
176
+ code,
177
+ status: input.turnStatus,
178
+ turnId: input.turnId,
179
+ terminalEventId: input.terminalEvent.id,
180
+ terminalEventType: input.terminalEvent.type,
181
+ terminal,
182
+ };
183
+ if (Buffer.byteLength(message, "utf8") <= MAX_TEXT_BYTES && fitsRealtimePayload(exactPayload)) {
184
+ return {
185
+ kind: "error",
186
+ text: message,
187
+ payload: exactPayload,
188
+ };
189
+ }
123
190
  return {
124
191
  kind: "error",
125
- text: message,
192
+ text: `Delegated turn ${input.turnStatus}. The full diagnostic remains in the canonical session event.`,
126
193
  payload: boundedPayload({
127
- code,
194
+ ...(Buffer.byteLength(code, "utf8") <= 256 ? { code } : {}),
128
195
  status: input.turnStatus,
129
196
  turnId: input.turnId,
197
+ terminalEventId: input.terminalEvent.id,
130
198
  terminalEventType: input.terminalEvent.type,
131
- terminal,
199
+ terminal: terminalReference(input, terminal),
132
200
  }),
133
201
  };
134
202
  }
@@ -150,8 +218,8 @@ function mapEntry(
150
218
  sourceUpdateId: row.sourceUpdateId,
151
219
  historyItemId: row.historyItemId,
152
220
  turnId: row.turnId,
153
- text: row.text,
154
- payload: row.payload,
221
+ text: row.text === null ? null : fromPostgresLosslessText(row.text, row.textCodecVersion),
222
+ payload: fromPostgresLosslessJson(row.payload, row.payloadCodecVersion),
155
223
  clientAckedAt: row.clientAckedAt?.toISOString() ?? null,
156
224
  providerAckedAt: row.providerAckedAt?.toISOString() ?? null,
157
225
  createdAt: row.createdAt.toISOString(),
@@ -187,7 +255,7 @@ export async function projectSessionRealtimeDelegationTerminalInTransaction(
187
255
  if (calls.length > 1) {
188
256
  throw new Error(`Delegation turn ${input.turnId} has multiple accepted realtime calls`);
189
257
  }
190
- const projected = terminalProjection(input);
258
+ const projected = buildSessionRealtimeDelegationTerminalProjection(input);
191
259
  const now = input.now ?? new Date();
192
260
  const call = calls[0] ?? null;
193
261
  const [mode] = call
@@ -225,10 +293,8 @@ export async function projectSessionRealtimeDelegationTerminalInTransaction(
225
293
  channel: "speakable",
226
294
  text: projected.text,
227
295
  payload: {
296
+ ...projected.payload,
228
297
  route: "session_context",
229
- status: input.turnStatus,
230
- terminalEventType: input.terminalEvent.type,
231
- terminal: boundedPayload(input.terminalEvent.payload),
232
298
  ...(call ? { priorRealtimeId: call.realtimeId } : {}),
233
299
  },
234
300
  now,
@@ -296,7 +362,9 @@ export async function projectSessionRealtimeDelegationTerminalInTransaction(
296
362
  delegationItemId: call.delegationItemId,
297
363
  turnId: input.turnId,
298
364
  text: projected.text,
365
+ textCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
299
366
  payload,
367
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
300
368
  createdAt: now,
301
369
  updatedAt: now,
302
370
  })
@@ -8,8 +8,8 @@ import type {
8
8
  } from "@opengeni/contracts";
9
9
  import { and, asc, eq, gt, inArray, isNull, or } from "drizzle-orm";
10
10
 
11
- import { sanitizeEventPayload } from "./event-payload-sanitizer";
12
- import type { Database } from "./database";
11
+ import type { Database, SessionActivityDatabase } from "./database";
12
+ import { LOSSLESS_CONTENT_CODEC_VERSION } from "./lossless-json";
13
13
  import { flushSessionRealtimeTranscriptTailInTransaction } from "./session-realtime-context";
14
14
  import {
15
15
  evaluateSessionControl,
@@ -161,7 +161,7 @@ function assertOwner(
161
161
  }
162
162
 
163
163
  async function appendRealtimeLifecycleEvent(
164
- db: Database,
164
+ db: SessionActivityDatabase,
165
165
  session: SessionRow,
166
166
  sequence: number,
167
167
  type: Extract<SessionEventType, "session.realtime.started" | "session.realtime.ended">,
@@ -185,7 +185,8 @@ async function appendRealtimeLifecycleEvent(
185
185
  sessionId: session.id,
186
186
  sequence,
187
187
  type,
188
- payload: sanitizeEventPayload(payload),
188
+ payload: payload,
189
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
189
190
  occurredAt: now,
190
191
  })
191
192
  .returning();
@@ -258,7 +259,7 @@ async function registerNormalModeWake(db: Database, session: SessionRow, reason:
258
259
  }
259
260
 
260
261
  async function endWithEvent(
261
- db: Database,
262
+ db: SessionActivityDatabase,
262
263
  session: SessionRow,
263
264
  row: RealtimeRow,
264
265
  reason: SessionRealtimeEndReason,
@@ -351,7 +352,7 @@ function assertRealtimeAdmission(session: SessionRow): void {
351
352
  }
352
353
 
353
354
  export async function beginSessionRealtimeInTransaction(
354
- db: Database,
355
+ db: SessionActivityDatabase,
355
356
  input: BeginSessionRealtimeInput,
356
357
  ): Promise<SessionRealtimeMutationResult> {
357
358
  const now = input.now ?? new Date();
@@ -552,7 +553,7 @@ export async function assertSessionRealtimeOwnerInTransaction(
552
553
  }
553
554
 
554
555
  export async function renewSessionRealtimeInTransaction(
555
- db: Database,
556
+ db: SessionActivityDatabase,
556
557
  input: RenewSessionRealtimeInput,
557
558
  ): Promise<RenewSessionRealtimeResult> {
558
559
  const now = input.now ?? new Date();
@@ -615,7 +616,7 @@ export async function renewSessionRealtimeInTransaction(
615
616
  }
616
617
 
617
618
  export async function endSessionRealtimeInTransaction(
618
- db: Database,
619
+ db: SessionActivityDatabase,
619
620
  input: EndSessionRealtimeInput,
620
621
  ): Promise<SessionRealtimeMutationResult> {
621
622
  const now = input.now ?? new Date();
@@ -648,7 +649,7 @@ export async function endSessionRealtimeInTransaction(
648
649
 
649
650
  /** Lazily settle an expired voice lease under the canonical session lock. */
650
651
  export async function settleExpiredSessionRealtimeInTransaction(
651
- db: Database,
652
+ db: SessionActivityDatabase,
652
653
  session: SessionRow,
653
654
  now = new Date(),
654
655
  ): Promise<SessionRow> {
@@ -2,8 +2,9 @@ import type { SessionEvent } from "@opengeni/contracts";
2
2
  import { boundModelToolOutputItem } from "@opengeni/codex";
3
3
  import { and, asc, eq, sql } from "drizzle-orm";
4
4
  import type { Database } from "./database";
5
- import { sanitizeEventPayload, sanitizeModelPayload } from "./event-payload-sanitizer";
5
+ import { fromPostgresLosslessJson, LOSSLESS_CONTENT_CODEC_VERSION } from "./lossless-json";
6
6
  import * as schema from "./schema";
7
+ import { cancelUnacceptedVideoGenerationsForToolCallsInTransaction } from "./video-generation";
7
8
 
8
9
  export const TOOL_RESULT_TYPE_BY_CALL_TYPE: Readonly<Record<string, string>> = {
9
10
  function_call: "function_call_result",
@@ -93,7 +94,7 @@ function mapEvent(row: typeof schema.sessionEvents.$inferSelect): SessionEvent {
93
94
  sessionId: row.sessionId,
94
95
  sequence: row.sequence,
95
96
  type: row.type as SessionEvent["type"],
96
- payload: row.payload,
97
+ payload: fromPostgresLosslessJson(row.payload, row.payloadCodecVersion),
97
98
  occurredAt: row.occurredAt.toISOString(),
98
99
  clientEventId: row.clientEventId,
99
100
  turnId: row.turnId,
@@ -115,7 +116,7 @@ export async function closePendingSessionToolCallsInTransaction(
115
116
  tx: Database,
116
117
  input: ClosePendingSessionToolCallsInput,
117
118
  ): Promise<{ sequence: number; events: SessionEvent[]; closed: number }> {
118
- const pending = await tx
119
+ const pendingRows = await tx
119
120
  .select()
120
121
  .from(schema.sessionPendingToolCalls)
121
122
  .where(
@@ -127,12 +128,21 @@ export async function closePendingSessionToolCallsInTransaction(
127
128
  )
128
129
  .orderBy(asc(schema.sessionPendingToolCalls.createdAt), asc(schema.sessionPendingToolCalls.id))
129
130
  .for("update");
131
+ const pending = pendingRows.map((row) => ({
132
+ ...row,
133
+ callItem: fromPostgresLosslessJson(row.callItem, row.callItemCodecVersion),
134
+ resultItem:
135
+ row.resultItem === null
136
+ ? null
137
+ : fromPostgresLosslessJson(row.resultItem, row.resultItemCodecVersion),
138
+ }));
130
139
  if (pending.length === 0) return { sequence: input.sequence, events: [], closed: 0 };
131
140
 
132
141
  const history = await tx
133
142
  .select({
134
143
  position: schema.sessionHistoryItems.position,
135
144
  item: schema.sessionHistoryItems.item,
145
+ itemCodecVersion: schema.sessionHistoryItems.itemCodecVersion,
136
146
  active: schema.sessionHistoryItems.active,
137
147
  })
138
148
  .from(schema.sessionHistoryItems)
@@ -144,6 +154,10 @@ export async function closePendingSessionToolCallsInTransaction(
144
154
  ),
145
155
  )
146
156
  .orderBy(asc(schema.sessionHistoryItems.position));
157
+ const decodedHistory = history.map((row) => ({
158
+ ...row,
159
+ item: fromPostgresLosslessJson(row.item, row.itemCodecVersion),
160
+ }));
147
161
  const [{ maxPosition } = { maxPosition: -1 }] = await tx
148
162
  .select({ maxPosition: sql<number>`coalesce(max(${schema.sessionHistoryItems.position}), -1)` })
149
163
  .from(schema.sessionHistoryItems)
@@ -173,23 +187,23 @@ export async function closePendingSessionToolCallsInTransaction(
173
187
  const eventValues: Array<typeof schema.sessionEvents.$inferInsert> = [];
174
188
  const resolutions = pending.map((call) => {
175
189
  const resultType = TOOL_RESULT_TYPE_BY_CALL_TYPE[call.callType];
176
- const existingCall = history.find(
190
+ const existingCall = decodedHistory.find(
177
191
  ({ item }) => historyItemType(item) === call.callType && historyCallId(item) === call.callId,
178
192
  );
179
193
  const existingResult = resultType
180
- ? history.find(
194
+ ? decodedHistory.find(
181
195
  ({ item, position }) =>
182
196
  position > (existingCall?.position ?? Number.MAX_SAFE_INTEGER) &&
183
197
  historyItemType(item) === resultType &&
184
198
  historyCallId(item) === call.callId,
185
199
  )
186
200
  : undefined;
187
- const activeCall = history.find(
201
+ const activeCall = decodedHistory.find(
188
202
  ({ item, active }) =>
189
203
  active && historyItemType(item) === call.callType && historyCallId(item) === call.callId,
190
204
  );
191
205
  const activeResult = resultType
192
- ? history.find(
206
+ ? decodedHistory.find(
193
207
  ({ item, active, position }) =>
194
208
  active &&
195
209
  position > (activeCall?.position ?? Number.MAX_SAFE_INTEGER) &&
@@ -232,7 +246,8 @@ export async function closePendingSessionToolCallsInTransaction(
232
246
  sessionId: input.sessionId,
233
247
  turnId: input.turnId,
234
248
  position: nextPosition++,
235
- item: sanitizeModelPayload(resolution.call.callItem),
249
+ item: resolution.call.callItem,
250
+ itemCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
236
251
  active: true,
237
252
  });
238
253
  }
@@ -255,12 +270,11 @@ export async function closePendingSessionToolCallsInTransaction(
255
270
  sessionId: input.sessionId,
256
271
  turnId: input.turnId,
257
272
  position: nextPosition++,
258
- item: sanitizeModelPayload(
259
- boundModelToolOutputItem(
260
- resolution.result,
261
- resolution.call.modelToolOutputTruncationTokens ?? undefined,
262
- ),
273
+ item: boundModelToolOutputItem(
274
+ resolution.result,
275
+ resolution.call.modelToolOutputTruncationTokens ?? undefined,
263
276
  ),
277
+ itemCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
264
278
  active: true,
265
279
  });
266
280
  }
@@ -280,7 +294,7 @@ export async function closePendingSessionToolCallsInTransaction(
280
294
  turnGeneration: resolution.call.executionGeneration,
281
295
  turnAttemptId: resolution.call.attemptId,
282
296
  turnAssociation: "current",
283
- payload: sanitizeEventPayload({
297
+ payload: {
284
298
  id: resolution.call.callId,
285
299
  output: resolution.interrupted
286
300
  ? {
@@ -302,7 +316,8 @@ export async function closePendingSessionToolCallsInTransaction(
302
316
  unsupportedCallShape:
303
317
  resolution.interrupted && (!resolution.result || !resolution.rawCallIsValid),
304
318
  },
305
- }),
319
+ },
320
+ payloadCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
306
321
  occurredAt: input.now,
307
322
  });
308
323
  }
@@ -312,6 +327,14 @@ export async function closePendingSessionToolCallsInTransaction(
312
327
  eventValues.length > 0
313
328
  ? await tx.insert(schema.sessionEvents).values(eventValues).returning()
314
329
  : [];
330
+ await cancelUnacceptedVideoGenerationsForToolCallsInTransaction(tx, {
331
+ workspaceId: input.workspaceId,
332
+ sessionId: input.sessionId,
333
+ turnId: input.turnId,
334
+ toolCallIds: pending.map((call) => call.callId),
335
+ reason: input.reason,
336
+ now: input.now,
337
+ });
315
338
  await tx
316
339
  .delete(schema.sessionPendingToolCalls)
317
340
  .where(