@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
@@ -17,7 +17,6 @@ import {
17
17
  type ScheduledTaskRun,
18
18
  } from "@opengeni/contracts";
19
19
  import {
20
- defaultSessionMcpServerIds,
21
20
  openGeniSlackBotMetadata,
22
21
  requireOpenGeniSlackBotConnection,
23
22
  resolveWorkspaceCatalogSettings,
@@ -25,6 +24,12 @@ import {
25
24
  workspaceCustomModelReference,
26
25
  lockActiveCustomModelForAdmission,
27
26
  scheduledSlackBotConnectionId,
27
+ freezeConnectionAccounts,
28
+ ConnectionAccountSelectionError,
29
+ scheduledConnectionSurfaceEligibility,
30
+ scheduledConnectionTools,
31
+ settingsWithEnabledCapabilityMcpServers,
32
+ settingsWithSessionMcpServerMetadata,
28
33
  swapActiveSandbox,
29
34
  } from "@opengeni/core";
30
35
  import {
@@ -41,7 +46,6 @@ import {
41
46
  getScheduledTaskRunAcceptedExecution,
42
47
  getScheduledTaskRunByProducerKey,
43
48
  getScheduledTargetSessionExecution,
44
- getScheduledTaskPersonalConnectionDelegations,
45
49
  getScheduledTaskRunPersonalResourceAuthority,
46
50
  getScheduledTaskPersonalResourceAuthoritySubject,
47
51
  getScheduledTaskRevisionAuthority,
@@ -57,7 +61,6 @@ import {
57
61
  isCodexBilledModel,
58
62
  initializeSessionStartAtomically,
59
63
  materializeScheduledTaskReusableSessionFromRun,
60
- listEnabledMcpCapabilityServerIds,
61
64
  listInstalledApiIntegrationServerIdsForDelegations,
62
65
  markScheduledTaskRunFailedIfQueued,
63
66
  markScheduledTaskRunSkippedIfQueued,
@@ -391,20 +394,6 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
391
394
  if (incidentDeclaration.action === "blocked") {
392
395
  return incidentDeclaration;
393
396
  }
394
- const taskPersonalConnectionDelegations = await getScheduledTaskPersonalConnectionDelegations(
395
- db,
396
- task.workspaceId,
397
- task.id,
398
- );
399
- const taskConnectionAuthoritySubjects = [
400
- ...new Set(
401
- taskPersonalConnectionDelegations.map((delegation) => delegation.ownerSubjectId),
402
- ),
403
- ];
404
- if (taskConnectionAuthoritySubjects.length > 1) {
405
- throw new Error("scheduled connection authority has multiple causal humans");
406
- }
407
- const taskConnectionAuthoritySubjectId = taskConnectionAuthoritySubjects[0] ?? null;
408
397
  const taskPersonalResourceAuthoritySubjectId =
409
398
  await getScheduledTaskPersonalResourceAuthoritySubject(db, {
410
399
  accountId: task.accountId,
@@ -418,17 +407,16 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
418
407
  taskId: task.id,
419
408
  taskAuthorityRevision: task.authorityRevision,
420
409
  });
410
+ const taskAuthoritySubjectId = task.ownerSubjectId;
421
411
  if (
422
- taskConnectionAuthoritySubjectId &&
423
- taskPersonalResourceAuthoritySubjectId &&
424
- taskConnectionAuthoritySubjectId !== taskPersonalResourceAuthoritySubjectId
412
+ task.action.kind === "agent_turn" &&
413
+ ((taskRevisionAuthority?.subjectId ?? null) !== taskAuthoritySubjectId ||
414
+ [taskPersonalResourceAuthoritySubjectId].some(
415
+ (subject) => subject !== null && subject !== taskAuthoritySubjectId,
416
+ ))
425
417
  ) {
426
- throw new Error("scheduled authority classes have different causal humans");
418
+ throw new Error("scheduled authority differs from its immutable execution owner");
427
419
  }
428
- const taskAuthoritySubjectId =
429
- taskRevisionAuthority?.subjectId ??
430
- taskPersonalResourceAuthoritySubjectId ??
431
- taskConnectionAuthoritySubjectId;
432
420
  const acceptedTargetSessionId =
433
421
  task.runMode === "existing_session"
434
422
  ? task.targetSessionId
@@ -467,6 +455,60 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
467
455
  const firstPartyMcpPermissions = creatorPolicy?.firstPartyMcpPermissions
468
456
  ? [...creatorPolicy.firstPartyMcpPermissions]
469
457
  : [...DEFAULT_FIRST_PARTY_MCP_PERMISSIONS];
458
+ // A fresh occurrence resolves the immutable owner's current accounts.
459
+ // Retry/recovery above uses the already accepted occurrence snapshot.
460
+ const connectionSettings = await settingsWithEnabledCapabilityMcpServers(
461
+ db,
462
+ task.workspaceId,
463
+ settings,
464
+ taskAuthoritySubjectId ? { subjectId: taskAuthoritySubjectId } : {},
465
+ );
466
+ const connectionTarget =
467
+ acceptedTargetSessionId && targetSessionExecutionBase
468
+ ? await requireSession(db, task.workspaceId, acceptedTargetSessionId)
469
+ : null;
470
+ const connectionTools = await scheduledConnectionTools(
471
+ db,
472
+ task.workspaceId,
473
+ connectionSettings,
474
+ connectionTarget,
475
+ taskTools,
476
+ taskAuthoritySubjectId ?? undefined,
477
+ );
478
+ const taskConnections = await freezeConnectionAccounts({
479
+ db,
480
+ accountId: task.accountId,
481
+ workspaceId: task.workspaceId,
482
+ settings: connectionTarget
483
+ ? settingsWithSessionMcpServerMetadata(connectionSettings, connectionTarget.mcpServers)
484
+ : connectionSettings,
485
+ tools: connectionTools,
486
+ resources: connectionTarget?.resources ?? task.agentConfig.resources,
487
+ source: taskAuthoritySubjectId
488
+ ? { kind: "subject", subjectId: taskAuthoritySubjectId, accountId: task.accountId }
489
+ : { kind: "none" },
490
+ authoritySelections: task.agentConfig.connectionAccounts ?? [],
491
+ authoritySelectionsFrozen: task.agentConfig.connectionAccountsFrozen === true,
492
+ ...scheduledConnectionSurfaceEligibility(
493
+ settings,
494
+ connectionTarget ?? {
495
+ firstPartyMcpTools,
496
+ firstPartyMcpPermissions,
497
+ },
498
+ ),
499
+ }).catch((error: unknown) => {
500
+ if (error instanceof ConnectionAccountSelectionError) return null;
501
+ throw error;
502
+ });
503
+ if (taskConnections === null) {
504
+ return { action: "blocked", reason: "connection_account_unavailable" };
505
+ }
506
+ const {
507
+ personalConnectionDelegations: taskPersonalConnectionDelegations,
508
+ mcpAccountBindings: taskMcpAccountBindings,
509
+ } = taskConnections;
510
+ const taskConnectionAuthoritySubjectId =
511
+ taskPersonalConnectionDelegations.length > 0 ? taskAuthoritySubjectId : null;
470
512
  const creatorSessionPolicy = scheduledCreatorSessionPolicyInput(
471
513
  creatorPolicy?.sessionPolicy ?? null,
472
514
  );
@@ -537,20 +579,16 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
537
579
  : null;
538
580
  const targetSessionExecution = targetSessionExecutionBase
539
581
  ? await (async () => {
540
- const [capabilityServerIds, apiIntegrationServerIds] = await Promise.all([
541
- listEnabledMcpCapabilityServerIds(db, task.workspaceId),
542
- listInstalledApiIntegrationServerIdsForDelegations(
582
+ const apiIntegrationServerIds =
583
+ await listInstalledApiIntegrationServerIdsForDelegations(
543
584
  db,
544
585
  task.workspaceId,
545
586
  taskPersonalConnectionDelegations,
546
- ),
587
+ );
588
+ const availableMcpServerIds = new Set([
589
+ ...connectionSettings.mcpServers.map((server) => server.id),
590
+ ...apiIntegrationServerIds,
547
591
  ]);
548
- const workspaceDefaultMcpServerIds = new Set(
549
- settings.mcpServers.map((server) => server.id),
550
- );
551
- for (const id of capabilityServerIds) workspaceDefaultMcpServerIds.add(id);
552
- for (const id of apiIntegrationServerIds) workspaceDefaultMcpServerIds.add(id);
553
- const availableMcpServerIds = new Set(workspaceDefaultMcpServerIds);
554
592
  for (const id of targetSessionExecutionBase.mcpServerIds) {
555
593
  availableMcpServerIds.add(id);
556
594
  }
@@ -558,9 +596,10 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
558
596
  toolPolicy: targetSessionExecutionBase.toolPolicy,
559
597
  sessionTools: targetSessionExecutionBase.tools,
560
598
  availableMcpServerIds,
561
- defaultMcpServerIds: defaultSessionMcpServerIds(
562
- [...workspaceDefaultMcpServerIds].map((id) => ({ id })),
563
- ),
599
+ defaultMcpServerIds: [
600
+ ...connectionTools.map((tool) => tool.id),
601
+ ...apiIntegrationServerIds,
602
+ ],
564
603
  });
565
604
  return {
566
605
  ...targetSessionExecutionBase,
@@ -604,7 +643,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
604
643
  )
605
644
  : null;
606
645
  if (generatedTarget && task.rigId && (!acceptedRig || !acceptedRig.activeVersion)) {
607
- throw new Error(`rig has no active version to bind: ${task.rigId}`);
646
+ throw new Error(`sandbox environment has no active version to bind: ${task.rigId}`);
608
647
  }
609
648
  const acceptedRigDefaultVariableSets = acceptedRig?.activeVersion
610
649
  ? await Promise.all(
@@ -619,7 +658,9 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
619
658
  variableSetId,
620
659
  );
621
660
  if (!variableSet) {
622
- throw new Error(`rig default Variable Set not found: ${variableSetId}`);
661
+ throw new Error(
662
+ `sandbox environment default Variable Set not found: ${variableSetId}`,
663
+ );
623
664
  }
624
665
  return { id: variableSet.id, generation: variableSet.generation };
625
666
  }),
@@ -843,6 +884,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
843
884
  targetSessionExecution,
844
885
  generatedSessionBinding,
845
886
  personalConnectionDelegations: taskPersonalConnectionDelegations,
887
+ mcpAccountBindings: taskMcpAccountBindings,
846
888
  personalResourceAuthoritySubjectId: taskPersonalResourceAuthoritySubjectId,
847
889
  causalHumanSubjectId,
848
890
  causalHumanAuthority: taskRevisionAuthority,
@@ -966,16 +1008,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
966
1008
  taskId: task.id,
967
1009
  },
968
1010
  );
969
- if (
970
- stableJson({
971
- task: exactAuthority.task,
972
- personalConnectionDelegations: exactAuthority.personalConnectionDelegations,
973
- }) !==
974
- stableJson({
975
- task,
976
- personalConnectionDelegations: taskPersonalConnectionDelegations,
977
- })
978
- ) {
1011
+ if (stableJson(exactAuthority) !== stableJson(task)) {
979
1012
  throw new IncidentTelemetryPreflightBlockedError(
980
1013
  "incident_preflight_metadata_missing",
981
1014
  );
@@ -1009,7 +1042,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
1009
1042
  if (task.rigId) {
1010
1043
  const rig = acceptedRig;
1011
1044
  if (!rig || !rig.activeVersion) {
1012
- throw new Error(`rig has no active version to bind: ${task.rigId}`);
1045
+ throw new Error(`sandbox environment has no active version to bind: ${task.rigId}`);
1013
1046
  }
1014
1047
  frozenRigId = rig.id;
1015
1048
  frozenRigVersionId =
@@ -1017,7 +1050,9 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
1017
1050
  (resource) => resource.resourceKind === "rig" && resource.resourceId === rig.id,
1018
1051
  )?.resourceVersionId ?? rig.activeVersion.id;
1019
1052
  if (frozenRigVersionId !== rig.activeVersion.id) {
1020
- throw new Error("scheduled run rig version changed during admission");
1053
+ throw new Error(
1054
+ "scheduled run sandbox environment version changed during admission",
1055
+ );
1021
1056
  }
1022
1057
  }
1023
1058
  let session: Awaited<ReturnType<typeof createSession>>;
@@ -1368,6 +1403,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
1368
1403
  : {}),
1369
1404
  },
1370
1405
  personalConnectionDelegations: taskPersonalConnectionDelegations,
1406
+ mcpAccountBindings: taskMcpAccountBindings,
1371
1407
  xaiProviderAccountAuthoritySnapshot: taskXaiProviderAccountAuthoritySnapshot,
1372
1408
  scheduledTaskRunId: run.id,
1373
1409
  },
