@opengeni/db 0.28.9 → 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 (163) 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-VHBFHMPC.js → chunk-YHZXQ7HP.js} +754 -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/generated-images.d.ts +139 -0
  35. package/dist/index.d.ts +698 -111
  36. package/dist/index.js +27573 -10322
  37. package/dist/index.js.map +1 -1
  38. package/dist/insights.d.ts +51 -4
  39. package/dist/integration-bindings.d.ts +70 -0
  40. package/dist/integration-features.d.ts +99 -0
  41. package/dist/interaction-revisions.d.ts +3 -0
  42. package/dist/interaction-schema.d.ts +5372 -0
  43. package/dist/knowledge-source-sync-schema.d.ts +1679 -0
  44. package/dist/knowledge-source-sync.d.ts +274 -0
  45. package/dist/memory-governance.d.ts +2 -2
  46. package/dist/memory-slack-delivery.d.ts +101 -0
  47. package/dist/new-session-drafts.d.ts +2 -2
  48. package/dist/pack-components.d.ts +76 -0
  49. package/dist/pack-installations.d.ts +86 -0
  50. package/dist/persistence-errors.d.ts +3 -3
  51. package/dist/plugin-packages.d.ts +126 -0
  52. package/dist/preference-registry.d.ts +1 -1
  53. package/dist/provision-roles.d.ts +9 -1
  54. package/dist/provision-roles.js +1 -1
  55. package/dist/runtime-posture.d.ts +18 -6
  56. package/dist/schema.d.ts +18342 -9099
  57. package/dist/schema.js +165 -1
  58. package/dist/scoped-knowledge.d.ts +97 -1
  59. package/dist/session-control.d.ts +4 -4
  60. package/dist/session-queue-commands.d.ts +19 -11
  61. package/dist/session-realtime-context.d.ts +2 -2
  62. package/dist/session-realtime-ledger.d.ts +4 -4
  63. package/dist/session-realtime-mirror.d.ts +2 -2
  64. package/dist/session-realtime-state.d.ts +1 -1
  65. package/dist/session-realtime-terminal.d.ts +1 -1
  66. package/dist/session-realtime.d.ts +7 -7
  67. package/dist/session-tool-call-settlement.d.ts +1 -1
  68. package/dist/slack-user-link-access.d.ts +54 -0
  69. package/dist/transcription-recordings.d.ts +2 -2
  70. package/dist/turn-initiator.d.ts +2 -2
  71. package/dist/video-generation.d.ts +216 -0
  72. package/dist/video-generation.js +66 -0
  73. package/dist/video-generation.js.map +1 -0
  74. package/dist/workspace-artifacts.d.ts +1 -1
  75. package/dist/workspace-instruction-policies.d.ts +1 -1
  76. package/dist/workspace-learning-policy-schema.d.ts +932 -0
  77. package/dist/workspace-learning-policy.d.ts +161 -0
  78. package/drizzle/0183_model_call_provider_cost_estimates.sql +39 -0
  79. package/drizzle/0184_sandbox_drain_teardown_fence.sql +682 -0
  80. package/drizzle/0185_temporal_schedule_cleanup_outbox.sql +168 -0
  81. package/drizzle/0186_sandbox_capture_provider_contract.sql +400 -0
  82. package/drizzle/0187_generated_image_artifacts.sql +173 -0
  83. package/drizzle/0188_image_generation_retention_failure.sql +25 -0
  84. package/drizzle/0189_retained_session_image_formats.sql +13 -0
  85. package/drizzle/0190_timeline_annotations.sql +31 -0
  86. package/drizzle/0191_editable_artifact_engine.sql +3853 -0
  87. package/drizzle/0192_editable_artifact_live_tickets.sql +338 -0
  88. package/drizzle/0193_editable_artifact_authorization.sql +190 -0
  89. package/drizzle/0194_editable_artifact_durable_exports.sql +160 -0
  90. package/drizzle/0195_editable_artifact_import_authorization.sql +203 -0
  91. package/drizzle/0196_rig_provider_images.sql +152 -0
  92. package/drizzle/0197_knowledge_source_sync_schedules.sql +523 -0
  93. package/drizzle/0198_memory_slack_publication_delivery.sql +393 -0
  94. package/drizzle/0199_workspace_learning_policy.sql +980 -0
  95. package/drizzle/0201_company_profile_authority.sql +849 -0
  96. package/drizzle/0202_document_index_checkpoints.sql +85 -0
  97. package/drizzle/0203_durable_video_generation.sql +353 -0
  98. package/drizzle/0204_video_generation_funding.sql +44 -0
  99. package/drizzle/0205_attempt_tool_catalogs.sql +230 -0
  100. package/drizzle/0206_browser_sessions.sql +646 -0
  101. package/drizzle/0207_browser_identities.sql +379 -0
  102. package/drizzle/0208_attached_browser_devices.sql +165 -0
  103. package/drizzle/0209_computer_sessions.sql +575 -0
  104. package/drizzle/0210_browser_auth_network_interventions.sql +441 -0
  105. package/drizzle/0211_editable_artifact_session_links.sql +58 -0
  106. package/drizzle/0212_slack_installation_bindings.sql +348 -0
  107. package/drizzle/0213_slack_user_link_access_requests.sql +177 -0
  108. package/drizzle/0214_session_activity_commit_gate.sql +262 -0
  109. package/drizzle/0215_capabilities_platform.sql +980 -0
  110. package/drizzle/0216_pack_component_ownership.sql +235 -0
  111. package/drizzle/0217_capability_definition_delete_authority.sql +32 -0
  112. package/package.json +18 -5
  113. package/src/attached-browser-devices.ts +371 -0
  114. package/src/attempt-tool-catalogs.ts +131 -0
  115. package/src/browser-auth.ts +1896 -0
  116. package/src/browser-identities.ts +1168 -0
  117. package/src/browser-sessions.ts +2005 -0
  118. package/src/browser-state-artifacts.ts +59 -0
  119. package/src/capability-components.ts +166 -0
  120. package/src/capability-integrations.ts +1663 -0
  121. package/src/codemode-operations.ts +674 -0
  122. package/src/company-profile-schema.ts +143 -0
  123. package/src/company-profile.ts +968 -0
  124. package/src/computer-sessions.ts +1130 -0
  125. package/src/connection-token-resolver.ts +270 -25
  126. package/src/database.ts +427 -23
  127. package/src/editable-artifact-durable-export.ts +1201 -0
  128. package/src/editable-artifact-materialization.ts +893 -0
  129. package/src/editable-artifacts-schema.ts +879 -0
  130. package/src/editable-artifacts.ts +5404 -0
  131. package/src/generated-images.ts +740 -0
  132. package/src/index.ts +5917 -1182
  133. package/src/insights.ts +160 -13
  134. package/src/integration-bindings.ts +455 -0
  135. package/src/integration-features.ts +859 -0
  136. package/src/interaction-revisions.ts +40 -0
  137. package/src/interaction-schema.ts +1303 -0
  138. package/src/knowledge-source-sync-schema.ts +192 -0
  139. package/src/knowledge-source-sync.ts +1922 -0
  140. package/src/memory-slack-delivery.ts +801 -0
  141. package/src/pack-components.ts +954 -0
  142. package/src/pack-installations.ts +929 -0
  143. package/src/persistence-errors.ts +4 -7
  144. package/src/plugin-packages.ts +1186 -0
  145. package/src/provision-roles.ts +302 -1
  146. package/src/runtime-posture-cli.ts +9 -0
  147. package/src/runtime-posture.ts +508 -5
  148. package/src/schema.ts +5117 -3119
  149. package/src/scoped-knowledge-schema.ts +1 -1
  150. package/src/scoped-knowledge.ts +655 -3
  151. package/src/session-control.ts +8 -5
  152. package/src/session-queue-commands.ts +187 -14
  153. package/src/session-realtime-context.ts +2 -2
  154. package/src/session-realtime-ledger.ts +3 -3
  155. package/src/session-realtime.ts +7 -7
  156. package/src/session-tool-call-settlement.ts +9 -0
  157. package/src/slack-user-link-access.ts +702 -0
  158. package/src/video-generation.ts +1452 -0
  159. package/src/workspace-learning-policy-schema.ts +139 -0
  160. package/src/workspace-learning-policy.ts +595 -0
  161. package/dist/chunk-P6CUHXQZ.js +0 -7248
  162. package/dist/chunk-P6CUHXQZ.js.map +0 -1
  163. package/dist/chunk-VHBFHMPC.js.map +0 -1
