@opengeni/worker-bundle 1.0.1 → 2.0.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 (122) hide show
  1. package/dist/activities/agent-turn/codex.d.ts +1 -1
  2. package/dist/activities/agent-turn/compaction-prep.d.ts +1 -5
  3. package/dist/activities/agent-turn/errors.d.ts +31 -5
  4. package/dist/activities/agent-turn/finalization-monitor.d.ts +17 -0
  5. package/dist/activities/agent-turn/finalization.d.ts +1 -1
  6. package/dist/activities/agent-turn/governance-model.d.ts +0 -2
  7. package/dist/activities/agent-turn/quiescence.d.ts +1 -0
  8. package/dist/activities/agent-turn/recovery-warning.d.ts +8 -0
  9. package/dist/activities/agent-turn/run-credentials.d.ts +0 -1
  10. package/dist/activities/agent-turn/sandbox-establish.d.ts +1 -1
  11. package/dist/activities/agent-turn/sandbox-route.d.ts +0 -20
  12. package/dist/activities/agent-turn/sandbox-runtime.d.ts +1 -1
  13. package/dist/activities/agent-turn/skill-remove.d.ts +14 -0
  14. package/dist/activities/agent-turn/skill-search.d.ts +1 -1
  15. package/dist/activities/agent-turn/stream-attempt.d.ts +1 -0
  16. package/dist/activities/agent-turn/tool-environment.d.ts +0 -4
  17. package/dist/activities/agent-turn/turn-context.d.ts +2 -0
  18. package/dist/activities/agent-turn/turn-sandbox-access.d.ts +3 -0
  19. package/dist/activities/codex-capacity.d.ts +6 -1
  20. package/dist/activities/codex-rotation.d.ts +1 -1
  21. package/dist/activities/context-compaction.d.ts +7 -1
  22. package/dist/activities/mcp-account-routes.d.ts +22 -0
  23. package/dist/activities/mcp-credentials.d.ts +12 -13
  24. package/dist/activities/mcp-operation-authority.d.ts +0 -5
  25. package/dist/activities/rig-verification.d.ts +2 -3
  26. package/dist/activities/sandbox-images.d.ts +1 -1
  27. package/dist/activities/sandbox-lease.d.ts +4 -3
  28. package/dist/activities/session-state.d.ts +57 -2
  29. package/dist/activities/types.d.ts +12 -3
  30. package/dist/{activities-control-HMFGSKC5.js → activities-control-BOLIY3H4.js} +366 -187
  31. package/dist/activities-control-BOLIY3H4.js.map +1 -0
  32. package/dist/activities-control.d.ts +110 -2
  33. package/dist/{activities-turn-AP67JADS.js → activities-turn-2B3WMHBB.js} +767 -471
  34. package/dist/activities-turn-2B3WMHBB.js.map +1 -0
  35. package/dist/activities.d.ts +110 -2
  36. package/dist/artifact-materializer-entry.js +5 -2
  37. package/dist/artifact-materializer-entry.js.map +1 -1
  38. package/dist/artifact-outbox-entry.js +2 -2
  39. package/dist/artifact-outbox-entry.js.map +1 -1
  40. package/dist/{chunk-A4XQWVZK.js → chunk-I7HKKMUJ.js} +77 -1
  41. package/dist/chunk-I7HKKMUJ.js.map +1 -0
  42. package/dist/{chunk-CYITU5UH.js → chunk-TVEE2UUC.js} +275 -146
  43. package/dist/chunk-TVEE2UUC.js.map +1 -0
  44. package/dist/editable-artifact-materializer-service.d.ts +2 -2
  45. package/dist/editable-artifact-outbox-service.d.ts +2 -2
  46. package/dist/index.d.ts +55 -1
  47. package/dist/index.js +4 -3
  48. package/dist/index.js.map +1 -1
  49. package/dist/observability-metrics.d.ts +11 -3
  50. package/dist/retained-process-diagnostics.d.ts +4 -0
  51. package/dist/sandbox-resume.d.ts +2 -12
  52. package/dist/sandbox-routing.d.ts +5 -3
  53. package/dist/sandbox-snapshot-diagnostics.d.ts +20 -0
  54. package/dist/warm-capture-holder.d.ts +3 -0
  55. package/dist/workflow-bundle.js +51 -11
  56. package/package.json +15 -15
  57. package/src/activities/agent-turn/agent-build.ts +42 -5
  58. package/src/activities/agent-turn/claim.ts +12 -0
  59. package/src/activities/agent-turn/codex-capacity.ts +26 -4
  60. package/src/activities/agent-turn/codex.ts +6 -2
  61. package/src/activities/agent-turn/compaction-prep.ts +53 -72
  62. package/src/activities/agent-turn/errors.ts +98 -10
  63. package/src/activities/agent-turn/failure-settlement.ts +49 -28
  64. package/src/activities/agent-turn/finalization-monitor.ts +121 -0
  65. package/src/activities/agent-turn/finalization.ts +79 -21
  66. package/src/activities/agent-turn/governance-model.ts +15 -19
  67. package/src/activities/agent-turn/history.ts +24 -10
  68. package/src/activities/agent-turn/quiescence.ts +3 -0
  69. package/src/activities/agent-turn/recovery-warning.ts +18 -0
  70. package/src/activities/agent-turn/run-credentials.ts +3 -7
  71. package/src/activities/agent-turn/run.ts +68 -52
  72. package/src/activities/agent-turn/sandbox-establish.ts +10 -2
  73. package/src/activities/agent-turn/sandbox-route.ts +0 -20
  74. package/src/activities/agent-turn/sandbox-runtime.ts +40 -7
  75. package/src/activities/agent-turn/skill-remove.ts +46 -0
  76. package/src/activities/agent-turn/skill-save.ts +1 -1
  77. package/src/activities/agent-turn/skill-search.ts +1 -1
  78. package/src/activities/agent-turn/skill-selection.ts +2 -0
  79. package/src/activities/agent-turn/skill-tools.ts +10 -5
  80. package/src/activities/agent-turn/stream-attempt.ts +38 -15
  81. package/src/activities/agent-turn/tool-environment.ts +44 -29
  82. package/src/activities/agent-turn/turn-context.ts +3 -0
  83. package/src/activities/agent-turn/turn-sandbox-access.ts +7 -1
  84. package/src/activities/capabilities.ts +17 -2
  85. package/src/activities/codex-capacity.ts +38 -9
  86. package/src/activities/codex-rotation.ts +18 -5
  87. package/src/activities/context-compaction.ts +26 -4
  88. package/src/activities/goals.ts +1 -0
  89. package/src/activities/google-drive-publication.ts +1 -3
  90. package/src/activities/mcp-account-routes.ts +139 -0
  91. package/src/activities/mcp-credentials.ts +83 -194
  92. package/src/activities/mcp-operation-authority.ts +16 -41
  93. package/src/activities/parent-wake.ts +8 -0
  94. package/src/activities/rig-verification.ts +38 -37
  95. package/src/activities/run-input.ts +25 -16
  96. package/src/activities/sandbox-images.ts +0 -1
  97. package/src/activities/sandbox-lease.ts +177 -44
  98. package/src/activities/scheduled-tasks.ts +118 -93
  99. package/src/activities/session-state.ts +83 -3
  100. package/src/activities/types.ts +18 -2
  101. package/src/activities/workflow-wake.ts +2 -17
  102. package/src/editable-artifact-materializer-service.ts +7 -3
  103. package/src/editable-artifact-outbox-service.ts +4 -4
  104. package/src/github-rest-mcp.ts +0 -1
  105. package/src/index.ts +2 -1
  106. package/src/observability-metrics.ts +105 -2
  107. package/src/personal-github-git-credentials.ts +0 -1
  108. package/src/pr-review-credentials.ts +0 -2
  109. package/src/retained-process-diagnostics.ts +50 -0
  110. package/src/sandbox-resume.ts +58 -73
  111. package/src/sandbox-routing.ts +44 -19
  112. package/src/sandbox-snapshot-diagnostics.ts +112 -0
  113. package/src/warm-capture-holder.ts +15 -0
  114. package/src/workflows/session.ts +64 -2
  115. package/dist/activities/agent-turn/knowledge-sources.d.ts +0 -20
  116. package/dist/activities/packs.d.ts +0 -55
  117. package/dist/activities-control-HMFGSKC5.js.map +0 -1
  118. package/dist/activities-turn-AP67JADS.js.map +0 -1
  119. package/dist/chunk-A4XQWVZK.js.map +0 -1
  120. package/dist/chunk-CYITU5UH.js.map +0 -1
  121. package/src/activities/agent-turn/knowledge-sources.ts +0 -86
  122. package/src/activities/packs.ts +0 -166