@@ -1495,6 +1531,7 @@ export function createScheduledTaskActivities(services: () => Promise<ControlAct
1495
1531
  : {}),
1496
1532
  },
1497
1533
  personalConnectionDelegations: taskPersonalConnectionDelegations,
1534
+ mcpAccountBindings: taskMcpAccountBindings,
1498
1535
  xaiProviderAccountAuthoritySnapshot: taskXaiProviderAccountAuthoritySnapshot,
1499
1536
  scheduledTaskRunId: run.id,
1500
1537
  },
@@ -1799,18 +1836,10 @@ async function prepareIncidentTelemetrySource(input: {
1799
1836
  workspaceId: string;
1800
1837
  sessionId: string;
1801
1838
  alertOccurrenceLabels: Readonly<Record<string, string>> | null;
1802
- acceptedExecution?: ScheduledTaskRunAcceptedExecution;
1839
+ acceptedExecution: ScheduledTaskRunAcceptedExecution;
1803
1840
  }) {
1804
1841
  const session = await requireSession(input.tx, input.workspaceId, input.sessionId);
1805
- const { task, personalConnectionDelegations } = input.acceptedExecution
1806
- ? {
1807
- task: input.acceptedExecution.task,
1808
- personalConnectionDelegations: input.acceptedExecution.personalConnectionDelegations,
1809
- }
1810
- : await requireScheduledTaskIncidentAuthorityInTransaction(input.tx, {
1811
- workspaceId: input.workspaceId,
1812
- taskId: input.taskId,
1813
- });
1842
+ const { task, personalConnectionDelegations } = input.acceptedExecution;
1814
1843
  const responder = await resolveIncidentTelemetryResponderMetadata({
1815
1844
  db: input.tx,
1816
1845
  settings: input.settings,
@@ -1818,39 +1847,34 @@ async function prepareIncidentTelemetrySource(input: {
1818
1847
  session,
1819
1848
  personalConnectionDelegations,
1820
1849
  personalResourceAuthoritySubjectId:
1821
- input.acceptedExecution?.personalResourceAuthoritySubjectId ?? null,
1822
- ...(input.acceptedExecution
1850
+ input.acceptedExecution.personalResourceAuthoritySubjectId ?? null,
1851
+ executionPolicy: input.acceptedExecution.targetSessionExecution
1823
1852
  ? {
1824
- executionPolicy: input.acceptedExecution.targetSessionExecution
1825
- ? {
1826
- tools: input.acceptedExecution.targetSessionExecution.tools,
1827
- firstPartyMcpTools:
1828
- input.acceptedExecution.targetSessionExecution.firstPartyMcpTools,
1829
- firstPartyMcpPermissions:
1830
- input.acceptedExecution.targetSessionExecution.firstPartyMcpPermissions,
1831
- variableSetIds: input.acceptedExecution.targetSessionExecution.variableSets.map(
1832
- (variableSet) => variableSet.id,
1833
- ),
1834
- variableSetId: input.acceptedExecution.targetSessionExecution.variableSetId,
1835
- rigId: input.acceptedExecution.targetSessionExecution.rigId,
1836
- rigVersionId: input.acceptedExecution.targetSessionExecution.rigVersionId,
1837
- toolPolicy: input.acceptedExecution.targetSessionExecution.toolPolicy,
1838
- mcpServerIds: input.acceptedExecution.targetSessionExecution.mcpServerIds,
1839
- toolPolicyVersion: input.acceptedExecution.targetSessionExecution.toolPolicyVersion,
1840
- }
1841
- : {
1842
- tools: input.acceptedExecution.resolvedTools,
1843
- firstPartyMcpTools: input.acceptedExecution.resolvedFirstPartyMcpTools,
1844
- firstPartyMcpPermissions: input.acceptedExecution.resolvedFirstPartyMcpPermissions,
1845
- variableSetId: input.acceptedExecution.resolvedVariableSet?.id ?? null,
1846
- rigId: input.acceptedExecution.resolvedRig?.id ?? null,
1847
- rigVersionId: input.acceptedExecution.resolvedRig?.versionId ?? null,
1848
- toolPolicy: session.toolPolicy,
1849
- mcpServerIds: [],
1850
- toolPolicyVersion: session.toolPolicyVersion,
1851
- },
1853
+ tools: input.acceptedExecution.targetSessionExecution.tools,
1854
+ firstPartyMcpTools: input.acceptedExecution.targetSessionExecution.firstPartyMcpTools,
1855
+ firstPartyMcpPermissions:
1856
+ input.acceptedExecution.targetSessionExecution.firstPartyMcpPermissions,
1857
+ variableSetIds: input.acceptedExecution.targetSessionExecution.variableSets.map(
1858
+ (variableSet) => variableSet.id,
1859
+ ),
1860
+ variableSetId: input.acceptedExecution.targetSessionExecution.variableSetId,
1861
+ rigId: input.acceptedExecution.targetSessionExecution.rigId,
1862
+ rigVersionId: input.acceptedExecution.targetSessionExecution.rigVersionId,
1863
+ toolPolicy: input.acceptedExecution.targetSessionExecution.toolPolicy,
1864
+ mcpServerIds: input.acceptedExecution.targetSessionExecution.mcpServerIds,
1865
+ toolPolicyVersion: input.acceptedExecution.targetSessionExecution.toolPolicyVersion,
1852
1866
  }
1853
- : {}),
1867
+ : {
1868
+ tools: input.acceptedExecution.resolvedTools,
1869
+ firstPartyMcpTools: input.acceptedExecution.resolvedFirstPartyMcpTools,
1870
+ firstPartyMcpPermissions: input.acceptedExecution.resolvedFirstPartyMcpPermissions,
1871
+ variableSetId: input.acceptedExecution.resolvedVariableSet?.id ?? null,
1872
+ rigId: input.acceptedExecution.resolvedRig?.id ?? null,
1873
+ rigVersionId: input.acceptedExecution.resolvedRig?.versionId ?? null,
1874
+ toolPolicy: session.toolPolicy,
1875
+ mcpServerIds: [],
1876
+ toolPolicyVersion: session.toolPolicyVersion,
1877
+ },
1854
1878
  });
1855
1879
  const preflight = evaluateIncidentTelemetryPreflight({
1856
1880
  agentConfig: task.agentConfig,
@@ -2356,6 +2380,7 @@ async function recoverBoundScheduledTaskDispatch(input: {
2356
2380
  : {}),
2357
2381
  },
2358
2382
  personalConnectionDelegations: input.acceptedExecution.personalConnectionDelegations,
2383
+ mcpAccountBindings: input.acceptedExecution.mcpAccountBindings ?? null,
2359
2384
  xaiProviderAccountAuthoritySnapshot:
2360
2385
  input.acceptedExecution.xaiProviderAccountAuthoritySnapshot,
2361
2386
  scheduledTaskRunId: input.run.id,
@@ -3,6 +3,7 @@ import {
3
3
  applySessionTurnSettlement,
4
4
  enqueueSessionWorkflowWake,
5
5
  failSessionWorkBeforeAttemptClaim,
6
+ blockSessionWorkBeforeAttemptClaim,
6
7
  requestSessionTurnRecovery,
7
8
  recoverSessionDispatch,
8
9
  reconcileSessionAttemptQuiescence,
@@ -19,6 +20,8 @@ import {
19
20
  settleSessionIdleWithParentOutbox,
20
21
  } from "@opengeni/db";
21
22
  import { publishDurableSessionEvents } from "@opengeni/events";
23
+ import { CancelledFailure } from "@temporalio/activity";
24
+ import { currentActivityContext } from "./streaming";
22
25
  import { deliverFailedChildTurnToParent, notifyParentOfChildIdle } from "./parent-wake";
23
26
  import { recordTurnsQueuedGauge, recordWorkerDeathRecoveryMetrics } from "../observability-metrics";
24
27
  import {
@@ -52,6 +55,7 @@ export type SessionStateActivityOverrides = Partial<{
52
55
  applySessionTurnSettlement: typeof applySessionTurnSettlement;
53
56
  enqueueSessionWorkflowWake: typeof enqueueSessionWorkflowWake;
54
57
  failSessionWorkBeforeAttemptClaim: typeof failSessionWorkBeforeAttemptClaim;
58
+ blockSessionWorkBeforeAttemptClaim: typeof blockSessionWorkBeforeAttemptClaim;
55
59
  requestSessionTurnRecovery: typeof requestSessionTurnRecovery;
56
60
  recoverSessionDispatch: typeof recoverSessionDispatch;
57
61
  reconcileSessionAttemptQuiescence: typeof reconcileSessionAttemptQuiescence;
@@ -91,6 +95,8 @@ export function createSessionStateActivities(
91
95
  overrides.enqueueSessionWorkflowWake ?? enqueueSessionWorkflowWake;
92
96
  const failSessionWorkBeforeAttemptClaimFn =
93
97
  overrides.failSessionWorkBeforeAttemptClaim ?? failSessionWorkBeforeAttemptClaim;
98
+ const blockSessionWorkBeforeAttemptClaimFn =
99
+ overrides.blockSessionWorkBeforeAttemptClaim ?? blockSessionWorkBeforeAttemptClaim;
94
100
  const requestSessionTurnRecoveryFn =
95
101
  overrides.requestSessionTurnRecovery ?? requestSessionTurnRecovery;
96
102
  const recoverSessionDispatchFn = overrides.recoverSessionDispatch ?? recoverSessionDispatch;
@@ -153,6 +159,28 @@ export function createSessionStateActivities(
153
159
 
154
160
  const preClaimFailureDisposition =
155
161
  input.preClaimFailure?.disposition ?? input.preClaimFailureDisposition;
162
+ if (
163
+ preClaimFailureDisposition === "blocked" &&
164
+ input.admissionFence &&
165
+ input.preClaimFailure?.reason
166
+ ) {
167
+ const blocked = await blockSessionWorkBeforeAttemptClaimFn(db, input.workspaceId, {
168
+ accountId: input.accountId,
169
+ sessionId: input.sessionId,
170
+ workflowId,
171
+ attemptId: input.attemptId,
172
+ fence: input.admissionFence,
173
+ reason: input.preClaimFailure.reason,
174
+ sqlState: input.preClaimFailure.sqlState ?? null,
175
+ });
176
+ await publishDurableSessionEventsFn(
177
+ bus,
178
+ input.workspaceId,
179
+ input.sessionId,
180
+ blocked.events,
181
+ );
182
+ return { action: blocked.action };
183
+ }
156
184
  if (preClaimFailureDisposition === "permanent" && input.trigger) {
157
185
  const failed = await failSessionWorkBeforeAttemptClaimFn(db, input.workspaceId, {
158
186
  accountId: input.accountId,
@@ -160,7 +188,14 @@ export function createSessionStateActivities(
160
188
  workflowId,
161
189
  trigger: input.trigger,
162
190
  error: input.error ?? "Agent turn admission failed before attempt claim.",
163
- ...(input.preClaimFailure ? { admissionFailure: input.preClaimFailure } : {}),
191
+ ...(input.preClaimFailure?.disposition === "permanent"
192
+ ? {
193
+ admissionFailure: {
194
+ disposition: "permanent" as const,
195
+ code: input.preClaimFailure.code,
196
+ },
197
+ }
198
+ : {}),
164
199
  });
165
200
  if (failed.action === "terminal") return { action: "terminal" };
166
201
  if (failed.action === "stale") return { action: "stale" };
@@ -488,8 +523,53 @@ export function createSessionStateActivities(
488
523
  }
489
524
 
490
525
  async function peekSessionWork(input: PeekSessionWorkInput) {
491
- const { db, observability } = await services();
492
- const peek = await peekSessionWorkFn(db, input.workspaceId, input.sessionId);
526
+ const { db, observability, inspectSessionAttemptActivity } = await services();
527
+ const peek = await peekSessionWorkFn(
528
+ db,
529
+ input.workspaceId,
530
+ input.sessionId,
531
+ input.includeAdmissionFence,
532
+ input.observerAccountId,
533
+ );
534
+ if (peek.kind === "unavailable") return peek;
535
+ if (peek.kind === "attempt-owned") {
536
+ // Observation never revokes a writer or recovers a live owner. In
537
+ // particular, a settled Temporal activity is not physical-writer proof.
538
+ let ownerActivityState: "pending" | "settled" | "unknown" = "unknown";
539
+ if (inspectSessionAttemptActivity) {
540
+ try {
541
+ ownerActivityState = await inspectSessionAttemptActivity(peek.activityRef);
542
+ } catch (error) {
543
+ if (error instanceof CancelledFailure) throw error;
544
+ if (currentActivityContext()?.cancellationSignal.aborted)
545
+ throw new CancelledFailure("Control observation cancelled");
546
+ // This optional metadata observation grants no recovery authority.
547
+ // An unavailable inspector must not pin the control activity in
548
+ // retries and prevent a fresh Pause/owner/visibility observation.
549
+ // Database reads below remain outside this catch and retry normally.
550
+ }
551
+ }
552
+ if (currentActivityContext()?.cancellationSignal.aborted)
553
+ throw new CancelledFailure("Control observation cancelled");
554
+ const current = await peekSessionWorkFn(
555
+ db,
556
+ input.workspaceId,
557
+ input.sessionId,
558
+ input.includeAdmissionFence,
559
+ input.observerAccountId,
560
+ );
561
+ if (
562
+ current.kind !== "attempt-owned" ||
563
+ current.turnId !== peek.turnId ||
564
+ current.attemptId !== peek.attemptId ||
565
+ current.executionGeneration !== peek.executionGeneration ||
566
+ current.activityRef.workflowId !== peek.activityRef.workflowId ||
567
+ current.activityRef.workflowRunId !== peek.activityRef.workflowRunId ||
568
+ current.activityRef.activityId !== peek.activityRef.activityId
569
+ )
570
+ return current;
571
+ return { ...current, ownerActivityState };
572
+ }
493
573
  await refreshQueuedTurnsGauge(db, observability, countQueuedTurnsFn, recordTurnsQueuedGaugeFn);
494
574
  return peek;
495
575
  }
@@ -7,7 +7,11 @@ import type {
7
7
  ScheduledTaskTriggerType,
8
8
  TurnInitiator,
9
9
  } from "@opengeni/contracts";
10
- import type { Database, SessionWorkflowWakeDeliveryResult } from "@opengeni/db";
10
+ import type {
11
+ Database,
12
+ SessionWorkflowWakeDeliveryResult,
13
+ SessionAdmissionFence,
14
+ } from "@opengeni/db";
11
15
  import type { DocumentServices } from "@opengeni/documents";
12
16
  import type { EventBus } from "@opengeni/events";
13
17
  import type { Observability } from "@opengeni/observability";
@@ -252,6 +256,7 @@ export type FailSessionAttemptInput = {
252
256
  * committed claim discovered by the control lane can recover the exact
253
257
  * attempt instead of terminally failing it. */
254
258
  preClaimFailure?: PreClaimFailureDetail;
259
+ admissionFence?: SessionAdmissionFence;
255
260
  /** Added in v4. A claimed attempt that lost operational database access
256
261
  * before turn-start completion carries its exact immutable turn identity so
257
262
  * the DB-only control lane can recover it instead of terminally failing it. */
@@ -263,17 +268,24 @@ export type FailSessionAttemptInput = {
263
268
  };
264
269
 
265
270
  export type FailSessionAttemptResult =
271
+ | { action: "blocked" }
266
272
  | { action: "failed" }
267
273
  | { action: "recovering" }
268
274
  | { action: "unclaimed" }
269
275
  | { action: "terminal" }
270
276
  | { action: "stale" };
271
277
 
272
- export type PreClaimFailureDisposition = "retryable" | "permanent";
278
+ export type PreClaimFailureDisposition = "retryable" | "permanent" | "blocked";
273
279
 
274
280
  export type PreClaimFailureDetail = {
275
281
  disposition: PreClaimFailureDisposition;
276
282
  code: "db_deadlock" | "db_serialization_failure" | "db_failure" | "claim_invariant";
283
+ sqlState?: string | null;
284
+ reason?:
285
+ | "database_claim_rejected"
286
+ | "initiator_membership_required"
287
+ | "personal_resource_grant_required";
288
+ retryPolicy?: "explicit_recheck";
277
289
  };
278
290
 
279
291
  export const PRE_CLAIM_FAILURE_TYPE = "OpenGeniPreClaimFailure";
@@ -344,6 +356,9 @@ export type RecoverEscapedMcpTimeoutResult = {
344
356
  export type PeekSessionWorkInput = {
345
357
  workspaceId: string;
346
358
  sessionId: string;
359
+ includeAdmissionFence?: boolean;
360
+ /** Versioned workflow observer opt-in, never a caller authorization grant. */
361
+ observerAccountId?: string;
347
362
  };
348
363
 
349
364
  export type SettleSessionInputWaitInput = {
@@ -434,6 +449,7 @@ export type DispatchScheduledTaskRunResult =
434
449
  | "scheduled_authority_exhausted"
435
450
  | "scheduled_run_terminal"
436
451
  | "scheduled_execution_unrepresentable"
452
+ | "connection_account_unavailable"
437
453
  | "knowledge_source_paused"
438
454
  | "legacy_source_schedule_requires_migration"
439
455
  | "incident_preflight_metadata_missing"
@@ -6,6 +6,7 @@ import {
6
6
  type Database,
7
7
  } from "@opengeni/db";
8
8
  import { publishDurableWorkspaceControlEvent } from "@opengeni/events";
9
+ import { recordWorkflowWakeReconciliation } from "@opengeni/observability";
9
10
  import type { ControlActivityServices } from "./types";
10
11
  import {
11
12
  reconcileAutomaticSessionTitleFanout,
@@ -115,23 +116,7 @@ export function createWorkflowWakeActivities(services: () => Promise<ControlActi
115
116
  pendingAdmissionBlockers,
116
117
  exhaustedBatchLimit,
117
118
  };
118
- if (claimed > 0) {
119
- service.observability.info("session workflow wake delivery reconciled", {
120
- claimed,
121
- signaled,
122
- delivered,
123
- pendingAdmission,
124
- unconfirmed,
125
- failed,
126
- exhaustedBatchLimit,
127
- ...Object.fromEntries(
128
- Object.entries(pendingAdmissionBlockers).map(([blocker, count]) => [
129
- `pendingAdmissionBlockers.${blocker}`,
130
- count,
131
- ]),
132
- ),
133
- });
134
- }
119
+ recordWorkflowWakeReconciliation(service.observability, result);
135
120
  return result;
136
121
  },
137
122
  };
@@ -1,4 +1,8 @@
1
- import { dbSearchPath, getSettings, type Settings } from "@opengeni/config";
1
+ import {
2
+ dbSearchPath,
3
+ getArtifactMaterializerSettings,
4
+ type ArtifactMaterializerSettings,
5
+ } from "@opengeni/config";
2
6
  import {
3
7
  createDb,
4
8
  dbSql,
@@ -77,7 +81,7 @@ export type CreateEditableArtifactMaterializerServiceInput = Readonly<{
77
81
  }>;
78
82
 
79
83
  export type ProductionEditableArtifactMaterializerServiceOptions = Readonly<{
80
- settings: Settings;
84
+ settings: ArtifactMaterializerSettings;
81
85
  /** Dedicated DSN; never defaults to settings.databaseUrl. */
82
86
  databaseUrl: string;
83
87
  declaredDatabaseRole: string;
@@ -671,7 +675,7 @@ export async function createMaterializerSidecarFromEnvironment(
671
675
  }> | null> {
672
676
  const sidecar = readEditableArtifactMaterializerSidecarEnvironment(environment);
673
677
  if (!sidecar) return null;
674
- const settings = getSettings();
678
+ const settings = getArtifactMaterializerSettings(environment);
675
679
  const service = await createProductionEditableArtifactMaterializerService({
676
680
  settings,
677
681
  databaseUrl: sidecar.databaseUrl,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  dbSearchPath,
3
- getSettings,
3
+ getArtifactOutboxSettings,
4
4
  resolveNatsControlPlaneAuth,
5
- type Settings,
5
+ type ArtifactOutboxSettings,
6
6
  } from "@opengeni/config";
7
7
  import type { EditableArtifactOutboxDispatchSummary } from "@opengeni/core";
8
8
  import { createObservability, type Observability } from "@opengeni/observability";
@@ -51,7 +51,7 @@ export type CreateEditableArtifactOutboxServiceInput = Readonly<{
51
51
  }>;
52
52
 
53
53
  export type ProductionEditableArtifactOutboxServiceOptions = Readonly<{
54
- settings: Settings;
54
+ settings: ArtifactOutboxSettings;
55
55
  databaseUrl: string;
56
56
  declaredDatabaseRole: string;
57
57
  natsUrl: string;
@@ -360,7 +360,7 @@ export async function createOutboxSidecarFromEnvironment(
360
360
  ): Promise<Readonly<{ service: EditableArtifactOutboxService; httpPort: number }> | null> {
361
361
  const sidecar = readEditableArtifactOutboxSidecarEnvironment(environment);
362
362
  if (!sidecar) return null;
363
- const settings = getSettings();
363
+ const settings = getArtifactOutboxSettings(environment);
364
364
  const controlPlaneAuth = resolveNatsControlPlaneAuth(settings);
365
365
  const natsAuth: EditableArtifactHintNatsAuth = controlPlaneAuth
366
366
  ? {
@@ -519,7 +519,6 @@ function exactPersonalDelegation(
519
519
  delegation.providerDomain !== "github.com" ||
520
520
  delegation.kind !== "oauth2" ||
521
521
  !delegation.originWorkspaceId ||
522
- !delegation.userDelegation ||
523
522
  !delegation.personalGitHubRepositorySelection
524
523
  ) {
525
524
  throw new GitHubRestAuthorityError("Personal GitHub delegation is unavailable");
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  } from "@opengeni/config";
10
10
  import {
11
11
  assertRuntimeDatabasePosture,
12
+ isRetryableRuntimeDatabaseStartupError,
12
13
  countSessionRecoveryBacklog,
13
14
  createDb,
14
15
  getContextCompactionPendingSummary,
@@ -1162,7 +1163,7 @@ export async function startWorker() {
1162
1163
  await retryStartupDependency(
1163
1164
  "PostgreSQL runtime posture",
1164
1165
  () => assertRuntimeDatabasePosture(dbClient.db, databasePosture),
1165
- { ...retryOptions, onRetry },
1166
+ { ...retryOptions, onRetry, shouldRetry: isRetryableRuntimeDatabaseStartupError },
1166
1167
  );
1167
1168
  bus = await retryStartupDependency(
1168
1169
  "NATS",