@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.
- package/dist/attached-browser-devices.d.ts +7 -0
- package/dist/automations.d.ts +154 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/capability-integrations.d.ts +13 -0
- package/dist/child-lifecycle-notices.d.ts +68 -0
- package/dist/{chunk-GYO7ED2Q.js → chunk-EULAN2NP.js} +2 -2
- package/dist/{chunk-VTPRIXKG.js → chunk-NJVZPWXY.js} +3 -3
- package/dist/{chunk-HSOWSYOX.js → chunk-NMUBV7Z5.js} +19 -11
- package/dist/chunk-NMUBV7Z5.js.map +1 -0
- package/dist/chunk-OF5OBB76.js +4457 -0
- package/dist/chunk-OF5OBB76.js.map +1 -0
- package/dist/{chunk-5KTIEDX7.js → chunk-PR2WMLOQ.js} +7714 -4443
- package/dist/chunk-PR2WMLOQ.js.map +1 -0
- package/dist/{chunk-Z7VYMNPZ.js → chunk-SCPUJS53.js} +41 -4
- package/dist/chunk-SCPUJS53.js.map +1 -0
- package/dist/{chunk-SK7YYHBI.js → chunk-SIBYBA2D.js} +46 -1
- package/dist/chunk-SIBYBA2D.js.map +1 -0
- package/dist/chunk-TIKF3KTI.js +383 -0
- package/dist/chunk-TIKF3KTI.js.map +1 -0
- package/dist/chunk-ZZ5LJEFX.js +516 -0
- package/dist/chunk-ZZ5LJEFX.js.map +1 -0
- package/dist/codemode-operations.d.ts +1 -6
- package/dist/company-brain-context-selection-schema.d.ts +705 -0
- package/dist/company-brain-context-selection.d.ts +94 -0
- package/dist/company-brain-governed-writes.d.ts +24 -0
- package/dist/company-brain.d.ts +55 -0
- package/dist/company-profile-agent-admin.d.ts +15 -0
- package/dist/company-profile-schema.d.ts +619 -2
- package/dist/company-profile.d.ts +9 -4
- package/dist/connection-authority.d.ts +95 -0
- package/dist/connection-scopes.d.ts +8 -0
- package/dist/connection-tenancy-backfill.d.ts +41 -0
- package/dist/connection-token-resolver.d.ts +30 -1
- package/dist/database.d.ts +19 -0
- package/dist/editable-artifact-durable-export.d.ts +10 -0
- package/dist/editable-artifact-durable-export.js +18 -3
- package/dist/editable-artifact-durable-export.js.map +1 -1
- package/dist/editable-artifacts.d.ts +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/governed-learning-activation-schema.d.ts +984 -0
- package/dist/governed-learning-activation.d.ts +98 -0
- package/dist/governed-learning-evaluator-schema.d.ts +633 -0
- package/dist/governed-learning-evaluator.d.ts +28 -0
- package/dist/index.d.ts +1633 -87
- package/dist/index.js +22004 -8109
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +18 -0
- package/dist/integration-bindings.d.ts +1 -0
- package/dist/integration-facets.d.ts +30 -0
- package/dist/interaction-placement-loss.d.ts +22 -0
- package/dist/knowledge-source-sync-schema.d.ts +730 -0
- package/dist/knowledge-source-sync.d.ts +60 -0
- package/dist/managed-human-provisioning.d.ts +25 -0
- package/dist/memory-domain.d.ts +3 -3
- package/dist/migrate.d.ts +11 -1
- package/dist/migrate.js +1 -1
- package/dist/new-session-drafts.d.ts +43 -5
- package/dist/organization-membership-backfill.d.ts +174 -0
- package/dist/organization-membership-lifecycle.d.ts +162 -0
- package/dist/pr-review.d.ts +107 -0
- package/dist/preference-registry-schema.d.ts +2 -0
- package/dist/preference-registry.d.ts +2 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +23 -9
- package/dist/schema.d.ts +24925 -13697
- package/dist/schema.js +103 -1
- package/dist/scoped-knowledge-schema.d.ts +52 -1
- package/dist/session-background-commands.d.ts +125 -0
- package/dist/session-background-commands.js +34 -0
- package/dist/session-background-commands.js.map +1 -0
- package/dist/session-control.d.ts +156 -3
- package/dist/session-goal-pacing.d.ts +68 -0
- package/dist/session-queue-commands.d.ts +42 -5
- package/dist/session-realtime-ledger.d.ts +3 -0
- package/dist/session-tenancy.d.ts +71 -1
- package/dist/session-tenancy.js +25 -3
- package/dist/session-tool-call-settlement.d.ts +9 -4
- package/dist/slack-routing-personal-workspace.d.ts +23 -0
- package/dist/slack-routing.d.ts +153 -0
- package/dist/slack-task-policy-schema.d.ts +34 -0
- package/dist/slack-task-policy.d.ts +8 -0
- package/dist/slack-user-link-access.d.ts +1 -0
- package/dist/task-notes-schema.d.ts +594 -0
- package/dist/task-notes.d.ts +39 -0
- package/dist/turn-initiator.d.ts +2 -0
- package/dist/user-resource-authority.d.ts +109 -0
- package/dist/video-generation.js +3 -3
- package/dist/workspace-authority.d.ts +81 -0
- package/dist/workspace-instruction-policies-schema.d.ts +279 -0
- package/dist/workspace-instruction-policies.d.ts +62 -0
- package/dist/workspace-learning-policy.d.ts +1 -0
- package/dist/workspace-membership-permissions.d.ts +2 -0
- package/drizzle/0240_enrollment_connection_authority.sql +39 -0
- package/drizzle/0240_model_context_user_messages.sql +204 -0
- package/drizzle/0241_atomic_personal_resource_delegation.sql +1000 -0
- package/drizzle/0241_enrollment_agent_runtime.sql +70 -0
- package/drizzle/0243_google_drive_object_acl_authority.sql +554 -0
- package/drizzle/0244_slack_app_home_refresh_queue.sql +120 -0
- package/drizzle/0245_model_context_contribution_facts.sql +88 -0
- package/drizzle/0246_integration_personal_instance_authority.sql +70 -0
- package/drizzle/0247_terraform_stacks_provenance_repair.sql +428 -0
- package/drizzle/0248_terraform_stacks_component_resolution_fence.sql +83 -0
- package/drizzle/0249_personal_resource_delegation_authority_correction.sql +662 -0
- package/drizzle/0250_direct_retained_process_owner_liveness.sql +199 -0
- package/drizzle/0251_connected_machine_operation_policy.sql +45 -0
- package/drizzle/0252_scheduled_personal_resource_delegation.sql +1867 -0
- package/drizzle/0253_common_user_resource_authority_lifecycle.sql +1555 -0
- package/drizzle/0254_scoped_variable_set_authority.sql +1255 -0
- package/drizzle/0255_company_brain_governed_write_proposals.sql +524 -0
- package/drizzle/0256_connection_authority_delegation.sql +703 -0
- package/drizzle/0257_goal_revision_decisions_and_root_constraints.sql +436 -0
- package/drizzle/0258_three_scope_document_knowledge_authority.sql +1273 -0
- package/drizzle/0259_company_brain_context_selection_receipts.sql +869 -0
- package/drizzle/0260_task_note_knowledge_promotion.sql +820 -0
- package/drizzle/0261_preference_knowledge_proposal_actor_binding.sql +471 -0
- package/drizzle/0262_scoped_connected_machines_and_rigs.sql +1700 -0
- package/drizzle/0263_organization_membership_lifecycle.sql +3284 -0
- package/drizzle/0264_connection_authority_runtime_activation.sql +1084 -0
- package/drizzle/0266_company_brain_context_receipt_inspection.sql +156 -0
- package/drizzle/0268_governed_learning_decision_receipts.sql +825 -0
- package/drizzle/0269_governed_learning_activation_controller.sql +1874 -0
- package/drizzle/0270_governed_learning_history_inspection.sql +170 -0
- package/drizzle/0271_company_brain_retrieval_only_default.sql +524 -0
- package/drizzle/0272_human_confirmed_learning_activation.sql +591 -0
- package/drizzle/0273_scheduled_variable_set_materialization.sql +268 -0
- package/drizzle/0274_human_confirmed_knowledge_review.sql +310 -0
- package/drizzle/0275_scheduled_connection_authority.sql +5527 -0
- package/drizzle/0276_onboarding_proposal_initiating_human_guc.sql +198 -0
- package/drizzle/0277_workspace_writer_authority_attribution.sql +393 -0
- package/drizzle/0278_workspace_membership_removal_fencing.sql +1174 -0
- package/drizzle/0279_workspace_connection_use_lane.sql +343 -0
- package/drizzle/0280_connection_and_variable_set_audit_attribution.sql +773 -0
- package/drizzle/0281_viewer_holder_authority_claims.sql +52 -0
- package/drizzle/0282_variable_set_session_attach_attribution.sql +178 -0
- package/drizzle/0283_editable_spreadsheet_authored_state.sql +82 -0
- package/drizzle/0284_truthful_human_confirmed_review_reason.sql +930 -0
- package/drizzle/0285_organization_tenancy_inventory.sql +329 -0
- package/drizzle/0286_widen_task_note_expiry_ceiling.sql +391 -0
- package/drizzle/0287_open_suffix_pending_tool_calls.sql +18 -0
- package/drizzle/0288_attached_browser_reenrollment.sql +64 -0
- package/drizzle/0289_session_composer_policy_authority.sql +597 -0
- package/drizzle/0290_organization_membership_backfill.sql +268 -0
- package/drizzle/0291_resource_authority_classification_assertion.sql +371 -0
- package/drizzle/0292_truthful_tenancy_inventory_counters.sql +291 -0
- package/drizzle/0293_confirm_time_rule_rebaseline.sql +615 -0
- package/drizzle/0294_preference_activation_authority.sql +237 -0
- package/drizzle/0295_retire_legacy_standing_memory_mode.sql +476 -0
- package/drizzle/0296_force_rls_backfill_noop_repair.sql +215 -0
- package/drizzle/0297_session_ownership_classification_and_backfill.sql +752 -0
- package/drizzle/0298_organization_tenancy_parity.sql +609 -0
- package/drizzle/0299_organization_membership_lock_order.sql +291 -0
- package/drizzle/0300_tenancy_backfill_ledger.sql +459 -0
- package/drizzle/0301_session_snapshot_and_pin_visibility.sql +181 -0
- package/drizzle/0302_personal_workspace_session_ownership.sql +303 -0
- package/drizzle/0303_session_tenancy_product_activation.sql +919 -0
- package/drizzle/0304_personal_workspace_private_session_reads.sql +97 -0
- package/drizzle/0305_personal_resource_grant_management.sql +584 -0
- package/drizzle/0306_atomic_personal_resource_attachments.sql +1374 -0
- package/drizzle/0307_session_attention_state.sql +51 -0
- package/drizzle/0308_session_archives.sql +35 -0
- package/drizzle/0309_channel_project_pins.sql +6 -0
- package/drizzle/0310_channel_project_order.sql +27 -0
- package/drizzle/0311_company_scope_and_private_session_create.sql +656 -0
- package/drizzle/0312_quiescent_session_tree_deletion.sql +39 -0
- package/drizzle/0313_private_child_session_authority.sql +365 -0
- package/drizzle/0314_unregistered_organization_invitations.sql +606 -0
- package/drizzle/0315_personal_github_repository_selection.sql +624 -0
- package/drizzle/0316_human_confirmed_activation_resumed_generation.sql +869 -0
- package/drizzle/0317_session_goal_continuation_hold.sql +64 -0
- package/drizzle/0318_session_turn_startup_milestones.sql +115 -0
- package/drizzle/0319_event_triggered_automations.sql +254 -0
- package/drizzle/0320_pr_review_pack.sql +113 -0
- package/drizzle/0321_slack_bot_environment_display_name.sql +15 -0
- package/drizzle/0322_session_turns_unclaimed_prompt_trigger_index.sql +5 -0
- package/drizzle/0323_organization_private_session_enablement.sql +489 -0
- package/drizzle/0324_human_confirmed_company_profile_agent_admin.sql +856 -0
- package/drizzle/0325_child_lifecycle_notices.sql +44 -0
- package/drizzle/0326_interaction_operation_error_codes.sql +62 -0
- package/drizzle/0327_slack_first_task_hint.sql +29 -0
- package/drizzle/0328_session_background_commands.sql +590 -0
- package/drizzle/0329_slack_orchestration_delivery_events.sql +91 -0
- package/drizzle/0330_api_key_descriptions.sql +20 -0
- package/drizzle/0331_managed_organization_creation.sql +163 -0
- package/drizzle/0332_organization_shared_workspace_control_plane.sql +539 -0
- package/drizzle/0333_session_turn_prompt_routing.sql +45 -0
- package/drizzle/0334_connected_machine_workspace_root.sql +99 -0
- package/drizzle/0335_slack_workspace_routing.sql +460 -0
- package/drizzle/0336_atomic_session_fork_visibility.sql +667 -0
- package/drizzle/0337_slack_routed_action_handles.sql +189 -0
- package/drizzle/0338_atomic_connected_machine_attachments.sql +410 -0
- package/drizzle/0339_document_authority_reclassification.sql +1153 -0
- package/drizzle/0340_tenancy_backfill_activation_evidence.sql +1347 -0
- package/drizzle/0341_slack_routing_probe_organization_fence.sql +109 -0
- package/package.json +10 -6
- package/src/attached-browser-devices.ts +233 -5
- package/src/automations.ts +911 -0
- package/src/browser-sessions.ts +10 -0
- package/src/capability-integrations.ts +175 -1
- package/src/child-lifecycle-notices.ts +241 -0
- package/src/codemode-operations.ts +1 -35
- package/src/company-brain-context-selection-schema.ts +100 -0
- package/src/company-brain-context-selection.ts +359 -0
- package/src/company-brain-governed-writes.ts +1170 -0
- package/src/company-brain.ts +309 -0
- package/src/company-profile-agent-admin.ts +225 -0
- package/src/company-profile-schema.ts +121 -1
- package/src/company-profile.ts +21 -0
- package/src/computer-sessions.ts +10 -1
- package/src/connection-authority.ts +290 -0
- package/src/connection-scopes.ts +20 -0
- package/src/connection-tenancy-backfill.ts +81 -0
- package/src/connection-token-resolver.ts +263 -31
- package/src/database.ts +75 -2
- package/src/editable-artifact-durable-export.ts +27 -0
- package/src/editable-artifacts-schema.ts +10 -5
- package/src/editable-artifacts.ts +21 -11
- package/src/governed-learning-activation-schema.ts +121 -0
- package/src/governed-learning-activation.ts +588 -0
- package/src/governed-learning-evaluator-schema.ts +72 -0
- package/src/governed-learning-evaluator.ts +217 -0
- package/src/index.ts +12001 -1699
- package/src/insights.ts +107 -0
- package/src/integration-bindings.ts +88 -6
- package/src/integration-facets.ts +287 -84
- package/src/interaction-placement-loss.ts +234 -0
- package/src/knowledge-source-sync-schema.ts +83 -0
- package/src/knowledge-source-sync.ts +530 -0
- package/src/managed-human-provisioning.ts +116 -0
- package/src/memory-domain.ts +27 -32
- package/src/migrate.ts +77 -1
- package/src/new-session-drafts.ts +229 -35
- package/src/organization-membership-backfill.ts +735 -0
- package/src/organization-membership-lifecycle.ts +985 -0
- package/src/pr-review.ts +890 -0
- package/src/preference-registry.ts +31 -1
- package/src/provision-roles.ts +931 -24
- package/src/runtime-posture-cli.ts +2 -0
- package/src/runtime-posture.ts +1315 -52
- package/src/schema.ts +3336 -438
- package/src/scoped-knowledge-schema.ts +16 -8
- package/src/scoped-knowledge.ts +1 -1
- package/src/session-background-commands.ts +759 -0
- package/src/session-control.ts +640 -74
- package/src/session-goal-pacing.ts +126 -0
- package/src/session-queue-commands.ts +450 -98
- package/src/session-realtime-context.ts +19 -3
- package/src/session-realtime-ledger.ts +75 -12
- package/src/session-realtime-mirror.ts +1 -1
- package/src/session-tenancy.ts +403 -49
- package/src/session-tool-call-settlement.ts +38 -29
- package/src/slack-routing-personal-workspace.ts +67 -0
- package/src/slack-routing.ts +469 -0
- package/src/slack-task-policy-schema.ts +5 -0
- package/src/slack-task-policy.ts +18 -0
- package/src/slack-user-link-access.ts +17 -1
- package/src/task-notes-schema.ts +74 -0
- package/src/task-notes.ts +124 -2
- package/src/turn-initiator.ts +8 -0
- package/src/user-resource-authority.ts +377 -0
- package/src/workspace-authority.ts +160 -0
- package/src/workspace-instruction-policies-schema.ts +53 -1
- package/src/workspace-instruction-policies.ts +528 -77
- package/src/workspace-learning-policy.ts +21 -5
- package/src/workspace-membership-permissions.ts +9 -0
- package/dist/chunk-5KTIEDX7.js.map +0 -1
- package/dist/chunk-FPVAD4CO.js +0 -117
- package/dist/chunk-FPVAD4CO.js.map +0 -1
- package/dist/chunk-HSOWSYOX.js.map +0 -1
- package/dist/chunk-SK7YYHBI.js.map +0 -1
- package/dist/chunk-VKLB2ZGI.js +0 -2389
- package/dist/chunk-VKLB2ZGI.js.map +0 -1
- package/dist/chunk-Z7VYMNPZ.js.map +0 -1
- /package/dist/{chunk-GYO7ED2Q.js.map → chunk-EULAN2NP.js.map} +0 -0
- /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
|
|
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:
|
|
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
|
-
|
|
230
|
+
targetSessionId: string,
|
|
231
|
+
): Promise<{
|
|
232
|
+
delegations: McpPersonalConnectionDelegation[];
|
|
233
|
+
connectionAuthoritySubjectId: string | null;
|
|
234
|
+
}> {
|
|
215
235
|
const [row] = await db
|
|
216
|
-
.select({
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
1665
|
-
//
|
|
1666
|
-
//
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
|
2215
|
+
routing,
|
|
1967
2216
|
text: renderTimelineAnnotationsForModel(input.text, annotations),
|
|
1968
2217
|
}),
|
|
1969
2218
|
payload: {
|
|
1970
2219
|
delivery: input.delivery,
|
|
1971
|
-
routing
|
|
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
|
-
|
|
1994
|
-
await db
|
|
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
|
-
...(
|
|
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
|
|
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
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
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
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
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 (
|
|
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 +
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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"))
|