@opengeni/core 1.0.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4826,7 +4826,7 @@ function withDeveloperSetupCredentialRestriction(policy, source) {
4826
4826
  import {
4827
4827
  CLAUDE_CONNECTION_KINDS as CLAUDE_CONNECTION_KINDS3,
4828
4828
  claudeProviderId as claudeProviderId2,
4829
- canonicalizeConfiguredModelId as canonicalizeConfiguredModelId2,
4829
+ canonicalizeConfiguredModelId as canonicalizeConfiguredModelId3,
4830
4830
  configuredAllowedModels,
4831
4831
  withCodexCatalogProvider as withCodexCatalogProvider3,
4832
4832
  ORGANIZATION_GATEWAY_MODEL_ID_PREFIX as ORGANIZATION_GATEWAY_MODEL_ID_PREFIX2,
@@ -4856,6 +4856,7 @@ import {
4856
4856
  OPENGENI_SLACK_BOT_SESSION_METADATA_KEY as OPENGENI_SLACK_BOT_SESSION_METADATA_KEY2,
4857
4857
  SessionSkills,
4858
4858
  resolveBundledSkillSelection,
4859
+ bundledSkillSelectionForAgentConfig as bundledSkillSelectionForAgentConfig2,
4859
4860
  SessionSpawnDenial,
4860
4861
  ServiceTurnInitiator,
4861
4862
  ServiceTurnInitiatorContext as ServiceTurnInitiatorContext2,
@@ -4922,7 +4923,6 @@ import {
4922
4923
  SessionToolPolicyVersionConflictError,
4923
4924
  SessionCreateIdempotencyConflictError,
4924
4925
  PersonalResourceAttachmentAcceptanceError,
4925
- sessionTenancyProductActivated as sessionTenancyProductActivated2,
4926
4926
  workspaceControlRequestLockTimeoutMs,
4927
4927
  WorkspaceControlBusyError
4928
4928
  } from "@opengeni/db";
@@ -5088,6 +5088,7 @@ function prepareExternalLinkTaskAdmission(authorization, actor) {
5088
5088
  // src/billing/limits.ts
5089
5089
  import {
5090
5090
  configuredStaticUsageLimits,
5091
+ canonicalizeConfiguredModelId,
5091
5092
  resolveModelProviderForTurn
5092
5093
  } from "@opengeni/config";
5093
5094
  import {
@@ -5096,7 +5097,7 @@ import {
5096
5097
  countActiveOrganizationApiKeysForAccount,
5097
5098
  countScheduledTasksForWorkspace,
5098
5099
  countWorkspacesForAccount,
5099
- getBillingBalance,
5100
+ getSpendableCreditBalance,
5100
5101
  isCodexBilledTurn,
5101
5102
  recordUsageEvent,
5102
5103
  sumUsageQuantity
@@ -5177,11 +5178,19 @@ async function checkCreditBalance(deps, input, externallyBilled) {
5177
5178
  if (!usesCreditLimits(deps) || !isCostlyAction(input.action)) {
5178
5179
  return { allowed: true };
5179
5180
  }
5180
- const balance = await getBillingBalance(deps.db, input.accountId);
5181
+ const balance = await getSpendableCreditBalance(
5182
+ deps.db,
5183
+ input.accountId,
5184
+ input.model ? canonicalizeConfiguredModelId(deps.settings, input.model) : void 0
5185
+ );
5181
5186
  if (balance.balanceMicros > 0) {
5182
5187
  return { allowed: true };
5183
5188
  }
5184
- return { allowed: false, code: "insufficient_credits", message: "insufficient Opengeni credits" };
5189
+ return {
5190
+ allowed: false,
5191
+ code: "insufficient_credits",
5192
+ message: input.model ? "No credits available for this model. Choose a model covered by your promotional credits or add credits." : "No general credits available. Promotional credits cover eligible models only."
5193
+ };
5185
5194
  }
5186
5195
  async function checkStaticCaps(deps, input, funding) {
5187
5196
  const limits = configuredStaticUsageLimits(deps.settings);
@@ -7213,7 +7222,7 @@ function resolveWorkspaceModelSelection(input) {
7213
7222
 
7214
7223
  // src/default-session-model.ts
7215
7224
  import {
7216
- canonicalizeConfiguredModelId,
7225
+ canonicalizeConfiguredModelId as canonicalizeConfiguredModelId2,
7217
7226
  CLAUDE_CONNECTION_KINDS as CLAUDE_CONNECTION_KINDS2
7218
7227
  } from "@opengeni/config";
7219
7228
  import {
@@ -7235,7 +7244,8 @@ import {
7235
7244
  workspaceCodexSubscriptionActive,
7236
7245
  workspaceOpenRouterConnectionActive,
7237
7246
  workspaceVercelAiGatewayConnectionActive,
7238
- organizationHoldsCredits,
7247
+ getBillingBalance,
7248
+ spendableCreditMicros,
7239
7249
  workspaceXaiSubscriptionActive,
7240
7250
  workspaceXaiSubscriptionActiveForAuthority,
7241
7251
  XaiAuthorityPoolInactiveError,
@@ -7371,9 +7381,12 @@ function findSelection(selections, modelId) {
7371
7381
  return selections.find((selection) => selection.model.id === modelId) ?? selections.find((selection) => selection.model.aliases.includes(modelId));
7372
7382
  }
7373
7383
  function creditsCandidate(input) {
7384
+ const selections = input.creditBalance ? input.selections.filter(
7385
+ (selection) => spendableCreditMicros(input.creditBalance, selection.model.id) > 0
7386
+ ) : input.selections;
7374
7387
  const fallbackEffort = input.settings.openaiReasoningEffort;
7375
- const deployment = findSelection(input.selections, input.settings.openaiModel);
7376
- const configured = findSelection(input.selections, input.settings.creditsDefaultModel);
7388
+ const deployment = findSelection(selections, input.settings.openaiModel);
7389
+ const configured = findSelection(selections, input.settings.creditsDefaultModel);
7377
7390
  if (deployment?.availability.selectable && deployment.model.cost === "credits") {
7378
7391
  if (configured?.model.id !== deployment.model.id) return null;
7379
7392
  return {
@@ -7397,7 +7410,7 @@ function creditsCandidate(input) {
7397
7410
  source: "credits"
7398
7411
  };
7399
7412
  }
7400
- const first = input.selections.find(
7413
+ const first = selections.find(
7401
7414
  (selection) => selection.availability.selectable && selection.model.cost === "credits"
7402
7415
  );
7403
7416
  return first ? {
@@ -7446,7 +7459,7 @@ function selectDefaultSessionModel(input) {
7446
7459
  reasoningEffort: defaultReasoningEffortForConfiguredModel(fallback.model, fallbackEffort),
7447
7460
  source: "deployment"
7448
7461
  } : {
7449
- model: canonicalizeConfiguredModelId(input.settings, input.settings.openaiModel),
7462
+ model: canonicalizeConfiguredModelId2(input.settings, input.settings.openaiModel),
7450
7463
  reasoningEffort: fallbackEffort,
7451
7464
  source: "deployment"
7452
7465
  };
@@ -7457,7 +7470,8 @@ function creditsDefaultSessionModel(input) {
7457
7470
  settings: input.settings,
7458
7471
  selections: input.selections,
7459
7472
  workspaceDefaults: resolveWorkspaceSessionDefaults(input.workspaceSettings),
7460
- creditsAvailable: true
7473
+ creditsAvailable: true,
7474
+ ...input.creditBalance ? { creditBalance: input.creditBalance } : {}
7461
7475
  });
7462
7476
  }
7463
7477
  async function resolveDefaultSessionModelForSelections(db, input) {
@@ -7467,10 +7481,13 @@ async function resolveDefaultSessionModelForSelections(db, input) {
7467
7481
  workspaceDefaults: resolveWorkspaceSessionDefaults(input.workspaceSettings)
7468
7482
  };
7469
7483
  const withoutCredits = selectDefaultSessionModel({ ...decision, creditsAvailable: false });
7470
- if (withoutCredits.source !== "deployment" || input.settings.billingMode !== "stripe" || creditsCandidate(decision) === null) {
7484
+ if (withoutCredits.source !== "deployment" || input.settings.billingMode !== "stripe" || !input.selections.some(
7485
+ (selection) => selection.availability.selectable && selection.model.cost === "credits"
7486
+ )) {
7471
7487
  return withoutCredits;
7472
7488
  }
7473
- return await organizationHoldsCredits(db, input.accountId) ? selectDefaultSessionModel({ ...decision, creditsAvailable: true }) : withoutCredits;
7489
+ const creditBalance = await getBillingBalance(db, input.accountId);
7490
+ return selectDefaultSessionModel({ ...decision, creditsAvailable: true, creditBalance });
7474
7491
  }
7475
7492
  async function connectionRestrictionsAndXaiReadiness(db, settings, context) {
7476
7493
  const { workspaceId, subjectId, xaiAuthoritySnapshot } = context;
@@ -7788,6 +7805,7 @@ import {
7788
7805
  import {
7789
7806
  AGENT_SKILL_MANAGE_TOOL_NAMES,
7790
7807
  AUTOMATIC_SESSION_TITLE_FALLBACK,
7808
+ bundledSkillSelectionForAgentConfig,
7791
7809
  DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
7792
7810
  FIRST_PARTY_IN_PROCESS_TOOL_NAMES,
7793
7811
  SESSION_EFFECTIVE_TOOL_POLICY_ID_LIMIT,
@@ -8023,13 +8041,17 @@ async function workspaceSessionEffectiveToolsContext(deps, workspaceId, subjectI
8023
8041
  }
8024
8042
  function sessionHasSkills(session, context) {
8025
8043
  if (context.hasWorkspaceSkills || session.skills.length > 0) return true;
8026
- if (session.bundledSkillIds === void 0) return true;
8044
+ const bundledSkillIds = bundledSkillSelectionForAgentConfig(
8045
+ session.bundledSkillIds,
8046
+ session.agent
8047
+ );
8048
+ if (bundledSkillIds === void 0) return true;
8027
8049
  const tools = new Set(
8028
8050
  resolveAgentToolFamilies(session.agent).firstPartyTools(
8029
8051
  allowedFirstPartyMcpToolsForSession2(context.settings, session.firstPartyMcpTools)
8030
8052
  )
8031
8053
  );
8032
- return session.bundledSkillIds.some((id) => {
8054
+ return bundledSkillIds.some((id) => {
8033
8055
  if ([
8034
8056
  "builtin:opengeni-documents",
8035
8057
  "builtin:opengeni-spreadsheets",
@@ -8078,7 +8100,7 @@ function sessionEffectiveToolProjectionInput(session, toolRefs, context) {
8078
8100
  ) && session.sandboxOs !== "windows" ? ["code_search"] : []
8079
8101
  ] : [];
8080
8102
  const needsTitle = session.titleSource !== "user" && (!session.title?.trim() || session.title.trim() === AUTOMATIC_SESSION_TITLE_FALLBACK);
8081
- const firstPartyMcpTools = context && toolRefs.some((ref) => ref.id === "opengeni") ? resolveAgentToolFamilies(session.agent).firstPartyTools(
8103
+ const firstPartyMcpTools = context && toolRefs.some((ref) => ref.id === "opengeni") ? resolveAgentToolFamilies(session.agent, { sandboxAttached: sandboxAvailable }).firstPartyTools(
8082
8104
  allowedFirstPartyMcpToolsForSession2(context.settings, session.firstPartyMcpTools)
8083
8105
  ).filter((name) => name !== "set_session_title" || !needsTitle) : [];
8084
8106
  const interactionNames = new Set(FIRST_PARTY_IN_PROCESS_TOOL_NAMES);
@@ -8101,7 +8123,9 @@ function sessionEffectiveToolProjectionInput(session, toolRefs, context) {
8101
8123
  ].includes(name);
8102
8124
  if (permissionAllowed(readOnly ? "sessions:read" : "sessions:control") && (name !== "browser_download_save" || permissionAllowed("files:upload"))) {
8103
8125
  firstPartyModelNames.set(name, `interaction__${name}`);
8104
- if (!firstPartyMcpTools.includes(name) && resolveAgentToolFamilies(session.agent).allowsFirstPartyTool(name) && session.firstPartyMcpTools.includes(name))
8126
+ if (!firstPartyMcpTools.includes(name) && resolveAgentToolFamilies(session.agent, {
8127
+ sandboxAttached: sandboxAvailable
8128
+ }).allowsFirstPartyTool(name) && session.firstPartyMcpTools.includes(name))
8105
8129
  firstPartyMcpTools.push(name);
8106
8130
  }
8107
8131
  }
@@ -8132,7 +8156,8 @@ function sessionEffectiveToolProjectionInput(session, toolRefs, context) {
8132
8156
  webSearch: hostedToolNames.includes("web_search"),
8133
8157
  humanInput: context?.humanInputEnabled ?? false,
8134
8158
  media: media.toolsKnown ? media.hosted.length + media.runtime.length > 0 : void 0,
8135
- routerInHistory: context?.routerInHistory === true || context?.routerHistorySessionIds?.has(session.id) === true
8159
+ routerInHistory: context?.routerInHistory === true || context?.routerHistorySessionIds?.has(session.id) === true,
8160
+ ...context ? { sandboxAttached: sandboxAvailable } : {}
8136
8161
  };
8137
8162
  const families = resolveAgentToolFamilies(session.agent, environment);
8138
8163
  environment.hasDeferredTools = toolRefs.some(
@@ -8538,10 +8563,8 @@ import {
8538
8563
  isRetryableDatabaseTransportFailure,
8539
8564
  nestedPostgresSqlState as nestedPostgresSqlState3,
8540
8565
  replayAppliedSessionFork,
8541
- sessionTenancyProductActivated,
8542
8566
  SessionTenancyAccessError,
8543
8567
  SessionTenancyInvalidRequestError,
8544
- SessionTenancyNotActivatedError,
8545
8568
  transitionSessionVisibility
8546
8569
  } from "@opengeni/db";
8547
8570
  import { publishDurableSessionEvents } from "@opengeni/events";
@@ -8605,9 +8628,6 @@ async function requireManagedHumanPrivateSessionCreate(deps, authorization, work
8605
8628
  async function requireSessionTenancyMutationGate(deps, authorization, workspaceId, permissions) {
8606
8629
  requireVerifiedOwningUser(authorization, workspaceId);
8607
8630
  for (const permission of permissions) requirePermission(authorization.grant, permission);
8608
- if (!await sessionTenancyProductActivated(deps.db, workspaceId)) {
8609
- throw new SessionTenancyNotActivatedError();
8610
- }
8611
8631
  }
8612
8632
  async function publishExactCommittedEvent(deps, input) {
8613
8633
  if (input.eventId === null && input.eventSequence === null) return;
@@ -8879,11 +8899,6 @@ async function requireAtomicPersonalResourceAttachment(deps, authorization, work
8879
8899
  cause: error
8880
8900
  });
8881
8901
  }
8882
- if (!await sessionTenancyProductActivated2(deps.db, workspaceId)) {
8883
- throw new HTTPException17(409, {
8884
- message: "Session tenancy is not activated for this organization."
8885
- });
8886
- }
8887
8902
  if (existingSession && intent.expectedAuthorityEpoch === void 0) {
8888
8903
  throw new HTTPException17(422, {
8889
8904
  message: "Personal-resource attachment requires expectedAuthorityEpoch."
@@ -9248,6 +9263,13 @@ function automaticTitleForAgentChildCreate(presentation, goal, initialMessage) {
9248
9263
  return null;
9249
9264
  }
9250
9265
  async function createAndStartSessionWithOutcome(input) {
9266
+ const frozenBundledSkillIds = bundledSkillSelectionForAgentConfig2(
9267
+ input.bundledSkillIds,
9268
+ input.agentConfig
9269
+ );
9270
+ if (frozenBundledSkillIds !== input.bundledSkillIds) {
9271
+ input = { ...input, bundledSkillIds: frozenBundledSkillIds };
9272
+ }
9251
9273
  const sessionMetadata = metadataWithTurnExecutionPolicyV1(
9252
9274
  {
9253
9275
  ...input.metadata,
@@ -9631,7 +9653,7 @@ function canonicalConfiguredModel(settings, model) {
9631
9653
  if (model === null || model === void 0) {
9632
9654
  return model;
9633
9655
  }
9634
- const canonicalModel = canonicalizeConfiguredModelId2(settings, model);
9656
+ const canonicalModel = canonicalizeConfiguredModelId3(settings, model);
9635
9657
  if (canonicalModel.startsWith(CODEX_MODEL_ID_PREFIX) && settings.resolvedCodexModelsJson !== void 0) {
9636
9658
  if (settings.codexSubscriptionEnabled && configuredAllowedModels(withCodexCatalogProvider3(settings)).includes(canonicalModel)) {
9637
9659
  return canonicalModel;
@@ -10253,6 +10275,7 @@ async function createSessionForRequestInFileScope(unresolvedDeps, grant, workspa
10253
10275
  if (agentResolution.instructions !== void 0) {
10254
10276
  payload.instructions = agentResolution.instructions;
10255
10277
  }
10278
+ bundledSkillIds = bundledSkillSelectionForAgentConfig2(bundledSkillIds, agentConfig);
10256
10279
  const parentCallingTurn = parentSession && creationInitiator.actor ? await getSessionTurnForAttempt3(
10257
10280
  db,
10258
10281
  workspaceId,
@@ -12391,7 +12414,7 @@ import {
12391
12414
  applyCreditDebitAfterUse,
12392
12415
  checkWorkspaceAllowance as checkWorkspaceAllowance2,
12393
12416
  creditDebitAttributionForTurn,
12394
- getBillingBalance as getBillingBalance2,
12417
+ getSpendableCreditBalance as getSpendableCreditBalance2,
12395
12418
  listKnowledgeEntries,
12396
12419
  recordUsageEvent as recordUsageEvent2,
12397
12420
  sumUsageQuantity as sumUsageQuantity2,
@@ -12521,7 +12544,7 @@ async function searchKnowledgeEntries(db, context, input, embedder, settings) {
12521
12544
  context.accountId,
12522
12545
  context.workspaceId,
12523
12546
  async (lockedDb) => {
12524
- const balance = await getBillingBalance2(lockedDb, context.accountId);
12547
+ const balance = await getSpendableCreditBalance2(lockedDb, context.accountId);
12525
12548
  if (balance.balanceMicros <= 0)
12526
12549
  return keywordFallback(lockedDb, new KnowledgeVectorFundingError(), "awaiting_funding");
12527
12550
  const attribution = billingActor.kind === "agent" ? await creditDebitAttributionForTurn(lockedDb, {
@@ -12751,6 +12774,220 @@ function filenameForMimeType(mimeType) {
12751
12774
  }
12752
12775
  }
12753
12776
 
12777
+ // src/goal-admission.ts
12778
+ import {
12779
+ isModelAvailableForNewSelection as isModelAvailableForNewSelection2,
12780
+ policyProviderIdForModel as policyProviderIdForModel2,
12781
+ resolveModelProvider,
12782
+ runnableLatencyModesForModel,
12783
+ withCodexCatalogProvider as withCodexCatalogProvider4,
12784
+ withXaiSubscriptionCatalogProvider as withXaiSubscriptionCatalogProvider2
12785
+ } from "@opengeni/config";
12786
+ import {
12787
+ evaluateWorkspaceModelPolicy as evaluateWorkspaceModelPolicy3
12788
+ } from "@opengeni/contracts";
12789
+ import { isCodexBilledModel as isCodexBilledModel2 } from "@opengeni/codex";
12790
+ import { getWorkspaceModelPolicy as getWorkspaceModelPolicy3 } from "@opengeni/db";
12791
+
12792
+ // src/billing/agent-run-admission.ts
12793
+ import {
12794
+ canonicalizeConfiguredModelId as canonicalizeConfiguredModelId4,
12795
+ configuredStaticUsageLimits as configuredStaticUsageLimits2
12796
+ } from "@opengeni/config";
12797
+ import {
12798
+ checkWorkspaceAllowance as checkWorkspaceAllowance3,
12799
+ getSpendableCreditBalance as getSpendableCreditBalance3,
12800
+ isCodexBilledTurn as isCodexBilledTurn2,
12801
+ sumUsageQuantity as sumUsageQuantity3
12802
+ } from "@opengeni/db";
12803
+ async function agentRunAdmissionDenial(services, input) {
12804
+ const codexBilled = await isCodexBilledTurn2({
12805
+ db: services.db,
12806
+ settings: services.settings,
12807
+ workspaceId: input.workspaceId,
12808
+ model: input.model
12809
+ });
12810
+ const externallyBilled = modelFundingForAdmission(
12811
+ services.settings,
12812
+ input.model,
12813
+ codexBilled
12814
+ ).fundedWithoutCredits;
12815
+ if (!externallyBilled && (services.settings.billingMode === "stripe" || services.settings.usageLimitsMode === "managed")) {
12816
+ if (services.entitlements) {
12817
+ const decision = await services.entitlements.admitRun({
12818
+ accountId: input.accountId,
12819
+ workspaceId: input.workspaceId,
12820
+ action: "agent_run:create",
12821
+ quantity: input.requestedAgentRuns
12822
+ });
12823
+ if (!decision.allowed) return "insufficient_credits";
12824
+ } else {
12825
+ const balance = await getSpendableCreditBalance3(
12826
+ services.db,
12827
+ input.accountId,
12828
+ canonicalizeConfiguredModelId4(services.settings, input.model)
12829
+ );
12830
+ if (balance.balanceMicros <= 0) return "insufficient_credits";
12831
+ }
12832
+ }
12833
+ if (!externallyBilled) {
12834
+ const refusal = await checkWorkspaceAllowance3(services.db, {
12835
+ accountId: input.accountId,
12836
+ workspaceId: input.workspaceId,
12837
+ subjectId: input.initiatingHumanSubjectId ?? null
12838
+ });
12839
+ if (refusal) return refusal.code;
12840
+ }
12841
+ if (services.settings.usageLimitsMode !== "static" && services.settings.usageLimitsMode !== "managed") {
12842
+ return null;
12843
+ }
12844
+ const limits = configuredStaticUsageLimits2(services.settings);
12845
+ if (!externallyBilled && limits.maxMonthlyCostMicrosPerAccount) {
12846
+ const used = await sumUsageQuantity3(services.db, {
12847
+ accountId: input.accountId,
12848
+ eventType: "model.cost",
12849
+ since: startOfUtcMonth2()
12850
+ });
12851
+ if (used >= limits.maxMonthlyCostMicrosPerAccount) {
12852
+ return "monthly_model_cost_limit";
12853
+ }
12854
+ }
12855
+ if (limits.maxMonthlyAgentRunsPerWorkspace) {
12856
+ const used = await sumUsageQuantity3(services.db, {
12857
+ workspaceId: input.workspaceId,
12858
+ eventType: "agent_run.created",
12859
+ since: startOfUtcMonth2()
12860
+ });
12861
+ if (used + input.requestedAgentRuns > limits.maxMonthlyAgentRunsPerWorkspace) {
12862
+ return "monthly_agent_run_limit";
12863
+ }
12864
+ }
12865
+ return null;
12866
+ }
12867
+ function startOfUtcMonth2() {
12868
+ const now = /* @__PURE__ */ new Date();
12869
+ return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
12870
+ }
12871
+
12872
+ // src/goal-admission.ts
12873
+ function goalContinuationModelDecision(input) {
12874
+ const catalogSettings = input.settings.supergrokSubscriptionEnabled ? withXaiSubscriptionCatalogProvider2(
12875
+ input.settings.codexSubscriptionEnabled ? withCodexCatalogProvider4(input.settings) : input.settings
12876
+ ) : input.settings.codexSubscriptionEnabled ? withCodexCatalogProvider4(input.settings) : input.settings;
12877
+ const model = input.inheritedModel;
12878
+ if (!resolveModelProvider(catalogSettings, model)) {
12879
+ return {
12880
+ model,
12881
+ blocked: "The selected model is unavailable. Choose an available model before resuming.",
12882
+ pausedReason: "model_unavailable"
12883
+ };
12884
+ }
12885
+ if (!isModelAvailableForNewSelection2(catalogSettings, model)) {
12886
+ return {
12887
+ model,
12888
+ blocked: "The selected model has been retired. Choose an available model before resuming.",
12889
+ pausedReason: "model_unavailable"
12890
+ };
12891
+ }
12892
+ if (input.workspaceModelPolicy !== null && !evaluateWorkspaceModelPolicy3(input.workspaceModelPolicy, {
12893
+ providerId: policyProviderIdForModel2(catalogSettings, model),
12894
+ modelId: model
12895
+ }).allowed) {
12896
+ return {
12897
+ model,
12898
+ blocked: "Workspace policy blocks the selected model. Choose an allowed model before resuming.",
12899
+ pausedReason: "model_policy"
12900
+ };
12901
+ }
12902
+ if (input.codexCompactionMode === "remote_v2" && !isCodexBilledModel2(model)) {
12903
+ return {
12904
+ model,
12905
+ blocked: "This conversation requires a Codex model. Choose a Codex model before resuming.",
12906
+ pausedReason: "model_policy"
12907
+ };
12908
+ }
12909
+ if (!runnableLatencyModesForModel(catalogSettings, model).includes(input.latencyMode ?? "standard")) {
12910
+ return {
12911
+ model,
12912
+ blocked: "The selected model does not support this conversation's latency mode. Choose a supported mode or model before resuming.",
12913
+ pausedReason: "model_policy"
12914
+ };
12915
+ }
12916
+ return { model, blocked: null };
12917
+ }
12918
+ async function resolveGoalModelAdmission(db, settings, input) {
12919
+ const catalog = await resolveWorkspaceCatalogSettings(db, settings, {
12920
+ accountId: input.accountId,
12921
+ workspaceId: input.workspaceId,
12922
+ retainedProductModelId: input.model
12923
+ });
12924
+ const workspaceModelPolicy = await getWorkspaceModelPolicy3(db, input.workspaceId);
12925
+ return {
12926
+ settings: catalog.settings,
12927
+ ...goalContinuationModelDecision({
12928
+ settings: catalog.settings,
12929
+ workspaceModelPolicy,
12930
+ inheritedModel: input.model,
12931
+ ...input.codexCompactionMode ? { codexCompactionMode: input.codexCompactionMode } : {},
12932
+ ...input.latencyMode ? { latencyMode: input.latencyMode } : {}
12933
+ })
12934
+ };
12935
+ }
12936
+ async function goalRunBudgetBlocked(services, input) {
12937
+ const denial = await agentRunAdmissionDenial(services, { ...input, requestedAgentRuns: 1 });
12938
+ if (denial === null) return null;
12939
+ const blocks = {
12940
+ insufficient_credits: services.entitlements ? {
12941
+ pausedReason: "usage_policy",
12942
+ message: "The application's usage policy blocks another run. Resume when it allows."
12943
+ } : {
12944
+ pausedReason: "credits",
12945
+ message: "Insufficient Opengeni credits. Add credits before resuming."
12946
+ },
12947
+ allowance_exhausted: {
12948
+ pausedReason: "allowance",
12949
+ message: "Opengeni usage allowance exhausted. Resume when your allowance is available."
12950
+ },
12951
+ monthly_model_cost_limit: {
12952
+ pausedReason: "budget",
12953
+ message: "Monthly model spending limit reached. Resume when the spending limit allows."
12954
+ },
12955
+ monthly_agent_run_limit: {
12956
+ pausedReason: "usage_limit",
12957
+ message: "Monthly agent run limit reached. Resume when the run limit allows."
12958
+ }
12959
+ };
12960
+ return blocks[denial];
12961
+ }
12962
+ var GoalResumeBlockedError = class extends Error {
12963
+ constructor(pausedReason, message) {
12964
+ super(message);
12965
+ this.pausedReason = pausedReason;
12966
+ this.name = "GoalResumeBlockedError";
12967
+ }
12968
+ };
12969
+ async function assertGoalResumeAllowed(services, session, causalTurn) {
12970
+ const decision = await resolveGoalModelAdmission(
12971
+ services.db,
12972
+ services.catalogSourceSettings ?? services.settings,
12973
+ session
12974
+ );
12975
+ if (decision.blocked) {
12976
+ throw new GoalResumeBlockedError(decision.pausedReason, decision.blocked);
12977
+ }
12978
+ const block = await goalRunBudgetBlocked(
12979
+ { ...services, settings: decision.settings },
12980
+ {
12981
+ accountId: session.accountId,
12982
+ workspaceId: session.workspaceId,
12983
+ model: decision.model,
12984
+ // Resuming does not lend the clicking user's allowance or credentials.
12985
+ initiatingHumanSubjectId: causalTurn?.initiatingHumanSubjectId ?? null
12986
+ }
12987
+ );
12988
+ if (block) throw new GoalResumeBlockedError(block.pausedReason, block.message);
12989
+ }
12990
+
12754
12991
  // src/application/external-workspace-members.ts
12755
12992
  import { HTTPException as HTTPException18 } from "hono/http-exception";
12756
12993
  import {
@@ -17695,7 +17932,7 @@ function orderScheduledTaskAccessAttention(items) {
17695
17932
  }
17696
17933
 
17697
17934
  // src/domain/insights.ts
17698
- import { configuredStaticUsageLimits as configuredStaticUsageLimits2 } from "@opengeni/config";
17935
+ import { configuredStaticUsageLimits as configuredStaticUsageLimits3 } from "@opengeni/config";
17699
17936
  import {
17700
17937
  WorkspaceInsightsSnapshot
17701
17938
  } from "@opengeni/contracts";
@@ -17826,7 +18063,7 @@ function cacheHitPct(cached2, input) {
17826
18063
  function startOfUtcDay(date) {
17827
18064
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
17828
18065
  }
17829
- function startOfUtcMonth2(date) {
18066
+ function startOfUtcMonth3(date) {
17830
18067
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1));
17831
18068
  }
17832
18069
  function startOfUtcYear(date) {
@@ -17855,7 +18092,7 @@ function resolveRangeWindow(range, now) {
17855
18092
  cacheSeriesLabel = "Cache hit % / UTC day";
17856
18093
  break;
17857
18094
  case "month":
17858
- since = startOfUtcMonth2(now);
18095
+ since = startOfUtcMonth3(now);
17859
18096
  rangeLabel = "This month (UTC)";
17860
18097
  priorLabel = "Prior equal window";
17861
18098
  seriesLabel = "Credit $ / UTC day";
@@ -17986,7 +18223,7 @@ async function getWorkspaceInsights(db, settings, input, observePhase) {
17986
18223
  until: window.until,
17987
18224
  priorSince: window.priorSince,
17988
18225
  priorUntil: window.priorUntil,
17989
- monthSince: startOfUtcMonth2(now),
18226
+ monthSince: startOfUtcMonth3(now),
17990
18227
  granularity: input.range === "today" ? "hour" : "day",
17991
18228
  warmGroupLimit: 24
17992
18229
  })
@@ -18229,7 +18466,7 @@ async function getWorkspaceInsights(db, settings, input, observePhase) {
18229
18466
  billing: fact ? billingPathOf(fact.billingPath) : null
18230
18467
  };
18231
18468
  });
18232
- const limits = configuredStaticUsageLimits2(settings);
18469
+ const limits = configuredStaticUsageLimits3(settings);
18233
18470
  const floor = floorRows.filter((row) => {
18234
18471
  if (!model) return true;
18235
18472
  return row.model === model;
@@ -20178,7 +20415,7 @@ import {
20178
20415
  withWorkspaceSubjectRls as withWorkspaceSubjectRls6
20179
20416
  } from "@opengeni/db";
20180
20417
  import { HTTPException as HTTPException29 } from "hono/http-exception";
20181
- import { canonicalizeConfiguredModelId as canonicalizeConfiguredModelId3 } from "@opengeni/config";
20418
+ import { canonicalizeConfiguredModelId as canonicalizeConfiguredModelId5 } from "@opengeni/config";
20182
20419
  function hasOwn(value, key) {
20183
20420
  return typeof value === "object" && value !== null && Object.hasOwn(value, key);
20184
20421
  }
@@ -20203,7 +20440,7 @@ function mapNewSessionDraft(row) {
20203
20440
  }
20204
20441
  function draftModelProvided(settings, draft) {
20205
20442
  if (draft.modelProvided !== void 0) return draft.modelProvided;
20206
- return !(canonicalizeConfiguredModelId3(settings, draft.model) === canonicalizeConfiguredModelId3(settings, settings.openaiModel) && draft.reasoningEffort === settings.openaiReasoningEffort && draft.latencyMode === "standard");
20443
+ return !(canonicalizeConfiguredModelId5(settings, draft.model) === canonicalizeConfiguredModelId5(settings, settings.openaiModel) && draft.reasoningEffort === settings.openaiReasoningEffort && draft.latencyMode === "standard");
20207
20444
  }
20208
20445
  async function actorDefaultModel(deps, grant, workspaceId) {
20209
20446
  return await resolveDefaultSessionModel(deps.db, deps.settings, {
@@ -20477,7 +20714,7 @@ async function submitComposerDraftForRequest(deps, grant, workspaceId, sessionId
20477
20714
  import { DraftTimelineAnnotations as DraftTimelineAnnotations3 } from "@opengeni/contracts";
20478
20715
  import { HTTPException as HTTPException30 } from "hono/http-exception";
20479
20716
  import {
20480
- checkWorkspaceAllowance as checkWorkspaceAllowance3,
20717
+ checkWorkspaceAllowance as checkWorkspaceAllowance4,
20481
20718
  deleteSessionQueueItemInTransaction,
20482
20719
  editQueuedTurnInTransaction,
20483
20720
  getComposerDraftInTransaction as getComposerDraftInTransaction2,
@@ -20486,7 +20723,7 @@ import {
20486
20723
  getWorkspaceControlEvent as getWorkspaceControlEvent2,
20487
20724
  getSessionQueueSnapshot,
20488
20725
  frozenInitiatorForCommandActor as frozenInitiatorForCommandActor2,
20489
- isCodexBilledTurn as isCodexBilledTurn2,
20726
+ isCodexBilledTurn as isCodexBilledTurn3,
20490
20727
  moveQueuedTurnInTransaction,
20491
20728
  mutateSessionControlInTransaction,
20492
20729
  mutateWorkspaceControlInTransaction,
@@ -20564,7 +20801,7 @@ async function assertFreshAgentCommandAllowance(tx, deps, context, targetSession
20564
20801
  workspaceId: context.workspaceId,
20565
20802
  retainedProductModelId: target.model
20566
20803
  });
20567
- const codexBilled = await isCodexBilledTurn2({
20804
+ const codexBilled = await isCodexBilledTurn3({
20568
20805
  db: tx,
20569
20806
  settings,
20570
20807
  workspaceId: context.workspaceId,
@@ -20575,7 +20812,7 @@ async function assertFreshAgentCommandAllowance(tx, deps, context, targetSession
20575
20812
  }
20576
20813
  }
20577
20814
  const frozen = await frozenInitiatorForCommandActor2(tx, context.workspaceId, agentActor(context));
20578
- const refusal = await checkWorkspaceAllowance3(tx, {
20815
+ const refusal = await checkWorkspaceAllowance4(tx, {
20579
20816
  accountId: target.accountId,
20580
20817
  workspaceId: context.workspaceId,
20581
20818
  subjectId: initiatingHumanForAllowance(frozen)
@@ -21432,9 +21669,7 @@ async function consentManagedHumanSandboxRecovery(deps, authorization, workspace
21432
21669
  import {
21433
21670
  issueSelfUserResourceGrant,
21434
21671
  listSelfUserResourceAuthorities,
21435
- revokeSelfUserResourceGrant,
21436
- sessionTenancyProductActivated as sessionTenancyProductActivated3,
21437
- SessionTenancyNotActivatedError as SessionTenancyNotActivatedError2
21672
+ revokeSelfUserResourceGrant
21438
21673
  } from "@opengeni/db";
21439
21674
  var LIST_PERMISSIONS = {
21440
21675
  connection: ["connections:read"],
@@ -21452,9 +21687,6 @@ var ISSUE_PERMISSIONS = {
21452
21687
  };
21453
21688
  async function requireOwnerProductGate(deps, authorization, workspaceId, permissions) {
21454
21689
  requireOwnerAuthority(authorization, workspaceId, permissions);
21455
- if (!await sessionTenancyProductActivated3(deps.db, workspaceId)) {
21456
- throw new SessionTenancyNotActivatedError2();
21457
- }
21458
21690
  }
21459
21691
  function requireOwnerAuthority(authorization, workspaceId, permissions) {
21460
21692
  if (!authorization.canonicalLocalHumanSession) {
@@ -21466,9 +21698,6 @@ function requireOwnerAuthority(authorization, workspaceId, permissions) {
21466
21698
  }
21467
21699
  async function listManagedHumanUserResourceAuthorities(deps, authorization, workspaceId, input) {
21468
21700
  requireOwnerAuthority(authorization, workspaceId, LIST_PERMISSIONS[input.resourceKind]);
21469
- if (!await sessionTenancyProductActivated3(deps.db, workspaceId)) {
21470
- return { authorities: [], nextCursor: null };
21471
- }
21472
21701
  return await listSelfUserResourceAuthorities(deps.db, {
21473
21702
  accountId: authorization.grant.accountId,
21474
21703
  workspaceId,
@@ -22195,6 +22424,7 @@ export {
22195
22424
  EditableArtifactStaleBaseError,
22196
22425
  EditableArtifactUndoTargetError,
22197
22426
  GITHUB_ACTION_POLICY_GROUP_TOOL_NAMES,
22427
+ GoalResumeBlockedError,
22198
22428
  InMemoryEditableArtifactLiveTicketStore,
22199
22429
  InMemoryEditableArtifactStableIdFactory,
22200
22430
  InMemoryEditableArtifactStore,
@@ -22266,6 +22496,7 @@ export {
22266
22496
  agentAccessListScopeForViewer,
22267
22497
  agentAccessPermitsCrossTreeAccess,
22268
22498
  agentConfigParentFor,
22499
+ agentRunAdmissionDenial,
22269
22500
  apiIntegrationsMatchingDelegations,
22270
22501
  appendArchivedSessionEventsForRequest,
22271
22502
  appendRigSetupCommand,
@@ -22285,6 +22516,7 @@ export {
22285
22516
  assertConversationDeliveryOutcome,
22286
22517
  assertConversationInboundEnvelope,
22287
22518
  assertConversationProviderReceipt,
22519
+ assertGoalResumeAllowed,
22288
22520
  assertIsoTimestamp,
22289
22521
  assertKnownVideoGenerationModelIds,
22290
22522
  assertManagedUserAdmission,
@@ -22438,6 +22670,8 @@ export {
22438
22670
  getManagedSession,
22439
22671
  getWorkspaceInsights,
22440
22672
  githubAppActionPolicyActor,
22673
+ goalContinuationModelDecision,
22674
+ goalRunBudgetBlocked,
22441
22675
  googleDrivePublicationDelegationFromVisibleConnections,
22442
22676
  governedLearningEvidenceIsSlackDerived,
22443
22677
  governedLearningSlackImportance,
@@ -22642,6 +22876,7 @@ export {
22642
22876
  resolveFikenDefaultCompanySlug,
22643
22877
  resolveFirstPartyMcpToolsForCreate,
22644
22878
  resolveGitHubRepositoryBindings,
22879
+ resolveGoalModelAdmission,
22645
22880
  resolveMemberSubjectId,
22646
22881
  resolveRigProviderImageForRun,
22647
22882
  resolveRigProviderImageSelection,