@opengeni/worker-bundle 2.3.1 → 2.3.2-canary.37090756480001

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 (66) hide show
  1. package/dist/activities/agent-turn/claude-usage-observer.d.ts +30 -6
  2. package/dist/activities/agent-turn/credential-leases.d.ts +5 -32
  3. package/dist/activities/agent-turn/errors.d.ts +3 -0
  4. package/dist/activities/agent-turn/finalization-monitor.d.ts +1 -1
  5. package/dist/activities/agent-turn/finalization.d.ts +2 -0
  6. package/dist/activities/agent-turn/quiescence.d.ts +3 -4
  7. package/dist/activities/agent-turn/subscription-lease.d.ts +38 -0
  8. package/dist/activities/agent-turn/turn-context.d.ts +1 -1
  9. package/dist/activities/model-call-fact-reconciler.d.ts +34 -0
  10. package/dist/activities/session-state.d.ts +2 -2
  11. package/dist/activities/types.d.ts +7 -0
  12. package/dist/{activities-control-3HAH4FMG.js → activities-control-3BY4IJKL.js} +166 -35
  13. package/dist/activities-control-3BY4IJKL.js.map +1 -0
  14. package/dist/activities-control.d.ts +6 -4
  15. package/dist/{activities-turn-KU25J3VQ.js → activities-turn-TTNAVGKN.js} +263 -308
  16. package/dist/activities-turn-TTNAVGKN.js.map +1 -0
  17. package/dist/activities.d.ts +6 -4
  18. package/dist/{chunk-3K3ULWEE.js → chunk-PA7Z55P4.js} +242 -17
  19. package/dist/chunk-PA7Z55P4.js.map +1 -0
  20. package/dist/{chunk-YG27NEMX.js → chunk-YOI3Z3GF.js} +9 -1
  21. package/dist/chunk-YOI3Z3GF.js.map +1 -0
  22. package/dist/http.d.ts +1 -1
  23. package/dist/index.d.ts +6 -2
  24. package/dist/index.js +82 -16
  25. package/dist/index.js.map +1 -1
  26. package/dist/observability-metrics.d.ts +6 -1
  27. package/dist/sandbox-resume.d.ts +3 -0
  28. package/dist/session-event-fanout.d.ts +6 -0
  29. package/dist/worker-service-lifecycle.d.ts +12 -0
  30. package/dist/workflow-bundle.js +3 -2
  31. package/package.json +21 -21
  32. package/src/activities/agent-turn/claim.ts +13 -0
  33. package/src/activities/agent-turn/claude-usage-observer.ts +99 -8
  34. package/src/activities/agent-turn/credential-leases.ts +86 -213
  35. package/src/activities/agent-turn/errors.ts +61 -1
  36. package/src/activities/agent-turn/failure-settlement.ts +59 -5
  37. package/src/activities/agent-turn/finalization-monitor.ts +3 -4
  38. package/src/activities/agent-turn/finalization.ts +8 -3
  39. package/src/activities/agent-turn/quiescence.ts +3 -4
  40. package/src/activities/agent-turn/run.ts +24 -20
  41. package/src/activities/agent-turn/sandbox-establish.ts +2 -0
  42. package/src/activities/agent-turn/sandbox-runtime.ts +5 -1
  43. package/src/activities/agent-turn/skill-selection.ts +2 -0
  44. package/src/activities/agent-turn/subscription-lease.ts +115 -0
  45. package/src/activities/agent-turn/turn-context.ts +1 -4
  46. package/src/activities/codex-rotation.ts +2 -12
  47. package/src/activities/model-call-fact-reconciler.ts +112 -0
  48. package/src/activities/sandbox-lease.ts +59 -8
  49. package/src/activities/session-state.ts +29 -4
  50. package/src/activities/types.ts +7 -0
  51. package/src/activities-control.ts +2 -0
  52. package/src/activities-turn.ts +5 -0
  53. package/src/activities.ts +7 -0
  54. package/src/http.ts +4 -2
  55. package/src/index.ts +39 -9
  56. package/src/observability-metrics.ts +27 -0
  57. package/src/sandbox-resume.ts +9 -0
  58. package/src/sandbox-routing.ts +77 -0
  59. package/src/session-event-fanout.ts +23 -0
  60. package/src/worker-service-lifecycle.ts +53 -0
  61. package/src/workflows/file-upload-reaper.ts +2 -0
  62. package/src/workflows/session.ts +6 -1
  63. package/dist/activities-control-3HAH4FMG.js.map +0 -1
  64. package/dist/activities-turn-KU25J3VQ.js.map +0 -1
  65. package/dist/chunk-3K3ULWEE.js.map +0 -1
  66. package/dist/chunk-YG27NEMX.js.map +0 -1