@@ -22,6 +22,7 @@ import {
22
22
  codexUsageLimitFailurePayload,
23
23
  compactionFailureReason,
24
24
  compactionFailureReasonFromError,
25
+ compactionFailureTurnEventPayload,
25
26
  computeIdleDelayMs,
26
27
  createKnowledgeSourceSyncActivities,
27
28
  createModelHistoryAttachmentProjector,
@@ -56,7 +57,6 @@ import {
56
57
  refreshExhaustedXaiQuota,
57
58
  releaseTurnSandboxAfterWriterDrain,
58
59
  requireAgentStreamFinalOutput,
59
- resolveWorkspacePackRuntime,
60
60
  resumeBoxForTurn,
61
61
  rigProviderImageSourceImage,
62
62
  routingEnabled,
@@ -68,7 +68,6 @@ import {
68
68
  sandboxLifecycleTransitionDiagnostic,
69
69
  sandboxRouteTransitionCode,
70
70
  selectCodexCredentialLeaseForTurn,
71
- settingsWithPackSandboxImage,
72
71
  shouldRecoverCompactionProviderFailure,
73
72
  shouldRunTurnEndWorkspacePersistence,
74
73
  shouldStartPeriodicWorkspaceSnapshot,
@@ -87,7 +86,7 @@ import {
87
86
  withFirstPartyTools,
88
87
  wrapLazyTurnBoxWithRouting,
89
88
  wrapTurnBoxWithRouting
90
- } from "./chunk-CYITU5UH.js";
89
+ } from "./chunk-TVEE2UUC.js";
91
90
  import {
92
91
  StreamTimingMetrics,
93
92
  makeMachineOpObserver,
@@ -107,13 +106,14 @@ import {
107
106
  recordSessionEventAppendLatency,
108
107
  recordSessionEventAppendPhase,
109
108
  recordSessionEventPublishLatency,
109
+ recordToolPreparationPhase,
110
110
  recordTurnSandboxEstablishPolicy,
111
111
  recordTurnStartupMilestone,
112
112
  recordTurnStartupPhase,
113
113
  recordTurnWorkerPreparationTotal,
114
114
  runtimeMetricsHooksForObservability,
115
115
  turnLifecycleMetricsFor
116
- } from "./chunk-A4XQWVZK.js";
116
+ } from "./chunk-I7HKKMUJ.js";
117
117
  import {
118
118
  __export
119
119
  } from "./chunk-PZ5AY32C.js";
@@ -121,64 +121,8 @@ import {
121
121
  // src/activities-turn.ts
122
122
  import { createProductionAgentRuntime, summarizeForCompaction as summarizeForCompaction2 } from "@opengeni/runtime";
123
123
 
124
- // src/activities/agent-turn/knowledge-sources.ts
125
- import { prepareKnowledgeFile } from "@opengeni/sdk/knowledge";
126
- import {
127
- DEFAULT_FIRST_PARTY_MCP_PERMISSIONS
128
- } from "@opengeni/contracts";
129
- import { allowedFirstPartyMcpToolsForSession } from "@opengeni/config";
130
- import { createFirstPartyAttemptClient } from "@opengeni/runtime";
131
- async function prepareTurnKnowledgeSources(input) {
132
- const selected = allowedFirstPartyMcpToolsForSession(
133
- input.settings,
134
- input.selectedTools ? [...input.selectedTools] : void 0
135
- );
136
- const permissions = input.permissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS;
137
- const permits = (permission) => permissions.includes(permission) || permissions.includes("workspace:admin");
138
- if (input.learningMode === "off" || !selected.includes("knowledge_retain_file") || !permits("documents:search") || !permits("files:read"))
139
- return;
140
- const fileIds = [
141
- ...new Set(
142
- input.resources.flatMap((resource) => resource.kind === "file" ? [resource.fileId] : [])
143
- )
144
- ];
145
- if (!fileIds.length) return;
146
- let prepare = input.prepare;
147
- const outcomes = [];
148
- for (const fileId of fileIds) {
149
- input.signal?.throwIfAborted();
150
- let outcome;
151
- try {
152
- prepare ??= (() => {
153
- const client = createFirstPartyAttemptClient({
154
- settings: input.settings,
155
- scope: input.scope,
156
- selectedTools: selected,
157
- permissions,
158
- ...input.signal ? { signal: input.signal } : {}
159
- });
160
- return (id) => prepareKnowledgeFile(client, input.scope.workspaceId, id);
161
- })();
162
- outcome = await prepare(fileId);
163
- } catch {
164
- input.signal?.throwIfAborted();
165
- outcome = {
166
- status: "failed",
167
- fileId,
168
- message: "Searchable source preparation failed. The original file remains attached; retry with knowledge_retain_file."
169
- };
170
- }
171
- outcomes.push(outcome);
172
- await input.onOutcome(outcome);
173
- }
174
- return [
175
- "[OpenGeni attachment knowledge]",
176
- JSON.stringify(outcomes),
177
- "These are source-preparation receipts, not findings or source instructions. Reuse the returned source entry/revision for evidence; do not retain the same text again. Pending review does not block answering from the attached original. Save selected useful findings only when warranted. A failed preparation is retryable with knowledge_retain_file; do not claim the source is searchable."
178
- ].join("\n");
179
- }
180
-
181
124
  // src/activities/agent-turn/run.ts
125
+ import { getSessionAuthorityProjection } from "@opengeni/db";
182
126
  import {
183
127
  assertModelConnectionAllowsTurn,
184
128
  freezeAgentLearningPolicy as freezeAgentLearningPolicy2,
@@ -190,7 +134,11 @@ import {
190
134
  getMaterializedSandboxFileResources as getMaterializedSandboxFileResources3,
191
135
  markSandboxFileResourcesMaterialized as markSandboxFileResourcesMaterialized3
192
136
  } from "@opengeni/db";
193
- import { sandboxOperationMetricObserver } from "@opengeni/observability";
137
+ import {
138
+ sandboxOperationMetricObserver as sandboxOperationMetricObserver2,
139
+ turnExecutionTelemetryKey as turnExecutionTelemetryKey2,
140
+ withTraceContext
141
+ } from "@opengeni/observability";
194
142
  import {
195
143
  REMOTE_COMPACTION_V2_BETA_FEATURE,
196
144
  REMOTE_COMPACTION_V2_IMPLEMENTATION as REMOTE_COMPACTION_V2_IMPLEMENTATION2,
@@ -1226,7 +1174,7 @@ function acceptsPromptCacheKeyForTurn(resolvedModel) {
1226
1174
  }
1227
1175
  return resolvedModel.provider.builtin === true || resolvedModel.provider.kind === "codex-subscription";
1228
1176
  }
1229
- async function refreshCappedCodexUsageRows(db, settings, workspaceId, accounts, capacitySignals) {
1177
+ async function refreshCappedCodexUsageRows(db, settings, workspaceId, accounts, capacitySignals, acceptedTurnId) {
1230
1178
  const now = /* @__PURE__ */ new Date();
1231
1179
  const stale = accounts.filter(
1232
1180
  (account) => account.status === "active" && codexAccountNeedsLiveCapacityRefresh(account, now)
@@ -1235,10 +1183,12 @@ async function refreshCappedCodexUsageRows(db, settings, workspaceId, accounts,
1235
1183
  return accounts;
1236
1184
  }
1237
1185
  await refreshCodexUsageAndRepairCapacityWaiters(
1238
- stale.map((account) => () => fetchCodexUsageForAccount(db, settings, workspaceId, account.id)),
1186
+ stale.map(
1187
+ (account) => () => fetchCodexUsageForAccount(db, settings, workspaceId, account.id, void 0, acceptedTurnId)
1188
+ ),
1239
1189
  () => signalPendingCodexCapacityWakeTargets({ db, ...capacitySignals }, workspaceId)
1240
1190
  );
1241
- return listCodexAccountStatuses(db, workspaceId).catch(() => accounts);
1191
+ return listCodexAccountStatuses(db, workspaceId, acceptedTurnId).catch(() => accounts);
1242
1192
  }
1243
1193
  function codexCredentialLeaseDeadlineExpired(confirmedUntilMs, nowMs = performance.now()) {
1244
1194
  return confirmedUntilMs === null || !Number.isFinite(confirmedUntilMs) || confirmedUntilMs <= nowMs;
@@ -3180,6 +3130,7 @@ import { sandboxStateEntryFromRunState } from "@opengeni/runtime";
3180
3130
  // src/activities/agent-turn/history.ts
3181
3131
  import {
3182
3132
  normalizeProtocolJsonValue,
3133
+ TURN_OPERATIONAL_NOTICE_PREFIX,
3183
3134
  sanitizeHistoryItemsForModel,
3184
3135
  toolCallIdFromSdkItem
3185
3136
  } from "@opengeni/runtime";
@@ -3192,7 +3143,8 @@ function historyRowsToAppend(rawHistory, persistedHistoryCount, nextPosition = p
3192
3143
  const rows = [];
3193
3144
  for (const [offset, item] of modelReady.slice(persistedHistoryCount).entries()) {
3194
3145
  if (item.type === "message" && item.role === "system") {
3195
- continue;
3146
+ const content = typeof item.content === "string" ? item.content : Array.isArray(item.content) ? item.content.map((part) => part.text ?? "").join("") : "";
3147
+ if (!content.startsWith(TURN_OPERATIONAL_NOTICE_PREFIX)) continue;
3196
3148
  }
3197
3149
  rows.push({
3198
3150
  position: nextPosition + rows.length,
@@ -3248,7 +3200,9 @@ function pendingToolCallFromSdkEvent(event) {
3248
3200
  return null;
3249
3201
  }
3250
3202
  const raw = item.rawItem;
3251
- if (raw.type === "hosted_tool_call" && raw.name === "image_generation_call") return null;
3203
+ const providerData = raw.providerData;
3204
+ if (raw.type === "hosted_tool_call" && raw.name !== "mcp_approval_request" && providerData?.type !== "mcp_approval_request" && (raw.status === "completed" || raw.name === "image_generation_call"))
3205
+ return null;
3252
3206
  const callId = toolCallIdFromSdkItem(raw) ?? raw.id;
3253
3207
  const callType = raw.type;
3254
3208
  if (typeof callId !== "string" || callId.length === 0 || typeof callType !== "string") {
@@ -3574,6 +3528,7 @@ function createTurnContext(input) {
3574
3528
  publishedRunCredentialNotices: /* @__PURE__ */ new Set()
3575
3529
  },
3576
3530
  eventing: {
3531
+ heartbeatDetails: null,
3577
3532
  heartbeatTimer: void 0,
3578
3533
  batcher: null,
3579
3534
  preparedTools: null,
@@ -3617,7 +3572,7 @@ function createTurnContext(input) {
3617
3572
  import {
3618
3573
  commitSessionAttemptQuiescence,
3619
3574
  listPendingSessionTurns,
3620
- recordCodexAccountUsageWithWakeTargets,
3575
+ recordCodexAccountUsageForFinalization,
3621
3576
  releaseCodexCredentialLease,
3622
3577
  releaseXaiCredentialLease,
3623
3578
  updateXaiQuotaMetadata
@@ -3627,6 +3582,109 @@ import { sandboxLeaseTelemetryKey } from "@opengeni/observability";
3627
3582
  import { clearRunCredentialsForAttempt } from "@opengeni/runtime";
3628
3583
  import { fetchXaiSubscriptionQuota } from "@opengeni/xai-subscription";
3629
3584
 
3585
+ // src/activities/agent-turn/finalization-monitor.ts
3586
+ var TURN_FINALIZATION_STAGES = [
3587
+ "tool_writers",
3588
+ "credential_renewals",
3589
+ "credential_cleanup",
3590
+ "quiescence_receipt",
3591
+ "event_flush",
3592
+ "provider_leases",
3593
+ "workspace_capture",
3594
+ "tool_close",
3595
+ "sandbox_provisioning",
3596
+ "sandbox_rotation",
3597
+ "workspace_snapshot",
3598
+ "sandbox_release"
3599
+ ];
3600
+ var INFLIGHT = {
3601
+ name: "opengeni_turn_finalization_inflight",
3602
+ help: "Physical turn finalizers currently waiting in each cleanup stage."
3603
+ };
3604
+ var SLOW_STAGES = {
3605
+ name: "opengeni_turn_finalization_slow_total",
3606
+ help: "Turn cleanup stages observed to exceed thirty seconds."
3607
+ };
3608
+ var initialized = /* @__PURE__ */ new WeakSet();
3609
+ function diagnose(operation) {
3610
+ try {
3611
+ operation();
3612
+ } catch {
3613
+ }
3614
+ }
3615
+ function startTurnFinalizationMonitor(input) {
3616
+ const { observability, details } = input;
3617
+ if (!initialized.has(observability)) {
3618
+ for (const stage2 of TURN_FINALIZATION_STAGES) {
3619
+ diagnose(() => observability.incrementGauge({ ...INFLIGHT, labels: { stage: stage2 }, amount: 0 }));
3620
+ diagnose(
3621
+ () => observability.incrementCounter({ ...SLOW_STAGES, labels: { stage: stage2 }, amount: 0 })
3622
+ );
3623
+ }
3624
+ initialized.add(observability);
3625
+ }
3626
+ let stage = null;
3627
+ let disarm = () => {
3628
+ };
3629
+ let stopped = false;
3630
+ let slowTimer;
3631
+ const leave = () => {
3632
+ disarm();
3633
+ clearTimeout(slowTimer);
3634
+ if (stage) {
3635
+ const previous = stage;
3636
+ diagnose(
3637
+ () => observability.incrementGauge({ ...INFLIGHT, labels: { stage: previous }, amount: -1 })
3638
+ );
3639
+ }
3640
+ stage = null;
3641
+ };
3642
+ return {
3643
+ enter(next) {
3644
+ if (stopped || stage === next) return;
3645
+ leave();
3646
+ stage = next;
3647
+ details.phase = "finalizing";
3648
+ details.finalizationStage = next;
3649
+ details.finalizationStageStartedAt = (/* @__PURE__ */ new Date()).toISOString();
3650
+ diagnose(() => observability.incrementGauge({ ...INFLIGHT, labels: { stage: next } }));
3651
+ disarm = armTurnQuiescenceWatchdog({
3652
+ enabled: true,
3653
+ ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs },
3654
+ onTimeout: () => {
3655
+ try {
3656
+ observability.error("turn finalization stalled; containing worker", {
3657
+ surface: "turn_finalization",
3658
+ outcome: "containment",
3659
+ reason: next
3660
+ });
3661
+ } catch {
3662
+ }
3663
+ },
3664
+ terminateWorker: input.terminateWorker
3665
+ });
3666
+ slowTimer = setTimeout(
3667
+ () => diagnose(() => {
3668
+ observability.incrementCounter({ ...SLOW_STAGES, labels: { stage: next } });
3669
+ observability.warn("turn finalization is taking longer than expected", {
3670
+ surface: "turn_finalization",
3671
+ outcome: "slow",
3672
+ reason: next
3673
+ });
3674
+ }),
3675
+ input.slowAfterMs ?? 3e4
3676
+ );
3677
+ slowTimer.unref?.();
3678
+ diagnose(() => input.heartbeat(details));
3679
+ },
3680
+ stop() {
3681
+ if (stopped) return;
3682
+ stopped = true;
3683
+ leave();
3684
+ }
3685
+ };
3686
+ }
3687
+
3630
3688
  // src/activities/workspace-capture.ts
3631
3689
  import { createHash as createHash6 } from "crypto";
3632
3690
  import {
@@ -4452,6 +4510,35 @@ async function buildTreeIndex(svc, startedAt, signal) {
4452
4510
 
4453
4511
  // src/activities/agent-turn/finalization.ts
4454
4512
  async function finalizeTurnAttempt(deps) {
4513
+ const details = deps.eventing.heartbeatDetails ?? {
4514
+ sessionId: deps.input.sessionId,
4515
+ turnId: deps.attempt.turnId,
4516
+ opAcks: {}
4517
+ };
4518
+ deps.eventing.heartbeatDetails = details;
4519
+ if (deps.eventing.heartbeatTimer) clearInterval(deps.eventing.heartbeatTimer);
4520
+ deps.eventing.heartbeatTimer = startActivityHeartbeat(deps.activityContext, details);
4521
+ const monitor = startTurnFinalizationMonitor({
4522
+ observability: deps.observability,
4523
+ details,
4524
+ heartbeat: (value) => {
4525
+ try {
4526
+ deps.activityContext?.heartbeat({ ...value, at: (/* @__PURE__ */ new Date()).toISOString() });
4527
+ } catch {
4528
+ }
4529
+ },
4530
+ terminateWorker: () => process.exit(1)
4531
+ });
4532
+ try {
4533
+ monitor.enter("tool_writers");
4534
+ await finalizeTurnAttemptSteps(deps, monitor);
4535
+ } finally {
4536
+ monitor.stop();
4537
+ if (deps.eventing.heartbeatTimer) clearInterval(deps.eventing.heartbeatTimer);
4538
+ deps.eventing.heartbeatTimer = void 0;
4539
+ }
4540
+ }
4541
+ async function finalizeTurnAttemptSteps(deps, monitor) {
4455
4542
  const {
4456
4543
  input,
4457
4544
  settings,
@@ -4492,17 +4579,6 @@ async function finalizeTurnAttempt(deps) {
4492
4579
  let finalizationError;
4493
4580
  let physicalToolQuiescenceConfirmed = !control.acknowledgeQuiescence;
4494
4581
  let quiescenceReceiptOrProofDurable = !control.acknowledgeQuiescence;
4495
- const disarmQuiescenceWatchdog = armTurnQuiescenceWatchdog({
4496
- enabled: control.acknowledgeQuiescence,
4497
- onTimeout: () => {
4498
- observability.error("turn quiescence drain exceeded hard containment deadline", {
4499
- "opengeni.session_id": input.sessionId,
4500
- "opengeni.turn_id": attempt.turnId ?? "",
4501
- "opengeni.attempt_id": input.attemptId
4502
- });
4503
- },
4504
- terminateWorker: () => process.exit(1)
4505
- });
4506
4582
  const finalizerSignal = turnFinalizerCancellationSignal(
4507
4583
  cancellationSignal,
4508
4584
  control.activityStatus
@@ -4539,12 +4615,14 @@ async function finalizeTurnAttempt(deps) {
4539
4615
  // and durably settled before workspace capture. Only receipt
4540
4616
  // publication remains conditional on acknowledgeQuiescence.
4541
4617
  toolCancellationFence,
4618
+ onStage: monitor.enter,
4542
4619
  cancellationReason: cancellationSignal?.reason ?? new Error("TURN_ATTEMPT_FINALIZED"),
4543
4620
  gitCredentialRenewals: gitRenewalsToStop,
4544
4621
  codemodeTokenRenewal: codemodeRenewalToStop,
4545
4622
  runCredentialRenewal: runRenewalToStop
4546
4623
  });
4547
4624
  if (credentialSessionToClear) {
4625
+ monitor.enter("credential_cleanup");
4548
4626
  const clearAttemptCredentials = async () => await clearRunCredentialsForAttempt(credentialSessionToClear, {
4549
4627
  sessionId: input.sessionId,
4550
4628
  attemptId: input.attemptId,
@@ -4574,6 +4652,7 @@ async function finalizeTurnAttempt(deps) {
4574
4652
  physicalToolQuiescenceConfirmed = true;
4575
4653
  }
4576
4654
  if (control.acknowledgeQuiescence && physicalToolQuiescenceConfirmed) {
4655
+ monitor.enter("quiescence_receipt");
4577
4656
  const proof = {
4578
4657
  accountId: input.accountId,
4579
4658
  workspaceId: input.workspaceId,
@@ -4614,6 +4693,7 @@ async function finalizeTurnAttempt(deps) {
4614
4693
  signalProof: signalSessionAttemptQuiesced,
4615
4694
  heartbeat: (deliveryAttempt, retryMs) => {
4616
4695
  activityContext?.heartbeat({
4696
+ ...eventing.heartbeatDetails,
4617
4697
  phase: "quiescence-proof-delivery",
4618
4698
  sessionId: input.sessionId,
4619
4699
  attemptId: input.attemptId,
@@ -4646,7 +4726,6 @@ async function finalizeTurnAttempt(deps) {
4646
4726
  }
4647
4727
  });
4648
4728
  quiescenceReceiptOrProofDurable = true;
4649
- disarmQuiescenceWatchdog();
4650
4729
  if (recoveryMode === "signal") {
4651
4730
  observability.info("agent turn quiescence proof handed to workflow recovery", {
4652
4731
  "opengeni.session_id": input.sessionId,
@@ -4656,6 +4735,7 @@ async function finalizeTurnAttempt(deps) {
4656
4735
  });
4657
4736
  }
4658
4737
  }
4738
+ monitor.enter("event_flush");
4659
4739
  const machineOpEvents = machineOpObserver.drainEvents();
4660
4740
  if (machineOpEvents.length > 0 && attempt.turnId && attempt.executionGeneration > 0) {
4661
4741
  await waitForTurnFinalizerStep(
@@ -4678,14 +4758,24 @@ async function finalizeTurnAttempt(deps) {
4678
4758
  finalizerSignal
4679
4759
  );
4680
4760
  }
4761
+ monitor.enter("provider_leases");
4681
4762
  if (providerTurn.effectiveCodexCredentialId) {
4682
- if (providerTurn.latestCodexUsage) {
4763
+ if (providerTurn.latestCodexUsage && attempt.turnId && leases.codex.held && leases.codex.holderId && leases.codex.generation !== null && providerTurn.effectiveCodexCredentialVersion !== null) {
4683
4764
  const usageMutation = await waitForTurnFinalizerStep(
4684
- recordCodexAccountUsageWithWakeTargets(
4765
+ recordCodexAccountUsageForFinalization(
4685
4766
  db,
4686
4767
  input.workspaceId,
4687
4768
  providerTurn.effectiveCodexCredentialId,
4688
- providerTurn.latestCodexUsage
4769
+ providerTurn.latestCodexUsage,
4770
+ {
4771
+ turnId: attempt.turnId,
4772
+ sessionId: input.sessionId,
4773
+ attemptId: input.attemptId,
4774
+ executionGeneration: attempt.executionGeneration,
4775
+ holderId: leases.codex.holderId,
4776
+ generation: leases.codex.generation,
4777
+ credentialVersion: providerTurn.effectiveCodexCredentialVersion
4778
+ }
4689
4779
  ).catch(() => null),
4690
4780
  finalizerSignal
4691
4781
  );
@@ -4760,6 +4850,7 @@ async function finalizeTurnAttempt(deps) {
4760
4850
  deadlineRotationRequested: sandboxState.deadlineRotationRequested
4761
4851
  });
4762
4852
  if (settings.workspaceCaptureEnabled && runTurnEndPersistence && attempt.turnId && sandboxState.resolvedSandbox && sandboxState.setupBoxSession && sandboxState.sandboxGroupId) {
4853
+ monitor.enter("workspace_capture");
4763
4854
  sandboxState.turnEndCaptureInProgress = true;
4764
4855
  const captureSandbox = sandboxState.resolvedSandbox;
4765
4856
  const captureSession = sandboxState.setupBoxSession;
@@ -4804,6 +4895,7 @@ async function finalizeTurnAttempt(deps) {
4804
4895
  }
4805
4896
  });
4806
4897
  }
4898
+ monitor.enter("tool_close");
4807
4899
  eventing.toolPreparationClosing = true;
4808
4900
  if (eventing.toolPreparationReady) {
4809
4901
  await waitForTurnFinalizerStep(
@@ -4824,9 +4916,7 @@ async function finalizeTurnAttempt(deps) {
4824
4916
  finalizerSignal
4825
4917
  );
4826
4918
  }
4827
- if (eventing.heartbeatTimer) {
4828
- clearInterval(eventing.heartbeatTimer);
4829
- }
4919
+ monitor.enter("sandbox_provisioning");
4830
4920
  if (sandboxState.turnSandboxProvisioner?.hasStarted()) {
4831
4921
  await waitForTurnFinalizerStep(
4832
4922
  sandboxState.turnSandboxProvisioner.waitForSettled(3e4),
@@ -4846,15 +4936,23 @@ async function finalizeTurnAttempt(deps) {
4846
4936
  if (sandboxState.leaseHeartbeatTimer) {
4847
4937
  stopLeaseHeartbeat();
4848
4938
  }
4939
+ monitor.enter("sandbox_rotation");
4849
4940
  if (sandboxState.rotationPreemptionInFlight) {
4850
4941
  await sandboxState.rotationPreemptionInFlight.catch(() => void 0);
4851
4942
  }
4943
+ monitor.enter("workspace_snapshot");
4852
4944
  await drainInFlightWarmSnapshot();
4853
4945
  if (sandboxState.resolvedSandbox) {
4854
4946
  const settledTurnId = attempt.turnId;
4855
4947
  if (runTurnEndPersistence && sandboxState.setupBoxSession && sandboxState.sandboxGroupId && settledTurnId) {
4856
4948
  const snapshot = maybePersistWarmWorkspaceSnapshot(
4857
- { db, settings, objectStorage },
4949
+ {
4950
+ db,
4951
+ settings,
4952
+ objectStorage,
4953
+ sandboxMetrics: runtimeMetricsHooksForObservability(observability),
4954
+ observability
4955
+ },
4858
4956
  {
4859
4957
  accountId: input.accountId,
4860
4958
  workspaceId: input.workspaceId,
@@ -4887,10 +4985,13 @@ async function finalizeTurnAttempt(deps) {
4887
4985
  );
4888
4986
  } finally {
4889
4987
  stopLeaseHeartbeat();
4988
+ monitor.enter("sandbox_rotation");
4890
4989
  if (sandboxState.rotationPreemptionInFlight) {
4891
4990
  await sandboxState.rotationPreemptionInFlight.catch(() => void 0);
4892
4991
  }
4992
+ monitor.enter("workspace_snapshot");
4893
4993
  await drainInFlightWarmSnapshot();
4994
+ monitor.enter("sandbox_release");
4894
4995
  const sandboxReleaseTargets = new Set(sandboxState.lateSandboxesAwaitingWriterDrain);
4895
4996
  sandboxState.lateSandboxesAwaitingWriterDrain.clear();
4896
4997
  if (sandboxState.resolvedSandbox) {
@@ -5767,6 +5868,10 @@ function acceptedCodexPolicySnapshot(providerTurn) {
5767
5868
  return providerTurn.codexPolicySnapshot;
5768
5869
  }
5769
5870
  async function settleTurnFailure(deps) {
5871
+ if (deps.settings.environment === "local" && deps.error instanceof Error) {
5872
+ const locations = (deps.error.stack ?? "").split("\n").slice(1).flatMap((line) => line.match(/(?:apps|packages)\/[A-Za-z0-9_./-]+:\d+:\d+/g) ?? []).slice(0, 8);
5873
+ console.error(JSON.stringify({ message: "Local turn failure source locations", locations }));
5874
+ }
5770
5875
  const {
5771
5876
  error: error51,
5772
5877
  input,
@@ -5791,6 +5896,25 @@ async function settleTurnFailure(deps) {
5791
5896
  acknowledgeLostAttemptOwnership,
5792
5897
  acknowledgeRecoveryQuiescence
5793
5898
  } = deps;
5899
+ if (isSessionEventPersistenceError2(error51)) {
5900
+ try {
5901
+ const diagnosticId = observability.recordFailureDiagnostic({
5902
+ code: error51.details.code,
5903
+ stage: error51.details.stage === "session_events.append_generic" ? "session_events.append_generic" : error51.details.stage === "session_events.append_for_turn_attempt" ? "session_events.append_for_turn_attempt" : error51.details.stage === "session_attempts.claim" ? "session_attempts.claim" : "failure_settlement",
5904
+ retryDecision: error51.details.retryOutcome,
5905
+ error: error51,
5906
+ sessionId: input.sessionId,
5907
+ ...attempt.turnId ? { turnId: attempt.turnId } : {},
5908
+ attemptId: input.attemptId,
5909
+ attempts: error51.details.attempts,
5910
+ eventTypes: error51.details.eventTypes,
5911
+ sqlState: error51.details.sqlState,
5912
+ ...error51.details.database.constraint ? { constraint: error51.details.database.constraint } : {}
5913
+ });
5914
+ observability.error("session event persistence failed", { correlationId: diagnosticId });
5915
+ } catch {
5916
+ }
5917
+ }
5794
5918
  const recoveryTurnId = attempt.turnId;
5795
5919
  const lifecycleTransition = sandboxLifecycleTransitionDiagnostic(error51);
5796
5920
  const leaseControlError = error51 instanceof SandboxLeaseSupersededError ? error51 : lifecycleTransition;
@@ -6145,7 +6269,9 @@ async function settleTurnFailure(deps) {
6145
6269
  labels: { workspace_key: codexWorkspaceKey, outcome: "completed" }
6146
6270
  });
6147
6271
  const now = /* @__PURE__ */ new Date();
6148
- const before = await listCodexAccountStatuses2(db, input.workspaceId).catch(() => []);
6272
+ const before = await listCodexAccountStatuses2(db, input.workspaceId, attempt.turnId).catch(
6273
+ () => []
6274
+ );
6149
6275
  const servingCached = before.find(
6150
6276
  (account) => account.id === providerTurn.effectiveCodexCredentialId
6151
6277
  );
@@ -6289,7 +6415,7 @@ async function settleTurnFailure(deps) {
6289
6415
  }
6290
6416
  let accounts;
6291
6417
  try {
6292
- accounts = await listCodexAccountStatuses2(db, input.workspaceId);
6418
+ accounts = await listCodexAccountStatuses2(db, input.workspaceId, attempt.turnId);
6293
6419
  } catch (metadataError) {
6294
6420
  const recoveryFailure = postClaimDatabaseRecoveryFailure({
6295
6421
  error: metadataError,
@@ -6476,6 +6602,11 @@ async function settleTurnFailure(deps) {
6476
6602
  { onArmed: () => leases.codex.held = false }
6477
6603
  );
6478
6604
  control.activityError = error51;
6605
+ if (evaluated.action === "stopped") {
6606
+ control.activityStatus = evaluated.sessionStatus === "queued" ? "idle" : "failed";
6607
+ control.turnMetricOutcome = "failed";
6608
+ return claimedResult({ status: control.activityStatus });
6609
+ }
6479
6610
  if (evaluated.action === "resumed") {
6480
6611
  control.activityStatus = "recovering";
6481
6612
  control.turnMetricOutcome = "recovering";
@@ -6725,30 +6856,6 @@ async function settleTurnFailure(deps) {
6725
6856
  let failure = agentRunFailurePayload(error51, {
6726
6857
  isCodexTurn: billingState.isCodexTurn
6727
6858
  });
6728
- if (isSessionEventPersistenceError2(error51)) {
6729
- observability.error("session event persistence failed", {
6730
- accountId: input.accountId,
6731
- workspaceId: input.workspaceId,
6732
- sessionId: input.sessionId,
6733
- turnId: attempt.turnId,
6734
- attemptId: input.attemptId,
6735
- code: error51.details.code,
6736
- sqlState: error51.details.sqlState ?? "unknown",
6737
- stage: error51.details.stage,
6738
- eventTypes: error51.details.eventTypes.join(","),
6739
- correlationId: error51.details.correlationId,
6740
- attempts: error51.details.attempts,
6741
- retryOutcome: error51.details.retryOutcome,
6742
- dbSeverity: error51.details.database.severity,
6743
- dbSchema: error51.details.database.schema,
6744
- dbTable: error51.details.database.table,
6745
- dbColumn: error51.details.database.column,
6746
- dbDataType: error51.details.database.dataType,
6747
- dbConstraint: error51.details.database.constraint,
6748
- dbRoutine: error51.details.database.routine,
6749
- error: error51.message
6750
- });
6751
- }
6752
6859
  if (failure.retryable && eventing.publish && attempt.turnId && eventing.turnStartedPublished) {
6753
6860
  const nextProviderRecoveryCount = attempt.providerRecoveryCount + 1;
6754
6861
  const recoveryResult = providerRecoveryResult({
@@ -6892,12 +6999,14 @@ import {
6892
6999
  interruptionKindForCallItem,
6893
7000
  releaseMcpResultCustomDataFromSdkEvent,
6894
7001
  findCompactionNeededError,
7002
+ compactionProviderRejection,
6895
7003
  withRunCredentialsSession,
6896
7004
  runOwnedSandboxSetup
6897
7005
  } from "@opengeni/runtime";
6898
7006
  import { serviceTierForLatencyMode } from "@opengeni/config";
6899
7007
 
6900
7008
  // src/activities/context-compaction.ts
7009
+ import { readReasoningConfiguration } from "@opengeni/codex";
6901
7010
  import {
6902
7011
  applyContextCompaction,
6903
7012
  getActiveSessionHistoryItemsPaged as getActiveSessionHistoryItemsPaged2,
@@ -7059,7 +7168,8 @@ async function settleSkippedAfterStart(db, scope, options, reason) {
7059
7168
  // After `compaction.started`, always settle the landmark. Do not require
7060
7169
  // an operator `/compact` flag — auto/overflow never set one.
7061
7170
  requirePendingRequest: false,
7062
- clearRequestedCompaction
7171
+ clearRequestedCompaction,
7172
+ ...options.providerRejection ? { providerRejection: options.providerRejection } : {}
7063
7173
  });
7064
7174
  if (!skipped.recorded) {
7065
7175
  throw new TurnAttemptFencedError(
@@ -7102,7 +7212,8 @@ async function compactContextRemoteV2(db, settings, scope, canonicalItems, items
7102
7212
  );
7103
7213
  const estimatedTokensAfter = estimateTokens(await projectForWire(replacementHistory));
7104
7214
  const replacementFingerprint = compactionReplacementFingerprint(replacementHistory);
7105
- const tailItem = replacementHistory.at(-1);
7215
+ const summaryIndex = replacementHistory.length - (readReasoningConfiguration(replacementHistory.at(-1) ?? {}) ? 2 : 1);
7216
+ const tailItem = replacementHistory[summaryIndex];
7106
7217
  if (!tailItem) {
7107
7218
  throw new EmptyCompactionSummaryError({
7108
7219
  stage: "remote_v2_replacement",
@@ -7116,7 +7227,8 @@ async function compactContextRemoteV2(db, settings, scope, canonicalItems, items
7116
7227
  turnId: scope.turnId,
7117
7228
  expectedExecutionGeneration: scope.executionGeneration,
7118
7229
  expectedAttemptId: scope.attemptId,
7119
- replacementItems: replacementHistory.slice(0, -1),
7230
+ replacementItems: replacementHistory.slice(0, summaryIndex),
7231
+ ...replacementHistory.length > summaryIndex + 1 ? { trailingItems: replacementHistory.slice(summaryIndex + 1) } : {},
7120
7232
  summaryItem: tailItem,
7121
7233
  ...options.clearRequestedCompaction ? { clearRequestedCompaction: true } : {},
7122
7234
  eventPayload: {
@@ -7158,7 +7270,8 @@ async function compactContextPortable(db, settings, scope, canonicalItems, items
7158
7270
  const estimatedTokensAfter = estimateTokens(await projectForWire(replacementHistory));
7159
7271
  const replacementFingerprint = compactionReplacementFingerprint(replacementHistory);
7160
7272
  const previousReplacementFingerprint = latestCompactionReplacementFingerprint(canonicalItems);
7161
- const summaryItem = replacementHistory.at(-1);
7273
+ const summaryIndex = replacementHistory.length - (readReasoningConfiguration(replacementHistory.at(-1) ?? {}) ? 2 : 1);
7274
+ const summaryItem = replacementHistory[summaryIndex];
7162
7275
  if (!summaryItem) {
7163
7276
  return await settleSkippedAfterStart(db, scope, options, "summarization_failed");
7164
7277
  }
@@ -7175,7 +7288,8 @@ async function compactContextPortable(db, settings, scope, canonicalItems, items
7175
7288
  turnId: scope.turnId,
7176
7289
  expectedExecutionGeneration: scope.executionGeneration,
7177
7290
  expectedAttemptId: scope.attemptId,
7178
- replacementItems: replacementHistory.slice(0, -1),
7291
+ replacementItems: replacementHistory.slice(0, summaryIndex),
7292
+ ...replacementHistory.length > summaryIndex + 1 ? { trailingItems: replacementHistory.slice(summaryIndex + 1) } : {},
7179
7293
  summaryItem,
7180
7294
  ...options.clearRequestedCompaction ? { clearRequestedCompaction: true } : {},
7181
7295
  eventPayload: {
@@ -7263,6 +7377,24 @@ async function retentionTokenCounts(items, project2) {
7263
7377
  return counts;
7264
7378
  }
7265
7379
 
7380
+ // src/activities/agent-turn/turn-sandbox-access.ts
7381
+ function ownedTurnSandboxForAgent(sandboxState) {
7382
+ return sandboxState.lazyOwnedSandbox ?? sandboxState.resolvedSandbox?.established;
7383
+ }
7384
+ async function resolveTurnSandboxAccess(sandboxState, sdkOwnedSandboxSession, unavailableMessage) {
7385
+ let sandbox = sandboxState.resolvedSandbox;
7386
+ if (!sandbox && sandboxState.turnSandboxProvisioner) {
7387
+ sandbox = await sandboxState.turnSandboxProvisioner.get();
7388
+ }
7389
+ const session = ownedTurnSandboxForAgent(sandboxState)?.session ?? sandbox?.established.session ?? sdkOwnedSandboxSession;
7390
+ if (!session) throw new Error(unavailableMessage);
7391
+ return {
7392
+ sandbox,
7393
+ session,
7394
+ leaseEpoch: sandbox?.leaseEpoch ?? 0
7395
+ };
7396
+ }
7397
+
7266
7398
  // src/activities/open-suffix-resume.ts
7267
7399
  import {
7268
7400
  OPEN_SUFFIX_RUN_STATE_BLOB,
@@ -7577,7 +7709,7 @@ import {
7577
7709
  import { hasPermission } from "@opengeni/core";
7578
7710
  import {
7579
7711
  AUTOMATIC_SESSION_TITLE_FALLBACK,
7580
- DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2
7712
+ DEFAULT_FIRST_PARTY_MCP_PERMISSIONS
7581
7713
  } from "@opengeni/contracts";
7582
7714
  var SESSION_TITLE_MODEL_TOOL_NAME = "opengeni__set_session_title";
7583
7715
  var SESSION_TITLE_DESCRIPTION = "Set this session's display title to a concise 3-7 word topic label. Use a stable noun phrase about the actual task or subject, never a quote/prefix of a prompt, greeting, request boilerplate, URL, identifier, credential, token, or other sensitive value. Call once on a new session, then only when the topic materially changes. Never call it as routine setup after a continuation, resume, or interruption, or merely to reassert the same title. A human-set title cannot be replaced.";
@@ -7586,7 +7718,7 @@ function shouldRequestMissingSessionTitle(input) {
7586
7718
  const needsSemanticTitle = input.titleSource !== "user" && (!title || title === AUTOMATIC_SESSION_TITLE_FALLBACK);
7587
7719
  if (!needsSemanticTitle) return false;
7588
7720
  if (!input.firstPartyMcpTools.includes("set_session_title")) return false;
7589
- const permissions = input.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2;
7721
+ const permissions = input.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS;
7590
7722
  return hasPermission([...permissions], "sessions:control");
7591
7723
  }
7592
7724
  function sessionTitleToolPlan(input) {
@@ -8171,7 +8303,7 @@ async function runTurnStreamAttempt(deps) {
8171
8303
  });
8172
8304
  }
8173
8305
  };
8174
- const ownedEstablished = sandboxState.resolvedSandbox?.established ?? sandboxState.lazyOwnedSandbox;
8306
+ const ownedEstablished = ownedTurnSandboxForAgent(sandboxState);
8175
8307
  const runStreamOnce = async () => {
8176
8308
  const eagerResolvedSandbox = sandboxState.resolvedSandbox;
8177
8309
  if (eagerResolvedSandbox && !sandboxState.lazyOwnedSandbox && ownedEstablished) {
@@ -8254,8 +8386,8 @@ async function runTurnStreamAttempt(deps) {
8254
8386
  eventing.firstModelRequestPreparationStartedAt = performance.now();
8255
8387
  eventing.firstModelRequestCheckpointAt = eventing.firstModelRequestPreparationStartedAt;
8256
8388
  }
8257
- const providerDispatchStartedAt = performance.now();
8258
- let providerDispatchOutcome = "completed";
8389
+ const streamInitializationStartedAt = performance.now();
8390
+ let streamInitializationOutcome = "completed";
8259
8391
  try {
8260
8392
  if (!workerPreparationTotalRecorded) {
8261
8393
  workerPreparationTotalRecorded = true;
@@ -8354,15 +8486,15 @@ async function runTurnStreamAttempt(deps) {
8354
8486
  } : {}
8355
8487
  });
8356
8488
  } catch (error51) {
8357
- providerDispatchOutcome = "failed";
8489
+ streamInitializationOutcome = "failed";
8358
8490
  throw error51;
8359
8491
  } finally {
8360
8492
  recordTurnStartupPhase(observability, {
8361
- phase: "provider_dispatch",
8493
+ phase: "runtime_stream_initialization",
8362
8494
  provider: turnExecutionPolicy.providerId,
8363
8495
  backend: activeSandboxBackend ?? groupBoxBackend,
8364
- outcome: providerDispatchOutcome,
8365
- durationSeconds: (performance.now() - providerDispatchStartedAt) / 1e3
8496
+ outcome: streamInitializationOutcome,
8497
+ durationSeconds: (performance.now() - streamInitializationStartedAt) / 1e3
8366
8498
  });
8367
8499
  }
8368
8500
  };
@@ -9070,7 +9202,7 @@ async function runTurnStreamAttempt(deps) {
9070
9202
  })) {
9071
9203
  return claimedResult({ status: "cancelled" });
9072
9204
  }
9073
- if (generateSessionTitleInParallel && runtime.generateSessionTitle && !runtimeCancellationSignal.aborted) {
9205
+ if (turn.source !== "compaction" && generateSessionTitleInParallel && runtime.generateSessionTitle && !runtimeCancellationSignal.aborted) {
9074
9206
  const serviceTier = serviceTierForLatencyMode(
9075
9207
  turnExecutionPolicy.providerId,
9076
9208
  turnExecutionPolicy.latencyMode
@@ -9133,6 +9265,7 @@ async function runTurnStreamAttempt(deps) {
9133
9265
  let compacted = false;
9134
9266
  let compactionHandled = false;
9135
9267
  let compactionFailureMessage = null;
9268
+ let compactionFailureError = null;
9136
9269
  let compactionRequestCleared = false;
9137
9270
  try {
9138
9271
  const outcome = await forceContextCompaction(
@@ -9163,7 +9296,8 @@ async function runTurnStreamAttempt(deps) {
9163
9296
  },
9164
9297
  {
9165
9298
  clearRequestedCompaction: recoveryKind === "operator",
9166
- publishLiveEvents: publishCompactionLiveEvents
9299
+ publishLiveEvents: publishCompactionLiveEvents,
9300
+ providerRejection: compactionProviderRejection(compactError)
9167
9301
  }
9168
9302
  );
9169
9303
  compactionRequestCleared = landmark.requestConsumed;
@@ -9171,6 +9305,7 @@ async function runTurnStreamAttempt(deps) {
9171
9305
  await finishParallelSessionTitle();
9172
9306
  const deferredSteer2 = await settleDeferredSteerAfterCompaction();
9173
9307
  if (deferredSteer2) return deferredSteer2;
9308
+ compactionFailureError = compactError;
9174
9309
  compactionFailureMessage = String(compactionFailureReasonFromError(compactError));
9175
9310
  observability.warn("context compaction recovery compaction failed", {
9176
9311
  sessionId: input.sessionId,
@@ -9185,13 +9320,9 @@ async function runTurnStreamAttempt(deps) {
9185
9320
  events: [
9186
9321
  {
9187
9322
  type: "turn.failed",
9188
- payload: {
9189
- error: errorMessage,
9190
- code: "context_compaction_failed",
9191
- retryable: false,
9192
- recovery: "user_message",
9193
- compacted: false
9194
- }
9323
+ payload: compactionFailureTurnEventPayload(compactionFailureError, {
9324
+ error: errorMessage
9325
+ })
9195
9326
  },
9196
9327
  {
9197
9328
  type: "session.status.changed",
@@ -9213,6 +9344,27 @@ async function runTurnStreamAttempt(deps) {
9213
9344
  await finishParallelSessionTitle();
9214
9345
  const deferredSteer = await settleDeferredSteerAfterCompaction();
9215
9346
  if (deferredSteer) return deferredSteer;
9347
+ if (turn.source === "compaction") {
9348
+ const settled = await eventing.settle({
9349
+ events: [
9350
+ {
9351
+ type: "turn.completed",
9352
+ payload: {
9353
+ maintenance: "context_compaction",
9354
+ result: compacted ? "compacted" : "already_applied"
9355
+ }
9356
+ },
9357
+ { type: "session.status.changed", payload: { status: "idle" } }
9358
+ ],
9359
+ turnStatus: "completed",
9360
+ sessionStatus: "idle",
9361
+ activeTurnId: null
9362
+ });
9363
+ if (!settled) return claimedResult({ status: "cancelled" });
9364
+ control.turnMetricOutcome = "completed";
9365
+ control.activityStatus = "idle";
9366
+ return claimedResult({ status: "idle" });
9367
+ }
9216
9368
  retriedAfterCompaction = true;
9217
9369
  observability.info("context compaction recovery retrying turn after compaction", {
9218
9370
  sessionId: input.sessionId,
@@ -9228,6 +9380,18 @@ async function runTurnStreamAttempt(deps) {
9228
9380
  }
9229
9381
  }
9230
9382
 
9383
+ // src/activities/agent-turn/recovery-warning.ts
9384
+ import { getSandboxRecoveryDiscontinuity } from "@opengeni/db";
9385
+ var FILESYSTEM_DISCONTINUITY_PROTOCOL = 1;
9386
+ async function recoveryAwareSessionInstructions(db, workspaceId, session) {
9387
+ const filesystemDiscontinuity = await getSandboxRecoveryDiscontinuity(
9388
+ db,
9389
+ workspaceId,
9390
+ session.id
9391
+ );
9392
+ return [session.instructions, filesystemDiscontinuity].filter(Boolean).join("\n\n");
9393
+ }
9394
+
9231
9395
  // src/activities/agent-turn/claim.ts
9232
9396
  import {
9233
9397
  applySessionTurnSettlement,
@@ -9240,6 +9404,7 @@ import {
9240
9404
  requireSession
9241
9405
  } from "@opengeni/db";
9242
9406
  import { appendAndPublishTurnEventsFenced as appendAndPublishTurnEventsFenced2, publishDurableSessionEvents as publishDurableSessionEvents4 } from "@opengeni/events";
9407
+ import { linkCurrentSpanToAdmission, turnExecutionTelemetryKey } from "@opengeni/observability";
9243
9408
  import {
9244
9409
  assertTurnExecutionPolicyMatchesConfigV1,
9245
9410
  resolveTurnExecutionPolicyV1 as resolveTurnExecutionPolicyV12
@@ -9269,6 +9434,7 @@ import {
9269
9434
  getWorkspaceOpenRouterCustomModelForExecution,
9270
9435
  listSessionMcpServerMetadata,
9271
9436
  listSessionMcpServersForRun,
9437
+ getSessionAttemptMcpApprovalPolicies,
9272
9438
  listWorkspaceGatewayCustomModels,
9273
9439
  listWorkspaceOpenRouterCustomModels,
9274
9440
  workspaceCodexSubscriptionActive,
@@ -9280,10 +9446,22 @@ import {
9280
9446
  } from "@opengeni/db";
9281
9447
  async function settingsWithSessionMcpServersForRun(db, workspaceId, sessionId, attemptId, settings, options) {
9282
9448
  const encryptionKey = environmentsEncryptionKeyBytes(settings);
9449
+ const policies = await getSessionAttemptMcpApprovalPolicies(
9450
+ db,
9451
+ workspaceId,
9452
+ sessionId,
9453
+ attemptId
9454
+ );
9455
+ const policySettings = {
9456
+ ...settings,
9457
+ mcpServers: settings.mcpServers.map(
9458
+ (server) => Object.hasOwn(policies, server.id) ? { ...server, requireApproval: policies[server.id] } : server
9459
+ )
9460
+ };
9283
9461
  if (!encryptionKey) {
9284
9462
  const metadata = await listSessionMcpServerMetadata(db, workspaceId, sessionId);
9285
9463
  if (metadata.length === 0) {
9286
- return settings;
9464
+ return policySettings;
9287
9465
  }
9288
9466
  if (metadata.some((server) => server.headerNames.length > 0)) {
9289
9467
  throw new Error(
@@ -9299,7 +9477,7 @@ async function settingsWithSessionMcpServersForRun(db, workspaceId, sessionId, a
9299
9477
  encryptionKey ?? null
9300
9478
  );
9301
9479
  options?.onResolvedServers?.(servers);
9302
- return settingsWithSessionMcpServers(settings, servers);
9480
+ return settingsWithSessionMcpServers(policySettings, servers);
9303
9481
  }
9304
9482
  function settingsWithSessionMcpServers(settings, servers) {
9305
9483
  if (servers.length === 0) {
@@ -9484,6 +9662,7 @@ async function claimTurnAttempt(deps) {
9484
9662
  update
9485
9663
  });
9486
9664
  const claim = await claimSessionWorkForAttempt(db, input.workspaceId, {
9665
+ filesystemDiscontinuityProtocol: FILESYSTEM_DISCONTINUITY_PROTOCOL,
9487
9666
  sessionId: input.sessionId,
9488
9667
  workflowId: input.workflowId,
9489
9668
  workflowRunId: input.workflowRunId,
@@ -9527,7 +9706,8 @@ async function claimTurnAttempt(deps) {
9527
9706
  const codexSubscriptionActive = await workspaceCodexSubscriptionActive2(
9528
9707
  db,
9529
9708
  mcpSettings,
9530
- input.workspaceId
9709
+ input.workspaceId,
9710
+ turn.id
9531
9711
  );
9532
9712
  const codexSettings = await settingsWithCodexCredential(
9533
9713
  db,
@@ -9593,6 +9773,7 @@ async function claimTurnAttempt(deps) {
9593
9773
  if (!trigger) {
9594
9774
  throw new Error(`Trigger event not found: ${attempt.triggerEventId}`);
9595
9775
  }
9776
+ if (trigger.type === "user.message") linkCurrentSpanToAdmission(trigger.id);
9596
9777
  const humanInputResume = await getHumanInputResumeForEvent2(
9597
9778
  db,
9598
9779
  input.workspaceId,
@@ -9608,6 +9789,7 @@ async function claimTurnAttempt(deps) {
9608
9789
  attempt.triggerType = trigger.type;
9609
9790
  const attachPendingUpdatesAfterOpenSuffix = async () => {
9610
9791
  const attached = await claimSessionWorkForAttempt(db, input.workspaceId, {
9792
+ filesystemDiscontinuityProtocol: FILESYSTEM_DISCONTINUITY_PROTOCOL,
9611
9793
  sessionId: input.sessionId,
9612
9794
  workflowId: input.workflowId,
9613
9795
  workflowRunId: input.workflowRunId,
@@ -9647,6 +9829,7 @@ async function claimTurnAttempt(deps) {
9647
9829
  turnId: attempt.turnId,
9648
9830
  opAcks: {}
9649
9831
  };
9832
+ eventing.heartbeatDetails = heartbeatDetails;
9650
9833
  const opJournal = makeTurnOpJournal(activityContext, heartbeatDetails);
9651
9834
  eventing.heartbeatTimer = startActivityHeartbeat(activityContext, heartbeatDetails);
9652
9835
  let producerSeq = 0;
@@ -9773,6 +9956,11 @@ async function claimTurnAttempt(deps) {
9773
9956
  throwIfTurnCancelled();
9774
9957
  recordTurnStartupPhase(observability, {
9775
9958
  phase: "claim_and_policy",
9959
+ executionCorrelationId: turnExecutionTelemetryKey(
9960
+ input.workspaceId,
9961
+ input.sessionId,
9962
+ input.attemptId
9963
+ ),
9776
9964
  provider: turnExecutionPolicy.providerId,
9777
9965
  backend: turn.sandboxBackend,
9778
9966
  outcome: "completed",
@@ -10105,10 +10293,17 @@ async function selectCodexTurnCapacity(deps) {
10105
10293
  selectForTurn
10106
10294
  );
10107
10295
  if (leased.decision.kind === "allCapped") {
10108
- await refreshCappedCodexUsageRows(db, settings, input.workspaceId, leased.accounts, {
10109
- signalCodexCapacityWorkflow,
10110
- wakeSessionWorkflow
10111
- });
10296
+ await refreshCappedCodexUsageRows(
10297
+ db,
10298
+ settings,
10299
+ input.workspaceId,
10300
+ leased.accounts,
10301
+ {
10302
+ signalCodexCapacityWorkflow,
10303
+ wakeSessionWorkflow
10304
+ },
10305
+ turn.id
10306
+ );
10112
10307
  leaseAcquisitionStartedAtMs = performance.now();
10113
10308
  leased = await acquireCodexCredentialLease(
10114
10309
  db,
@@ -10348,6 +10543,11 @@ async function selectCodexTurnCapacity(deps) {
10348
10543
  }
10349
10544
  }
10350
10545
  );
10546
+ if (evaluated.action === "stopped") {
10547
+ control.turnMetricOutcome = "failed";
10548
+ control.activityStatus = evaluated.sessionStatus === "queued" ? "idle" : "failed";
10549
+ return { exit: claimedResult({ status: control.activityStatus }) };
10550
+ }
10351
10551
  if (evaluated.action === "resumed") {
10352
10552
  control.turnMetricOutcome = "recovering";
10353
10553
  control.activityStatus = "recovering";
@@ -10442,6 +10642,11 @@ async function selectCodexTurnCapacity(deps) {
10442
10642
  }
10443
10643
  }
10444
10644
  );
10645
+ if (evaluated.action === "stopped") {
10646
+ control.turnMetricOutcome = "failed";
10647
+ control.activityStatus = evaluated.sessionStatus === "queued" ? "idle" : "failed";
10648
+ return { exit: claimedResult({ status: control.activityStatus }) };
10649
+ }
10445
10650
  if (evaluated.action === "resumed") {
10446
10651
  control.turnMetricOutcome = "recovering";
10447
10652
  control.activityStatus = "recovering";
@@ -10525,6 +10730,11 @@ async function selectCodexTurnCapacity(deps) {
10525
10730
  failurePayload
10526
10731
  }
10527
10732
  );
10733
+ if (evaluated.action === "stopped") {
10734
+ control.turnMetricOutcome = "failed";
10735
+ control.activityStatus = evaluated.sessionStatus === "queued" ? "idle" : "failed";
10736
+ return { exit: claimedResult({ status: control.activityStatus }) };
10737
+ }
10528
10738
  if (evaluated.action === "resumed") {
10529
10739
  control.turnMetricOutcome = "recovering";
10530
10740
  control.activityStatus = "recovering";
@@ -10653,6 +10863,7 @@ import {
10653
10863
  renderWorkspaceGovernanceContext
10654
10864
  } from "@opengeni/runtime";
10655
10865
  import { settingsWithResolvedModelContext } from "@opengeni/config";
10866
+ import { projectReasoningConfigurations, supportsReasoningConfiguration } from "@opengeni/codex";
10656
10867
  import { resolveRigProviderImageForRun } from "@opengeni/core";
10657
10868
  import { retryWhileMissing as retryWhileMissing3 } from "@opengeni/storage";
10658
10869
  import { WorkspaceModelPolicyBlockedError } from "@opengeni/runtime";
@@ -11002,12 +11213,10 @@ async function prepareGovernanceAndModel(deps) {
11002
11213
  executionGeneration: turn.executionGeneration
11003
11214
  };
11004
11215
  const [
11005
- packRuntime,
11006
11216
  rigMaterialization,
11007
11217
  [workspace, companyProfileSnapshot, instructionPolicySnapshot, preferenceSnapshot],
11008
11218
  workspaceModelPolicy
11009
11219
  ] = await Promise.all([
11010
- resolveWorkspacePackRuntime(db, input.workspaceId),
11011
11220
  session.rigId && session.rigVersionId ? (async () => await materializeRigVersionForAttempt(db, {
11012
11221
  accountId: input.accountId,
11013
11222
  workspaceId: input.workspaceId,
@@ -11073,11 +11282,7 @@ async function prepareGovernanceAndModel(deps) {
11073
11282
  );
11074
11283
  } catch {
11075
11284
  }
11076
- const logicalSandboxSettings = rigVersion ? capabilitySettings : settingsWithPackSandboxImage(
11077
- capabilitySettings,
11078
- packRuntime.sandboxImage,
11079
- packRuntime.sandboxProviderImages
11080
- );
11285
+ const logicalSandboxSettings = capabilitySettings;
11081
11286
  const providerImageSelection = await resolveRigProviderImageForRun(
11082
11287
  logicalSandboxSettings,
11083
11288
  rigVersion,
@@ -11086,9 +11291,8 @@ async function prepareGovernanceAndModel(deps) {
11086
11291
  const providerImageSettings = providerImageSelection.settings;
11087
11292
  const verifiedRigProviderImageId = providerImageSelection.reason === "selected" ? providerImageSelection.imageId ?? void 0 : void 0;
11088
11293
  const baseRunSettings = {
11089
- // IMAGE PRECEDENCE: a Rig uses the deployment platform base; a rig-less
11090
- // pre-v2 Pack may retain its compatibility image. A matching verified
11091
- // provider-native ID is then applied only to fresh creation without
11294
+ // A Rig uses the deployment platform base. A matching verified
11295
+ // provider-native ID is applied only to fresh creation without
11092
11296
  // changing the logical lease image.
11093
11297
  ...providerImageSettings,
11094
11298
  openaiModel: turn.model,
@@ -11128,8 +11332,12 @@ async function prepareGovernanceAndModel(deps) {
11128
11332
  fileIds
11129
11333
  })
11130
11334
  );
11335
+ const useReasoningUpdates = runSettings.reasoningConfigurationUpdatesEnabled && providerApi === "responses" && (resolvedModel?.provider.id === "codex" || resolvedModel?.provider.id === "openai") && supportsReasoningConfiguration(turnExecutionPolicy.upstreamModelId, turn.reasoningEffort);
11131
11336
  const modelHistoryProjector = async (items, projectionOptions) => projectModelInputForCapabilities(
11132
- await attachmentProjector(items, projectionOptions),
11337
+ projectReasoningConfigurations(
11338
+ await attachmentProjector(items, projectionOptions),
11339
+ useReasoningUpdates
11340
+ ),
11133
11341
  modelInputPolicy
11134
11342
  );
11135
11343
  const generatedImageHistoryProjector = async (items) => {
@@ -11187,7 +11395,6 @@ async function prepareGovernanceAndModel(deps) {
11187
11395
  return {
11188
11396
  ok: {
11189
11397
  runtimePreparationStartedAt,
11190
- packRuntime,
11191
11398
  rigVersion,
11192
11399
  rigName,
11193
11400
  agentHumanInputEnabled,
@@ -11221,8 +11428,11 @@ import {
11221
11428
  appendWorkspaceMemory,
11222
11429
  composeAgentInstructions,
11223
11430
  requestRemoteCompactionV2,
11224
- serializedToolsForRemoteCompaction,
11225
- EmptyCompactionSummaryError as EmptyCompactionSummaryError2,
11431
+ preparedCompactionRequest,
11432
+ queuePreparedCompaction,
11433
+ compactionThresholdTokens as compactionThresholdTokens2,
11434
+ CompactionNeededError,
11435
+ compactionProviderRejection as compactionProviderRejection2,
11226
11436
  SUMMARY_BUFFER_TOKENS as SUMMARY_BUFFER_TOKENS2
11227
11437
  } from "@opengeni/runtime";
11228
11438
  async function prepareCompaction(deps) {
@@ -11260,9 +11470,6 @@ async function prepareCompaction(deps) {
11260
11470
  withCodexRemoteCompaction
11261
11471
  } = deps;
11262
11472
  const remotePrefix = {
11263
- tools: [],
11264
- instructions: "",
11265
- toolsReady: false,
11266
11473
  agent: null
11267
11474
  };
11268
11475
  const promptCacheKey = acceptsPromptCacheKeyForTurn(resolvedModel) ? input.sessionId : void 0;
@@ -11315,38 +11522,16 @@ async function prepareCompaction(deps) {
11315
11522
  ...promptCacheKey ? { promptCacheKey } : {}
11316
11523
  });
11317
11524
  const remoteCompactionRequester = resolvedModel && billingState.isCodexTurn ? (s, m) => withCodexRemoteCompaction(async () => {
11318
- if (!remotePrefix.instructions.trim()) {
11319
- throw new EmptyCompactionSummaryError2({
11320
- stage: "remote_v2_instructions",
11321
- reason: "agent_missing_system_instructions"
11322
- });
11323
- }
11324
- if (!remotePrefix.toolsReady) {
11325
- if (!remotePrefix.agent) {
11326
- throw new EmptyCompactionSummaryError2({
11327
- stage: "remote_v2_tools",
11328
- reason: "agent_missing_for_tools"
11329
- });
11330
- }
11331
- try {
11332
- remotePrefix.tools = await serializedToolsForRemoteCompaction(remotePrefix.agent);
11333
- } catch (error51) {
11334
- throw new EmptyCompactionSummaryError2({
11335
- stage: "remote_v2_tools",
11336
- reason: "serialize_tools_failed",
11337
- error: String(error51)
11338
- });
11339
- }
11340
- remotePrefix.toolsReady = true;
11341
- }
11525
+ if (!remotePrefix.agent) throw new Error("Compaction agent is unavailable");
11526
+ const preparedRequest = preparedCompactionRequest(remotePrefix.agent);
11342
11527
  return requestRemoteCompactionV2(s, m, {
11343
11528
  client: resolvedModel.client,
11344
11529
  provider: resolvedModel.provider,
11345
11530
  model: turnExecutionPolicy.upstreamModelId,
11346
- systemInstructions: remotePrefix.instructions,
11347
- onUsage: recordCompactionUsage,
11348
- tools: remotePrefix.tools,
11349
- ...promptCacheKey ? { promptCacheKey } : {}
11531
+ preparedRequest,
11532
+ captureAgent: remotePrefix.agent,
11533
+ signal: cancellationSignal,
11534
+ onUsage: recordCompactionUsage
11350
11535
  });
11351
11536
  }) : void 0;
11352
11537
  const publishCompactionLiveEvents = async (events) => {
@@ -11458,22 +11643,16 @@ async function prepareCompaction(deps) {
11458
11643
  },
11459
11644
  {
11460
11645
  clearRequestedCompaction: true,
11461
- publishLiveEvents: publishCompactionLiveEvents
11646
+ publishLiveEvents: publishCompactionLiveEvents,
11647
+ providerRejection: compactionProviderRejection2(error51)
11462
11648
  }
11463
11649
  );
11464
11650
  if (!isCompactionSummaryFailure(error51)) throw error51;
11465
- const errorMessage = String(compactionFailureReasonFromError(error51));
11466
11651
  if (!await eventing.settle({
11467
11652
  events: [
11468
11653
  {
11469
11654
  type: "turn.failed",
11470
- payload: {
11471
- error: errorMessage,
11472
- code: "context_compaction_failed",
11473
- retryable: false,
11474
- recovery: "user_message",
11475
- compacted: false
11476
- }
11655
+ payload: compactionFailureTurnEventPayload(error51)
11477
11656
  },
11478
11657
  {
11479
11658
  type: "session.status.changed",
@@ -11563,12 +11742,23 @@ async function runPostAgentCompaction(deps) {
11563
11742
  agentInstructions.trim() ? agentInstructions : void 0
11564
11743
  );
11565
11744
  if (remoteCompactionRequester) {
11566
- remotePrefix.instructions = agentInstructions;
11567
11745
  remotePrefix.agent = agent;
11568
11746
  }
11569
11747
  if (compactionOnlyTurn) {
11570
11748
  const requested = await isSessionCompactionRequested2(db, input.workspaceId, input.sessionId);
11571
11749
  let outcome = null;
11750
+ if (requested && remoteCompactionRequester && session.codexCompactionMode === "remote_v2") {
11751
+ queuePreparedCompaction(
11752
+ agent,
11753
+ new CompactionNeededError({
11754
+ trigger: "operator",
11755
+ signalSource: "operator",
11756
+ signalTokens: session.lastInputTokens ?? 0,
11757
+ thresholdTokens: compactionThresholdTokens2(eventing.modelRunSettings)
11758
+ })
11759
+ );
11760
+ return { ok: { compactSummarizer } };
11761
+ }
11572
11762
  if (requested) {
11573
11763
  try {
11574
11764
  outcome = await waitForTurnOperation(
@@ -11611,22 +11801,16 @@ async function runPostAgentCompaction(deps) {
11611
11801
  },
11612
11802
  {
11613
11803
  clearRequestedCompaction: true,
11614
- publishLiveEvents: publishCompactionLiveEvents
11804
+ publishLiveEvents: publishCompactionLiveEvents,
11805
+ providerRejection: compactionProviderRejection2(error51)
11615
11806
  }
11616
11807
  );
11617
11808
  if (!isCompactionSummaryFailure(error51)) throw error51;
11618
- const errorMessage = String(compactionFailureReasonFromError(error51));
11619
11809
  if (!await eventing.settle({
11620
11810
  events: [
11621
11811
  {
11622
11812
  type: "turn.failed",
11623
- payload: {
11624
- error: errorMessage,
11625
- code: "context_compaction_failed",
11626
- retryable: false,
11627
- recovery: "user_message",
11628
- compacted: false
11629
- }
11813
+ payload: compactionFailureTurnEventPayload(error51)
11630
11814
  },
11631
11815
  {
11632
11816
  type: "session.status.changed",
@@ -11673,6 +11857,22 @@ async function runPostAgentCompaction(deps) {
11673
11857
  control.activityStatus = "idle";
11674
11858
  return { exit: claimedResult({ status: "idle" }) };
11675
11859
  }
11860
+ if (remoteCompactionRequester && session.codexCompactionMode === "remote_v2") {
11861
+ const forced = await isSessionCompactionRequested2(db, input.workspaceId, input.sessionId);
11862
+ const thresholdTokens = compactionThresholdTokens2(eventing.modelRunSettings);
11863
+ if (forced || (attempt.triggerType === "user.message" || attempt.triggerType === "system.update.delivered") && (session.lastInputTokens ?? 0) >= thresholdTokens) {
11864
+ queuePreparedCompaction(
11865
+ agent,
11866
+ new CompactionNeededError({
11867
+ trigger: forced ? "operator" : "threshold",
11868
+ signalSource: forced ? "operator" : "provider",
11869
+ signalTokens: session.lastInputTokens ?? 0,
11870
+ thresholdTokens
11871
+ })
11872
+ );
11873
+ }
11874
+ return { ok: { compactSummarizer } };
11875
+ }
11676
11876
  if (attempt.triggerType === "user.message" || attempt.triggerType === "system.update.delivered") {
11677
11877
  let forced = false;
11678
11878
  try {
@@ -11741,13 +11941,13 @@ async function runPostAgentCompaction(deps) {
11741
11941
  },
11742
11942
  {
11743
11943
  clearRequestedCompaction: forced,
11744
- publishLiveEvents: publishCompactionLiveEvents
11944
+ publishLiveEvents: publishCompactionLiveEvents,
11945
+ providerRejection: compactionProviderRejection2(compactError)
11745
11946
  }
11746
11947
  );
11747
11948
  if (!isCompactionSummaryFailure(compactError)) throw compactError;
11748
11949
  const deferredSteer = await settleDeferredSteerAfterCompaction();
11749
11950
  if (deferredSteer) return { exit: deferredSteer };
11750
- const errorMessage = String(compactionFailureReasonFromError(compactError));
11751
11951
  observability.error("context compaction failed", {
11752
11952
  sessionId: input.sessionId,
11753
11953
  turnId: attempt.turnId,
@@ -11757,13 +11957,7 @@ async function runPostAgentCompaction(deps) {
11757
11957
  events: [
11758
11958
  {
11759
11959
  type: "turn.failed",
11760
- payload: {
11761
- error: errorMessage,
11762
- code: "context_compaction_failed",
11763
- retryable: false,
11764
- recovery: "user_message",
11765
- compacted: false
11766
- }
11960
+ payload: compactionFailureTurnEventPayload(compactError)
11767
11961
  },
11768
11962
  { type: "session.status.changed", payload: { status: "idle" } }
11769
11963
  ],
@@ -11793,7 +11987,8 @@ import {
11793
11987
  SandboxWorkspaceMutationFencedError
11794
11988
  } from "@opengeni/db";
11795
11989
  import {
11796
- RoutingMutationOutcomeUnknownError
11990
+ RoutingMutationOutcomeUnknownError,
11991
+ runManagedCodemodeClientHook
11797
11992
  } from "@opengeni/runtime";
11798
11993
  import {
11799
11994
  sandboxLifecycleTransitionWaitMs,
@@ -11844,12 +12039,23 @@ function createSandboxTurnRuntime(deps) {
11844
12039
  sandboxState.machinePrimarySession
11845
12040
  );
11846
12041
  };
11847
- const onHomeSandboxRebound = (rebound) => {
12042
+ const onHomeSandboxRebound = async (rebound) => {
11848
12043
  const current = sandboxState.resolvedSandbox;
12044
+ if (!current) throw new Error("Home sandbox rebound before turn sandbox admission");
12045
+ if (rebound.established.backendId !== "selfhosted" && rebound.established.instanceId !== current.established.instanceId) {
12046
+ const commandFence = eventing.toolCancellationFenceRef.current;
12047
+ await runWorkspaceMutationForSandbox(
12048
+ { ...current, established: rebound.established, leaseEpoch: rebound.leaseEpoch },
12049
+ "homeSandboxClientPreparation",
12050
+ () => runManagedCodemodeClientHook(rebound.established.session, {
12051
+ environment: {},
12052
+ ...commandFence ? { commandRunner: commandFence.runSandboxCommand.bind(commandFence) } : {}
12053
+ })
12054
+ );
12055
+ }
11849
12056
  const previousSession = current?.established.session;
11850
12057
  const preserveRoutingProxy = current !== null && previousSession !== sandboxState.setupBoxSession;
11851
12058
  sandboxState.setupBoxSession = rebound.established.session;
11852
- if (!current) return;
11853
12059
  current.leaseEpoch = rebound.leaseEpoch;
11854
12060
  current.established = preserveRoutingProxy ? {
11855
12061
  ...current.established,
@@ -12120,7 +12326,13 @@ function createSandboxTurnRuntime(deps) {
12120
12326
  deadlineRotationRequested: sandboxState.deadlineRotationRequested
12121
12327
  })) {
12122
12328
  const snapshot = maybePersistWarmWorkspaceSnapshot(
12123
- { db, settings, objectStorage },
12329
+ {
12330
+ db,
12331
+ settings,
12332
+ objectStorage,
12333
+ sandboxMetrics: runtimeMetricsHooksForObservability(observability),
12334
+ observability
12335
+ },
12124
12336
  {
12125
12337
  accountId: input.accountId,
12126
12338
  workspaceId: input.workspaceId,
@@ -12177,6 +12389,9 @@ import {
12177
12389
  getLiveEnrollmentConnection,
12178
12390
  assertPersonalMachineForAttempt
12179
12391
  } from "@opengeni/db";
12392
+ import {
12393
+ sandboxCaptureWaitMetricObserver
12394
+ } from "@opengeni/observability";
12180
12395
  import {
12181
12396
  withRunCredentialsSession as withRunCredentialsSession2,
12182
12397
  runOwnedSandboxSetup as runOwnedSandboxSetup2,
@@ -12552,6 +12767,7 @@ async function establishTurnSandbox(deps) {
12552
12767
  bus,
12553
12768
  onOp: machineOpObserver.observer,
12554
12769
  onSandboxOperation: sandboxOperationObserver,
12770
+ onSandboxCaptureWait: sandboxCaptureWaitMetricObserver(observability),
12555
12771
  opJournal
12556
12772
  },
12557
12773
  {
@@ -12614,6 +12830,7 @@ async function establishTurnSandbox(deps) {
12614
12830
  opJournal,
12615
12831
  onOp: machineOpObserver.observer,
12616
12832
  onSandboxOperation: sandboxOperationObserver,
12833
+ onSandboxCaptureWait: sandboxCaptureWaitMetricObserver(observability),
12617
12834
  onHomeSandboxRebound,
12618
12835
  ...runtimeCancellationSignal ? { waitSignal: runtimeCancellationSignal } : {}
12619
12836
  },
@@ -12820,6 +13037,7 @@ async function establishTurnSandbox(deps) {
12820
13037
  bus,
12821
13038
  opJournal,
12822
13039
  onSandboxOperation: sandboxOperationObserver,
13040
+ onSandboxCaptureWait: sandboxCaptureWaitMetricObserver(observability),
12823
13041
  onHomeSandboxLost: publishSandboxLost,
12824
13042
  onHomeSandboxRebound,
12825
13043
  ...runtimeCancellationSignal ? { waitSignal: runtimeCancellationSignal } : {}
@@ -13020,6 +13238,7 @@ async function bindLazySandboxProvisioner(deps) {
13020
13238
  {
13021
13239
  settings: runSettings,
13022
13240
  environment: sandboxEnvironment,
13241
+ recordLazyManifest: true,
13023
13242
  onRuntimeEvent: async (event) => {
13024
13243
  await eventing.publish?.([{ type: event.type, payload: event.payload }], true);
13025
13244
  },
@@ -13121,6 +13340,7 @@ async function bindLazySandboxProvisioner(deps) {
13121
13340
  opJournal,
13122
13341
  onOp: machineOpObserver.observer,
13123
13342
  onSandboxOperation: sandboxOperationObserver,
13343
+ onSandboxCaptureWait: sandboxCaptureWaitMetricObserver(observability),
13124
13344
  onHomeSandboxLost: publishSandboxLost,
13125
13345
  onHomeSandboxRebound,
13126
13346
  ...runtimeCancellationSignal ? { waitSignal: runtimeCancellationSignal } : {}
@@ -13966,7 +14186,7 @@ async function prepareRunCredentials(deps) {
13966
14186
  )
13967
14187
  ]);
13968
14188
  const needsHostCredentialRoot = Boolean(
13969
- connectionCredentials?.gitCredentials || personalGitHubCredentials || connectionCredentials?.mcpCredentials
14189
+ connectionCredentials?.gitCredentials || personalGitHubCredentials
13970
14190
  );
13971
14191
  const hostCredentialRootSessionId = needsHostCredentialRoot ? await getSessionRootId2(db, input.workspaceId, input.sessionId) : null;
13972
14192
  if (needsHostCredentialRoot && !hostCredentialRootSessionId) {
@@ -14336,7 +14556,6 @@ async function prepareRunCredentials(deps) {
14336
14556
  initialRunCredentialMaterial,
14337
14557
  runCredentialsNote,
14338
14558
  authorizeGitHubTokenMint,
14339
- hostCredentialRootSessionId,
14340
14559
  gitCredentialAuthority,
14341
14560
  codemodeAuthority,
14342
14561
  sandboxArtifactRuntime,
@@ -14442,7 +14661,7 @@ import { getWorkspaceConnectionModelRestrictions } from "@opengeni/db";
14442
14661
  import {
14443
14662
  beginConnectorActionExecution,
14444
14663
  getExternalLinkTurnAuthorization,
14445
- getSessionTurnForAttempt as getSessionTurnForAttempt2,
14664
+ getSessionTurnForAttempt,
14446
14665
  getWorkspaceVideoGenerationPolicy,
14447
14666
  listSkillDescriptors as listSkillDescriptors2,
14448
14667
  completeConnectorActionExecution,
@@ -14516,15 +14735,14 @@ async function resolveGoogleDrivePublicationTarget(db, workspace, delegations, p
14516
14735
  );
14517
14736
  if (frozen.length !== 1) return null;
14518
14737
  const delegation = frozen[0];
14519
- const activated = delegation.userDelegation !== void 0;
14520
- if (!activated && !await ports.getMembership(db, {
14738
+ if (!await ports.getMembership(db, {
14521
14739
  accountId: workspace.accountId,
14522
14740
  workspaceId,
14523
14741
  subjectId: delegation.ownerSubjectId
14524
14742
  })) {
14525
14743
  return null;
14526
14744
  }
14527
- const originWorkspaceId = activated ? delegation.originWorkspaceId : workspaceId;
14745
+ const originWorkspaceId = delegation.originWorkspaceId;
14528
14746
  if (!originWorkspaceId) return null;
14529
14747
  const connection = await ports.getConnection(
14530
14748
  db,
@@ -15075,23 +15293,17 @@ function driveQuery(value) {
15075
15293
  }
15076
15294
 
15077
15295
  // src/activities/mcp-credentials.ts
15296
+ import { stableJson as stableJson2 } from "@opengeni/contracts";
15078
15297
  import {
15079
15298
  buildConnectionTokenResolver,
15080
- buildHostConnectionTokenResolver,
15081
- getSessionTurnForAttempt,
15082
- authorizeDirectHostMcpUse,
15083
- resolveAcceptedHostMcpBinding,
15084
- resolveAcceptedConnectionUse,
15085
- sessionTenancyProductActivated
15299
+ resolveAcceptedConnectionUse
15086
15300
  } from "@opengeni/db";
15087
- import { recordTenancyCompatibilityLaneUse } from "@opengeni/observability";
15088
15301
 
15089
15302
  // src/activities/mcp-operation-authority.ts
15090
15303
  import { createHash as createHash10 } from "crypto";
15091
15304
  import { stableJson } from "@opengeni/contracts";
15092
15305
  function mcpOperationAuthorityDigest(request, authority) {
15093
15306
  const n = authority.native;
15094
- const h = authority.host;
15095
15307
  const ref = request.connectionRef;
15096
15308
  const metadata = {
15097
15309
  version: 1,
@@ -15105,14 +15317,13 @@ function mcpOperationAuthorityDigest(request, authority) {
15105
15317
  providerDomain: ref.providerDomain,
15106
15318
  kind: ref.kind,
15107
15319
  subjectScope: ref.subjectScope,
15108
- hostBinding: ref.hostBinding,
15109
15320
  scopes: ref.scopes ? [...ref.scopes].sort() : void 0,
15110
15321
  resource: ref.resource,
15111
15322
  selectedResources: ref.selectedResources ? [...ref.selectedResources].sort(
15112
15323
  (a, b) => stableJson(a) < stableJson(b) ? -1 : stableJson(a) > stableJson(b) ? 1 : 0
15113
15324
  ) : void 0
15114
15325
  },
15115
- native: n ? {
15326
+ native: {
15116
15327
  organizationId: n.organizationId,
15117
15328
  workspaceId: n.workspaceId,
15118
15329
  sessionId: n.sessionId,
@@ -15122,87 +15333,28 @@ function mcpOperationAuthorityDigest(request, authority) {
15122
15333
  ownerSubjectId: n.ownerSubjectId,
15123
15334
  authorityId: n.authorityId,
15124
15335
  grantId: n.grantId,
15125
- principal: "principal" in authority ? authority.principal : void 0
15126
- } : void 0,
15127
- host: h ? {
15128
- accountId: h.accountId,
15129
- workspaceId: h.workspaceId,
15130
- targetSessionId: h.targetSessionId,
15131
- targetSessionVisibility: h.targetSessionVisibility,
15132
- targetSessionAuthorityEpoch: h.targetSessionAuthorityEpoch,
15133
- ownerSubjectId: h.ownerSubjectId,
15134
- ownerOrganizationMembershipId: h.ownerOrganizationMembershipId,
15135
- ownerMembershipAuthorizationRevision: h.ownerMembershipAuthorizationRevision,
15136
- bindingId: h.bindingId,
15137
- bindingGeneration: h.bindingGeneration,
15138
- definition: h.definition,
15139
- delegationId: h.delegationId,
15140
- delegationGeneration: h.delegationGeneration
15141
- } : void 0
15336
+ principal: authority.principal
15337
+ }
15142
15338
  };
15143
15339
  return createHash10("sha256").update(stableJson(metadata)).digest("hex");
15144
15340
  }
15145
15341
 
15146
15342
  // src/activities/mcp-credentials.ts
15147
- var OPENGENI_CONNECTION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
15148
15343
  function connectionTokenResolverForTurn(input) {
15149
- const hostResolver = input.connectionCredentials?.mcpCredentials;
15150
- const readHostTurn = input.getHostTurnForAttempt ?? getSessionTurnForAttempt;
15151
- const hostDb = input.db;
15152
- const nativeResolver = buildConnectionTokenResolver(input.db, input.settings);
15344
+ return bindNativeConnectionCredentialsToTurn(
15345
+ input,
15346
+ buildConnectionTokenResolver(input.db, input.settings)
15347
+ );
15348
+ }
15349
+ function bindNativeConnectionCredentialsToTurn(input, nativeResolver) {
15153
15350
  const recoveryEnabled = (serverId) => input.settings.mcpServers.some(
15154
15351
  (server) => server.id === serverId && "operationRecovery" in server && server.operationRecovery !== void 0 && Object.keys(server.operationRecovery ?? {}).length > 0
15155
15352
  );
15156
- const configuredResolver = hostResolver ? async (credentialRequest) => {
15157
- let authorizedSnapshot;
15158
- const wantsDigest = recoveryEnabled(credentialRequest.serverId);
15159
- const resolver = buildHostConnectionTokenResolver(hostResolver, {
15160
- accountId: input.accountId,
15161
- workspaceId: input.workspaceId,
15162
- sessionId: input.sessionId,
15163
- rootSessionId: input.rootSessionId,
15164
- turnId: input.turn.id,
15165
- attemptId: input.attemptId,
15166
- executionGeneration: input.turn.executionGeneration,
15167
- initiator: input.turn.initiator,
15168
- initiatorContext: input.turn.initiatorContext,
15169
- surface: "model",
15170
- resolveAcceptedBinding: (request) => resolveAcceptedHostMcpBinding(hostDb, request),
15171
- // Only immutable captured direct-turn authority is currently supported.
15172
- // Direct, scheduled and exact causal/child snapshots are validated;
15173
- // no authority follows merely from a binding or creator identity.
15174
- authorizeDurableBinding: (request) => authorizeDirectHostMcpUse(
15175
- hostDb,
15176
- request,
15177
- wantsDigest ? (snapshot) => {
15178
- authorizedSnapshot = snapshot;
15179
- } : void 0
15180
- ),
15181
- authorizeExecution: async (request) => {
15182
- if (request.connectionRef.authoritySource !== "host" && (!request.connectionRef.connectionId || OPENGENI_CONNECTION_ID_PATTERN.test(request.connectionRef.connectionId)))
15183
- return true;
15184
- if (!request.attemptId) return false;
15185
- const current = await readHostTurn(
15186
- hostDb,
15187
- request.workspaceId,
15188
- request.sessionId,
15189
- request.attemptId
15190
- );
15191
- return current !== null && current.id === request.turnId && current.executionGeneration === request.executionGeneration;
15192
- }
15193
- });
15194
- const result = await resolver(credentialRequest);
15195
- return result.status === "ok" && authorizedSnapshot ? {
15196
- ...result,
15197
- operationAuthorityDigest: mcpOperationAuthorityDigest(credentialRequest, {
15198
- host: authorizedSnapshot
15199
- })
15200
- } : result;
15201
- } : nativeResolver;
15202
- const baseResolver = (request) => input.connectionCredentials?.mcpAuthoritySource === "host" && request.connectionRef.authoritySource !== "host" ? nativeResolver(request) : configuredResolver(request);
15353
+ const canonicalMcpServerIds = new Set(
15354
+ input.canonicalMcpServerIds ?? input.settings.mcpServers.filter((server) => server.connectionRef).map((server) => server.id)
15355
+ );
15203
15356
  return async (request) => {
15204
15357
  if (request.connectionRef.authoritySource === "host") {
15205
- if (hostResolver) return await baseResolver(request);
15206
15358
  return {
15207
15359
  status: "auth_needed",
15208
15360
  reason: "unsupported_auth",
@@ -15215,22 +15367,15 @@ function connectionTokenResolverForTurn(input) {
15215
15367
  ...request.connectionRef.selectedResources ? { selectedResources: request.connectionRef.selectedResources } : {}
15216
15368
  };
15217
15369
  }
15218
- if (hostResolver && input.connectionCredentials?.mcpAuthoritySource !== "host" && request.connectionRef.connectionId && !OPENGENI_CONNECTION_ID_PATTERN.test(request.connectionRef.connectionId)) {
15219
- try {
15220
- return await baseResolver(request);
15221
- } catch {
15222
- return {
15223
- status: "auth_needed",
15224
- reason: "refresh_failed",
15225
- providerDomain: request.connectionRef.providerDomain,
15226
- authoritySource: "host",
15227
- ...request.connectionRef.provider ? { provider: request.connectionRef.provider } : {},
15228
- connectionId: request.connectionRef.connectionId,
15229
- ...request.connectionRef.scopes ? { scopes: request.connectionRef.scopes } : {},
15230
- ...request.connectionRef.resource ? { resource: request.connectionRef.resource } : {},
15231
- ...request.connectionRef.selectedResources ? { selectedResources: request.connectionRef.selectedResources } : {}
15232
- };
15233
- }
15370
+ const accountBindings = input.turn.mcpAccountBindings ?? [];
15371
+ const accountBinding = accountBindings.find((binding) => binding.serverId === request.serverId);
15372
+ if (input.turn.mcpAccountBindings != null && !accountBinding && canonicalMcpServerIds.has(request.serverId) || !accountBinding && accountBindings.some((binding) => binding.canonicalServerId === request.serverId) || accountBinding && (request.connectionRef.connectionId !== accountBinding.connectionId || request.connectionRef.providerDomain !== accountBinding.providerDomain || request.connectionRef.kind !== accountBinding.kind || request.connectionRef.subjectScope !== accountBinding.subjectScope || stableJson2(request.connectionRef) !== stableJson2(accountBinding.connectionRef) || accountBinding.subjectScope === "subject" && request.subjectId !== accountBinding.ownerSubjectId)) {
15373
+ return {
15374
+ status: "auth_needed",
15375
+ reason: "personal_authority_unavailable",
15376
+ providerDomain: request.connectionRef.providerDomain,
15377
+ ...request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}
15378
+ };
15234
15379
  }
15235
15380
  const acceptedDelegation = input.turn.personalConnectionDelegations.find(
15236
15381
  (delegation) => (delegation.connectionType === void 0 || delegation.connectionType === "mcp" || delegation.connectionType === "github_personal" && delegation.serverId === "github:personal" && request.serverId === "github:personal" && request.connectionRef.provider === "github" && request.connectionRef.kind === "oauth2" && request.connectionRef.providerDomain === "github.com" && request.credentialTarget === "http_api" && isGitHubApiDestination(request.destinationUrl)) && delegation.serverId === request.serverId && delegation.connectionId === request.connectionRef.connectionId
@@ -15245,19 +15390,12 @@ function connectionTokenResolverForTurn(input) {
15245
15390
  };
15246
15391
  }
15247
15392
  if (subjectScope === "workspace" && !request.connectionRef.connectionId) {
15248
- if (await (input.isSessionTenancyProductActivated ?? sessionTenancyProductActivated)(
15249
- input.db,
15250
- input.workspaceId
15251
- )) {
15252
- return {
15253
- status: "auth_needed",
15254
- reason: "missing_connection",
15255
- providerDomain: request.connectionRef.providerDomain,
15256
- ...request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}
15257
- };
15258
- }
15259
- recordTenancyCompatibilityLaneUse(input.observability, "connection_pre_snapshot_ref");
15260
- return await baseResolver(request);
15393
+ return {
15394
+ status: "auth_needed",
15395
+ reason: "missing_connection",
15396
+ providerDomain: request.connectionRef.providerDomain,
15397
+ ...request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}
15398
+ };
15261
15399
  }
15262
15400
  const credentialUseContext = {
15263
15401
  accountId: input.accountId,
@@ -15299,51 +15437,32 @@ function connectionTokenResolverForTurn(input) {
15299
15437
  })
15300
15438
  } : {},
15301
15439
  authorizeProviderRequest: async () => {
15302
- const authorization2 = await authorize({
15440
+ const authorization = await authorize({
15303
15441
  ...credentialUseContext,
15304
15442
  physicalRequestId: crypto.randomUUID(),
15305
15443
  usePhase: "provider_request"
15306
15444
  });
15307
- return authorization2.status === "authorized";
15445
+ return authorization.status === "authorized";
15308
15446
  }
15309
15447
  };
15310
15448
  };
15311
- const recordAuthorizedScope = (scope) => {
15312
- if (scope === "legacy_user") {
15313
- recordTenancyCompatibilityLaneUse(input.observability, "connection_legacy_user");
15314
- }
15315
- };
15316
- if (!hostResolver) {
15317
- const result2 = await baseResolver({
15318
- ...request,
15319
- connectionUseContext: credentialUseContext
15320
- });
15321
- if (result2.status === "ok") recordAuthorizedScope(result2.connectionUseAttribution?.scope);
15322
- return withProviderRequestAuthorization(result2);
15323
- }
15324
- const authorization = await authorize(credentialUseContext);
15325
- if (authorization.status === "denied") {
15449
+ const { subjectId: requestSubjectId, ...requestWithoutSubject } = request;
15450
+ const result = await nativeResolver({
15451
+ ...requestWithoutSubject,
15452
+ ...accountBinding?.connectionAuthorityGeneration !== void 0 ? { expectedAuthorityGeneration: accountBinding.connectionAuthorityGeneration } : {},
15453
+ // Workspace authority has no personal owner, even when the turn has a
15454
+ // causal human. Do not pass that human as credential ownership context.
15455
+ ...accountBinding?.subjectScope !== "workspace" && requestSubjectId !== void 0 ? { subjectId: requestSubjectId } : {},
15456
+ connectionUseContext: credentialUseContext
15457
+ });
15458
+ if (accountBinding && result.status === "ok" && result.connectionId !== accountBinding.connectionId) {
15326
15459
  return {
15327
15460
  status: "auth_needed",
15328
- reason: request.connectionRef.subjectScope === "subject" ? "personal_authority_unavailable" : "missing_connection",
15329
- providerDomain: request.connectionRef.providerDomain,
15330
- ...request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}
15461
+ reason: "personal_authority_unavailable",
15462
+ providerDomain: accountBinding.providerDomain
15331
15463
  };
15332
15464
  }
15333
- recordAuthorizedScope(authorization.attribution.scope);
15334
- const result = await baseResolver({
15335
- ...request,
15336
- connectionUseContext: credentialUseContext,
15337
- connectionUseAuthority: authorization.attribution,
15338
- connectionRef: {
15339
- ...request.connectionRef,
15340
- connectionId: authorization.attribution.connectionId,
15341
- kind: authorization.connectionKind,
15342
- subjectScope: authorization.attribution.scope === "workspace" ? "workspace" : "subject"
15343
- },
15344
- ...authorization.attribution.ownerSubjectId ? { subjectId: authorization.attribution.ownerSubjectId } : {}
15345
- });
15346
- return withProviderRequestAuthorization(result, authorization.attribution);
15465
+ return withProviderRequestAuthorization(result);
15347
15466
  };
15348
15467
  }
15349
15468
  function isGitHubApiDestination(value) {
@@ -15355,6 +15474,100 @@ function isGitHubApiDestination(value) {
15355
15474
  }
15356
15475
  }
15357
15476
 
15477
+ // src/activities/mcp-account-routes.ts
15478
+ function accountRouteAuthNeededPayload(payload, bindings) {
15479
+ const binding = bindings?.find((candidate) => candidate.serverId === payload.serverId);
15480
+ return binding ? {
15481
+ ...payload,
15482
+ canonicalServerId: binding.canonicalServerId,
15483
+ connectionSubjectScope: binding.subjectScope
15484
+ } : payload;
15485
+ }
15486
+ function expandMcpAccountRoutes(input) {
15487
+ if (input.bindings == null) {
15488
+ return { settings: input.settings, tools: input.tools, accountLabels: /* @__PURE__ */ new Map() };
15489
+ }
15490
+ const configured = new Map(input.settings.mcpServers.map((server) => [server.id, server]));
15491
+ const byCanonical = /* @__PURE__ */ new Map();
15492
+ const routes = /* @__PURE__ */ new Set();
15493
+ const accounts = /* @__PURE__ */ new Set();
15494
+ for (const binding of input.bindings) {
15495
+ const account = JSON.stringify([binding.canonicalServerId, binding.connectionId]);
15496
+ if (routes.has(binding.serverId) || accounts.has(account) || configured.has(binding.serverId) || binding.subjectScope === "subject" !== (binding.ownerSubjectId !== null) || binding.connectionRef.authoritySource === "host" || binding.connectionRef.connectionId !== binding.connectionId || binding.connectionRef.subjectScope !== binding.subjectScope || binding.connectionRef.providerDomain !== binding.providerDomain || binding.connectionRef.kind !== binding.kind) {
15497
+ throw new Error("Invalid accepted MCP account route");
15498
+ }
15499
+ routes.add(binding.serverId);
15500
+ accounts.add(account);
15501
+ const siblings = byCanonical.get(binding.canonicalServerId) ?? [];
15502
+ siblings.push(binding);
15503
+ byCanonical.set(binding.canonicalServerId, siblings);
15504
+ }
15505
+ const servers = [];
15506
+ const tools = [];
15507
+ const accountLabels = /* @__PURE__ */ new Map();
15508
+ for (const tool of input.tools) {
15509
+ const bindings = byCanonical.get(tool.id);
15510
+ if (!bindings) {
15511
+ if (!configured.get(tool.id)?.connectionRef) tools.push(tool);
15512
+ continue;
15513
+ }
15514
+ const canonical = configured.get(tool.id);
15515
+ if (!canonical?.connectionRef) {
15516
+ throw new Error("Accepted MCP account route has no canonical connection configuration");
15517
+ }
15518
+ for (const binding of bindings) {
15519
+ if (canonical.connectionRef.authoritySource === "host" || canonical.connectionRef.providerDomain !== binding.providerDomain || canonical.connectionRef.kind && canonical.connectionRef.kind !== binding.kind) {
15520
+ throw new Error("Accepted MCP account route does not match canonical provider");
15521
+ }
15522
+ const { headers: _headers, ...config2 } = canonical;
15523
+ const label = `${canonical.name ?? canonical.id} \u2014 ${binding.subjectScope === "subject" ? "Personal" : "Workspace"}: ${binding.accountLabel}`;
15524
+ servers.push({
15525
+ ...config2,
15526
+ id: binding.serverId,
15527
+ name: label,
15528
+ connectionRef: structuredClone(binding.connectionRef)
15529
+ });
15530
+ tools.push({ ...tool, id: binding.serverId });
15531
+ accountLabels.set(binding.serverId, label);
15532
+ }
15533
+ }
15534
+ return {
15535
+ settings: {
15536
+ ...input.settings,
15537
+ mcpServers: [
15538
+ ...input.settings.mcpServers.filter((server) => !server.connectionRef),
15539
+ ...servers
15540
+ ]
15541
+ },
15542
+ tools,
15543
+ accountLabels
15544
+ };
15545
+ }
15546
+ function expandApiIntegrationAccountRoutes(input) {
15547
+ const selected = new Set(input.tools.map((tool) => tool.id));
15548
+ if (input.bindings == null)
15549
+ return input.integrations.filter((item) => selected.has(item.serverId));
15550
+ const acceptedBindings = input.bindings;
15551
+ return input.integrations.flatMap((integration) => {
15552
+ const bindings = acceptedBindings.filter(
15553
+ (binding) => binding.canonicalServerId === integration.serverId
15554
+ );
15555
+ if (bindings.length === 0)
15556
+ return !integration.connectionRef && selected.has(integration.serverId) ? [integration] : [];
15557
+ return bindings.filter((binding) => selected.has(binding.serverId)).map((binding) => {
15558
+ if (binding.connectionAuthorityGeneration === void 0) {
15559
+ throw new Error("Accepted API integration account route has no authority generation");
15560
+ }
15561
+ return {
15562
+ ...integration,
15563
+ serverId: binding.serverId,
15564
+ connectionRef: structuredClone(binding.connectionRef),
15565
+ connectionAuthorityGeneration: binding.connectionAuthorityGeneration
15566
+ };
15567
+ });
15568
+ });
15569
+ }
15570
+
15358
15571
  // src/activities/agent-turn/tool-environment.ts
15359
15572
  import { createMcpOperationPersistence } from "@opengeni/db/mcp-operations";
15360
15573
 
@@ -30486,7 +30699,7 @@ function exactPersonalDelegation(delegations) {
30486
30699
  (delegation2) => delegation2.serverId === PERSONAL_GITHUB_DELEGATION_SERVER_ID && delegation2.connectionType === "github_personal"
30487
30700
  );
30488
30701
  const delegation = matches[0];
30489
- if (matches.length !== 1 || !delegation || delegation.providerDomain !== "github.com" || delegation.kind !== "oauth2" || !delegation.originWorkspaceId || !delegation.userDelegation || !delegation.personalGitHubRepositorySelection) {
30702
+ if (matches.length !== 1 || !delegation || delegation.providerDomain !== "github.com" || delegation.kind !== "oauth2" || !delegation.originWorkspaceId || !delegation.personalGitHubRepositorySelection) {
30490
30703
  throw new GitHubRestAuthorityError("Personal GitHub delegation is unavailable");
30491
30704
  }
30492
30705
  return delegation;
@@ -30686,7 +30899,7 @@ async function materializeConnectorAttachmentsInChannel(channel, request, option
30686
30899
  }
30687
30900
 
30688
30901
  // src/activities/agent-turn/tool-environment.ts
30689
- import { allowedFirstPartyMcpToolsForSession as allowedFirstPartyMcpToolsForSession2 } from "@opengeni/config";
30902
+ import { allowedFirstPartyMcpToolsForSession } from "@opengeni/config";
30690
30903
 
30691
30904
  // src/activities/codemode-dispatcher.ts
30692
30905
  import { randomUUID as randomUUID3 } from "crypto";
@@ -31080,7 +31293,7 @@ function safeErrorMessage(error51) {
31080
31293
  // src/activities/agent-turn/tool-environment.ts
31081
31294
  import { CODEX_CLIENT_VERSION } from "@opengeni/codex";
31082
31295
  import {
31083
- defaultSessionMcpServerIds,
31296
+ workspaceSessionToolPolicyDefaultServerIds,
31084
31297
  loadRigDefaultVariableSetEnvironment,
31085
31298
  mergeRigDefaultVariableSetEnvironment,
31086
31299
  buildApiIntegrationMcpServers,
@@ -31093,24 +31306,9 @@ import {
31093
31306
  import { SandboxChannelAService as SandboxChannelAService3 } from "@opengeni/runtime/sandbox";
31094
31307
  import { sandboxRunAs as sandboxRunAs4 } from "@opengeni/runtime";
31095
31308
  import {
31096
- DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS3
31309
+ DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2
31097
31310
  } from "@opengeni/contracts";
31098
31311
 
31099
- // src/activities/agent-turn/turn-sandbox-access.ts
31100
- async function resolveTurnSandboxAccess(sandboxState, sdkOwnedSandboxSession, unavailableMessage) {
31101
- let sandbox = sandboxState.resolvedSandbox;
31102
- if (!sandbox && sandboxState.turnSandboxProvisioner) {
31103
- sandbox = await sandboxState.turnSandboxProvisioner.get();
31104
- }
31105
- const session = sandboxState.lazyOwnedSandbox?.session ?? sandbox?.established.session ?? sdkOwnedSandboxSession;
31106
- if (!session) throw new Error(unavailableMessage);
31107
- return {
31108
- sandbox,
31109
- session,
31110
- leaseEpoch: sandbox?.leaseEpoch ?? 0
31111
- };
31112
- }
31113
-
31114
31312
  // src/activities/agent-turn/list-models.ts
31115
31313
  import {
31116
31314
  compareModelPickerOrder,
@@ -31204,7 +31402,8 @@ import {
31204
31402
  portableSkillPluginKey,
31205
31403
  readSkill,
31206
31404
  resolveSkillImport,
31207
- saveSkill
31405
+ saveSkill,
31406
+ removeSkill
31208
31407
  } from "@opengeni/core";
31209
31408
  import {
31210
31409
  buildPortableSkillArtifact as buildPortableSkillArtifact3,
@@ -31369,7 +31568,7 @@ function createSkillSaveAttemptToolDefinition(input) {
31369
31568
  modelName: "skill_save",
31370
31569
  codemodePath: ["opengeni", "skill_save"],
31371
31570
  title: "Save Skill text",
31372
- description: "Create or edit a workspace Skill without a sandbox. Supply only changed UTF-8 text files and explicit deletions; omitted files are preserved. Use the revision and scope version returned by Skill discovery for stale-write protection. For creation choose a new UUID, set expectedRevisionId to null and expectedScopeVersion to 1. The effective Skills setting governs publication: Automatic publishes, Review first saves a pending revision in Knowledge > Needs review while the task continues, and Off prevents agent authoring. Report the actual receipt without asking an approval question. Private chats save personal Skills; shared chats save workspace Skills.",
31571
+ description: "Create or edit a Skill for reusable procedures or context-specific and personal behavioral preferences, not retrieval-only facts. Put its applicability in the SKILL.md description so the prompt index can guide skill_read; the full body is loaded when relevant. Short always-on workspace rules use instruction_policy_save. Supply only changed UTF-8 text files and explicit deletions; omitted files are preserved. No sandbox is needed. Use the revision and scope version returned by Skill discovery for stale-write protection. For creation choose a new UUID, set expectedRevisionId to null and expectedScopeVersion to 1. The effective Skills setting governs publication: Automatic publishes, Review first saves a pending revision in Knowledge > Needs review while the task continues, and Off prevents agent authoring. Report the actual receipt without asking an approval question. Private chats save personal Skills; shared chats save workspace Skills. Preserve the intended scope; another destination is not a workaround for unavailable scope or learning restrictions.",
31373
31572
  inputSchema: {
31374
31573
  type: "object",
31375
31574
  properties: {
@@ -31492,6 +31691,43 @@ function createSkillInstallAttemptToolDefinition(input) {
31492
31691
  };
31493
31692
  }
31494
31693
 
31694
+ // src/activities/agent-turn/skill-remove.ts
31695
+ var SkillRemoveRequest = external_exports.object({
31696
+ operationId: external_exports.uuid(),
31697
+ skillId: external_exports.uuid(),
31698
+ expectedRevisionId: external_exports.uuid().nullable(),
31699
+ expectedScopeVersion: external_exports.number().int().positive(),
31700
+ reason: external_exports.string().min(1).max(2e3)
31701
+ }).strict();
31702
+ function createSkillRemoveAttemptToolDefinition(input) {
31703
+ return {
31704
+ identity: { serverId: "opengeni", toolName: "skill_remove" },
31705
+ modelName: "skill_remove",
31706
+ codemodePath: ["opengeni", "skill_remove"],
31707
+ title: "Permanently remove Skill",
31708
+ description: "Permanently delete a saved Skill and ALL its stored revisions, not a recoverable hide. Conversations remain unchanged. Read the exact Skill first; supply its current active revision and scope version. Built-in, repository and inline session Skills cannot be removed. Automatic applies deletion; Review first retains an explicitly labeled deletion proposal for human review in Knowledge > Needs review; Off refuses changes. Reuse the same operationId and exact arguments after an uncertain result. Never report a pending proposal as deleted.",
31709
+ inputSchema: JSON.parse(JSON.stringify(external_exports.toJSONSchema(SkillRemoveRequest))),
31710
+ annotations: {
31711
+ readOnlyHint: false,
31712
+ destructiveHint: true,
31713
+ idempotentHint: true,
31714
+ openWorldHint: false
31715
+ },
31716
+ source: "opengeni",
31717
+ approval: "none",
31718
+ execute: async (args) => {
31719
+ await input.authorize();
31720
+ const output = await input.remove(SkillRemoveRequest.parse(args));
31721
+ const text = JSON.stringify(output);
31722
+ return {
31723
+ isError: false,
31724
+ content: [{ type: "text", text }],
31725
+ structuredContent: JSON.parse(text)
31726
+ };
31727
+ }
31728
+ };
31729
+ }
31730
+
31495
31731
  // src/activities/agent-turn/skill-transfer.ts
31496
31732
  import { posix } from "path";
31497
31733
  import {
@@ -31768,6 +32004,12 @@ function createWorkspaceSkillTools(input) {
31768
32004
  );
31769
32005
  };
31770
32006
  return [
32007
+ createSkillRemoveAttemptToolDefinition({
32008
+ authorize,
32009
+ remove: async (request) => withReviewState(
32010
+ await removeSkill(input.db, { ...context, ...request, actor: input.actor })
32011
+ )
32012
+ }),
31771
32013
  createSkillReadAttemptToolDefinition({ authorize, load }),
31772
32014
  createSkillSearchAttemptToolDefinition({
31773
32015
  authorize,
@@ -31784,7 +32026,7 @@ function createWorkspaceSkillTools(input) {
31784
32026
  id: entry.id,
31785
32027
  name: entry.artifact.name,
31786
32028
  description: entry.artifact.description || entry.artifact.name,
31787
- source: entry.id.startsWith("builtin:") ? "builtin" : entry.id.startsWith("session:") ? "session" : "pack"
32029
+ source: entry.id.startsWith("builtin:") ? "builtin" : "session"
31788
32030
  }))
31789
32031
  ],
31790
32032
  publicSearch: createPublicSkillSearchClient(input.settings)
@@ -31904,6 +32146,8 @@ function configuredBundledSkillNames(context) {
31904
32146
  const tools = new Set(context.firstPartyTools);
31905
32147
  const artifacts = () => tools.has("editable_artifact_list") && tools.has("editable_artifact_get");
31906
32148
  const definitions = [
32149
+ { name: "opengeni-help", include: () => true },
32150
+ { name: "opengeni-client", include: () => true },
31907
32151
  { name: "opengeni-visualize", include: () => true },
31908
32152
  { name: "document-parsing", include: () => true },
31909
32153
  { name: "opengeni-skills", include: () => true },
@@ -31962,7 +32206,12 @@ async function prepareTurnToolPolicy(deps) {
31962
32206
  toolPolicy: session.toolPolicy,
31963
32207
  sessionTools: scheduledEffectiveMcpServerIds ? turn.tools : session.tools,
31964
32208
  availableMcpServerIds: scheduledEffectiveMcpServerIds ? scheduledEffectiveMcpServerIds.filter((id) => currentMcpServerIds.has(id)) : [...currentMcpServerIds],
31965
- defaultMcpServerIds: scheduledEffectiveMcpServerIds ?? defaultSessionMcpServerIds(capabilitySettings.mcpServers)
32209
+ defaultMcpServerIds: scheduledEffectiveMcpServerIds ?? (session.toolPolicy.mode === "workspace_default" ? await workspaceSessionToolPolicyDefaultServerIds(
32210
+ db,
32211
+ input.workspaceId,
32212
+ capabilitySettings,
32213
+ fileAuthoritySubjectId ?? void 0
32214
+ ) : [])
31966
32215
  });
31967
32216
  const mcpAvailabilityNote = unavailableMcpOperationalContext({
31968
32217
  droppedIds: resolvedToolPolicy.effectivePolicy.droppedIds,
@@ -32064,7 +32313,6 @@ async function prepareTurnToolRuntime(deps) {
32064
32313
  objectStorage,
32065
32314
  observability,
32066
32315
  cancellationSignal,
32067
- connectionCredentials,
32068
32316
  eventing,
32069
32317
  attempt,
32070
32318
  sandboxState,
@@ -32076,10 +32324,9 @@ async function prepareTurnToolRuntime(deps) {
32076
32324
  codexAppsCredentialId,
32077
32325
  turnExecutionPolicy,
32078
32326
  trigger,
32079
- runSettings,
32327
+ runSettings: canonicalRunSettings,
32080
32328
  lazyToolTransport,
32081
- turnTools,
32082
- hostCredentialRootSessionId,
32329
+ turnTools: canonicalTurnTools,
32083
32330
  sandboxArtifactRuntime,
32084
32331
  activeSandboxBackend,
32085
32332
  groupBoxBackend,
@@ -32091,21 +32338,25 @@ async function prepareTurnToolRuntime(deps) {
32091
32338
  throwIfWorkerShuttingDown,
32092
32339
  throwIfTurnCancelled
32093
32340
  } = deps;
32341
+ const accountRoutes = expandMcpAccountRoutes({
32342
+ settings: canonicalRunSettings,
32343
+ tools: canonicalTurnTools,
32344
+ bindings: turn.mcpAccountBindings
32345
+ });
32346
+ const runSettings = accountRoutes.settings;
32347
+ const turnTools = accountRoutes.tools;
32094
32348
  const toolContextPreparationStartedAt = performance.now();
32095
32349
  throwIfWorkerShuttingDown();
32096
32350
  throwIfTurnCancelled();
32097
- const mcpCredentialRootSessionId = connectionCredentials?.mcpCredentials && hostCredentialRootSessionId ? hostCredentialRootSessionId : input.sessionId;
32098
32351
  const rawResolveCredential = connectionTokenResolverForTurn({
32099
32352
  db,
32100
32353
  settings: runSettings,
32101
- connectionCredentials: connectionCredentials ?? null,
32354
+ canonicalMcpServerIds: canonicalRunSettings.mcpServers.filter((server) => server.connectionRef).map((server) => server.id),
32102
32355
  accountId: input.accountId,
32103
32356
  workspaceId: input.workspaceId,
32104
32357
  sessionId: input.sessionId,
32105
- rootSessionId: mcpCredentialRootSessionId,
32106
32358
  attemptId: input.attemptId,
32107
- turn,
32108
- observability
32359
+ turn
32109
32360
  });
32110
32361
  const personalConnectionDelegations = turn.personalConnectionDelegations;
32111
32362
  const delegatedMembershipChecks = /* @__PURE__ */ new Map();
@@ -32163,16 +32414,24 @@ async function prepareTurnToolRuntime(deps) {
32163
32414
  return;
32164
32415
  }
32165
32416
  await eventing.publish(
32166
- [{ type: "tool.auth_needed", payload: rollingSafeToolAuthNeededPayload(payload) }],
32417
+ [
32418
+ {
32419
+ type: "tool.auth_needed",
32420
+ payload: rollingSafeToolAuthNeededPayload(
32421
+ accountRouteAuthNeededPayload(payload, turn.mcpAccountBindings)
32422
+ )
32423
+ }
32424
+ ],
32167
32425
  true
32168
32426
  );
32169
32427
  };
32170
- const selectedApiIntegrationServerIds = new Set(turnTools.map((tool) => tool.id));
32171
32428
  const apiIntegrationMcpServers = buildApiIntegrationMcpServers({
32172
32429
  settings: runSettings,
32173
- integrations: installedApiIntegrations.filter(
32174
- (integration) => selectedApiIntegrationServerIds.has(integration.serverId)
32175
- ),
32430
+ integrations: expandApiIntegrationAccountRoutes({
32431
+ integrations: installedApiIntegrations,
32432
+ bindings: turn.mcpAccountBindings,
32433
+ tools: turnTools
32434
+ }),
32176
32435
  authority: {
32177
32436
  accountId: input.accountId,
32178
32437
  workspaceId: input.workspaceId,
@@ -32230,10 +32489,10 @@ async function prepareTurnToolRuntime(deps) {
32230
32489
  );
32231
32490
  if (linkedAuthority && !linkedAuthority.authorized)
32232
32491
  throw new Error("Native identity link was revoked");
32233
- const effectiveFirstPartyPermissions = linkedAuthority ? (session.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS3).filter(
32492
+ const effectiveFirstPartyPermissions = linkedAuthority ? (session.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2).filter(
32234
32493
  (permission) => hasPermission2(linkedAuthority.permissions, permission)
32235
32494
  ) : session.firstPartyMcpPermissions;
32236
- const selectedFirstPartyMcpTools = allowedFirstPartyMcpToolsForSession2(
32495
+ const selectedFirstPartyMcpTools = allowedFirstPartyMcpToolsForSession(
32237
32496
  runSettings,
32238
32497
  session.firstPartyMcpTools
32239
32498
  );
@@ -32249,10 +32508,10 @@ async function prepareTurnToolRuntime(deps) {
32249
32508
  parallelGenerationAvailable: typeof runtime.generateSessionTitle === "function"
32250
32509
  });
32251
32510
  const googleDrivePublicationAllowed = selectedFirstPartyMcpTools.includes("editable_artifact_export") && selectedFirstPartyMcpTools.includes("editable_artifact_export_status") && hasPermission2(
32252
- [...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS3],
32511
+ [...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2],
32253
32512
  "artifacts:read"
32254
32513
  ) && hasPermission2(
32255
- [...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS3],
32514
+ [...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2],
32256
32515
  "artifacts:publish"
32257
32516
  );
32258
32517
  const googleDriveConnectorBindings = googleDrivePublicationTool && googleDrivePublicationTarget && googleDrivePublicationAllowed ? [
@@ -32289,7 +32548,6 @@ async function prepareTurnToolRuntime(deps) {
32289
32548
  });
32290
32549
  const selectedSkills = [
32291
32550
  ...bundledSkills,
32292
- ...deps.selectedSkillActivations.map((entry) => ({ id: entry.id, artifact: entry.artifact })),
32293
32551
  ...session.skills.map((skill) => ({
32294
32552
  id: `session:${session.id}:${skill.name}`,
32295
32553
  artifact: skill
@@ -32391,7 +32649,7 @@ async function prepareTurnToolRuntime(deps) {
32391
32649
  assertAttempt: async () => {
32392
32650
  throwIfWorkerShuttingDown();
32393
32651
  throwIfTurnCancelled();
32394
- const current = await getSessionTurnForAttempt2(
32652
+ const current = await getSessionTurnForAttempt(
32395
32653
  db,
32396
32654
  input.workspaceId,
32397
32655
  input.sessionId,
@@ -32597,6 +32855,7 @@ async function prepareTurnToolRuntime(deps) {
32597
32855
  try {
32598
32856
  eventing.preparedTools = await waitForTurnOperation(
32599
32857
  runtime.prepareTools(githubRestMcp.settings, githubRestMcp.tools, {
32858
+ mcpAccountLabels: accountRoutes.accountLabels,
32600
32859
  accountId: input.accountId,
32601
32860
  workspaceId: input.workspaceId,
32602
32861
  sessionId: input.sessionId,
@@ -32614,7 +32873,7 @@ async function prepareTurnToolRuntime(deps) {
32614
32873
  ...operationPersistence ? { mcpOperationPersistence: operationPersistence } : {},
32615
32874
  ...linkedAuthority ? {
32616
32875
  authorizeAttemptExecution: async () => {
32617
- const current = await getSessionTurnForAttempt2(
32876
+ const current = await getSessionTurnForAttempt(
32618
32877
  db,
32619
32878
  input.workspaceId,
32620
32879
  input.sessionId,
@@ -32636,13 +32895,10 @@ async function prepareTurnToolRuntime(deps) {
32636
32895
  localMcpServers,
32637
32896
  ...deferNonEagerToolPreparation ? { deferNonEagerUntilToolDemand: true } : {},
32638
32897
  onPreparationPhase: (measurement) => {
32639
- recordTurnStartupPhase(observability, {
32640
- phase: `tool_${measurement.phase}`,
32898
+ recordToolPreparationPhase(observability, {
32899
+ ...measurement,
32641
32900
  provider: turnExecutionPolicy.providerId,
32642
- backend: activeSandboxBackend ?? groupBoxBackend,
32643
- outcome: measurement.outcome,
32644
- durationSeconds: measurement.durationSeconds,
32645
- count: githubRestMcp.tools.length
32901
+ backend: activeSandboxBackend ?? groupBoxBackend
32646
32902
  });
32647
32903
  },
32648
32904
  onAttemptToolCatalog: async (catalog) => {
@@ -32920,7 +33176,9 @@ import {
32920
33176
  getWorkspaceVideoGenerationPolicy as getWorkspaceVideoGenerationPolicy2,
32921
33177
  loadWorkspaceVercelAiGatewayCredentialLease,
32922
33178
  getExternalLinkTurnAuthorization as getExternalLinkTurnAuthorization2,
32923
- getSessionTurnForAttempt as getSessionTurnForAttempt3
33179
+ getSessionTurnForAttempt as getSessionTurnForAttempt2,
33180
+ ensureSessionReasoningConfiguration,
33181
+ ensureSessionSkillCatalog
32924
33182
  } from "@opengeni/db";
32925
33183
  import {
32926
33184
  formatSkillCatalog
@@ -32931,6 +33189,7 @@ import {
32931
33189
  WORKSPACE_GATEWAY_PROVIDER_ID as WORKSPACE_GATEWAY_PROVIDER_ID2,
32932
33190
  resolveModelProvider as resolveModelProvider2
32933
33191
  } from "@opengeni/config";
33192
+ import { supportsReasoningConfiguration as supportsReasoningConfiguration2 } from "@opengeni/codex";
32934
33193
 
32935
33194
  // src/activities/xai-image-generation.ts
32936
33195
  import {
@@ -34144,6 +34403,11 @@ async function buildTurnAgent(deps) {
34144
34403
  codexContext
34145
34404
  } = deps;
34146
34405
  const preparedTools = eventing.preparedTools;
34406
+ const sessionInstructions = await recoveryAwareSessionInstructions(
34407
+ db,
34408
+ input.workspaceId,
34409
+ session
34410
+ );
34147
34411
  const missingSessionTitleHint = preparationIndependentToolNames.includes(
34148
34412
  SESSION_TITLE_MODEL_TOOL_NAME
34149
34413
  );
@@ -34455,7 +34719,15 @@ async function buildTurnAgent(deps) {
34455
34719
  turnExecutionPolicy.latencyMode
34456
34720
  );
34457
34721
  const approvedToolCallId = approvedConnectorActionCallId(trigger);
34458
- const modelVisibleSkillCatalogText = formatSkillCatalog(deps.skillCatalog);
34722
+ const modelVisibleSkillCatalogText = await ensureSessionSkillCatalog(db, {
34723
+ accountId: input.accountId,
34724
+ workspaceId: input.workspaceId,
34725
+ sessionId: input.sessionId,
34726
+ turnId: turn.id,
34727
+ expectedExecutionGeneration: turn.executionGeneration,
34728
+ expectedAttemptId: input.attemptId,
34729
+ catalog: formatSkillCatalog(deps.skillCatalog)
34730
+ });
34459
34731
  try {
34460
34732
  eventing.companyBrainContextContributions = summarizeCompanyBrainContributions(
34461
34733
  buildCompanyBrainContributionReceiptFor(modelVisibleSkillCatalogText)
@@ -34479,6 +34751,16 @@ async function buildTurnAgent(deps) {
34479
34751
  );
34480
34752
  if (linkedToolAuthority && !linkedToolAuthority.authorized)
34481
34753
  throw new Error("Native identity link was revoked");
34754
+ const useReasoningUpdates = eventing.modelRunSettings.reasoningConfigurationUpdatesEnabled && resolvedModel?.provider.api === "responses" && (resolvedModel.provider.id === "codex" || resolvedModel.provider.id === "openai") && supportsReasoningConfiguration2(turnExecutionPolicy.upstreamModelId, turn.reasoningEffort);
34755
+ const requestReasoningEffort = useReasoningUpdates && supportsReasoningConfiguration2(turnExecutionPolicy.upstreamModelId, turn.reasoningEffort) ? await ensureSessionReasoningConfiguration(db, {
34756
+ accountId: input.accountId,
34757
+ workspaceId: input.workspaceId,
34758
+ sessionId: input.sessionId,
34759
+ turnId: turn.id,
34760
+ expectedExecutionGeneration: turn.executionGeneration,
34761
+ expectedAttemptId: input.attemptId,
34762
+ effort: turn.reasoningEffort
34763
+ }) : turn.reasoningEffort;
34482
34764
  const agent = (() => {
34483
34765
  const agentConstructionStartedAt = performance.now();
34484
34766
  let agentConstructionOutcome = "completed";
@@ -34486,7 +34768,7 @@ async function buildTurnAgent(deps) {
34486
34768
  return runtime.buildAgent(eventing.modelRunSettings, runtimeResources, {
34487
34769
  ...linkedToolAuthority ? {
34488
34770
  authorizeAttemptExecution: async () => {
34489
- const current = await getSessionTurnForAttempt3(
34771
+ const current = await getSessionTurnForAttempt2(
34490
34772
  db,
34491
34773
  input.workspaceId,
34492
34774
  input.sessionId,
@@ -34497,7 +34779,7 @@ async function buildTurnAgent(deps) {
34497
34779
  }
34498
34780
  } : {},
34499
34781
  ...preparedTools.inputWaitYield ? { inputWaitYield: preparedTools.inputWaitYield } : {},
34500
- reasoningEffort: turn.reasoningEffort,
34782
+ reasoningEffort: requestReasoningEffort,
34501
34783
  latencyMode: turnExecutionPolicy.latencyMode,
34502
34784
  ...serviceTier ? { serviceTier } : {},
34503
34785
  ...humanInputResume ? { humanInputResponse: humanInputResume } : {},
@@ -34582,13 +34864,14 @@ async function buildTurnAgent(deps) {
34582
34864
  ),
34583
34865
  onRetainableSessionImageOutput: media.retainSessionImageAtToolBoundary,
34584
34866
  skillCatalog: deps.skillCatalog,
34867
+ skillCatalogInHistory: true,
34585
34868
  ...!structuredWorkspacePolicyActive && workspaceAgentInstructions ? { instructionsTemplate: workspaceAgentInstructions } : {},
34586
34869
  ...workspaceGovernance ? { workspaceGovernance } : {},
34587
34870
  ...workspaceMemory ? { workspaceMemory } : {},
34588
34871
  // Per-session persona tier (session > workspace > deployment default).
34589
34872
  // Composed system-level AFTER the workspace persona so it refines it for
34590
34873
  // this one session; absent ⇒ byte-identical to today's composition.
34591
- ...session.instructions ? { sessionInstructions: session.instructions } : {},
34874
+ ...sessionInstructions ? { sessionInstructions } : {},
34592
34875
  ...workspaceEnvironmentOption,
34593
34876
  // RIG RUNTIME (M3): the doctrine block, the setup-script hook (only when
34594
34877
  // the frozen version carries a non-empty script), and the rig credential
@@ -34687,7 +34970,7 @@ function createRunAgentTurnActivity(services) {
34687
34970
  });
34688
34971
  const modelCheckpointMemoryCollector = createModelCheckpointMemoryCollector();
34689
34972
  const turnCompletionMemoryCollector = createModelCheckpointMemoryCollector();
34690
- return async function runAgentTurn(input) {
34973
+ const runAgentTurn = async (input, resolvedServices, activitySpan) => {
34691
34974
  const {
34692
34975
  settings,
34693
34976
  catalogSourceSettings = settings,
@@ -34704,7 +34987,7 @@ function createRunAgentTurnActivity(services) {
34704
34987
  connectionCredentials,
34705
34988
  personalGitHubCredentials,
34706
34989
  startVideoGenerationWorkflow
34707
- } = await services();
34990
+ } = resolvedServices;
34708
34991
  const activityContext = currentActivityContext();
34709
34992
  const cancellationSignal = activityContext?.cancellationSignal;
34710
34993
  const sandboxResumeController = new AbortController();
@@ -34732,11 +35015,6 @@ function createRunAgentTurnActivity(services) {
34732
35015
  });
34733
35016
  const dispatchId = activityContext?.info.activityId ?? randomUUID6();
34734
35017
  const activityStarted = performance.now();
34735
- const activitySpan = observability.startSpan("worker.run_agent_segment", {
34736
- "opengeni.session_id": input.sessionId,
34737
- "opengeni.workflow_id": input.workflowId,
34738
- "opengeni.trigger_kind": input.trigger.kind
34739
- });
34740
35018
  const acknowledgeLostAttemptOwnership = () => {
34741
35019
  control.acknowledgeQuiescence = true;
34742
35020
  noteCancellationRequested();
@@ -34757,7 +35035,7 @@ function createRunAgentTurnActivity(services) {
34757
35035
  const machineOpObserver = makeMachineOpObserver(
34758
35036
  runtimeMetricsHooksForObservability(observability)
34759
35037
  );
34760
- const sandboxOperationObserver = sandboxOperationMetricObserver(observability);
35038
+ const sandboxOperationObserver = sandboxOperationMetricObserver2(observability);
34761
35039
  const setLastInputTokensFenced = async (lastInputTokens) => {
34762
35040
  if (!attempt.turnId || attempt.executionGeneration <= 0) {
34763
35041
  throw new Error("Turn attempt was not initialized before token accounting");
@@ -34918,8 +35196,26 @@ function createRunAgentTurnActivity(services) {
34918
35196
  executionGeneration: attempt.executionGeneration
34919
35197
  }
34920
35198
  });
35199
+ const attachmentAuthority = await getSessionAuthorityProjection(
35200
+ db,
35201
+ input.workspaceId,
35202
+ input.sessionId
35203
+ );
35204
+ if (!attachmentAuthority) throw new Error("Session attachment authority unavailable");
34921
35205
  return await withSessionRlsActorContext(
34922
35206
  {
35207
+ sessionAttachmentReadAccess: {
35208
+ sessionId: input.sessionId,
35209
+ authorityEpoch: attachmentAuthority.authorityEpoch,
35210
+ actor: {
35211
+ kind: "agent_attempt",
35212
+ subjectId: "service:agent-turn",
35213
+ callerSessionId: input.sessionId,
35214
+ turnId: attempt.turnId,
35215
+ attemptId: input.attemptId,
35216
+ executionGeneration: attempt.executionGeneration
35217
+ }
35218
+ },
34923
35219
  subjectId: "service:agent-turn",
34924
35220
  initiatingHumanSubjectId: fileAuthoritySubjectId,
34925
35221
  privateFileOwnerSubjectId: learning.defaultScope === "personal" ? learning.subjectId : null
@@ -34987,7 +35283,6 @@ function createRunAgentTurnActivity(services) {
34987
35283
  });
34988
35284
  const {
34989
35285
  runtimePreparationStartedAt,
34990
- packRuntime,
34991
35286
  rigVersion,
34992
35287
  rigName,
34993
35288
  agentHumanInputEnabled,
@@ -35017,7 +35312,13 @@ function createRunAgentTurnActivity(services) {
35017
35312
  db,
35018
35313
  runSettings,
35019
35314
  input.workspaceId,
35020
- providerTurn.effectiveCodexCredentialId ?? ""
35315
+ providerTurn.effectiveCodexCredentialId ?? "",
35316
+ void 0,
35317
+ {
35318
+ turnId: turn.id,
35319
+ holderId: leases.codex.holderId,
35320
+ generation: leases.codex.generation
35321
+ }
35021
35322
  );
35022
35323
  const resolveTrackedToken = async (resolve) => {
35023
35324
  const token = await resolve();
@@ -35408,38 +35709,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
35408
35709
  cancellationSignal?.throwIfAborted();
35409
35710
  knowledgeRecoveryNote = "[OpenGeni confirmation recovery unavailable] Do not assume an earlier remember confirmation was published. Inspect the current Knowledge or instruction review.";
35410
35711
  }
35411
- const attachmentPreparationNote = await prepareTurnKnowledgeSources({
35412
- settings: runSettings,
35413
- scope: {
35414
- accountId: input.accountId,
35415
- workspaceId: input.workspaceId,
35416
- sessionId: input.sessionId,
35417
- turnId: turn.id,
35418
- attemptId: input.attemptId,
35419
- executionGeneration: attempt.executionGeneration
35420
- },
35421
- // Only attachments on this accepted turn are new source inputs.
35422
- // Session-level file receipts remain historical context and must
35423
- // never trigger metadata reads, downloads, or re-preparation.
35424
- resources: turn.resources,
35425
- selectedTools: session.firstPartyMcpTools,
35426
- permissions: session.firstPartyMcpPermissions,
35427
- learningMode: learning.effective.knowledge,
35428
- signal: cancellationSignal,
35429
- onOutcome: async (outcome) => {
35430
- if (outcome.status === "disabled") return;
35431
- await eventing.publish(
35432
- [
35433
- {
35434
- type: outcome.status === "failed" ? "knowledge.source.failed" : "knowledge.source.prepared",
35435
- payload: outcome
35436
- }
35437
- ],
35438
- true
35439
- );
35440
- }
35441
- });
35442
- const knowledgeSourcePreparationNote = [knowledgeRecoveryNote, attachmentPreparationNote].filter(Boolean).join("\n\n") || void 0;
35712
+ const knowledgeSourcePreparationNote = knowledgeRecoveryNote;
35443
35713
  const sandboxRoute = await resolveSandboxRoute({
35444
35714
  input,
35445
35715
  settings,
@@ -35510,7 +35780,6 @@ These are publication receipts for the human's earlier answer. Do not call the r
35510
35780
  establishPolicy,
35511
35781
  initialRunCredentialMaterial,
35512
35782
  runCredentialsNote,
35513
- hostCredentialRootSessionId,
35514
35783
  codemodeAuthority,
35515
35784
  sandboxArtifactRuntime,
35516
35785
  sandboxEnvironment,
@@ -35628,7 +35897,6 @@ These are publication receipts for the human's earlier answer. Do not call the r
35628
35897
  ];
35629
35898
  const toolRuntime = await prepareTurnToolRuntime({
35630
35899
  fetchKnowledgeSource: sourceActivities.runKnowledgeSourceSyncBatch,
35631
- selectedSkillActivations: packRuntime.skillActivations,
35632
35900
  input,
35633
35901
  catalogSourceSettings,
35634
35902
  db,
@@ -35637,7 +35905,6 @@ These are publication receipts for the human's earlier answer. Do not call the r
35637
35905
  objectStorage,
35638
35906
  observability,
35639
35907
  cancellationSignal,
35640
- connectionCredentials,
35641
35908
  eventing,
35642
35909
  attempt,
35643
35910
  sandboxState,
@@ -35655,7 +35922,6 @@ These are publication receipts for the human's earlier answer. Do not call the r
35655
35922
  lazyToolTransport,
35656
35923
  turnTools,
35657
35924
  connectionScope,
35658
- hostCredentialRootSessionId,
35659
35925
  sandboxArtifactRuntime,
35660
35926
  activeSandboxBackend,
35661
35927
  groupBoxBackend,
@@ -36103,6 +36369,36 @@ These are publication receipts for the human's earlier answer. Do not call the r
36103
36369
  });
36104
36370
  }
36105
36371
  };
36372
+ return async (input) => {
36373
+ const resolvedServices = await services();
36374
+ const correlationId = turnExecutionTelemetryKey2(
36375
+ input.workspaceId,
36376
+ input.sessionId,
36377
+ input.attemptId
36378
+ );
36379
+ const span = resolvedServices.observability.startSpan(
36380
+ "worker.run_agent_segment",
36381
+ {
36382
+ "opengeni.trigger_kind": input.trigger.kind,
36383
+ correlationId
36384
+ },
36385
+ { parent: null }
36386
+ );
36387
+ try {
36388
+ return await withTraceContext(span, () => {
36389
+ try {
36390
+ resolvedServices.observability.info("worker execution started", { correlationId });
36391
+ } catch {
36392
+ }
36393
+ return runAgentTurn(input, resolvedServices, span);
36394
+ });
36395
+ } catch (error51) {
36396
+ span.end({ error: error51 });
36397
+ throw error51;
36398
+ } finally {
36399
+ span.end();
36400
+ }
36401
+ };
36106
36402
  }
36107
36403
 
36108
36404
  // src/activities/video-generation-reconciliation.ts
@@ -37202,4 +37498,4 @@ export {
37202
37498
  createTurnActivities,
37203
37499
  createTurnActivitiesFromServices
37204
37500
  };
37205
- //# sourceMappingURL=activities-turn-AP67JADS.js.map
37501
+ //# sourceMappingURL=activities-turn-2B3WMHBB.js.map