@opengeni/worker-bundle 2.2.0 → 2.2.1-canary.36927100590001

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 (88) hide show
  1. package/dist/activities/agent-run-admission.d.ts +3 -1
  2. package/dist/activities/agent-turn/admission.d.ts +24 -3
  3. package/dist/activities/agent-turn/agent-build.d.ts +1 -0
  4. package/dist/activities/agent-turn/claude-usage-observer.d.ts +13 -1
  5. package/dist/activities/agent-turn/compaction-prep.d.ts +20 -0
  6. package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
  7. package/dist/activities/agent-turn/final-reply.d.ts +18 -0
  8. package/dist/activities/agent-turn/governance-model.d.ts +6 -0
  9. package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
  10. package/dist/activities/agent-turn/run-credentials.d.ts +4 -0
  11. package/dist/activities/agent-turn/sandbox-establish.d.ts +1 -0
  12. package/dist/activities/agent-turn/session-title.d.ts +3 -1
  13. package/dist/activities/agent-turn/stream-attempt.d.ts +1 -0
  14. package/dist/activities/agent-turn/turn-context.d.ts +1 -0
  15. package/dist/activities/automations.d.ts +3 -1
  16. package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
  17. package/dist/activities/goals.d.ts +8 -0
  18. package/dist/activities/run-credentials.d.ts +4 -2
  19. package/dist/activities/scheduled-tasks.d.ts +4 -35
  20. package/dist/activities/types.d.ts +4 -1
  21. package/dist/activities/workspace-capture.d.ts +2 -0
  22. package/dist/{activities-control-MHNA3CYV.js → activities-control-4F2A734B.js} +502 -133
  23. package/dist/activities-control-4F2A734B.js.map +1 -0
  24. package/dist/activities-control.d.ts +30 -0
  25. package/dist/{activities-turn-FQ5OO2WW.js → activities-turn-TESOIOEX.js} +696 -251
  26. package/dist/activities-turn-TESOIOEX.js.map +1 -0
  27. package/dist/activities.d.ts +30 -0
  28. package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
  29. package/dist/{chunk-RZAAGRFQ.js → chunk-4PJTUBWQ.js} +220 -88
  30. package/dist/chunk-4PJTUBWQ.js.map +1 -0
  31. package/dist/{chunk-IJZU752L.js → chunk-YG27NEMX.js} +34 -1
  32. package/dist/chunk-YG27NEMX.js.map +1 -0
  33. package/dist/index.d.ts +15 -0
  34. package/dist/index.js +46 -24
  35. package/dist/index.js.map +1 -1
  36. package/dist/observability-metrics.d.ts +16 -1
  37. package/dist/sandbox-resume.d.ts +4 -1
  38. package/dist/workflow-bundle.js +89 -21
  39. package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
  40. package/dist/workflows/scheduled-tasks.d.ts +4 -0
  41. package/dist/workflows.d.ts +1 -0
  42. package/package.json +21 -20
  43. package/src/activities/agent-run-admission.ts +17 -1
  44. package/src/activities/agent-turn/admission.ts +64 -1
  45. package/src/activities/agent-turn/agent-build.ts +24 -3
  46. package/src/activities/agent-turn/claim.ts +69 -15
  47. package/src/activities/agent-turn/claude-usage-observer.ts +33 -1
  48. package/src/activities/agent-turn/compaction-prep.ts +67 -16
  49. package/src/activities/agent-turn/credential-restriction.ts +14 -0
  50. package/src/activities/agent-turn/errors.ts +55 -0
  51. package/src/activities/agent-turn/failure-settlement.ts +26 -6
  52. package/src/activities/agent-turn/final-reply.ts +46 -0
  53. package/src/activities/agent-turn/governance-model.ts +12 -0
  54. package/src/activities/agent-turn/model-call-admission.ts +94 -0
  55. package/src/activities/agent-turn/run-credentials.ts +20 -3
  56. package/src/activities/agent-turn/run.ts +44 -5
  57. package/src/activities/agent-turn/sandbox-establish.ts +9 -5
  58. package/src/activities/agent-turn/session-title.ts +8 -2
  59. package/src/activities/agent-turn/stream-attempt.ts +144 -38
  60. package/src/activities/agent-turn/tool-environment.ts +55 -39
  61. package/src/activities/agent-turn/turn-context.ts +1 -0
  62. package/src/activities/automations.ts +78 -4
  63. package/src/activities/browser-deadline-checkpoint.ts +279 -0
  64. package/src/activities/capabilities.ts +52 -14
  65. package/src/activities/goals.ts +95 -98
  66. package/src/activities/knowledge-indexing.ts +29 -0
  67. package/src/activities/open-suffix-resume.ts +2 -1
  68. package/src/activities/run-credentials.ts +22 -16
  69. package/src/activities/sandbox-lease.ts +22 -0
  70. package/src/activities/scheduled-tasks.ts +172 -38
  71. package/src/activities/site-auth-maintenance.ts +1 -0
  72. package/src/activities/types.ts +4 -0
  73. package/src/activities/workspace-capture.ts +13 -2
  74. package/src/activities/workspace-credential-provider.ts +12 -0
  75. package/src/activities-control.ts +2 -0
  76. package/src/activities.ts +3 -0
  77. package/src/browser-deadline-checkpoint-contract.ts +5 -0
  78. package/src/index.ts +53 -25
  79. package/src/observability-metrics.ts +55 -1
  80. package/src/sandbox-resume.ts +23 -8
  81. package/src/sandbox-routing.ts +4 -2
  82. package/src/workflows/browser-deadline-checkpoint.ts +50 -0
  83. package/src/workflows/scheduled-tasks.ts +26 -13
  84. package/src/workflows.ts +4 -0
  85. package/dist/activities-control-MHNA3CYV.js.map +0 -1
  86. package/dist/activities-turn-FQ5OO2WW.js.map +0 -1
  87. package/dist/chunk-IJZU752L.js.map +0 -1
  88. package/dist/chunk-RZAAGRFQ.js.map +0 -1
@@ -83,6 +83,7 @@ import {
83
83
  signalPendingCodexCapacityWakeTargets,
84
84
  startActivityHeartbeat,
85
85
  throwIfTurnOperationCancelled,
86
+ turnCredentialRestriction,
86
87
  turnFinalizerCancellationSignal,
87
88
  turnInput,
88
89
  turnOperationCancellationFailure,
@@ -94,7 +95,7 @@ import {
94
95
  withFirstPartyTools,
95
96
  wrapLazyTurnBoxWithRouting,
96
97
  wrapTurnBoxWithRouting
97
- } from "./chunk-RZAAGRFQ.js";
98
+ } from "./chunk-4PJTUBWQ.js";
98
99
  import {
99
100
  StreamTimingMetrics,
100
101
  makeMachineOpObserver,
@@ -126,7 +127,7 @@ import {
126
127
  runtimeMetricsHooksForObservability,
127
128
  sandboxAutomaticRecoveryOutcome,
128
129
  turnLifecycleMetricsFor
129
- } from "./chunk-IJZU752L.js";
130
+ } from "./chunk-YG27NEMX.js";
130
131
  import {
131
132
  __export
132
133
  } from "./chunk-PZ5AY32C.js";
@@ -139,10 +140,13 @@ import {
139
140
  getSessionAuthorityProjection,
140
141
  readActiveSandbox as readActiveSandbox3,
141
142
  getWorkspaceCredentialProvider,
142
- loadClaudeSubscriptionUsageCredential
143
+ loadClaudeSubscriptionUsageCredential as loadClaudeSubscriptionUsageCredential2,
144
+ resolveClaudeSubscriptionCredential,
145
+ ClaudeSubscriptionReconnectRequired
143
146
  } from "@opengeni/db";
147
+ import { resolveAgentToolFamilies as resolveAgentToolFamilies3 } from "@opengeni/contracts";
144
148
  import {
145
- assertModelConnectionAllowsTurn,
149
+ assertModelConnectionAllowsTurn as assertModelConnectionAllowsTurn2,
146
150
  freezeAgentLearningPolicy as freezeAgentLearningPolicy2,
147
151
  recoverLegacyKnowledgeConfirmations,
148
152
  withSessionRlsActorContext
@@ -161,6 +165,7 @@ import {
161
165
  import {
162
166
  REMOTE_COMPACTION_V2_BETA_FEATURE,
163
167
  REMOTE_COMPACTION_V2_IMPLEMENTATION as REMOTE_COMPACTION_V2_IMPLEMENTATION2,
168
+ awaitModelCallAdmission,
164
169
  materializeSandboxFileDownloads as materializeSandboxFileDownloads3,
165
170
  sandboxFileDownloadFailureNote
166
171
  } from "@opengeni/runtime";
@@ -191,6 +196,17 @@ async function createClaudeUsageObserver(providers, latest, readCredential) {
191
196
  (provider) => provider.kind === "claude-subscription-workspace" || provider.kind === "claude-subscription-organization"
192
197
  ).map(async (provider) => {
193
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
+ ];
194
210
  const credential = await readCredential(scope).catch(() => null);
195
211
  if (!credential || credential.token !== provider.apiKey) return null;
196
212
  return [
@@ -205,7 +221,7 @@ async function createClaudeUsageObserver(providers, latest, readCredential) {
205
221
  })
206
222
  );
207
223
  const captured = new Map(bindings.filter((binding) => binding !== null));
208
- return (providerId, response) => {
224
+ const observe2 = (providerId, response) => {
209
225
  const binding = captured.get(providerId);
210
226
  if (!binding) return;
211
227
  const { scope, ...identity } = binding;
@@ -230,6 +246,16 @@ async function createClaudeUsageObserver(providers, latest, readCredential) {
230
246
  ...response.status === 401 ? { refresh: { status: "reconnect", checkedAt: (/* @__PURE__ */ new Date()).toISOString() } } : {}
231
247
  });
232
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
+ });
233
259
  }
234
260
 
235
261
  // src/activities/agent-turn/run.ts
@@ -4435,13 +4461,16 @@ async function runCapture(input, ctx, startedAt, signal, stage, ownership) {
4435
4461
  "error.message": gcError instanceof Error ? gcError.message : String(gcError)
4436
4462
  });
4437
4463
  }
4438
- const durationMs = Date.now() - startedAt;
4464
+ recordWorkspaceCaptureCompleted(observability, Date.now() - startedAt);
4465
+ }
4466
+ function recordWorkspaceCaptureCompleted(observability, durationMs) {
4439
4467
  observability.incrementCounter({
4440
4468
  name: "opengeni_workspace_capture_total",
4441
4469
  labels: { result: "ok" }
4442
4470
  });
4443
4471
  observability.observeHistogram({
4444
- name: "opengeni_workspace_capture_duration_seconds",
4472
+ name: "opengeni_workspace_capture_revision_duration_seconds",
4473
+ help: "Turn-end logical workspace revision capture duration for committed revisions.",
4445
4474
  value: durationMs / 1e3
4446
4475
  });
4447
4476
  }
@@ -5245,7 +5274,10 @@ import {
5245
5274
  isSessionEventPersistenceError as isSessionEventPersistenceError2
5246
5275
  } from "@opengeni/db";
5247
5276
  import { publishDurableSessionEvents as publishDurableSessionEvents2 } from "@opengeni/events";
5248
- import { maxTurnsExceededRunState } from "@opengeni/runtime";
5277
+ import {
5278
+ maxTurnsExceededRunState,
5279
+ isModalTaskExecStartPreDispatchUnavailableError
5280
+ } from "@opengeni/runtime";
5249
5281
  import { ApplicationFailure, CancelledFailure } from "@temporalio/activity";
5250
5282
  import { TurnExecutionPolicyDefinitionMismatchError } from "@opengeni/config";