@@ -24,6 +24,7 @@ import {
24
24
  notifyParentOfChildIdle,
25
25
  persistWorkspaceArchiveCandidate,
26
26
  providerRecoveryCountFromMetadata,
27
+ publishDurableSessionEvents,
27
28
  putVersion1TarArchiveOrInline,
28
29
  reconcileAutomaticSessionTitleFanout,
29
30
  reconcilePendingParentSystemUpdates,
@@ -34,7 +35,7 @@ import {
34
35
  warnDrainSnapshotFailure,
35
36
  withFirstPartyTools,
36
37
  workflowIdForSession
37
- } from "./chunk-3K3ULWEE.js";
38
+ } from "./chunk-PA7Z55P4.js";
38
39
  import {
39
40
  inspectOpenSandboxKubernetesInventory,
40
41
  recordActiveUserGauges,
@@ -47,6 +48,7 @@ import {
47
48
  recordRetainedProcessReconciliation,
48
49
  recordSandboxCheckpointArtifactGauges,
49
50
  recordSandboxCheckpointArtifactOutcome,
51
+ recordSandboxCommandContainment,
50
52
  recordSandboxDeadlineRotationsRequested,
51
53
  recordSandboxInventoryProjectionFailure,
52
54
  recordSandboxInventoryProjectionSuccess,
@@ -60,7 +62,7 @@ import {
60
62
  recordVerifiedSignupTrialSwitchGauge,
61
63
  recordWorkerDeathRecoveryMetrics,
62
64
  runtimeMetricsHooksForObservability
63
- } from "./chunk-YG27NEMX.js";
65
+ } from "./chunk-YOI3Z3GF.js";
64
66
  import "./chunk-PZ5AY32C.js";
65
67
 
66
68
  // src/activities/knowledge-indexing.ts
@@ -1156,6 +1158,85 @@ function createFileUploadReaperActivities(services, options = {}) {
1156
1158
  return { reapExpiredFileUploads, recoverVideoGenerationWorkflows };
1157
1159
  }
1158
1160
 
1161
+ // src/activities/model-call-fact-reconciler.ts
1162
+ import { randomUUID as randomUUID2 } from "crypto";
1163
+ import { listWorkspaceIdsAfter, reconcileModelCallFacts } from "@opengeni/db";
1164
+ var MODEL_CALL_FACT_RECONCILE_LOOKBACK_MS = 2 * 60 * 60 * 1e3;
1165
+ var MODEL_CALL_FACT_RECONCILE_SETTLE_MS = 10 * 60 * 1e3;
1166
+ var MODEL_CALL_FACT_RECONCILE_WORKSPACE_LIMIT = 500;
1167
+ var MODEL_CALL_FACT_RECONCILE_RUN_BUDGET_MS = 3 * 60 * 1e3;
1168
+ var WORKSPACE_PAGE_SIZE = 200;
1169
+ function createModelCallFactReconcilerActivities(services, options = {}) {
1170
+ const now = options.now ?? Date.now;
1171
+ const runBudgetMs = options.runBudgetMs ?? MODEL_CALL_FACT_RECONCILE_RUN_BUDGET_MS;
1172
+ const startAfterWorkspaceId = options.startAfterWorkspaceId ?? randomUUID2;
1173
+ const reconcile = options.reconcile ?? reconcileModelCallFacts;
1174
+ const listWorkspaces = options.listWorkspaces ?? listWorkspaceIdsAfter;
1175
+ async function reconcileRecentModelCallFacts() {
1176
+ const { db, observability } = await services();
1177
+ const startedAt = now();
1178
+ const until = new Date(startedAt - MODEL_CALL_FACT_RECONCILE_SETTLE_MS);
1179
+ const since = new Date(until.getTime() - MODEL_CALL_FACT_RECONCILE_LOOKBACK_MS);
1180
+ const result = {
1181
+ workspaces: 0,
1182
+ missing: 0,
1183
+ repaired: 0,
1184
+ unrepaired: 0,
1185
+ truncatedWorkspaces: 0,
1186
+ failedWorkspaces: 0,
1187
+ budgetExhausted: false
1188
+ };
1189
+ const start = startAfterWorkspaceId();
1190
+ let cursor = start;
1191
+ let wrapped = false;
1192
+ while (true) {
1193
+ const page = await listWorkspaces(db, { afterId: cursor, limit: WORKSPACE_PAGE_SIZE });
1194
+ const ids = wrapped ? page.filter((id) => id <= start) : page;
1195
+ for (const workspaceId of ids) {
1196
+ if (now() - startedAt >= runBudgetMs) {
1197
+ result.budgetExhausted = true;
1198
+ break;
1199
+ }
1200
+ result.workspaces += 1;
1201
+ try {
1202
+ const outcome = await reconcile(db, {
1203
+ workspaceId,
1204
+ since,
1205
+ until,
1206
+ limit: MODEL_CALL_FACT_RECONCILE_WORKSPACE_LIMIT
1207
+ });
1208
+ result.missing += outcome.missing;
1209
+ result.repaired += outcome.repaired;
1210
+ result.unrepaired += outcome.unrepaired;
1211
+ if (outcome.truncated) result.truncatedWorkspaces += 1;
1212
+ } catch (error) {
1213
+ result.failedWorkspaces += 1;
1214
+ observability.warn("model call fact reconciliation failed for a workspace", {
1215
+ workspaceId,
1216
+ errorName: error instanceof Error ? error.name : "unknown"
1217
+ });
1218
+ }
1219
+ }
1220
+ if (result.budgetExhausted) break;
1221
+ if (wrapped && ids.length < page.length) break;
1222
+ if (page.length < WORKSPACE_PAGE_SIZE) {
1223
+ if (wrapped) break;
1224
+ wrapped = true;
1225
+ cursor = null;
1226
+ continue;
1227
+ }
1228
+ cursor = page[page.length - 1];
1229
+ }
1230
+ if (result.failedWorkspaces > 0 || result.truncatedWorkspaces > 0 || result.budgetExhausted) {
1231
+ observability.warn("model call fact reconciliation incomplete", { ...result });
1232
+ } else if (result.missing > 0) {
1233
+ observability.info("model call fact reconciliation", { ...result });
1234
+ }
1235
+ return result;
1236
+ }
1237
+ return { reconcileRecentModelCallFacts };
1238
+ }
1239
+
1159
1240
  // src/activities/retained-screenshot-reaper.ts
1160
1241
  import {
1161
1242
  claimRetainedScreenshotMaintenance,
@@ -2671,7 +2752,7 @@ function retainedProcessDeadlineRetryMs(process, lease, settings, retryAfterMs,
2671
2752
  }
2672
2753
 
2673
2754
  // src/activities/sandbox-lease.ts
2674
- import { createHash, randomUUID as randomUUID2 } from "crypto";
2755
+ import { createHash, randomUUID as randomUUID3 } from "crypto";
2675
2756
  import { requestRetainedProcessDeadlineCancellation } from "@opengeni/db/retained-provider-commands";
2676
2757
  import { Context as Context2 } from "@temporalio/activity";
2677
2758
  import { OpLostReason, OpState } from "@opengeni/agent-proto";
@@ -2721,6 +2802,7 @@ import {
2721
2802
  workspaceArchiveCaptureDeadlineElapsed,
2722
2803
  retainedProcessReconciliationProof,
2723
2804
  retainedProcessSettlementIdentity,
2805
+ recoverManagedSessionBackgroundCommand,
2724
2806
  settleClaimedConnectedMachineBackgroundCommand,
2725
2807
  settleSandboxCheckpointArtifactGc,
2726
2808
  rlsContextForWorkspace,
@@ -2887,14 +2969,18 @@ function createSandboxLeaseActivities(services, options = {}) {
2887
2969
  try {
2888
2970
  const { db, settings, observability } = await services();
2889
2971
  const timing = sandboxDrainTiming(settings);
2890
- const onUnobservableCommandDrainError = (error) => {
2891
- observability.warn("sandbox reaper: unobservable command drain inspection failed", {
2892
- error: error instanceof Error ? error.message : String(error)
2893
- });
2972
+ const commandContainment = {
2973
+ idleCommandContainmentMs: settings.sandboxIdleCommandContainmentMs,
2974
+ onCommandContainment: (outcome) => recordSandboxCommandContainment(observability, outcome),
2975
+ onCommandContainmentError: (error) => {
2976
+ observability.warn("sandbox reaper: retained command containment inspection failed", {
2977
+ error: error instanceof Error ? error.message : String(error)
2978
+ });
2979
+ }
2894
2980
  };
2895
2981
  if (!settings.sandboxOwnershipEnabled) {
2896
2982
  const drainableInventory2 = await reapStaleLeaseHoldersGlobal(db, {
2897
- onUnobservableCommandDrainError,
2983
+ ...commandContainment,
2898
2984
  viewerHolderTtlMs: settings.sandboxViewerHolderTtlMs,
2899
2985
  turnHolderTtlMs: settings.sandboxLeaseTtlMs,
2900
2986
  interactionHolderTtlMs: settings.sandboxInteractionHolderTtlMs,
@@ -2921,7 +3007,7 @@ function createSandboxLeaseActivities(services, options = {}) {
2921
3007
  });
2922
3008
  recordSandboxDeadlineRotationsRequested(observability, rotationsRequested);
2923
3009
  const drainableInventory = await reapStaleLeaseHoldersGlobal(db, {
2924
- onUnobservableCommandDrainError,
3010
+ ...commandContainment,
2925
3011
  viewerHolderTtlMs: settings.sandboxViewerHolderTtlMs,
2926
3012
  // Dead-worker turn holders: a live holder is touched every 10s from the
2927
3013
  // moment it is registered (resumeBoxForTurn's holder-liveness loop covers
@@ -2962,7 +3048,7 @@ function createSandboxLeaseActivities(services, options = {}) {
2962
3048
  instanceId: input.target.instanceId
2963
3049
  });
2964
3050
  try {
2965
- const { db, settings, observability, objectStorage } = await services();
3051
+ const { db, settings, observability, objectStorage, bus } = await services();
2966
3052
  assertSandboxDrainInputTiming(input);
2967
3053
  const drainSettings = settings.sandboxSnapshotTimeoutMs === input.snapshotTimeoutMs ? settings : { ...settings, sandboxSnapshotTimeoutMs: input.snapshotTimeoutMs };
2968
3054
  const row = input.target;
@@ -2982,7 +3068,8 @@ function createSandboxLeaseActivities(services, options = {}) {
2982
3068
  terminateBox,
2983
3069
  probeDrainableProvider,
2984
3070
  captureAttempt,
2985
- objectStorage
3071
+ objectStorage,
3072
+ bus
2986
3073
  );
2987
3074
  return { status: drainedCold ? "terminated" : "skipped" };
2988
3075
  } catch (error) {
@@ -3178,7 +3265,7 @@ function createSandboxLeaseActivities(services, options = {}) {
3178
3265
  timeoutClass: plan.timeoutClass,
3179
3266
  snapshotTimeoutMs: plan.snapshotTimeoutMs,
3180
3267
  captureTimeoutMs: plan.captureTimeoutMs,
3181
- operationId: randomUUID2()
3268
+ operationId: randomUUID3()
3182
3269
  })
3183
3270
  )
3184
3271
  );
@@ -3617,6 +3704,24 @@ async function reconcileTerminalRetainedProcesses(db, settings, observability, p
3617
3704
  sessionId: process.sessionId,
3618
3705
  processId: process.id
3619
3706
  };
3707
+ if (process.ownerActorKind === "turn" && process.providerBackend === "modal" && !proof && !claim.ownerState.startsWith("background_")) {
3708
+ try {
3709
+ const command = await recoverManagedSessionBackgroundCommand(db, {
3710
+ ...processScope,
3711
+ expected,
3712
+ reconciliationClaimId: claim.claimId
3713
+ });
3714
+ if (command) {
3715
+ claim.ownerState = `background_${command.state}`;
3716
+ recordRetainedProcessReconciliation(observability, "background_recovered");
3717
+ }
3718
+ } catch (error) {
3719
+ observability.warn("sandbox reaper: retained-command background recovery failed", {
3720
+ processId: process.id,
3721
+ error: error instanceof Error ? error.message : String(error)
3722
+ });
3723
+ }
3724
+ }
3620
3725
  const storedCommandPersistence = retainedProviderCommandPersistence(
3621
3726
  db,
3622
3727
  processScope,
@@ -4608,7 +4713,7 @@ function sandboxDrainReason(lease) {
4608
4713
  if (lease.rotationRequestedAt === null) return "idle";
4609
4714
  return lease.rotationReason ?? "rotation_requested";
4610
4715
  }
4611
- async function terminateDrainableBox(db, settings, row, observability, terminateBox, probeDrainableProvider, attempt, objectStorage) {
4716
+ async function terminateDrainableBox(db, settings, row, observability, terminateBox, probeDrainableProvider, attempt, objectStorage, bus = null) {
4612
4717
  const { accountId } = await rlsContextForWorkspace(db, row.workspaceId);
4613
4718
  const lease = await readLease2(db, row.workspaceId, row.sandboxGroupId);
4614
4719
  if (!lease) {
@@ -4922,18 +5027,31 @@ async function terminateDrainableBox(db, settings, row, observability, terminate
4922
5027
  }
4923
5028
  }
4924
5029
  const providerMissing = providerMissingBeforeCapture || (typeof termination === "boolean" ? false : termination.providerMissingBeforeCapture);
4925
- const { wentCold } = await confirmDrainCold(db, {
5030
+ const { wentCold, backgroundCommandEvents } = await confirmDrainCold(db, {
4926
5031
  accountId,
4927
5032
  workspaceId: row.workspaceId,
4928
5033
  sandboxGroupId: row.sandboxGroupId,
4929
5034
  expectedEpoch: row.leaseEpoch,
4930
5035
  ...captureClaim ? { expectedCaptureId: captureClaim.id } : {},
4931
- providerMissingBeforeCapture: providerMissing
5036
+ providerMissingBeforeCapture: providerMissing,
5037
+ idleCommandContainmentMs: settings.sandboxIdleCommandContainmentMs
5038
+ });
5039
+ await publishDurableSessionEvents(bus, row.workspaceId, backgroundCommandEvents, (error) => {
5040
+ observability.warn("sandbox reaper: contained command event fanout failed", {
5041
+ sandboxGroupId: row.sandboxGroupId,
5042
+ error: error instanceof Error ? error.message : String(error)
5043
+ });
4932
5044
  });
4933
5045
  if (wentCold) {
4934
5046
  if (providerMissing) {
4935
5047
  recordSandboxProviderMissingBeforeCapture(observability, backend);
4936
5048
  }
5049
+ if (lease.unobservableCommandDrainIds?.length) {
5050
+ recordSandboxCommandContainment(
5051
+ observability,
5052
+ providerMissing ? "provider_missing" : "contained"
5053
+ );
5054
+ }
4937
5055
  try {
4938
5056
  await appendSessionEventToSandboxGroup(db, row.workspaceId, row.sandboxGroupId, {
4939
5057
  type: "sandbox.box.terminated",
@@ -5123,7 +5241,7 @@ async function terminateProviderBox(settings, lease, observability, persistArchi
5123
5241
  session,
5124
5242
  Date.now(),
5125
5243
  {
5126
- requestId: providerCaptureRequestId ?? randomUUID2(),
5244
+ requestId: providerCaptureRequestId ?? randomUUID3(),
5127
5245
  strategy: liveCapturePolicy.strategy
5128
5246
  },
5129
5247
  diskBackedArchives
@@ -5317,7 +5435,7 @@ import {
5317
5435
  upsertScheduledSessionGoalForRun,
5318
5436
  withSessionActivityRlsContext
5319
5437
  } from "@opengeni/db";
5320
- import { publishDurableSessionEvents } from "@opengeni/events";
5438
+ import { publishDurableSessionEvents as publishDurableSessionEvents2 } from "@opengeni/events";
5321
5439
  import {
5322
5440
  allowedFirstPartyMcpToolsForSession,
5323
5441
  resolveFirstPartyMcpToolPolicy,
@@ -6458,7 +6576,7 @@ function createScheduledTaskActivities(services) {
6458
6576
  events: started.events
6459
6577
  });
6460
6578
  } else {
6461
- await publishDurableSessionEvents(
6579
+ await publishDurableSessionEvents2(
6462
6580
  bus,
6463
6581
  task.workspaceId,
6464
6582
  session.id,
@@ -6501,7 +6619,7 @@ function createScheduledTaskActivities(services) {
6501
6619
  if (deferPublications) {
6502
6620
  deferredEvents.push({ sessionId: session.id, events: started.events });
6503
6621
  } else {
6504
- await publishDurableSessionEvents(
6622
+ await publishDurableSessionEvents2(
6505
6623
  bus,
6506
6624
  task.workspaceId,
6507
6625
  session.id,
@@ -6530,7 +6648,7 @@ function createScheduledTaskActivities(services) {
6530
6648
  if (deferPublications) {
6531
6649
  deferredEvents.push({ sessionId: session.id, events: titleEvents });
6532
6650
  } else {
6533
- await publishDurableSessionEvents(bus, task.workspaceId, session.id, titleEvents);
6651
+ await publishDurableSessionEvents2(bus, task.workspaceId, session.id, titleEvents);
6534
6652
  }
6535
6653
  }
6536
6654
  const scheduledUpdate = await addSessionSystemUpdateWithSourceMutation(
@@ -6617,7 +6735,7 @@ function createScheduledTaskActivities(services) {
6617
6735
  events: scheduledUpdate.events
6618
6736
  });
6619
6737
  } else {
6620
- await publishDurableSessionEvents(
6738
+ await publishDurableSessionEvents2(
6621
6739
  bus,
6622
6740
  task.workspaceId,
6623
6741
  session.id,
@@ -6744,7 +6862,7 @@ function createScheduledTaskActivities(services) {
6744
6862
  events: bundled.events
6745
6863
  });
6746
6864
  } else {
6747
- await publishDurableSessionEvents(
6865
+ await publishDurableSessionEvents2(
6748
6866
  bus,
6749
6867
  task.workspaceId,
6750
6868
  session.id,
@@ -6826,7 +6944,7 @@ function createScheduledTaskActivities(services) {
6826
6944
  });
6827
6945
  }
6828
6946
  for (const deferred of deferredEvents) {
6829
- await publishDurableSessionEvents(
6947
+ await publishDurableSessionEvents2(
6830
6948
  bus,
6831
6949
  task.workspaceId,
6832
6950
  deferred.sessionId,
@@ -7058,7 +7176,7 @@ async function seedScheduledGeneratedSessionRoute(input) {
7058
7176
  if (input.deferPublications) {
7059
7177
  input.deferredEvents.push({ sessionId: input.session.id, events: failed.events });
7060
7178
  } else {
7061
- await publishDurableSessionEvents(
7179
+ await publishDurableSessionEvents2(
7062
7180
  input.bus,
7063
7181
  input.task.workspaceId,
7064
7182
  input.session.id,
@@ -7328,7 +7446,7 @@ async function recoverBoundScheduledTaskDispatch(input) {
7328
7446
  });
7329
7447
  workflowId = started.temporalWorkflowId;
7330
7448
  if (started.events.length > 0) {
7331
- await publishDurableSessionEvents(input.bus, task.workspaceId, session.id, started.events);
7449
+ await publishDurableSessionEvents2(input.bus, task.workspaceId, session.id, started.events);
7332
7450
  }
7333
7451
  if (task.runMode === "reusable_session") {
7334
7452
  await materializeScheduledTaskReusableSessionFromRun(input.db, {
@@ -7347,7 +7465,7 @@ async function recoverBoundScheduledTaskDispatch(input) {
7347
7465
  taskName: task.name
7348
7466
  });
7349
7467
  if (titleEvents.length > 0) {
7350
- await publishDurableSessionEvents(input.bus, task.workspaceId, session.id, titleEvents);
7468
+ await publishDurableSessionEvents2(input.bus, task.workspaceId, session.id, titleEvents);
7351
7469
  }
7352
7470
  }
7353
7471
  const scheduledUpdate = await addSessionSystemUpdateWithSourceMutation(
@@ -7440,7 +7558,7 @@ async function recoverBoundScheduledTaskDispatch(input) {
7440
7558
  recordUserMessageAccepted(input.observability, { surface: "scheduled" });
7441
7559
  }
7442
7560
  if (scheduledUpdate.added && scheduledUpdate.events.length > 0) {
7443
- await publishDurableSessionEvents(
7561
+ await publishDurableSessionEvents2(
7444
7562
  input.bus,
7445
7563
  task.workspaceId,
7446
7564
  session.id,
@@ -7796,9 +7914,10 @@ import {
7796
7914
  expireSessionHumanInputRequest,
7797
7915
  markSessionAttemptQuiesced,
7798
7916
  requireSession as requireSession2,
7799
- settleSessionIdleWithParentOutbox
7917
+ settleSessionIdleWithParentOutbox,
7918
+ SANDBOX_SETUP_RECOVERY_LIMIT
7800
7919
  } from "@opengeni/db";
7801
- import { publishDurableSessionEvents as publishDurableSessionEvents2 } from "@opengeni/events";
7920
+ import { publishDurableSessionEvents as publishDurableSessionEvents3 } from "@opengeni/events";
7802
7921
  import { CancelledFailure } from "@temporalio/activity";
7803
7922
  var WORKER_DEATH_MAX_REDISPATCHES = 3;
7804
7923
  function createSessionStateActivities(services, overrides = {}) {
@@ -7822,7 +7941,7 @@ function createSessionStateActivities(services, overrides = {}) {
7822
7941
  const requireSessionFn = overrides.requireSession ?? requireSession2;
7823
7942
  const settleSessionIdleWithParentOutboxFn = overrides.settleSessionIdleWithParentOutbox ?? settleSessionIdleWithParentOutbox;
7824
7943
  const markSessionAttemptQuiescedFn = overrides.markSessionAttemptQuiesced ?? markSessionAttemptQuiesced;
7825
- const publishDurableSessionEventsFn = overrides.publishDurableSessionEvents ?? publishDurableSessionEvents2;
7944
+ const publishDurableSessionEventsFn = overrides.publishDurableSessionEvents ?? publishDurableSessionEvents3;
7826
7945
  const deliverFailedChildTurnToParentFn = overrides.deliverFailedChildTurnToParent ?? deliverFailedChildTurnToParent;
7827
7946
  const notifyParentOfChildIdleFn = overrides.notifyParentOfChildIdle ?? notifyParentOfChildIdle;
7828
7947
  const recordTurnsQueuedGaugeFn = overrides.recordTurnsQueuedGauge ?? recordTurnsQueuedGauge;
@@ -7911,12 +8030,16 @@ function createSessionStateActivities(services, overrides = {}) {
7911
8030
  const postClaimIdentityMatches = Boolean(
7912
8031
  postClaimRecovery && turn.id === postClaimRecovery.turnId && turn.triggerEventId === postClaimRecovery.triggerEventId && turn.executionGeneration === postClaimRecovery.executionGeneration
7913
8032
  );
8033
+ if (postClaimRecovery?.sandboxSetupRecoveryExhausted && !postClaimIdentityMatches) {
8034
+ return { action: "stale" };
8035
+ }
7914
8036
  const providerRecoveryCount = postClaimIdentityMatches ? postClaimRecovery?.providerRecoveryCount : void 0;
7915
8037
  const providerFailureCode = postClaimIdentityMatches ? postClaimRecovery?.providerFailureCode : void 0;
7916
8038
  const hasProviderRecoveryCount = providerRecoveryCount !== void 0;
7917
8039
  const hasProviderFailureCode = providerFailureCode !== void 0;
7918
8040
  const setupOutcomeUnknown = postClaimIdentityMatches && postClaimRecovery?.sandboxSetupOutcomeUnknown === true;
7919
- if (setupOutcomeUnknown && (hasProviderRecoveryCount || hasProviderFailureCode)) {
8041
+ const setupRecoveryExhausted = postClaimIdentityMatches && postClaimRecovery?.sandboxSetupRecoveryExhausted === true;
8042
+ if (setupOutcomeUnknown && setupRecoveryExhausted || (setupOutcomeUnknown || setupRecoveryExhausted) && (hasProviderRecoveryCount || hasProviderFailureCode) || setupRecoveryExhausted && turn.metadata?.providerRecoveryCount !== SANDBOX_SETUP_RECOVERY_LIMIT) {
7920
8043
  return { action: "stale" };
7921
8044
  }
7922
8045
  if (hasProviderRecoveryCount !== hasProviderFailureCode) {
@@ -7932,13 +8055,20 @@ function createSessionStateActivities(services, overrides = {}) {
7932
8055
  turnId: turn.id,
7933
8056
  triggerEventId: turn.triggerEventId,
7934
8057
  attemptId: input.attemptId,
7935
- reason: setupOutcomeUnknown ? "sandbox_command_start_outcome_unknown" : providerFailureCode ?? "claimed_attempt_database_failure",
8058
+ reason: setupOutcomeUnknown ? "sandbox_command_start_outcome_unknown" : setupRecoveryExhausted ? "sandbox_command_start_recovery_exhausted" : providerFailureCode ?? "claimed_attempt_database_failure",
7936
8059
  ...setupOutcomeUnknown ? { sandboxSetupOutcomeUnknown: true } : {},
8060
+ ...setupRecoveryExhausted ? { sandboxSetupRecoveryExhausted: true } : {},
7937
8061
  ...providerRecoveryCount !== void 0 ? { providerRecoveryCount } : {},
7938
8062
  detail: {
7939
- code: setupOutcomeUnknown ? "sandbox_command_start_outcome_unknown" : providerFailureCode ?? recoveredClaimCode,
7940
- retryable: !setupOutcomeUnknown,
8063
+ code: setupOutcomeUnknown ? "sandbox_command_start_outcome_unknown" : setupRecoveryExhausted ? "sandbox_command_start_recovery_exhausted" : providerFailureCode ?? recoveredClaimCode,
8064
+ retryable: !setupOutcomeUnknown && !setupRecoveryExhausted,
7941
8065
  ...setupOutcomeUnknown ? { setupOutcome: "unknown", replay: "blocked" } : {},
8066
+ ...setupRecoveryExhausted ? {
8067
+ setupOutcome: "not_started",
8068
+ replay: "blocked",
8069
+ recoveryExhausted: true,
8070
+ providerRecoveryCount: SANDBOX_SETUP_RECOVERY_LIMIT
8071
+ } : {},
7942
8072
  ...providerRecoveryCount !== void 0 ? {
7943
8073
  databaseFailureCode: recoveredClaimCode,
7944
8074
  providerRecoveryCount
@@ -8374,6 +8504,7 @@ function createControlActivitiesFromServices(services, resolveDocumentServices)
8374
8504
  ...createBrowserStateArtifactMaintenanceActivities(services),
8375
8505
  ...createBrowserDeadlineCheckpointActivities(services),
8376
8506
  ...createFileUploadReaperActivities(services),
8507
+ ...createModelCallFactReconcilerActivities(services),
8377
8508
  ...createRetainedScreenshotMaintenanceActivities(services),
8378
8509
  ...createWorkflowWakeActivities(services),
8379
8510
  ...createSandboxLeaseActivities(services)
@@ -8394,4 +8525,4 @@ export {
8394
8525
  createControlActivities,
8395
8526
  createControlActivitiesFromServices
8396
8527
  };
8397
- //# sourceMappingURL=activities-control-3HAH4FMG.js.map
8528
+ //# sourceMappingURL=activities-control-3BY4IJKL.js.map