@@ -7,7 +7,7 @@ import {
7
7
  type TurnInitiatorContext,
8
8
  } from "@opengeni/contracts";
9
9
  import { and, eq, inArray, sql } from "drizzle-orm";
10
- import type { Database } from "./database";
10
+ import type { Database, SessionActivityDatabase } from "./database";
11
11
  import { withLosslessContentWriteVersion } from "./lossless-json";
12
12
  import * as schema from "./schema";
13
13
  import { closePendingSessionToolCallsInTransaction } from "./session-tool-call-settlement";
@@ -1163,7 +1163,10 @@ export async function evaluateSessionDiscoveryControls(
1163
1163
  );
1164
1164
  }
1165
1165
 
1166
- const workspace = await lockWorkspaceInferenceControl(db, workspaceId, "share");
1166
+ // Discovery owns one read-only repeatable-read snapshot, so this projection
1167
+ // must not join the writer lock graph merely to keep workspace/session facts
1168
+ // coherent. The snapshot is the consistency boundary.
1169
+ const workspace = await lockWorkspaceInferenceControl(db, workspaceId, "none");
1167
1170
  const workspacePauseRevision = asSafeRevision(
1168
1171
  workspace.workspacePauseRevision,
1169
1172
  "workspace pause revision",
@@ -2050,7 +2053,7 @@ async function assertSessionBranchIsNotCancelled(
2050
2053
  }
2051
2054
 
2052
2055
  async function cancelSessionSubtreeInTransaction(
2053
- db: Database,
2056
+ db: SessionActivityDatabase,
2054
2057
  input: {
2055
2058
  accountId: string;
2056
2059
  workspaceId: string;
@@ -2375,7 +2378,7 @@ async function cancelSessionSubtreeInTransaction(
2375
2378
  }
2376
2379
 
2377
2380
  export async function mutateSessionControlInTransaction(
2378
- db: Database,
2381
+ db: SessionActivityDatabase,
2379
2382
  input: {
2380
2383
  accountId: string;
2381
2384
  workspaceId: string;
@@ -2694,7 +2697,7 @@ export async function mutateSessionControlInTransaction(
2694
2697
  }
2695
2698
 
2696
2699
  export async function autoResumeSessionBranchInTransaction(
2697
- db: Database,
2700
+ db: SessionActivityDatabase,
2698
2701
  input: {
2699
2702
  workspaceId: string;
2700
2703
  sessionId: string;
@@ -1,19 +1,36 @@
1
1
  import {
2
+ DraftTimelineAnnotations,
2
3
  McpPersonalConnectionDelegations,
4
+ TimelineAnnotations,
3
5
  metadataWithTurnExecutionPolicyV1,
4
6
  mergeResourceRefs,
7
+ renderTimelineAnnotationsForModel,
5
8
  ResourceRef,
6
9
  resourceMountPath,
7
10
  stableJson,
8
11
  turnExecutionPolicyAuditMetadata,
9
12
  type McpPersonalConnectionDelegation,
13
+ type DraftTimelineAnnotation,
10
14
  type LatencyMode,
11
15
  type ReasoningEffort,
16
+ type SandboxBackend,
17
+ type SandboxOs,
18
+ type SessionEvent,
19
+ type SessionEventType,
20
+ type SessionTurn,
21
+ type SessionTurnSource,
22
+ type SessionTurnStatus,
23
+ type ToolRef,
12
24
  type TurnExecutionPolicyV1,
25
+ type TimelineAnnotation,
13
26
  } from "@opengeni/contracts";
14
27
  import { and, asc, eq, inArray, sql } from "drizzle-orm";
15
- import type { Database } from "./database";
16
- import { withLosslessContentWriteVersion } from "./lossless-json";
28
+ import type { Database, SessionActivityDatabase } from "./database";
29
+ import {
30
+ fromPostgresLosslessJson,
31
+ fromPostgresLosslessText,
32
+ withLosslessContentWriteVersion,
33
+ } from "./lossless-json";
17
34
  import { closePendingSessionToolCallsInTransaction } from "./session-tool-call-settlement";
18
35
  import {
19
36
  assertAgentCommandAuthorityInTransaction,
@@ -97,6 +114,10 @@ export type SteerQueueCommandResult = QueueCommandResult & {
97
114
  export type SubmitHumanPromptResult = {
98
115
  receipt: SessionCommandReceiptRow;
99
116
  queueVersion: number;
117
+ accepted: SessionEvent;
118
+ events: SessionEvent[];
119
+ turn: SessionTurn;
120
+ /** Backward-compatible row identities for lower-level callers. */
100
121
  acceptedEventId: string;
101
122
  eventIds: string[];
102
123
  turnId: string;
@@ -106,6 +127,69 @@ export type SubmitHumanPromptResult = {
106
127
  replay: boolean;
107
128
  };
108
129
 
130
+ function mapSubmittedPromptEvent(row: typeof schema.sessionEvents.$inferSelect): SessionEvent {
131
+ return {
132
+ id: row.id,
133
+ workspaceId: row.workspaceId,
134
+ sessionId: row.sessionId,
135
+ sequence: row.sequence,
136
+ type: row.type as SessionEventType,
137
+ payload: fromPostgresLosslessJson(row.payload, row.payloadCodecVersion),
138
+ occurredAt: row.occurredAt.toISOString(),
139
+ clientEventId: row.clientEventId,
140
+ turnId: row.turnId,
141
+ turnGeneration: row.turnGeneration,
142
+ turnAttemptId: row.turnAttemptId,
143
+ turnAssociation: row.turnAssociation as SessionEvent["turnAssociation"],
144
+ duplicateOfEventId: row.duplicateOfEventId,
145
+ duplicateReason: row.duplicateReason,
146
+ };
147
+ }
148
+
149
+ function mapSubmittedPromptTurn(row: typeof schema.sessionTurns.$inferSelect): SessionTurn {
150
+ const personalConnections = McpPersonalConnectionDelegations.parse(
151
+ row.personalConnectionDelegations,
152
+ ).map(({ serverId, providerDomain }) => ({ serverId, providerDomain }));
153
+ return {
154
+ id: row.id,
155
+ workspaceId: row.workspaceId,
156
+ sessionId: row.sessionId,
157
+ triggerEventId: row.triggerEventId,
158
+ temporalWorkflowId: row.temporalWorkflowId,
159
+ status: row.status as SessionTurnStatus,
160
+ source: row.source as SessionTurnSource,
161
+ position: row.position,
162
+ prompt: fromPostgresLosslessText(row.prompt, row.promptCodecVersion),
163
+ annotations: TimelineAnnotations.parse(row.annotations),
164
+ resources: row.resources as ResourceRef[],
165
+ tools: row.tools as ToolRef[],
166
+ toolsProvided: row.toolsProvided,
167
+ model: row.model,
168
+ reasoningEffort: row.reasoningEffort as ReasoningEffort,
169
+ latencyMode: (row.latencyMode as LatencyMode | null | undefined) ?? "standard",
170
+ sandboxBackend: row.sandboxBackend as SandboxBackend,
171
+ sandboxOs: (row.sandboxOs as SandboxOs | null) ?? null,
172
+ metadata: row.metadata,
173
+ version: row.version,
174
+ executionGeneration: row.executionGeneration,
175
+ activeAttemptId: row.activeAttemptId,
176
+ lineage: row.lineage,
177
+ initiator: initiatorFromStorage(
178
+ row.initiatorKind,
179
+ row.initiatorSubjectId,
180
+ row.initiatorContext ?? {},
181
+ ),
182
+ initiatorContext: row.initiatorContext ?? {},
183
+ personalConnections,
184
+ cancelledBy: row.cancelledBy,
185
+ cancelReason: row.cancelReason,
186
+ startedAt: row.startedAt ? row.startedAt.toISOString() : null,
187
+ finishedAt: row.finishedAt ? row.finishedAt.toISOString() : null,
188
+ createdAt: row.createdAt.toISOString(),
189
+ updatedAt: row.updatedAt.toISOString(),
190
+ };
191
+ }
192
+
109
193
  export type AgentInternalUpdateCommandResult = {
110
194
  receipt: SessionCommandReceiptRow;
111
195
  updateId: string;
@@ -414,7 +498,7 @@ async function loadQueuedTurns(
414
498
  }
415
499
 
416
500
  async function normalizeQueuePositions(
417
- db: Database,
501
+ db: SessionActivityDatabase,
418
502
  workspaceId: string,
419
503
  sessionId: string,
420
504
  orderedIds: string[],
@@ -446,7 +530,19 @@ async function normalizeQueuePositions(
446
530
  }
447
531
 
448
532
  function draftIsNonEmpty(draft: ComposerDraftRow): boolean {
449
- return draft.text.length > 0 || draft.resources.length > 0 || draft.sourceTurnId !== null;
533
+ return (
534
+ draft.text.length > 0 ||
535
+ DraftTimelineAnnotations.parse(draft.annotations).length > 0 ||
536
+ draft.resources.length > 0 ||
537
+ draft.sourceTurnId !== null
538
+ );
539
+ }
540
+
541
+ function draftAnnotationsFromTurn(value: unknown): DraftTimelineAnnotation[] {
542
+ return TimelineAnnotations.parse(value).map(({ ordinal: _ordinal, ...annotation }) => ({
543
+ ...annotation,
544
+ source: { ...annotation.source },
545
+ }));
450
546
  }
451
547
 
452
548
  function withCanonicalResourceMountPaths(resources: readonly unknown[]): unknown[] {
@@ -503,6 +599,7 @@ export async function saveComposerDraftInTransaction(
503
599
  subjectId: string;
504
600
  expectedRevision: number;
505
601
  text: string;
602
+ annotations?: DraftTimelineAnnotation[];
506
603
  resources: ResourceRef[];
507
604
  model: string;
508
605
  reasoningEffort: ReasoningEffort;
@@ -534,6 +631,7 @@ export async function saveComposerDraftInTransaction(
534
631
  subjectId: input.subjectId,
535
632
  revision,
536
633
  text: input.text,
634
+ annotations: DraftTimelineAnnotations.parse(input.annotations ?? []),
537
635
  resources: withCanonicalResourceMountPaths(input.resources),
538
636
  tools: [],
539
637
  toolsProvided: false,
@@ -559,7 +657,7 @@ export async function saveComposerDraftInTransaction(
559
657
  }
560
658
 
561
659
  export async function moveQueuedTurnInTransaction(
562
- db: Database,
660
+ db: SessionActivityDatabase,
563
661
  input: {
564
662
  accountId: string;
565
663
  workspaceId: string;
@@ -695,7 +793,7 @@ export async function moveQueuedTurnInTransaction(
695
793
  }
696
794
 
697
795
  export async function deleteSessionQueueItemInTransaction(
698
- db: Database,
796
+ db: SessionActivityDatabase,
699
797
  input: {
700
798
  accountId: string;
701
799
  workspaceId: string;
@@ -826,7 +924,7 @@ export async function deleteSessionQueueItemInTransaction(
826
924
  }
827
925
 
828
926
  export async function editQueuedTurnInTransaction(
829
- db: Database,
927
+ db: SessionActivityDatabase,
830
928
  input: {
831
929
  accountId: string;
832
930
  workspaceId: string;
@@ -919,6 +1017,7 @@ export async function editQueuedTurnInTransaction(
919
1017
  subjectId: input.subjectId,
920
1018
  revision: nextDraftRevision,
921
1019
  text: turn.prompt,
1020
+ annotations: draftAnnotationsFromTurn(turn.annotations),
922
1021
  resources: withCanonicalResourceMountPaths(turn.resources),
923
1022
  tools: [],
924
1023
  toolsProvided: false,
@@ -1007,7 +1106,7 @@ export async function editQueuedTurnInTransaction(
1007
1106
  }
1008
1107
 
1009
1108
  export async function steerQueuedTurnInTransaction(
1010
- db: Database,
1109
+ db: SessionActivityDatabase,
1011
1110
  input: {
1012
1111
  accountId: string;
1013
1112
  workspaceId: string;
@@ -1240,7 +1339,7 @@ export async function steerQueuedTurnInTransaction(
1240
1339
  }
1241
1340
 
1242
1341
  export async function submitHumanPromptInTransaction(
1243
- db: Database,
1342
+ db: SessionActivityDatabase,
1244
1343
  input: {
1245
1344
  accountId: string;
1246
1345
  workspaceId: string;
@@ -1253,6 +1352,7 @@ export async function submitHumanPromptInTransaction(
1253
1352
  controlEtag?: string | null;
1254
1353
  expectedDraftRevision?: number | null;
1255
1354
  text: string;
1355
+ annotations?: TimelineAnnotation[];
1256
1356
  turnInstructions?: string | null;
1257
1357
  resources: ResourceRef[];
1258
1358
  model?: string | null;
@@ -1270,6 +1370,8 @@ export async function submitHumanPromptInTransaction(
1270
1370
  context: string;
1271
1371
  };
1272
1372
  source: "user" | "api";
1373
+ /** Record the admitted run's durable usage fact in this transaction. */
1374
+ recordAgentRunUsage?: boolean;
1273
1375
  personalConnectionDelegations?: McpPersonalConnectionDelegation[];
1274
1376
  mcpCredentialUpdates?: Array<{
1275
1377
  id: string;
@@ -1277,6 +1379,7 @@ export async function submitHumanPromptInTransaction(
1277
1379
  }>;
1278
1380
  },
1279
1381
  ): Promise<SubmitHumanPromptResult> {
1382
+ const annotations = TimelineAnnotations.parse(input.annotations ?? []);
1280
1383
  const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "update");
1281
1384
  await lockSessionEventWriteRows(db, {
1282
1385
  workspaceId: input.workspaceId,
@@ -1293,6 +1396,7 @@ export async function submitHumanPromptInTransaction(
1293
1396
  controlEtag: input.controlEtag ?? null,
1294
1397
  expectedDraftRevision: input.expectedDraftRevision ?? null,
1295
1398
  text: input.text,
1399
+ annotations,
1296
1400
  turnInstructions: input.turnInstructions ?? null,
1297
1401
  resources: withCanonicalResourceMountPaths(input.resources),
1298
1402
  model: input.model ?? null,
@@ -1332,9 +1436,39 @@ export async function submitHumanPromptInTransaction(
1332
1436
  if (!turnId || !acceptedEventId || wakeRevision < 1) {
1333
1437
  throw new SessionControlInvariantError("Replayed prompt receipt is incomplete");
1334
1438
  }
1439
+ const replayEvents = await db
1440
+ .select()
1441
+ .from(schema.sessionEvents)
1442
+ .where(
1443
+ and(
1444
+ eq(schema.sessionEvents.workspaceId, input.workspaceId),
1445
+ eq(schema.sessionEvents.sessionId, input.sessionId),
1446
+ inArray(schema.sessionEvents.id, eventIds),
1447
+ ),
1448
+ )
1449
+ .orderBy(asc(schema.sessionEvents.sequence));
1450
+ const [replayTurn] = await db
1451
+ .select()
1452
+ .from(schema.sessionTurns)
1453
+ .where(
1454
+ and(
1455
+ eq(schema.sessionTurns.workspaceId, input.workspaceId),
1456
+ eq(schema.sessionTurns.sessionId, input.sessionId),
1457
+ eq(schema.sessionTurns.id, turnId),
1458
+ ),
1459
+ )
1460
+ .limit(1);
1461
+ const events = replayEvents.map(mapSubmittedPromptEvent);
1462
+ const accepted = events.find((event) => event.id === acceptedEventId);
1463
+ if (!accepted || !replayTurn || events.length !== eventIds.length) {
1464
+ throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
1465
+ }
1335
1466
  return {
1336
1467
  receipt: reserved.receipt,
1337
1468
  queueVersion: Number(reserved.receipt.appliedQueueVersion),
1469
+ accepted,
1470
+ events,
1471
+ turn: mapSubmittedPromptTurn(replayTurn),
1338
1472
  acceptedEventId,
1339
1473
  eventIds,
1340
1474
  turnId,
@@ -1404,6 +1538,7 @@ export async function submitHumanPromptInTransaction(
1404
1538
  draft &&
1405
1539
  canonicalSessionCommandHash({
1406
1540
  text: draft.text,
1541
+ annotations: DraftTimelineAnnotations.parse(draft.annotations),
1407
1542
  resources: withCanonicalResourceMountPaths(draft.resources),
1408
1543
  model: draft.model,
1409
1544
  reasoningEffort: draft.reasoningEffort,
@@ -1411,6 +1546,7 @@ export async function submitHumanPromptInTransaction(
1411
1546
  }) !==
1412
1547
  canonicalSessionCommandHash({
1413
1548
  text: input.text,
1549
+ annotations: annotations.map(({ ordinal: _ordinal, ...annotation }) => annotation),
1414
1550
  resources: withCanonicalResourceMountPaths(input.resources),
1415
1551
  model: input.model ?? session.model,
1416
1552
  reasoningEffort: input.reasoningEffort ?? input.reasoningEffortFallback,
@@ -1531,6 +1667,7 @@ export async function submitHumanPromptInTransaction(
1531
1667
  clientEventId: input.operationKey,
1532
1668
  payload: {
1533
1669
  text: input.messagePresentation?.text ?? input.text,
1670
+ ...(annotations.length > 0 ? { annotations } : {}),
1534
1671
  ...(input.messagePresentation
1535
1672
  ? {
1536
1673
  presentation: {
@@ -1565,6 +1702,7 @@ export async function submitHumanPromptInTransaction(
1565
1702
  source: input.source,
1566
1703
  position: input.delivery === "steer" ? 0 : existingQueued.length + 1,
1567
1704
  prompt: input.text,
1705
+ annotations,
1568
1706
  turnInstructions:
1569
1707
  editedSourceTurnInstructions !== undefined
1570
1708
  ? editedSourceTurnInstructions
@@ -1601,6 +1739,7 @@ export async function submitHumanPromptInTransaction(
1601
1739
  )
1602
1740
  .returning();
1603
1741
  if (!turn) throw new SessionControlInvariantError("Prompt turn was not inserted");
1742
+ let committedTurn = turn;
1604
1743
  eventValues.push({
1605
1744
  accountId: input.accountId,
1606
1745
  workspaceId: input.workspaceId,
@@ -1651,7 +1790,7 @@ export async function submitHumanPromptInTransaction(
1651
1790
  // settlement has already cleared sessions.active_turn_id. Do not infer this
1652
1791
  // state from a local request spinner or queue position.
1653
1792
  if (input.delivery === "steer") {
1654
- await db
1793
+ const [updatedTurn] = await db
1655
1794
  .update(schema.sessionTurns)
1656
1795
  .set({
1657
1796
  metadata: {
@@ -1669,7 +1808,12 @@ export async function submitHumanPromptInTransaction(
1669
1808
  eq(schema.sessionTurns.sessionId, input.sessionId),
1670
1809
  eq(schema.sessionTurns.id, turnId),
1671
1810
  ),
1672
- );
1811
+ )
1812
+ .returning();
1813
+ if (!updatedTurn) {
1814
+ throw new SessionControlInvariantError("Steer prompt turn metadata was not updated");
1815
+ }
1816
+ committedTurn = updatedTurn;
1673
1817
  }
1674
1818
  if (supersession.replacedTurn) {
1675
1819
  const current = supersession.replacedTurn;
@@ -1749,7 +1893,7 @@ export async function submitHumanPromptInTransaction(
1749
1893
  text: renderRealtimeHumanInputContext({
1750
1894
  delivery: input.delivery,
1751
1895
  routing: realtimeRouting,
1752
- text: input.text,
1896
+ text: renderTimelineAnnotationsForModel(input.text, annotations),
1753
1897
  }),
1754
1898
  payload: {
1755
1899
  delivery: input.delivery,
@@ -1811,6 +1955,27 @@ export async function submitHumanPromptInTransaction(
1811
1955
  "metadataCodecVersion",
1812
1956
  ),
1813
1957
  );
1958
+ if (input.recordAgentRunUsage) {
1959
+ await db
1960
+ .insert(schema.usageEvents)
1961
+ .values({
1962
+ accountId: input.accountId,
1963
+ workspaceId: input.workspaceId,
1964
+ subjectId: input.subjectId,
1965
+ eventType: "agent_run.created",
1966
+ quantity: 1,
1967
+ unit: "run",
1968
+ sourceResourceType: "session_turn",
1969
+ sourceResourceId: turnId,
1970
+ sessionId: input.sessionId,
1971
+ turnId,
1972
+ ...initiatorColumns(frozenInitiator),
1973
+ origin: input.source,
1974
+ idempotencyKey: `agent_run.created:${input.workspaceId}:${turnId}`,
1975
+ occurredAt: now,
1976
+ })
1977
+ .onConflictDoNothing({ target: schema.usageEvents.idempotencyKey });
1978
+ }
1814
1979
  const eventIds = eventRows.map((event) => event.id);
1815
1980
  const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
1816
1981
  controlRevision: resumed.revision,
@@ -1832,9 +1997,17 @@ export async function submitHumanPromptInTransaction(
1832
1997
  : {}),
1833
1998
  },
1834
1999
  });
2000
+ const events = eventRows.map(mapSubmittedPromptEvent);
2001
+ const accepted = events.find((event) => event.id === acceptedEventId);
2002
+ if (!accepted) {
2003
+ throw new SessionControlInvariantError("Inserted user.message event is missing");
2004
+ }
1835
2005
  return {
1836
2006
  receipt,
1837
2007
  queueVersion,
2008
+ accepted,
2009
+ events,
2010
+ turn: mapSubmittedPromptTurn(committedTurn),
1838
2011
  acceptedEventId,
1839
2012
  eventIds,
1840
2013
  turnId,
@@ -1846,7 +2019,7 @@ export async function submitHumanPromptInTransaction(
1846
2019
  }
1847
2020
 
1848
2021
  export async function sendAgentMessageInTransaction(
1849
- db: Database,
2022
+ db: SessionActivityDatabase,
1850
2023
  input: {
1851
2024
  accountId: string;
1852
2025
  workspaceId: string;
@@ -2050,7 +2223,7 @@ export async function sendAgentMessageInTransaction(
2050
2223
  }
2051
2224
 
2052
2225
  export async function steerAgentSessionInTransaction(
2053
- db: Database,
2226
+ db: SessionActivityDatabase,
2054
2227
  input: {
2055
2228
  accountId: string;
2056
2229
  workspaceId: string;
@@ -3,7 +3,7 @@ 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
7
  import { fromPostgresLosslessJson, fromPostgresLosslessText } from "./lossless-json";
8
8
  import * as schema from "./schema";
9
9
  import { submitHumanPromptInTransaction } from "./session-queue-commands";
@@ -178,7 +178,7 @@ function mapProjection(
178
178
  * delegation into the same canonical Steer-or-start path used by a human.
179
179
  */
180
180
  export async function flushSessionRealtimeTranscriptTailInTransaction(
181
- db: Database,
181
+ db: SessionActivityDatabase,
182
182
  input: {
183
183
  accountId: string;
184
184
  workspaceId: string;
@@ -3,7 +3,7 @@ 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 type { Database } from "./database";
6
+ import type { Database, SessionActivityDatabase } from "./database";
7
7
  import {
8
8
  fromPostgresLosslessJson,
9
9
  fromPostgresLosslessText,
@@ -1075,7 +1075,7 @@ async function appendInvalidDelegationFailure(
1075
1075
  }
1076
1076
 
1077
1077
  async function admitRealtimeDelegationInTransaction(
1078
- db: Database,
1078
+ db: SessionActivityDatabase,
1079
1079
  input: Pick<
1080
1080
  SyncSessionRealtimeLedgerInput,
1081
1081
  "workspaceId" | "sessionId" | "realtimeId" | "connectionEpoch" | "ownerSubjectId"
@@ -1268,7 +1268,7 @@ function assertProviderAckSequences(values: number[] | undefined, maximum: numbe
1268
1268
  }
1269
1269
 
1270
1270
  export async function syncSessionRealtimeLedgerInTransaction(
1271
- db: Database,
1271
+ db: SessionActivityDatabase,
1272
1272
  input: SyncSessionRealtimeLedgerInput,
1273
1273
  hooks: SyncSessionRealtimeLedgerHooks = {},
1274
1274
  ): Promise<SyncSessionRealtimeLedgerResult> {
@@ -8,7 +8,7 @@ import type {
8
8
  } from "@opengeni/contracts";
9
9
  import { and, asc, eq, gt, inArray, isNull, or } from "drizzle-orm";
10
10
 
11
- import type { Database } from "./database";
11
+ import type { Database, SessionActivityDatabase } from "./database";
12
12
  import { LOSSLESS_CONTENT_CODEC_VERSION } from "./lossless-json";
13
13
  import { flushSessionRealtimeTranscriptTailInTransaction } from "./session-realtime-context";
14
14
  import {
@@ -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">,
@@ -259,7 +259,7 @@ async function registerNormalModeWake(db: Database, session: SessionRow, reason:
259
259
  }
260
260
 
261
261
  async function endWithEvent(
262
- db: Database,
262
+ db: SessionActivityDatabase,
263
263
  session: SessionRow,
264
264
  row: RealtimeRow,
265
265
  reason: SessionRealtimeEndReason,
@@ -352,7 +352,7 @@ function assertRealtimeAdmission(session: SessionRow): void {
352
352
  }
353
353
 
354
354
  export async function beginSessionRealtimeInTransaction(
355
- db: Database,
355
+ db: SessionActivityDatabase,
356
356
  input: BeginSessionRealtimeInput,
357
357
  ): Promise<SessionRealtimeMutationResult> {
358
358
  const now = input.now ?? new Date();
@@ -553,7 +553,7 @@ export async function assertSessionRealtimeOwnerInTransaction(
553
553
  }
554
554
 
555
555
  export async function renewSessionRealtimeInTransaction(
556
- db: Database,
556
+ db: SessionActivityDatabase,
557
557
  input: RenewSessionRealtimeInput,
558
558
  ): Promise<RenewSessionRealtimeResult> {
559
559
  const now = input.now ?? new Date();
@@ -616,7 +616,7 @@ export async function renewSessionRealtimeInTransaction(
616
616
  }
617
617
 
618
618
  export async function endSessionRealtimeInTransaction(
619
- db: Database,
619
+ db: SessionActivityDatabase,
620
620
  input: EndSessionRealtimeInput,
621
621
  ): Promise<SessionRealtimeMutationResult> {
622
622
  const now = input.now ?? new Date();
@@ -649,7 +649,7 @@ export async function endSessionRealtimeInTransaction(
649
649
 
650
650
  /** Lazily settle an expired voice lease under the canonical session lock. */
651
651
  export async function settleExpiredSessionRealtimeInTransaction(
652
- db: Database,
652
+ db: SessionActivityDatabase,
653
653
  session: SessionRow,
654
654
  now = new Date(),
655
655
  ): Promise<SessionRow> {
@@ -4,6 +4,7 @@ import { and, asc, eq, sql } from "drizzle-orm";
4
4
  import type { Database } from "./database";
5
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",
@@ -326,6 +327,14 @@ export async function closePendingSessionToolCallsInTransaction(
326
327
  eventValues.length > 0
327
328
  ? await tx.insert(schema.sessionEvents).values(eventValues).returning()
328
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
+ });
329
338
  await tx
330
339
  .delete(schema.sessionPendingToolCalls)
331
340
  .where(