@opengeni/worker-bundle 2.0.3 → 2.1.0-canary.36239117573001

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 (51) hide show
  1. package/dist/activities/agent-turn/agent-build.d.ts +2 -0
  2. package/dist/activities/agent-turn/code-search.d.ts +60 -0
  3. package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
  4. package/dist/activities/agent-turn/errors.d.ts +12 -1
  5. package/dist/activities/agent-turn/governance-model.d.ts +2 -0
  6. package/dist/activities/agent-turn/session-title.d.ts +32 -2
  7. package/dist/activities/agent-turn/tool-environment.d.ts +4 -0
  8. package/dist/activities/context-compaction.d.ts +10 -2
  9. package/dist/activities/knowledge-indexing.d.ts +19 -0
  10. package/dist/{activities-control-IVTL723D.js → activities-control-I72CRMAE.js} +81 -14
  11. package/dist/activities-control-I72CRMAE.js.map +1 -0
  12. package/dist/{activities-turn-EZEDZTEZ.js → activities-turn-CSDKK4N3.js} +425 -46
  13. package/dist/activities-turn-CSDKK4N3.js.map +1 -0
  14. package/dist/artifact-outbox-entry.js +3 -0
  15. package/dist/artifact-outbox-entry.js.map +1 -1
  16. package/dist/{chunk-JMO5ZUW3.js → chunk-7M6G2SCF.js} +159 -11
  17. package/dist/chunk-7M6G2SCF.js.map +1 -0
  18. package/dist/{chunk-I7HKKMUJ.js → chunk-DSPP6CZL.js} +48 -3
  19. package/dist/chunk-DSPP6CZL.js.map +1 -0
  20. package/dist/index.js +4 -4
  21. package/dist/index.js.map +1 -1
  22. package/dist/observability-metrics.d.ts +11 -1
  23. package/dist/sandbox-resume.d.ts +46 -0
  24. package/dist/workflow-bundle.js +77 -2
  25. package/dist/workflows/session.d.ts +30 -0
  26. package/package.json +20 -19
  27. package/src/activities/agent-turn/agent-build.ts +4 -0
  28. package/src/activities/agent-turn/code-search.ts +275 -0
  29. package/src/activities/agent-turn/codex-capacity.ts +37 -2
  30. package/src/activities/agent-turn/compaction-prep.ts +52 -16
  31. package/src/activities/agent-turn/errors.ts +59 -1
  32. package/src/activities/agent-turn/governance-model.ts +17 -1
  33. package/src/activities/agent-turn/run.ts +4 -0
  34. package/src/activities/agent-turn/sandbox-establish.ts +12 -1
  35. package/src/activities/agent-turn/session-title.ts +73 -3
  36. package/src/activities/agent-turn/stream-attempt.ts +14 -13
  37. package/src/activities/agent-turn/tool-environment.ts +65 -0
  38. package/src/activities/context-compaction.ts +49 -14
  39. package/src/activities/knowledge-indexing.ts +107 -9
  40. package/src/activities/scheduled-tasks.ts +18 -2
  41. package/src/activity-services.ts +16 -4
  42. package/src/editable-artifact-hint-broker.ts +3 -0
  43. package/src/index.ts +2 -2
  44. package/src/observability-metrics.ts +70 -1
  45. package/src/personal-github-git-credentials.ts +2 -0
  46. package/src/sandbox-resume.ts +205 -5
  47. package/src/workflows/session.ts +102 -6
  48. package/dist/activities-control-IVTL723D.js.map +0 -1
  49. package/dist/activities-turn-EZEDZTEZ.js.map +0 -1
  50. package/dist/chunk-I7HKKMUJ.js.map +0 -1
  51. package/dist/chunk-JMO5ZUW3.js.map +0 -1
@@ -24,6 +24,7 @@ import {
24
24
  compactionFailureReasonFromError,
25
25
  compactionFailureTurnEventPayload,
26
26
  computeIdleDelayMs,
27
+ createFreshSandboxReadinessReplacementBudget,
27
28
  createKnowledgeSourceSyncActivities,
28
29
  createModelHistoryAttachmentProjector,
29
30
  createRuntimeBatcher,
@@ -86,13 +87,14 @@ import {
86
87
  withFirstPartyTools,
87
88
  wrapLazyTurnBoxWithRouting,
88
89
  wrapTurnBoxWithRouting
89
- } from "./chunk-JMO5ZUW3.js";
90
+ } from "./chunk-7M6G2SCF.js";
90
91
  import {
91
92
  StreamTimingMetrics,
92
93
  makeMachineOpObserver,
93
94
  modelCallAccountContext,
94
95
  modelRequestLifecycleMetricsFor,
95
96
  recordBatchFlush,
97
+ recordCodeSearchCall,
96
98
  recordCompanyBrainContributions,
97
99
  recordContextCompaction,
98
100
  recordContextCompactionStarted,
@@ -113,7 +115,7 @@ import {
113
115
  recordTurnWorkerPreparationTotal,
114
116
  runtimeMetricsHooksForObservability,
115
117
  turnLifecycleMetricsFor
116
- } from "./chunk-I7HKKMUJ.js";
118
+ } from "./chunk-DSPP6CZL.js";
117
119
  import {
118
120
  __export
119
121
  } from "./chunk-PZ5AY32C.js";
