@opengeni/db 1.0.1 → 3.2.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/dist/attached-browser-devices.d.ts +7 -0
  2. package/dist/automations.d.ts +154 -0
  3. package/dist/canonical-human-identities.js +3 -3
  4. package/dist/capability-integrations.d.ts +13 -0
  5. package/dist/child-lifecycle-notices.d.ts +68 -0
  6. package/dist/{chunk-4SR4HKKA.js → chunk-2EH4WRHL.js} +19 -11
  7. package/dist/chunk-2EH4WRHL.js.map +1 -0
  8. package/dist/{chunk-CUPM3FGB.js → chunk-2PRS4J5Q.js} +3 -3
  9. package/dist/chunk-6HMM2R5T.js +390 -0
  10. package/dist/chunk-6HMM2R5T.js.map +1 -0
  11. package/dist/{chunk-ZWREYEWA.js → chunk-AZHW7R5V.js} +56 -11
  12. package/dist/chunk-AZHW7R5V.js.map +1 -0
  13. package/dist/{chunk-LTG3S6ZY.js → chunk-E6CLMKEE.js} +2 -2
  14. package/dist/{chunk-6ZYKCRFO.js → chunk-KRLPEMLH.js} +7591 -4417
  15. package/dist/chunk-KRLPEMLH.js.map +1 -0
  16. package/dist/chunk-NAB6FKFN.js +516 -0
  17. package/dist/chunk-NAB6FKFN.js.map +1 -0
  18. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  19. package/dist/chunk-SIBYBA2D.js.map +1 -0
  20. package/dist/chunk-UZNXG44K.js +4508 -0
  21. package/dist/chunk-UZNXG44K.js.map +1 -0
  22. package/dist/codemode-operations.d.ts +1 -6
  23. package/dist/company-brain-context-selection-schema.d.ts +705 -0
  24. package/dist/company-brain-context-selection.d.ts +94 -0
  25. package/dist/company-brain-governed-writes.d.ts +24 -0
  26. package/dist/company-brain.d.ts +55 -0
  27. package/dist/company-profile-agent-admin.d.ts +15 -0
  28. package/dist/company-profile-schema.d.ts +619 -2
  29. package/dist/company-profile.d.ts +9 -4
  30. package/dist/connection-authority.d.ts +95 -0
  31. package/dist/connection-scopes.d.ts +8 -0
  32. package/dist/connection-tenancy-backfill.d.ts +85 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +23 -4
  35. package/dist/editable-artifact-durable-export.js +2 -2
  36. package/dist/editable-artifacts.d.ts +2 -2
  37. package/dist/editable-artifacts.js +3 -3
  38. package/dist/governed-learning-activation-schema.d.ts +984 -0
  39. package/dist/governed-learning-activation.d.ts +98 -0
  40. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  41. package/dist/governed-learning-evaluator.d.ts +28 -0
  42. package/dist/index.d.ts +1606 -81
  43. package/dist/index.js +21898 -8147
  44. package/dist/index.js.map +1 -1
  45. package/dist/insights.d.ts +18 -0
  46. package/dist/integration-bindings.d.ts +1 -0
  47. package/dist/integration-facets.d.ts +30 -0
  48. package/dist/interaction-placement-loss.d.ts +22 -0
  49. package/dist/managed-human-provisioning.d.ts +25 -0
  50. package/dist/memory-domain.d.ts +3 -3
  51. package/dist/migrate.d.ts +11 -1
  52. package/dist/migrate.js +1 -1
  53. package/dist/new-session-drafts.d.ts +43 -5
  54. package/dist/organization-membership-backfill.d.ts +174 -0
  55. package/dist/organization-membership-lifecycle.d.ts +162 -0
  56. package/dist/pr-review.d.ts +107 -0
  57. package/dist/preference-registry-schema.d.ts +2 -0
  58. package/dist/preference-registry.d.ts +2 -0
  59. package/dist/provision-roles.js +1 -1
  60. package/dist/runtime-posture.d.ts +29 -8
  61. package/dist/schema.d.ts +24914 -13703
  62. package/dist/schema.js +99 -1
  63. package/dist/scoped-knowledge-schema.d.ts +52 -1
  64. package/dist/session-background-commands.d.ts +125 -0
  65. package/dist/session-background-commands.js +34 -0
  66. package/dist/session-background-commands.js.map +1 -0
  67. package/dist/session-control.d.ts +156 -3
  68. package/dist/session-goal-pacing.d.ts +68 -0
  69. package/dist/session-queue-commands.d.ts +43 -4
  70. package/dist/session-realtime-ledger.d.ts +2 -0
  71. package/dist/session-tenancy.d.ts +71 -1
  72. package/dist/session-tenancy.js +25 -3
  73. package/dist/session-tool-call-settlement.d.ts +9 -4
  74. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  75. package/dist/slack-routing.d.ts +268 -0
  76. package/dist/slack-task-policy-schema.d.ts +34 -0
  77. package/dist/slack-task-policy.d.ts +8 -0
  78. package/dist/slack-user-link-access.d.ts +28 -0
  79. package/dist/task-notes-schema.d.ts +594 -0
  80. package/dist/task-notes.d.ts +39 -0
  81. package/dist/turn-initiator.d.ts +2 -0
  82. package/dist/user-resource-authority.d.ts +109 -0
  83. package/dist/video-generation.js +3 -3
  84. package/dist/workspace-authority.d.ts +81 -0
  85. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  86. package/dist/workspace-instruction-policies.d.ts +62 -0
  87. package/dist/workspace-learning-policy.d.ts +1 -0
  88. package/dist/workspace-membership-permissions.d.ts +2 -0
  89. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  90. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  91. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  92. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  93. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  94. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  95. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  96. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  97. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  98. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  99. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  100. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  101. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  102. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  103. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  104. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  105. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  106. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  107. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  108. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  109. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  110. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  111. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  112. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  113. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  114. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  115. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  116. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  117. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  118. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  119. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  120. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  121. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  122. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  123. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  124. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  125. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  126. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  127. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  128. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  129. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  130. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  131. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  132. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  133. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  134. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  135. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  136. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  137. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  138. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  139. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  140. package/drizzle/0294_preference_activation_authority.sql +237 -0
  141. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  142. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  143. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  144. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  145. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  146. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  147. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  148. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  149. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  150. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  151. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  152. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  153. package/drizzle/0307_session_attention_state.sql +51 -0
  154. package/drizzle/0308_session_archives.sql +35 -0
  155. package/drizzle/0309_channel_project_pins.sql +6 -0
  156. package/drizzle/0310_channel_project_order.sql +27 -0
  157. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  158. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  159. package/drizzle/0313_private_child_session_authority.sql +365 -0
  160. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  161. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  162. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  163. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  164. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  165. package/drizzle/0319_event_triggered_automations.sql +254 -0
  166. package/drizzle/0320_pr_review_pack.sql +113 -0
  167. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  168. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  169. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  170. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  171. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  172. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  173. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  174. package/drizzle/0328_session_background_commands.sql +590 -0
  175. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  176. package/drizzle/0330_api_key_descriptions.sql +20 -0
  177. package/drizzle/0331_managed_organization_creation.sql +163 -0
  178. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  179. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  180. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  181. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  182. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  183. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  184. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  185. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  186. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  187. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
  188. package/drizzle/0342_slack_route_prompt_single_pending.sql +32 -0
  189. package/drizzle/0343_personal_document_force_rls_lock_repair.sql +146 -0
  190. package/drizzle/0344_private_session_visibility_transition_gate.sql +85 -0
  191. package/drizzle/0345_tenant_scoped_session_tenancy_fence.sql +2839 -0
  192. package/drizzle/0346_document_migration_audit_surface.sql +454 -0
  193. package/drizzle/0347_connection_authority_convergence_evidence.sql +396 -0
  194. package/package.json +10 -6
  195. package/src/attached-browser-devices.ts +233 -5
  196. package/src/automations.ts +911 -0
  197. package/src/browser-sessions.ts +10 -0
  198. package/src/capability-integrations.ts +175 -1
  199. package/src/child-lifecycle-notices.ts +241 -0
  200. package/src/codemode-operations.ts +1 -35
  201. package/src/company-brain-context-selection-schema.ts +100 -0
  202. package/src/company-brain-context-selection.ts +359 -0
  203. package/src/company-brain-governed-writes.ts +1170 -0
  204. package/src/company-brain.ts +309 -0
  205. package/src/company-profile-agent-admin.ts +225 -0
  206. package/src/company-profile-schema.ts +121 -1
  207. package/src/company-profile.ts +21 -0
  208. package/src/computer-sessions.ts +10 -1
  209. package/src/connection-authority.ts +290 -0
  210. package/src/connection-scopes.ts +20 -0
  211. package/src/connection-tenancy-backfill.ts +167 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +87 -2
  214. package/src/editable-artifacts-schema.ts +10 -5
  215. package/src/editable-artifacts.ts +21 -11
  216. package/src/governed-learning-activation-schema.ts +121 -0
  217. package/src/governed-learning-activation.ts +588 -0
  218. package/src/governed-learning-evaluator-schema.ts +72 -0
  219. package/src/governed-learning-evaluator.ts +217 -0
  220. package/src/index.ts +11676 -1550
  221. package/src/insights.ts +107 -0
  222. package/src/integration-bindings.ts +88 -6
  223. package/src/integration-facets.ts +287 -84
  224. package/src/interaction-placement-loss.ts +234 -0
  225. package/src/managed-human-provisioning.ts +116 -0
  226. package/src/memory-domain.ts +27 -32
  227. package/src/migrate.ts +77 -1
  228. package/src/new-session-drafts.ts +229 -35
  229. package/src/organization-membership-backfill.ts +735 -0
  230. package/src/organization-membership-lifecycle.ts +995 -0
  231. package/src/pr-review.ts +890 -0
  232. package/src/preference-registry.ts +31 -1
  233. package/src/provision-roles.ts +905 -6
  234. package/src/runtime-posture-cli.ts +2 -0
  235. package/src/runtime-posture.ts +1317 -72
  236. package/src/schema.ts +3316 -428
  237. package/src/scoped-knowledge-schema.ts +16 -8
  238. package/src/scoped-knowledge.ts +1 -1
  239. package/src/session-background-commands.ts +759 -0
  240. package/src/session-control.ts +640 -74
  241. package/src/session-goal-pacing.ts +126 -0
  242. package/src/session-queue-commands.ts +441 -85
  243. package/src/session-realtime-context.ts +4 -6
  244. package/src/session-realtime-ledger.ts +28 -14
  245. package/src/session-realtime-mirror.ts +1 -1
  246. package/src/session-tenancy.ts +410 -49
  247. package/src/session-tool-call-settlement.ts +38 -29
  248. package/src/slack-routing-personal-workspace.ts +67 -0
  249. package/src/slack-routing.ts +867 -0
  250. package/src/slack-task-policy-schema.ts +5 -0
  251. package/src/slack-task-policy.ts +18 -0
  252. package/src/slack-user-link-access.ts +138 -11
  253. package/src/task-notes-schema.ts +74 -0
  254. package/src/task-notes.ts +124 -2
  255. package/src/turn-initiator.ts +8 -0
  256. package/src/user-resource-authority.ts +377 -0
  257. package/src/workspace-authority.ts +160 -0
  258. package/src/workspace-instruction-policies-schema.ts +53 -1
  259. package/src/workspace-instruction-policies.ts +528 -77
  260. package/src/workspace-learning-policy.ts +21 -5
  261. package/src/workspace-membership-permissions.ts +9 -0
  262. package/dist/chunk-4SR4HKKA.js.map +0 -1
  263. package/dist/chunk-6ZYKCRFO.js.map +0 -1
  264. package/dist/chunk-NXAFLCQX.js +0 -2468
  265. package/dist/chunk-NXAFLCQX.js.map +0 -1
  266. package/dist/chunk-SK7YYHBI.js.map +0 -1
  267. package/dist/chunk-WD5ROSLL.js +0 -117
  268. package/dist/chunk-WD5ROSLL.js.map +0 -1
  269. package/dist/chunk-ZWREYEWA.js.map +0 -1
  270. /package/dist/{chunk-CUPM3FGB.js.map → chunk-2PRS4J5Q.js.map} +0 -0
  271. /package/dist/{chunk-LTG3S6ZY.js.map → chunk-E6CLMKEE.js.map} +0 -0