5251
5283
  import {
@@ -5256,7 +5288,7 @@ import {
5256
5288
  } from "@opengeni/codex";
5257
5289
 
5258
5290
  // src/activities/agent-turn/admission.ts
5259
- import { getBillingBalance, sumUsageQuantity } from "@opengeni/db";
5291
+ import { checkWorkspaceAllowance, getBillingBalance, sumUsageQuantity } from "@opengeni/db";
5260
5292
  import {
5261
5293
  configuredStaticUsageLimits
5262
5294
  } from "@opengeni/config";
@@ -5901,13 +5933,48 @@ function stableInteractionInterventionUuid(namespace, sessionId, turnId, toolCal
5901
5933
  return `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`;
5902
5934
  }
5903
5935
  var BudgetExhaustedError = class extends Error {
5904
- constructor(message, serializedRunState) {
5936
+ constructor(message, serializedRunState, allowance = null) {
5905
5937
  super(message);
5906
5938
  this.serializedRunState = serializedRunState;
5939
+ this.allowance = allowance;
5907
5940
  this.name = "BudgetExhaustedError";
5908
5941
  }
5909
5942
  };
5910
- async function ensureRunAllowed(settings, db, accountId, workspaceId, isExternallyBilledTurn, entitlements, chargesOpenGeniCredits = !isExternallyBilledTurn, countsTowardTokenCap = !isExternallyBilledTurn) {
5943
+ var AllowanceExhaustedError = class extends Error {
5944
+ constructor(refusal) {
5945
+ super(refusal.message);
5946
+ this.refusal = refusal;
5947
+ this.name = "AllowanceExhaustedError";
5948
+ }
5949
+ code = "allowance_exhausted";
5950
+ };
5951
+ async function ensureRunAllowedBetweenModelCalls(input) {
5952
+ try {
5953
+ await ensureRunAllowed(
5954
+ input.settings,
5955
+ input.db,
5956
+ input.accountId,
5957
+ input.workspaceId,
5958
+ input.isExternallyBilledTurn,
5959
+ input.entitlements,
5960
+ input.chargesOpenGeniCredits,
5961
+ input.countsTowardTokenCap,
5962
+ input.initiatingHumanSubjectId
5963
+ );
5964
+ } catch (limitError) {
5965
+ let serializedRunState = null;
5966
+ try {
5967
+ serializedRunState = input.serializedRunState?.() ?? null;
5968
+ } catch {
5969
+ }
5970
+ throw new BudgetExhaustedError(
5971
+ limitError instanceof Error ? limitError.message : String(limitError),
5972
+ serializedRunState,
5973
+ limitError instanceof AllowanceExhaustedError ? limitError.refusal : null
5974
+ );
5975
+ }
5976
+ }
5977
+ async function ensureRunAllowed(settings, db, accountId, workspaceId, isExternallyBilledTurn, entitlements, chargesOpenGeniCredits = !isExternallyBilledTurn, countsTowardTokenCap = !isExternallyBilledTurn, initiatingHumanSubjectId = null) {
5911
5978
  if (chargesOpenGeniCredits && entitlements && (settings.billingMode === "stripe" || settings.usageLimitsMode === "managed")) {
5912
5979
  const decision = await entitlements.admitRun({
5913
5980
  accountId,
@@ -5924,6 +5991,14 @@ async function ensureRunAllowed(settings, db, accountId, workspaceId, isExternal
5924
5991
  throw new Error("insufficient OpenGeni credits");
5925
5992
  }
5926
5993
  }
5994
+ if (chargesOpenGeniCredits) {
5995
+ const refusal = await checkWorkspaceAllowance(db, {
5996
+ accountId,
5997
+ workspaceId,
5998
+ subjectId: initiatingHumanSubjectId
5999
+ });
6000
+ if (refusal) throw new AllowanceExhaustedError(refusal);
6001
+ }
5927
6002
  if (settings.usageLimitsMode === "static" || settings.usageLimitsMode === "managed") {
5928
6003
  const limits = configuredStaticUsageLimits(settings);
5929
6004
  if (limits.maxMonthlyAgentRunsPerWorkspace) {
@@ -6998,19 +7073,22 @@ async function settleTurnFailure(deps) {
6998
7073
  await historySink.reconcileConversationTruth();
6999
7074
  if (!await eventing.settle({
7000
7075
  events: [
7076
+ ...error51.allowance ? [{ type: "usage.exhausted", payload: error51.allowance }] : [],
7001
7077
  {
7002
7078
  type: "turn.completed",
7003
7079
  payload: {
7004
7080
  output: "",
7005
7081
  segmentLimit: "budget_exhausted",
7006
- detail: error51.message
7082
+ detail: error51.message,
7083
+ ...error51.allowance ?? {}
7007
7084
  }
7008
7085
  },
7009
7086
  { type: "session.status.changed", payload: { status: "idle" } }
7010
7087
  ],
7011
7088
  turnStatus: "completed",
7012
7089
  sessionStatus: "idle",
7013
- activeTurnId: null
7090
+ activeTurnId: null,
7091
+ ...error51.allowance ? { allowanceGoalPause: { rationale: error51.allowance.message } } : {}
7014
7092
  })) {
7015
7093
  return claimedResult({ status: "cancelled" });
7016
7094
  }
@@ -7078,10 +7156,12 @@ async function settleTurnFailure(deps) {
7078
7156
  }
7079
7157
  }
7080
7158
  const earlyDefinitionMismatch = error51 instanceof TurnExecutionPolicyDefinitionMismatchError && !attempt.modelRequestStarted && !eventing.turnStartedPublished && !!attempt.turnId && !!attempt.triggerEventId && attempt.executionGeneration > 0;
7159
+ const earlyCommandStartUnavailable = isModalTaskExecStartPreDispatchUnavailableError(error51) && !attempt.modelRequestStarted && !eventing.turnStartedPublished && !!attempt.turnId && !!attempt.triggerEventId && attempt.executionGeneration > 0;
7160
+ const earlyRecoverableSetup = earlyDefinitionMismatch || earlyCommandStartUnavailable;
7081
7161
  let failure2 = earlyDefinitionMismatch ? { error: error51.message, code: error51.code, retryable: true } : codexTerminalFailure ?? agentRunFailurePayload(error51, {
7082
7162
  isCodexTurn: billingState.isCodexTurn
7083
7163
  });
7084
- if (attempt.turnId && (earlyDefinitionMismatch || failure2.retryable && eventing.publish && eventing.turnStartedPublished)) {
7164
+ if (attempt.turnId && (earlyRecoverableSetup || failure2.retryable && eventing.publish && eventing.turnStartedPublished)) {
7085
7165
  const nextProviderRecoveryCount = attempt.providerRecoveryCount + 1;
7086
7166
  const recoveryResult = providerRecoveryResult({
7087
7167
  failureCode: failure2.code,
@@ -7090,7 +7170,7 @@ async function settleTurnFailure(deps) {
7090
7170
  });
7091
7171
  try {
7092
7172
  if (recoveryResult.status === "recovering") {
7093
- if (!earlyDefinitionMismatch) {
7173
+ if (!earlyRecoverableSetup) {
7094
7174
  await flushRuntimeBatcher();
7095
7175
  await historySink.reconcileConversationTruth({ requireDurable: true });
7096
7176
  }
@@ -7121,13 +7201,13 @@ async function settleTurnFailure(deps) {
7121
7201
  return claimedResult(recoveryResult);
7122
7202
  }
7123
7203
  failure2 = providerRecoveryExhaustedFailure(failure2, recoveryResult);
7124
- if (earlyDefinitionMismatch) {
7204
+ if (earlyRecoverableSetup) {
7125
7205
  control.activityStatus = "failed";
7126
7206
  control.turnMetricOutcome = "failed";
7127
7207
  control.activityError = error51;
7128
7208
  throw ApplicationFailure.create({
7129
- message: `${error51.message}. Automatic same-turn configuration recovery exhausted after ${recoveryResult.providerRecoveryCount} retries.`,
7130
- type: "TurnExecutionPolicyDefinitionMismatchError",
7209
+ message: earlyDefinitionMismatch ? `${error51.message}. Automatic same-turn configuration recovery exhausted after ${recoveryResult.providerRecoveryCount} retries.` : failure2.error,
7210
+ type: earlyDefinitionMismatch ? "TurnExecutionPolicyDefinitionMismatchError" : "SandboxCommandStartUnavailableError",
7131
7211
  nonRetryable: true
7132
7212
  });
7133
7213
  }
@@ -7216,6 +7296,9 @@ async function settleTurnFailure(deps) {
7216
7296
  // src/activities/agent-turn/stream-attempt.ts
7217
7297
  import { measureMcpPhase, withMcpCallIdentity } from "@opengeni/observability";
7218
7298
  import {
7299
+ appendSessionHistoryItems as appendSessionHistoryItems3,
7300
+ sessionTurnFinalReplyFacts,
7301
+ sessionTurnHasFinalReplyNudge,
7219
7302
  getSessionHumanInputRequest,
7220
7303
  getWorkspace,
7221
7304
  recordUsageEvent as recordUsageEvent3,
@@ -7665,7 +7748,8 @@ async function resolveTurnSandboxAccess(sandboxState, sdkOwnedSandboxSession, un
7665
7748
  // src/activities/open-suffix-resume.ts
7666
7749
  import {
7667
7750
  OPEN_SUFFIX_RUN_STATE_BLOB,
7668
- approvalIdentifier
7751
+ approvalIdentifier,
7752
+ withPublicApprovalFields
7669
7753
  } from "@opengeni/contracts";
7670
7754
  import {
7671
7755
  appendSessionHistoryItems as appendSessionHistoryItems2,
@@ -7931,7 +8015,7 @@ async function settleOpenSuffixResumeIfNeeded(input) {
7931
8015
  ...requiresActionApprovals.length > 0 ? [
7932
8016
  {
7933
8017
  type: "session.requiresAction",
7934
- payload: { approvals: requiresActionApprovals }
8018
+ payload: { approvals: requiresActionApprovals.map(withPublicApprovalFields) }
7935
8019
  }
7936
8020
  ] : [],
7937
8021
  {
@@ -7969,9 +8053,85 @@ function interruptionCallIdsFromPause(input) {
7969
8053
  // src/activities/agent-turn/stream-attempt.ts
7970
8054
  import {
7971
8055
  OPEN_SUFFIX_RUN_STATE_BLOB as OPEN_SUFFIX_RUN_STATE_BLOB2,
7972
- resolveWorkspaceAgentHumanInputEnabled
8056
+ resolveWorkspaceAgentHumanInputEnabled,
8057
+ withPublicApprovalFields as withPublicApprovalFields2
7973
8058
  } from "@opengeni/contracts";
7974
8059
 
8060
+ // src/activities/agent-turn/model-call-admission.ts
8061
+ function createModelCallAdmission(input) {
8062
+ const receipts = /* @__PURE__ */ new WeakMap();
8063
+ const responseReceipts = /* @__PURE__ */ new Map();
8064
+ const pending = /* @__PURE__ */ new Set();
8065
+ const responseId = (event) => {
8066
+ const id = event?.response?.id;
8067
+ return typeof id === "string" && id.length > 0 ? id : null;
8068
+ };
8069
+ let latest = Promise.resolve();
8070
+ let failure2;
8071
+ let failed = false;
8072
+ let rejectHalted;
8073
+ const halted = new Promise((_, reject) => {
8074
+ rejectHalted = reject;
8075
+ });
8076
+ void halted.catch(() => void 0);
8077
+ const fail = (error51) => {
8078
+ if (failed) return;
8079
+ failed = true;
8080
+ failure2 = error51;
8081
+ rejectHalted(error51);
8082
+ for (const receipt of pending) receipt.reject(error51);
8083
+ pending.clear();
8084
+ responseReceipts.clear();
8085
+ };
8086
+ const abort = () => fail(input.signal.reason ?? new Error("Model stream cancelled"));
8087
+ input.signal.addEventListener("abort", abort, { once: true });
8088
+ if (input.signal.aborted) abort();
8089
+ return {
8090
+ beforeModelRequest: async () => {
8091
+ await Promise.race([latest, halted]);
8092
+ if (failed) throw failure2;
8093
+ await Promise.race([input.admit(), halted]);
8094
+ if (failed) throw failure2;
8095
+ },
8096
+ onModelResponse: (event) => {
8097
+ if (failed) return Promise.reject(failure2);
8098
+ const id = responseId(event);
8099
+ const existing = receipts.get(event) ?? (id ? responseReceipts.get(id) : void 0) ?? (!id && pending.size === 1 ? pending.values().next().value : void 0);
8100
+ if (existing) return existing.promise;
8101
+ let resolve;
8102
+ let reject;
8103
+ const promise2 = new Promise((yes, no) => {
8104
+ resolve = yes;
8105
+ reject = no;
8106
+ });
8107
+ void promise2.catch(() => void 0);
8108
+ const receipt = { promise: promise2, resolve, reject };
8109
+ receipts.set(event, receipt);
8110
+ if (id) responseReceipts.set(id, receipt);
8111
+ pending.add(receipt);
8112
+ latest = promise2;
8113
+ return promise2;
8114
+ },
8115
+ settle: (event) => {
8116
+ if (event.type !== "raw_model_stream_event" || !event.data || typeof event.data !== "object")
8117
+ return;
8118
+ if (event.data.type !== "response_done") return;
8119
+ const id = responseId(event.data);
8120
+ const receipt = receipts.get(event.data) ?? (id ? responseReceipts.get(id) : void 0) ?? (pending.size === 1 ? pending.values().next().value : void 0);
8121
+ if (!receipt) return;
8122
+ pending.delete(receipt);
8123
+ if (id) responseReceipts.delete(id);
8124
+ receipt.resolve();
8125
+ },
8126
+ fail,
8127
+ close: () => {
8128
+ input.signal.removeEventListener("abort", abort);
8129
+ if (pending.size > 0) fail(new Error("Model stream closed before response settlement"));
8130
+ responseReceipts.clear();
8131
+ }
8132
+ };
8133
+ }
8134
+
7975
8135
  // src/activities/agent-turn/session-title.ts
7976
8136
  import { hasPermission } from "@opengeni/core";
7977
8137
  import { isManagedOpenRouterFreeRoute } from "@opengeni/config";
@@ -7986,7 +8146,7 @@ function shouldRequestMissingSessionTitle(input) {
7986
8146
  const title = input.title?.trim() ?? "";
7987
8147
  const needsSemanticTitle = input.titleSource !== "user" && (!title || title === AUTOMATIC_SESSION_TITLE_FALLBACK);
7988
8148
  if (!needsSemanticTitle) return false;
7989
- if (!input.firstPartyMcpTools.includes("set_session_title")) return false;
8149
+ if (!input.agentConfig && !input.firstPartyMcpTools.includes("set_session_title")) return false;
7990
8150
  const permissions = input.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS;
7991
8151
  return hasPermission([...permissions], "sessions:control");
7992
8152
  }
@@ -7994,7 +8154,7 @@ function routeAllowsSessionTitleRequests(resolvedModel) {
7994
8154
  return !resolvedModel || !isManagedOpenRouterFreeRoute(resolvedModel);
7995
8155
  }
7996
8156
  function sessionTitleToolPlan(input) {
7997
- const titleToolAvailable = input.shouldRequestTitle && input.tools.some((tool) => tool.kind === "mcp" && tool.id === "opengeni");
8157
+ const titleToolAvailable = input.shouldRequestTitle && (input.agentConfig != null || input.tools.some((tool) => tool.kind === "mcp" && tool.id === "opengeni"));
7998
8158
  const titleRequestAllowed = titleToolAvailable && input.routeAllowsTitleRequests;
7999
8159
  const generateTitleInParallel = titleRequestAllowed && input.parallelGenerationAvailable;
8000
8160
  const promoteTitleTool = titleRequestAllowed && !generateTitleInParallel;
@@ -8301,6 +8461,24 @@ function createSharedRigSetupCoordinator(options) {
8301
8461
  };
8302
8462
  }
8303
8463
 
8464
+ // src/activities/agent-turn/final-reply.ts
8465
+ function finalReplyNudge(turnId) {
8466
+ return {
8467
+ type: "message",
8468
+ role: "developer",
8469
+ content: [
8470
+ {
8471
+ type: "input_text",
8472
+ text: `[Runtime final-reply handoff for turn ${turnId}]
8473
+ Your final user-facing answer was empty. Reply to the user now with the requested deliverable or a concise outcome and its retained artifact link. Goal evidence is a short ledger proof, not the answer, and goal_complete does not deliver a chat reply. Use the completed work and tool results already in history; do not repeat completed tools or restart the task. If this is a late child result after goal completion, integrate material new findings and deliver any still-missing handoff. Do not change the completed goal or invent a result.`
8474
+ }
8475
+ ]
8476
+ };
8477
+ }
8478
+ function needsFinalReply(input) {
8479
+ return typeof input.output === "string" && input.output.trim().length === 0 && !input.inputWaitYielded && !input.interrupted && !input.maintenance && (input.toolsExecuted || input.completedGoal);
8480
+ }
8481
+
8304
8482
  // src/activities/agent-turn/stream-attempt.ts
8305
8483
  async function attachPendingUpdatesBeforePreparingModelInput(input) {
8306
8484
  if (input.shouldAttach && !await input.attachPendingUpdates()) return false;
@@ -8567,12 +8745,33 @@ async function runTurnStreamAttempt(deps) {
8567
8745
  const modelResponseState = createModelResponseEventState(claimedModelUsageSourceKeys);
8568
8746
  let latestAssistantMessageText = null;
8569
8747
  let workerPreparationTotalRecorded = false;
8748
+ let toolsExecuted = false;
8749
+ let finalReplyNudged = false;
8750
+ const revalidateModelCallAdmission = async () => {
8751
+ await historySink.reconcileConversationTruth({ requireDurable: true });
8752
+ await ensureRunAllowedBetweenModelCalls({
8753
+ settings,
8754
+ db,
8755
+ accountId: input.accountId,
8756
+ workspaceId: input.workspaceId,
8757
+ isExternallyBilledTurn: billingState.isExternallyBilledTurn,
8758
+ entitlements,
8759
+ chargesOpenGeniCredits: billingState.chargesOpenGeniCredits,
8760
+ countsTowardTokenCap: billingState.countsTowardTokenCap,
8761
+ initiatingHumanSubjectId: turn.initiatingHumanSubjectId
8762
+ });
8763
+ };
8570
8764
  const runStreamAttempt = async (options) => {
8571
8765
  if (!runInput) {
8572
8766
  throw new Error("Run input was not prepared");
8573
8767
  }
8574
- const responseCountBeforeStream = modelResponseState.responseCount;
8575
8768
  eventing.stream = void 0;
8769
+ if (options.requireTerminalModelResponse) await revalidateModelCallAdmission();
8770
+ const modelCallAdmission = createModelCallAdmission({
8771
+ signal: runtimeCancellationSignal,
8772
+ admit: revalidateModelCallAdmission
8773
+ });
8774
+ const responseCountBeforeStream = modelResponseState.responseCount;
8576
8775
  eventing.batcher = null;
8577
8776
  let currentToolBatchCallIds = /* @__PURE__ */ new Set();
8578
8777
  let currentToolBatchCompletedCallIds = /* @__PURE__ */ new Set();
@@ -8740,6 +8939,8 @@ async function runTurnStreamAttempt(deps) {
8740
8939
  }
8741
8940
  attempt.modelRequestStarted = true;
8742
8941
  return await runtime.runStream(agent, runInput, eventing.modelRunSettings, {
8942
+ beforeModelRequest: modelCallAdmission.beforeModelRequest,
8943
+ onModelResponse: modelCallAdmission.onModelResponse,
8743
8944
  signal: runtimeCancellationSignal,
8744
8945
  sandboxEnvironment,
8745
8946
  onModelVisibleContext: async (snapshot) => {
@@ -8846,7 +9047,13 @@ async function runTurnStreamAttempt(deps) {
8846
9047
  if (leases.xai.lost) {
8847
9048
  throw new Error("xAI credential lease expired before the model run");
8848
9049
  }
8849
- eventing.stream = await withProviderRequestContext(runStreamOnce);
9050
+ try {
9051
+ eventing.stream = await withProviderRequestContext(runStreamOnce);
9052
+ } catch (error51) {
9053
+ modelCallAdmission.fail(error51);
9054
+ modelCallAdmission.close();
9055
+ throw error51;
9056
+ }
8850
9057
  const streamTiming = new StreamTimingMetrics(observability, {
8851
9058
  provider: streamProvider
8852
9059
  });
@@ -8985,32 +9192,20 @@ async function runTurnStreamAttempt(deps) {
8985
9192
  await historySink.reconcileConversationTruth();
8986
9193
  turnLifecycleMetricsFor(observability).progress({ attemptId: input.attemptId });
8987
9194
  modelCheckpointMemoryCollector.schedule(observability);
8988
- try {
8989
- await ensureRunAllowed(
8990
- settings,
8991
- db,
8992
- input.accountId,
8993
- input.workspaceId,
8994
- billingState.isExternallyBilledTurn,
8995
- entitlements,
8996
- billingState.chargesOpenGeniCredits,
8997
- billingState.countsTowardTokenCap
8998
- );
8999
- } catch (limitError) {
9000
- let serializedRunState = null;
9001
- try {
9002
- serializedRunState = media.compactMediaRunState(
9003
- String(eventing.stream.state.toString())
9004
- );
9005
- } catch {
9006
- serializedRunState = null;
9007
- }
9008
- throw new BudgetExhaustedError(
9009
- limitError instanceof Error ? limitError.message : String(limitError),
9010
- serializedRunState
9011
- );
9012
- }
9195
+ await ensureRunAllowedBetweenModelCalls({
9196
+ settings,
9197
+ db,
9198
+ accountId: input.accountId,
9199
+ workspaceId: input.workspaceId,
9200
+ isExternallyBilledTurn: billingState.isExternallyBilledTurn,
9201
+ entitlements,
9202
+ chargesOpenGeniCredits: billingState.chargesOpenGeniCredits,
9203
+ countsTowardTokenCap: billingState.countsTowardTokenCap,
9204
+ initiatingHumanSubjectId: turn.initiatingHumanSubjectId,
9205
+ serializedRunState: () => media.compactMediaRunState(String(eventing.stream.state.toString()))
9206
+ });
9013
9207
  }
9208
+ modelCallAdmission.settle(next.value);
9014
9209
  const durableSdkEvent = generatedImageReceipt ? compactGeneratedImageSdkEvent(next.value, generatedImageReceipt) : next.value;
9015
9210
  const pendingToolCall = pendingToolCallFromSdkEvent(durableSdkEvent);
9016
9211
  if (pendingToolCall) {
@@ -9044,6 +9239,7 @@ async function runTurnStreamAttempt(deps) {
9044
9239
  }
9045
9240
  const completedToolCall = completedToolCallFromSdkEvent(durableSdkEvent);
9046
9241
  if (completedToolCall) {
9242
+ toolsExecuted = true;
9047
9243
  retainedScreenshotMetadata = media.retainedScreenshotReceiptsByCallId.get(completedToolCall.callId) ?? null;
9048
9244
  const typedScreenshot = retainedScreenshotMetadata ? null : typedScreenshotFromSdkEvent(durableSdkEvent);
9049
9245
  if (!retainedScreenshotMetadata && media.retainedSessionImageCallIds.has(completedToolCall.callId) && sdkEventContainsInlineImage(durableSdkEvent) && !typedScreenshot) {
@@ -9225,6 +9421,7 @@ async function runTurnStreamAttempt(deps) {
9225
9421
  }
9226
9422
  }
9227
9423
  } catch (error51) {
9424
+ modelCallAdmission.fail(error51);
9228
9425
  closeStreamWaitAdmission?.();
9229
9426
  if (fallbackProviderRequestLifecycleStartedAt !== null) {
9230
9427
  const durationMs = Math.max(
@@ -9274,6 +9471,7 @@ async function runTurnStreamAttempt(deps) {
9274
9471
  }
9275
9472
  throw error51;
9276
9473
  } finally {
9474
+ modelCallAdmission.close();
9277
9475
  if (!streamDone) {
9278
9476
  void iterator.return?.().catch(() => void 0);
9279
9477
  }
@@ -9284,7 +9482,7 @@ async function runTurnStreamAttempt(deps) {
9284
9482
  temporalCancellationSignal: cancellationSignal,
9285
9483
  runtimeCancellationSignal
9286
9484
  });
9287
- await eventing.preparedTools?.inputWaitYield?.sealForSettlement(runtimeCancellationSignal);
9485
+ await eventing.preparedTools?.inputWaitYield?.drainForHandoff(runtimeCancellationSignal);
9288
9486
  if (options.requireTerminalModelResponse && !eventing.preparedTools?.inputWaitYield?.yielded && eventing.stream.interruptions.length === 0 && modelResponseState.responseCount === responseCountBeforeStream) {
9289
9487
  throwIfWorkerShuttingDown();
9290
9488
  throwIfTurnCancelled();
@@ -9380,6 +9578,7 @@ async function runTurnStreamAttempt(deps) {
9380
9578
  }
9381
9579
  }
9382
9580
  if (eventing.stream.interruptions.length > 0) {
9581
+ await eventing.preparedTools?.inputWaitYield?.sealForSettlement(runtimeCancellationSignal);
9383
9582
  await historySink.reconcileConversationTruth({ requireDurable: true });
9384
9583
  const approvals = runtime.serializeApprovals(eventing.stream.interruptions);
9385
9584
  const humanInputInterruptions = runtime.serializeHumanInputRequests?.(eventing.stream.interruptions) ?? [];
@@ -9487,9 +9686,11 @@ async function runTurnStreamAttempt(deps) {
9487
9686
  type: "session.requiresAction",
9488
9687
  payload: {
9489
9688
  approvals: approvals.map(
9490
- (approval) => withMcpToolDisplayMetadata(
9491
- eventing.preparedTools?.mcpServers ?? [],
9492
- approval
9689
+ (approval) => withPublicApprovalFields2(
9690
+ withMcpToolDisplayMetadata(
9691
+ eventing.preparedTools?.mcpServers ?? [],
9692
+ approval
9693
+ )
9493
9694
  )
9494
9695
  )
9495
9696
  }
@@ -9520,6 +9721,48 @@ async function runTurnStreamAttempt(deps) {
9520
9721
  const finalOutput = String(
9521
9722
  requireAgentStreamFinalOutput(eventing.stream.finalOutput, inputWaitYielded)
9522
9723
  );
9724
+ const durableReplyFacts = !inputWaitYielded && finalOutput.trim().length === 0 ? await sessionTurnFinalReplyFacts(db, input.workspaceId, input.sessionId, activeTurnId) : { toolsExecuted: false, completedGoal: false };
9725
+ let emptyFinalReply = false;
9726
+ if (needsFinalReply({
9727
+ output: finalOutput,
9728
+ inputWaitYielded: inputWaitYielded || eventing.preparedTools?.inputWaitYield?.requested === true,
9729
+ interrupted: false,
9730
+ // interruption settlement returned above
9731
+ maintenance: turn.source === "compaction",
9732
+ toolsExecuted: toolsExecuted || finalReplyNudged || durableReplyFacts.toolsExecuted,
9733
+ completedGoal: durableReplyFacts.completedGoal
9734
+ })) {
9735
+ await historySink.reconcileConversationTruth({ requireDurable: true });
9736
+ if (finalReplyNudged || await sessionTurnHasFinalReplyNudge(
9737
+ db,
9738
+ input.workspaceId,
9739
+ input.sessionId,
9740
+ activeTurnId,
9741
+ finalReplyNudge(activeTurnId).content[0].text
9742
+ )) {
9743
+ emptyFinalReply = true;
9744
+ } else {
9745
+ const appended = await appendSessionHistoryItems3(db, {
9746
+ accountId: input.accountId,
9747
+ workspaceId: input.workspaceId,
9748
+ sessionId: input.sessionId,
9749
+ turnId: activeTurnId,
9750
+ expectedExecutionGeneration: attempt.executionGeneration,
9751
+ expectedAttemptId: input.attemptId,
9752
+ items: [
9753
+ {
9754
+ position: await nextSessionHistoryPosition2(db, input.workspaceId, input.sessionId),
9755
+ item: finalReplyNudge(activeTurnId)
9756
+ }
9757
+ ]
9758
+ });
9759
+ if (!appended) throw new TurnAttemptFencedError("turn ended before final reply handoff");
9760
+ finalReplyNudged = true;
9761
+ await prepareRunAttemptInput();
9762
+ return "reply_nudge";
9763
+ }
9764
+ }
9765
+ await eventing.preparedTools?.inputWaitYield?.sealForSettlement(runtimeCancellationSignal);
9523
9766
  const finalOutputAlreadyCompleted = latestStreamedAssistantText === finalOutput;
9524
9767
  const reply = await inputWaitReply({
9525
9768
  inputWaitYielded,
@@ -9539,7 +9782,11 @@ async function runTurnStreamAttempt(deps) {
9539
9782
  ...inputWaitYielded || finalOutputAlreadyCompleted ? [] : [{ type: "agent.message.completed", payload: { text: finalOutput } }],
9540
9783
  {
9541
9784
  type: "turn.completed",
9542
- payload: { output: finalOutput, ...reply === null ? {} : { reply } }
9785
+ payload: {
9786
+ output: finalOutput,
9787
+ ...reply === null ? {} : { reply },
9788
+ ...emptyFinalReply ? { emptyFinalReply: true } : {}
9789
+ }
9543
9790
  },
9544
9791
  { type: "session.status.changed", payload: { status: "idle" } }
9545
9792
  ],
@@ -9595,6 +9842,7 @@ async function runTurnStreamAttempt(deps) {
9595
9842
  })) {
9596
9843
  return claimedResult({ status: "cancelled" });
9597
9844
  }
9845
+ await revalidateModelCallAdmission();
9598
9846
  if (turn.source !== "compaction" && generateSessionTitleInParallel && runtime.generateSessionTitle && !runtimeCancellationSignal.aborted) {
9599
9847
  const serviceTier = serviceTierForLatencyMode(
9600
9848
  turnExecutionPolicy.providerId,
@@ -9626,11 +9874,19 @@ async function runTurnStreamAttempt(deps) {
9626
9874
  }
9627
9875
  try {
9628
9876
  let retriedAfterCompaction = false;
9877
+ finalReplyNudged = await sessionTurnHasFinalReplyNudge(
9878
+ db,
9879
+ input.workspaceId,
9880
+ input.sessionId,
9881
+ activeTurnId,
9882
+ finalReplyNudge(activeTurnId).content[0].text
9883
+ );
9629
9884
  while (true) {
9630
9885
  try {
9631
9886
  const result = await runStreamAttempt({
9632
9887
  requireTerminalModelResponse: retriedAfterCompaction
9633
9888
  });
9889
+ if (result === "reply_nudge") continue;
9634
9890
  if (retriedAfterCompaction) {
9635
9891
  observability.info("context compaction recovery succeeded after in-activity retry", {
9636
9892
  sessionId: input.sessionId,
@@ -9841,7 +10097,9 @@ import {
9841
10097
  loadOrganizationModelProviderApiKey,
9842
10098
  listWorkspaceProviderCustomModels,
9843
10099
  getWorkspaceProviderCustomModelForExecution,
9844
- loadWorkspaceProviderApiKey
10100
+ loadWorkspaceProviderApiKey,
10101
+ loadClaudeSubscriptionUsageCredential,
10102
+ assertModelConnectionAllowsTurn
9845
10103
  } from "@opengeni/db";
9846
10104
  async function settingsWithSessionMcpServersForRun(db, workspaceId, sessionId, attemptId, settings, options) {
9847
10105
  const encryptionKey = environmentsEncryptionKeyBytes(settings);
@@ -9999,12 +10257,24 @@ async function settingsWithOrganizationProviderCredentials(db, accountId, worksp
9999
10257
  if (kind === "claude_subscription" && !settings.claudeSubscriptionEnabled) continue;
10000
10258
  const models = await buildModels(kind, claudeProviderId(kind) + "/");
10001
10259
  result = withClaudeConnectionCatalog(result, { [kind]: { models } });
10002
- const credential = await loadOrganizationModelProviderApiKey(db, settings, {
10260
+ const binding = kind === "claude_subscription" ? await loadClaudeSubscriptionUsageCredential(db, settings, {
10261
+ accountId,
10262
+ workspaceId,
10263
+ scope: "organization"
10264
+ }) : null;
10265
+ const credential = kind === "claude_subscription" ? binding?.serializedCredential : await loadOrganizationModelProviderApiKey(db, settings, {
10003
10266
  accountId,
10004
10267
  workspaceId,
10005
10268
  providerKind: kind
10006
10269
  });
10007
- if (credential) result = withClaudeConnectionCredential(result, kind, credential);
10270
+ if (credential)
10271
+ result = withClaudeConnectionCredential(
10272
+ result,
10273
+ kind,
10274
+ credential,
10275
+ "organization",
10276
+ binding ?? void 0
10277
+ );
10008
10278
  const workspaceModels = await listWorkspaceProviderCustomModels(db, {
10009
10279
  accountId,
10010
10280
  workspaceId,
@@ -10027,15 +10297,27 @@ async function settingsWithOrganizationProviderCredentials(db, accountId, worksp
10027
10297
  { [kind]: { models: workspaceModels } },
10028
10298
  "workspace"
10029
10299
  );
10030
- const workspaceCredential = await loadWorkspaceProviderApiKey(
10031
- db,
10032
- settings,
10300
+ const workspaceBinding = kind === "claude_subscription" ? await loadClaudeSubscriptionUsageCredential(db, settings, {
10301
+ accountId,
10033
10302
  workspaceId,
10034
- kind,
10035
- workspaceModelId
10036
- );
10303
+ scope: "workspace"
10304
+ }) : null;
10305
+ if (workspaceBinding && workspaceModelId)
10306
+ await assertModelConnectionAllowsTurn(db, {
10307
+ workspaceId,
10308
+ subjectId: "worker:model-access",
10309
+ modelId: workspaceModelId,
10310
+ workspaceProviderConnectionId: workspaceBinding.connectionId
10311
+ });
10312
+ const workspaceCredential = kind === "claude_subscription" ? workspaceBinding?.serializedCredential : await loadWorkspaceProviderApiKey(db, settings, workspaceId, kind, workspaceModelId);
10037
10313
  if (workspaceCredential)
10038
- result = withClaudeConnectionCredential(result, kind, workspaceCredential, "workspace");
10314
+ result = withClaudeConnectionCredential(
10315
+ result,
10316
+ kind,
10317
+ workspaceCredential,
10318
+ "workspace",
10319
+ workspaceBinding ?? void 0
10320
+ );
10039
10321
  }
10040
10322
  return result;
10041
10323
  }
@@ -10180,7 +10462,9 @@ async function claimTurnAttempt(deps) {
10180
10462
  claimedPolicy.kind === "valid" ? claimedPolicy.policy.productModelId : turn.model
10181
10463
  );
10182
10464
  const codexAppsCredentialId = capabilitySettings.codexConnectedAppsEnabled ? await resolveCodexAppsCredentialIdForRun(db, input.workspaceId) : null;
10183
- const policyForAbsent = claimedPolicy.kind === "valid" ? claimedPolicy.policy : resolveTurnExecutionPolicyV12(capabilitySettings, legacyTurnExecutionPolicyInput(turn));
10465
+ const candidatePolicy = claimedPolicy.kind === "valid" ? claimedPolicy.policy : resolveTurnExecutionPolicyV12(capabilitySettings, legacyTurnExecutionPolicyInput(turn));
10466
+ const credentialRestriction = claimedPolicy.kind === "absent" ? turn.initiatorContext?.credentialRestriction === "developer_setup" ? "developer_setup" : turnCredentialRestriction(candidatePolicy, session.metadata) : void 0;
10467
+ const policyForAbsent = credentialRestriction ? { ...candidatePolicy, credentialRestriction } : candidatePolicy;
10184
10468
  const installedPolicy = await installOrReadTurnExecutionPolicyForAttempt(db, {
10185
10469
  accountId: input.accountId,
10186
10470
  workspaceId: input.workspaceId,
@@ -10253,20 +10537,27 @@ async function claimTurnAttempt(deps) {
10253
10537
  return attached.action === "claimed" && attached.turn.id === turn.id;
10254
10538
  };
10255
10539
  turnLifecycleMetricsFor(observability).start({ attemptId: input.attemptId });
10256
- await waitForTurnOperation(
10257
- ensureRunAllowed(
10258
- capabilitySettings,
10259
- db,
10260
- input.accountId,
10261
- input.workspaceId,
10262
- billingState.isExternallyBilledTurn,
10263
- entitlements,
10264
- billingState.chargesOpenGeniCredits,
10265
- billingState.countsTowardTokenCap
10266
- ),
10267
- cancellationSignal,
10268
- void 0
10269
- );
10540
+ let allowanceRefusal = null;
10541
+ try {
10542
+ await waitForTurnOperation(
10543
+ ensureRunAllowed(
10544
+ capabilitySettings,
10545
+ db,
10546
+ input.accountId,
10547
+ input.workspaceId,
10548
+ billingState.isExternallyBilledTurn,
10549
+ entitlements,
10550
+ billingState.chargesOpenGeniCredits,
10551
+ billingState.countsTowardTokenCap,
10552
+ turn.initiatingHumanSubjectId
10553
+ ),
10554
+ cancellationSignal,
10555
+ void 0
10556
+ );
10557
+ } catch (error51) {
10558
+ if (!(error51 instanceof AllowanceExhaustedError)) throw error51;
10559
+ allowanceRefusal = error51.refusal;
10560
+ }
10270
10561
  const throwIfWorkerShuttingDown = () => {
10271
10562
  const reason = activityContext?.cancellationSignal.reason;
10272
10563
  if (isWorkerShutdownCancellation(reason)) {
@@ -10371,6 +10662,7 @@ async function claimTurnAttempt(deps) {
10371
10662
  sessionStatus: inputSettlement.sessionStatus,
10372
10663
  activeTurnId: inputSettlement.activeTurnId,
10373
10664
  ...inputSettlement.suppressGoalContinuation !== void 0 ? { suppressGoalContinuation: inputSettlement.suppressGoalContinuation } : {},
10665
+ ...inputSettlement.allowanceGoalPause ? { allowanceGoalPause: inputSettlement.allowanceGoalPause } : {},
10374
10666
  events: inputs,
10375
10667
  ...runState ? { runState } : {},
10376
10668
  ...compactionRequestFailure ? { compactionRequestFailure } : {}
@@ -10418,6 +10710,31 @@ async function claimTurnAttempt(deps) {
10418
10710
  durationSeconds: (performance.now() - activityStarted) / 1e3
10419
10711
  });
10420
10712
  const turnStartSettlementStartedAt = performance.now();
10713
+ if (allowanceRefusal) {
10714
+ if (!await eventing.settle({
10715
+ events: [
10716
+ { type: "usage.exhausted", payload: allowanceRefusal },
10717
+ {
10718
+ type: "turn.completed",
10719
+ payload: {
10720
+ output: "",
10721
+ segmentLimit: "budget_exhausted",
10722
+ ...allowanceRefusal
10723
+ }
10724
+ },
10725
+ { type: "session.status.changed", payload: { status: "idle" } }
10726
+ ],
10727
+ turnStatus: "completed",
10728
+ sessionStatus: "idle",
10729
+ activeTurnId: null,
10730
+ allowanceGoalPause: { rationale: allowanceRefusal.message }
10731
+ })) {
10732
+ return { exit: claimedResult({ status: "cancelled" }) };
10733
+ }
10734
+ control.turnMetricOutcome = "completed";
10735
+ control.activityStatus = "idle";
10736
+ return { exit: claimedResult({ status: "idle" }) };
10737
+ }
10421
10738
  if (!await eventing.settle({
10422
10739
  events: [
10423
10740
  { type: "session.status.changed", payload: { status: "running" } },
@@ -11431,7 +11748,8 @@ import { retryWhileMissing as retryWhileMissing3 } from "@opengeni/storage";
11431
11748
  import { WorkspaceModelPolicyBlockedError } from "@opengeni/runtime";
11432
11749
  import {
11433
11750
  evaluateWorkspaceModelPolicy,
11434
- resolveWorkspaceAgentHumanInputEnabled as resolveWorkspaceAgentHumanInputEnabled2
11751
+ resolveWorkspaceAgentHumanInputEnabled as resolveWorkspaceAgentHumanInputEnabled2,
11752
+ resolveWorkspaceDefaultAgentIdentity
11435
11753
  } from "@opengeni/contracts";
11436
11754
  import { codeSearchEnabledForTurn } from "@opengeni/contracts/code-search";
11437
11755
 
@@ -11822,6 +12140,10 @@ async function prepareGovernanceAndModel(deps) {
11822
12140
  );
11823
12141
  const contextSelection = await resolveCompanyBrainContextSelection(db, governanceClaims);
11824
12142
  const workspaceAgentInstructions = contextSelection.legacyWorkspaceInstructions;
12143
+ const workspaceAgentIdentity = resolveWorkspaceDefaultAgentIdentity(
12144
+ workspace.settings,
12145
+ workspaceAgentInstructions
12146
+ ).identity;
11825
12147
  const memoryPromptMode = contextSelection.receipt.memoryPromptMode;
11826
12148
  assertWorkspaceHumanInputAllowed(agentHumanInputEnabled, "resume", humanInputResume !== null);
11827
12149
  const companyProfileIncluded = contextSelection.receipt.companyProfileIncluded;
@@ -11981,6 +12303,7 @@ async function prepareGovernanceAndModel(deps) {
11981
12303
  agentHumanInputEnabled,
11982
12304
  codeSearchEnabled,
11983
12305
  workspaceAgentInstructions,
12306
+ workspaceAgentIdentity,
11984
12307
  workspaceGovernance,
11985
12308
  structuredWorkspacePolicyActive,
11986
12309
  workspaceMemory,
@@ -12008,7 +12331,9 @@ import {
12008
12331
  appendSessionInstructions,
12009
12332
  appendWorkspaceGovernance,
12010
12333
  appendWorkspaceMemory,
12334
+ agentPromptResourcesFor,
12011
12335
  composeAgentInstructions,
12336
+ inspectPersistentAgentInstructions,
12012
12337
  requestRemoteCompactionV2,
12013
12338
  preparedCompactionRequest,
12014
12339
  queuePreparedCompaction,
@@ -12018,6 +12343,39 @@ import {
12018
12343
  estimateSerializedValueTokens,
12019
12344
  compactionSummaryOutputTokens as compactionSummaryOutputTokens2
12020
12345
  } from "@opengeni/runtime";
12346
+ function standaloneCompactionInstructions(input) {
12347
+ if (input.session.agent) {
12348
+ return inspectPersistentAgentInstructions(input.settings, {
12349
+ agentConfig: input.session.agent,
12350
+ ...input.workspaceAgentIdentity ? { workspaceAgentIdentity: input.workspaceAgentIdentity } : {},
12351
+ ...input.workspaceGovernance ? { workspaceGovernance: input.workspaceGovernance } : {},
12352
+ ...input.workspaceMemory ? { workspaceMemory: input.workspaceMemory } : {},
12353
+ ...input.session.instructions ? { sessionInstructions: input.session.instructions } : {},
12354
+ ...input.rig ? { rig: input.rig } : {},
12355
+ // Session-level facts only: per-turn attachments do not apply to a
12356
+ // standalone compaction request.
12357
+ agentPromptResources: agentPromptResourcesFor(
12358
+ input.settings,
12359
+ input.session.resources.filter((resource) => resource.kind !== "file"),
12360
+ input.rig ? { rig: input.rig } : {}
12361
+ )
12362
+ }).composed;
12363
+ }
12364
+ return appendWorkspaceMemory(
12365
+ appendSessionInstructions(
12366
+ appendWorkspaceGovernance(
12367
+ composeAgentInstructions(
12368
+ input.structuredWorkspacePolicyActive ? input.settings.agentInstructionsTemplate : input.workspaceAgentInstructions ?? input.settings.agentInstructionsTemplate,
12369
+ void 0,
12370
+ input.rig
12371
+ ),
12372
+ input.workspaceGovernance ?? void 0
12373
+ ),
12374
+ input.session.instructions ?? void 0
12375
+ ),
12376
+ input.workspaceMemory ?? void 0
12377
+ );
12378
+ }
12021
12379
  async function prepareCompaction(deps) {
12022
12380
  const {
12023
12381
  input,
@@ -12042,6 +12400,7 @@ async function prepareCompaction(deps) {
12042
12400
  turnExecutionPolicy,
12043
12401
  resolvedModel,
12044
12402
  workspaceAgentInstructions,
12403
+ workspaceAgentIdentity,
12045
12404
  workspaceGovernance,
12046
12405
  structuredWorkspacePolicyActive,
12047
12406
  workspaceMemory,
@@ -12185,20 +12544,16 @@ async function prepareCompaction(deps) {
12185
12544
  return claimedResult({ status: "idle" });
12186
12545
  };
12187
12546
  if (compactionOnlyTurn && !remoteV2CompactionNeedsAgentPrefix && !portableResponsesNeedsAgentPrefix) {
12188
- const compactionInstructions = appendWorkspaceMemory(
12189
- appendSessionInstructions(
12190
- appendWorkspaceGovernance(
12191
- composeAgentInstructions(
12192
- structuredWorkspacePolicyActive ? eventing.modelRunSettings.agentInstructionsTemplate : workspaceAgentInstructions ?? eventing.modelRunSettings.agentInstructionsTemplate,
12193
- void 0,
12194
- rigVersion && rigName ? { name: rigName, version: rigVersion.version } : void 0
12195
- ),
12196
- workspaceGovernance ?? void 0
12197
- ),
12198
- session.instructions ?? void 0
12199
- ),
12200
- workspaceMemory ?? void 0
12201
- );
12547
+ const compactionInstructions = standaloneCompactionInstructions({
12548
+ settings: eventing.modelRunSettings,
12549
+ session,
12550
+ workspaceAgentInstructions,
12551
+ workspaceAgentIdentity,
12552
+ workspaceGovernance,
12553
+ structuredWorkspacePolicyActive,
12554
+ workspaceMemory,
12555
+ rig: rigVersion && rigName ? { name: rigName, version: rigVersion.version } : void 0
12556
+ });
12202
12557
  const requested = await isSessionCompactionRequested2(db, input.workspaceId, input.sessionId);
12203
12558
  let outcome = null;
12204
12559
  if (requested) {
@@ -13267,6 +13622,7 @@ async function resolveSandboxRoute(deps) {
13267
13622
  machinePrimary,
13268
13623
  groupBoxBackend,
13269
13624
  groupBoxImage,
13625
+ groupBoxImagePolicy: "new_creates_only",
13270
13626
  sandboxCreationBackend,
13271
13627
  effectiveRunCredentialBackend
13272
13628
  };
@@ -13306,6 +13662,7 @@ async function establishTurnSandbox(deps) {
13306
13662
  machinePrimary,
13307
13663
  groupBoxBackend,
13308
13664
  groupBoxImage,
13665
+ groupBoxImagePolicy,
13309
13666
  rigVersion,
13310
13667
  turnResources
13311
13668
  } = deps;
@@ -13560,7 +13917,8 @@ async function establishTurnSandbox(deps) {
13560
13917
  os: groupBoxOs,
13561
13918
  environment: sandboxEnvironment,
13562
13919
  ...groupBoxImage ? {
13563
- image: groupBoxImage
13920
+ image: groupBoxImage,
13921
+ imagePolicy: groupBoxImagePolicy
13564
13922
  } : {},
13565
13923
  // The lazy acquire must enforce the same frozen rig authority
13566
13924
  // as the eager acquire; otherwise a warm box for another rig
@@ -13637,16 +13995,16 @@ async function establishTurnSandbox(deps) {
13637
13995
  backend: groupBoxBackend,
13638
13996
  os: groupBoxOs,
13639
13997
  environment: sandboxEnvironment,
13640
- // IMAGE IS SHARED STATE (B3): the container image
13641
- // this run resolves. The lease stamps it + conflicts on a live shared box
13642
- // running a DIFFERENT image (solo → durable rotation; N-holders →
13643
- // SandboxImageConflictError surfaced as an actionable turn error). Select
13644
- // the image for the actual group-box backend; a configured Modal image must
13998
+ // Deployment/workspace pins select NEW creates only. The lease
13999
+ // retains a live group's image through between-turn repins, even
14000
+ // with other holders; only rotation/reaping elects a new image.
14001
+ // Select the image for the actual group-box backend; a configured Modal image must
13645
14002
  // never override a Docker run. The selfhosted branch
13646
14003
  // (establishSelfhostedTurnSession) NEVER passes
13647
14004
  // an image — B3 lives only on this managed-box branch.
13648
14005
  ...groupBoxImage ? {
13649
- image: groupBoxImage
14006
+ image: groupBoxImage,
14007
+ imagePolicy: groupBoxImagePolicy
13650
14008
  } : {},
13651
14009
  // RIG IS SHARED STATE (M3): stamp the frozen rig version so the lease
13652
14010
  // conflicts on a live shared box set up under a different rig (solo
@@ -14342,6 +14700,100 @@ import {
14342
14700
  } from "@opengeni/runtime";
14343
14701
  import { codemodeWorkspaceUrl as codemodeWorkspaceUrl2 } from "@opengeni/config";
14344
14702
 
14703
+ // src/activities/mcp-account-routes.ts
14704
+ function accountRouteAuthNeededPayload(payload, bindings) {
14705
+ const binding = bindings?.find((candidate) => candidate.serverId === payload.serverId);
14706
+ return binding ? {
14707
+ ...payload,
14708
+ canonicalServerId: binding.canonicalServerId,
14709
+ connectionSubjectScope: binding.subjectScope
14710
+ } : payload;
14711
+ }
14712
+ function expandMcpAccountRoutes(input) {
14713
+ if (input.bindings == null) {
14714
+ return { settings: input.settings, tools: input.tools, accountLabels: /* @__PURE__ */ new Map() };
14715
+ }
14716
+ const configured = new Map(input.settings.mcpServers.map((server) => [server.id, server]));
14717
+ const byCanonical = /* @__PURE__ */ new Map();
14718
+ const routes = /* @__PURE__ */ new Set();
14719
+ const accounts = /* @__PURE__ */ new Set();
14720
+ for (const binding of input.bindings) {
14721
+ const account = JSON.stringify([binding.canonicalServerId, binding.connectionId]);
14722
+ if (routes.has(binding.serverId) || accounts.has(account) || configured.has(binding.serverId) || binding.subjectScope === "subject" !== (binding.ownerSubjectId !== null) || binding.connectionRef.authoritySource === "host" || binding.connectionRef.connectionId !== binding.connectionId || binding.connectionRef.subjectScope !== binding.subjectScope || binding.connectionRef.providerDomain !== binding.providerDomain || binding.connectionRef.kind !== binding.kind) {
14723
+ throw new Error("Invalid accepted MCP account route");
14724
+ }
14725
+ routes.add(binding.serverId);
14726
+ accounts.add(account);
14727
+ const siblings = byCanonical.get(binding.canonicalServerId) ?? [];
14728
+ siblings.push(binding);
14729
+ byCanonical.set(binding.canonicalServerId, siblings);
14730
+ }
14731
+ const servers = [];
14732
+ const tools = [];
14733
+ const accountLabels = /* @__PURE__ */ new Map();
14734
+ for (const tool of input.tools) {
14735
+ const bindings = byCanonical.get(tool.id);
14736
+ if (!bindings) {
14737
+ if (!configured.get(tool.id)?.connectionRef) tools.push(tool);
14738
+ continue;
14739
+ }
14740
+ const canonical = configured.get(tool.id);
14741
+ if (!canonical?.connectionRef) {
14742
+ throw new Error("Accepted MCP account route has no canonical connection configuration");
14743
+ }
14744
+ for (const binding of bindings) {
14745
+ if (canonical.connectionRef.authoritySource === "host" || canonical.connectionRef.providerDomain !== binding.providerDomain || canonical.connectionRef.kind && canonical.connectionRef.kind !== binding.kind) {
14746
+ throw new Error("Accepted MCP account route does not match canonical provider");
14747
+ }
14748
+ const { headers: _headers, ...config2 } = canonical;
14749
+ const label = `${canonical.name ?? canonical.id} \u2014 ${binding.subjectScope === "subject" ? "Personal" : "Workspace"}: ${binding.accountLabel}`;
14750
+ servers.push({
14751
+ ...config2,
14752
+ id: binding.serverId,
14753
+ name: label,
14754
+ connectionRef: structuredClone(binding.connectionRef)
14755
+ });
14756
+ tools.push({ ...tool, id: binding.serverId });
14757
+ accountLabels.set(binding.serverId, label);
14758
+ }
14759
+ }
14760
+ return {
14761
+ settings: {
14762
+ ...input.settings,
14763
+ mcpServers: [
14764
+ ...input.settings.mcpServers.filter((server) => !server.connectionRef),
14765
+ ...servers
14766
+ ]
14767
+ },
14768
+ tools,
14769
+ accountLabels
14770
+ };
14771
+ }
14772
+ function expandApiIntegrationAccountRoutes(input) {
14773
+ const selected = new Set(input.tools.map((tool) => tool.id));
14774
+ if (input.bindings == null)
14775
+ return input.integrations.filter((item) => selected.has(item.serverId));
14776
+ const acceptedBindings = input.bindings;
14777
+ return input.integrations.flatMap((integration) => {
14778
+ const bindings = acceptedBindings.filter(
14779
+ (binding) => binding.canonicalServerId === integration.serverId
14780
+ );
14781
+ if (bindings.length === 0)
14782
+ return !integration.connectionRef && selected.has(integration.serverId) ? [integration] : [];
14783
+ return bindings.filter((binding) => selected.has(binding.serverId)).map((binding) => {
14784
+ if (binding.connectionAuthorityGeneration === void 0) {
14785
+ throw new Error("Accepted API integration account route has no authority generation");
14786
+ }
14787
+ return {
14788
+ ...integration,
14789
+ serverId: binding.serverId,
14790
+ connectionRef: structuredClone(binding.connectionRef),
14791
+ connectionAuthorityGeneration: binding.connectionAuthorityGeneration
14792
+ };
14793
+ });
14794
+ });
14795
+ }
14796
+
14345
14797
  // src/activities/git-credential-renewal.ts
14346
14798
  var GIT_CREDENTIAL_DEFAULT_REFRESH_MS = 30 * 6e4;
14347
14799
  var GIT_CREDENTIAL_EXPIRY_LEAD_MS = 5 * 6e4;
@@ -14700,6 +15152,8 @@ function credentialProviderRequestBody(input, initiatingHumanSubjectId, initiati
14700
15152
  lane: "workspace",
14701
15153
  mcpServers: []
14702
15154
  }) {
15155
+ const via = input.initiatorContext.via;
15156
+ const latestHop = Array.isArray(via) ? via.at(-1) : null;
14703
15157
  return {
14704
15158
  type: "credentials.request",
14705
15159
  lane: selection.lane,
@@ -14714,6 +15168,11 @@ function credentialProviderRequestBody(input, initiatingHumanSubjectId, initiati
14714
15168
  turnId: input.turnId,
14715
15169
  attemptId: input.attemptId,
14716
15170
  initiator: { kind: input.initiator.kind, subjectId: input.initiator.subjectId },
15171
+ initiatorContext: {
15172
+ kind: latestHop?.kind === "agent" ? "agent" : input.initiator.kind === "subject" ? "human" : "service",
15173
+ initiator: input.initiator,
15174
+ context: input.initiatorContext
15175
+ },
14717
15176
  initiatingHumanSubjectId,
14718
15177
  initiatingHuman,
14719
15178
  sandboxBackend: input.effectiveSandboxBackend,
@@ -14905,7 +15364,7 @@ async function bindRunCredentialResolver(input) {
14905
15364
  mcpServers: selectedSessionRemoteMcpTargets(
14906
15365
  input.settings,
14907
15366
  input.session.mcpServers ?? [],
14908
- input.turn.tools ?? [],
15367
+ input.effectiveTools,
14909
15368
  (input.localMcpServerIds ?? []).map((id) => ({ id }))
14910
15369
  )
14911
15370
  }
@@ -14921,22 +15380,23 @@ async function bindRunCredentialResolver(input) {
14921
15380
  workspaceId: input.workspaceId,
14922
15381
  sessionId: input.session.id
14923
15382
  };
15383
+ const frozenRequest = structuredClone(
15384
+ buildRunCredentialsRequest({
15385
+ accountId: input.accountId,
15386
+ workspaceId: input.workspaceId,
15387
+ session: input.session,
15388
+ turn: input.turn,
15389
+ attemptId: input.attemptId,
15390
+ effectiveSandboxBackend: input.effectiveSandboxBackend,
15391
+ variableSet: input.variableSet,
15392
+ rootSessionId,
15393
+ purpose: "provision",
15394
+ forceRefresh: false
15395
+ })
15396
+ );
14924
15397
  return {
14925
15398
  resolve: async ({ purpose, forceRefresh }) => {
14926
- const resolution = await resolver(
14927
- buildRunCredentialsRequest({
14928
- accountId: input.accountId,
14929
- workspaceId: input.workspaceId,
14930
- session: input.session,
14931
- turn: input.turn,
14932
- attemptId: input.attemptId,
14933
- effectiveSandboxBackend: input.effectiveSandboxBackend,
14934
- variableSet: input.variableSet,
14935
- rootSessionId,
14936
- purpose,
14937
- forceRefresh
14938
- })
14939
- );
15399
+ const resolution = await resolver({ ...frozenRequest, purpose, forceRefresh });
14940
15400
  return normalizeRunCredentialsResolution(resolution, scope);
14941
15401
  }
14942
15402
  };
@@ -14959,6 +15419,7 @@ async function prepareRunCredentials(deps) {
14959
15419
  sandboxState,
14960
15420
  turn,
14961
15421
  session,
15422
+ turnExecutionPolicy,
14962
15423
  fileAuthoritySubjectId,
14963
15424
  runSettings,
14964
15425
  workspaceVariableSet,
@@ -14981,13 +15442,19 @@ async function prepareRunCredentials(deps) {
14981
15442
  const platformGitResources = turnResources.filter(
14982
15443
  (resource) => resource.kind !== "repository" || repositoryHasExplicitGitConnection(resource)
14983
15444
  );
15445
+ const accountRoutes = expandMcpAccountRoutes({
15446
+ settings: runSettings,
15447
+ tools: deps.turnTools,
15448
+ bindings: turn.mcpAccountBindings
15449
+ });
14984
15450
  const runCredentialResolver = effectiveRunCredentialBackend === "none" || effectiveRunCredentialBackend === "selfhosted" ? null : await waitForTurnOperation(
14985
15451
  bindRunCredentialResolver({
14986
15452
  db,
14987
- settings: runSettings,
15453
+ settings: accountRoutes.settings,
14988
15454
  initiatingHumanSubjectId: turn.initiatingHumanSubjectId ?? null,
14989
15455
  connectionCredentials: connectionCredentials ?? null,
14990
15456
  localMcpServerIds: deps.localMcpServerIds ?? [],
15457
+ effectiveTools: accountRoutes.tools,
14991
15458
  accountId: input.accountId,
14992
15459
  workspaceId: input.workspaceId,
14993
15460
  session,
@@ -15026,9 +15493,9 @@ async function prepareRunCredentials(deps) {
15026
15493
  ) : null;
15027
15494
  const runMcpCredentials = new RunMcpCredentials(
15028
15495
  selectedSessionRemoteMcpTargets2(
15029
- runSettings,
15496
+ accountRoutes.settings,
15030
15497
  session.mcpServers ?? [],
15031
- turn.tools ?? [],
15498
+ accountRoutes.tools,
15032
15499
  (deps.localMcpServerIds ?? []).map((id) => ({ id }))
15033
15500
  ),
15034
15501
  {
@@ -15111,11 +15578,13 @@ async function prepareRunCredentials(deps) {
15111
15578
  attemptId: input.attemptId,
15112
15579
  turn
15113
15580
  }) : void 0;
15581
+ const credentialRestriction = turnCredentialRestriction(turnExecutionPolicy, session.metadata);
15114
15582
  const codemodeAuthority = {
15115
15583
  sessionId: input.sessionId,
15116
15584
  turnId: turn.id,
15117
15585
  attemptId: input.attemptId,
15118
- executionGeneration: turn.executionGeneration
15586
+ executionGeneration: turn.executionGeneration,
15587
+ ...credentialRestriction ? { credentialRestriction } : {}
15119
15588
  };
15120
15589
  const sandboxArtifactRuntime = sandboxArtifactRuntimeAdmission(
15121
15590
  settings,
@@ -16410,100 +16879,6 @@ function isGitHubApiDestination(value) {
16410
16879
  }
16411
16880
  }
16412
16881
 
16413
- // src/activities/mcp-account-routes.ts
16414
- function accountRouteAuthNeededPayload(payload, bindings) {
16415
- const binding = bindings?.find((candidate) => candidate.serverId === payload.serverId);
16416
- return binding ? {
16417
- ...payload,
16418
- canonicalServerId: binding.canonicalServerId,
16419
- connectionSubjectScope: binding.subjectScope
16420
- } : payload;
16421
- }
16422
- function expandMcpAccountRoutes(input) {
16423
- if (input.bindings == null) {
16424
- return { settings: input.settings, tools: input.tools, accountLabels: /* @__PURE__ */ new Map() };
16425
- }
16426
- const configured = new Map(input.settings.mcpServers.map((server) => [server.id, server]));
16427
- const byCanonical = /* @__PURE__ */ new Map();
16428
- const routes = /* @__PURE__ */ new Set();
16429
- const accounts = /* @__PURE__ */ new Set();
16430
- for (const binding of input.bindings) {
16431
- const account = JSON.stringify([binding.canonicalServerId, binding.connectionId]);
16432
- if (routes.has(binding.serverId) || accounts.has(account) || configured.has(binding.serverId) || binding.subjectScope === "subject" !== (binding.ownerSubjectId !== null) || binding.connectionRef.authoritySource === "host" || binding.connectionRef.connectionId !== binding.connectionId || binding.connectionRef.subjectScope !== binding.subjectScope || binding.connectionRef.providerDomain !== binding.providerDomain || binding.connectionRef.kind !== binding.kind) {
16433
- throw new Error("Invalid accepted MCP account route");
16434
- }
16435
- routes.add(binding.serverId);
16436
- accounts.add(account);
16437
- const siblings = byCanonical.get(binding.canonicalServerId) ?? [];
16438
- siblings.push(binding);
16439
- byCanonical.set(binding.canonicalServerId, siblings);
16440
- }
16441
- const servers = [];
16442
- const tools = [];
16443
- const accountLabels = /* @__PURE__ */ new Map();
16444
- for (const tool of input.tools) {
16445
- const bindings = byCanonical.get(tool.id);
16446
- if (!bindings) {
16447
- if (!configured.get(tool.id)?.connectionRef) tools.push(tool);
16448
- continue;
16449
- }
16450
- const canonical = configured.get(tool.id);
16451
- if (!canonical?.connectionRef) {
16452
- throw new Error("Accepted MCP account route has no canonical connection configuration");
16453
- }
16454
- for (const binding of bindings) {
16455
- if (canonical.connectionRef.authoritySource === "host" || canonical.connectionRef.providerDomain !== binding.providerDomain || canonical.connectionRef.kind && canonical.connectionRef.kind !== binding.kind) {
16456
- throw new Error("Accepted MCP account route does not match canonical provider");
16457
- }
16458
- const { headers: _headers, ...config2 } = canonical;
16459
- const label = `${canonical.name ?? canonical.id} \u2014 ${binding.subjectScope === "subject" ? "Personal" : "Workspace"}: ${binding.accountLabel}`;
16460
- servers.push({
16461
- ...config2,
16462
- id: binding.serverId,
16463
- name: label,
16464
- connectionRef: structuredClone(binding.connectionRef)
16465
- });
16466
- tools.push({ ...tool, id: binding.serverId });
16467
- accountLabels.set(binding.serverId, label);
16468
- }
16469
- }
16470
- return {
16471
- settings: {
16472
- ...input.settings,
16473
- mcpServers: [
16474
- ...input.settings.mcpServers.filter((server) => !server.connectionRef),
16475
- ...servers
16476
- ]
16477
- },
16478
- tools,
16479
- accountLabels
16480
- };
16481
- }
16482
- function expandApiIntegrationAccountRoutes(input) {
16483
- const selected = new Set(input.tools.map((tool) => tool.id));
16484
- if (input.bindings == null)
16485
- return input.integrations.filter((item) => selected.has(item.serverId));
16486
- const acceptedBindings = input.bindings;
16487
- return input.integrations.flatMap((integration) => {
16488
- const bindings = acceptedBindings.filter(
16489
- (binding) => binding.canonicalServerId === integration.serverId
16490
- );
16491
- if (bindings.length === 0)
16492
- return !integration.connectionRef && selected.has(integration.serverId) ? [integration] : [];
16493
- return bindings.filter((binding) => selected.has(binding.serverId)).map((binding) => {
16494
- if (binding.connectionAuthorityGeneration === void 0) {
16495
- throw new Error("Accepted API integration account route has no authority generation");
16496
- }
16497
- return {
16498
- ...integration,
16499
- serverId: binding.serverId,
16500
- connectionRef: structuredClone(binding.connectionRef),
16501
- connectionAuthorityGeneration: binding.connectionAuthorityGeneration
16502
- };
16503
- });
16504
- });
16505
- }
16506
-
16507
16882
  // src/activities/agent-turn/tool-environment.ts
16508
16883
  import { createMcpOperationPersistence } from "@opengeni/db/mcp-operations";
16509
16884
 
@@ -32257,14 +32632,17 @@ import {
32257
32632
  buildApiIntegrationMcpServers,
32258
32633
  resolveCatalogSettings as resolveCatalogSettings2,
32259
32634
  resolveWorkspaceModelSelection,
32635
+ loadWorkspaceCodexModelAvailability,
32260
32636
  withFrozenPersonalConnectionDelegations,
32261
- resolveSessionToolPolicy,
32637
+ resolveTurnToolPolicy,
32638
+ scheduledTurnMcpServerIds,
32262
32639
  hasPermission as hasPermission2
32263
32640
  } from "@opengeni/core";
32264
32641
  import { SandboxChannelAService as SandboxChannelAService3 } from "@opengeni/runtime/sandbox";
32265
32642
  import { sandboxRunAs as sandboxRunAs4 } from "@opengeni/runtime";
32266
32643
  import {
32267
- DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2
32644
+ DEFAULT_FIRST_PARTY_MCP_PERMISSIONS as DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2,
32645
+ resolveAgentToolFamilies
32268
32646
  } from "@opengeni/contracts";
32269
32647
 
32270
32648
  // src/activities/agent-turn/list-models.ts
@@ -33703,27 +34081,31 @@ async function prepareTurnToolPolicy(deps) {
33703
34081
  } = deps;
33704
34082
  const turnResources = mergeResourceRefs(session.resources, turn.resources);
33705
34083
  const runtimeResources = runtimeResourcesForTurn(session.resources, turn.resources);
33706
- const scheduledEffectiveMcpServerIds = (() => {
33707
- const value = turn.metadata && typeof turn.metadata === "object" && !Array.isArray(turn.metadata) ? turn.metadata.scheduledEffectiveMcpServerIds : null;
33708
- return Array.isArray(value) && value.every((id) => typeof id === "string") ? [...new Set(value)].sort() : null;
33709
- })();
33710
- const currentMcpServerIds = new Set(runSettings.mcpServers.map((server) => server.id));
33711
- const resolvedToolPolicy = resolveSessionToolPolicy({
34084
+ const resolvedToolPolicy = resolveTurnToolPolicy({
33712
34085
  toolPolicy: session.toolPolicy,
33713
- sessionTools: scheduledEffectiveMcpServerIds ? turn.tools : session.tools,
33714
- availableMcpServerIds: scheduledEffectiveMcpServerIds ? scheduledEffectiveMcpServerIds.filter((id) => currentMcpServerIds.has(id)) : [...currentMcpServerIds],
33715
- defaultMcpServerIds: scheduledEffectiveMcpServerIds ?? (session.toolPolicy.mode === "workspace_default" ? await workspaceSessionToolPolicyDefaultServerIds(
34086
+ session,
34087
+ turn,
34088
+ availableMcpServerIds: runSettings.mcpServers.map((server) => server.id),
34089
+ defaultMcpServerIds: scheduledTurnMcpServerIds(turn) === null && session.toolPolicy.mode === "workspace_default" ? await workspaceSessionToolPolicyDefaultServerIds(
33716
34090
  db,
33717
34091
  input.workspaceId,
33718
34092
  capabilitySettings,
33719
34093
  fileAuthoritySubjectId ?? void 0
33720
- ) : [])
34094
+ ) : []
33721
34095
  });
33722
34096
  const mcpAvailabilityNote = unavailableMcpOperationalContext({
33723
34097
  droppedIds: resolvedToolPolicy.effectivePolicy.droppedIds,
33724
34098
  droppedCount: resolvedToolPolicy.effectivePolicy.counts.dropped
33725
34099
  });
33726
- const effectivePolicyTools = resolvedToolPolicy.toolRefs;
34100
+ const families = resolveAgentToolFamilies(session.agent, {
34101
+ productServerIds: /* @__PURE__ */ new Set([
34102
+ ...session.mcpServers.map((server) => server.id),
34103
+ ...session.toolPolicy.mode !== "workspace_default" ? session.tools.map((tool) => tool.id) : []
34104
+ ])
34105
+ });
34106
+ const effectivePolicyTools = resolvedToolPolicy.toolRefs.filter(
34107
+ (tool) => tool.kind !== "mcp" || families.allowsMcpServer(tool.id)
34108
+ );
33727
34109
  const turnTools = withFirstPartyTools(runSettings, effectivePolicyTools);
33728
34110
  const connectionScope = {
33729
34111
  accountId: input.accountId,
@@ -33854,6 +34236,7 @@ async function prepareTurnToolRuntime(deps) {
33854
34236
  });
33855
34237
  const runSettings = accountRoutes.settings;
33856
34238
  const turnTools = accountRoutes.tools;
34239
+ const credentialRestriction = turnCredentialRestriction(turnExecutionPolicy, session.metadata);
33857
34240
  const toolContextPreparationStartedAt = performance.now();
33858
34241
  throwIfWorkerShuttingDown();
33859
34242
  throwIfTurnCancelled();
@@ -34003,14 +34386,16 @@ async function prepareTurnToolRuntime(deps) {
34003
34386
  const effectiveFirstPartyPermissions = linkedAuthority ? (session.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2).filter(
34004
34387
  (permission) => hasPermission2(linkedAuthority.permissions, permission)
34005
34388
  ) : session.firstPartyMcpPermissions;
34006
- const selectedFirstPartyMcpTools = allowedFirstPartyMcpToolsForSession(
34007
- runSettings,
34008
- session.firstPartyMcpTools
34389
+ const toolFamilies = resolveAgentToolFamilies(session.agent);
34390
+ const selectedFirstPartyMcpTools = toolFamilies.firstPartyTools(
34391
+ allowedFirstPartyMcpToolsForSession(runSettings, session.firstPartyMcpTools)
34009
34392
  );
34010
34393
  const titleToolPlan = sessionTitleToolPlan({
34394
+ agentConfig: session.agent,
34011
34395
  tools: turnTools,
34012
34396
  selectedFirstPartyMcpTools,
34013
34397
  shouldRequestTitle: shouldRequestMissingSessionTitle({
34398
+ agentConfig: session.agent,
34014
34399
  title: session.title,
34015
34400
  titleSource: session.titleSource,
34016
34401
  firstPartyMcpTools: selectedFirstPartyMcpTools,
@@ -34070,7 +34455,7 @@ async function prepareTurnToolRuntime(deps) {
34070
34455
  workspaceId: input.workspaceId,
34071
34456
  ...deps.fileAuthoritySubjectId ? { subjectId: deps.fileAuthoritySubjectId } : {}
34072
34457
  });
34073
- const skillCatalog = [
34458
+ const skillCatalog = toolFamilies.skills === false ? [] : [
34074
34459
  ...sharedSkillDescriptors.filter((entry) => entry.activationMode === "workspace_managed").map((entry) => ({
34075
34460
  id: entry.id,
34076
34461
  name: entry.title,
@@ -34242,6 +34627,9 @@ async function prepareTurnToolRuntime(deps) {
34242
34627
  );
34243
34628
  }
34244
34629
  });
34630
+ const attemptToolFamilies = resolveAgentToolFamilies(session.agent, {
34631
+ hasSkills: skillCatalog.length > 0
34632
+ });
34245
34633
  const attemptToolDefinitions = [
34246
34634
  ...operationReadStore ? [
34247
34635
  createOperationReadAttemptToolDefinition({
@@ -34283,7 +34671,8 @@ async function prepareTurnToolRuntime(deps) {
34283
34671
  organizationGatewayConnectionActive,
34284
34672
  organizationGatewayCustomModels,
34285
34673
  organizationOpenRouterConnectionActive,
34286
- organizationOpenRouterCustomModels
34674
+ organizationOpenRouterCustomModels,
34675
+ codexModelAvailability
34287
34676
  ] = await Promise.all([
34288
34677
  getWorkspaceConnectionModelRestrictions(
34289
34678
  db,
@@ -34326,10 +34715,12 @@ async function prepareTurnToolRuntime(deps) {
34326
34715
  accountId: input.accountId,
34327
34716
  workspaceId: input.workspaceId,
34328
34717
  providerKind: "openrouter"
34329
- })
34718
+ }),
34719
+ loadWorkspaceCodexModelAvailability(db, currentSettings, input.workspaceId)
34330
34720
  ]);
34331
34721
  return {
34332
34722
  selections: resolveWorkspaceModelSelection({
34723
+ observations: codexModelAvailability,
34333
34724
  connectionModelRestrictions,
34334
34725
  settings: currentSettings,
34335
34726
  policy,
@@ -34369,6 +34760,7 @@ async function prepareTurnToolRuntime(deps) {
34369
34760
  ] : [],
34370
34761
  ...createFirstPartyInteractionAttemptToolDefinitions({
34371
34762
  settings: runSettings,
34763
+ ...credentialRestriction ? { credentialRestriction } : {},
34372
34764
  scope: {
34373
34765
  accountId: input.accountId,
34374
34766
  workspaceId: input.workspaceId,
@@ -34385,7 +34777,7 @@ async function prepareTurnToolRuntime(deps) {
34385
34777
  }),
34386
34778
  ...googleDrivePublicationTool && googleDrivePublicationAllowed ? [googleDrivePublicationTool] : [],
34387
34779
  ...codeSearchTools
34388
- ];
34780
+ ].filter((tool) => attemptToolFamilies.allowsFunctionTool(tool.modelName));
34389
34781
  recordTurnStartupPhase(observability, {
34390
34782
  phase: "tool_context_preparation",
34391
34783
  provider: turnExecutionPolicy.providerId,
@@ -34455,6 +34847,7 @@ async function prepareTurnToolRuntime(deps) {
34455
34847
  try {
34456
34848
  eventing.preparedTools = await waitForTurnOperation(
34457
34849
  runtime.prepareTools(githubRestMcp.settings, githubRestMcp.tools, {
34850
+ ...credentialRestriction ? { credentialRestriction } : {},
34458
34851
  mcpAccountLabels: accountRoutes.accountLabels,
34459
34852
  accountId: input.accountId,
34460
34853
  workspaceId: input.workspaceId,
@@ -34473,7 +34866,7 @@ async function prepareTurnToolRuntime(deps) {
34473
34866
  sessionAttachedRemoteMcpTargets: selectedSessionRemoteMcpTargets3(
34474
34867
  githubRestMcp.settings,
34475
34868
  session.mcpServers ?? [],
34476
- turn.tools ?? [],
34869
+ githubRestMcp.tools,
34477
34870
  localMcpServers
34478
34871
  ),
34479
34872
  ...deps.runMcpCredentials ? { runMcpCredentials: deps.runMcpCredentials } : {},
@@ -34917,7 +35310,8 @@ import {
34917
35310
  getExternalLinkTurnAuthorization as getExternalLinkTurnAuthorization2,
34918
35311
  getSessionTurnForAttempt as getSessionTurnForAttempt2,
34919
35312
  ensureSessionReasoningConfiguration,
34920
- ensureSessionSkillCatalog
35313
+ ensureSessionSkillCatalog,
35314
+ sessionHasToolRouterHistory
34921
35315
  } from "@opengeni/db";
34922
35316
  import {
34923
35317
  formatSkillCatalog,
@@ -36073,7 +36467,7 @@ function validateReferenceImage(bytes) {
36073
36467
  // src/activities/agent-turn/agent-build.ts
36074
36468
  import { SandboxChannelAService as SandboxChannelAService4 } from "@opengeni/runtime/sandbox";
36075
36469
  import { sandboxRunAs as sandboxRunAs5 } from "@opengeni/runtime";
36076
- import { VideoGenerationRejectedResult } from "@opengeni/contracts";
36470
+ import { VideoGenerationRejectedResult, resolveAgentToolFamilies as resolveAgentToolFamilies2 } from "@opengeni/contracts";
36077
36471
 
36078
36472
  // src/activities/agent-turn/video-reference-sandbox.ts
36079
36473
  async function resolveVideoReferenceSandboxAccess(request, sandboxState, sdkOwnedSandboxSession) {
@@ -36117,6 +36511,7 @@ async function buildTurnAgent(deps) {
36117
36511
  supportsImageInput,
36118
36512
  agentHumanInputEnabled,
36119
36513
  workspaceAgentInstructions,
36514
+ workspaceAgentIdentity,
36120
36515
  workspaceGovernance,
36121
36516
  structuredWorkspacePolicyActive,
36122
36517
  workspaceMemory,
@@ -36197,7 +36592,7 @@ async function buildTurnAgent(deps) {
36197
36592
  }
36198
36593
  });
36199
36594
  const imageGenerationOption = (() => {
36200
- if (!objectStorage) return {};
36595
+ if (!objectStorage || !resolveAgentToolFamilies2(session.agent).media) return {};
36201
36596
  if (nativeImageProviderBinding) {
36202
36597
  media.nativeImageGenerationRetention = {
36203
36598
  ...nativeImageProviderBinding,
@@ -36313,7 +36708,7 @@ async function buildTurnAgent(deps) {
36313
36708
  const videoGenerationPolicy = await getWorkspaceVideoGenerationPolicy2(db, input.workspaceId);
36314
36709
  const videoGenerationEnabled = videoGenerationPolicy.defaultModelId !== null && videoGenerationPolicy.enabledModelIds.length > 0;
36315
36710
  let videoGenerationCredential = null;
36316
- if (objectStorage && videoGenerationEnabled) {
36711
+ if (objectStorage && videoGenerationEnabled && resolveAgentToolFamilies2(session.agent).media) {
36317
36712
  if (videoGenerationPolicy.fundingSource === "opengeni_credits") {
36318
36713
  videoGenerationCredential = managedVideoGenerationCredentialLease(eventing.modelRunSettings);
36319
36714
  } else if (videoGenerationPolicy.fundingSource === "workspace_gateway") {
@@ -36505,6 +36900,11 @@ async function buildTurnAgent(deps) {
36505
36900
  expectedAttemptId: input.attemptId,
36506
36901
  effort: turn.reasoningEffort
36507
36902
  }) : turn.reasoningEffort;
36903
+ const toolRouterInHistory = session.agent ? await sessionHasToolRouterHistory(db, {
36904
+ accountId: input.accountId,
36905
+ workspaceId: input.workspaceId,
36906
+ sessionId: input.sessionId
36907
+ }) : false;
36508
36908
  const agent = (() => {
36509
36909
  const agentConstructionStartedAt = performance.now();
36510
36910
  let agentConstructionOutcome = "completed";
@@ -36523,6 +36923,7 @@ async function buildTurnAgent(deps) {
36523
36923
  }
36524
36924
  } : {},
36525
36925
  ...preparedTools.inputWaitYield ? { inputWaitYield: preparedTools.inputWaitYield } : {},
36926
+ ...session.agent ? { agentConfig: session.agent, toolRouterInHistory } : {},
36526
36927
  reasoningEffort: requestReasoningEffort,
36527
36928
  latencyMode: turnExecutionPolicy.latencyMode,
36528
36929
  ...serviceTier ? { serviceTier } : {},
@@ -36611,6 +37012,14 @@ async function buildTurnAgent(deps) {
36611
37012
  onRetainableSessionImageOutput: media.retainSessionImageAtToolBoundary,
36612
37013
  skillCatalog: deps.skillCatalog,
36613
37014
  skillCatalogInHistory: true,
37015
+ // A session with an agent configuration composes the modular prompt
37016
+ // (identity, base behavior, runtime mechanics, capability modules);
37017
+ // its workspace identity survives instruction policies. Null keeps
37018
+ // the legacy composition below byte-for-byte.
37019
+ ...session.agent ? {
37020
+ agentConfig: session.agent,
37021
+ ...workspaceAgentIdentity ? { workspaceAgentIdentity } : {}
37022
+ } : {},
36614
37023
  ...!structuredWorkspacePolicyActive && workspaceAgentInstructions ? { instructionsTemplate: workspaceAgentInstructions } : {},
36615
37024
  ...workspaceGovernance ? { workspaceGovernance } : {},
36616
37025
  ...workspaceMemory ? { workspaceMemory } : {},
@@ -36878,11 +37287,14 @@ function createRunAgentTurnActivity(services) {
36878
37287
  getModelRunSettings: () => eventing.modelRunSettings,
36879
37288
  getExecutionGeneration: () => attempt.executionGeneration
36880
37289
  });
36881
- const checkpointBeforeProviderDispatch = () => checkpointHistoryBeforeProviderDispatch(historySink, {
36882
- effectiveSandboxBackend: eventing.modelRunSettings.sandboxBackend,
36883
- routingEnabled: routingEnabled(settings),
36884
- readActiveSandbox: () => readActiveSandbox3(db, input.workspaceId, input.sessionId)
36885
- });
37290
+ const checkpointBeforeProviderDispatch = async () => {
37291
+ await awaitModelCallAdmission();
37292
+ await checkpointHistoryBeforeProviderDispatch(historySink, {
37293
+ effectiveSandboxBackend: eventing.modelRunSettings.sandboxBackend,
37294
+ routingEnabled: routingEnabled(settings),
37295
+ readActiveSandbox: () => readActiveSandbox3(db, input.workspaceId, input.sessionId)
37296
+ });
37297
+ };
36886
37298
  try {
36887
37299
  const claimed = await claimTurnAttempt({
36888
37300
  input,
@@ -37025,7 +37437,7 @@ function createRunAgentTurnActivity(services) {
37025
37437
  requiredGeneratedVideoFiles
37026
37438
  });
37027
37439
  if ("exit" in governance) return governance.exit;
37028
- await assertModelConnectionAllowsTurn(db, {
37440
+ await assertModelConnectionAllowsTurn2(db, {
37029
37441
  workspaceId: input.workspaceId,
37030
37442
  subjectId: turn.initiatingHumanSubjectId ?? "worker:model-access",
37031
37443
  modelId: turnExecutionPolicy.productModelId,
@@ -37039,6 +37451,7 @@ function createRunAgentTurnActivity(services) {
37039
37451
  agentHumanInputEnabled,
37040
37452
  codeSearchEnabled,
37041
37453
  workspaceAgentInstructions,
37454
+ workspaceAgentIdentity,
37042
37455
  workspaceGovernance,
37043
37456
  structuredWorkspacePolicyActive,
37044
37457
  workspaceMemory,
@@ -37221,8 +37634,12 @@ function createRunAgentTurnActivity(services) {
37221
37634
  credentialId: providerTurn.effectiveXaiCredentialId,
37222
37635
  authoritySnapshot: turn.xaiProviderAccountAuthoritySnapshot,
37223
37636
  hostedSearch: {
37224
- webSearch: runSettings.webSearchEnabled,
37225
- xSearch: runSettings.webSearchEnabled
37637
+ webSearch: resolveAgentToolFamilies3(session.agent, {
37638
+ webSearch: runSettings.webSearchEnabled
37639
+ }).webSearch,
37640
+ xSearch: resolveAgentToolFamilies3(session.agent, {
37641
+ webSearch: runSettings.webSearchEnabled
37642
+ }).webSearch
37226
37643
  },
37227
37644
  streamIdleTimeoutMs: runSettings.supergrokResponseStreamIdleTimeoutMs,
37228
37645
  nextRequestId: () => `${dispatchId}:xai:${++xaiModelRequestSequence}`,
@@ -37332,13 +37749,36 @@ function createRunAgentTurnActivity(services) {
37332
37749
  const claudeUsageObserver = await createClaudeUsageObserver(
37333
37750
  parseModelProvidersJson(runSettings.modelProvidersJson),
37334
37751
  providerTurn.latestClaudeUsage,
37335
- (scope) => loadClaudeSubscriptionUsageCredential(db, settings, {
37752
+ (scope) => loadClaudeSubscriptionUsageCredential2(db, settings, {
37336
37753
  accountId: input.accountId,
37337
37754
  workspaceId: input.workspaceId,
37338
37755
  scope
37339
37756
  })
37340
37757
  );
37341
- const withClaudeUsage = (fn) => withClaudeUsageObserver(claudeUsageObserver, fn);
37758
+ const withClaudeUsage = (fn) => withClaudeUsageObserver(claudeUsageObserver, fn, async (providerId, headers) => {
37759
+ const binding = claudeUsageObserver.binding(providerId);
37760
+ if (!binding) return headers;
37761
+ const credential = await resolveClaudeSubscriptionCredential(
37762
+ db,
37763
+ settings,
37764
+ {
37765
+ accountId: input.accountId,
37766
+ workspaceId: input.workspaceId,
37767
+ scope: binding.scope
37768
+ },
37769
+ {
37770
+ expectedConnectionId: binding.expectedConnectionId,
37771
+ expectedCredentialVersion: binding.expectedCredentialVersion
37772
+ }
37773
+ );
37774
+ if (!credential) return headers;
37775
+ if ("reconnectRequired" in credential)
37776
+ throw new ClaudeSubscriptionReconnectRequired();
37777
+ claudeUsageObserver.renew(providerId, credential);
37778
+ headers.set("authorization", `Bearer ${credential.token}`);
37779
+ headers.delete("x-api-key");
37780
+ return headers;
37781
+ });
37342
37782
  const withCodex = (fn) => codexContext ? codexRequestStorage.run(codexContext, fn) : fn();
37343
37783
  const withProviderRequestContext = (fn) => withClaudeUsage(
37344
37784
  () => providerTurn.xaiRequestContext ? xaiSubscriptionRequestStorage.run(providerTurn.xaiRequestContext, fn) : withCodex(fn)
@@ -37396,6 +37836,7 @@ function createRunAgentTurnActivity(services) {
37396
37836
  turnExecutionPolicy,
37397
37837
  resolvedModel,
37398
37838
  workspaceAgentInstructions,
37839
+ workspaceAgentIdentity,
37399
37840
  workspaceGovernance,
37400
37841
  structuredWorkspacePolicyActive,
37401
37842
  workspaceMemory,
@@ -37542,6 +37983,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
37542
37983
  void 0
37543
37984
  );
37544
37985
  const runCredentials = await prepareRunCredentials({
37986
+ turnTools,
37545
37987
  localMcpServerIds: installedApiIntegrations.map((integration) => integration.serverId),
37546
37988
  input,
37547
37989
  settings,
@@ -37557,6 +37999,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
37557
37999
  sandboxRuntime,
37558
38000
  turn,
37559
38001
  session,
38002
+ turnExecutionPolicy,
37560
38003
  fileAuthoritySubjectId,
37561
38004
  runSettings,
37562
38005
  workspaceVariableSet,
@@ -37774,6 +38217,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
37774
38217
  supportsImageInput,
37775
38218
  agentHumanInputEnabled,
37776
38219
  workspaceAgentInstructions,
38220
+ workspaceAgentIdentity,
37777
38221
  workspaceGovernance,
37778
38222
  structuredWorkspacePolicyActive,
37779
38223
  workspaceMemory,
@@ -37898,6 +38342,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
37898
38342
  turnExecutionPolicy,
37899
38343
  resolvedModel,
37900
38344
  workspaceAgentInstructions,
38345
+ workspaceAgentIdentity,
37901
38346
  workspaceGovernance,
37902
38347
  structuredWorkspacePolicyActive,
37903
38348
  workspaceMemory,
@@ -39307,4 +39752,4 @@ export {
39307
39752
  createTurnActivities,
39308
39753
  createTurnActivitiesFromServices
39309
39754
  };
39310
- //# sourceMappingURL=activities-turn-FQ5OO2WW.js.map
39755
+ //# sourceMappingURL=activities-turn-TESOIOEX.js.map