@opengeni/db 0.36.1 → 3.1.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 (274) 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-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
  7. package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
  8. package/dist/{chunk-HSOWSYOX.js → chunk-NMUBV7Z5.js} +19 -11
  9. package/dist/chunk-NMUBV7Z5.js.map +1 -0
  10. package/dist/chunk-OF5OBB76.js +4457 -0
  11. package/dist/chunk-OF5OBB76.js.map +1 -0
  12. package/dist/{chunk-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
  13. package/dist/chunk-PR2WMLOQ.js.map +1 -0
  14. package/dist/{chunk-Z7VYMNPZ.js → chunk-SCPUJS53.js} +41 -4
  15. package/dist/chunk-SCPUJS53.js.map +1 -0
  16. package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
  17. package/dist/chunk-SIBYBA2D.js.map +1 -0
  18. package/dist/chunk-TIKF3KTI.js +383 -0
  19. package/dist/chunk-TIKF3KTI.js.map +1 -0
  20. package/dist/chunk-ZZ5LJEFX.js +516 -0
  21. package/dist/chunk-ZZ5LJEFX.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 +41 -0
  33. package/dist/connection-token-resolver.d.ts +30 -1
  34. package/dist/database.d.ts +19 -0
  35. package/dist/editable-artifact-durable-export.d.ts +10 -0
  36. package/dist/editable-artifact-durable-export.js +18 -3
  37. package/dist/editable-artifact-durable-export.js.map +1 -1
  38. package/dist/editable-artifacts.d.ts +2 -2
  39. package/dist/editable-artifacts.js +3 -3
  40. package/dist/governed-learning-activation-schema.d.ts +984 -0
  41. package/dist/governed-learning-activation.d.ts +98 -0
  42. package/dist/governed-learning-evaluator-schema.d.ts +633 -0
  43. package/dist/governed-learning-evaluator.d.ts +28 -0
  44. package/dist/index.d.ts +1633 -87
  45. package/dist/index.js +22004 -8109
  46. package/dist/index.js.map +1 -1
  47. package/dist/insights.d.ts +18 -0
  48. package/dist/integration-bindings.d.ts +1 -0
  49. package/dist/integration-facets.d.ts +30 -0
  50. package/dist/interaction-placement-loss.d.ts +22 -0
  51. package/dist/knowledge-source-sync-schema.d.ts +730 -0
  52. package/dist/knowledge-source-sync.d.ts +60 -0
  53. package/dist/managed-human-provisioning.d.ts +25 -0
  54. package/dist/memory-domain.d.ts +3 -3
  55. package/dist/migrate.d.ts +11 -1
  56. package/dist/migrate.js +1 -1
  57. package/dist/new-session-drafts.d.ts +43 -5
  58. package/dist/organization-membership-backfill.d.ts +174 -0
  59. package/dist/organization-membership-lifecycle.d.ts +162 -0
  60. package/dist/pr-review.d.ts +107 -0
  61. package/dist/preference-registry-schema.d.ts +2 -0
  62. package/dist/preference-registry.d.ts +2 -0
  63. package/dist/provision-roles.js +1 -1
  64. package/dist/runtime-posture.d.ts +23 -9
  65. package/dist/schema.d.ts +24925 -13697
  66. package/dist/schema.js +103 -1
  67. package/dist/scoped-knowledge-schema.d.ts +52 -1
  68. package/dist/session-background-commands.d.ts +125 -0
  69. package/dist/session-background-commands.js +34 -0
  70. package/dist/session-background-commands.js.map +1 -0
  71. package/dist/session-control.d.ts +156 -3
  72. package/dist/session-goal-pacing.d.ts +68 -0
  73. package/dist/session-queue-commands.d.ts +42 -5
  74. package/dist/session-realtime-ledger.d.ts +3 -0
  75. package/dist/session-tenancy.d.ts +71 -1
  76. package/dist/session-tenancy.js +25 -3
  77. package/dist/session-tool-call-settlement.d.ts +9 -4
  78. package/dist/slack-routing-personal-workspace.d.ts +23 -0
  79. package/dist/slack-routing.d.ts +153 -0
  80. package/dist/slack-task-policy-schema.d.ts +34 -0
  81. package/dist/slack-task-policy.d.ts +8 -0
  82. package/dist/slack-user-link-access.d.ts +1 -0
  83. package/dist/task-notes-schema.d.ts +594 -0
  84. package/dist/task-notes.d.ts +39 -0
  85. package/dist/turn-initiator.d.ts +2 -0
  86. package/dist/user-resource-authority.d.ts +109 -0
  87. package/dist/video-generation.js +3 -3
  88. package/dist/workspace-authority.d.ts +81 -0
  89. package/dist/workspace-instruction-policies-schema.d.ts +279 -0
  90. package/dist/workspace-instruction-policies.d.ts +62 -0
  91. package/dist/workspace-learning-policy.d.ts +1 -0
  92. package/dist/workspace-membership-permissions.d.ts +2 -0
  93. package/drizzle/0240_enrollment_connection_authority.sql +39 -0
  94. package/drizzle/0240_model_context_user_messages.sql +204 -0
  95. package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
  96. package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
  97. package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
  98. package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
  99. package/drizzle/0245_model_context_contribution_facts.sql +88 -0
  100. package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
  101. package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
  102. package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
  103. package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
  104. package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
  105. package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
  106. package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
  107. package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
  108. package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
  109. package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
  110. package/drizzle/0256_connection_authority_delegation.sql +703 -0
  111. package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
  112. package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
  113. package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
  114. package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
  115. package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
  116. package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
  117. package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
  118. package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
  119. package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
  120. package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
  121. package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
  122. package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
  123. package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
  124. package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
  125. package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
  126. package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
  127. package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
  128. package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
  129. package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
  130. package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
  131. package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
  132. package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
  133. package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
  134. package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
  135. package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
  136. package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
  137. package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
  138. package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
  139. package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
  140. package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
  141. package/drizzle/0289_session_composer_policy_authority.sql +597 -0
  142. package/drizzle/0290_organization_membership_backfill.sql +268 -0
  143. package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
  144. package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
  145. package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
  146. package/drizzle/0294_preference_activation_authority.sql +237 -0
  147. package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
  148. package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
  149. package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
  150. package/drizzle/0298_organization_tenancy_parity.sql +609 -0
  151. package/drizzle/0299_organization_membership_lock_order.sql +291 -0
  152. package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
  153. package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
  154. package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
  155. package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
  156. package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
  157. package/drizzle/0305_personal_resource_grant_management.sql +584 -0
  158. package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
  159. package/drizzle/0307_session_attention_state.sql +51 -0
  160. package/drizzle/0308_session_archives.sql +35 -0
  161. package/drizzle/0309_channel_project_pins.sql +6 -0
  162. package/drizzle/0310_channel_project_order.sql +27 -0
  163. package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
  164. package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
  165. package/drizzle/0313_private_child_session_authority.sql +365 -0
  166. package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
  167. package/drizzle/0315_personal_github_repository_selection.sql +624 -0
  168. package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
  169. package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
  170. package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
  171. package/drizzle/0319_event_triggered_automations.sql +254 -0
  172. package/drizzle/0320_pr_review_pack.sql +113 -0
  173. package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
  174. package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
  175. package/drizzle/0323_organization_private_session_enablement.sql +489 -0
  176. package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
  177. package/drizzle/0325_child_lifecycle_notices.sql +44 -0
  178. package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
  179. package/drizzle/0327_slack_first_task_hint.sql +29 -0
  180. package/drizzle/0328_session_background_commands.sql +590 -0
  181. package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
  182. package/drizzle/0330_api_key_descriptions.sql +20 -0
  183. package/drizzle/0331_managed_organization_creation.sql +163 -0
  184. package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
  185. package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
  186. package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
  187. package/drizzle/0335_slack_workspace_routing.sql +460 -0
  188. package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
  189. package/drizzle/0337_slack_routed_action_handles.sql +189 -0
  190. package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
  191. package/drizzle/0339_document_authority_reclassification.sql +1153 -0
  192. package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
  193. package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -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 +81 -0
  212. package/src/connection-token-resolver.ts +263 -31
  213. package/src/database.ts +75 -2
  214. package/src/editable-artifact-durable-export.ts +27 -0
  215. package/src/editable-artifacts-schema.ts +10 -5
  216. package/src/editable-artifacts.ts +21 -11
  217. package/src/governed-learning-activation-schema.ts +121 -0
  218. package/src/governed-learning-activation.ts +588 -0
  219. package/src/governed-learning-evaluator-schema.ts +72 -0
  220. package/src/governed-learning-evaluator.ts +217 -0
  221. package/src/index.ts +12001 -1699
  222. package/src/insights.ts +107 -0
  223. package/src/integration-bindings.ts +88 -6
  224. package/src/integration-facets.ts +287 -84
  225. package/src/interaction-placement-loss.ts +234 -0
  226. package/src/knowledge-source-sync-schema.ts +83 -0
  227. package/src/knowledge-source-sync.ts +530 -0
  228. package/src/managed-human-provisioning.ts +116 -0
  229. package/src/memory-domain.ts +27 -32
  230. package/src/migrate.ts +77 -1
  231. package/src/new-session-drafts.ts +229 -35
  232. package/src/organization-membership-backfill.ts +735 -0
  233. package/src/organization-membership-lifecycle.ts +985 -0
  234. package/src/pr-review.ts +890 -0
  235. package/src/preference-registry.ts +31 -1
  236. package/src/provision-roles.ts +931 -24
  237. package/src/runtime-posture-cli.ts +2 -0
  238. package/src/runtime-posture.ts +1315 -52
  239. package/src/schema.ts +3336 -438
  240. package/src/scoped-knowledge-schema.ts +16 -8
  241. package/src/scoped-knowledge.ts +1 -1
  242. package/src/session-background-commands.ts +759 -0
  243. package/src/session-control.ts +640 -74
  244. package/src/session-goal-pacing.ts +126 -0
  245. package/src/session-queue-commands.ts +450 -98
  246. package/src/session-realtime-context.ts +19 -3
  247. package/src/session-realtime-ledger.ts +75 -12
  248. package/src/session-realtime-mirror.ts +1 -1
  249. package/src/session-tenancy.ts +403 -49
  250. package/src/session-tool-call-settlement.ts +38 -29
  251. package/src/slack-routing-personal-workspace.ts +67 -0
  252. package/src/slack-routing.ts +469 -0
  253. package/src/slack-task-policy-schema.ts +5 -0
  254. package/src/slack-task-policy.ts +18 -0
  255. package/src/slack-user-link-access.ts +17 -1
  256. package/src/task-notes-schema.ts +74 -0
  257. package/src/task-notes.ts +124 -2
  258. package/src/turn-initiator.ts +8 -0
  259. package/src/user-resource-authority.ts +377 -0
  260. package/src/workspace-authority.ts +160 -0
  261. package/src/workspace-instruction-policies-schema.ts +53 -1
  262. package/src/workspace-instruction-policies.ts +528 -77
  263. package/src/workspace-learning-policy.ts +21 -5
  264. package/src/workspace-membership-permissions.ts +9 -0
  265. package/dist/chunk-5KTIEDX7.js.map +0 -1
  266. package/dist/chunk-FPVAD4CO.js +0 -117
  267. package/dist/chunk-FPVAD4CO.js.map +0 -1
  268. package/dist/chunk-HSOWSYOX.js.map +0 -1
  269. package/dist/chunk-SK7YYHBI.js.map +0 -1
  270. package/dist/chunk-VKLB2ZGI.js +0 -2389
  271. package/dist/chunk-VKLB2ZGI.js.map +0 -1
  272. package/dist/chunk-Z7VYMNPZ.js.map +0 -1
  273. /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
  274. /package/dist/{chunk-VTPRIXKG.js.map → chunk-NJVZPWXY.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
  }
@@ -1414,7 +1533,7 @@ export async function submitHumanPromptInTransaction(
1414
1533
  expectedDraftRevision?: number | null;
1415
1534
  text: string;
1416
1535
  annotations?: TimelineAnnotation[];
1417
- turnInstructions?: string | null;
1536
+ modelContext?: string | null;
1418
1537
  resources: ResourceRef[];
1419
1538
  model?: string | null;
1420
1539
  reasoningEffort?: ReasoningEffort | null;
@@ -1434,14 +1553,34 @@ export async function submitHumanPromptInTransaction(
1434
1553
  /** Record the admitted run's durable usage fact in this transaction. */
1435
1554
  recordAgentRunUsage?: boolean;
1436
1555
  personalConnectionDelegations?: McpPersonalConnectionDelegation[];
1556
+ personalResourceAttachment?: PersonalResourceAttachmentIntent;
1437
1557
  mcpCredentialUpdates?: Array<{
1438
1558
  id: string;
1439
1559
  headersEncrypted: Record<string, string>;
1440
1560
  }>;
1561
+ /** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
1562
+ controlLockTimeoutMs?: number;
1441
1563
  },
1442
1564
  ): Promise<SubmitHumanPromptResult> {
1443
1565
  const annotations = TimelineAnnotations.parse(input.annotations ?? []);
1444
- const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "update");
1566
+ // Send is inert queue admission while paused; Steer deliberately resumes.
1567
+ // Tell the lock helper which path may need the exclusive control prefix.
1568
+ const admission = await lockWorkspaceInferenceControlForAdmission(db, {
1569
+ workspaceId: input.workspaceId,
1570
+ sessionId: input.sessionId,
1571
+ resumePausedBranch: input.delivery === "steer",
1572
+ ...(input.controlLockTimeoutMs !== undefined
1573
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
1574
+ : {}),
1575
+ });
1576
+ const workspaceControl = admission.control;
1577
+ if (input.actor.type === "human") {
1578
+ await setSubjectRlsContext(db, input.actor.subjectId);
1579
+ await assertActiveManagedHumanOrganizationMembership(db, {
1580
+ accountId: input.accountId,
1581
+ subjectId: input.actor.subjectId,
1582
+ });
1583
+ }
1445
1584
  await lockSessionEventWriteRows(db, {
1446
1585
  workspaceId: input.workspaceId,
1447
1586
  controlLock: "already_locked",
@@ -1458,7 +1597,7 @@ export async function submitHumanPromptInTransaction(
1458
1597
  expectedDraftRevision: input.expectedDraftRevision ?? null,
1459
1598
  text: input.text,
1460
1599
  annotations,
1461
- turnInstructions: input.turnInstructions ?? null,
1600
+ modelContext: input.modelContext ?? null,
1462
1601
  resources: withCanonicalResourceMountPaths(input.resources),
1463
1602
  model: input.model ?? null,
1464
1603
  reasoningEffort: input.reasoningEffort ?? null,
@@ -1467,6 +1606,8 @@ export async function submitHumanPromptInTransaction(
1467
1606
  turnMetadata: input.turnMetadata ?? {},
1468
1607
  messagePresentation: input.messagePresentation ?? null,
1469
1608
  mcpCredentialUpdates: input.mcpCredentialUpdates ?? [],
1609
+ personalConnectionDelegations: input.personalConnectionDelegations ?? [],
1610
+ personalResourceAttachment: input.personalResourceAttachment ?? null,
1470
1611
  ...(input.actor.type === "service"
1471
1612
  ? {
1472
1613
  serviceInitiator: {
@@ -1524,12 +1665,32 @@ export async function submitHumanPromptInTransaction(
1524
1665
  if (!accepted || !replayTurn || events.length !== eventIds.length) {
1525
1666
  throw new SessionControlInvariantError("Replayed prompt rows are incomplete");
1526
1667
  }
1668
+ const replayDraft =
1669
+ input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1670
+ ? null
1671
+ : await getComposerDraftInTransaction(db, {
1672
+ workspaceId: input.workspaceId,
1673
+ sessionId: input.sessionId,
1674
+ subjectId: input.subjectId,
1675
+ });
1527
1676
  return {
1528
1677
  receipt: reserved.receipt,
1678
+ routing:
1679
+ reserved.receipt.result.routing === "accepted_for_execution" ||
1680
+ reserved.receipt.result.routing === "queued_for_execution" ||
1681
+ reserved.receipt.result.routing === "accepted_for_steering"
1682
+ ? reserved.receipt.result.routing
1683
+ : input.delivery === "steer"
1684
+ ? "accepted_for_steering"
1685
+ : // Pre-routing receipts cannot reconstruct admission-time activity
1686
+ // or Pause truth. Queue is the only conservative placement; a
1687
+ // later turn.started event moves it into chat without duplication.
1688
+ "queued_for_execution",
1529
1689
  queueVersion: Number(reserved.receipt.appliedQueueVersion),
1530
1690
  accepted,
1531
1691
  events,
1532
1692
  turn: mapSubmittedPromptTurn(replayTurn),
1693
+ draft: replayDraft,
1533
1694
  acceptedEventId,
1534
1695
  eventIds,
1535
1696
  turnId,
@@ -1550,34 +1711,39 @@ export async function submitHumanPromptInTransaction(
1550
1711
  throw new SessionControlConflictError();
1551
1712
  }
1552
1713
 
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
1714
  const session = await lockSession(db, input.workspaceId, input.sessionId);
1571
1715
  if (session.status === "cancelled") {
1572
1716
  throw new QueueCommandConflictError(
1573
1717
  "QUEUE_PROMPT_STARTED",
1574
- "Cancelled session cannot accept work",
1575
- {
1576
- queueVersion: session.queueVersion,
1577
- },
1718
+ "Cancelled session subtree cannot accept work",
1719
+ { queueVersion: session.queueVersion },
1578
1720
  );
1579
1721
  }
1580
1722
 
1723
+ // Send is queue admission, never a hidden control mutation. A paused Send
1724
+ // remains inert behind the existing gate until the user explicitly resumes.
1725
+ // Steer is the intentional exception: it replaces the current direction and
1726
+ // therefore activates the selected branch atomically.
1727
+ const resumed =
1728
+ input.delivery === "send"
1729
+ ? {
1730
+ revision: before.controlVersion,
1731
+ control: before,
1732
+ changed: false,
1733
+ workspaceControlEventId: null,
1734
+ }
1735
+ : await autoResumeSessionBranchInTransaction(db, {
1736
+ workspaceId: input.workspaceId,
1737
+ sessionId: input.sessionId,
1738
+ actor:
1739
+ input.actor.type === "agent_attempt"
1740
+ ? `attempt:${input.actor.attemptId}`
1741
+ : input.actor.subjectId,
1742
+ reason: input.actor.type === "service" ? "service_steer" : "human_steer",
1743
+ observedControlEtag: input.controlEtag ?? null,
1744
+ admission,
1745
+ });
1746
+
1581
1747
  const draft =
1582
1748
  input.expectedDraftRevision === null || input.expectedDraftRevision === undefined
1583
1749
  ? null
@@ -1626,7 +1792,7 @@ export async function submitHumanPromptInTransaction(
1626
1792
  }
1627
1793
 
1628
1794
  let editedSourceTurn: QueuedTurnRow | undefined;
1629
- let editedSourceTurnInstructions: string | null | undefined;
1795
+ let editedSourceModelContext: string | null | undefined;
1630
1796
  if (draft?.sourceTurnId) {
1631
1797
  const sourceLocks = await lockSessionEventWriteRows(db, {
1632
1798
  workspaceId: input.workspaceId,
@@ -1661,14 +1827,11 @@ export async function submitHumanPromptInTransaction(
1661
1827
  },
1662
1828
  );
1663
1829
  }
1664
- // This is the sole private-instruction source for an edited replacement.
1665
- // It is deliberately held separately from the public draft and event
1666
- // projections below. The public draft is expected to differ after editing;
1667
- // source identity is fenced by its exact withdrawn row version, not by
1668
- // comparing the replacement content with the old prompt. A client-supplied
1669
- // instruction value must never override the private source value.
1830
+ // Preserve the non-rendered message segment when editing only the visible
1831
+ // draft. Source identity is fenced by the exact withdrawn row version; a
1832
+ // replacement request cannot accidentally detach or replace its context.
1670
1833
  editedSourceTurn = sourceTurn;
1671
- editedSourceTurnInstructions = sourceTurn.turnInstructions ?? null;
1834
+ editedSourceModelContext = sourceTurn.modelContext ?? null;
1672
1835
  }
1673
1836
 
1674
1837
  for (const update of input.mcpCredentialUpdates ?? []) {
@@ -1713,6 +1876,28 @@ export async function submitHumanPromptInTransaction(
1713
1876
  input.subjectLabel,
1714
1877
  );
1715
1878
  }
1879
+ const acceptedInitiatingHumanSubjectId = editedSourceTurn
1880
+ ? (editedSourceTurn.initiatingHumanSubjectId ??
1881
+ (editedSourceTurn.initiatorKind === "subject" ? editedSourceTurn.initiatorSubjectId : null))
1882
+ : (frozenInitiator.initiatingHumanSubjectId ??
1883
+ (frozenInitiator.initiator.kind === "subject" ? frozenInitiator.initiator.subjectId : null));
1884
+ if (
1885
+ (input.personalConnectionDelegations ?? []).some(
1886
+ (delegation) => delegation.userDelegation !== undefined,
1887
+ ) ||
1888
+ input.personalResourceAttachment !== undefined
1889
+ ) {
1890
+ if (!acceptedInitiatingHumanSubjectId) {
1891
+ throw new SessionControlInvariantError("Personal authority requires an exact causal human");
1892
+ }
1893
+ await db.execute(
1894
+ sql`select set_config(
1895
+ 'opengeni.initiating_human_subject_id',
1896
+ ${acceptedInitiatingHumanSubjectId},
1897
+ true
1898
+ )`,
1899
+ );
1900
+ }
1716
1901
  const xaiProviderAccountAuthoritySnapshot = editedSourceTurn
1717
1902
  ? XaiProviderAccountAuthoritySnapshotV1.parse(
1718
1903
  editedSourceTurn.xaiProviderAccountAuthoritySnapshot,
@@ -1725,6 +1910,17 @@ export async function submitHumanPromptInTransaction(
1725
1910
  const acceptedEventId = crypto.randomUUID();
1726
1911
  const turnId = crypto.randomUUID();
1727
1912
  const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
1913
+ const effectiveModelContext =
1914
+ editedSourceModelContext !== undefined
1915
+ ? editedSourceModelContext
1916
+ : (input.modelContext ?? null);
1917
+ const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
1918
+ const routing: SessionPromptRouting =
1919
+ input.delivery === "steer"
1920
+ ? "accepted_for_steering"
1921
+ : before.state === "paused" || session.activeTurnId || existingQueued.length > 0
1922
+ ? "queued_for_execution"
1923
+ : "accepted_for_execution";
1728
1924
  let sequence = session.lastSequence;
1729
1925
  const eventValues: SessionEventInsertWithPayload[] = [
1730
1926
  {
@@ -1747,16 +1943,17 @@ export async function submitHumanPromptInTransaction(
1747
1943
  }
1748
1944
  : {}),
1749
1945
  ...(input.resources.length ? { resources: input.resources } : {}),
1946
+ ...(effectiveModelContext ? { modelContext: effectiveModelContext } : {}),
1750
1947
  ...(input.model ? { model: input.model } : {}),
1751
1948
  ...(input.reasoningEffort ? { reasoningEffort: input.reasoningEffort } : {}),
1752
1949
  ...(input.latencyMode ? { latencyMode: input.latencyMode } : {}),
1753
1950
  delivery: input.delivery,
1951
+ routing,
1754
1952
  initiator: frozenInitiator.initiator,
1755
1953
  },
1756
1954
  occurredAt: now,
1757
1955
  },
1758
1956
  ];
1759
- const existingQueued = await loadQueuedTurns(db, input.workspaceId, input.sessionId, true);
1760
1957
  const [turn] = await db
1761
1958
  .insert(schema.sessionTurns)
1762
1959
  .values(
@@ -1770,13 +1967,11 @@ export async function submitHumanPromptInTransaction(
1770
1967
  temporalWorkflowId: workflowId,
1771
1968
  status: "queued",
1772
1969
  source: input.source,
1970
+ promptRouting: routing,
1773
1971
  position: input.delivery === "steer" ? 0 : existingQueued.length + 1,
1774
1972
  prompt: input.text,
1775
1973
  annotations,
1776
- turnInstructions:
1777
- editedSourceTurnInstructions !== undefined
1778
- ? editedSourceTurnInstructions
1779
- : (input.turnInstructions ?? null),
1974
+ modelContext: effectiveModelContext,
1780
1975
  resources: input.resources,
1781
1976
  tools: [],
1782
1977
  toolsProvided: false,
@@ -1789,14 +1984,7 @@ export async function submitHumanPromptInTransaction(
1789
1984
  : (input.turnMetadata ?? {}),
1790
1985
  lineage: { actor: input.actor.type },
1791
1986
  ...initiatorColumns(frozenInitiator),
1792
- initiatingHumanSubjectId: editedSourceTurn
1793
- ? (editedSourceTurn.initiatingHumanSubjectId ??
1794
- (editedSourceTurn.initiatorKind === "subject"
1795
- ? editedSourceTurn.initiatorSubjectId
1796
- : null))
1797
- : frozenInitiator.initiator.kind === "subject"
1798
- ? frozenInitiator.initiator.subjectId
1799
- : null,
1987
+ initiatingHumanSubjectId: acceptedInitiatingHumanSubjectId,
1800
1988
  personalConnectionDelegations: editedSourceTurn
1801
1989
  ? editedSourceTurn.personalConnectionDelegations
1802
1990
  : (input.personalConnectionDelegations ?? []),
@@ -1811,6 +1999,49 @@ export async function submitHumanPromptInTransaction(
1811
1999
  .returning();
1812
2000
  if (!turn) throw new SessionControlInvariantError("Prompt turn was not inserted");
1813
2001
  let committedTurn = turn;
2002
+ const personalResourceExpectedAuthorityEpoch =
2003
+ input.personalResourceAttachment?.expectedAuthorityEpoch;
2004
+ let acceptedPersonalResources: Awaited<
2005
+ ReturnType<typeof acceptTurnPersonalResourceAttachmentInTransaction>
2006
+ > | null = null;
2007
+ if (input.personalResourceAttachment) {
2008
+ if (personalResourceExpectedAuthorityEpoch === undefined) {
2009
+ throw new SessionControlInvariantError(
2010
+ "Personal-resource attachment requires an expected authority epoch",
2011
+ );
2012
+ }
2013
+ acceptedPersonalResources = await acceptTurnPersonalResourceAttachmentInTransaction(db, {
2014
+ accountId: input.accountId,
2015
+ workspaceId: input.workspaceId,
2016
+ sessionId: input.sessionId,
2017
+ turnId,
2018
+ subjectId: acceptedInitiatingHumanSubjectId!,
2019
+ intent: {
2020
+ ...input.personalResourceAttachment,
2021
+ expectedAuthorityEpoch: personalResourceExpectedAuthorityEpoch,
2022
+ },
2023
+ });
2024
+ }
2025
+ if (acceptedPersonalResources) {
2026
+ committedTurn = {
2027
+ ...turn,
2028
+ personalResourceAttachmentSummary: acceptedPersonalResources.summary,
2029
+ personalResourceProtocolVersion: 1,
2030
+ };
2031
+ eventValues.push({
2032
+ accountId: input.accountId,
2033
+ workspaceId: input.workspaceId,
2034
+ sessionId: input.sessionId,
2035
+ turnId,
2036
+ sequence: ++sequence,
2037
+ type: "session.personal_resources.attached",
2038
+ payload: {
2039
+ turnId,
2040
+ ...acceptedPersonalResources.summary,
2041
+ },
2042
+ occurredAt: now,
2043
+ });
2044
+ }
1814
2045
  eventValues.push({
1815
2046
  accountId: input.accountId,
1816
2047
  workspaceId: input.workspaceId,
@@ -1822,6 +2053,7 @@ export async function submitHumanPromptInTransaction(
1822
2053
  turnId,
1823
2054
  triggerEventId: acceptedEventId,
1824
2055
  source: input.source,
2056
+ routing,
1825
2057
  initiator: frozenInitiator.initiator,
1826
2058
  },
1827
2059
  occurredAt: now,
@@ -1920,6 +2152,29 @@ export async function submitHumanPromptInTransaction(
1920
2152
  });
1921
2153
  }
1922
2154
 
2155
+ // A human/API prompt is external input for the goal. A goal paused only by
2156
+ // its continuation ceiling (`max_auto_continuations`, pacing rather than
2157
+ // intent) resumes in this same commit; a user/API/agent/limits pause is never
2158
+ // touched here. Goal row FOR UPDATE follows the session and turn locks above,
2159
+ // the order the claim transaction uses.
2160
+ const goalAutoResumed = await autoResumeGoalPausedByCapInTransaction(db, {
2161
+ workspaceId: input.workspaceId,
2162
+ sessionId: input.sessionId,
2163
+ cause: { kind: "human_prompt", turnId },
2164
+ now,
2165
+ });
2166
+ if (goalAutoResumed) {
2167
+ eventValues.push({
2168
+ accountId: input.accountId,
2169
+ workspaceId: input.workspaceId,
2170
+ sessionId: input.sessionId,
2171
+ sequence: ++sequence,
2172
+ type: "goal.resumed",
2173
+ payload: goalAutoResumed.payload,
2174
+ occurredAt: now,
2175
+ });
2176
+ }
2177
+
1923
2178
  const ordered =
1924
2179
  input.delivery === "steer" ? [turn, ...existingQueued] : [...existingQueued, turn];
1925
2180
  await normalizeQueuePositions(
@@ -1947,12 +2202,6 @@ export async function submitHumanPromptInTransaction(
1947
2202
  .values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
1948
2203
  .returning();
1949
2204
  if (input.actor.type === "human") {
1950
- const realtimeRouting =
1951
- input.delivery === "steer"
1952
- ? "accepted_for_steering"
1953
- : session.activeTurnId || existingQueued.length > 0
1954
- ? "queued_for_execution"
1955
- : "accepted_for_execution";
1956
2205
  await mirrorSessionRealtimeContextInTransaction(db, {
1957
2206
  accountId: input.accountId,
1958
2207
  workspaceId: input.workspaceId,
@@ -1963,12 +2212,12 @@ export async function submitHumanPromptInTransaction(
1963
2212
  channel: null,
1964
2213
  text: renderRealtimeHumanInputContext({
1965
2214
  delivery: input.delivery,
1966
- routing: realtimeRouting,
2215
+ routing,
1967
2216
  text: renderTimelineAnnotationsForModel(input.text, annotations),
1968
2217
  }),
1969
2218
  payload: {
1970
2219
  delivery: input.delivery,
1971
- routing: realtimeRouting,
2220
+ routing,
1972
2221
  acceptedEventId,
1973
2222
  instruction: "OpenGeni accepted and routed this user input; do not delegate it again.",
1974
2223
  },
@@ -1990,8 +2239,25 @@ export async function submitHumanPromptInTransaction(
1990
2239
  updatedAt: now,
1991
2240
  })
1992
2241
  .where(eq(schema.sessions.id, input.sessionId));
1993
- if (draft) {
1994
- await db.delete(schema.composerDrafts).where(eq(schema.composerDrafts.id, draft.id));
2242
+ const [nextDraft] = draft
2243
+ ? await db
2244
+ .update(schema.composerDrafts)
2245
+ .set({
2246
+ revision: draft.revision + 1,
2247
+ text: "",
2248
+ annotations: [],
2249
+ resources: [],
2250
+ tools: [],
2251
+ toolsProvided: false,
2252
+ sourceTurnId: null,
2253
+ sourceTurnVersion: null,
2254
+ updatedAt: now,
2255
+ })
2256
+ .where(eq(schema.composerDrafts.id, draft.id))
2257
+ .returning()
2258
+ : [undefined];
2259
+ if (draft && !nextDraft) {
2260
+ throw new SessionControlInvariantError("Accepted composer draft did not rotate");
1995
2261
  }
1996
2262
  const wakeRevision = await registerSessionWorkflowWakeInTransaction(db, {
1997
2263
  accountId: input.accountId,
@@ -2052,7 +2318,7 @@ export async function submitHumanPromptInTransaction(
2052
2318
  controlRevision: resumed.revision,
2053
2319
  queueVersion,
2054
2320
  turnVersion: turn.version,
2055
- ...(draft ? { draftRevision: draft.revision } : {}),
2321
+ ...(nextDraft ? { draftRevision: nextDraft.revision } : {}),
2056
2322
  result: {
2057
2323
  turnId,
2058
2324
  acceptedEventId,
@@ -2061,6 +2327,7 @@ export async function submitHumanPromptInTransaction(
2061
2327
  interruptionCount,
2062
2328
  replacedTurnId,
2063
2329
  workspaceControlEventId: resumed.workspaceControlEventId,
2330
+ routing,
2064
2331
  ...(input.turnExecutionPolicy
2065
2332
  ? {
2066
2333
  executionPolicy: turnExecutionPolicyAuditMetadata(input.turnExecutionPolicy, turnId),
@@ -2075,10 +2342,12 @@ export async function submitHumanPromptInTransaction(
2075
2342
  }
2076
2343
  return {
2077
2344
  receipt,
2345
+ routing,
2078
2346
  queueVersion,
2079
2347
  accepted,
2080
2348
  events,
2081
2349
  turn: mapSubmittedPromptTurn(committedTurn),
2350
+ draft: nextDraft ?? null,
2082
2351
  acceptedEventId,
2083
2352
  eventIds,
2084
2353
  turnId,
@@ -2098,9 +2367,18 @@ export async function sendAgentMessageInTransaction(
2098
2367
  actor: Extract<SessionCommandActor, { type: "agent_attempt" }>;
2099
2368
  operationKey: string;
2100
2369
  text: string;
2370
+ /**
2371
+ * Bound the workspace control prefix wait (request-scoped API callers pass
2372
+ * `workspaceControlRequestLockTimeoutMs()`); omit for lifecycle callers.
2373
+ */
2374
+ controlLockTimeoutMs?: number;
2101
2375
  },
2102
2376
  ): Promise<AgentInternalUpdateCommandResult> {
2103
- const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "share");
2377
+ const workspaceControl = await lockWorkspaceInferenceControl(db, input.workspaceId, "share", {
2378
+ ...(input.controlLockTimeoutMs !== undefined
2379
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
2380
+ : {}),
2381
+ });
2104
2382
  await lockSessionEventWriteRows(db, {
2105
2383
  workspaceId: input.workspaceId,
2106
2384
  controlLock: "already_locked",
@@ -2149,11 +2427,13 @@ export async function sendAgentMessageInTransaction(
2149
2427
  targetSessionId: input.targetSessionId,
2150
2428
  action: "message",
2151
2429
  });
2152
- const personalConnectionDelegations = await personalConnectionDelegationsForAgentActor(
2430
+ const inheritedConnectionAuthority = await personalConnectionDelegationsForAgentActor(
2153
2431
  db,
2154
2432
  input.workspaceId,
2155
2433
  input.actor,
2434
+ input.targetSessionId,
2156
2435
  );
2436
+ const personalConnectionDelegations = inheritedConnectionAuthority.delegations;
2157
2437
  const xaiAuthority = await xaiAuthorityForAgentActor(db, input.workspaceId, input.actor);
2158
2438
  const session = await lockSession(db, input.workspaceId, input.targetSessionId);
2159
2439
  if (session.status === "cancelled") {
@@ -2196,6 +2476,12 @@ export async function sendAgentMessageInTransaction(
2196
2476
  callerTurnId: input.actor.turnId,
2197
2477
  callerAttemptId: input.actor.attemptId,
2198
2478
  callerExecutionGeneration: input.actor.executionGeneration,
2479
+ ...(inheritedConnectionAuthority.connectionAuthoritySubjectId
2480
+ ? {
2481
+ connectionAuthoritySubjectId:
2482
+ inheritedConnectionAuthority.connectionAuthoritySubjectId,
2483
+ }
2484
+ : {}),
2199
2485
  ...(xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}),
2200
2486
  },
2201
2487
  personalConnectionDelegations,
@@ -2211,29 +2497,52 @@ export async function sendAgentMessageInTransaction(
2211
2497
  )
2212
2498
  .returning({ id: schema.sessionSystemUpdates.id });
2213
2499
  if (!update) throw new SessionControlInvariantError("Agent message was not inserted");
2214
- const [event] = await db
2215
- .insert(schema.sessionEvents)
2216
- .values(
2217
- withLosslessContentWriteVersion(
2218
- {
2219
- accountId: input.accountId,
2220
- workspaceId: input.workspaceId,
2221
- sessionId: input.targetSessionId,
2222
- sequence: session.lastSequence + 1,
2223
- type: "system.update.pending",
2224
- payload: {
2225
- updateId: update.id,
2226
- kind: "agent_message",
2227
- sourceSessionId: input.actor.sessionId,
2500
+ // An Agent message is external input for the target's goal. A goal paused
2501
+ // only by its continuation ceiling (`max_auto_continuations`, pacing rather
2502
+ // than intent) resumes in this same commit; any other pause stays. Goal row
2503
+ // FOR UPDATE follows the session lock above, the goal tools' order.
2504
+ const goalAutoResumed = await autoResumeGoalPausedByCapInTransaction(db, {
2505
+ workspaceId: input.workspaceId,
2506
+ sessionId: input.targetSessionId,
2507
+ cause: { kind: "agent_message", updateId: update.id },
2508
+ now,
2509
+ });
2510
+ const eventValues: SessionEventInsertWithPayload[] = [
2511
+ {
2512
+ accountId: input.accountId,
2513
+ workspaceId: input.workspaceId,
2514
+ sessionId: input.targetSessionId,
2515
+ sequence: session.lastSequence + 1,
2516
+ type: "system.update.pending",
2517
+ payload: {
2518
+ updateId: update.id,
2519
+ kind: "agent_message",
2520
+ sourceSessionId: input.actor.sessionId,
2521
+ },
2522
+ occurredAt: now,
2523
+ },
2524
+ ...(goalAutoResumed
2525
+ ? [
2526
+ {
2527
+ accountId: input.accountId,
2528
+ workspaceId: input.workspaceId,
2529
+ sessionId: input.targetSessionId,
2530
+ sequence: session.lastSequence + 2,
2531
+ type: "goal.resumed" as const,
2532
+ payload: goalAutoResumed.payload,
2533
+ occurredAt: now,
2228
2534
  },
2229
- occurredAt: now,
2230
- },
2231
- "payload",
2232
- "payloadCodecVersion",
2233
- ),
2234
- )
2535
+ ]
2536
+ : []),
2537
+ ];
2538
+ const insertedEvents = await db
2539
+ .insert(schema.sessionEvents)
2540
+ .values(withLosslessContentWriteVersion(eventValues, "payload", "payloadCodecVersion"))
2235
2541
  .returning({ id: schema.sessionEvents.id });
2236
- if (!event) throw new SessionControlInvariantError("Agent message event was not inserted");
2542
+ if (insertedEvents.length !== eventValues.length) {
2543
+ throw new SessionControlInvariantError("Agent message event was not inserted");
2544
+ }
2545
+ const eventIds = insertedEvents.map((event) => event.id);
2237
2546
  const workflowId = session.temporalWorkflowId ?? `session-${session.id}`;
2238
2547
  const runnable = !realtimeActive && session.activeTurnId === null && effective.state === "active";
2239
2548
  const wake = runnable
@@ -2247,7 +2556,7 @@ export async function sendAgentMessageInTransaction(
2247
2556
  await db
2248
2557
  .update(schema.sessions)
2249
2558
  .set({
2250
- lastSequence: session.lastSequence + 1,
2559
+ lastSequence: session.lastSequence + eventValues.length,
2251
2560
  ...(runnable ? { status: "queued" as const } : {}),
2252
2561
  updatedAt: now,
2253
2562
  })
@@ -2276,7 +2585,7 @@ export async function sendAgentMessageInTransaction(
2276
2585
  const receipt = await updateSessionCommandReceiptResult(db, reserved.receipt.id, {
2277
2586
  result: {
2278
2587
  updateId: update.id,
2279
- eventIds: [event.id],
2588
+ eventIds,
2280
2589
  wakeRevision: wake?.wakeRevision ?? null,
2281
2590
  workflowId,
2282
2591
  effectiveState: effective.state,
@@ -2285,7 +2594,7 @@ export async function sendAgentMessageInTransaction(
2285
2594
  return {
2286
2595
  receipt,
2287
2596
  updateId: update.id,
2288
- eventIds: [event.id],
2597
+ eventIds,
2289
2598
  wakeRevision: wake?.wakeRevision ?? null,
2290
2599
  shouldSignal: wake?.shouldSignal ?? false,
2291
2600
  workflowId,
@@ -2305,9 +2614,18 @@ export async function steerAgentSessionInTransaction(
2305
2614
  actor: Extract<SessionCommandActor, { type: "agent_attempt" }>;
2306
2615
  operationKey: string;
2307
2616
  instruction: string;
2617
+ /** Request-scoped callers bound the control prefix wait; lifecycle callers omit it. */
2618
+ controlLockTimeoutMs?: number;
2308
2619
  },
2309
2620
  ): Promise<AgentInternalUpdateCommandResult> {
2310
- await lockWorkspaceInferenceControl(db, input.workspaceId, "update");
2621
+ const admission = await lockWorkspaceInferenceControlForAdmission(db, {
2622
+ workspaceId: input.workspaceId,
2623
+ sessionId: input.targetSessionId,
2624
+ resumePausedBranch: true,
2625
+ ...(input.controlLockTimeoutMs !== undefined
2626
+ ? { lockTimeoutMs: input.controlLockTimeoutMs }
2627
+ : {}),
2628
+ });
2311
2629
  await lockSessionEventWriteRows(db, {
2312
2630
  workspaceId: input.workspaceId,
2313
2631
  controlLock: "already_locked",
@@ -2359,17 +2677,20 @@ export async function steerAgentSessionInTransaction(
2359
2677
  targetSessionId: input.targetSessionId,
2360
2678
  action: "steer",
2361
2679
  });
2362
- const personalConnectionDelegations = await personalConnectionDelegationsForAgentActor(
2680
+ const inheritedConnectionAuthority = await personalConnectionDelegationsForAgentActor(
2363
2681
  db,
2364
2682
  input.workspaceId,
2365
2683
  input.actor,
2684
+ input.targetSessionId,
2366
2685
  );
2686
+ const personalConnectionDelegations = inheritedConnectionAuthority.delegations;
2367
2687
  const xaiAuthority = await xaiAuthorityForAgentActor(db, input.workspaceId, input.actor);
2368
2688
  const resumed = await autoResumeSessionBranchInTransaction(db, {
2369
2689
  workspaceId: input.workspaceId,
2370
2690
  sessionId: input.targetSessionId,
2371
2691
  actor: `attempt:${input.actor.attemptId}`,
2372
2692
  reason: "agent_steer",
2693
+ admission,
2373
2694
  });
2374
2695
  const session = await lockSession(db, input.workspaceId, input.targetSessionId);
2375
2696
  if (session.status === "cancelled") {
@@ -2379,6 +2700,20 @@ export async function steerAgentSessionInTransaction(
2379
2700
  { queueVersion: session.queueVersion },
2380
2701
  );
2381
2702
  }
2703
+ const now = new Date();
2704
+ const updateId = crypto.randomUUID();
2705
+ // An Agent Steer is external input for the target's goal. A goal paused only
2706
+ // by its continuation ceiling (`max_auto_continuations`, pacing rather than
2707
+ // intent) resumes here, before the supersession, so the Steer starts a fresh
2708
+ // continuation epoch; any other pause stays. Goal row FOR UPDATE follows the
2709
+ // session lock above; the `goal.resumed` fact is appended below at the next
2710
+ // sequence of this same commit.
2711
+ const goalAutoResumed = await autoResumeGoalPausedByCapInTransaction(db, {
2712
+ workspaceId: input.workspaceId,
2713
+ sessionId: input.targetSessionId,
2714
+ cause: { kind: "agent_steer_instruction", updateId },
2715
+ now,
2716
+ });
2382
2717
  const supersession = await supersedeSessionCurrentDirectionInTransaction(db, {
2383
2718
  accountId: input.accountId,
2384
2719
  workspaceId: input.workspaceId,
@@ -2401,13 +2736,13 @@ export async function steerAgentSessionInTransaction(
2401
2736
  ),
2402
2737
  )
2403
2738
  .returning({ id: schema.sessionSystemUpdates.id });
2404
- const now = new Date();
2405
2739
  const [update] = await db
2406
2740
  .insert(schema.sessionSystemUpdates)
2407
2741
  .values(
2408
2742
  withLosslessContentWriteVersion(
2409
2743
  withLosslessContentWriteVersion(
2410
2744
  {
2745
+ id: updateId,
2411
2746
  accountId: input.accountId,
2412
2747
  workspaceId: input.workspaceId,
2413
2748
  sessionId: input.targetSessionId,
@@ -2426,6 +2761,12 @@ export async function steerAgentSessionInTransaction(
2426
2761
  callerTurnId: input.actor.turnId,
2427
2762
  callerAttemptId: input.actor.attemptId,
2428
2763
  callerExecutionGeneration: input.actor.executionGeneration,
2764
+ ...(inheritedConnectionAuthority.connectionAuthoritySubjectId
2765
+ ? {
2766
+ connectionAuthoritySubjectId:
2767
+ inheritedConnectionAuthority.connectionAuthoritySubjectId,
2768
+ }
2769
+ : {}),
2429
2770
  ...(xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}),
2430
2771
  },
2431
2772
  personalConnectionDelegations,
@@ -2507,6 +2848,17 @@ export async function steerAgentSessionInTransaction(
2507
2848
  occurredAt: now,
2508
2849
  },
2509
2850
  );
2851
+ if (goalAutoResumed) {
2852
+ events.push({
2853
+ accountId: input.accountId,
2854
+ workspaceId: input.workspaceId,
2855
+ sessionId: input.targetSessionId,
2856
+ sequence: ++sequence,
2857
+ type: "goal.resumed",
2858
+ payload: goalAutoResumed.payload,
2859
+ occurredAt: now,
2860
+ });
2861
+ }
2510
2862
  const insertedEvents = await db
2511
2863
  .insert(schema.sessionEvents)
2512
2864
  .values(withLosslessContentWriteVersion(events, "payload", "payloadCodecVersion"))