@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
@@ -4,6 +4,7 @@ import {
4
4
  PostCompactionContinuationEmptyError,
5
5
  SandboxDeadlineRotationError,
6
6
  agentRunFailurePayload,
7
+ agentRunRecoveryFailurePayload,
7
8
  armAndReconcileCodexCapacityWait,
8
9
  armTurnQuiescenceWatchdog,
9
10
  assertAgentStreamNotCancelled,
@@ -31,6 +32,7 @@ import {
31
32
  compactionFailureReasonFromError,
32
33
  compactionFailureTurnEventPayload,
33
34
  computeIdleDelayMs,
35
+ createClaudeUsageObserver,
34
36
  createFreshSandboxReadinessReplacementBudget,
35
37
  createKnowledgeSourceSyncActivities,
36
38
  createModelHistoryAttachmentProjector,
@@ -95,7 +97,7 @@ import {
95
97
  withFirstPartyTools,
96
98
  wrapLazyTurnBoxWithRouting,
97
99
  wrapTurnBoxWithRouting
98
- } from "./chunk-3K3ULWEE.js";
100
+ } from "./chunk-PA7Z55P4.js";
99
101
  import {
100
102
  StreamTimingMetrics,
101
103
  makeMachineOpObserver,
@@ -127,7 +129,7 @@ import {
127
129
  runtimeMetricsHooksForObservability,
128
130
  sandboxAutomaticRecoveryOutcome,
129
131
  turnLifecycleMetricsFor
130
- } from "./chunk-YG27NEMX.js";
132
+ } from "./chunk-YOI3Z3GF.js";
131
133
  import {
132
134
  __export
133
135
  } from "./chunk-PZ5AY32C.js";
@@ -183,82 +185,6 @@ import {
183
185
  import { codexUpstreamModelSlugs } from "@opengeni/config";
184
186
  import { parseModelProvidersJson } from "@opengeni/config";
185
187
  import { withClaudeUsageObserver } from "@opengeni/runtime";
186
-
187
- // src/activities/agent-turn/claude-usage-observer.ts
188
- import {
189
- emptyClaudeUsage,
190
- mergeClaudeUsage,
191
- parseClaudeUsageHeaders
192
- } from "@opengeni/config";
193
- async function createClaudeUsageObserver(providers, latest, readCredential) {
194
- const bindings = await Promise.all(
195
- providers.filter(
196
- (provider) => provider.kind === "claude-subscription-workspace" || provider.kind === "claude-subscription-organization"
197
- ).map(async (provider) => {
198
- const scope = provider.kind === "claude-subscription-workspace" ? "workspace" : "organization";
199
- const binding = provider.anthropic?.credentialBinding;
200
- if (binding && provider.apiKey)
201
- return [
202
- provider.id,
203
- {
204
- scope,
205
- token: provider.apiKey,
206
- expectedConnectionId: binding.connectionId,
207
- expectedCredentialVersion: binding.credentialVersion
208
- }
209
- ];
210
- const credential = await readCredential(scope).catch(() => null);
211
- if (!credential || credential.token !== provider.apiKey) return null;
212
- return [
213
- provider.id,
214
- {
215
- scope,
216
- token: credential.token,
217
- expectedConnectionId: credential.connectionId,
218
- expectedCredentialVersion: credential.credentialVersion
219
- }
220
- ];
221
- })
222
- );
223
- const captured = new Map(bindings.filter((binding) => binding !== null));
224
- const observe2 = (providerId, response) => {
225
- const binding = captured.get(providerId);
226
- if (!binding) return;
227
- const { scope, ...identity } = binding;
228
- const previous = latest.get(scope);
229
- let observation = parseClaudeUsageHeaders(response.headers);
230
- if (observation && previous?.observation) {
231
- const merged = mergeClaudeUsage(
232
- mergeClaudeUsage(emptyClaudeUsage(binding.expectedCredentialVersion), previous.observation),
233
- observation
234
- );
235
- observation = {
236
- windows: merged.windows,
237
- observedAt: merged.observedAt,
238
- source: merged.source
239
- };
240
- }
241
- if (observation || response.status === 401)
242
- latest.set(scope, {
243
- ...identity,
244
- ...previous?.observation && !observation ? { observation: previous.observation } : {},
245
- ...observation ? { observation } : {},
246
- ...response.status === 401 ? { refresh: { status: "reconnect", checkedAt: (/* @__PURE__ */ new Date()).toISOString() } } : {}
247
- });
248
- };
249
- return Object.assign(observe2, {
250
- binding(providerId) {
251
- return captured.get(providerId);
252
- },
253
- renew(providerId, credential) {
254
- const binding = captured.get(providerId);
255
- if (binding && binding.expectedConnectionId === credential.connectionId && binding.expectedCredentialVersion === credential.credentialVersion)
256
- captured.set(providerId, { ...binding, token: credential.token });
257
- }
258
- });
259
- }
260
-
261
- // src/activities/agent-turn/run.ts
262
188
  import {
263
189
  xaiSubscriptionRequestStorage
264
190
  } from "@opengeni/xai-subscription";
@@ -1261,161 +1187,72 @@ import {
1261
1187
  heartbeatXaiCredentialLeaseUntil
1262
1188
  } from "@opengeni/db";
1263
1189
 
1264
- // src/activities/agent-turn/codex.ts
1265
- import {
1266
- listCodexAccountStatuses,
1267
- fetchCodexUsageForAccount
1268
- } from "@opengeni/db";
1269
- import { createHash as createHash2 } from "crypto";
1270
- function codexWorkspaceMetricKey(workspaceId) {
1271
- return createHash2("sha256").update(workspaceId).digest("hex").slice(0, 12);
1272
- }
1273
- function acceptsPromptCacheKeyForTurn(resolvedModel) {
1274
- if (!resolvedModel) {
1275
- return true;
1276
- }
1277
- return resolvedModel.provider.builtin === true || resolvedModel.provider.kind === "codex-subscription" || // Native Claude consumes this internal key as session identity; it never
1278
- // sends OpenAI's prompt_cache_key field to the Messages endpoint.
1279
- resolvedModel.provider.api === "anthropic-messages";
1280
- }
1281
- async function refreshCappedCodexUsageRows(db, settings, workspaceId, accounts, capacitySignals, acceptedTurnId) {
1282
- const now = /* @__PURE__ */ new Date();
1283
- const stale = accounts.filter(
1284
- (account) => account.status === "active" && codexAccountNeedsLiveCapacityRefresh(account, now)
1285
- );
1286
- if (stale.length === 0) {
1287
- return accounts;
1288
- }
1289
- await refreshCodexUsageAndRepairCapacityWaiters(
1290
- stale.map(
1291
- (account) => () => fetchCodexUsageForAccount(db, settings, workspaceId, account.id, void 0, acceptedTurnId)
1292
- ),
1293
- () => signalPendingCodexCapacityWakeTargets({ db, ...capacitySignals }, workspaceId)
1294
- );
1295
- return listCodexAccountStatuses(db, workspaceId, acceptedTurnId).catch(() => accounts);
1296
- }
1297
- function codexCredentialLeaseDeadlineExpired(confirmedUntilMs, nowMs = performance.now()) {
1298
- return confirmedUntilMs === null || !Number.isFinite(confirmedUntilMs) || confirmedUntilMs <= nowMs;
1299
- }
1300
-
1301
- // src/activities/agent-turn/credential-leases.ts
1302
- var CodexCredentialLeaseLostError = class extends Error {
1303
- constructor(reason) {
1304
- super("Codex credential lease is not usable for provider dispatch");
1305
- this.reason = reason;
1306
- this.name = "CodexCredentialLeaseLostError";
1307
- }
1308
- code = "codex_credential_lease_lost";
1309
- };
1310
- var CodexTurnLease = class {
1311
- constructor(deps) {
1312
- this.deps = deps;
1190
+ // src/activities/agent-turn/subscription-lease.ts
1191
+ var SubscriptionTurnLease = class {
1192
+ constructor(leaseDeps) {
1193
+ this.leaseDeps = leaseDeps;
1194
+ if (!Number.isFinite(leaseDeps.ttlMs) || leaseDeps.ttlMs <= 0)
1195
+ throw new Error("Subscription lease TTL must be positive");
1196
+ this.now = leaseDeps.now ?? (() => performance.now());
1313
1197
  }
1314
1198
  held = false;
1315
1199
  lost = false;
1316
1200
  lossReason = null;
1317
1201
  holderId = null;
1318
1202
  generation = null;
1319
- // Monotonic worker deadline, not a comparison between the Postgres and
1320
- // worker wall clocks. It is advanced only after a database renewal confirms,
1321
- // from the request START + TTL; slow queries therefore shorten (never extend)
1322
- // the conservative ownership window.
1323
1203
  confirmedUntilMs = null;
1324
1204
  heartbeatInFlight = false;
1325
1205
  heartbeatTimer;
1206
+ now;
1207
+ expired = (deadline) => deadline === null || !Number.isFinite(deadline) || this.now() >= deadline;
1326
1208
  markLost = (reason) => {
1327
1209
  if (this.lost) return;
1328
1210
  this.lost = true;
1329
1211
  this.lossReason = reason;
1330
- this.deps.observability.incrementCounter({
1331
- name: "opengeni_codex_lease_renewals_total",
1332
- help: "Codex lease renewal checkpoints by outcome and reason.",
1333
- labels: { workspace_key: this.deps.codexWorkspaceKey, outcome: "lost", reason }
1334
- });
1335
- this.deps.observability.warn("Codex credential lease was lost during an active turn", {
1336
- workspaceId: this.deps.workspaceId,
1337
- turnId: this.deps.getTurnId(),
1338
- reason
1339
- });
1212
+ this.leaseDeps.onLost(reason);
1340
1213
  };
1341
- /** Fail closed at the last worker-confirmed lease deadline before dispatch. */
1342
1214
  assertUsable = () => {
1343
- if (this.lost) {
1344
- throw new CodexCredentialLeaseLostError(this.lossReason ?? "not_found");
1345
- }
1346
- if (!this.held || this.holderId === null || this.generation === null || codexCredentialLeaseDeadlineExpired(this.confirmedUntilMs)) {
1215
+ if (this.lost) throw this.leaseDeps.lostError(this.lossReason ?? "not_found");
1216
+ if (!this.held || this.holderId === null || this.generation === null || this.expired(this.confirmedUntilMs)) {
1347
1217
  this.markLost("deadline");
1348
- throw new CodexCredentialLeaseLostError("deadline");
1218
+ throw this.leaseDeps.lostError("deadline");
1349
1219
  }
1350
1220
  };
1351
- renew = async (reason) => {
1352
- const turnId = this.deps.getTurnId();
1353
- if (!turnId || !this.held || !this.holderId || this.generation === null || this.lost) {
1354
- return;
1355
- }
1356
- if (codexCredentialLeaseDeadlineExpired(this.confirmedUntilMs)) {
1221
+ renew = async (reason = "timer") => {
1222
+ const turnId = this.leaseDeps.getTurnId();
1223
+ if (!turnId || !this.held || !this.holderId || this.generation === null || this.lost) return;
1224
+ if (this.expired(this.confirmedUntilMs)) {
1357
1225
  this.markLost("deadline");
1358
1226
  return;
1359
1227
  }
1360
1228
  if (this.heartbeatInFlight) return;
1361
1229
  this.heartbeatInFlight = true;
1362
- const priorConfirmedUntilMs = this.confirmedUntilMs;
1363
- const renewalStartedAtMs = performance.now();
1230
+ const priorDeadline = this.confirmedUntilMs;
1231
+ const startedAt = this.now();
1232
+ const identity = { turnId, holderId: this.holderId, generation: this.generation };
1364
1233
  try {
1365
- const renewedUntil = await heartbeatCodexCredentialLeaseUntil(
1366
- this.deps.db,
1367
- this.deps.accountId,
1368
- this.deps.workspaceId,
1369
- turnId,
1370
- this.holderId,
1371
- this.generation,
1372
- CODEX_CREDENTIAL_LEASE_TTL_MS
1373
- );
1374
- if (!renewedUntil) {
1375
- this.markLost("not_found");
1376
- } else if (codexCredentialLeaseDeadlineExpired(priorConfirmedUntilMs) || codexCredentialLeaseDeadlineExpired(renewalStartedAtMs + CODEX_CREDENTIAL_LEASE_TTL_MS)) {
1234
+ const renewedUntil = await this.leaseDeps.heartbeat(identity);
1235
+ if (!this.held || this.lost || this.leaseDeps.getTurnId() !== identity.turnId || this.holderId !== identity.holderId || this.generation !== identity.generation)
1236
+ return;
1237
+ if (!renewedUntil) this.markLost("not_found");
1238
+ else if (this.expired(priorDeadline) || this.expired(startedAt + this.leaseDeps.ttlMs))
1377
1239
  this.markLost("deadline");
1378
- } else {
1379
- this.confirmedUntilMs = renewalStartedAtMs + CODEX_CREDENTIAL_LEASE_TTL_MS;
1380
- this.deps.observability.incrementCounter({
1381
- name: "opengeni_codex_lease_renewals_total",
1382
- help: "Codex lease renewal checkpoints by outcome and reason.",
1383
- labels: {
1384
- workspace_key: this.deps.codexWorkspaceKey,
1385
- outcome: "completed",
1386
- reason
1387
- }
1388
- });
1240
+ else {
1241
+ this.confirmedUntilMs = startedAt + this.leaseDeps.ttlMs;
1242
+ this.leaseDeps.onRenewed?.(reason);
1389
1243
  }
1390
1244
  } catch (error51) {
1391
- if (codexCredentialLeaseDeadlineExpired(this.confirmedUntilMs)) {
1392
- this.markLost("deadline");
1245
+ if (!this.held || this.lost || this.leaseDeps.getTurnId() !== identity.turnId || this.holderId !== identity.holderId || this.generation !== identity.generation)
1393
1246
  return;
1394
- }
1395
- this.deps.observability.warn("Codex credential lease heartbeat failed", {
1396
- workspaceId: this.deps.workspaceId,
1397
- turnId,
1398
- reason,
1399
- ...safeErrorDiagnostic(error51)
1400
- });
1401
- this.deps.observability.incrementCounter({
1402
- name: "opengeni_codex_lease_renewals_total",
1403
- help: "Codex lease renewal checkpoints by outcome and reason.",
1404
- labels: {
1405
- workspace_key: this.deps.codexWorkspaceKey,
1406
- outcome: "error",
1407
- reason
1408
- }
1409
- });
1247
+ if (this.expired(this.confirmedUntilMs)) this.markLost("deadline");
1248
+ else this.leaseDeps.onError(error51, reason);
1410
1249
  } finally {
1411
1250
  this.heartbeatInFlight = false;
1412
1251
  }
1413
1252
  };
1414
1253
  startHeartbeat = () => {
1415
- if (!this.deps.getTurnId() || this.heartbeatTimer) return;
1416
- this.heartbeatTimer = setInterval(() => {
1417
- void this.renew("timer");
1418
- }, 6e4);
1254
+ if (!this.leaseDeps.getTurnId() || this.heartbeatTimer) return;
1255
+ this.heartbeatTimer = setInterval(() => void this.renew("timer"), 6e4);
1419
1256
  this.heartbeatTimer.unref?.();
1420
1257
  };
1421
1258
  stopHeartbeat = () => {
@@ -1424,79 +1261,94 @@ var CodexTurnLease = class {
1424
1261
  this.heartbeatTimer = void 0;
1425
1262
  };
1426
1263
  };
1427
- var XaiTurnLease = class {
1264
+
1265
+ // src/activities/agent-turn/credential-leases.ts
1266
+ var CodexCredentialLeaseLostError = class extends Error {
1267
+ constructor(reason) {
1268
+ super("Codex credential lease is not usable for provider dispatch");
1269
+ this.reason = reason;
1270
+ this.name = "CodexCredentialLeaseLostError";
1271
+ }
1272
+ code = "codex_credential_lease_lost";
1273
+ };
1274
+ var CodexTurnLease = class extends SubscriptionTurnLease {
1428
1275
  constructor(deps) {
1429
- this.deps = deps;
1276
+ super({
1277
+ ttlMs: CODEX_CREDENTIAL_LEASE_TTL_MS,
1278
+ getTurnId: deps.getTurnId,
1279
+ heartbeat: ({ turnId, holderId, generation }) => heartbeatCodexCredentialLeaseUntil(
1280
+ deps.db,
1281
+ deps.accountId,
1282
+ deps.workspaceId,
1283
+ turnId,
1284
+ holderId,
1285
+ generation,
1286
+ CODEX_CREDENTIAL_LEASE_TTL_MS
1287
+ ),
1288
+ lostError: (reason) => new CodexCredentialLeaseLostError(reason),
1289
+ onLost: (reason) => {
1290
+ deps.observability.incrementCounter({
1291
+ name: "opengeni_codex_lease_renewals_total",
1292
+ help: "Codex lease renewal checkpoints by outcome and reason.",
1293
+ labels: { workspace_key: deps.codexWorkspaceKey, outcome: "lost", reason }
1294
+ });
1295
+ deps.observability.warn("Codex credential lease was lost during an active turn", {
1296
+ workspaceId: deps.workspaceId,
1297
+ turnId: deps.getTurnId(),
1298
+ reason
1299
+ });
1300
+ },
1301
+ onRenewed: (reason) => deps.observability.incrementCounter({
1302
+ name: "opengeni_codex_lease_renewals_total",
1303
+ help: "Codex lease renewal checkpoints by outcome and reason.",
1304
+ labels: { workspace_key: deps.codexWorkspaceKey, outcome: "completed", reason }
1305
+ }),
1306
+ onError: (error51, reason) => {
1307
+ deps.observability.warn("Codex credential lease heartbeat failed", {
1308
+ workspaceId: deps.workspaceId,
1309
+ turnId: deps.getTurnId(),
1310
+ reason,
1311
+ ...safeErrorDiagnostic(error51)
1312
+ });
1313
+ deps.observability.incrementCounter({
1314
+ name: "opengeni_codex_lease_renewals_total",
1315
+ help: "Codex lease renewal checkpoints by outcome and reason.",
1316
+ labels: { workspace_key: deps.codexWorkspaceKey, outcome: "error", reason }
1317
+ });
1318
+ }
1319
+ });
1430
1320
  }
1431
- held = false;
1432
- lost = false;
1321
+ };
1322
+ var XaiTurnLease = class extends SubscriptionTurnLease {
1433
1323
  subjectId = null;
1434
- holderId = null;
1435
- generation = null;
1436
- confirmedUntilMs = null;
1437
- heartbeatInFlight = false;
1438
- heartbeatTimer;
1439
- markLost = (reason) => {
1440
- if (this.lost) return;
1441
- this.lost = true;
1442
- this.deps.observability.warn("xAI credential lease was lost during an active turn", {
1443
- workspaceId: this.deps.workspaceId,
1444
- turnId: this.deps.getTurnId(),
1445
- reason
1446
- });
1447
- };
1448
- renew = async () => {
1449
- const turnId = this.deps.getTurnId();
1450
- if (!turnId || !this.held || !this.subjectId || !this.holderId || this.generation === null || this.lost) {
1451
- return;
1452
- }
1453
- if (codexCredentialLeaseDeadlineExpired(this.confirmedUntilMs)) {
1454
- this.markLost("deadline");
1455
- return;
1456
- }
1457
- if (this.heartbeatInFlight) return;
1458
- this.heartbeatInFlight = true;
1459
- const renewalStartedAtMs = performance.now();
1460
- try {
1461
- const renewedUntil = await heartbeatXaiCredentialLeaseUntil(this.deps.db, {
1462
- workspaceId: this.deps.workspaceId,
1324
+ constructor(deps) {
1325
+ super({
1326
+ ttlMs: XAI_CREDENTIAL_LEASE_TTL_MS,
1327
+ getTurnId: deps.getTurnId,
1328
+ heartbeat: ({ turnId, holderId, generation }) => this.subjectId ? heartbeatXaiCredentialLeaseUntil(deps.db, {
1329
+ workspaceId: deps.workspaceId,
1463
1330
  subjectId: this.subjectId,
1464
1331
  turnId,
1465
- holderId: this.holderId,
1466
- generation: this.generation,
1332
+ holderId,
1333
+ generation,
1467
1334
  leaseTtlMs: XAI_CREDENTIAL_LEASE_TTL_MS
1468
- });
1469
- if (!renewedUntil) {
1470
- this.markLost("not_found");
1471
- } else {
1472
- this.confirmedUntilMs = renewalStartedAtMs + XAI_CREDENTIAL_LEASE_TTL_MS;
1473
- }
1474
- } catch (error51) {
1475
- if (codexCredentialLeaseDeadlineExpired(this.confirmedUntilMs)) {
1476
- this.markLost("deadline");
1477
- return;
1478
- }
1479
- this.deps.observability.warn("xAI credential lease heartbeat failed", {
1480
- workspaceId: this.deps.workspaceId,
1481
- turnId,
1335
+ }) : Promise.resolve(null),
1336
+ lostError: (reason) => Object.assign(new Error("SuperGrok credential lease is not usable for provider dispatch"), {
1337
+ code: "xai_credential_lease_lost",
1338
+ reason
1339
+ }),
1340
+ onLost: (reason) => deps.observability.warn("xAI credential lease was lost during an active turn", {
1341
+ workspaceId: deps.workspaceId,
1342
+ turnId: deps.getTurnId(),
1343
+ reason
1344
+ }),
1345
+ onError: (error51) => deps.observability.warn("xAI credential lease heartbeat failed", {
1346
+ workspaceId: deps.workspaceId,
1347
+ turnId: deps.getTurnId(),
1482
1348
  ...safeErrorDiagnostic(error51)
1483
- });
1484
- } finally {
1485
- this.heartbeatInFlight = false;
1486
- }
1487
- };
1488
- startHeartbeat = () => {
1489
- if (!this.deps.getTurnId() || this.heartbeatTimer) return;
1490
- this.heartbeatTimer = setInterval(() => {
1491
- void this.renew();
1492
- }, 6e4);
1493
- this.heartbeatTimer.unref?.();
1494
- };
1495
- stopHeartbeat = () => {
1496
- if (!this.heartbeatTimer) return;
1497
- clearInterval(this.heartbeatTimer);
1498
- this.heartbeatTimer = void 0;
1499
- };
1349
+ })
1350
+ });
1351
+ }
1500
1352
  };
1501
1353
  function createTurnCredentialLeases(deps) {
1502
1354
  const codex = new CodexTurnLease(deps);
@@ -1539,7 +1391,7 @@ import {
1539
1391
  settleGeneratedImageArtifactReady
1540
1392
  } from "@opengeni/db";
1541
1393
  import { retryWhileMissing as retryWhileMissing2 } from "@opengeni/storage";
1542
- import { createHash as createHash4 } from "crypto";
1394
+ import { createHash as createHash3 } from "crypto";
1543
1395
 
1544
1396
  // src/activities/retained-screenshots.ts
1545
1397
  import {
@@ -1563,7 +1415,7 @@ import {
1563
1415
  settleRetainedScreenshotArtifactReady
1564
1416
  } from "@opengeni/db";
1565
1417
  import { retryWhileMissing } from "@opengeni/storage";
1566
- import { createHash as createHash3 } from "crypto";
1418
+ import { createHash as createHash2 } from "crypto";
1567
1419
  var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71, 13, 10, 26, 10);
1568
1420
  var PNG_ALLOWED_CRITICAL_CHUNKS = /* @__PURE__ */ new Set(["IHDR", "PLTE", "IDAT", "IEND"]);
1569
1421
  var PNG_MAX_CHUNKS = 16384;
@@ -1847,7 +1699,7 @@ function validateComputerScreenshot(input, limits = {}) {
1847
1699
  bytes: input.bytes,
1848
1700
  mediaType: "image/png",
1849
1701
  sizeBytes: input.bytes.byteLength,
1850
- sha256: createHash3("sha256").update(input.bytes).digest("hex"),
1702
+ sha256: createHash2("sha256").update(input.bytes).digest("hex"),
1851
1703
  width,
1852
1704
  height
1853
1705
  };
@@ -1903,11 +1755,11 @@ function validateRetainableSessionImage(input, limits = {}) {
1903
1755
  bytes: input.bytes,
1904
1756
  ...identity,
1905
1757
  sizeBytes: input.bytes.byteLength,
1906
- sha256: createHash3("sha256").update(input.bytes).digest("hex")
1758
+ sha256: createHash2("sha256").update(input.bytes).digest("hex")
1907
1759
  };
1908
1760
  }
1909
1761
  function retainedScreenshotIdentity(input) {
1910
- const settlementKey = createHash3("sha256").update(
1762
+ const settlementKey = createHash2("sha256").update(
1911
1763
  input.kind === "browser_screenshot" ? "opengeni:browser-screenshot:v1\0" : "opengeni:computer-screenshot:v1\0"
1912
1764
  ).update(input.sessionId).update("\0").update(input.turnId).update("\0").update(input.attemptId).update("\0").update(input.toolCallId).update("\0").update(input.toolOutputId).digest("hex");
1913
1765
  const uuidBytes = Uint8Array.from(Buffer.from(settlementKey.slice(0, 32), "hex"));
@@ -2621,7 +2473,7 @@ function validateGeneratedImage(input) {
2621
2473
  }
2622
2474
  }
2623
2475
  function generatedImageIdentity(input) {
2624
- const hash2 = createHash4("sha256").update("opengeni:generated-image:v2\0").update(input.workspaceId).update("\0").update(input.sourceStrategy).update("\0").update(input.providerId).update("\0").update(input.providerBindingHash).update("\0");
2476
+ const hash2 = createHash3("sha256").update("opengeni:generated-image:v2\0").update(input.workspaceId).update("\0").update(input.sourceStrategy).update("\0").update(input.providerId).update("\0").update(input.providerBindingHash).update("\0");
2625
2477
  if (input.sourceStrategy === "native_hosted") {
2626
2478
  hash2.update(input.providerItemId);
2627
2479
  } else {
@@ -3378,7 +3230,7 @@ function completedToolCallFromSdkEvent(event) {
3378
3230
  }
3379
3231
 
3380
3232
  // src/activities/agent-turn/history-prefix.ts
3381
- import { createHash as createHash5 } from "crypto";
3233
+ import { createHash as createHash4 } from "crypto";
3382
3234
  import { normalizeProtocolJsonValue as normalizeProtocolJsonValue2, sanitizeHistoryItemsForModel as sanitizeHistoryItemsForModel2 } from "@opengeni/runtime";
3383
3235
  var HistoryPrefixGuard = class {
3384
3236
  persisted = [];
@@ -3404,7 +3256,7 @@ var HistoryPrefixGuard = class {
3404
3256
  }
3405
3257
  keys(items, truncationTokens) {
3406
3258
  return sanitizeHistoryItemsForModel2(items, truncationTokens).map(
3407
- (item) => createHash5("sha256").update(JSON.stringify(sorted(normalizeProtocolJsonValue2(item)))).digest("hex")
3259
+ (item) => createHash4("sha256").update(JSON.stringify(sorted(normalizeProtocolJsonValue2(item)))).digest("hex")
3408
3260
  );
3409
3261
  }
3410
3262
  };
@@ -3611,6 +3463,40 @@ function safeObserveHistogram(observability, input) {
3611
3463
  }
3612
3464
  }
3613
3465
 
3466
+ // src/activities/agent-turn/codex.ts
3467
+ import {
3468
+ listCodexAccountStatuses,
3469
+ fetchCodexUsageForAccount
3470
+ } from "@opengeni/db";
3471
+ import { createHash as createHash5 } from "crypto";
3472
+ function codexWorkspaceMetricKey(workspaceId) {
3473
+ return createHash5("sha256").update(workspaceId).digest("hex").slice(0, 12);
3474
+ }
3475
+ function acceptsPromptCacheKeyForTurn(resolvedModel) {
3476
+ if (!resolvedModel) {
3477
+ return true;
3478
+ }
3479
+ return resolvedModel.provider.builtin === true || resolvedModel.provider.kind === "codex-subscription" || // Native Claude consumes this internal key as session identity; it never
3480
+ // sends OpenAI's prompt_cache_key field to the Messages endpoint.
3481
+ resolvedModel.provider.api === "anthropic-messages";
3482
+ }
3483
+ async function refreshCappedCodexUsageRows(db, settings, workspaceId, accounts, capacitySignals, acceptedTurnId) {
3484
+ const now = /* @__PURE__ */ new Date();
3485
+ const stale = accounts.filter(
3486
+ (account) => account.status === "active" && codexAccountNeedsLiveCapacityRefresh(account, now)
3487
+ );
3488
+ if (stale.length === 0) {
3489
+ return accounts;
3490
+ }
3491
+ await refreshCodexUsageAndRepairCapacityWaiters(
3492
+ stale.map(
3493
+ (account) => () => fetchCodexUsageForAccount(db, settings, workspaceId, account.id, void 0, acceptedTurnId)
3494
+ ),
3495
+ () => signalPendingCodexCapacityWakeTargets({ db, ...capacitySignals }, workspaceId)
3496
+ );
3497
+ return listCodexAccountStatuses(db, workspaceId, acceptedTurnId).catch(() => accounts);
3498
+ }
3499
+
3614
3500
  // src/activities/agent-turn/turn-context.ts
3615
3501
  function createTurnContext(input) {
3616
3502
  return {
@@ -3809,7 +3695,7 @@ function startTurnFinalizationMonitor(input) {
3809
3695
  } catch {
3810
3696
  }
3811
3697
  },
3812
- terminateWorker: input.terminateWorker
3698
+ terminateWorker: input.requestWorkerDrain
3813
3699
  });
3814
3700
  slowTimer = setTimeout(
3815
3701
  () => diagnose(() => {
@@ -4671,6 +4557,7 @@ async function finalizeTurnAttempt(deps) {
4671
4557
  deps.eventing.heartbeatTimer = startActivityHeartbeat(deps.activityContext, details);
4672
4558
  const monitor = startTurnFinalizationMonitor({
4673
4559
  observability: deps.observability,
4560
+ ...deps.turnFinalizationTimeoutMs === void 0 ? {} : { timeoutMs: deps.turnFinalizationTimeoutMs },
4674
4561
  details,
4675
4562
  heartbeat: (value) => {
4676
4563
  try {
@@ -4678,7 +4565,7 @@ async function finalizeTurnAttempt(deps) {
4678
4565
  } catch {
4679
4566
  }
4680
4567
  },
4681
- terminateWorker: () => process.exit(1)
4568
+ requestWorkerDrain: deps.requestWorkerDrain
4682
4569
  });
4683
4570
  try {
4684
4571
  monitor.enter("tool_writers");
@@ -4912,12 +4799,12 @@ async function finalizeTurnAttemptSteps(deps, monitor) {
4912
4799
  );
4913
4800
  }
4914
4801
  monitor.enter("provider_leases");
4915
- for (const [scope, snapshot] of providerTurn.latestClaudeUsage) {
4802
+ for (const snapshot of providerTurn.latestClaudeUsage.values()) {
4916
4803
  await waitForTurnFinalizerStep(
4917
4804
  recordClaudeSubscriptionUsage(
4918
4805
  db,
4919
4806
  settings,
4920
- { accountId: input.accountId, workspaceId: input.workspaceId, scope },
4807
+ { accountId: input.accountId, workspaceId: input.workspaceId, scope: snapshot.scope },
4921
4808
  snapshot
4922
4809
  ).catch(() => null),
4923
4810
  finalizerSignal
@@ -5271,13 +5158,15 @@ import {
5271
5158
  settleCodexCredentialFailover,
5272
5159
  readLease,
5273
5160
  SandboxLeaseSupersededError,
5274
- isSessionEventPersistenceError as isSessionEventPersistenceError2
5161
+ isSessionEventPersistenceError as isSessionEventPersistenceError2,
5162
+ SANDBOX_SETUP_RECOVERY_LIMIT
5275
5163
  } from "@opengeni/db";
5276
5164
  import { publishDurableSessionEvents as publishDurableSessionEvents2 } from "@opengeni/events";
5277
5165
  import {
5278
5166
  maxTurnsExceededRunState,
5279
5167
  isModalTaskExecStartPreDispatchUnavailableError,
5280
- isModalCommandStartOutcomeUnknownError
5168
+ isModalCommandStartOutcomeUnknownError,
5169
+ isProviderCommandObservationUnavailableError
5281
5170
  } from "@opengeni/runtime";
5282
5171
  import { ApplicationFailure, CancelledFailure } from "@temporalio/activity";
5283
5172
  import { TurnExecutionPolicyDefinitionMismatchError } from "@opengeni/config";
@@ -6141,7 +6030,8 @@ async function settleTurnFailure(deps) {
6141
6030
  }
6142
6031
  }
6143
6032
  const recoveryTurnId = attempt.turnId;
6144
- if (isModalCommandStartOutcomeUnknownError(error51) && recoveryTurnId && attempt.triggerEventId && attempt.executionGeneration > 0) {
6033
+ const observationUnavailable = isProviderCommandObservationUnavailableError(error51);
6034
+ if ((isModalCommandStartOutcomeUnknownError(error51) || observationUnavailable) && recoveryTurnId && attempt.triggerEventId && attempt.executionGeneration > 0) {
6145
6035
  let recovery;
6146
6036
  try {
6147
6037
  if (eventing.turnStartedPublished) {
@@ -6153,10 +6043,10 @@ async function settleTurnFailure(deps) {
6153
6043
  turnId: recoveryTurnId,
6154
6044
  triggerEventId: attempt.triggerEventId,
6155
6045
  attemptId: input.attemptId,
6156
- reason: "sandbox_command_start_outcome_unknown",
6046
+ reason: observationUnavailable ? "sandbox_command_observation_unavailable" : "sandbox_command_start_outcome_unknown",
6157
6047
  sandboxSetupOutcomeUnknown: true,
6158
6048
  detail: {
6159
- code: "sandbox_command_start_outcome_unknown",
6049
+ code: observationUnavailable ? "sandbox_command_observation_unavailable" : "sandbox_command_start_outcome_unknown",
6160
6050
  retryable: false,
6161
6051
  setupOutcome: "unknown",
6162
6052
  replay: "blocked",
@@ -7218,7 +7108,39 @@ async function settleTurnFailure(deps) {
7218
7108
  attemptNumber: nextProviderRecoveryCount,
7219
7109
  retryAfterMs: providerRetryAfterMs(error51)
7220
7110
  });
7111
+ const setupRecoveryExhausted = earlyCommandStartUnavailable && recoveryResult.status === "exhausted" && attempt.providerRecoveryCount === SANDBOX_SETUP_RECOVERY_LIMIT;
7221
7112
  try {
7113
+ if (setupRecoveryExhausted) {
7114
+ const recovery = await requestSessionTurnRecovery(db, input.workspaceId, {
7115
+ sessionId: input.sessionId,
7116
+ turnId: attempt.turnId,
7117
+ triggerEventId: attempt.triggerEventId,
7118
+ attemptId: input.attemptId,
7119
+ reason: "sandbox_command_start_recovery_exhausted",
7120
+ sandboxSetupRecoveryExhausted: true,
7121
+ detail: {
7122
+ code: failure2.code,
7123
+ error: "Automatic sandbox setup recovery exhausted after five retries; the accepted turn remains parked without starting a command.",
7124
+ retryable: false,
7125
+ setupOutcome: "not_started",
7126
+ replay: "blocked",
7127
+ recoveryExhausted: true,
7128
+ providerRecoveryCount: SANDBOX_SETUP_RECOVERY_LIMIT
7129
+ }
7130
+ });
7131
+ if (recovery.action === "stale") {
7132
+ acknowledgeLostAttemptOwnership();
7133
+ control.activityStatus = "cancelled";
7134
+ control.turnMetricOutcome = "cancelled";
7135
+ return claimedResult({ status: "cancelled" });
7136
+ }
7137
+ acknowledgeRecoveryQuiescence();
7138
+ await publishDurableSessionEvents2(bus, input.workspaceId, input.sessionId, recovery.events);
7139
+ control.turnMetricOutcome = "recovering";
7140
+ control.activityStatus = "recovering";
7141
+ control.activityError = error51;
7142
+ return claimedResult({ status: "recovering" });
7143
+ }
7222
7144
  if (recoveryResult.status === "recovering") {
7223
7145
  if (!earlyRecoverableSetup) {
7224
7146
  await flushRuntimeBatcher();
@@ -7232,7 +7154,7 @@ async function settleTurnFailure(deps) {
7232
7154
  reason: failure2.code ?? "provider_unavailable",
7233
7155
  providerRecoveryCount: nextProviderRecoveryCount,
7234
7156
  detail: {
7235
- ...failure2,
7157
+ ...agentRunRecoveryFailurePayload(error51, failure2),
7236
7158
  continueDelayMs: recoveryResult.continueDelayMs,
7237
7159
  providerRecoveryCount: nextProviderRecoveryCount
7238
7160
  }
@@ -7288,6 +7210,12 @@ async function settleTurnFailure(deps) {
7288
7210
  failureCode: failure2.code ?? "provider_unavailable",
7289
7211
  providerRecoveryCount: nextProviderRecoveryCount
7290
7212
  }
7213
+ }) : setupRecoveryExhausted ? postClaimDatabaseRecoveryFailure({
7214
+ error: recoveryError,
7215
+ turnId: attempt.turnId,
7216
+ triggerEventId: attempt.triggerEventId,
7217
+ executionGeneration: attempt.executionGeneration,
7218
+ sandboxSetupRecoveryExhausted: true
7291
7219
  }) : null;
7292
7220
  if (postClaimRecovery) {
7293
7221
  control.activityStatus = "recovering";
@@ -10079,6 +10007,10 @@ async function runTurnStreamAttempt(deps) {
10079
10007
  }
10080
10008
  }
10081
10009
 
10010
+ // src/activities/agent-turn/claim.ts
10011
+ import { withDirectModelProviders } from "@opengeni/config";
10012
+ import { loadDirectModelProviderConnection } from "@opengeni/db";
10013
+
10082
10014
  // src/activities/agent-turn/recovery-warning.ts
10083
10015
  import { getSandboxRecoveryDiscontinuity } from "@opengeni/db";
10084
10016
  var FILESYSTEM_DISCONTINUITY_PROTOCOL = 3;
@@ -10511,6 +10443,15 @@ async function claimTurnAttempt(deps) {
10511
10443
  workspaceProviderSettings,
10512
10444
  claimedPolicy.kind === "valid" ? claimedPolicy.policy.productModelId : turn.model
10513
10445
  );
10446
+ const selectedDirectConnection = await loadDirectModelProviderConnection(
10447
+ db,
10448
+ capabilitySettings,
10449
+ input.workspaceId,
10450
+ claimedPolicy.kind === "valid" ? claimedPolicy.policy.productModelId : turn.model ?? ""
10451
+ );
10452
+ if (selectedDirectConnection) {
10453
+ capabilitySettings = withDirectModelProviders(capabilitySettings, [selectedDirectConnection]);
10454
+ }
10514
10455
  const codexAppsCredentialId = capabilitySettings.codexConnectedAppsEnabled ? await resolveCodexAppsCredentialIdForRun(db, input.workspaceId) : null;
10515
10456
  const candidatePolicy = claimedPolicy.kind === "valid" ? claimedPolicy.policy : resolveTurnExecutionPolicyV12(capabilitySettings, legacyTurnExecutionPolicyInput(turn));
10516
10457
  const credentialRestriction = claimedPolicy.kind === "absent" ? turn.initiatorContext?.credentialRestriction === "developer_setup" ? "developer_setup" : turnCredentialRestriction(candidatePolicy, session.metadata) : void 0;
@@ -13001,6 +12942,7 @@ import { createProviderCommandRetainer } from "@opengeni/db/retained-provider-co
13001
12942
  import {
13002
12943
  RoutingMutationOutcomeUnknownError,
13003
12944
  ProviderCommandStartOutcomeUnknownError,
12945
+ ProviderCommandObservationUnavailableError,
13004
12946
  isModalCommandStartOutcomeUnknownError as isModalCommandStartOutcomeUnknownError2,
13005
12947
  withModalCommandStartSignal,
13006
12948
  resolveModalCheckpointProviderBindingForSession,
@@ -13028,7 +12970,7 @@ function internalMutationUnknownCommand(error51, instanceId) {
13028
12970
  if (!value || typeof value !== "object" || seen.has(value)) continue;
13029
12971
  seen.add(value);
13030
12972
  try {
13031
- if (value instanceof ProviderCommandStartOutcomeUnknownError) {
12973
+ if (value instanceof ProviderCommandStartOutcomeUnknownError || value instanceof ProviderCommandObservationUnavailableError) {
13032
12974
  unknown2 = true;
13033
12975
  let remaining = 64;
13034
12976
  const copyCommandData = (candidate, descriptorDepth = 0) => {
@@ -14161,7 +14103,8 @@ async function establishTurnSandbox(deps) {
14161
14103
  observability,
14162
14104
  freshSandboxReadinessReplacementBudget,
14163
14105
  onSandboxLost: publishSandboxLost,
14164
- objectStorage
14106
+ objectStorage,
14107
+ bus
14165
14108
  },
14166
14109
  {
14167
14110
  accountId: input.accountId,
@@ -14236,7 +14179,8 @@ async function establishTurnSandbox(deps) {
14236
14179
  observability,
14237
14180
  freshSandboxReadinessReplacementBudget,
14238
14181
  onSandboxLost: publishSandboxLost,
14239
- objectStorage
14182
+ objectStorage,
14183
+ bus
14240
14184
  },
14241
14185
  {
14242
14186
  accountId: input.accountId,
@@ -34291,6 +34235,7 @@ function configuredBundledSkillNames(context) {
34291
34235
  { name: "document-parsing", include: () => true },
34292
34236
  { name: "opengeni-skills", include: () => true },
34293
34237
  { name: "opengeni-projects", include: () => true },
34238
+ { name: "opengeni-schedules", include: () => tools.has("scheduled_tasks_create") },
34294
34239
  { name: "opengeni-documents", include: artifacts },
34295
34240
  { name: "opengeni-spreadsheets", include: artifacts },
34296
34241
  { name: "opengeni-presentations", include: artifacts },
@@ -34308,6 +34253,7 @@ function loadConfiguredBundledSkills(context) {
34308
34253
  const names = new Set(configuredBundledSkillNames(context));
34309
34254
  const artifacts = loadNativeToolSkillArtifacts({
34310
34255
  projects: names.has("opengeni-projects"),
34256
+ schedules: names.has("opengeni-schedules"),
34311
34257
  editableArtifacts: [
34312
34258
  "opengeni-documents",
34313
34259
  "opengeni-spreadsheets",
@@ -37388,6 +37334,8 @@ function createRunAgentTurnActivity(services) {
37388
37334
  bus,
37389
37335
  runtime,
37390
37336
  summarizeContextForCompaction,
37337
+ requestWorkerDrain,
37338
+ turnFinalizationTimeoutMs,
37391
37339
  objectStorage,
37392
37340
  observability,
37393
37341
  wakeSessionWorkflow,
@@ -38011,28 +37959,28 @@ function createRunAgentTurnActivity(services) {
38011
37959
  })
38012
37960
  );
38013
37961
  const withClaudeUsage = (fn) => withClaudeUsageObserver(claudeUsageObserver, fn, async (providerId, headers) => {
38014
- const binding = claudeUsageObserver.binding(providerId);
38015
- if (!binding) return headers;
38016
- const credential = await resolveClaudeSubscriptionCredential(
38017
- db,
38018
- settings,
38019
- {
38020
- accountId: input.accountId,
38021
- workspaceId: input.workspaceId,
38022
- scope: binding.scope
38023
- },
38024
- {
38025
- expectedConnectionId: binding.expectedConnectionId,
38026
- expectedCredentialVersion: binding.expectedCredentialVersion
37962
+ return claudeUsageObserver.prepareRequestWithObserver(
37963
+ providerId,
37964
+ headers,
37965
+ async (binding) => {
37966
+ const credential = await resolveClaudeSubscriptionCredential(
37967
+ db,
37968
+ settings,
37969
+ {
37970
+ accountId: input.accountId,
37971
+ workspaceId: input.workspaceId,
37972
+ scope: binding.scope
37973
+ },
37974
+ {
37975
+ expectedConnectionId: binding.expectedConnectionId,
37976
+ expectedCredentialVersion: binding.expectedCredentialVersion
37977
+ }
37978
+ );
37979
+ if (credential && "reconnectRequired" in credential)
37980
+ throw new ClaudeSubscriptionReconnectRequired();
37981
+ return credential;
38027
37982
  }
38028
37983
  );
38029
- if (!credential) return headers;
38030
- if ("reconnectRequired" in credential)
38031
- throw new ClaudeSubscriptionReconnectRequired();
38032
- claudeUsageObserver.renew(providerId, credential);
38033
- headers.set("authorization", `Bearer ${credential.token}`);
38034
- headers.delete("x-api-key");
38035
- return headers;
38036
37984
  });
38037
37985
  const withCodex = (fn) => codexContext ? codexRequestStorage.run(codexContext, fn) : fn();
38038
37986
  const withProviderRequestContext = (fn) => withClaudeUsage(
@@ -38842,6 +38790,8 @@ These are publication receipts for the human's earlier answer. Do not call the r
38842
38790
  });
38843
38791
  } finally {
38844
38792
  await finalizeTurnAttempt({
38793
+ turnFinalizationTimeoutMs,
38794
+ requestWorkerDrain,
38845
38795
  input,
38846
38796
  settings,
38847
38797
  db,
@@ -39982,12 +39932,17 @@ function createTurnActivityServices(dependencies) {
39982
39932
  let servicesPromise = null;
39983
39933
  return async () => {
39984
39934
  servicesPromise ??= (async () => {
39935
+ if (!dependencies.requestWorkerDrain) {
39936
+ throw new Error("Turn activities require a host requestWorkerDrain lifecycle edge");
39937
+ }
39985
39938
  const services = await shared();
39986
39939
  return {
39987
39940
  ...services,
39988
39941
  runtime: dependencies.runtime ?? createProductionAgentRuntime({
39989
39942
  metrics: runtimeMetricsHooksForObservability(services.observability)
39990
39943
  }),
39944
+ requestWorkerDrain: dependencies.requestWorkerDrain,
39945
+ turnFinalizationTimeoutMs: dependencies.turnFinalizationTimeoutMs,
39991
39946
  summarizeContextForCompaction: dependencies.summarizeContextForCompaction ?? summarizeForCompaction2
39992
39947
  };
39993
39948
  })();
@@ -40007,4 +39962,4 @@ export {
40007
39962
  createTurnActivities,
40008
39963
  createTurnActivitiesFromServices
40009
39964
  };
40010
- //# sourceMappingURL=activities-turn-KU25J3VQ.js.map
39965
+ //# sourceMappingURL=activities-turn-TTNAVGKN.js.map