@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
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  observabilityEventLogger
3
- } from "./chunk-A4XQWVZK.js";
3
+ } from "./chunk-I7HKKMUJ.js";
4
4
 
5
5
  // src/activity-services.ts
6
6
  import { dbSearchPath, getSettings, resolveNatsControlPlaneAuth } from "@opengeni/config";
@@ -220,7 +220,7 @@ function exactPersonalGitHubDelegation(delegations, credentialBindingId) {
220
220
  (delegation2) => delegation2.serverId === PERSONAL_GITHUB_SERVER_ID && delegation2.connectionType === "github_personal" && delegation2.personalGitHubRepositorySelection?.credentialBindingId === credentialBindingId
221
221
  );
222
222
  const delegation = matches[0];
223
- if (matches.length !== 1 || !delegation || delegation.providerDomain !== "github.com" || delegation.kind !== "oauth2" || !delegation.originWorkspaceId || !delegation.userDelegation || !delegation.personalGitHubRepositorySelection) {
223
+ if (matches.length !== 1 || !delegation || delegation.providerDomain !== "github.com" || delegation.kind !== "oauth2" || !delegation.originWorkspaceId || !delegation.personalGitHubRepositorySelection) {
224
224
  throw new Error("personal GitHub Git delegation is unavailable");
225
225
  }
226
226
  return delegation;
@@ -246,7 +246,6 @@ function exactRequestedRepositories(refs, credentialBindingId, snapshots) {
246
246
  // src/pr-review-credentials.ts
247
247
  import { environmentsEncryptionKeyBytes } from "@opengeni/config";
248
248
  import { prReviewRegistrationIdFromCredentialBinding } from "@opengeni/core";
249
- import { createNativeRemoteMcpCredentialsPort } from "@opengeni/core/remote-mcp-credentials";
250
249
  import { decryptVariableSetValue, resolvePrReviewGitCredential } from "@opengeni/db";
251
250
  import {
252
251
  createGitHubAppInstallationTokenWithExpiry,
@@ -254,7 +253,6 @@ import {
254
253
  } from "@opengeni/github";
255
254
  function createStandaloneConnectionCredentialsPort(settings, db) {
256
255
  return {
257
- ...createNativeRemoteMcpCredentialsPort(settings, db),
258
256
  gitCredentials: async (request) => await resolveStandaloneGitCredentials(settings, db, request)
259
257
  };
260
258
  }
@@ -433,6 +431,7 @@ function createSharedActivityServices(dependencies) {
433
431
 
434
432
  // src/activities/codex-capacity.ts
435
433
  import {
434
+ connectionModelAllowed as connectionModelAllowed2,
436
435
  armCodexCapacityWait,
437
436
  fetchCodexUsageForAccount,
438
437
  getCodexCapacityWaitForSession,
@@ -571,8 +570,9 @@ async function refreshExhaustedXaiQuota(input) {
571
570
  }
572
571
 
573
572
  // src/activities/codex-rotation.ts
574
- function codexAccountNeedsLiveCapacityRefresh(account, now) {
575
- return (account.primaryUsedPercent ?? 0) >= CODEX_USAGE_EXHAUSTED_PCT || (account.secondaryUsedPercent ?? 0) >= CODEX_USAGE_EXHAUSTED_PCT || account.exhaustedKind === "quota" && account.exhaustedUntil !== null && account.exhaustedUntil > now;
573
+ import { connectionModelAllowed } from "@opengeni/db";
574
+ function codexAccountNeedsLiveCapacityRefresh(account, _now) {
575
+ return (account.primaryUsedPercent ?? 0) >= CODEX_USAGE_EXHAUSTED_PCT || (account.secondaryUsedPercent ?? 0) >= CODEX_USAGE_EXHAUSTED_PCT || account.exhaustedKind === "quota" && account.exhaustedUntil !== null;
576
576
  }
577
577
  function effectiveRotationStrategy(_stored) {
578
578
  return "sharded";
@@ -761,7 +761,13 @@ function chooseRotationActive(args) {
761
761
  return decide(chosen);
762
762
  }
763
763
  function selectCodexCredentialLeaseForTurn(args) {
764
- const { accounts, activeCredentialId, rotationEnabled, rotationStrategy, existingCredentialId } = args.context;
764
+ const { activeCredentialId, rotationEnabled, rotationStrategy, existingCredentialId } = args.context;
765
+ if (args.context.failoverExhausted) {
766
+ return { credentialId: null, decision: { kind: "none" }, advanceActivePointer: false };
767
+ }
768
+ const accounts = args.context.modelId ? args.context.accounts.filter(
769
+ (account) => connectionModelAllowed(account.allowedModelIds, args.context.modelId)
770
+ ) : args.context.accounts;
765
771
  const failedCredentialIds = new Set(args.context.failedCredentialIds ?? []);
766
772
  const strategy = effectiveRotationStrategy(rotationStrategy);
767
773
  const existing = existingCredentialId ? accounts.find((account) => account.id === existingCredentialId) : void 0;
@@ -787,6 +793,9 @@ function selectCodexCredentialLeaseForTurn(args) {
787
793
  if (!pinned) {
788
794
  return { credentialId: null, decision: { kind: "none" }, advanceActivePointer: false };
789
795
  }
796
+ if (failedCredentialIds.has(pinned.id)) {
797
+ return { credentialId: null, decision: { kind: "none" }, advanceActivePointer: false };
798
+ }
790
799
  if (!pinned.allocatorEnabled) {
791
800
  return {
792
801
  credentialId: null,
@@ -843,6 +852,9 @@ function selectCodexCredentialLeaseForTurn(args) {
843
852
  if (!active) {
844
853
  return { credentialId: null, decision: { kind: "none" }, advanceActivePointer: false };
845
854
  }
855
+ if (failedCredentialIds.has(active.id)) {
856
+ return { credentialId: null, decision: { kind: "none" }, advanceActivePointer: false };
857
+ }
846
858
  if (!active.allocatorEnabled) {
847
859
  return {
848
860
  credentialId: null,
@@ -910,8 +922,13 @@ async function signalPendingCodexCapacityWakeTargets(services, workspaceId) {
910
922
  );
911
923
  await signalCodexCapacityWakeTargets(services, targets);
912
924
  }
913
- function codexCapacityDecision(context) {
914
- const now = /* @__PURE__ */ new Date();
925
+ function codexCapacityDecision(context, now = /* @__PURE__ */ new Date()) {
926
+ context = {
927
+ ...context,
928
+ accounts: context.accounts.filter(
929
+ (account) => !context.modelId || connectionModelAllowed2(account.allowedModelIds, context.modelId)
930
+ )
931
+ };
915
932
  const selected = selectCodexCredentialLeaseForTurn({
916
933
  context,
917
934
  sessionId: context.sessionId,
@@ -928,7 +945,9 @@ function codexCapacityDecision(context) {
928
945
  credentialId: selected.credentialId,
929
946
  diagnostic: {
930
947
  connectedCount: context.accounts.length,
931
- eligibleCount: context.accounts.filter((account) => isCodexCredentialEligible(account, now)).length
948
+ eligibleCount: context.accounts.filter(
949
+ (account) => (account.id === selected.credentialId || !context.failedCredentialIds?.includes(account.id)) && isCodexCredentialEligible(account, now)
950
+ ).length
932
951
  }
933
952
  };
934
953
  }
@@ -936,7 +955,7 @@ function codexCapacityDecision(context) {
936
955
  const capacityAccounts = policyCredentialId ? context.accounts.filter((account) => account.id === policyCredentialId) : context.accounts;
937
956
  const authoritativeReset = authoritativeCodexCapacityResetAt(capacityAccounts, now);
938
957
  const hasReconcilableQuotaCooldown = capacityAccounts.some(
939
- (account) => account.status === "active" && account.allocatorEnabled && account.exhaustedKind === "quota" && account.exhaustedUntil !== null && account.exhaustedUntil > now
958
+ (account) => account.status === "active" && account.allocatorEnabled && account.exhaustedKind === "quota" && account.exhaustedUntil !== null
940
959
  );
941
960
  const policyAccount = capacityAccounts[0] ?? null;
942
961
  const mutationOnlyStatusBlock = policyAccount != null && (!policyAccount.allocatorEnabled || policyAccount.status !== "active") || authoritativeReset === null && capacityAccounts.length > 0 && capacityAccounts.every(
@@ -946,7 +965,7 @@ function codexCapacityDecision(context) {
946
965
  return {
947
966
  kind: "unavailable",
948
967
  earliestResetAt: authoritativeReset,
949
- resetKind: selected.decision.kind === "none" || selected.decision.kind === "allocatorDisabled" || mutationOnlyStatusBlock ? "mutation_only" : authoritativeReset && !hasReconcilableQuotaCooldown ? "authoritative" : "bounded_refresh",
968
+ resetKind: selected.decision.kind === "none" && !hasReconcilableQuotaCooldown && !authoritativeReset || selected.decision.kind === "allocatorDisabled" || mutationOnlyStatusBlock ? "mutation_only" : authoritativeReset && !hasReconcilableQuotaCooldown ? "authoritative" : "bounded_refresh",
950
969
  diagnostic: {
951
970
  connectedCount: context.accounts.length,
952
971
  allocatorEnabledCount: context.accounts.filter((account) => account.allocatorEnabled).length,
@@ -957,6 +976,16 @@ function codexCapacityDecision(context) {
957
976
  }
958
977
  async function armAndReconcileCodexCapacityWait(services, input, options = {}) {
959
978
  const armed = await armCodexCapacityWait(services.db, input);
979
+ if (armed.action === "stopped") {
980
+ options.onArmed?.();
981
+ await publishDurableSessionEvents(
982
+ services.bus,
983
+ input.workspaceId,
984
+ input.sessionId,
985
+ armed.events
986
+ );
987
+ return armed;
988
+ }
960
989
  if (armed.action !== "waiting") return armed;
961
990
  options.onArmed?.();
962
991
  await publishDurableSessionEvents(services.bus, input.workspaceId, input.sessionId, armed.events);
@@ -980,15 +1009,22 @@ async function armAndReconcileCodexCapacityWait(services, input, options = {}) {
980
1009
  );
981
1010
  return evaluated;
982
1011
  }
983
- async function refreshCapacityMetadata(services, workspaceId) {
984
- const accounts = await listCodexAccountStatuses(services.db, workspaceId).catch(() => []);
1012
+ async function refreshCapacityMetadata(services, workspaceId, turnId) {
1013
+ const accounts = await listCodexAccountStatuses(services.db, workspaceId, turnId).catch(() => []);
985
1014
  const now = /* @__PURE__ */ new Date();
986
1015
  const stale = accounts.filter(
987
1016
  (account) => account.allocatorEnabled && account.status === "active" && (codexAccountNeedsLiveCapacityRefresh(account, now) || account.usageCheckedAt === null)
988
1017
  );
989
1018
  await refreshCodexUsageAndRepairCapacityWaiters(
990
1019
  stale.map(
991
- (account) => () => fetchCodexUsageForAccount(services.db, services.settings, workspaceId, account.id)
1020
+ (account) => () => fetchCodexUsageForAccount(
1021
+ services.db,
1022
+ services.settings,
1023
+ workspaceId,
1024
+ account.id,
1025
+ void 0,
1026
+ turnId
1027
+ )
992
1028
  ),
993
1029
  () => signalPendingCodexCapacityWakeTargets(services, workspaceId)
994
1030
  );
@@ -1078,7 +1114,7 @@ function createCodexCapacityActivities(services) {
1078
1114
  }
1079
1115
  const boundedRefreshAttempted = current.resetKind === "bounded_refresh" && input.cause === "timer" && current.nextCheckAt.getTime() <= Date.now();
1080
1116
  if (boundedRefreshAttempted) {
1081
- await refreshCapacityMetadata(resolved, input.workspaceId);
1117
+ await refreshCapacityMetadata(resolved, input.workspaceId, current.blockedTurnId);
1082
1118
  }
1083
1119
  const result = await reconcileCodexCapacityWaitDb(
1084
1120
  resolved.db,
@@ -1427,6 +1463,7 @@ function goalContinuationPrompt(_goal, _autoContinuation, _cap, options = {}) {
1427
1463
  "- For every explicit requirement, named artifact, command, test, gate, invariant, and deliverable, identify and inspect the authoritative evidence that would prove it.",
1428
1464
  "- Match verification scope to requirement scope. Treat uncertain, indirect, incomplete, or missing evidence as not achieved and continue working.",
1429
1465
  "- The audit must prove completion, not merely fail to find obvious remaining work.",
1466
+ "- For user-facing report deliverables, including reports produced during another task, follow the Documents Skill: create the durable native document first, inspect its relevant final head after the last edit, and provide the returned artifact reference. Declare report requirements through the available goal tools before authoring and satisfy every persisted report requirement with verified artifact delivery evidence before completion. Sandbox paths and raw file IDs do not prove report delivery. If artifact tooling or access is unavailable, keep that deliverable incomplete and state the blocker; never invent proof or silently substitute a local report. Ordinary chat answers, short progress updates, source-code links, and explicitly requested local-file work remain outside this report contract.",
1430
1467
  "",
1431
1468
  "Do not rely on intent, partial progress, memory of earlier work, or a plausible final answer as proof of completion. Call opengeni__goal_complete with concrete evidence only when the full objective is actually achieved and no required work remains.",
1432
1469
  "",
@@ -4583,65 +4620,10 @@ var SyncFailure = class extends Error {
4583
4620
  import {
4584
4621
  resolveRigProviderImageSelection,
4585
4622
  rigProviderImageSourceImage,
4586
- settingsWithPackSandboxImage,
4587
4623
  settingsWithRigImage,
4588
4624
  settingsWithRigProviderImage
4589
4625
  } from "@opengeni/core";
4590
4626
 
4591
- // src/activities/packs.ts
4592
- import { getWorkspace, listInstalledPortableSkills } from "@opengeni/db";
4593
- import {
4594
- legacySandboxRuntimeFromPacks,
4595
- packInstallationUsesLegacyRuntime,
4596
- resolveWorkspaceLegacyRuntimePacks
4597
- } from "@opengeni/core";
4598
- import {
4599
- buildPortableSkillArtifact
4600
- } from "@opengeni/runtime";
4601
- var emptyPackRuntime = {
4602
- sandboxImage: null,
4603
- sandboxProviderImages: null,
4604
- skillActivations: []
4605
- };
4606
- async function resolveWorkspacePackRuntime(db, workspaceId) {
4607
- const packs = await resolveWorkspaceLegacyRuntimePacks(db, workspaceId);
4608
- if (packs.length === 0) return emptyPackRuntime;
4609
- return workspacePackRuntimeFromPacks(packs);
4610
- }
4611
- function workspacePackRuntimeFromPacks(packs) {
4612
- const sandboxRuntime = legacySandboxRuntimeFromPacks(packs);
4613
- const skillActivations = [];
4614
- const skillOwners = /* @__PURE__ */ new Map();
4615
- for (const pack of [...packs].sort((a, b) => a.id.localeCompare(b.id))) {
4616
- for (const skill of pack.skills) {
4617
- const key = skill.name.toLowerCase();
4618
- const existingOwner = skillOwners.get(key);
4619
- if (existingOwner !== void 0 && existingOwner !== pack.id) {
4620
- throw new Error(
4621
- `Enabled packs ${existingOwner} and ${pack.id} both declare a skill named "${skill.name}". Pack skill names must be unique across enabled packs; disable one of the packs and retry.`
4622
- );
4623
- }
4624
- skillOwners.set(key, pack.id);
4625
- const artifact = {
4626
- name: skill.name,
4627
- description: skill.description ?? null,
4628
- files: skill.files.map((file) => ({ path: file.path, content: file.content }))
4629
- };
4630
- skillActivations.push({
4631
- source: "pack",
4632
- id: `pack:${pack.id}:${skill.name}`,
4633
- artifact,
4634
- reason: `active legacy Pack ${pack.id}`
4635
- });
4636
- }
4637
- }
4638
- return {
4639
- sandboxImage: sandboxRuntime.sandboxImage,
4640
- sandboxProviderImages: sandboxRuntime.sandboxProviderImages,
4641
- skillActivations
4642
- };
4643
- }
4644
-
4645
4627
  // src/activities/streaming.ts
4646
4628
  import { TURN_ACTIVITY_CANCELLATION_HEARTBEAT_INTERVAL_MS } from "@opengeni/core";
4647
4629
  import { Context } from "@temporalio/activity";
@@ -4816,6 +4798,73 @@ async function nextStreamEvent(iterator, context) {
4816
4798
  });
4817
4799
  }
4818
4800
 
4801
+ // src/sandbox-snapshot-diagnostics.ts
4802
+ import { sandboxLeaseTelemetryKey } from "@opengeni/observability";
4803
+ function safeSnapshotError(error, origin = "sandbox-resume") {
4804
+ const fields = {
4805
+ errorClass: "SnapshotOperationError",
4806
+ errorCode: "snapshot_operation_failed",
4807
+ origin
4808
+ };
4809
+ try {
4810
+ if (error && typeof error === "object") {
4811
+ const candidate = error;
4812
+ if (typeof candidate.name === "string" && /^[A-Z][A-Za-z0-9]{2,62}Error$/u.test(candidate.name)) {
4813
+ fields.causeName = candidate.name;
4814
+ }
4815
+ if (typeof candidate.code === "string" && /^[a-z0-9_]{1,64}$/u.test(candidate.code)) {
4816
+ fields.integrityCode = candidate.code;
4817
+ }
4818
+ const status = Number(candidate.status ?? candidate.statusCode);
4819
+ if (Number.isInteger(status) && status >= 100 && status <= 599) fields.status = status;
4820
+ }
4821
+ } catch {
4822
+ }
4823
+ const read = (value, key) => {
4824
+ try {
4825
+ return value && typeof value === "object" ? Reflect.get(value, key) : void 0;
4826
+ } catch {
4827
+ return void 0;
4828
+ }
4829
+ };
4830
+ const details = read(error, "details");
4831
+ const providerName = read(details, "errorName");
4832
+ if (typeof providerName === "string" && [
4833
+ "ClientError",
4834
+ "TimeoutError",
4835
+ "ConnectionError",
4836
+ "AuthError",
4837
+ "NotFoundError",
4838
+ "InvalidError",
4839
+ "RemoteError",
4840
+ "AbortError"
4841
+ ].includes(providerName))
4842
+ fields.providerErrorName = providerName;
4843
+ const grpcCode = read(details, "errorCode");
4844
+ if (providerName === "ClientError" && typeof grpcCode === "number" && Number.isInteger(grpcCode) && grpcCode >= 0 && grpcCode <= 16)
4845
+ fields.providerGrpcCode = grpcCode;
4846
+ for (const key of ["status", "httpStatus", "responseStatus"]) {
4847
+ const status = read(details, key);
4848
+ if (typeof status === "number" && Number.isInteger(status) && status >= 100 && status <= 599) {
4849
+ fields.providerHttpStatus = status;
4850
+ break;
4851
+ }
4852
+ }
4853
+ const retryable = read(error, "retryable");
4854
+ if (typeof retryable === "boolean") fields.providerRetryable = retryable;
4855
+ return fields;
4856
+ }
4857
+ function warnDrainSnapshotFailure(observability, message, error, lease) {
4858
+ try {
4859
+ observability.warn(message, {
4860
+ ...safeSnapshotError(error, "worker-lifecycle"),
4861
+ ...lease.workspaceId ? { sandboxLeaseKey: sandboxLeaseTelemetryKey(lease.workspaceId, lease.sandboxGroupId) } : {},
4862
+ leaseEpoch: lease.leaseEpoch
4863
+ });
4864
+ } catch {
4865
+ }
4866
+ }
4867
+
4819
4868
  // src/sandbox-archive-storage.ts
4820
4869
  import { uploadWorkspaceArchiveSpool } from "@opengeni/storage";
4821
4870
  import { randomUUID as randomUUID2 } from "crypto";
@@ -4952,12 +5001,13 @@ async function deleteUnpublishedWorkspaceArchiveObject(objectStorage, ref, metri
4952
5001
  import { sandboxLifecycleTransitionWaitMs as sandboxLifecycleTransitionWaitMs2 } from "@opengeni/config";
4953
5002
  import {
4954
5003
  createProviderCommandRetainer,
4955
- retainedProviderCommandPersistence
5004
+ supervisedCommandProtocolReady
4956
5005
  } from "@opengeni/db/retained-provider-commands";
4957
5006
  import {
4958
5007
  adoptConnectedMachineSessionBackgroundCommand,
4959
5008
  adoptManagedSessionBackgroundCommand,
4960
5009
  advanceWorkspaceGenerationForRetainedProcess,
5010
+ retainedProviderCommandPersistence,
4961
5011
  advanceWorkspaceGeneration,
4962
5012
  getRetainedProcess,
4963
5013
  retainWorkspaceMutationProcess,
@@ -5002,6 +5052,15 @@ import {
5002
5052
  sandboxLifecycleTransitionWaitMs
5003
5053
  } from "@opengeni/config";
5004
5054
  import { randomUUID as randomUUID3 } from "crypto";
5055
+
5056
+ // src/warm-capture-holder.ts
5057
+ function retainsHolderForWarmCapture(lease, expectedEpoch, now = Date.now()) {
5058
+ return Boolean(
5059
+ lease?.liveness === "warm" && lease.leaseEpoch === expectedEpoch && lease.archiveCapture && lease.archiveCapture.deadlineAt.getTime() > now
5060
+ );
5061
+ }
5062
+
5063
+ // src/sandbox-resume.ts
5005
5064
  import {
5006
5065
  acquireLease,
5007
5066
  adoptLegacyModalCheckpointArtifact,
@@ -5054,6 +5113,7 @@ import {
5054
5113
  downloadWorkspaceArchiveSpool,
5055
5114
  WorkspaceArchiveStorageError
5056
5115
  } from "@opengeni/storage";
5116
+ import { sandboxLeaseTelemetryKey as sandboxLeaseTelemetryKey2 } from "@opengeni/observability";
5057
5117
  import { parseWorkspaceArchiveObjectRef as parseWorkspaceArchiveObjectRef2 } from "@opengeni/contracts";
5058
5118
  function sandboxLeaseHolderIdForAttempt(attemptId) {
5059
5119
  const normalized = attemptId.trim();
@@ -5160,29 +5220,6 @@ var SnapshotTimeoutError = class extends Error {
5160
5220
  this.name = "SnapshotTimeoutError";
5161
5221
  }
5162
5222
  };
5163
- function safeSnapshotError(error) {
5164
- const fields = {
5165
- errorClass: "SnapshotOperationError",
5166
- errorCode: "snapshot_operation_failed",
5167
- origin: "sandbox-resume"
5168
- };
5169
- try {
5170
- if (error && typeof error === "object") {
5171
- const candidate = error;
5172
- if (typeof candidate.name === "string" && /^[A-Z][A-Za-z0-9]{2,62}Error$/u.test(candidate.name)) {
5173
- fields.causeName = candidate.name;
5174
- }
5175
- if (typeof candidate.code === "string" && /^[a-z0-9_]{1,64}$/u.test(candidate.code)) {
5176
- fields.integrityCode = candidate.code;
5177
- }
5178
- const rawStatus = candidate.status ?? candidate.statusCode;
5179
- const status = Number(rawStatus);
5180
- if (Number.isInteger(status) && status >= 100 && status <= 599) fields.status = status;
5181
- }
5182
- } catch {
5183
- }
5184
- return fields;
5185
- }
5186
5223
  async function waitForWarmSnapshot(snapshot, timeoutMs, signal) {
5187
5224
  if (signal?.aborted) return false;
5188
5225
  let timeout;
@@ -5361,6 +5398,18 @@ function maybePersistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch, s
5361
5398
  }
5362
5399
  async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch, signal, force, registerOwnedContinuation) {
5363
5400
  const { db, settings } = services;
5401
+ const warnSnapshotFailure = (message, error) => {
5402
+ const fields = {
5403
+ ...safeSnapshotError(error),
5404
+ sandboxLeaseKey: sandboxLeaseTelemetryKey2(ids.workspaceId, ids.sandboxGroupId),
5405
+ leaseEpoch
5406
+ };
5407
+ try {
5408
+ if (services.observability) services.observability.warn(message, fields);
5409
+ else console.warn(message, fields);
5410
+ } catch {
5411
+ }
5412
+ };
5364
5413
  const intervalMs = settings.sandboxSnapshotIntervalMs;
5365
5414
  if (intervalMs <= 0 && !force) {
5366
5415
  return false;
@@ -5434,6 +5483,7 @@ async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch,
5434
5483
  } : {}
5435
5484
  });
5436
5485
  if (claimed.status !== "claimed") {
5486
+ if (claimed.status === "throttled") return false;
5437
5487
  console.error("mid-session workspace snapshot skipped (capture claim)", {
5438
5488
  sandboxGroupId: ids.sandboxGroupId,
5439
5489
  status: claimed.status
@@ -5472,6 +5522,8 @@ async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch,
5472
5522
  }).catch(() => void 0);
5473
5523
  };
5474
5524
  const captureAndPublish = (async () => {
5525
+ const captureStarted = performance.now();
5526
+ let captureOutcome = "failed";
5475
5527
  let archive;
5476
5528
  let candidate = null;
5477
5529
  let publicationAttempted = false;
@@ -5521,6 +5573,7 @@ async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch,
5521
5573
  if (!wrote && candidate) {
5522
5574
  await abandonCandidate(candidate.id, "snapshot_publication_fenced");
5523
5575
  }
5576
+ if (wrote) captureOutcome = "completed";
5524
5577
  return wrote;
5525
5578
  } catch (error) {
5526
5579
  if (candidate && !publicationAttempted)
@@ -5538,20 +5591,23 @@ async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch,
5538
5591
  expectedEpoch: leaseEpoch,
5539
5592
  expectedInstanceId: instanceId
5540
5593
  }).catch((error) => {
5541
- console.error(
5542
- "mid-session workspace capture gate release failed",
5543
- safeSnapshotError(error)
5544
- );
5594
+ captureOutcome = "failed";
5595
+ warnSnapshotFailure("mid-session workspace capture gate release failed", error);
5545
5596
  });
5597
+ try {
5598
+ services.sandboxMetrics?.onWorkspaceCapture?.({
5599
+ backend: lease.backend,
5600
+ outcome: captureOutcome,
5601
+ durationSeconds: Math.max(0, performance.now() - captureStarted) / 1e3
5602
+ });
5603
+ } catch {
5604
+ }
5546
5605
  }
5547
5606
  })();
5548
5607
  const settled = captureAndPublish.then(
5549
5608
  (persisted) => ({ kind: "settled", persisted }),
5550
5609
  (error) => {
5551
- console.error(
5552
- "mid-session workspace snapshot failed (turn unaffected)",
5553
- safeSnapshotError(error)
5554
- );
5610
+ warnSnapshotFailure("mid-session workspace snapshot failed (turn unaffected)", error);
5555
5611
  return { kind: "settled", persisted: false };
5556
5612
  }
5557
5613
  );
@@ -5578,10 +5634,7 @@ async function persistWarmWorkspaceSnapshot(services, ids, session, leaseEpoch,
5578
5634
  });
5579
5635
  return outcome.kind === "settled" ? outcome.persisted : false;
5580
5636
  } catch (error) {
5581
- console.error(
5582
- "mid-session workspace snapshot failed (turn unaffected)",
5583
- safeSnapshotError(error)
5584
- );
5637
+ warnSnapshotFailure("mid-session workspace snapshot failed (turn unaffected)", error);
5585
5638
  return false;
5586
5639
  }
5587
5640
  }
@@ -5714,7 +5767,12 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
5714
5767
  });
5715
5768
  await providerRenewalInFlight;
5716
5769
  };
5717
- const releaseDeadHolder = (reason) => {
5770
+ const releaseDeadHolder = async (reason) => {
5771
+ if (reason === "holder_gone" && kind === "turn" && holderLeaseHeartbeat) {
5772
+ const expectedEpoch = holderLeaseHeartbeat.expectedEpoch;
5773
+ const lease = await readLease(db, ids.workspaceId, ids.sandboxGroupId);
5774
+ if (retainsHolderForWarmCapture(lease, expectedEpoch)) return;
5775
+ }
5718
5776
  const message = "sandbox resume holder released: holder no longer live";
5719
5777
  const fields = {
5720
5778
  workspaceId: ids.workspaceId,
@@ -5738,14 +5796,14 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
5738
5796
  holderId,
5739
5797
  expectedEpoch: heartbeat2.expectedEpoch,
5740
5798
  leaseTtlMs: heartbeat2.leaseTtlMs
5741
- }).then((status) => {
5799
+ }).then(async (status) => {
5742
5800
  if (heartbeat2 !== holderLeaseHeartbeat) return;
5743
5801
  if (!status.holderAlive) {
5744
- releaseDeadHolder(status.fence);
5802
+ await releaseDeadHolder(status.fence);
5745
5803
  return;
5746
5804
  }
5747
5805
  if (status.fence === "epoch") {
5748
- releaseDeadHolder(status.fence);
5806
+ await releaseDeadHolder(status.fence);
5749
5807
  return;
5750
5808
  }
5751
5809
  if (status.leaseExtended || status.fence === "rotation_requested") {
@@ -5760,10 +5818,10 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
5760
5818
  sandboxGroupId: ids.sandboxGroupId,
5761
5819
  kind,
5762
5820
  holderId
5763
- }).then((touched) => {
5821
+ }).then(async (touched) => {
5764
5822
  if (heartbeat2 !== holderLeaseHeartbeat) return;
5765
5823
  if (!touched) {
5766
- releaseDeadHolder("holder_gone");
5824
+ await releaseDeadHolder("holder_gone");
5767
5825
  return;
5768
5826
  }
5769
5827
  void maybeRenewProviderExpiration().catch(() => void 0);
@@ -5809,7 +5867,7 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
5809
5867
  let spawnEnvelope = fallbackArchiveEnvelope ?? acquired.lease.resumeState ?? envelope;
5810
5868
  const archiveSource = acquired.lease.recovery.archive.status === "none" ? fallbackArchiveEnvelope : acquired.lease.resumeState;
5811
5869
  const continuityRecovery = acquired.lease.recovery.continuity;
5812
- if (acquired.lease.recovery.archive.status === "available" && acquired.lease.archiveComplete || acquired.lease.recovery.archive.status === "none" && workspaceArchiveFieldsFromEnvelope(archiveSource) !== null) {
5870
+ if (acquired.lease.recovery.archive.status === "available" && (acquired.lease.archiveComplete || acquired.lease.historicalRecoveryAuthorized === true) || acquired.lease.recovery.archive.status === "none" && workspaceArchiveFieldsFromEnvelope(archiveSource) !== null) {
5813
5871
  const rematerializationId = crypto.randomUUID();
5814
5872
  const legacyNativeArchive = legacyNativeArchiveFromEnvelope(archiveSource);
5815
5873
  const begun = await beginSandboxRematerialization(db, {
@@ -6159,7 +6217,8 @@ async function resumeBoxForTurn(services, ids, kind, holderId) {
6159
6217
  workspaceId: ids.workspaceId,
6160
6218
  sandboxGroupId: ids.sandboxGroupId,
6161
6219
  expectedEpoch: leaseEpoch,
6162
- expectedInstanceId: live.instanceId
6220
+ expectedInstanceId: live.instanceId,
6221
+ expectedBackend: ids.backend
6163
6222
  });
6164
6223
  if (marked.status === "marked") {
6165
6224
  await services.onSandboxLost?.({
@@ -6289,7 +6348,7 @@ async function resolveCurrentHomeBackend(services, ids, established) {
6289
6348
  throw homeRouteRecoveryError(lease, fallbackEpoch);
6290
6349
  }
6291
6350
  if (lease.instanceId === established.instanceId) {
6292
- services.onHomeSandboxRebound?.({
6351
+ await services.onHomeSandboxRebound?.({
6293
6352
  established,
6294
6353
  leaseEpoch: lease.leaseEpoch
6295
6354
  });
@@ -6329,6 +6388,7 @@ async function resolveCurrentHomeBackend(services, ids, established) {
6329
6388
  sandboxGroupId: ids.sandboxGroupId,
6330
6389
  expectedEpoch: lease.leaseEpoch,
6331
6390
  expectedInstanceId: lease.instanceId,
6391
+ expectedBackend: lease.backend,
6332
6392
  diagnostic: "provider_not_found_during_home_route_rebind"
6333
6393
  });
6334
6394
  if (marked.status === "marked") {
@@ -6348,7 +6408,7 @@ async function resolveCurrentHomeBackend(services, ids, established) {
6348
6408
  if (rebound.instanceId !== lease.instanceId || reboundBackend !== resumeBackend) {
6349
6409
  throw homeRouteRecoveryError(lease, lease.leaseEpoch);
6350
6410
  }
6351
- services.onHomeSandboxRebound?.({
6411
+ await services.onHomeSandboxRebound?.({
6352
6412
  established: rebound,
6353
6413
  leaseEpoch: lease.leaseEpoch
6354
6414
  });
@@ -6553,7 +6613,7 @@ function settleRetainedProcessForTurn(services, ids) {
6553
6613
  sessionId: ids.sessionId,
6554
6614
  processId: process2.id
6555
6615
  });
6556
- if (!durable || durable.providerSessionId !== process2.providerSessionId || durable.providerBackend !== backend.kind || durable.providerInstanceId !== backend.providerInstanceId || durable.leaseEpoch !== backend.leaseEpoch || durable.routeKind !== (backend.sandboxId === null ? "home" : "active") || durable.routeTargetId !== backend.sandboxId || durable.routeEpoch !== backend.activeEpoch) {
6616
+ if (!durable || durable.providerSessionId !== process2.providerSessionId || durable.providerBackend !== (sandboxBackendForSdkBackendId(backend.kind) ?? backend.kind) || durable.providerInstanceId !== backend.providerInstanceId || durable.leaseEpoch !== backend.leaseEpoch || durable.routeKind !== (backend.sandboxId === null ? "home" : "active") || durable.routeTargetId !== backend.sandboxId || durable.routeEpoch !== backend.activeEpoch) {
6557
6617
  throw new Error("Retained-process settlement lost its exact durable backend identity");
6558
6618
  }
6559
6619
  const settlement = await settleRetainedProcess(services.db, {
@@ -6584,7 +6644,7 @@ function adoptRetainedProcessAsBackgroundCommandForTurn(services, ids) {
6584
6644
  sessionId: ids.sessionId,
6585
6645
  processId: process2.id
6586
6646
  });
6587
- if (!durable || durable.providerSessionId !== process2.providerSessionId || durable.providerBackend !== backend.kind || durable.providerInstanceId !== backend.providerInstanceId || durable.leaseEpoch !== backend.leaseEpoch || durable.routeKind !== (backend.sandboxId === null ? "home" : "active") || durable.routeTargetId !== backend.sandboxId || durable.routeEpoch !== backend.activeEpoch) {
6647
+ if (!durable || durable.providerSessionId !== process2.providerSessionId || durable.providerBackend !== (sandboxBackendForSdkBackendId(backend.kind) ?? backend.kind) || durable.providerInstanceId !== backend.providerInstanceId || durable.leaseEpoch !== backend.leaseEpoch || durable.routeKind !== (backend.sandboxId === null ? "home" : "active") || durable.routeTargetId !== backend.sandboxId || durable.routeEpoch !== backend.activeEpoch) {
6588
6648
  throw new Error("Background command adoption lost its exact retained-process identity");
6589
6649
  }
6590
6650
  await adoptManagedSessionBackgroundCommand(services.db, {
@@ -6769,14 +6829,20 @@ function wrapTurnBoxWithRouting(services, ids, established) {
6769
6829
  },
6770
6830
  resolveActiveBackend: resolver,
6771
6831
  ...services.onSandboxOperation ? { onOperation: services.onSandboxOperation } : {},
6832
+ ...services.onSandboxCaptureWait ? { onCaptureWait: services.onSandboxCaptureWait } : {},
6772
6833
  providerCommandHandle: admittedCommandHandle,
6834
+ providerSupervisionReady: async () => settings.modalCommandSupervisionEnabled && await supervisedCommandProtocolReady(db),
6773
6835
  ...ids.workspaceMutationFence ? {
6774
- providerCommandPersistence: (process2) => retainedProviderCommandPersistence(db, {
6775
- accountId: ids.workspaceMutationFence.accountId,
6776
- workspaceId: ids.workspaceId,
6777
- sessionId: ids.sessionId,
6778
- processId: process2.id
6779
- })
6836
+ providerCommandPersistence: (process2) => retainedProviderCommandPersistence(
6837
+ db,
6838
+ {
6839
+ accountId: ids.workspaceMutationFence.accountId,
6840
+ workspaceId: ids.workspaceId,
6841
+ sessionId: ids.sessionId,
6842
+ processId: process2.id
6843
+ },
6844
+ services.bus ? (events) => services.bus.publish(ids.workspaceId, ids.sessionId, events) : void 0
6845
+ )
6780
6846
  } : {},
6781
6847
  ...beforeMutation ? { beforeMutation } : {},
6782
6848
  ...afterMutation ? { afterMutation } : {},
@@ -6801,6 +6867,7 @@ function wrapTurnBoxWithRouting(services, ids, established) {
6801
6867
  sandboxGroupId: home.sandboxGroupId,
6802
6868
  expectedEpoch,
6803
6869
  expectedInstanceId,
6870
+ expectedBackend: home.backend,
6804
6871
  diagnostic: "provider_not_found_during_routed_operation"
6805
6872
  });
6806
6873
  if (marked.status === "marked") {
@@ -6965,15 +7032,21 @@ function wrapLazyTurnBoxWithRouting(services, ids, args) {
6965
7032
  return routedResolver(pointer);
6966
7033
  },
6967
7034
  ...services.onSandboxOperation ? { onOperation: services.onSandboxOperation } : {},
7035
+ ...services.onSandboxCaptureWait ? { onCaptureWait: services.onSandboxCaptureWait } : {},
6968
7036
  ...args.onFirstOperation ? { onFirstOperation: args.onFirstOperation } : {},
6969
7037
  providerCommandHandle: admittedCommandHandle,
7038
+ providerSupervisionReady: async () => settings.modalCommandSupervisionEnabled && await supervisedCommandProtocolReady(db),
6970
7039
  ...ids.workspaceMutationFence ? {
6971
- providerCommandPersistence: (process2) => retainedProviderCommandPersistence(db, {
6972
- accountId: ids.workspaceMutationFence.accountId,
6973
- workspaceId: ids.workspaceId,
6974
- sessionId: ids.sessionId,
6975
- processId: process2.id
6976
- })
7040
+ providerCommandPersistence: (process2) => retainedProviderCommandPersistence(
7041
+ db,
7042
+ {
7043
+ accountId: ids.workspaceMutationFence.accountId,
7044
+ workspaceId: ids.workspaceId,
7045
+ sessionId: ids.sessionId,
7046
+ processId: process2.id
7047
+ },
7048
+ services.bus ? (events) => services.bus.publish(ids.workspaceId, ids.sessionId, events) : void 0
7049
+ )
6977
7050
  } : {},
6978
7051
  ...beforeMutation ? { beforeMutation } : {},
6979
7052
  ...afterMutation ? { afterMutation } : {},
@@ -6999,6 +7072,7 @@ function wrapLazyTurnBoxWithRouting(services, ids, args) {
6999
7072
  sandboxGroupId: home.sandboxGroupId,
7000
7073
  expectedEpoch: backend.leaseEpoch,
7001
7074
  expectedInstanceId: backend.providerInstanceId,
7075
+ expectedBackend: home.backend,
7002
7076
  diagnostic: "provider_not_found_during_routed_operation"
7003
7077
  });
7004
7078
  if (marked.status === "marked") {
@@ -7202,6 +7276,7 @@ import {
7202
7276
  getSession,
7203
7277
  getSessionGoal as getSessionGoal2,
7204
7278
  getSessionParentPersonalConnectionDelegations,
7279
+ getSessionParentMcpAccountBindings,
7205
7280
  getSessionParentXaiProviderAccountAuthority,
7206
7281
  addSessionSystemUpdateWithSourceMutation,
7207
7282
  claimPendingSessionSystemUpdateOutbox,
@@ -7232,6 +7307,11 @@ async function notifyParentOfChildIdle(svc, workspaceId, childSessionId, episode
7232
7307
  workspaceId,
7233
7308
  childSessionId
7234
7309
  );
7310
+ const mcpAccountBindings = await getSessionParentMcpAccountBindings(
7311
+ svc.db,
7312
+ workspaceId,
7313
+ childSessionId
7314
+ );
7235
7315
  const xaiAuthority = await getSessionParentXaiProviderAccountAuthority(
7236
7316
  svc.db,
7237
7317
  workspaceId,
@@ -7254,6 +7334,7 @@ async function notifyParentOfChildIdle(svc, workspaceId, childSessionId, episode
7254
7334
  ...xaiAuthority.subjectId ? { xaiAuthoritySubjectId: xaiAuthority.subjectId } : {}
7255
7335
  },
7256
7336
  personalConnectionDelegations,
7337
+ mcpAccountBindings,
7257
7338
  xaiProviderAccountAuthoritySnapshot: xaiAuthority.snapshot
7258
7339
  });
7259
7340
  if (outbox.status === "delivered") {
@@ -7329,6 +7410,7 @@ async function deliverParentSystemUpdateOutbox(svc, outbox) {
7329
7410
  summary: outbox.summary,
7330
7411
  lineage: outbox.lineage,
7331
7412
  personalConnectionDelegations: outbox.personalConnectionDelegations,
7413
+ mcpAccountBindings: outbox.mcpAccountBindings,
7332
7414
  xaiProviderAccountAuthoritySnapshot: outbox.xaiProviderAccountAuthoritySnapshot
7333
7415
  },
7334
7416
  async (tx) => {
@@ -8446,12 +8528,14 @@ async function persistOrSignalSessionAttemptQuiescence(input) {
8446
8528
  return "receipt";
8447
8529
  }
8448
8530
  async function drainAttemptOwnedSandboxWriters(input) {
8531
+ input.onStage?.("tool_writers");
8449
8532
  if (input.toolCancellationFence) {
8450
8533
  input.toolCancellationFence.cancel(
8451
8534
  input.cancellationReason ?? new Error("TURN_ATTEMPT_FENCED")
8452
8535
  );
8453
8536
  await input.toolCancellationFence.waitForQuiescence();
8454
8537
  }
8538
+ input.onStage?.("credential_renewals");
8455
8539
  await Promise.all(input.gitCredentialRenewals.map(async (renewal) => await renewal.stop()));
8456
8540
  await input.codemodeTokenRenewal?.stop();
8457
8541
  await input.runCredentialRenewal?.stop();
@@ -8597,10 +8681,14 @@ import {
8597
8681
  ActiveBackendUnresolvableError as ActiveBackendUnresolvableError2,
8598
8682
  CompactionProviderResponseError,
8599
8683
  EmptyCompactionSummaryError,
8684
+ compactionProviderRejection,
8685
+ describeCompactionProviderRejection,
8600
8686
  isMcpRequestTimeoutError,
8601
8687
  isMcpTransportConnectivityError,
8602
8688
  isModalTaskExecStartDnsResolutionError,
8603
8689
  RoutingWorkspaceRootChangedError,
8690
+ SandboxMaterializationVerificationError,
8691
+ materializationVerificationDiagnostic,
8604
8692
  SelfhostedWorkspaceRootChangedError,
8605
8693
  UNKNOWN_MODEL_FINISH_REASON_CODE
8606
8694
  } from "@opengeni/runtime";
@@ -8772,12 +8860,8 @@ function attachmentRefsFromItem(item) {
8772
8860
  }
8773
8861
  return refs;
8774
8862
  }
8775
- function attachmentReceiptText(ref, file) {
8776
- if (!file) {
8777
- return `[Earlier attachment: fileId=${ref.fileId}; mountDirectory=${resourceMountPath(ref)}. Use the existing file there, or call files__files_get_download_url with this fileId and download it with the shell.]`;
8778
- }
8779
- const path = sandboxFilePath(ref, file);
8780
- return `[Attachment: ${file.safeFilename}; fileId=${file.id}; type=${file.contentType}; bytes=${file.sizeBytes}; path=${path}. If the local path is absent, call files__files_get_download_url with this fileId and download it with the shell.]`;
8863
+ function attachmentReceiptText(ref) {
8864
+ return `[Attachment: fileId=${ref.fileId}; mountDirectory=${resourceMountPath(ref)}. Use the existing file there, or call files__files_get_download_url with this fileId and download it with the shell.]`;
8781
8865
  }
8782
8866
  function createModelHistoryAttachmentProjector(policy, readFileBytes, loadAuthorizedFiles) {
8783
8867
  const contentById = /* @__PURE__ */ new Map();
@@ -8856,7 +8940,7 @@ function createModelHistoryAttachmentProjector(policy, readFileBytes, loadAuthor
8856
8940
  const attachment = currentFile ? contentById.get(ref.fileId) : void 0;
8857
8941
  const receipt = {
8858
8942
  type: "input_text",
8859
- text: attachmentReceiptText(ref, currentFile)
8943
+ text: attachmentReceiptText(ref)
8860
8944
  };
8861
8945
  if (!attachment || attachment.kind !== "image") {
8862
8946
  return [receipt];
@@ -8875,12 +8959,18 @@ function createModelHistoryAttachmentProjector(policy, readFileBytes, loadAuthor
8875
8959
  }
8876
8960
  function withCurrentUserAttachmentRefs(historyItems, refs) {
8877
8961
  if (refs.length === 0) return historyItems;
8962
+ const retainedIds = new Set(
8963
+ historyItems.flatMap((item) => attachmentRefsFromItem(item).map((ref) => ref.fileId))
8964
+ );
8965
+ const missing = refs.filter((ref) => !retainedIds.has(ref.fileId));
8966
+ if (missing.length === 0) return historyItems;
8878
8967
  for (let index = historyItems.length - 1; index >= 0; index -= 1) {
8879
8968
  const item = historyItems[index];
8969
+ if (item[MODEL_ATTACHMENT_CATALOG_MARKER] === true) continue;
8880
8970
  if (item.type !== "message" || item.role !== "user") continue;
8881
8971
  const existing = attachmentRefsFromItem(item);
8882
8972
  const existingIds = new Set(existing.map((ref) => ref.fileId));
8883
- const additions = refs.filter((ref) => !existingIds.has(ref.fileId));
8973
+ const additions = missing.filter((ref) => !existingIds.has(ref.fileId));
8884
8974
  if (additions.length === 0) return historyItems;
8885
8975
  const projected = [...historyItems];
8886
8976
  projected[index] = { ...item, [MODEL_ATTACHMENT_REFS_FIELD]: [...existing, ...additions] };
@@ -8950,8 +9040,8 @@ async function turnInput(db, runtime, agent, trigger, options) {
8950
9040
  options
8951
9041
  );
8952
9042
  }
8953
- if (trigger.type === "system.update.delivered") {
8954
- if (updates.length === 0) {
9043
+ if (trigger.type === "system.update.delivered" || trigger.type === "session.context.compaction.requested") {
9044
+ if (trigger.type === "system.update.delivered" && updates.length === 0) {
8955
9045
  throw new Error("Internal update inference has no delivered updates");
8956
9046
  }
8957
9047
  return await messageInput(
@@ -9117,6 +9207,7 @@ function sandboxFilePath(resource, file) {
9117
9207
  // src/activities/agent-turn/errors.ts
9118
9208
  import {
9119
9209
  CodexReloginRequired,
9210
+ classifyCodexEncryptedArtifactRejection,
9120
9211
  classifyCodexResponseTimeoutError,
9121
9212
  classifyCodexUsageLimitError,
9122
9213
  isCodexTransportError
@@ -9242,9 +9333,15 @@ function escapedMcpTimeoutRecoveryFailure(input) {
9242
9333
  function preClaimAdmissionFailure(error) {
9243
9334
  const persistenceFailure = isSessionEventPersistenceError(error) ? error : null;
9244
9335
  const retryableCode = retryableDatabaseFailureCode(error);
9336
+ const rejectedClaim = persistenceFailure?.details.stage === "session_attempts.claim" && persistenceFailure.details.retryOutcome === "not_retryable" && !retryableCode;
9245
9337
  const detail = {
9246
- disposition: persistenceFailure || retryableCode ? "retryable" : "permanent",
9247
- code: retryableCode ?? persistenceFailure?.details.code ?? "claim_invariant"
9338
+ disposition: rejectedClaim ? "blocked" : persistenceFailure || retryableCode ? "retryable" : "permanent",
9339
+ code: retryableCode ?? persistenceFailure?.details.code ?? "claim_invariant",
9340
+ ...persistenceFailure && rejectedClaim ? {
9341
+ sqlState: persistenceFailure.details.sqlState,
9342
+ reason: persistenceFailure.details.stage === "session_attempts.claim" && persistenceFailure.details.sqlState === "OG001" ? "initiator_membership_required" : persistenceFailure.details.stage === "session_attempts.claim" && persistenceFailure.details.sqlState === "OG002" ? "personal_resource_grant_required" : "database_claim_rejected",
9343
+ retryPolicy: "explicit_recheck"
9344
+ } : {}
9248
9345
  };
9249
9346
  return ApplicationFailure.create({
9250
9347
  message: PRE_CLAIM_FAILURE_MESSAGE,
@@ -9384,19 +9481,38 @@ function safeErrorForTelemetry(error) {
9384
9481
  safe.origin = diagnostic.origin;
9385
9482
  return safe;
9386
9483
  }
9484
+ var COMPACTION_PROVIDER_REJECTION_GUIDANCE = "The provider refused this exact request, so repeating it fails the same way until the conversation changes. If a new message fails again, start a new session.";
9387
9485
  function compactionFailureReasonFromError(error) {
9486
+ const rejection = compactionProviderRejection(error);
9487
+ if (rejection) {
9488
+ return compactionFailureReason(
9489
+ `the model provider rejected the compaction request (${describeCompactionProviderRejection(rejection)}). Active history was preserved. ${COMPACTION_PROVIDER_REJECTION_GUIDANCE}`
9490
+ );
9491
+ }
9388
9492
  if (error instanceof CompactionProviderResponseError || error instanceof EmptyCompactionSummaryError) {
9389
9493
  return compactionFailureReason(error.message);
9390
9494
  }
9391
9495
  const errorName = error instanceof Error && error.name ? error.name : "unknown error";
9392
9496
  return compactionFailureReason(`unexpected ${errorName}`);
9393
9497
  }
9498
+ function compactionFailureTurnEventPayload(error, overrides = {}) {
9499
+ const rejection = compactionProviderRejection(error);
9500
+ return {
9501
+ error: overrides.error ?? compactionFailureReasonFromError(error),
9502
+ code: "context_compaction_failed",
9503
+ retryable: false,
9504
+ recovery: "user_message",
9505
+ compacted: false,
9506
+ ...rejection ? { providerRejection: rejection } : {}
9507
+ };
9508
+ }
9394
9509
  function isCompactionSummaryFailure(error) {
9395
9510
  return error instanceof CompactionProviderResponseError || error instanceof EmptyCompactionSummaryError;
9396
9511
  }
9397
9512
  function shouldRecoverCompactionProviderFailure(error) {
9398
9513
  if (!(error instanceof CompactionProviderResponseError)) return false;
9399
9514
  if (isCodexTransportError(error) && classifyCodexUsageLimitError(error)) return true;
9515
+ if (classifyCodexEncryptedArtifactRejection(error)) return true;
9400
9516
  return agentRunFailurePayload(error).retryable === true;
9401
9517
  }
9402
9518
  function classifyContextWindowOverflowError(error) {
@@ -9546,6 +9662,19 @@ function findPostgresDriverError(error) {
9546
9662
  return null;
9547
9663
  }
9548
9664
  function agentRunFailurePayload(error, options = {}) {
9665
+ const failure = baseAgentRunFailurePayload(error, options);
9666
+ const diagnostic = materializationVerificationDiagnostic(error);
9667
+ return diagnostic ? { ...failure, materializationDiagnostic: diagnostic } : failure;
9668
+ }
9669
+ function baseAgentRunFailurePayload(error, options = {}) {
9670
+ if (error instanceof SandboxMaterializationVerificationError) {
9671
+ return {
9672
+ error: error.message,
9673
+ code: error.code,
9674
+ retryable: false,
9675
+ materializationDiagnostic: error.diagnostic
9676
+ };
9677
+ }
9549
9678
  if (error instanceof RetainedAttachmentTransportLimitError) {
9550
9679
  return { error: error.message, code: "retained_attachment_transport_limit", retryable: false };
9551
9680
  }
@@ -9846,12 +9975,11 @@ export {
9846
9975
  withFirstPartyTools,
9847
9976
  createKnowledgeSourceSyncActivities,
9848
9977
  rigProviderImageSourceImage,
9849
- settingsWithPackSandboxImage,
9850
- resolveWorkspacePackRuntime,
9851
9978
  createRuntimeBatcher,
9852
9979
  currentActivityContext,
9853
9980
  startActivityHeartbeat,
9854
9981
  nextStreamEvent,
9982
+ warnDrainSnapshotFailure,
9855
9983
  persistWorkspaceArchiveCandidate,
9856
9984
  putVersion1TarArchiveOrInline,
9857
9985
  sandboxLeaseHolderIdForAttempt,
@@ -9925,6 +10053,7 @@ export {
9925
10053
  safeErrorDiagnostic,
9926
10054
  safeErrorForTelemetry,
9927
10055
  compactionFailureReasonFromError,
10056
+ compactionFailureTurnEventPayload,
9928
10057
  isCompactionSummaryFailure,
9929
10058
  shouldRecoverCompactionProviderFailure,
9930
10059
  classifyContextWindowOverflowError,
@@ -9935,4 +10064,4 @@ export {
9935
10064
  codexUsageLimitFailurePayload,
9936
10065
  CODEX_USAGE_LIMIT_MAX_RESUME_MS
9937
10066
  };
9938
- //# sourceMappingURL=chunk-CYITU5UH.js.map
10067
+ //# sourceMappingURL=chunk-TVEE2UUC.js.map