@@ -3,6 +3,7 @@ import {
3
3
  XaiProviderAccountAuthoritySnapshotV1,
4
4
  DraftTimelineAnnotations,
5
5
  McpPersonalConnectionDelegations,
6
+ PersonalResourceAttachmentSummary,
6
7
  TimelineAnnotations,
7
8
  metadataWithTurnExecutionPolicyV1,
8
9
  mergeResourceRefs,
@@ -19,15 +20,17 @@ import {
19
20
  type SandboxOs,
20
21
  type SessionEvent,
21
22
  type SessionEventType,
23
+ type SessionPromptRouting,
22
24
  type SessionTurn,
23
25
  type SessionTurnSource,
24
26
  type SessionTurnStatus,
25
27
  type ToolRef,
26
28
  type TurnExecutionPolicyV1,
27
29
  type TimelineAnnotation,
30
+ type PersonalResourceAttachmentIntent,
28
31
  } from "@opengeni/contracts";
29
32
  import { and, asc, eq, inArray, sql } from "drizzle-orm";
30
- import type { Database, SessionActivityDatabase } from "./database";
33
+ import { setSubjectRlsContext, type Database, type SessionActivityDatabase } from "./database";
31
34
  import {
32
35
  fromPostgresLosslessJson,
33
36
  fromPostgresLosslessText,
@@ -42,6 +45,7 @@ import {
42
45
  evaluateSessionControl,
43
46
  lockSessionEventWriteRows,
44
47
  lockWorkspaceInferenceControl,
48
+ lockWorkspaceInferenceControlForAdmission,
45
49
  registerInternalUpdateWakeInTransaction,
46
50
  reserveSessionCommandReceipt,
47
51
  registerSessionWorkflowWakeInTransaction,
@@ -52,6 +56,7 @@ import {
52
56
  updateSessionCommandReceiptResult,
53
57
  } from "./session-control";
54
58
  import { sessionRealtimeIsActiveInTransaction } from "./session-realtime-state";
59
+ import { autoResumeGoalPausedByCapInTransaction } from "./session-goal-pacing";
55
60
  import {
56
61
  mirrorSessionRealtimeContextInTransaction,
57
62
  renderRealtimeHumanInputContext,
@@ -65,6 +70,8 @@ import {
65
70
  type FrozenTurnInitiator,
66
71
  } from "./turn-initiator";
67
72
  import { resolveXaiProviderAccountAuthoritySnapshotForAcceptanceInTransaction } from "./xai-subscription";
73
+ import { assertActiveManagedHumanOrganizationMembership } from "./organization-membership-lifecycle";
74
+ import { acceptTurnPersonalResourceAttachmentInTransaction } from "./user-resource-authority";
68
75
 
69
76
  type SessionEventInsertWithPayload = typeof schema.sessionEvents.$inferInsert & {
70
77
  payload: unknown;
@@ -77,7 +84,8 @@ export type QueueCommandConflictCode =
77
84
  | "PROMPT_CHANGED"
78
85
  | "DRAFT_CHANGED"
79
86
  | "DRAFT_NOT_EMPTY"
80
- | "EDIT_SOURCE_CHANGED";
87
+ | "EDIT_SOURCE_CHANGED"
88
+ | "ONCE_ATTACHMENT_IMMUTABLE";
81
89
 
82
90
  export class QueueCommandConflictError extends Error {
83
91
  readonly name = "QueueCommandConflictError";
@@ -113,14 +121,19 @@ export type EditQueueCommandResult = QueueCommandResult & {
113
121
  export type SteerQueueCommandResult = QueueCommandResult & {
114
122
  interruptionCount: number;
115
123
  workspaceControlEventId: string | null;
124
+ workflowId: string;
125
+ wakeRevision: number;
116
126
  };
117
127
 
118
128
  export type SubmitHumanPromptResult = {
119
129
  receipt: SessionCommandReceiptRow;
130
+ routing: SessionPromptRouting;
120
131
  queueVersion: number;
121
132
  accepted: SessionEvent;
122
133
  events: SessionEvent[];
123
134
  turn: SessionTurn;
135
+ /** Current actor/session composer after an exact draft-bound submission. */
136
+ draft: ComposerDraftRow | null;
124
137
  /** Backward-compatible row identities for lower-level callers. */
125
138
  acceptedEventId: string;
126
139
  eventIds: string[];
@@ -170,7 +183,7 @@ function mapSubmittedPromptTurn(row: typeof schema.sessionTurns.$inferSelect): S
170
183
  toolsProvided: row.toolsProvided,
171
184
  model: row.model,
172
185
  reasoningEffort: row.reasoningEffort as ReasoningEffort,
173
- latencyMode: (row.latencyMode as LatencyMode | null | undefined) ?? "standard",
186
+ latencyMode: row.latencyMode as LatencyMode,
174
187
  sandboxBackend: row.sandboxBackend as SandboxBackend,
175
188
  sandboxOs: (row.sandboxOs as SandboxOs | null) ?? null,
176
189
  metadata: row.metadata,
@@ -185,6 +198,9 @@ function mapSubmittedPromptTurn(row: typeof schema.sessionTurns.$inferSelect): S
185
198
  ),
186
199
  initiatorContext: row.initiatorContext ?? {},
187
200
  personalConnections,
201
+ personalResources: row.personalResourceAttachmentSummary
202
+ ? PersonalResourceAttachmentSummary.parse(row.personalResourceAttachmentSummary)
203
+ : null,
188
204
  cancelledBy: row.cancelledBy,
189
205
  cancelReason: row.cancelReason,
190
206
  startedAt: row.startedAt ? row.startedAt.toISOString() : null,
@@ -211,9 +227,16 @@ async function personalConnectionDelegationsForAgentActor(
211
227
  db: Database,
212
228
  workspaceId: string,
213
229
  actor: Extract<SessionCommandActor, { type: "agent_attempt" }>,
214
- ): Promise<McpPersonalConnectionDelegation[]> {
230
+ targetSessionId: string,
231
+ ): Promise<{
232
+ delegations: McpPersonalConnectionDelegation[];
233
+ connectionAuthoritySubjectId: string | null;
234
+ }> {
215
235
  const [row] = await db
216
- .select({ delegations: schema.sessionTurns.personalConnectionDelegations })
236
+ .select({
237
+ delegations: schema.sessionTurns.personalConnectionDelegations,
238
+ initiatingHumanSubjectId: schema.sessionTurns.initiatingHumanSubjectId,
239
+ })
217
240
  .from(schema.sessionTurns)
218
241
  .where(
219
242
  and(
@@ -234,7 +257,37 @@ async function personalConnectionDelegationsForAgentActor(
234
257
  `Agent authority turn has malformed personal MCP delegation state: ${actor.sessionId}/${actor.turnId}`,
235
258
  );
236
259
  }
237
- return parsed.data.map((delegation) => ({ ...delegation }));
260
+ // Agent messages and Agent Steer create new accepted work. A once grant is
261
+ // already bound to the caller turn, while a session grant may be projected
262
+ // only into another turn of that exact session. Always grants can cross the
263
+ // direct parent/child boundary subject to the live admission fences.
264
+ const delegations = parsed.data
265
+ .filter((delegation) => {
266
+ const authority = delegation.userDelegation;
267
+ if (!authority) return true;
268
+ if (authority.mode === "once") return false;
269
+ if (authority.mode === "session") return authority.sessionId === targetSessionId;
270
+ return true;
271
+ })
272
+ .map((delegation) => ({ ...delegation }));
273
+ const activated = delegations.filter((delegation) => delegation.userDelegation);
274
+ if (activated.length === 0) {
275
+ return { delegations, connectionAuthoritySubjectId: null };
276
+ }
277
+ const connectionAuthoritySubjectId = row.initiatingHumanSubjectId;
278
+ if (!connectionAuthoritySubjectId) {
279
+ throw new SessionControlInvariantError(
280
+ `Agent authority turn lost its causal human: ${actor.sessionId}/${actor.turnId}`,
281
+ );
282
+ }
283
+ for (const delegation of activated) {
284
+ if (delegation.ownerSubjectId !== connectionAuthoritySubjectId) {
285
+ throw new SessionControlInvariantError(
286
+ `Agent authority turn causal human does not own retained connection authority: ${actor.sessionId}/${actor.turnId}`,
287
+ );
288
+ }
289
+ }
290
+ return { delegations, connectionAuthoritySubjectId };
238
291
  }
239
292
 
240
293
  async function xaiAuthorityForAgentActor(
@@ -664,10 +717,19 @@ export async function saveComposerDraftInTransaction(
664
717
  resources: ResourceRef[];
665
718
  model: string;
666
719
  reasoningEffort: ReasoningEffort;
667
- latencyMode?: LatencyMode;
720
+ latencyMode: LatencyMode;
721
+ /**
722
+ * Bound the workspace control prefix wait (request-scoped API callers pass
723
+ * `workspaceControlRequestLockTimeoutMs()`); omit for lifecycle callers.
724
+ */
725
+ controlLockTimeoutMs?: number;
668
726
  },
669
727
  ): Promise<ComposerDraftRow> {
670
- await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
728
+ await lockWorkspaceInferenceControl(db, input.workspaceId, "share", {
729
+ ...(input.controlLockTimeoutMs !== undefined
730
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
731
+ : {}),
732
+ });
671
733
  await lockSessionEventWriteRows(db, {
672
734
  workspaceId: input.workspaceId,
673
735
  controlLock: "already_locked",
@@ -698,7 +760,7 @@ export async function saveComposerDraftInTransaction(
698
760
  toolsProvided: false,
699
761
  model: input.model,
700
762
  reasoningEffort: input.reasoningEffort,
701
- latencyMode: input.latencyMode ?? "standard",
763
+ latencyMode: input.latencyMode,
702
764
  // A queue edit is still the same accepted work item. Preserve its frozen
703
765
  // initiator through arbitrary draft saves; only a genuinely new compose or
704
766
  // Steer captures the submitting actor.
@@ -728,9 +790,18 @@ export async function moveQueuedTurnInTransaction(
728
790
  expectedQueueVersion: number;
729
791
  actor: SessionCommandActor;
730
792
  operationKey: string;
793
+ /**
794
+ * Bound the workspace control prefix wait (request-scoped API callers pass
795
+ * `workspaceControlRequestLockTimeoutMs()`); omit for lifecycle callers.
796
+ */
797
+ controlLockTimeoutMs?: number;
731
798
  },
732
799
  ): Promise<QueueCommandResult> {
733
- await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
800
+ await lockWorkspaceInferenceControl(db, input.workspaceId, "share", {
801
+ ...(input.controlLockTimeoutMs !== undefined
802
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
803
+ : {}),
804
+ });
734
805
  await lockSessionEventWriteRows(db, {
735
806
  workspaceId: input.workspaceId,
736
807
  controlLock: "already_locked",
@@ -864,9 +935,18 @@ export async function deleteSessionQueueItemInTransaction(
864
935
  actor: SessionCommandActor;
865
936
  operationKey: string;
866
937
  reason?: string | null;
938
+ /**
939
+ * Bound the workspace control prefix wait (request-scoped API callers pass
940
+ * `workspaceControlRequestLockTimeoutMs()`); omit for lifecycle callers.
941
+ */
942
+ controlLockTimeoutMs?: number;
867
943
  },
868
944
  ): Promise<QueueCommandResult> {
869
- await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
945
+ await lockWorkspaceInferenceControl(db, input.workspaceId, "share", {
946
+ ...(input.controlLockTimeoutMs !== undefined
947
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
948
+ : {}),
949
+ });
870
950
  await lockSessionEventWriteRows(db, {
871
951
  workspaceId: input.workspaceId,
872
952
  controlLock: "already_locked",
@@ -997,9 +1077,18 @@ export async function editQueuedTurnInTransaction(
997
1077
  replaceDraft: boolean;
998
1078
  actor: SessionCommandActor;
999
1079
  operationKey: string;
1080
+ /**
1081
+ * Bound the workspace control prefix wait (request-scoped API callers pass
1082
+ * `workspaceControlRequestLockTimeoutMs()`); omit for lifecycle callers.
1083
+ */
1084
+ controlLockTimeoutMs?: number;
1000
1085
  },
1001
1086
  ): Promise<EditQueueCommandResult> {
1002
- await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
1087
+ await lockWorkspaceInferenceControl(db, input.workspaceId, "share", {
1088
+ ...(input.controlLockTimeoutMs !== undefined
1089
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
1090
+ : {}),
1091
+ });
1003
1092
  await lockSessionEventWriteRows(db, {
1004
1093
  workspaceId: input.workspaceId,
1005
1094
  controlLock: "already_locked",
@@ -1070,6 +1159,17 @@ export async function editQueuedTurnInTransaction(
1070
1159
  draftRevision,
1071
1160
  });
1072
1161
  }
1162
+ if (turn.personalResourceAttachmentSummary?.mode === "once") {
1163
+ throw new QueueCommandConflictError(
1164
+ "ONCE_ATTACHMENT_IMMUTABLE",
1165
+ "A queued prompt with a once personal-resource attachment cannot be edited into new work",
1166
+ {
1167
+ queueVersion: session.queueVersion,
1168
+ turnVersion: turn.version,
1169
+ draftRevision,
1170
+ },
1171
+ );
1172
+ }
1073
1173
  const nextDraftRevision = draftRevision + 1;
1074
1174
  const draftValues = {
1075
1175
  accountId: input.accountId,
@@ -1177,9 +1277,19 @@ export async function steerQueuedTurnInTransaction(
1177
1277
  controlEtag?: string | null;
1178
1278
  actor: SessionCommandActor;
1179
1279
  operationKey: string;
1280
+ /** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
1281
+ controlLockTimeoutMs?: number;
1180
1282
  },
1181
1283
  ): Promise<SteerQueueCommandResult> {
1182
- const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "update");
1284
+ const admission = await lockWorkspaceInferenceControlForAdmission(db, {
1285
+ workspaceId: input.workspaceId,
1286
+ sessionId: input.sessionId,
1287
+ resumePausedBranch: true,
1288
+ ...(input.controlLockTimeoutMs !== undefined
1289
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
1290
+ : {}),
1291
+ });
1292
+ const workspaceControl = admission.control;
1183
1293
  await lockSessionEventWriteRows(db, {
1184
1294
  workspaceId: input.workspaceId,
1185
1295
  controlLock: "already_locked",
@@ -1207,6 +1317,10 @@ export async function steerQueuedTurnInTransaction(
1207
1317
  });
1208
1318
  if (reserved.replay && reserved.receipt.appliedQueueVersion !== null) {
1209
1319
  const replaySession = await lockSession(db, input.workspaceId, input.sessionId);
1320
+ const wakeRevision = Number(reserved.receipt.result.wakeRevision ?? 0);
1321
+ if (wakeRevision < 1) {
1322
+ throw new SessionControlInvariantError("Replayed queue Steer receipt has no wake revision");
1323
+ }
1210
1324
  return {
1211
1325
  receipt: reserved.receipt,
1212
1326
  queueVersion: replaySession.queueVersion,
@@ -1217,6 +1331,8 @@ export async function steerQueuedTurnInTransaction(
1217
1331
  typeof reserved.receipt.result.workspaceControlEventId === "string"
1218
1332
  ? reserved.receipt.result.workspaceControlEventId
1219
1333
  : null,
1334
+ workflowId: replaySession.temporalWorkflowId ?? `session-${input.sessionId}`,
1335
+ wakeRevision,
1220
1336
  replay: true,
1221
1337
  };
1222
1338
  }
@@ -1244,6 +1360,7 @@ export async function steerQueuedTurnInTransaction(
1244
1360
  : input.actor.subjectId,
1245
1361
  reason: "human_steer",
1246
1362
  observedControlEtag: input.controlEtag ?? null,
1363
+ admission,
1247
1364
  });
1248
1365
  const session = await lockSession(db, input.workspaceId, input.sessionId);
1249
1366
  const rows = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
@@ -1395,6 +1512,8 @@ export async function steerQueuedTurnInTransaction(
1395
1512
  eventIds: eventRows.map((event) => event.id),
1396
1513
  interruptionCount,
1397
1514
  workspaceControlEventId: resumed.workspaceControlEventId,
1515
+ workflowId: session.temporalWorkflowId ?? `session-${input.sessionId}`,
1516
+ wakeRevision,
1398
1517
  replay: false,
1399
1518
  };
1400
1519
  }
@@ -1430,18 +1549,40 @@ export async function submitHumanPromptInTransaction(
1430
1549
  text: string;
1431
1550
  context: string;
1432
1551
  };
1552
+ /** False when the human input originated inside the active realtime provider session. */
1553
+ mirrorToRealtime?: boolean;
1433
1554
  source: "user" | "api";
1434
1555
  /** Record the admitted run's durable usage fact in this transaction. */
1435
1556
  recordAgentRunUsage?: boolean;
1436
1557
  personalConnectionDelegations?: McpPersonalConnectionDelegation[];
1558
+ personalResourceAttachment?: PersonalResourceAttachmentIntent;
1437
1559
  mcpCredentialUpdates?: Array<{
1438
1560
  id: string;
1439
1561
  headersEncrypted: Record<string, string>;
1440
1562
  }>;
1563
+ /** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
1564
+ controlLockTimeoutMs?: number;
1441
1565
  },
1442
1566
  ): Promise<SubmitHumanPromptResult> {
1443
1567
  const annotations = TimelineAnnotations.parse(input.annotations ?? []);
1444
- const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "update");
1568
+ // Send is inert queue admission while paused; Steer deliberately resumes.
1569
+ // Tell the lock helper which path may need the exclusive control prefix.
1570
+ const admission = await lockWorkspaceInferenceControlForAdmission(db, {
1571
+ workspaceId: input.workspaceId,
1572
+ sessionId: input.sessionId,
1573
+ resumePausedBranch: input.delivery === "steer",
1574
+ ...(input.controlLockTimeoutMs !== undefined
1575
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
1576
+ : {}),
1577
+ });
1578
+ const workspaceControl = admission.control;
1579
+ if (input.actor.type === "human") {
1580
+ await setSubjectRlsContext(db, input.actor.subjectId);
1581
+ await assertActiveManagedHumanOrganizationMembership(db, {
1582
+ accountId: input.accountId,
1583
+ subjectId: input.actor.subjectId,
1584
+ });
1585
+ }
1445
1586
  await lockSessionEventWriteRows(db, {
1446
1587
  workspaceId: input.workspaceId,
1447
1588
  controlLock: "already_locked",
@@ -1466,7 +1607,10 @@ export async function submitHumanPromptInTransaction(
1466
1607
  source: input.source,
1467
1608
  turnMetadata: input.turnMetadata ?? {},
1468
1609
  messagePresentation: input.messagePresentation ?? null,
1610
+ mirrorToRealtime: input.mirrorToRealtime ?? true,
1469
1611
  mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
1612
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
1613
+ personalResourceAttachment: input.personalResourceAttachment ?? null,
1470
1614
  ...(input.actor.type === "service"
1471
1615
  ? {
1472
1616
  serviceInitiator: {
@@ -1524,12 +1668,32 @@ export async function submitHumanPromptInTransaction(
1524
1668
  if (!accepted || !replayTurn || events.length !== eventIds.length) {
1525
1669
  throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
1526
1670
  }
1671
+ const replayDraft =
1672
+ input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1673
+ ? null
1674
+ : await getComposerDraftInTransaction(db, {
1675
+ workspaceId: input.workspaceId,
1676
+ sessionId: input.sessionId,
1677
+ subjectId: input.subjectId,
1678
+ });
1527
1679
  return {
1528
1680
  receipt: reserved.receipt,
1681
+ routing:
1682
+ reserved.receipt.result.routing === "accepted_for_execution" ||
1683
+ reserved.receipt.result.routing === "queued_for_execution" ||
1684
+ reserved.receipt.result.routing === "accepted_for_steering"
1685
+ ? reserved.receipt.result.routing
1686
+ : input.delivery === "steer"
1687
+ ? "accepted_for_steering"
1688
+ : // Pre-routing receipts cannot reconstruct admission-time activity
1689
+ // or Pause truth. Queue is the only conservative placement; a
1690
+ // later turn.started event moves it into chat without duplication.
1691
+ "queued_for_execution",
1529
1692
  queueVersion: Number(reserved.receipt.appliedQueueVersion),
1530
1693
  accepted,
1531
1694
  events,
1532
1695
  turn: mapSubmittedPromptTurn(replayTurn),
1696
+ draft: replayDraft,
1533
1697
  acceptedEventId,
1534
1698
  eventIds,
1535
1699
  turnId,
@@ -1550,34 +1714,39 @@ export async function submitHumanPromptInTransaction(
1550
1714
  throw new SessionControlConflictError();
1551
1715
  }
1552
1716
 
1553
- const resumed = await autoResumeSessionBranchInTransaction(db, {
1554
- workspaceId: input.workspaceId,
1555
- sessionId: input.sessionId,
1556
- actor:
1557
- input.actor.type === "agent_attempt"
1558
- ? `attempt:${input.actor.attemptId}`
1559
- : input.actor.subjectId,
1560
- reason:
1561
- input.actor.type === "service"
1562
- ? input.delivery === "steer"
1563
- ? "service_steer"
1564
- : "service_send"
1565
- : input.delivery === "steer"
1566
- ? "human_steer"
1567
- : "human_send",
1568
- observedControlEtag: input.controlEtag ?? null,
1569
- });
1570
1717
  const session = await lockSession(db, input.workspaceId, input.sessionId);
1571
1718
  if (session.status === "cancelled") {
1572
1719
  throw new QueueCommandConflictError(
1573
1720
  "QUEUE_PROMPT_STARTED",
1574
- "Cancelled session cannot accept work",
1575
- {
1576
- queueVersion: session.queueVersion,
1577
- },
1721
+ "Cancelled session subtree cannot accept work",
1722
+ { queueVersion: session.queueVersion },
1578
1723
  );
1579
1724
  }
1580
1725
 
1726
+ // Send is queue admission, never a hidden control mutation. A paused Send
1727
+ // remains inert behind the existing gate until the user explicitly resumes.
1728
+ // Steer is the intentional exception: it replaces the current direction and
1729
+ // therefore activates the selected branch atomically.
1730
+ const resumed =
1731
+ input.delivery === "send"
1732
+ ? {
1733
+ revision: before.controlVersion,
1734
+ control: before,
1735
+ changed: false,
1736
+ workspaceControlEventId: null,
1737
+ }
1738
+ : await autoResumeSessionBranchInTransaction(db, {
1739
+ workspaceId: input.workspaceId,
1740
+ sessionId: input.sessionId,
1741
+ actor:
1742
+ input.actor.type === "agent_attempt"
1743
+ ? `attempt:${input.actor.attemptId}`
1744
+ : input.actor.subjectId,
1745
+ reason: input.actor.type === "service" ? "service_steer" : "human_steer",
1746
+ observedControlEtag: input.controlEtag ?? null,
1747
+ admission,
1748
+ });
1749
+
1581
1750
  const draft =
1582
1751
  input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1583
1752
  ? null
@@ -1710,6 +1879,28 @@ export async function submitHumanPromptInTransaction(
1710
1879
  input.subjectLabel,
1711
1880
  );
1712
1881
  }
1882
+ const acceptedInitiatingHumanSubjectId = editedSourceTurn
1883
+ ? (editedSourceTurn.initiatingHumanSubjectId ??
1884
+ (editedSourceTurn.initiatorKind === "subject" ? editedSourceTurn.initiatorSubjectId : null))
1885
+ : (frozenInitiator.initiatingHumanSubjectId ??
1886
+ (frozenInitiator.initiator.kind === "subject" ? frozenInitiator.initiator.subjectId : null));
1887
+ if (
1888
+ (input.personalConnectionDelegations ?? []).some(
1889
+ (delegation) => delegation.userDelegation !== undefined,
1890
+ ) ||
1891
+ input.personalResourceAttachment !== undefined
1892
+ ) {
1893
+ if (!acceptedInitiatingHumanSubjectId) {
1894
+ throw new SessionControlInvariantError("Personal authority requires an exact causal human");
1895
+ }
1896
+ await db.execute(
1897
+ sql`select set_config(
1898
+ 'opengeni.initiating_human_subject_id',
1899
+ ${acceptedInitiatingHumanSubjectId},
1900
+ true
1901
+ )`,
1902
+ );
1903
+ }
1713
1904
  const xaiProviderAccountAuthoritySnapshot = editedSourceTurn
1714
1905
  ? XaiProviderAccountAuthoritySnapshotV1.parse(
1715
1906
  editedSourceTurn.xaiProviderAccountAuthoritySnapshot,
@@ -1726,6 +1917,13 @@ export async function submitHumanPromptInTransaction(
1726
1917
  editedSourceModelContext !== undefined
1727
1918
  ? editedSourceModelContext
1728
1919
  : (input.modelContext ?? null);
1920
+ const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
1921
+ const routing: SessionPromptRouting =
1922
+ input.delivery === "steer"
1923
+ ? "accepted_for_steering"
1924
+ : before.state === "paused" || session.activeTurnId || existingQueued.length > 0
1925
+ ? "queued_for_execution"
1926
+ : "accepted_for_execution";
1729
1927
  let sequence = session.lastSequence;
1730
1928
  const eventValues: SessionEventInsertWithPayload[] = [
1731
1929
  {
@@ -1753,12 +1951,12 @@ export async function submitHumanPromptInTransaction(
1753
1951
  ...(input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {}),
1754
1952
  ...(input.latencyMode ? { latencyMode: input.latencyMode } : {}),
1755
1953
  delivery: input.delivery,
1954
+ routing,
1756
1955
  initiator: frozenInitiator.initiator,
1757
1956
  },
1758
1957
  occurredAt: now,
1759
1958
  },
1760
1959
  ];
1761
- const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
1762
1960
  const [turn] = await db
1763
1961
  .insert(schema.sessionTurns)
1764
1962
  .values(
@@ -1772,6 +1970,7 @@ export async function submitHumanPromptInTransaction(
1772
1970
  temporalWorkflowId: workflowId,
1773
1971
  status: "queued",
1774
1972
  source: input.source,
1973
+ promptRouting: routing,
1775
1974
  position: input.delivery === "steer" ? 0 : existingQueued.length + 1,
1776
1975
  prompt: input.text,
1777
1976
  annotations,
@@ -1788,14 +1987,7 @@ export async function submitHumanPromptInTransaction(
1788
1987
  : (input.turnMetadata ?? {}),
1789
1988
  lineage: { actor: input.actor.type },
1790
1989
  ...initiatorColumns(frozenInitiator),
1791
- initiatingHumanSubjectId: editedSourceTurn
1792
- ? (editedSourceTurn.initiatingHumanSubjectId ??
1793
- (editedSourceTurn.initiatorKind === "subject"
1794
- ? editedSourceTurn.initiatorSubjectId
1795
- : null))
1796
- : frozenInitiator.initiator.kind === "subject"
1797
- ? frozenInitiator.initiator.subjectId
1798
- : null,
1990
+ initiatingHumanSubjectId: acceptedInitiatingHumanSubjectId,
1799
1991
  personalConnectionDelegations: editedSourceTurn
1800
1992
  ? editedSourceTurn.personalConnectionDelegations
1801
1993
  : (input.personalConnectionDelegations ?? []),
@@ -1810,6 +2002,49 @@ export async function submitHumanPromptInTransaction(
1810
2002
  .returning();
1811
2003
  if (!turn) throw new SessionControlInvariantError("Prompt turn was not inserted");
1812
2004
  let committedTurn = turn;
2005
+ const personalResourceExpectedAuthorityEpoch =
2006
+ input.personalResourceAttachment?.expectedAuthorityEpoch;
2007
+ let acceptedPersonalResources: Awaited<
2008
+ ReturnType<typeof acceptTurnPersonalResourceAttachmentInTransaction>
2009
+ > | null = null;
2010
+ if (input.personalResourceAttachment) {
2011
+ if (personalResourceExpectedAuthorityEpoch === undefined) {
2012
+ throw new SessionControlInvariantError(
2013
+ "Personal-resource attachment requires an expected authority epoch",
2014
+ );
2015
+ }
2016
+ acceptedPersonalResources = await acceptTurnPersonalResourceAttachmentInTransaction(db, {
2017
+ accountId: input.accountId,
2018
+ workspaceId: input.workspaceId,
2019
+ sessionId: input.sessionId,
2020
+ turnId,
2021
+ subjectId: acceptedInitiatingHumanSubjectId!,
2022
+ intent: {
2023
+ ...input.personalResourceAttachment,
2024
+ expectedAuthorityEpoch: personalResourceExpectedAuthorityEpoch,
2025
+ },
2026
+ });
2027
+ }
2028
+ if (acceptedPersonalResources) {
2029
+ committedTurn = {
2030
+ ...turn,
2031
+ personalResourceAttachmentSummary: acceptedPersonalResources.summary,
2032
+ personalResourceProtocolVersion: 1,
2033
+ };
2034
+ eventValues.push({
2035
+ accountId: input.accountId,
2036
+ workspaceId: input.workspaceId,
2037
+ sessionId: input.sessionId,
2038
+ turnId,
2039
+ sequence: ++sequence,
2040
+ type: "session.personal_resources.attached",
2041
+ payload: {
2042
+ turnId,
2043
+ ...acceptedPersonalResources.summary,
2044
+ },
2045
+ occurredAt: now,
2046
+ });
2047
+ }
1813
2048
  eventValues.push({
1814
2049
  accountId: input.accountId,
1815
2050
  workspaceId: input.workspaceId,
@@ -1821,6 +2056,7 @@ export async function submitHumanPromptInTransaction(
1821
2056
  turnId,
1822
2057
  triggerEventId: acceptedEventId,
1823
2058
  source: input.source,
2059
+ routing,
1824
2060
  initiator: frozenInitiator.initiator,
1825
2061
  },
1826
2062
  occurredAt: now,
@@ -1919,6 +2155,29 @@ export async function submitHumanPromptInTransaction(
1919
2155
  });
1920
2156
  }
1921
2157
 
2158
+ // A human/API prompt is external input for the goal. A goal paused only by
2159
+ // its continuation ceiling (`max_auto_continuations`, pacing rather than
2160
+ // intent) resumes in this same commit; a user/API/agent/limits pause is never
2161
+ // touched here. Goal row FOR UPDATE follows the session and turn locks above,
2162
+ // the order the claim transaction uses.
2163
+ const goalAutoResumed = await autoResumeGoalPausedByCapInTransaction(db, {
2164
+ workspaceId: input.workspaceId,
2165
+ sessionId: input.sessionId,
2166
+ cause: { kind: "human_prompt", turnId },
2167
+ now,
2168
+ });
2169
+ if (goalAutoResumed) {
2170
+ eventValues.push({
2171
+ accountId: input.accountId,
2172
+ workspaceId: input.workspaceId,
2173
+ sessionId: input.sessionId,
2174
+ sequence: ++sequence,
2175
+ type: "goal.resumed",
2176
+ payload: goalAutoResumed.payload,
2177
+ occurredAt: now,
2178
+ });
2179
+ }
2180
+
1922
2181
  const ordered =
1923
2182
  input.delivery === "steer" ? [turn, ...existingQueued] : [...existingQueued, turn];
1924
2183
  await normalizeQueuePositions(
@@ -1945,13 +2204,7 @@ export async function submitHumanPromptInTransaction(
1945
2204
  .insert(schema.sessionEvents)
1946
2205
  .values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
1947
2206
  .returning();
1948
- if (input.actor.type === "human") {
1949
- const realtimeRouting =
1950
- input.delivery === "steer"
1951
- ? "accepted_for_steering"
1952
- : session.activeTurnId || existingQueued.length > 0
1953
- ? "queued_for_execution"
1954
- : "accepted_for_execution";
2207
+ if (input.actor.type === "human" && input.mirrorToRealtime !== false) {
1955
2208
  await mirrorSessionRealtimeContextInTransaction(db, {
1956
2209
  accountId: input.accountId,
1957
2210
  workspaceId: input.workspaceId,
@@ -1962,12 +2215,12 @@ export async function submitHumanPromptInTransaction(
1962
2215
  channel: null,
1963
2216
  text: renderRealtimeHumanInputContext({
1964
2217
  delivery: input.delivery,
1965
- routing: realtimeRouting,
2218
+ routing,
1966
2219
  text: renderTimelineAnnotationsForModel(input.text, annotations),
1967
2220
  }),
1968
2221
  payload: {
1969
2222
  delivery: input.delivery,
1970
- routing: realtimeRouting,
2223
+ routing,
1971
2224
  acceptedEventId,
1972
2225
  instruction: "OpenGeni accepted and routed this user input; do not delegate it again.",
1973
2226
  },
@@ -1989,8 +2242,25 @@ export async function submitHumanPromptInTransaction(
1989
2242
  updatedAt: now,
1990
2243
  })
1991
2244
  .where(eq(schema.sessions.id, input.sessionId));
1992
- if (draft) {
1993
- await db.delete(schema.composerDrafts).where(eq(schema.composerDrafts.id, draft.id));
2245
+ const [nextDraft] = draft
2246
+ ? await db
2247
+ .update(schema.composerDrafts)
2248
+ .set({
2249
+ revision: draft.revision + 1,
2250
+ text: "",
2251
+ annotations: [],
2252
+ resources: [],
2253
+ tools: [],
2254
+ toolsProvided: false,
2255
+ sourceTurnId: null,
2256
+ sourceTurnVersion: null,
2257
+ updatedAt: now,
2258
+ })
2259
+ .where(eq(schema.composerDrafts.id, draft.id))
2260
+ .returning()
2261
+ : [undefined];
2262
+ if (draft && !nextDraft) {
2263
+ throw new SessionControlInvariantError("Accepted composer draft did not rotate");
1994
2264
  }
1995
2265
  const wakeRevision = await registerSessionWorkflowWakeInTransaction(db, {
1996
2266
  accountId: input.accountId,
@@ -2051,7 +2321,7 @@ export async function submitHumanPromptInTransaction(
2051
2321
  controlRevision: resumed.revision,
2052
2322
  queueVersion,
2053
2323
  turnVersion: turn.version,
2054
- ...(draft ? { draftRevision: draft.revision } : {}),
2324
+ ...(nextDraft ? { draftRevision: nextDraft.revision } : {}),
2055
2325
  result: {
2056
2326
  turnId,
2057
2327
  acceptedEventId,
@@ -2060,6 +2330,7 @@ export async function submitHumanPromptInTransaction(
2060
2330
  interruptionCount,
2061
2331
  replacedTurnId,
2062
2332
  workspaceControlEventId: resumed.workspaceControlEventId,
2333
+ routing,
2063
2334
  ...(input.turnExecutionPolicy
2064
2335
  ? {
2065
2336
  executionPolicy: turnExecutionPolicyAuditMetadata(input.turnExecutionPolicy, turnId),
@@ -2074,10 +2345,12 @@ export async function submitHumanPromptInTransaction(
2074
2345
  }
2075
2346
  return {
2076
2347
  receipt,
2348
+ routing,
2077
2349
  queueVersion,
2078
2350
  accepted,
2079
2351
  events,
2080
2352
  turn: mapSubmittedPromptTurn(committedTurn),
2353
+ draft: nextDraft ?? null,
2081
2354
  acceptedEventId,
2082
2355
  eventIds,
2083
2356
  turnId,
@@ -2097,9 +2370,18 @@ export async function sendAgentMessageInTransaction(
2097
2370
  actor: Extract<SessionCommandActor, { type: "agent_attempt" }>;
2098
2371
  operationKey: string;
2099
2372
  text: string;
2373
+ /**
2374
+ * Bound the workspace control prefix wait (request-scoped API callers pass
2375
+ * `workspaceControlRequestLockTimeoutMs()`); omit for lifecycle callers.
2376
+ */
2377
+ controlLockTimeoutMs?: number;
2100
2378
  },
2101
2379
  ): Promise<AgentInternalUpdateCommandResult> {
2102
- const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
2380
+ const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "share", {
2381
+ ...(input.controlLockTimeoutMs !== undefined
2382
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
2383
+ : {}),
2384
+ });
2103
2385
  await lockSessionEventWriteRows(db, {
2104
2386
  workspaceId: input.workspaceId,
2105
2387
  controlLock: "already_locked",
@@ -2148,11 +2430,13 @@ export async function sendAgentMessageInTransaction(
2148
2430
  targetSessionId: input.targetSessionId,
2149
2431
  action: "message",
2150
2432
  });
2151
- const personalConnectionDelegations = await personalConnectionDelegationsForAgentActor(
2433
+ const inheritedConnectionAuthority = await personalConnectionDelegationsForAgentActor(
2152
2434
  db,
2153
2435
  input.workspaceId,
2154
2436
  input.actor,
2437
+ input.targetSessionId,
2155
2438
  );
2439
+ const personalConnectionDelegations = inheritedConnectionAuthority.delegations;
2156
2440
  const xaiAuthority = await xaiAuthorityForAgentActor(db, input.workspaceId, input.actor);
2157
2441
  const session = await lockSession(db, input.workspaceId, input.targetSessionId);
2158
2442
  if (session.status === "cancelled") {
@@ -2195,6 +2479,12 @@ export async function sendAgentMessageInTransaction(
2195
2479
  callerTurnId: input.actor.turnId,
2196
2480
  callerAttemptId: input.actor.attemptId,
2197
2481
  callerExecutionGeneration: input.actor.executionGeneration,
2482
+ ...(inheritedConnectionAuthority.connectionAuthoritySubjectId
2483
+ ? {
2484
+ connectionAuthoritySubjectId:
2485
+ inheritedConnectionAuthority.connectionAuthoritySubjectId,
2486
+ }
2487
+ : {}),
2198
2488
  ...(xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}),
2199
2489
  },
2200
2490
  personalConnectionDelegations,
@@ -2210,29 +2500,52 @@ export async function sendAgentMessageInTransaction(
2210
2500
  )
2211
2501
  .returning({ id: schema.sessionSystemUpdates.id });
2212
2502
  if (!update) throw new SessionControlInvariantError("Agent message was not inserted");
2213
- const [event] = await db
2214
- .insert(schema.sessionEvents)
2215
- .values(
2216
- withLosslessContentWriteVersion(
2217
- {
2218
- accountId: input.accountId,
2219
- workspaceId: input.workspaceId,
2220
- sessionId: input.targetSessionId,
2221
- sequence: session.lastSequence + 1,
2222
- type: "system.update.pending",
2223
- payload: {
2224
- updateId: update.id,
2225
- kind: "agent_message",
2226
- sourceSessionId: input.actor.sessionId,
2503
+ // An Agent message is external input for the target's goal. A goal paused
2504
+ // only by its continuation ceiling (`max_auto_continuations`, pacing rather
2505
+ // than intent) resumes in this same commit; any other pause stays. Goal row
2506
+ // FOR UPDATE follows the session lock above, the goal tools' order.
2507
+ const goalAutoResumed = await autoResumeGoalPausedByCapInTransaction(db, {
2508
+ workspaceId: input.workspaceId,
2509
+ sessionId: input.targetSessionId,
2510
+ cause: { kind: "agent_message", updateId: update.id },
2511
+ now,
2512
+ });
2513
+ const eventValues: SessionEventInsertWithPayload[] = [
2514
+ {
2515
+ accountId: input.accountId,
2516
+ workspaceId: input.workspaceId,
2517
+ sessionId: input.targetSessionId,
2518
+ sequence: session.lastSequence + 1,
2519
+ type: "system.update.pending",
2520
+ payload: {
2521
+ updateId: update.id,
2522
+ kind: "agent_message",
2523
+ sourceSessionId: input.actor.sessionId,
2524
+ },
2525
+ occurredAt: now,
2526
+ },
2527
+ ...(goalAutoResumed
2528
+ ? [
2529
+ {
2530
+ accountId: input.accountId,
2531
+ workspaceId: input.workspaceId,
2532
+ sessionId: input.targetSessionId,
2533
+ sequence: session.lastSequence + 2,
2534
+ type: "goal.resumed" as const,
2535
+ payload: goalAutoResumed.payload,
2536
+ occurredAt: now,
2227
2537
  },
2228
- occurredAt: now,
2229
- },
2230
- "payload",
2231
- "payloadCodecVersion",
2232
- ),
2233
- )
2538
+ ]
2539
+ : []),
2540
+ ];
2541
+ const insertedEvents = await db
2542
+ .insert(schema.sessionEvents)
2543
+ .values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
2234
2544
  .returning({ id: schema.sessionEvents.id });
2235
- if (!event) throw new SessionControlInvariantError("Agent message event was not inserted");
2545
+ if (insertedEvents.length !== eventValues.length) {
2546
+ throw new SessionControlInvariantError("Agent message event was not inserted");
2547
+ }
2548
+ const eventIds = insertedEvents.map((event) => event.id);
2236
2549
  const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
2237
2550
  const runnable = !realtimeActive && session.activeTurnId === null && effective.state === "active";
2238
2551
  const wake = runnable
@@ -2246,7 +2559,7 @@ export async function sendAgentMessageInTransaction(
2246
2559
  await db
2247
2560
  .update(schema.sessions)
2248
2561
  .set({
2249
- lastSequence: session.lastSequence + 1,
2562
+ lastSequence: session.lastSequence + eventValues.length,
2250
2563
  ...(runnable ? { status: "queued" as const } : {}),
2251
2564
  updatedAt: now,
2252
2565
  })
@@ -2275,7 +2588,7 @@ export async function sendAgentMessageInTransaction(
2275
2588
  const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
2276
2589
  result: {
2277
2590
  updateId: update.id,
2278
- eventIds: [event.id],
2591
+ eventIds,
2279
2592
  wakeRevision: wake?.wakeRevision ?? null,
2280
2593
  workflowId,
2281
2594
  effectiveState: effective.state,
@@ -2284,7 +2597,7 @@ export async function sendAgentMessageInTransaction(
2284
2597
  return {
2285
2598
  receipt,
2286
2599
  updateId: update.id,
2287
- eventIds: [event.id],
2600
+ eventIds,
2288
2601
  wakeRevision: wake?.wakeRevision ?? null,
2289
2602
  shouldSignal: wake?.shouldSignal ?? false,
2290
2603
  workflowId,
@@ -2304,9 +2617,18 @@ export async function steerAgentSessionInTransaction(
2304
2617
  actor: Extract<SessionCommandActor, { type: "agent_attempt" }>;
2305
2618
  operationKey: string;
2306
2619
  instruction: string;
2620
+ /** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
2621
+ controlLockTimeoutMs?: number;
2307
2622
  },
2308
2623
  ): Promise<AgentInternalUpdateCommandResult> {
2309
- await lockWorkspaceInferenceControl(db, input.workspaceId, "update");
2624
+ const admission = await lockWorkspaceInferenceControlForAdmission(db, {
2625
+ workspaceId: input.workspaceId,
2626
+ sessionId: input.targetSessionId,
2627
+ resumePausedBranch: true,
2628
+ ...(input.controlLockTimeoutMs !== undefined
2629
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
2630
+ : {}),
2631
+ });
2310
2632
  await lockSessionEventWriteRows(db, {
2311
2633
  workspaceId: input.workspaceId,
2312
2634
  controlLock: "already_locked",
@@ -2358,17 +2680,20 @@ export async function steerAgentSessionInTransaction(
2358
2680
  targetSessionId: input.targetSessionId,
2359
2681
  action: "steer",
2360
2682
  });
2361
- const personalConnectionDelegations = await personalConnectionDelegationsForAgentActor(
2683
+ const inheritedConnectionAuthority = await personalConnectionDelegationsForAgentActor(
2362
2684
  db,
2363
2685
  input.workspaceId,
2364
2686
  input.actor,
2687
+ input.targetSessionId,
2365
2688
  );
2689
+ const personalConnectionDelegations = inheritedConnectionAuthority.delegations;
2366
2690
  const xaiAuthority = await xaiAuthorityForAgentActor(db, input.workspaceId, input.actor);
2367
2691
  const resumed = await autoResumeSessionBranchInTransaction(db, {
2368
2692
  workspaceId: input.workspaceId,
2369
2693
  sessionId: input.targetSessionId,
2370
2694
  actor: `attempt:${input.actor.attemptId}`,
2371
2695
  reason: "agent_steer",
2696
+ admission,
2372
2697
  });
2373
2698
  const session = await lockSession(db, input.workspaceId, input.targetSessionId);
2374
2699
  if (session.status === "cancelled") {
@@ -2378,6 +2703,20 @@ export async function steerAgentSessionInTransaction(
2378
2703
  { queueVersion: session.queueVersion },
2379
2704
  );
2380
2705
  }
2706
+ const now = new Date();
2707
+ const updateId = crypto.randomUUID();
2708
+ // An Agent Steer is external input for the target's goal. A goal paused only
2709
+ // by its continuation ceiling (`max_auto_continuations`, pacing rather than
2710
+ // intent) resumes here, before the supersession, so the Steer starts a fresh
2711
+ // continuation epoch; any other pause stays. Goal row FOR UPDATE follows the
2712
+ // session lock above; the `goal.resumed` fact is appended below at the next
2713
+ // sequence of this same commit.
2714
+ const goalAutoResumed = await autoResumeGoalPausedByCapInTransaction(db, {
2715
+ workspaceId: input.workspaceId,
2716
+ sessionId: input.targetSessionId,
2717
+ cause: { kind: "agent_steer_instruction", updateId },
2718
+ now,
2719
+ });
2381
2720
  const supersession = await supersedeSessionCurrentDirectionInTransaction(db, {
2382
2721
  accountId: input.accountId,
2383
2722
  workspaceId: input.workspaceId,
@@ -2400,13 +2739,13 @@ export async function steerAgentSessionInTransaction(
2400
2739
  ),
2401
2740
  )
2402
2741
  .returning({ id: schema.sessionSystemUpdates.id });
2403
- const now = new Date();
2404
2742
  const [update] = await db
2405
2743
  .insert(schema.sessionSystemUpdates)
2406
2744
  .values(
2407
2745
  withLosslessContentWriteVersion(
2408
2746
  withLosslessContentWriteVersion(
2409
2747
  {
2748
+ id: updateId,
2410
2749
  accountId: input.accountId,
2411
2750
  workspaceId: input.workspaceId,
2412
2751
  sessionId: input.targetSessionId,
@@ -2425,6 +2764,12 @@ export async function steerAgentSessionInTransaction(
2425
2764
  callerTurnId: input.actor.turnId,
2426
2765
  callerAttemptId: input.actor.attemptId,
2427
2766
  callerExecutionGeneration: input.actor.executionGeneration,
2767
+ ...(inheritedConnectionAuthority.connectionAuthoritySubjectId
2768
+ ? {
2769
+ connectionAuthoritySubjectId:
2770
+ inheritedConnectionAuthority.connectionAuthoritySubjectId,
2771
+ }
2772
+ : {}),
2428
2773
  ...(xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}),
2429
2774
  },
2430
2775
  personalConnectionDelegations,
@@ -2506,6 +2851,17 @@ export async function steerAgentSessionInTransaction(
2506
2851
  occurredAt: now,
2507
2852
  },
2508
2853
  );
2854
+ if (goalAutoResumed) {
2855
+ events.push({
2856
+ accountId: input.accountId,
2857
+ workspaceId: input.workspaceId,
2858
+ sessionId: input.targetSessionId,
2859
+ sequence: ++sequence,
2860
+ type: "goal.resumed",
2861
+ payload: goalAutoResumed.payload,
2862
+ occurredAt: now,
2863
+ });
2864
+ }
2509
2865
  const insertedEvents = await db
2510
2866
  .insert(schema.sessionEvents)
2511
2867
  .values(withLosslessContentWriteVersion(events, "payload", "payloadCodecVersion"))