@@ -7069,7 +7071,8 @@ import {
7069
7071
  import {
7070
7072
  EmptyCompactionSummaryError,
7071
7073
  REMOTE_COMPACTION_V2_IMPLEMENTATION,
7072
- SUMMARY_BUFFER_TOKENS,
7074
+ compactionSummaryOutputTokens,
7075
+ buildSummaryItem,
7073
7076
  buildCompactionReplacementHistory,
7074
7077
  buildRemoteV2ReplacementHistory,
7075
7078
  compactionThresholdTokens,
@@ -7084,7 +7087,7 @@ import {
7084
7087
  } from "@opengeni/runtime";
7085
7088
  import { contextInputBudgetTokens } from "@opengeni/config";
7086
7089
  async function maybeCompactContext(db, settings, scope, lastInputTokens, summarize = (s, m) => summarizeForCompaction(s, m, {
7087
- maxOutputTokens: SUMMARY_BUFFER_TOKENS
7090
+ maxOutputTokens: compactionSummaryOutputTokens(s.contextWindowTokens)
7088
7091
  }), options = {}) {
7089
7092
  if (options.codexCompactionMode === "remote_v2" && options.isCodexSubscriptionTurn !== true) {
7090
7093
  throw new Error(
@@ -7315,12 +7318,23 @@ async function compactContextPortable(db, settings, scope, canonicalItems, items
7315
7318
  const summarized = await summarizeWithCodexOverflowTrimming(summarize, settings, items);
7316
7319
  const summaryBody = summarized.summaryBody;
7317
7320
  const retainedTokens = await retentionTokenCounts(canonicalItems, projectForWire);
7321
+ const outputReserve = compactionSummaryOutputTokens(settings.contextWindowTokens);
7322
+ const structuralBudget = Math.min(
7323
+ contextInputBudgetTokens(settings) || settings.contextWindowTokens - outputReserve,
7324
+ settings.contextWindowTokens - outputReserve
7325
+ );
7326
+ const prefixTokens = Math.max(0, Math.ceil(summarize.estimatePrefixTokens?.() ?? 0));
7327
+ const summaryTokens = estimateTokens([buildSummaryItem(summaryBody)]);
7318
7328
  const replacementHistory = buildCompactionReplacementHistory(
7319
7329
  canonicalItems,
7320
7330
  summaryBody,
7321
- (item) => retainedTokens.get(item) ?? estimateTokens([item])
7331
+ (item) => retainedTokens.get(item) ?? estimateTokens([item]),
7332
+ Math.min(outputReserve, Math.max(0, structuralBudget - prefixTokens - summaryTokens))
7322
7333
  );
7323
7334
  const estimatedTokensAfter = estimateTokens(await projectForWire(replacementHistory));
7335
+ if (estimatedTokensAfter + prefixTokens > structuralBudget) {
7336
+ return await settleSkippedAfterStart(db, scope, options, "replacement_exceeds_model_budget");
7337
+ }
7324
7338
  const replacementFingerprint = compactionReplacementFingerprint(replacementHistory);
7325
7339
  const previousReplacementFingerprint = latestCompactionReplacementFingerprint(canonicalItems);
7326
7340
  const summaryIndex = replacementHistory.length - (readReasoningConfiguration(replacementHistory.at(-1) ?? {}) ? 2 : 1);
@@ -7373,14 +7387,27 @@ async function compactContextPortable(db, settings, scope, canonicalItems, items
7373
7387
  };
7374
7388
  }
7375
7389
  async function summarizeWithCodexOverflowTrimming(summarize, settings, activeHistory) {
7376
- const summaryAwareBudget = Math.max(0, settings.contextWindowTokens - SUMMARY_BUFFER_TOKENS);
7390
+ const summaryAwareBudget = Math.max(
7391
+ 0,
7392
+ settings.contextWindowTokens - compactionSummaryOutputTokens(settings.contextWindowTokens)
7393
+ );
7377
7394
  const configuredInputBudget = contextInputBudgetTokens(settings);
7378
7395
  const structuralBudget = Math.min(
7379
7396
  configuredInputBudget > 0 ? configuredInputBudget : summaryAwareBudget,
7380
7397
  summaryAwareBudget
7381
7398
  );
7382
- const initialBudget = Math.floor(structuralBudget * 0.85);
7399
+ const prefixTokens = Math.max(0, Math.ceil(summarize.estimatePrefixTokens?.() ?? 0));
7400
+ const initialBudget = Math.max(0, structuralBudget - prefixTokens);
7383
7401
  let preparation = prepareCompactionPromptInput(activeHistory, initialBudget);
7402
+ const requireHistory = () => {
7403
+ if (activeHistory.length > 0 && preparation.input.length === 1) {
7404
+ throw new EmptyCompactionSummaryError({
7405
+ stage: "portable_input_budget",
7406
+ reason: "no_history_fit"
7407
+ });
7408
+ }
7409
+ };
7410
+ requireHistory();
7384
7411
  try {
7385
7412
  return {
7386
7413
  summaryBody: await summarize(settings, preparation.input),
@@ -7390,9 +7417,10 @@ async function summarizeWithCodexOverflowTrimming(summarize, settings, activeHis
7390
7417
  } catch (error51) {
7391
7418
  if (!isContextWindowExceeded(error51)) throw error51;
7392
7419
  const retryBudget = Math.floor(
7393
- Math.min(initialBudget * 0.5, preparation.estimatedInputTokens * 0.5)
7420
+ Math.min(initialBudget * 0.4, preparation.estimatedInputTokens * 0.4)
7394
7421
  );
7395
7422
  preparation = prepareCompactionPromptInput(activeHistory, retryBudget);
7423
+ requireHistory();
7396
7424
  return {
7397
7425
  summaryBody: await summarize(settings, preparation.input),
7398
7426
  preparation,
@@ -7760,9 +7788,11 @@ import {
7760
7788
 
7761
7789
  // src/activities/agent-turn/session-title.ts
7762
7790
  import { hasPermission } from "@opengeni/core";
7791
+ import { isManagedOpenRouterFreeRoute } from "@opengeni/config";
7763
7792
  import {
7764
7793
  AUTOMATIC_SESSION_TITLE_FALLBACK,
7765
- DEFAULT_FIRST_PARTY_MCP_PERMISSIONS
7794
+ DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
7795
+ ReasoningEffort
7766
7796
  } from "@opengeni/contracts";
7767
7797
  var SESSION_TITLE_MODEL_TOOL_NAME = "opengeni__set_session_title";
7768
7798
  var SESSION_TITLE_DESCRIPTION = "Set this session's display title to a concise 3-7 word topic label. Use a stable noun phrase about the actual task or subject, never a quote/prefix of a prompt, greeting, request boilerplate, URL, identifier, credential, token, or other sensitive value. Call once on a new session, then only when the topic materially changes. Never call it as routine setup after a continuation, resume, or interruption, or merely to reassert the same title. A human-set title cannot be replaced.";
@@ -7774,10 +7804,14 @@ function shouldRequestMissingSessionTitle(input) {
7774
7804
  const permissions = input.firstPartyMcpPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS;
7775
7805
  return hasPermission([...permissions], "sessions:control");
7776
7806
  }
7807
+ function routeAllowsSessionTitleRequests(resolvedModel) {
7808
+ return !resolvedModel || !isManagedOpenRouterFreeRoute(resolvedModel);
7809
+ }
7777
7810
  function sessionTitleToolPlan(input) {
7778
7811
  const titleToolAvailable = input.shouldRequestTitle && input.tools.some((tool) => tool.kind === "mcp" && tool.id === "opengeni");
7779
- const generateTitleInParallel = titleToolAvailable && input.parallelGenerationAvailable;
7780
- const promoteTitleTool = titleToolAvailable && !generateTitleInParallel;
7812
+ const titleRequestAllowed = titleToolAvailable && input.routeAllowsTitleRequests;
7813
+ const generateTitleInParallel = titleRequestAllowed && input.parallelGenerationAvailable;
7814
+ const promoteTitleTool = titleRequestAllowed && !generateTitleInParallel;
7781
7815
  return {
7782
7816
  promoteTitleTool,
7783
7817
  generateTitleInParallel,
@@ -7786,6 +7820,31 @@ function sessionTitleToolPlan(input) {
7786
7820
  };
7787
7821
  }
7788
7822
  var PARALLEL_SESSION_TITLE_TIMEOUT_MS = 15e3;
7823
+ function sessionTitleReasoningEffort(capabilities) {
7824
+ const reasoning = capabilities?.reasoning;
7825
+ if (!reasoning?.runnable) return void 0;
7826
+ const order = ReasoningEffort.options;
7827
+ let lowest;
7828
+ for (const effort of reasoning.efforts) {
7829
+ if (!lowest || order.indexOf(effort) < order.indexOf(lowest)) lowest = effort;
7830
+ }
7831
+ return lowest;
7832
+ }
7833
+ function sessionTitleGenerationOptions(input) {
7834
+ const { resolvedModel, serviceTier } = input;
7835
+ const reasoningEffort = sessionTitleReasoningEffort(resolvedModel?.configured.capabilities);
7836
+ return {
7837
+ ...resolvedModel ? {
7838
+ client: resolvedModel.client,
7839
+ provider: resolvedModel.provider,
7840
+ model: resolvedModel.model
7841
+ } : {},
7842
+ modelName: input.modelName,
7843
+ ...serviceTier ? { serviceTier } : {},
7844
+ ...reasoningEffort ? { reasoningEffort } : {},
7845
+ signal: input.signal
7846
+ };
7847
+ }
7789
7848
  function startParallelSessionTitleGeneration(input) {
7790
7849
  const cancellationController = new AbortController();
7791
7850
  const timeoutSignal = AbortSignal.timeout(input.timeoutMs ?? PARALLEL_SESSION_TITLE_TIMEOUT_MS);
@@ -9285,16 +9344,16 @@ async function runTurnStreamAttempt(deps) {
9285
9344
  parallelSessionTitle = startParallelSessionTitleGeneration({
9286
9345
  signal: runtimeCancellationSignal,
9287
9346
  generate: async (signal) => await withSessionTitleProviderRequestContext(
9288
- () => runtime.generateSessionTitle(runSettings, sessionTitlePrompt, {
9289
- ...resolvedModel ? {
9290
- client: resolvedModel.client,
9291
- provider: resolvedModel.provider,
9292
- model: resolvedModel.model
9293
- } : {},
9294
- modelName: turnExecutionPolicy.upstreamModelId,
9295
- ...serviceTier ? { serviceTier } : {},
9296
- signal
9297
- })
9347
+ () => runtime.generateSessionTitle(
9348
+ runSettings,
9349
+ sessionTitlePrompt,
9350
+ sessionTitleGenerationOptions({
9351
+ resolvedModel,
9352
+ modelName: turnExecutionPolicy.upstreamModelId,
9353
+ serviceTier,
9354
+ signal
9355
+ })
9356
+ )
9298
9357
  ),
9299
9358
  onError: (error51) => {
9300
9359
  observability.warn("parallel session title generation failed", {
@@ -10307,6 +10366,24 @@ function safeErrorName(error51) {
10307
10366
 
10308
10367
  // src/activities/agent-turn/codex-capacity.ts
10309
10368
  import { randomUUID as randomUUID2 } from "crypto";
10369
+ import { createLogThrottle } from "@opengeni/observability";
10370
+ var CODEX_POOL_LOW_WARNING_INTERVAL_MS = 10 * 6e4;
10371
+ var codexPoolLowWarningThrottle = createLogThrottle({
10372
+ intervalMs: CODEX_POOL_LOW_WARNING_INTERVAL_MS,
10373
+ maxKeys: 1024
10374
+ });
10375
+ function warnCodexPoolLow(observability, input, throttle = codexPoolLowWarningThrottle) {
10376
+ const admission = throttle.admit(`${input.workspaceKey}:${input.depth}`);
10377
+ if (!admission) return;
10378
+ observability.warn("Codex eligible credential pool is low", {
10379
+ workspaceId: input.workspaceId,
10380
+ eligibleCount: input.eligibleCount,
10381
+ connectedCount: input.connectedCount,
10382
+ depth: input.depth,
10383
+ reason: input.depth === "zero" ? "eligible_pool_zero" : "eligible_pool_one",
10384
+ ...admission.suppressedCount > 0 ? { suppressedCount: admission.suppressedCount } : {}
10385
+ });
10386
+ }
10310
10387
  async function selectCodexTurnCapacity(deps) {
10311
10388
  const {
10312
10389
  input,
@@ -10572,11 +10649,12 @@ async function selectCodexTurnCapacity(deps) {
10572
10649
  help: "Alert signal emitted when the eligible Codex pool is zero or one.",
10573
10650
  labels: { workspace_key: codexWorkspaceKey, depth: poolDepth }
10574
10651
  });
10575
- observability.warn("Codex eligible credential pool is low", {
10652
+ warnCodexPoolLow(observability, {
10653
+ workspaceKey: codexWorkspaceKey,
10576
10654
  workspaceId: input.workspaceId,
10577
10655
  eligibleCount,
10578
10656
  connectedCount: leased.accounts.length,
10579
- depth: poolDepth
10657
+ depth: poolDepth === "zero" ? "zero" : "one"
10580
10658
  });
10581
10659
  }
10582
10660
  if (providerTurn.effectiveCodexCredentialId === null && leased.accounts.length > 0 && (rotationDecision.kind === "allocatorDisabled" || leased.accounts.every((account) => !account.allocatorEnabled)) && turnId) {
@@ -10947,7 +11025,10 @@ import {
10947
11025
  hasActiveWorkspaceInstructionPolicy,
10948
11026
  renderWorkspaceGovernanceContext
10949
11027
  } from "@opengeni/runtime";
10950
- import { settingsWithResolvedModelContext } from "@opengeni/config";
11028
+ import {
11029
+ codeSearchDeploymentPolicy,
11030
+ settingsWithResolvedModelContext
11031
+ } from "@opengeni/config";
10951
11032
  import { projectReasoningConfigurations, supportsReasoningConfiguration } from "@opengeni/codex";
10952
11033
  import { resolveRigProviderImageForRun } from "@opengeni/core";
10953
11034
  import { retryWhileMissing as retryWhileMissing3 } from "@opengeni/storage";
@@ -10956,6 +11037,7 @@ import {
10956
11037
  evaluateWorkspaceModelPolicy,
10957
11038
  resolveWorkspaceAgentHumanInputEnabled as resolveWorkspaceAgentHumanInputEnabled2
10958
11039
  } from "@opengeni/contracts";
11040
+ import { codeSearchEnabledForTurn } from "@opengeni/contracts/code-search";
10959
11041
 
10960
11042
  // src/activities/agent-turn/tool-policy.ts
10961
11043
  import {
@@ -11328,6 +11410,11 @@ async function prepareGovernanceAndModel(deps) {
11328
11410
  workspaceRefs.rigVersionId = session.rigVersionId ?? "";
11329
11411
  if (!workspace) throw new Error(`Workspace not found: ${input.workspaceId}`);
11330
11412
  const agentHumanInputEnabled = resolveWorkspaceAgentHumanInputEnabled2(workspace.settings);
11413
+ const codeSearchEnabled = codeSearchEnabledForTurn(
11414
+ session.codeSearchEnabled,
11415
+ workspace.settings,
11416
+ codeSearchDeploymentPolicy(capabilitySettings)
11417
+ );
11331
11418
  const contextSelection = await resolveCompanyBrainContextSelection(db, governanceClaims);
11332
11419
  const workspaceAgentInstructions = contextSelection.legacyWorkspaceInstructions;
11333
11420
  const memoryPromptMode = contextSelection.receipt.memoryPromptMode;
@@ -11483,6 +11570,7 @@ async function prepareGovernanceAndModel(deps) {
11483
11570
  rigVersion,
11484
11571
  rigName,
11485
11572
  agentHumanInputEnabled,
11573
+ codeSearchEnabled,
11486
11574
  workspaceAgentInstructions,
11487
11575
  workspaceGovernance,
11488
11576
  structuredWorkspacePolicyActive,
@@ -11518,7 +11606,8 @@ import {
11518
11606
  compactionThresholdTokens as compactionThresholdTokens2,
11519
11607
  CompactionNeededError,
11520
11608
  compactionProviderRejection as compactionProviderRejection2,
11521
- SUMMARY_BUFFER_TOKENS as SUMMARY_BUFFER_TOKENS2
11609
+ estimateSerializedValueTokens,
11610
+ compactionSummaryOutputTokens as compactionSummaryOutputTokens2
11522
11611
  } from "@opengeni/runtime";
11523
11612
  async function prepareCompaction(deps) {
11524
11613
  const {
@@ -11557,6 +11646,11 @@ async function prepareCompaction(deps) {
11557
11646
  const remotePrefix = {
11558
11647
  agent: null
11559
11648
  };
11649
+ const portableResponsesNeedsAgentPrefix = resolvedModel?.provider.api === "responses" && !(billingState.isCodexTurn && session.codexCompactionMode === "remote_v2");
11650
+ const preparedPortableRequest = () => {
11651
+ if (!remotePrefix.agent) throw new Error("Compaction agent is unavailable");
11652
+ return preparedCompactionRequest(remotePrefix.agent);
11653
+ };
11560
11654
  const promptCacheKey = acceptsPromptCacheKeyForTurn(resolvedModel) ? input.sessionId : void 0;
11561
11655
  const compactionUsageState = createCompactionModelUsageEventState(claimedModelUsageSourceKeys);
11562
11656
  const recordCompactionUsage = async (usage) => {
@@ -11588,24 +11682,37 @@ async function prepareCompaction(deps) {
11588
11682
  contextContributions: eventing.companyBrainContextContributions
11589
11683
  });
11590
11684
  };
11591
- const compactionSummarizerFor = (systemInstructions) => resolvedModel ? (s, m) => withProviderRequestContext(
11592
- () => summarizeContextForCompaction(s, m, {
11593
- client: resolvedModel.client,
11594
- provider: resolvedModel.provider,
11595
- api: resolvedModel.provider.api,
11685
+ const compactionSummarizerFor = (systemInstructions) => {
11686
+ const summarize = resolvedModel ? (s, m) => withProviderRequestContext(
11687
+ () => summarizeContextForCompaction(s, m, {
11688
+ client: resolvedModel.client,
11689
+ provider: resolvedModel.provider,
11690
+ api: resolvedModel.provider.api,
11691
+ model: turnExecutionPolicy.upstreamModelId,
11692
+ maxOutputTokens: compactionSummaryOutputTokens2(s.contextWindowTokens),
11693
+ ...cancellationSignal ? { signal: cancellationSignal } : {},
11694
+ onUsage: recordCompactionUsage,
11695
+ ...systemInstructions ? { systemInstructions } : {},
11696
+ ...promptCacheKey ? { promptCacheKey } : {},
11697
+ ...portableResponsesNeedsAgentPrefix ? { preparedRequest: preparedPortableRequest() } : {}
11698
+ })
11699
+ ) : (s, m) => summarizeContextForCompaction(s, m, {
11596
11700
  model: turnExecutionPolicy.upstreamModelId,
11597
- maxOutputTokens: SUMMARY_BUFFER_TOKENS2,
11701
+ maxOutputTokens: compactionSummaryOutputTokens2(s.contextWindowTokens),
11702
+ ...cancellationSignal ? { signal: cancellationSignal } : {},
11598
11703
  onUsage: recordCompactionUsage,
11599
11704
  ...systemInstructions ? { systemInstructions } : {},
11600
11705
  ...promptCacheKey ? { promptCacheKey } : {}
11601
- })
11602
- ) : (s, m) => summarizeContextForCompaction(s, m, {
11603
- model: turnExecutionPolicy.upstreamModelId,
11604
- maxOutputTokens: SUMMARY_BUFFER_TOKENS2,
11605
- onUsage: recordCompactionUsage,
11606
- ...systemInstructions ? { systemInstructions } : {},
11607
- ...promptCacheKey ? { promptCacheKey } : {}
11608
- });
11706
+ });
11707
+ summarize.estimatePrefixTokens = () => {
11708
+ if (resolvedModel?.provider.api === "chat") {
11709
+ return estimateSerializedValueTokens(systemInstructions ?? "");
11710
+ }
11711
+ const prepared = portableResponsesNeedsAgentPrefix ? preparedPortableRequest() : null;
11712
+ return estimateSerializedValueTokens(prepared?.systemInstructions ?? systemInstructions ?? "") + (prepared ? estimateSerializedValueTokens(prepared.tools) : 0);
11713
+ };
11714
+ return summarize;
11715
+ };
11609
11716
  const remoteCompactionRequester = resolvedModel && billingState.isCodexTurn ? (s, m) => withCodexRemoteCompaction(async () => {
11610
11717
  if (!remotePrefix.agent) throw new Error("Compaction agent is unavailable");
11611
11718
  const preparedRequest = preparedCompactionRequest(remotePrefix.agent);
@@ -11668,7 +11775,7 @@ async function prepareCompaction(deps) {
11668
11775
  control.activityStatus = "idle";
11669
11776
  return claimedResult({ status: "idle" });
11670
11777
  };
11671
- if (compactionOnlyTurn && !remoteV2CompactionNeedsAgentPrefix) {
11778
+ if (compactionOnlyTurn && !remoteV2CompactionNeedsAgentPrefix && !portableResponsesNeedsAgentPrefix) {
11672
11779
  const compactionInstructions = appendWorkspaceMemory(
11673
11780
  appendSessionInstructions(
11674
11781
  appendWorkspaceGovernance(
@@ -11810,6 +11917,7 @@ async function runPostAgentCompaction(deps) {
11810
11917
  claimedResult,
11811
11918
  turn,
11812
11919
  session,
11920
+ resolvedModel,
11813
11921
  remotePrefix,
11814
11922
  remoteCompactionRequester,
11815
11923
  publishCompactionLiveEvents,
@@ -11823,16 +11931,17 @@ async function runPostAgentCompaction(deps) {
11823
11931
  agent
11824
11932
  } = deps;
11825
11933
  const agentInstructions = typeof agent.instructions === "string" ? agent.instructions : "";
11934
+ const preparedPortable = resolvedModel?.provider.api === "responses" && !(remoteCompactionRequester && session.codexCompactionMode === "remote_v2");
11826
11935
  const compactSummarizer = compactionSummarizerFor(
11827
11936
  agentInstructions.trim() ? agentInstructions : void 0
11828
11937
  );
11829
- if (remoteCompactionRequester) {
11938
+ if (remoteCompactionRequester || preparedPortable) {
11830
11939
  remotePrefix.agent = agent;
11831
11940
  }
11832
11941
  if (compactionOnlyTurn) {
11833
11942
  const requested = await isSessionCompactionRequested2(db, input.workspaceId, input.sessionId);
11834
11943
  let outcome = null;
11835
- if (requested && remoteCompactionRequester && session.codexCompactionMode === "remote_v2") {
11944
+ if (requested && (preparedPortable || remoteCompactionRequester && session.codexCompactionMode === "remote_v2")) {
11836
11945
  queuePreparedCompaction(
11837
11946
  agent,
11838
11947
  new CompactionNeededError({
@@ -11942,7 +12051,7 @@ async function runPostAgentCompaction(deps) {
11942
12051
  control.activityStatus = "idle";
11943
12052
  return { exit: claimedResult({ status: "idle" }) };
11944
12053
  }
11945
- if (remoteCompactionRequester && session.codexCompactionMode === "remote_v2") {
12054
+ if (preparedPortable || remoteCompactionRequester && session.codexCompactionMode === "remote_v2") {
11946
12055
  const forced = await isSessionCompactionRequested2(db, input.workspaceId, input.sessionId);
11947
12056
  const thresholdTokens = compactionThresholdTokens2(eventing.modelRunSettings);
11948
12057
  if (forced || (attempt.triggerType === "user.message" || attempt.triggerType === "system.update.delivered") && (session.lastInputTokens ?? 0) >= thresholdTokens) {
@@ -12753,6 +12862,7 @@ async function resolveSandboxRoute(deps) {
12753
12862
  };
12754
12863
  }
12755
12864
  async function establishTurnSandbox(deps) {
12865
+ const freshSandboxReadinessReplacementBudget = createFreshSandboxReadinessReplacementBudget();
12756
12866
  const {
12757
12867
  input,
12758
12868
  settings,
@@ -12988,6 +13098,8 @@ async function establishTurnSandbox(deps) {
12988
13098
  logicalFallbackSettings: logicalSandboxSettings,
12989
13099
  cancellationSignal: sandboxResumeSignal,
12990
13100
  sandboxMetrics: runtimeMetricsHooksForObservability(observability),
13101
+ observability,
13102
+ freshSandboxReadinessReplacementBudget,
12991
13103
  onSandboxLost: publishSandboxLost,
12992
13104
  objectStorage
12993
13105
  },
@@ -13059,6 +13171,8 @@ async function establishTurnSandbox(deps) {
13059
13171
  logicalFallbackSettings: logicalSandboxSettings,
13060
13172
  cancellationSignal: sandboxResumeSignal,
13061
13173
  sandboxMetrics: runtimeMetricsHooksForObservability(observability),
13174
+ observability,
13175
+ freshSandboxReadinessReplacementBudget,
13062
13176
  onSandboxLost: publishSandboxLost,
13063
13177
  objectStorage
13064
13178
  },
@@ -14771,6 +14885,7 @@ import {
14771
14885
  organizationModelProviderConnectionActiveForWorkspace,
14772
14886
  persistAttemptToolCatalog,
14773
14887
  prepareConnectorActionApproval,
14888
+ recordUsageEvent as recordUsageEvent4,
14774
14889
  previewConnectorActionApproval,
14775
14890
  namedSubjectHasLiveWorkspaceAuthority as namedSubjectHasLiveWorkspaceAuthority2,
14776
14891
  updateSessionTitleWithEvent as updateSessionTitleWithEvent2,
@@ -31490,6 +31605,205 @@ function createListModelsAttemptToolDefinition(input) {
31490
31605
  };
31491
31606
  }
31492
31607
 
31608
+ // src/activities/agent-turn/code-search.ts
31609
+ import { usableJevApiKey } from "@opengeni/config";
31610
+ import {
31611
+ CODE_SEARCH_TOOL_DESCRIPTION,
31612
+ CODE_SEARCH_TOOL_NAME,
31613
+ CodeSearchArgumentError,
31614
+ CodeSearchRipgrepMissingError,
31615
+ CodeSearchWorkspaceError,
31616
+ JevCircuitBreaker,
31617
+ JevClient,
31618
+ JevRequestError,
31619
+ JevUnavailableError,
31620
+ codeSearchInputSchema,
31621
+ parseCodeSearchArguments,
31622
+ renderCodeSearchError,
31623
+ runCodeSearch
31624
+ } from "@opengeni/jev";
31625
+ import {
31626
+ ChannelANotFoundError,
31627
+ ChannelAUnavailableError,
31628
+ ChannelAUnsupportedError,
31629
+ ChannelAValidationError,
31630
+ isWindowsConnectedMachinePath
31631
+ } from "@opengeni/runtime/sandbox";
31632
+ var codeSearchCircuitBreaker = new JevCircuitBreaker();
31633
+ var CODE_SEARCH_RIPGREP_MAX_BYTES = 32 * 1024 * 1024;
31634
+ function codeSearchWorkspaceFromChannel(channel) {
31635
+ return {
31636
+ ripgrep: async (args, options) => {
31637
+ options.signal?.throwIfAborted();
31638
+ const outcome = await channel.codeSearchRipgrep(args, {
31639
+ timeoutMs: options.timeoutMs,
31640
+ maxBytes: CODE_SEARCH_RIPGREP_MAX_BYTES
31641
+ });
31642
+ if (!outcome.available) throw new CodeSearchRipgrepMissingError();
31643
+ return {
31644
+ stdout: outcome.stdout,
31645
+ exitCode: outcome.exitCode,
31646
+ truncated: outcome.truncated,
31647
+ timedOut: outcome.timedOut
31648
+ };
31649
+ },
31650
+ readText: async (path, options) => {
31651
+ options.signal?.throwIfAborted();
31652
+ try {
31653
+ const read = await channel.fsRead({ path, encoding: "utf8", maxBytes: options.maxBytes });
31654
+ return { text: read.content, truncated: read.truncated, binary: read.isBinary };
31655
+ } catch (error51) {
31656
+ if (error51 instanceof ChannelANotFoundError) return null;
31657
+ throw error51;
31658
+ }
31659
+ },
31660
+ pathKinds: async (paths, options) => {
31661
+ options.signal?.throwIfAborted();
31662
+ return await channel.codeSearchPathKinds(paths);
31663
+ }
31664
+ };
31665
+ }
31666
+ function textResult(text, isError) {
31667
+ return { isError, content: [{ type: "text", text }] };
31668
+ }
31669
+ function createCodeSearchAttemptToolDefinition(input) {
31670
+ const breaker = input.breaker ?? codeSearchCircuitBreaker;
31671
+ const jev = new JevClient({
31672
+ apiKey: input.apiKey,
31673
+ baseUrl: input.settings.jevBaseUrl,
31674
+ model: input.settings.jevModel,
31675
+ timeoutMs: input.settings.jevRequestTimeoutMs,
31676
+ ...input.fetch ? { fetch: input.fetch } : {}
31677
+ });
31678
+ return {
31679
+ identity: { serverId: "opengeni", toolName: CODE_SEARCH_TOOL_NAME },
31680
+ modelName: CODE_SEARCH_TOOL_NAME,
31681
+ codemodePath: ["opengeni", CODE_SEARCH_TOOL_NAME],
31682
+ title: "Search code",
31683
+ description: CODE_SEARCH_TOOL_DESCRIPTION,
31684
+ inputSchema: codeSearchInputSchema,
31685
+ annotations: {
31686
+ title: "Search code",
31687
+ readOnlyHint: true,
31688
+ destructiveHint: false,
31689
+ idempotentHint: true,
31690
+ openWorldHint: false
31691
+ },
31692
+ source: "opengeni",
31693
+ approval: "none",
31694
+ execute: async (args, context) => {
31695
+ const startedAt = performance.now();
31696
+ let outcome = "failed";
31697
+ let jevRequests = 0;
31698
+ let jevCostUsd = 0;
31699
+ let lease = null;
31700
+ try {
31701
+ const request = parseCodeSearchArguments(args);
31702
+ lease = breaker.tryAcquire(Date.now());
31703
+ if (!lease) {
31704
+ outcome = "breaker_open";
31705
+ return textResult(
31706
+ renderCodeSearchError(
31707
+ new JevUnavailableError("Jev is not responding; calls are paused for a few minutes")
31708
+ ),
31709
+ true
31710
+ );
31711
+ }
31712
+ const workspace = await input.workspace();
31713
+ const result = await runCodeSearch({
31714
+ ...request,
31715
+ workspace,
31716
+ jev,
31717
+ ...context.signal ? { signal: context.signal } : {}
31718
+ });
31719
+ const held = lease;
31720
+ lease = null;
31721
+ if (result.statusCheckError instanceof JevUnavailableError) {
31722
+ breaker.recordFailure(result.statusCheckError, Date.now(), held);
31723
+ } else if (result.stats.jev.requests > 0) {
31724
+ breaker.recordSuccess(held);
31725
+ } else {
31726
+ breaker.release(held);
31727
+ }
31728
+ outcome = "completed";
31729
+ jevRequests = result.stats.jev.requests;
31730
+ jevCostUsd = result.stats.jev.costUsd;
31731
+ if (input.recordUsage && jevRequests > 0) {
31732
+ await input.recordUsage({
31733
+ operationId: context.operationId,
31734
+ jevRequests,
31735
+ jevInputTokens: result.stats.jev.inputTokens,
31736
+ jevCostUsd
31737
+ }).catch((error51) => {
31738
+ input.observability.warn("code_search usage record failed", {
31739
+ error: error51 instanceof Error ? error51.message : String(error51)
31740
+ });
31741
+ });
31742
+ }
31743
+ return textResult(result.text, false);
31744
+ } catch (error51) {
31745
+ if (context.signal?.aborted) {
31746
+ outcome = "cancelled";
31747
+ throw error51;
31748
+ }
31749
+ if (error51 instanceof CodeSearchArgumentError) {
31750
+ outcome = "invalid_arguments";
31751
+ return textResult(error51.message, true);
31752
+ }
31753
+ if (error51 instanceof JevUnavailableError) {
31754
+ const held = lease;
31755
+ lease = null;
31756
+ breaker.recordFailure(error51, Date.now(), held);
31757
+ outcome = "jev_unavailable";
31758
+ return textResult(renderCodeSearchError(error51), true);
31759
+ }
31760
+ if (error51 instanceof JevRequestError) {
31761
+ outcome = "jev_rejected";
31762
+ return textResult(renderCodeSearchError(error51), true);
31763
+ }
31764
+ if (error51 instanceof CodeSearchWorkspaceError) {
31765
+ outcome = "workspace_unavailable";
31766
+ return textResult(renderCodeSearchError(error51), true);
31767
+ }
31768
+ if (error51 instanceof ChannelAUnavailableError || error51 instanceof ChannelAUnsupportedError || error51 instanceof ChannelAValidationError) {
31769
+ outcome = "workspace_unavailable";
31770
+ return textResult(
31771
+ renderCodeSearchError(new CodeSearchWorkspaceError(error51.message)),
31772
+ true
31773
+ );
31774
+ }
31775
+ throw error51;
31776
+ } finally {
31777
+ if (lease) breaker.release(lease);
31778
+ recordCodeSearchCall(input.observability, {
31779
+ outcome,
31780
+ durationSeconds: (performance.now() - startedAt) / 1e3,
31781
+ jevRequests,
31782
+ jevCostUsd
31783
+ });
31784
+ }
31785
+ }
31786
+ };
31787
+ }
31788
+ function codeSearchToolDefinitions(input) {
31789
+ const apiKey = usableJevApiKey(input.settings);
31790
+ const breaker = input.breaker ?? codeSearchCircuitBreaker;
31791
+ if (!input.enabled || !apiKey || input.backend === "none") return [];
31792
+ if (input.machineWorkspaceRoot && isWindowsConnectedMachinePath(input.machineWorkspaceRoot)) {
31793
+ return [];
31794
+ }
31795
+ return [
31796
+ createCodeSearchAttemptToolDefinition({
31797
+ settings: input.settings,
31798
+ apiKey,
31799
+ workspace: input.workspace,
31800
+ observability: input.observability,
31801
+ ...input.recordUsage ? { recordUsage: input.recordUsage } : {},
31802
+ breaker
31803
+ })
31804
+ ];
31805
+ }
31806
+
31493
31807
  // src/activities/agent-turn/skill-tools.ts
31494
31808
  import { createHash as createHash12 } from "crypto";
31495
31809
  import {
@@ -32429,6 +32743,7 @@ async function prepareTurnToolRuntime(deps) {
32429
32743
  turnExecutionPolicy,
32430
32744
  trigger,
32431
32745
  runSettings: canonicalRunSettings,
32746
+ resolvedModel,
32432
32747
  lazyToolTransport,
32433
32748
  turnTools: canonicalTurnTools,
32434
32749
  sandboxArtifactRuntime,
@@ -32439,6 +32754,7 @@ async function prepareTurnToolRuntime(deps) {
32439
32754
  credentialSubjectId,
32440
32755
  interactionInterventionResume,
32441
32756
  runWorkspaceMutationForSandbox,
32757
+ codeSearchEnabled,
32442
32758
  throwIfWorkerShuttingDown,
32443
32759
  throwIfTurnCancelled
32444
32760
  } = deps;
@@ -32609,7 +32925,8 @@ async function prepareTurnToolRuntime(deps) {
32609
32925
  firstPartyMcpTools: selectedFirstPartyMcpTools,
32610
32926
  firstPartyMcpPermissions: effectiveFirstPartyPermissions
32611
32927
  }),
32612
- parallelGenerationAvailable: typeof runtime.generateSessionTitle === "function"
32928
+ parallelGenerationAvailable: typeof runtime.generateSessionTitle === "function",
32929
+ routeAllowsTitleRequests: routeAllowsSessionTitleRequests(resolvedModel)
32613
32930
  });
32614
32931
  const googleDrivePublicationAllowed = selectedFirstPartyMcpTools.includes("editable_artifact_export") && selectedFirstPartyMcpTools.includes("editable_artifact_export_status") && hasPermission2(
32615
32932
  [...effectiveFirstPartyPermissions ?? DEFAULT_FIRST_PARTY_MCP_PERMISSIONS2],
@@ -32769,6 +33086,60 @@ async function prepareTurnToolRuntime(deps) {
32769
33086
  return (await prepared.ready ?? prepared).attemptToolEnvironment;
32770
33087
  }
32771
33088
  });
33089
+ const codeSearchTools = codeSearchToolDefinitions({
33090
+ enabled: codeSearchEnabled,
33091
+ settings: runSettings,
33092
+ backend: activeSandboxBackend ?? groupBoxBackend,
33093
+ machineWorkspaceRoot: sandboxState.machinePrimarySession?.workspaceRoot ?? null,
33094
+ observability,
33095
+ // OpenGeni's Jev key pays for these calls whatever model billing the
33096
+ // workspace uses; record them per workspace so the cost stays visible.
33097
+ recordUsage: async (usage) => {
33098
+ const shared = {
33099
+ accountId: input.accountId,
33100
+ workspaceId: input.workspaceId,
33101
+ sourceResourceType: "code_search",
33102
+ sourceResourceId: usage.operationId,
33103
+ sessionId: input.sessionId,
33104
+ turnId: turn.id,
33105
+ turnAttemptId: input.attemptId
33106
+ };
33107
+ await recordUsageEvent4(db, {
33108
+ ...shared,
33109
+ eventType: "code_search.jev_input_tokens",
33110
+ quantity: usage.jevInputTokens,
33111
+ unit: "tokens",
33112
+ idempotencyKey: `usage:code_search.jev_input_tokens:${input.attemptId}:${usage.operationId}`
33113
+ });
33114
+ await recordUsageEvent4(db, {
33115
+ ...shared,
33116
+ eventType: "code_search.jev_cost",
33117
+ quantity: Math.round(usage.jevCostUsd * 1e6),
33118
+ unit: "usd_micros",
33119
+ idempotencyKey: `usage:code_search.jev_cost:${input.attemptId}:${usage.operationId}`
33120
+ });
33121
+ },
33122
+ workspace: async () => {
33123
+ throwIfWorkerShuttingDown();
33124
+ throwIfTurnCancelled();
33125
+ const access = await resolveTurnSandboxAccess(
33126
+ sandboxState,
33127
+ media.sdkOwnedSandboxSession,
33128
+ "code_search requires a sandbox or Connected Machine."
33129
+ );
33130
+ const machineRoot = sandboxState.machinePrimarySession?.workspaceRoot;
33131
+ const runAs = sandboxRunAs4(runSettings);
33132
+ return codeSearchWorkspaceFromChannel(
33133
+ new SandboxChannelAService3({
33134
+ session: access.session,
33135
+ workspaceRoot: machineRoot ?? "/workspace",
33136
+ ...machineRoot ? { providerPathMode: "workspace-relative" } : {},
33137
+ leaseEpoch: access.leaseEpoch,
33138
+ ...runAs ? { runAs } : {}
33139
+ })
33140
+ );
33141
+ }
33142
+ });
32772
33143
  const attemptToolDefinitions = [
32773
33144
  ...operationReadStore ? [
32774
33145
  createOperationReadAttemptToolDefinition({
@@ -32898,7 +33269,8 @@ async function prepareTurnToolRuntime(deps) {
32898
33269
  subjectLabel: "OpenGeni worker",
32899
33270
  ...interactionInterventionResume ? { interventionResume: interactionInterventionResume } : {}
32900
33271
  }),
32901
- ...googleDrivePublicationTool && googleDrivePublicationAllowed ? [googleDrivePublicationTool] : []
33272
+ ...googleDrivePublicationTool && googleDrivePublicationAllowed ? [googleDrivePublicationTool] : [],
33273
+ ...codeSearchTools
32902
33274
  ];
32903
33275
  recordTurnStartupPhase(observability, {
32904
33276
  phase: "tool_context_preparation",
@@ -33087,6 +33459,7 @@ async function prepareTurnToolRuntime(deps) {
33087
33459
  ...titleToolPlan.preparationIndependentToolNames,
33088
33460
  "skill_read"
33089
33461
  ],
33462
+ codeSearchAvailable: codeSearchTools.length > 0,
33090
33463
  skillCatalog
33091
33464
  };
33092
33465
  }
@@ -34505,6 +34878,7 @@ async function buildTurnAgent(deps) {
34505
34878
  connectorActionPolicy,
34506
34879
  trigger,
34507
34880
  preparationIndependentToolNames,
34881
+ codeSearchAvailable,
34508
34882
  videoGenerationAcceptancesByCallId,
34509
34883
  activeSandboxBackend,
34510
34884
  groupBoxBackend,
@@ -34911,6 +35285,7 @@ async function buildTurnAgent(deps) {
34911
35285
  ...activeSandboxBackend !== "selfhosted" && sandboxGitCredentialBindings ? { gitCredentialBindings: sandboxGitCredentialBindings } : {},
34912
35286
  ...activeSandboxBackend !== "selfhosted" && !sandboxGitTokens && sandboxGitToken ? { gitTokenSeed: sandboxGitToken } : {},
34913
35287
  ...sandboxCodemodeToken ? { codemodeAvailable: true } : {},
35288
+ ...codeSearchAvailable ? { codeSearchAvailable: true } : {},
34914
35289
  // Managed boxes receive the bearer through their protected per-session
34915
35290
  // token file. Connected Machines use transient per-exec delivery above,
34916
35291
  // so they must not run the file-seeding lifecycle hook.
@@ -35395,6 +35770,7 @@ function createRunAgentTurnActivity(services) {
35395
35770
  rigVersion,
35396
35771
  rigName,
35397
35772
  agentHumanInputEnabled,
35773
+ codeSearchEnabled,
35398
35774
  workspaceAgentInstructions,
35399
35775
  workspaceGovernance,
35400
35776
  structuredWorkspacePolicyActive,
@@ -36028,6 +36404,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
36028
36404
  turnExecutionPolicy,
36029
36405
  trigger,
36030
36406
  runSettings,
36407
+ resolvedModel,
36031
36408
  lazyToolTransport,
36032
36409
  turnTools,
36033
36410
  connectionScope,
@@ -36039,6 +36416,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
36039
36416
  credentialSubjectId,
36040
36417
  interactionInterventionResume,
36041
36418
  runWorkspaceMutationForSandbox,
36419
+ codeSearchEnabled,
36042
36420
  throwIfWorkerShuttingDown,
36043
36421
  throwIfTurnCancelled
36044
36422
  });
@@ -36101,6 +36479,7 @@ These are publication receipts for the human's earlier answer. Do not call the r
36101
36479
  connectorActionPolicy,
36102
36480
  trigger,
36103
36481
  preparationIndependentToolNames,
36482
+ codeSearchAvailable: toolRuntime.codeSearchAvailable,
36104
36483
  videoGenerationAcceptancesByCallId,
36105
36484
  activeSandboxBackend,
36106
36485
  groupBoxBackend,
@@ -37608,4 +37987,4 @@ export {
37608
37987
  createTurnActivities,
37609
37988
  createTurnActivitiesFromServices
37610
37989
  };
37611
- //# sourceMappingURL=activities-turn-EZEDZTEZ.js.map
37990
+ //# sourceMappingURL=activities-turn-CSDKK4N3.js.map