@opengeni/config 0.16.2 → 0.19.0-canary.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
@@ -5,12 +5,14 @@ import {
5
5
  DEFAULT_FIRST_PARTY_MCP_TOOLS,
6
6
  Entitlements,
7
7
  EntitlementsMode,
8
+ KnowledgeSourceSyncLimits,
8
9
  LatencyMode,
9
10
  MAX_NESTED_AGENT_DEPTH,
10
11
  ProductAccessMode,
11
12
  ReasoningEffort,
12
13
  FIRST_PARTY_MCP_TOOL_NAMES,
13
14
  FirstPartyMcpToolName,
15
+ OpenGeniSlackBotDisplayName,
14
16
  SandboxBackend,
15
17
  SessionMcpApprovalPolicy,
16
18
  SEEDANCE_2_5_MODEL_ID,
@@ -35,7 +37,8 @@ import {
35
37
  XAI_SUBSCRIPTION_MODEL_EFFECTIVE_CONTEXT_WINDOW_TOKENS,
36
38
  XAI_SUBSCRIPTION_MODEL_ID_PREFIX,
37
39
  XAI_SUBSCRIPTION_PROVIDER_ID,
38
- XAI_SUBSCRIPTION_PROXY_BASE_URL
40
+ XAI_SUBSCRIPTION_PROXY_BASE_URL,
41
+ XAI_RESPONSE_STREAM_IDLE_TIMEOUT_MS
39
42
  } from "@opengeni/xai-subscription";
40
43
  import { XAI_SUBSCRIPTION_MODEL_ID_PREFIX as XAI_SUBSCRIPTION_MODEL_ID_PREFIX2 } from "@opengeni/xai-subscription";
41
44
  import { createHash } from "crypto";
@@ -45,6 +48,8 @@ var registryId = /^[A-Za-z0-9_-]+$/;
45
48
  var SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS = 60 * 6e4;
46
49
  var SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS = 1e4;
47
50
  var SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS = SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS - SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS;
51
+ var GOOGLE_DRIVE_PROVIDER_REQUEST_TIMEOUT_MAX_MS = 6e4;
52
+ var GOOGLE_DRIVE_PROVIDER_RETRY_DELAY_MAX_MS = 6e4;
48
53
  var SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS = 60 * 6e4;
49
54
  var SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS = 1e4;
50
55
  var EnvBoolean = z.preprocess((value) => {
@@ -60,6 +65,17 @@ var EnvBoolean = z.preprocess((value) => {
60
65
  }
61
66
  return value;
62
67
  }, z.boolean());
68
+ var DEFAULT_GOAL_IDLE_BACKOFF_MS = [3e3, 3e4, 12e4, 3e5];
69
+ var DEFAULT_GOAL_IDLE_BACKOFF_MAX_MS = 6e5;
70
+ var EnvGoalIdleBackoffMs = z.preprocess((value) => {
71
+ if (typeof value !== "string") return value;
72
+ const source = value.trim();
73
+ if (!source) return void 0;
74
+ return source.split(",").map((entry) => {
75
+ const trimmed = entry.trim();
76
+ return trimmed === "" ? Number.NaN : Number(trimmed);
77
+ });
78
+ }, z.array(z.number().int().nonnegative()).min(1, "OPENGENI_GOAL_IDLE_BACKOFF_MS must list at least one delay in milliseconds").readonly());
63
79
  var EnvFirstPartyMcpTools = z.preprocess(
64
80
  (value) => {
65
81
  if (typeof value !== "string") return value;
@@ -245,11 +261,31 @@ var SettingsSchema = z.object({
245
261
  // Explicit operator-controlled promotion pointer for `/agent/latest/*`.
246
262
  // Versioned agent releases are immutable; changing this setting promotes or
247
263
  // rolls back the stable channel without moving or deleting a provider tag.
248
- agentStableVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).default("0.1.14"),
264
+ agentStableVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).default("0.1.16"),
249
265
  // Optional independent beta-channel pointer. When unset, the beta update
250
266
  // manifest route is unavailable rather than silently serving stable.
251
267
  agentBetaVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).optional(),
252
268
  productAccessMode: ProductAccessMode.default("local"),
269
+ // --- canonical organization-tenancy authority activation, default OFF ---
270
+ // The named PRE-ACTIVATION opt-out for the organization-tenancy program. FALSE (the
271
+ // default, and the value an operator leaves in place to decline or defer) means
272
+ // this deployment stays on the reversible legacy workspace-owned lane: no phase-F
273
+ // subsystem may switch its access decision to organization/membership authority
274
+ // ids. TRUE is an operator's explicit statement that the activation preconditions
275
+ // in docs/organization-tenancy.md have been proven for this deployment and that
276
+ // the one-way boundary is accepted.
277
+ //
278
+ // This is NOT a kill switch and NOT a rollback: once an activation migration has
279
+ // committed, setting it back to false does not restore the legacy authority - only
280
+ // forward recovery is available. It also grants and revokes nothing by itself;
281
+ // every individual authorization decision keeps its own fences.
282
+ //
283
+ // No runtime path reads it yet: canonical activation (phase F) is unshipped, so
284
+ // the flag exists to reserve the name, pin the safe default, and give every future
285
+ // activation slice one gate to consult. EnvBoolean (NOT z.coerce.boolean(), which
286
+ // coerces "false" -> true and would activate the moment an operator wrote the
287
+ // variable out to disable it).
288
+ organizationTenancyCanonicalActivationEnabled: EnvBoolean.default(false),
253
289
  billingMode: BillingMode.default("disabled"),
254
290
  entitlementsMode: EntitlementsMode.default("none"),
255
291
  usageLimitsMode: UsageLimitsMode.default("none"),
@@ -268,7 +304,6 @@ var SettingsSchema = z.object({
268
304
  // holder of stream:control gets 403 until this flips. Keeps stream:control a
269
305
  // declared-but-inert permission so later hardening is a flag flip.
270
306
  streamControlEnabled: EnvBoolean.default(false),
271
- codemodeMaxCallsPerTurn: z.coerce.number().int().positive().default(200),
272
307
  // Optional release-coherent bootstrap hint for custom rigs/connected machines
273
308
  // that do not carry the stock-image ogtool binary. Exact stable versions only:
274
309
  // the agent must never guess a tag or silently install `latest`.
@@ -278,12 +313,24 @@ var SettingsSchema = z.object({
278
313
  integrationsStateSecret: z.string().optional(),
279
314
  integrationsAllowPrivateNetworkTargets: EnvBoolean.default(false),
280
315
  integrationsOauthClientsJson: z.string().default("{}"),
281
- gmailRestAdapterEnabled: EnvBoolean.default(false),
282
316
  slackClientId: z.string().optional(),
283
317
  slackClientSecret: z.string().optional(),
284
318
  slackSigningSecret: z.string().optional(),
319
+ slackBotDisplayName: OpenGeniSlackBotDisplayName.default("OpenGeni"),
320
+ slackCommand: z.string().trim().regex(/^\/[a-z0-9_-]{1,31}$/u).default("/opengeni"),
285
321
  googleDriveClientId: z.string().optional(),
286
322
  googleDriveClientSecret: z.string().optional(),
323
+ googleDriveSyncMaxItems: z.coerce.number().int().positive().max(1e4).default(500),
324
+ googleDriveSyncMaxBytes: z.coerce.number().int().positive().max(5e9).default(5e8),
325
+ googleDriveSyncMaxFileBytes: z.coerce.number().int().positive().max(5e9).default(1e8),
326
+ googleDriveSyncMaxProviderRequests: z.coerce.number().int().positive().max(1e4).default(1e3),
327
+ googleDriveSyncMaxElapsedSeconds: z.coerce.number().int().positive().max(3600).default(300),
328
+ googleDriveSyncMaxFailureDetails: z.coerce.number().int().positive().max(100).default(25),
329
+ googleDriveProviderRequestTimeoutMs: z.coerce.number().int().min(1e3).max(GOOGLE_DRIVE_PROVIDER_REQUEST_TIMEOUT_MAX_MS).default(3e4),
330
+ googleDriveProviderRetryAttempts: z.coerce.number().int().min(1).max(5).default(3),
331
+ googleDriveProviderRetryInitialDelayMs: z.coerce.number().int().positive().max(3e4).default(250),
332
+ googleDriveProviderRetryMaxDelayMs: z.coerce.number().int().positive().max(GOOGLE_DRIVE_PROVIDER_RETRY_DELAY_MAX_MS).default(5e3),
333
+ googleDriveProviderRetryBudgetMs: z.coerce.number().int().positive().max(12e4).default(15e3),
287
334
  fikenClientId: z.string().optional(),
288
335
  fikenClientSecret: z.string().optional(),
289
336
  googleDriveWorkspaceEventsEnabled: EnvBoolean.optional(),
@@ -296,24 +343,52 @@ var SettingsSchema = z.object({
296
343
  // id ("x", "reddit"): {"x":{"clientId":"...","clientSecret":"..."}}.
297
344
  socialOauthClientsJson: z.string().default("{}"),
298
345
  // Session goal guard rails. Goals are designed for runs that legitimately
299
- // span days, so length is bounded by pathology detection (no-progress
300
- // streaks, budget exhaustion), never by count. goalMaxAutoContinuations is
301
- // therefore UNSET by default (no cap); deployments may configure one, and
302
- // it then acts as a hard ceiling that per-goal overrides can only lower.
346
+ // span days, so length is bounded by explicit completion/pause and budget
347
+ // exhaustion, never by count. goalMaxAutoContinuations is therefore UNSET
348
+ // by default (no cap); deployments may configure one, and it then acts as a
349
+ // hard ceiling that per-goal overrides can only lower.
303
350
  goalMaxAutoContinuations: z.coerce.number().int().positive().optional(),
304
- goalNoProgressLimit: z.coerce.number().int().positive().default(3),
351
+ // Idle backoff between CONSECUTIVE no-input goal continuations. This is
352
+ // pacing, not a cap: the first continuation after a turn that consumed any
353
+ // external input is immediate, the n-th consecutive no-input continuation
354
+ // waits schedule[min(n - 1, last)] ms after the previous one finished, and
355
+ // any new input (machine input, human/API prompt, Steer) wakes the session
356
+ // immediately. The delay never exceeds goalIdleBackoffMaxMs.
357
+ goalIdleBackoffMs: EnvGoalIdleBackoffMs.default(DEFAULT_GOAL_IDLE_BACKOFF_MS),
358
+ goalIdleBackoffMaxMs: z.coerce.number().int().positive().default(DEFAULT_GOAL_IDLE_BACKOFF_MAX_MS),
359
+ // Child lifecycle notices: a child session's requires_action freeze, its
360
+ // resolution, a direct Pause, a provider-capacity wait, and goal progress
361
+ // become typed `session_system_updates` rows for the parent (in addition to
362
+ // `child_terminal_result`). Rolling hazard: a pre-notice worker throws on an
363
+ // unknown update kind, so enable only once the whole fleet runs an image
364
+ // that understands the new kinds. Once the flag has produced rows, a
365
+ // pre-notice image must never restart while any new-kind row is still
366
+ // pending (session_system_updates or session_system_update_outbox); turning
367
+ // the flag back off stops production but does not drain already committed
368
+ // rows. Default off. The API and both workers install the validated value
369
+ // into @opengeni/db once at boot.
370
+ // Env: OPENGENI_CHILD_LIFECYCLE_NOTICES_ENABLED.
371
+ childLifecycleNoticesEnabled: EnvBoolean.default(false),
372
+ // Per-channel and per-DM Slack workspace routing. Default off: with the flag
373
+ // off the routing resolver short-circuits to the installation's own workspace
374
+ // before any new read, so an existing single-workspace install behaves exactly
375
+ // as it did. Enabling it is a deploy decision, not a code default.
376
+ // Env: OPENGENI_SLACK_WORKSPACE_ROUTING_ENABLED.
377
+ slackWorkspaceRoutingEnabled: EnvBoolean.default(false),
305
378
  // Per-segment ceiling on agent loop turns (model calls) within a single
306
379
  // session turn. Effectively unbounded by default for the same reason as
307
380
  // above; the graceful max-turns valve (idle + goal continuation, never a
308
381
  // session failure) remains as inert safety should a deployment set a cap.
309
382
  agentMaxModelCallsPerTurn: z.coerce.number().int().positive().default(1e6),
310
- // The model family's real context window in tokens. OpenGeni always performs
311
- // one durable, portable plaintext compaction transition; there is no
312
- // provider/server/off mode ladder.
383
+ // Deployment fallback for models that do not declare their own window.
384
+ // Built-in billed GPT-5.6 Sol/Terra/Luna pin Codex's 272k catalog instead.
385
+ // OpenGeni always performs one durable, portable plaintext compaction
386
+ // transition; there is no provider/server/off mode ladder.
313
387
  contextWindowTokens: z.coerce.number().int().positive().default(105e4),
314
- // Optional model-catalog effective input ceiling. Codex models expose this as
315
- // raw context_window * effective_context_window_percent; when absent, retain
316
- // the deployment-level window-minus-reserved-output behavior.
388
+ // Optional model-catalog effective input ceiling. Codex and billed GPT-5.6
389
+ // models expose this as raw context_window * effective_context_window_percent;
390
+ // when absent, retain the deployment-level window-minus-reserved-output
391
+ // behavior.
317
392
  contextEffectiveWindowTokens: z.coerce.number().int().positive().optional(),
318
393
  // Proactive compaction threshold as a ratio of the model context window.
319
394
  // Defaults to 90%: compact as late as possible — retained context beats early
@@ -345,6 +420,10 @@ var SettingsSchema = z.object({
345
420
  apiHost: z.string().default("0.0.0.0"),
346
421
  apiPort: z.coerce.number().int().positive().default(8e3),
347
422
  workerHttpPort: z.coerce.number().int().positive().default(8001),
423
+ // Worker-side first-party MCP traffic stays on the deployment's internal
424
+ // network. OPENGENI_MCP_URL remains the sandbox/external route used by
425
+ // Codemode and remote placements.
426
+ opengeniMcpInternalUrl: z.string().url().optional(),
348
427
  opengeniMcpUrl: z.string().url().optional(),
349
428
  // Origins allowed to send browser cookies cross-origin. Other origins may
350
429
  // call the public API with bearer credentials, but never receive credentialed
@@ -429,6 +508,9 @@ var SettingsSchema = z.object({
429
508
  // account pool and a distinct rail from the existing xai/* API-key provider.
430
509
  supergrokSubscriptionEnabled: EnvBoolean.default(false),
431
510
  // OPENGENI_SUPERGROK_SUBSCRIPTION_ENABLED
511
+ // Maximum silence between complete, valid SuperGrok SSE data events. This is
512
+ // not a request/run duration cap; every valid event resets the timer.
513
+ supergrokResponseStreamIdleTimeoutMs: z.coerce.number().int().positive().max(24 * 60 * 6e4).default(XAI_RESPONSE_STREAM_IDLE_TIMEOUT_MS),
432
514
  // Expose the connected apps attached to a Codex subscription through the
433
515
  // synthetic codex_apps MCP server. Independent from subscription routing so
434
516
  // operators can use Codex models without exposing ChatGPT connectors.
@@ -437,12 +519,13 @@ var SettingsSchema = z.object({
437
519
  codexProductSku: z.string().optional(),
438
520
  // OPENGENI_CODEX_PRODUCT_SKU (X-OpenAI-Product-Sku, apps only)
439
521
  // Progressive MCP disclosure (Codex-CLI-style tool_search): on a codex turn,
440
- // flag non-mandatory selected MCP tools `defer_loading:true` (dropping their
522
+ // flag non-eager selected MCP tools `defer_loading:true` (dropping their
441
523
  // schemas from model context) and add one client-executed tool_search tool
442
- // that BM25-discloses bounded matches. The mandatory OpenGeni tools stay
443
- // eager. Default ON so selected connector catalogues do not consume every
444
- // Codex turn's context. Operators may explicitly disable it for emergency
445
- // compatibility diagnosis.
524
+ // that BM25-discloses bounded matches. Only an exact session tool ref with
525
+ // `eager:true` stays on the startup path; mandatory selection alone does not
526
+ // imply eagerness. Default ON so selected connector catalogues do not consume
527
+ // every Codex turn's context. Operators may explicitly disable it for
528
+ // emergency compatibility diagnosis.
446
529
  // OPENGENI_CODEX_TOOL_SEARCH_ENABLED
447
530
  codexToolSearchEnabled: EnvBoolean.default(true),
448
531
  // Provider-neutral progressive disclosure for direct OpenAI/Azure native
@@ -673,6 +756,31 @@ var SettingsSchema = z.object({
673
756
  vercelProjectId: z.string().optional(),
674
757
  vercelTeamId: z.string().optional(),
675
758
  vercelRuntime: z.string().optional(),
759
+ // --- OpenSandbox (optional Kubernetes-native provisioned sandbox) ---
760
+ openSandboxBaseUrl: z.string().url().optional(),
761
+ openSandboxApiKey: z.string().min(1).optional(),
762
+ // Release and preview profiles must provide an immutable OCI digest. The
763
+ // adapter refuses tag-only references when this backend is active.
764
+ openSandboxImage: z.string().min(1).optional(),
765
+ // Renewable provider TTL is a leak/backstop clock, not OpenGeni's idle
766
+ // policy. The pinned server accepts a one-minute minimum; ordinary
767
+ // deployments default to one hour.
768
+ openSandboxTtlSeconds: z.coerce.number().int().min(60).max(86400).default(3600),
769
+ openSandboxUseServerProxy: EnvBoolean.default(true),
770
+ // Channel B (browserd / noVNC / ttyd) uses OSEP-0011 signed URI-mode ingress.
771
+ // Exec/files stay on the private lifecycle server-proxy regardless of this flag.
772
+ openSandboxSignedEndpoints: EnvBoolean.default(false),
773
+ openSandboxSignedEndpointTtlSeconds: z.coerce.number().int().min(60).max(3600).default(600),
774
+ openSandboxChannelBPublicBaseUrl: z.string().url().optional(),
775
+ // Emergency hatch only: force JPEG/RFB through the API frame-proxy even when
776
+ // signed endpoints are on (M2 subprotocol failure). Unset means OpenSandbox
777
+ // uses the frame-proxy unless signed endpoints are on.
778
+ openSandboxInteractionFrameProxy: EnvBoolean.optional(),
779
+ openSandboxPoolRef: z.string().regex(/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/).optional(),
780
+ // Optional same-cluster, read-only observability projection. The application
781
+ // chart sets this only on the control worker and mounts a dedicated projected
782
+ // service-account token; non-Kubernetes and remote-provider deployments omit it.
783
+ openSandboxKubernetesInventoryNamespace: z.string().min(1).max(63).regex(/^[a-z0-9](?:[-a-z0-9]*[a-z0-9])?$/).optional(),
676
784
  // --- sandbox ownership inversion (P1.2 rollout flag, default OFF) ---
677
785
  // The keystone flag for the stateless resume-by-id model. When FALSE the
678
786
  // agent-turn path is BYTE-FOR-BYTE today's build-and-discard behavior (no
@@ -717,7 +825,7 @@ var SettingsSchema = z.object({
717
825
  // runner must ALSO advertise Capabilities.op_stream. Streaming is the default
718
826
  // because it is the only transport that can keep a command alive without an
719
827
  // arbitrary request/reply wall while still supporting replay and cancellation.
720
- // Older runners remain usable when an explicit positive exec timeout is set.
828
+ // Exec fails closed when the deployment or runner does not provide op-stream.
721
829
  // EnvBoolean (NOT
722
830
  // z.coerce.boolean(), which coerces "false" -> true).
723
831
  agentOpStreamEnabled: EnvBoolean.default(true),
@@ -749,9 +857,10 @@ var SettingsSchema = z.object({
749
857
  // nats-server is configured with AUTH CALLOUT: an external agent connects
750
858
  // presenting its `oge_` enrollment bearer as the connect auth-token; the server
751
859
  // issues an authorization request on $SYS.REQ.USER.AUTH to our responder, which
752
- // validates the bearer and returns a SIGNED NATS user JWT scoped to pub/sub ONLY
753
- // `agent.<ws>.>` (+ `_INBOX.>`). That per-subject scope IS the per-workspace
754
- // isolation. These are deployment-level secrets in the opengeni-runtime secret
860
+ // validates the bearer, claims one daemon generation, and returns a SIGNED NATS
861
+ // user JWT scoped to that exact process subtree (+ `_INBOX.>`). The exact scope
862
+ // provides both workspace isolation and single-daemon routing authority. These
863
+ // are deployment-level secrets in the opengeni-runtime secret
755
864
  // (Helm-clobbered configmap avoided), all OPTIONAL: when the callout plane is not
756
865
  // configured the responder simply does not start (selfhosted agents cannot
757
866
  // connect — graceful, never a boot-fail).
@@ -763,7 +872,7 @@ var SettingsSchema = z.object({
763
872
  // The TARGET ACCOUNT NAME the minted user is placed into (the server-config-mode
764
873
  // `auth_callout.account`, e.g. "APP"). The responder writes it as the minted user
765
874
  // JWT `aud` so nats-server binds the agent to this account — the SAME account the
766
- // privileged control plane connects into, so `agent.<ws>.<id>.rpc` request/reply
875
+ // privileged control plane connects into, so exact process request/reply
767
876
  // routes. Optional; resolveNatsCalloutConfig defaults it to "APP".
768
877
  selfhostedNatsCalloutAccountName: z.string().optional(),
769
878
  // The callout RESPONDER's own NATS login (one of the `auth_callout.auth_users`
@@ -772,7 +881,7 @@ var SettingsSchema = z.object({
772
881
  selfhostedNatsCalloutUser: z.string().optional(),
773
882
  selfhostedNatsCalloutPassword: z.string().optional(),
774
883
  // The PRIVILEGED control-plane login (api/worker): a static account user that may
775
- // request `agent.*.rpc` + receive its inbox replies. The event bus + the
884
+ // request exact process RPC subjects + receive their inbox replies. The event bus + the
776
885
  // selfhosted control RPC ride THIS connection. Username/password; when unset the
777
886
  // bus connects anonymously (local dev / a NATS with no auth_callout).
778
887
  selfhostedNatsControlUser: z.string().optional(),
@@ -851,6 +960,17 @@ var SettingsSchema = z.object({
851
960
  // (a liveness/reaper cadence), this bounds how long one turn waits for capacity
852
961
  // or provider creation before surfacing a clear turn.failed error.
853
962
  sandboxWarmingTimeoutMs: z.coerce.number().int().positive().default(6e5),
963
+ // Request-scoped workspace control-prefix budget: how long one HTTP-originated
964
+ // session/workspace mutation (Send, Steer, Pause/Resume/Cancel, queue
965
+ // move/edit/delete, composer draft, settings narrowing, quiescent tree
966
+ // deletion) may wait to enter the fair `workspace_inference_controls` prefix
967
+ // before failing with the retryable 503 `WORKSPACE_CONTROL_BUSY`. Worker
968
+ // settlement and claims never use it. The API installs the validated value
969
+ // into @opengeni/db once at app construction; nothing reads the env per
970
+ // request. Env: OPENGENI_WORKSPACE_CONTROL_LOCK_TIMEOUT_MS. Default 20 s.
971
+ workspaceControlLockTimeoutMs: z.coerce.number({
972
+ message: "OPENGENI_WORKSPACE_CONTROL_LOCK_TIMEOUT_MS must be a positive integer (ms)"
973
+ }).int("OPENGENI_WORKSPACE_CONTROL_LOCK_TIMEOUT_MS must be a positive integer (ms)").positive("OPENGENI_WORKSPACE_CONTROL_LOCK_TIMEOUT_MS must be a positive integer (ms)").default(2e4),
854
974
  // Rig setup-script budget (M3): the wall-clock timeout the rig-setup lifecycle
855
975
  // hook runs its script under, distinct from the 120s per-command lifecycle
856
976
  // default (a rig may compile/install heavy tooling on first cold create).
@@ -908,6 +1028,11 @@ var SettingsSchema = z.object({
908
1028
  githubAppId: z.string().optional(),
909
1029
  githubClientId: z.string().optional(),
910
1030
  githubClientSecret: z.string().optional(),
1031
+ /** Default-off rollout for the in-process GitHub repository API tool surface. */
1032
+ githubRestMcpEnabled: EnvBoolean.default(false),
1033
+ githubPersonalOauthEnabled: EnvBoolean.default(false),
1034
+ githubPersonalOauthClientId: z.string().optional(),
1035
+ githubPersonalOauthClientSecret: z.string().optional(),
911
1036
  githubAppSlug: z.string().optional(),
912
1037
  githubWebhookSecret: z.string().optional(),
913
1038
  githubAppPrivateKey: z.string().optional(),
@@ -942,6 +1067,46 @@ var SettingsSchema = z.object({
942
1067
  })
943
1068
  ).default([])
944
1069
  });
1070
+ function configuredGoogleDriveSyncLimits(settings) {
1071
+ return KnowledgeSourceSyncLimits.parse({
1072
+ maxItems: settings.googleDriveSyncMaxItems,
1073
+ maxBytes: settings.googleDriveSyncMaxBytes,
1074
+ maxFileBytes: settings.googleDriveSyncMaxFileBytes,
1075
+ maxProviderRequests: settings.googleDriveSyncMaxProviderRequests,
1076
+ maxElapsedSeconds: settings.googleDriveSyncMaxElapsedSeconds,
1077
+ maxFailureDetails: settings.googleDriveSyncMaxFailureDetails
1078
+ });
1079
+ }
1080
+ function googleDriveProviderRetryOptions(settings) {
1081
+ return {
1082
+ requestTimeoutMs: settings.googleDriveProviderRequestTimeoutMs,
1083
+ attempts: settings.googleDriveProviderRetryAttempts,
1084
+ initialDelayMs: settings.googleDriveProviderRetryInitialDelayMs,
1085
+ maxDelayMs: settings.googleDriveProviderRetryMaxDelayMs,
1086
+ budgetMs: settings.googleDriveProviderRetryBudgetMs
1087
+ };
1088
+ }
1089
+ function canonicalPublicOrigin(publicBaseUrl) {
1090
+ if (!publicBaseUrl) return null;
1091
+ let parsed;
1092
+ try {
1093
+ parsed = new URL(publicBaseUrl);
1094
+ } catch {
1095
+ return null;
1096
+ }
1097
+ if (!["http:", "https:"].includes(parsed.protocol) || parsed.username || parsed.password || parsed.search || parsed.hash || parsed.pathname !== "" && parsed.pathname !== "/") {
1098
+ return null;
1099
+ }
1100
+ return parsed.origin;
1101
+ }
1102
+ function googleDriveOAuthCallbackUrl(publicBaseUrl) {
1103
+ const origin = canonicalPublicOrigin(publicBaseUrl);
1104
+ return origin ? `${origin}/v1/integrations/google-drive/callback` : null;
1105
+ }
1106
+ function personalGitHubOAuthCallbackUrl(publicBaseUrl) {
1107
+ const origin = canonicalPublicOrigin(publicBaseUrl);
1108
+ return origin ? `${origin}/v1/integrations/github-personal/oauth/callback` : null;
1109
+ }
945
1110
  function isUsableVoiceInputSecret(value) {
946
1111
  if (value == null) return false;
947
1112
  const trimmed = value.trim();
@@ -1157,8 +1322,10 @@ var ModelCapabilitiesV1Schema = z.object({
1157
1322
  }
1158
1323
  });
1159
1324
  var ModelProviderApi = z.enum(["responses", "chat"]);
1325
+ var ModelProviderWireProfile = z.enum(["openai", "azure-openai"]);
1160
1326
  var RegistryProviderKind = z.enum([
1161
1327
  "api-key",
1328
+ "anonymous",
1162
1329
  "codex-subscription",
1163
1330
  "xai-subscription",
1164
1331
  "vercel-gateway-managed",
@@ -1213,6 +1380,7 @@ var RegistryProviderSchema = z.object({
1213
1380
  // stable provider id, e.g. "fireworks"
1214
1381
  label: z.string().min(1).optional(),
1215
1382
  api: ModelProviderApi.default("chat"),
1383
+ wireProfile: ModelProviderWireProfile.default("openai"),
1216
1384
  baseUrl: z.string().url(),
1217
1385
  apiKey: z.string().optional(),
1218
1386
  // inline key (pragmatic) ...
@@ -1227,6 +1395,52 @@ var RegistryProviderSchema = z.object({
1227
1395
  credentialSource: z.never().optional(),
1228
1396
  billing: z.never().optional(),
1229
1397
  models: z.array(RegistryModelSchema).min(1)
1398
+ }).superRefine((provider, ctx) => {
1399
+ if (provider.kind !== "anonymous") {
1400
+ return;
1401
+ }
1402
+ if (provider.apiKey !== void 0) {
1403
+ ctx.addIssue({
1404
+ code: "custom",
1405
+ path: ["apiKey"],
1406
+ message: "anonymous providers must not declare apiKey"
1407
+ });
1408
+ }
1409
+ if (provider.apiKeyEnv !== void 0) {
1410
+ ctx.addIssue({
1411
+ code: "custom",
1412
+ path: ["apiKeyEnv"],
1413
+ message: "anonymous providers must not declare apiKeyEnv"
1414
+ });
1415
+ }
1416
+ if (provider.defaultHeaders !== void 0) {
1417
+ ctx.addIssue({
1418
+ code: "custom",
1419
+ path: ["defaultHeaders"],
1420
+ message: "anonymous providers must not declare defaultHeaders"
1421
+ });
1422
+ }
1423
+ if (provider.defaultQuery !== void 0) {
1424
+ ctx.addIssue({
1425
+ code: "custom",
1426
+ path: ["defaultQuery"],
1427
+ message: "anonymous providers must not declare defaultQuery"
1428
+ });
1429
+ }
1430
+ if (provider.publicDefaultHeaderNames !== void 0) {
1431
+ ctx.addIssue({
1432
+ code: "custom",
1433
+ path: ["publicDefaultHeaderNames"],
1434
+ message: "anonymous providers must not declare publicDefaultHeaderNames"
1435
+ });
1436
+ }
1437
+ if (provider.publicDefaultQueryNames !== void 0) {
1438
+ ctx.addIssue({
1439
+ code: "custom",
1440
+ path: ["publicDefaultQueryNames"],
1441
+ message: "anonymous providers must not declare publicDefaultQueryNames"
1442
+ });
1443
+ }
1230
1444
  });
1231
1445
  var IntegrationOAuthClientConfigSchema = z.object({
1232
1446
  clientId: z.string().min(1),
@@ -1410,6 +1624,11 @@ var SANDBOX_REQUIRED_ENV = {
1410
1624
  { field: "vercelToken", env: "OPENGENI_VERCEL_TOKEN" },
1411
1625
  { field: "vercelProjectId", env: "OPENGENI_VERCEL_PROJECT_ID" }
1412
1626
  ],
1627
+ opensandbox: [
1628
+ { field: "openSandboxBaseUrl", env: "OPENGENI_OPENSANDBOX_BASE_URL" },
1629
+ { field: "openSandboxApiKey", env: "OPENGENI_OPENSANDBOX_API_KEY" },
1630
+ { field: "openSandboxImage", env: "OPENGENI_OPENSANDBOX_IMAGE" }
1631
+ ],
1413
1632
  // selfhosted needs NO per-box credentials: it is the user's own machine reached
1414
1633
  // over the agent's own enrollment. The enrollment-signing + relay-token secrets
1415
1634
  // are deployment-level (a single runtime secret, not per-active-backend creds),
@@ -1419,6 +1638,28 @@ var SANDBOX_REQUIRED_ENV = {
1419
1638
  function requiredSandboxEnvForBackend(backend) {
1420
1639
  return (SANDBOX_REQUIRED_ENV[backend] ?? []).map((entry) => entry.env);
1421
1640
  }
1641
+ function objectStorageConfiguredForWorkspaceArchives(settings) {
1642
+ switch (settings.objectStorageBackend) {
1643
+ case "azure-blob":
1644
+ return Boolean(
1645
+ settings.objectStorageAzureConnectionString || settings.objectStorageAzureAccountName && settings.objectStorageAzureAccountKey
1646
+ );
1647
+ case "gcs":
1648
+ return Boolean(
1649
+ settings.objectStorageGcsCredentialsJson || settings.objectStorageGcsKeyFilename || settings.objectStorageGcsProjectId
1650
+ );
1651
+ case "aws-s3":
1652
+ return true;
1653
+ case "s3-compatible":
1654
+ return Boolean(
1655
+ settings.objectStorageEndpoint && settings.objectStorageAccessKeyId && settings.objectStorageSecretAccessKey
1656
+ );
1657
+ default: {
1658
+ const _exhaustive = settings.objectStorageBackend;
1659
+ return _exhaustive;
1660
+ }
1661
+ }
1662
+ }
1422
1663
  function optional(name) {
1423
1664
  const value = process.env[name];
1424
1665
  return value && value.trim().length > 0 ? value : void 0;
@@ -1473,6 +1714,9 @@ function getSettings() {
1473
1714
  agentStableVersion: optional("OPENGENI_AGENT_STABLE_VERSION"),
1474
1715
  agentBetaVersion: optional("OPENGENI_AGENT_BETA_VERSION"),
1475
1716
  productAccessMode: optional("OPENGENI_PRODUCT_ACCESS_MODE"),
1717
+ organizationTenancyCanonicalActivationEnabled: optional(
1718
+ "OPENGENI_ORGANIZATION_TENANCY_CANONICAL_ACTIVATION_ENABLED"
1719
+ ),
1476
1720
  billingMode: optional("OPENGENI_BILLING_MODE"),
1477
1721
  entitlementsMode: optional("OPENGENI_ENTITLEMENTS_MODE"),
1478
1722
  usageLimitsMode: optional("OPENGENI_USAGE_LIMITS_MODE"),
@@ -1483,7 +1727,6 @@ function getSettings() {
1483
1727
  allowedFirstPartyMcpTools: optional("OPENGENI_ALLOWED_FIRST_PARTY_MCP_TOOLS"),
1484
1728
  streamTokenSecret: optional("OPENGENI_STREAM_TOKEN_SECRET"),
1485
1729
  streamControlEnabled: optional("OPENGENI_STREAM_CONTROL_ENABLED"),
1486
- codemodeMaxCallsPerTurn: optional("OPENGENI_CODEMODE_MAX_CALLS_PER_TURN"),
1487
1730
  ogtoolPackageSpec: optional("OPENGENI_OGTOOL_PACKAGE_SPEC"),
1488
1731
  environmentsEncryptionKey: optional("OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY"),
1489
1732
  integrationsEnabled: optional("OPENGENI_INTEGRATIONS_ENABLED"),
@@ -1492,12 +1735,32 @@ function getSettings() {
1492
1735
  "OPENGENI_INTEGRATIONS_ALLOW_PRIVATE_NETWORK_TARGETS"
1493
1736
  ),
1494
1737
  integrationsOauthClientsJson: optional("OPENGENI_INTEGRATIONS_OAUTH_CLIENTS_JSON"),
1495
- gmailRestAdapterEnabled: optional("OPENGENI_GMAIL_REST_ADAPTER_ENABLED"),
1496
1738
  slackClientId: optional("OPENGENI_SLACK_CLIENT_ID"),
1497
1739
  slackClientSecret: optional("OPENGENI_SLACK_CLIENT_SECRET"),
1498
1740
  slackSigningSecret: optional("OPENGENI_SLACK_SIGNING_SECRET"),
1741
+ slackBotDisplayName: optional("OPENGENI_SLACK_BOT_DISPLAY_NAME"),
1742
+ slackCommand: optional("OPENGENI_SLACK_COMMAND"),
1499
1743
  googleDriveClientId: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_ID"),
1500
1744
  googleDriveClientSecret: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_SECRET"),
1745
+ googleDriveSyncMaxItems: optional("OPENGENI_GOOGLE_DRIVE_SYNC_MAX_ITEMS"),
1746
+ googleDriveSyncMaxBytes: optional("OPENGENI_GOOGLE_DRIVE_SYNC_MAX_BYTES"),
1747
+ googleDriveSyncMaxFileBytes: optional("OPENGENI_GOOGLE_DRIVE_SYNC_MAX_FILE_BYTES"),
1748
+ googleDriveSyncMaxProviderRequests: optional(
1749
+ "OPENGENI_GOOGLE_DRIVE_SYNC_MAX_PROVIDER_REQUESTS"
1750
+ ),
1751
+ googleDriveSyncMaxElapsedSeconds: optional("OPENGENI_GOOGLE_DRIVE_SYNC_MAX_ELAPSED_SECONDS"),
1752
+ googleDriveSyncMaxFailureDetails: optional("OPENGENI_GOOGLE_DRIVE_SYNC_MAX_FAILURE_DETAILS"),
1753
+ googleDriveProviderRequestTimeoutMs: optional(
1754
+ "OPENGENI_GOOGLE_DRIVE_PROVIDER_REQUEST_TIMEOUT_MS"
1755
+ ),
1756
+ googleDriveProviderRetryAttempts: optional("OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_ATTEMPTS"),
1757
+ googleDriveProviderRetryInitialDelayMs: optional(
1758
+ "OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_INITIAL_DELAY_MS"
1759
+ ),
1760
+ googleDriveProviderRetryMaxDelayMs: optional(
1761
+ "OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_MAX_DELAY_MS"
1762
+ ),
1763
+ googleDriveProviderRetryBudgetMs: optional("OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_BUDGET_MS"),
1501
1764
  fikenClientId: optional("OPENGENI_FIKEN_OAUTH_CLIENT_ID"),
1502
1765
  fikenClientSecret: optional("OPENGENI_FIKEN_OAUTH_CLIENT_SECRET"),
1503
1766
  googleDriveWorkspaceEventsEnabled: optional("OPENGENI_GOOGLE_DRIVE_WORKSPACE_EVENTS_ENABLED"),
@@ -1506,7 +1769,10 @@ function getSettings() {
1506
1769
  maxNestedAgentDepth: optional("OPENGENI_MAX_NESTED_AGENT_DEPTH"),
1507
1770
  socialOauthClientsJson: optional("OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON"),
1508
1771
  goalMaxAutoContinuations: optional("OPENGENI_GOAL_MAX_AUTO_CONTINUATIONS"),
1509
- goalNoProgressLimit: optional("OPENGENI_GOAL_NO_PROGRESS_LIMIT"),
1772
+ goalIdleBackoffMs: optional("OPENGENI_GOAL_IDLE_BACKOFF_MS"),
1773
+ goalIdleBackoffMaxMs: optional("OPENGENI_GOAL_IDLE_BACKOFF_MAX_MS"),
1774
+ childLifecycleNoticesEnabled: optional("OPENGENI_CHILD_LIFECYCLE_NOTICES_ENABLED"),
1775
+ slackWorkspaceRoutingEnabled: optional("OPENGENI_SLACK_WORKSPACE_ROUTING_ENABLED"),
1510
1776
  agentMaxModelCallsPerTurn: optional("OPENGENI_AGENT_MAX_MODEL_CALLS_PER_TURN"),
1511
1777
  contextWindowTokens: optional("OPENGENI_CONTEXT_WINDOW_TOKENS"),
1512
1778
  contextEffectiveWindowTokens: optional("OPENGENI_CONTEXT_EFFECTIVE_WINDOW_TOKENS"),
@@ -1521,6 +1787,7 @@ function getSettings() {
1521
1787
  apiHost: optional("OPENGENI_API_HOST"),
1522
1788
  apiPort: optional("OPENGENI_API_PORT"),
1523
1789
  workerHttpPort: optional("OPENGENI_WORKER_HTTP_PORT"),
1790
+ opengeniMcpInternalUrl: optional("OPENGENI_MCP_INTERNAL_URL"),
1524
1791
  opengeniMcpUrl: optional("OPENGENI_MCP_URL"),
1525
1792
  corsAllowOriginRegex: optional("OPENGENI_CORS_ALLOW_ORIGIN_REGEX"),
1526
1793
  openaiProvider: optional("OPENGENI_OPENAI_PROVIDER"),
@@ -1577,6 +1844,9 @@ function getSettings() {
1577
1844
  modelProvidersJson: optional("OPENGENI_MODEL_PROVIDERS_JSON"),
1578
1845
  codexSubscriptionEnabled: optional("OPENGENI_CODEX_SUBSCRIPTION_ENABLED"),
1579
1846
  supergrokSubscriptionEnabled: optional("OPENGENI_SUPERGROK_SUBSCRIPTION_ENABLED"),
1847
+ supergrokResponseStreamIdleTimeoutMs: optional(
1848
+ "OPENGENI_SUPERGROK_RESPONSE_STREAM_IDLE_TIMEOUT_MS"
1849
+ ),
1580
1850
  codexConnectedAppsEnabled: optional("OPENGENI_CODEX_CONNECTED_APPS_ENABLED"),
1581
1851
  codexToolSearchEnabled: optional("OPENGENI_CODEX_TOOL_SEARCH_ENABLED"),
1582
1852
  lazyToolSearchEnabled: optional("OPENGENI_LAZY_TOOL_SEARCH_ENABLED"),
@@ -1666,6 +1936,21 @@ function getSettings() {
1666
1936
  vercelProjectId: optional("OPENGENI_VERCEL_PROJECT_ID"),
1667
1937
  vercelTeamId: optional("OPENGENI_VERCEL_TEAM_ID"),
1668
1938
  vercelRuntime: optional("OPENGENI_VERCEL_RUNTIME"),
1939
+ openSandboxBaseUrl: optional("OPENGENI_OPENSANDBOX_BASE_URL"),
1940
+ openSandboxApiKey: optional("OPENGENI_OPENSANDBOX_API_KEY"),
1941
+ openSandboxImage: optional("OPENGENI_OPENSANDBOX_IMAGE"),
1942
+ openSandboxTtlSeconds: optional("OPENGENI_OPENSANDBOX_TTL_SECONDS"),
1943
+ openSandboxUseServerProxy: optional("OPENGENI_OPENSANDBOX_USE_SERVER_PROXY"),
1944
+ openSandboxSignedEndpoints: optional("OPENGENI_OPENSANDBOX_SIGNED_ENDPOINTS"),
1945
+ openSandboxSignedEndpointTtlSeconds: optional(
1946
+ "OPENGENI_OPENSANDBOX_SIGNED_ENDPOINT_TTL_SECONDS"
1947
+ ),
1948
+ openSandboxChannelBPublicBaseUrl: optional("OPENGENI_OPENSANDBOX_CHANNEL_B_PUBLIC_BASE_URL"),
1949
+ openSandboxInteractionFrameProxy: optional("OPENGENI_OPENSANDBOX_INTERACTION_FRAME_PROXY"),
1950
+ openSandboxPoolRef: optional("OPENGENI_OPENSANDBOX_POOL_REF"),
1951
+ openSandboxKubernetesInventoryNamespace: optional(
1952
+ "OPENGENI_OPENSANDBOX_KUBERNETES_INVENTORY_NAMESPACE"
1953
+ ),
1669
1954
  sandboxOwnershipEnabled: optional("OPENGENI_SANDBOX_OWNERSHIP_ENABLED"),
1670
1955
  rigVerificationLeaseOwnershipEnabled: optional(
1671
1956
  "OPENGENI_RIG_VERIFICATION_LEASE_OWNERSHIP_ENABLED"
@@ -1697,6 +1982,7 @@ function getSettings() {
1697
1982
  sandboxLeaseTtlMs: optional("OPENGENI_SANDBOX_LEASE_TTL_MS"),
1698
1983
  sandboxLeaseWarmingTtlMs: optional("OPENGENI_SANDBOX_LEASE_WARMING_TTL_MS"),
1699
1984
  sandboxWarmingTimeoutMs: optional("OPENGENI_SANDBOX_WARMING_TIMEOUT_MS"),
1985
+ workspaceControlLockTimeoutMs: optional("OPENGENI_WORKSPACE_CONTROL_LOCK_TIMEOUT_MS"),
1700
1986
  rigSetupTimeoutMs: optional("OPENGENI_RIG_SETUP_TIMEOUT_MS"),
1701
1987
  sandboxWarmRateMicrosPerSecondJson: optional(
1702
1988
  "OPENGENI_SANDBOX_WARM_RATE_MICROS_PER_SECOND_JSON"
@@ -1743,6 +2029,10 @@ function getSettings() {
1743
2029
  githubAppId: optional("OPENGENI_GITHUB_APP_ID"),
1744
2030
  githubClientId: optional("OPENGENI_GITHUB_CLIENT_ID"),
1745
2031
  githubClientSecret: optional("OPENGENI_GITHUB_CLIENT_SECRET"),
2032
+ githubRestMcpEnabled: optional("OPENGENI_GITHUB_REST_MCP_ENABLED"),
2033
+ githubPersonalOauthEnabled: optional("OPENGENI_GITHUB_PERSONAL_OAUTH_ENABLED"),
2034
+ githubPersonalOauthClientId: optional("OPENGENI_GITHUB_PERSONAL_OAUTH_CLIENT_ID"),
2035
+ githubPersonalOauthClientSecret: optional("OPENGENI_GITHUB_PERSONAL_OAUTH_CLIENT_SECRET"),
1746
2036
  githubAppSlug: optional("OPENGENI_GITHUB_APP_SLUG"),
1747
2037
  githubWebhookSecret: optional("OPENGENI_GITHUB_WEBHOOK_SECRET"),
1748
2038
  githubAppPrivateKey: optional("OPENGENI_GITHUB_APP_PRIVATE_KEY"),
@@ -1761,8 +2051,8 @@ function getSettings() {
1761
2051
  const parsed = SettingsSchema.parse(raw);
1762
2052
  const settings = {
1763
2053
  ...parsed,
1764
- sandboxIdleGraceMs: raw.sandboxIdleGraceMs === void 0 ? Math.min(9e5, Math.floor(parsed.modalTimeoutSeconds * 1e3 / 2)) : parsed.sandboxIdleGraceMs,
1765
- sandboxRotationLeadMs: raw.sandboxRotationLeadMs === void 0 ? Math.min(36e5, Math.floor(parsed.modalTimeoutSeconds * 1e3 / 2)) : parsed.sandboxRotationLeadMs,
2054
+ sandboxIdleGraceMs: raw.sandboxIdleGraceMs === void 0 && parsed.sandboxBackend === "modal" ? Math.min(9e5, Math.floor(parsed.modalTimeoutSeconds * 1e3 / 2)) : parsed.sandboxIdleGraceMs,
2055
+ sandboxRotationLeadMs: raw.sandboxRotationLeadMs === void 0 && parsed.sandboxBackend === "modal" ? Math.min(36e5, Math.floor(parsed.modalTimeoutSeconds * 1e3 / 2)) : parsed.sandboxRotationLeadMs,
1766
2056
  mcpServers: ensureBuiltInMcpServers(parsed)
1767
2057
  };
1768
2058
  validateSettings(settings);
@@ -1795,6 +2085,30 @@ function allowedFirstPartyMcpToolsForSession(settings, selected) {
1795
2085
  function effectiveModalIdleTimeoutSeconds(settings) {
1796
2086
  return settings.modalIdleTimeoutSeconds ?? settings.modalTimeoutSeconds;
1797
2087
  }
2088
+ function effectiveSandboxLifecycle(settings, backend = settings.sandboxBackend) {
2089
+ if (backend === "modal") {
2090
+ return {
2091
+ hardLifetimeMs: settings.modalTimeoutSeconds * 1e3,
2092
+ renewableTtlSeconds: null,
2093
+ providerIdleTimeoutMs: effectiveModalIdleTimeoutSeconds(settings) * 1e3,
2094
+ rotationLeadMs: settings.sandboxRotationLeadMs
2095
+ };
2096
+ }
2097
+ if (backend === "opensandbox") {
2098
+ return {
2099
+ hardLifetimeMs: null,
2100
+ renewableTtlSeconds: settings.openSandboxTtlSeconds,
2101
+ providerIdleTimeoutMs: null,
2102
+ rotationLeadMs: null
2103
+ };
2104
+ }
2105
+ return {
2106
+ hardLifetimeMs: CAPABILITY_DESCRIPTORS[backend].lifetime.hardLifetimeMs ?? null,
2107
+ renewableTtlSeconds: null,
2108
+ providerIdleTimeoutMs: null,
2109
+ rotationLeadMs: null
2110
+ };
2111
+ }
1798
2112
  function sandboxArchiveCaptureTimeoutMs(settings) {
1799
2113
  return Math.min(
1800
2114
  SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS,
@@ -2118,6 +2432,7 @@ function gatewayRegistryProvider(settings, input) {
2118
2432
  // Model-specific compatibility stays at the reviewed request fence rather
2119
2433
  // than downgrading the whole provider wire.
2120
2434
  api: "responses",
2435
+ wireProfile: "openai",
2121
2436
  baseUrl: VERCEL_AI_GATEWAY_BASE_URL,
2122
2437
  ...input.apiKey ? { apiKey: input.apiKey } : {},
2123
2438
  models
@@ -2198,8 +2513,22 @@ function productShortLabelForModelId(modelId) {
2198
2513
  return null;
2199
2514
  }
2200
2515
  }
2516
+ var BUILTIN_GPT56_MODEL_IDS = ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"];
2517
+ function isBuiltinGpt56ModelId(modelId) {
2518
+ return BUILTIN_GPT56_MODEL_IDS.includes(modelId);
2519
+ }
2520
+ function builtinContextLimitsForModel(settings, modelId) {
2521
+ if (isBuiltinGpt56ModelId(modelId)) {
2522
+ return {
2523
+ contextWindowTokens: CODEX_MODEL_CONTEXT_WINDOW_TOKENS,
2524
+ effectiveContextWindowTokens: CODEX_MODEL_EFFECTIVE_CONTEXT_WINDOW_TOKENS,
2525
+ autoCompactTokenLimit: CODEX_MODEL_AUTO_COMPACT_TOKEN_LIMIT
2526
+ };
2527
+ }
2528
+ return { contextWindowTokens: settings.contextWindowTokens };
2529
+ }
2201
2530
  function builtinLatencyModesForModel(modelId) {
2202
- if (modelId === "gpt-5.6-sol" || modelId === "gpt-5.6-terra" || modelId === "gpt-5.6-luna" || modelId.startsWith("codex/gpt-5.6-")) {
2531
+ if (isBuiltinGpt56ModelId(modelId) || modelId.startsWith("codex/gpt-5.6-")) {
2203
2532
  return [
2204
2533
  { id: "standard", upstream: "supported", runnable: true },
2205
2534
  {
@@ -2217,7 +2546,7 @@ function builtinPromptCachingForModel(modelId) {
2217
2546
  return slug.startsWith("gpt-5.6-") ? { upstream: "supported", runnable: true, mode: "implicit" } : void 0;
2218
2547
  }
2219
2548
  function builtinHostedImageGenerationForModel(settings, modelId) {
2220
- return settings.openaiProvider === "openai" && isDirectOpenAiApiBaseUrl(settings.openaiBaseUrl) && ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"].includes(modelId);
2549
+ return settings.openaiProvider === "openai" && isDirectOpenAiApiBaseUrl(settings.openaiBaseUrl) && isBuiltinGpt56ModelId(modelId);
2221
2550
  }
2222
2551
  function isDirectOpenAiApiBaseUrl(baseUrl) {
2223
2552
  if (baseUrl === void 0) return true;
@@ -2262,6 +2591,9 @@ function assertLatencyModeRunnable(settings, modelId, latencyMode) {
2262
2591
  }
2263
2592
  }
2264
2593
  function registryCredentialSource(provider) {
2594
+ if (provider.kind === "anonymous") {
2595
+ return { kind: "deployment", mechanism: "none" };
2596
+ }
2265
2597
  if (provider.kind === "codex-subscription") {
2266
2598
  return { kind: "connected_subscription", provider: "codex" };
2267
2599
  }
@@ -2274,6 +2606,9 @@ function registryCredentialSource(provider) {
2274
2606
  return { kind: "deployment", mechanism: "api_key" };
2275
2607
  }
2276
2608
  function registryBilling(provider) {
2609
+ if (provider.kind === "anonymous") {
2610
+ return { upstreamPayer: "deployment", metering: "external" };
2611
+ }
2277
2612
  if (provider.kind === "codex-subscription" || provider.kind === "xai-subscription") {
2278
2613
  return { upstreamPayer: "connected_subscription", metering: "external" };
2279
2614
  }
@@ -2329,6 +2664,7 @@ function definitionVersionFor(model, provider) {
2329
2664
  provider: {
2330
2665
  adapterKind: provider.kind,
2331
2666
  wireApi: provider.api,
2667
+ wireProfile: provider.wireProfile,
2332
2668
  baseUrl: provider.baseUrl ?? null,
2333
2669
  defaultHeaders: requestMetadata.headers,
2334
2670
  defaultQuery: requestMetadata.query
@@ -2355,6 +2691,7 @@ function configuredProviders(settings) {
2355
2691
  label: builtinProviderLabel(settings),
2356
2692
  kind: "api-key",
2357
2693
  api: "responses",
2694
+ wireProfile: settings.openaiProvider === "azure" ? "azure-openai" : "openai",
2358
2695
  builtin: true,
2359
2696
  credentialSource,
2360
2697
  billing: { upstreamPayer: "deployment", metering: "opengeni_credits" }
@@ -2373,6 +2710,7 @@ function configuredProviders(settings) {
2373
2710
  label: provider.label ?? provider.id,
2374
2711
  kind: provider.kind,
2375
2712
  api: provider.api,
2713
+ wireProfile: provider.wireProfile,
2376
2714
  builtin: false,
2377
2715
  baseUrl: provider.baseUrl,
2378
2716
  apiKey: resolveProviderApiKey(provider),
@@ -2396,6 +2734,7 @@ function withCodexCatalogProvider(settings) {
2396
2734
  id: CODEX_PROVIDER_ID,
2397
2735
  label: "Codex (ChatGPT subscription)",
2398
2736
  api: "responses",
2737
+ wireProfile: "openai",
2399
2738
  baseUrl: CODEX_PROVIDER_BASE_URL,
2400
2739
  models: CODEX_FALLBACK_MODEL_SLUGS.map((slug) => {
2401
2740
  const capabilities = {
@@ -2443,11 +2782,13 @@ function withXaiSubscriptionCatalogProvider(settings) {
2443
2782
  id: XAI_SUBSCRIPTION_PROVIDER_ID,
2444
2783
  label: "SuperGrok (xAI subscription)",
2445
2784
  api: "responses",
2785
+ wireProfile: "openai",
2446
2786
  baseUrl: XAI_SUBSCRIPTION_PROXY_BASE_URL,
2447
2787
  models: XAI_SUBSCRIPTION_MODEL_SLUGS.map((slug) => {
2448
2788
  const capabilities = legacyModelCapabilities(settings, {
2449
2789
  reasoningEffort: true,
2450
- hostedWebSearch: true
2790
+ hostedWebSearch: true,
2791
+ vision: true
2451
2792
  });
2452
2793
  capabilities.reasoning.efforts = ["low", "medium", "high", "xhigh"];
2453
2794
  capabilities.reasoning.defaultEffort = "high";
@@ -2586,7 +2927,7 @@ function configuredModels(settings) {
2586
2927
  billing: builtinProvider.billing,
2587
2928
  capabilities,
2588
2929
  ...pricingSchedules[id] === void 0 ? {} : { pricing: pricingSchedules[id] },
2589
- contextWindowTokens: settings.contextWindowTokens,
2930
+ ...builtinContextLimitsForModel(settings, id),
2590
2931
  toolOutputTruncationTokens: settings.modelToolOutputTruncationTokens,
2591
2932
  reasoningEffort: capabilities.reasoning.runnable,
2592
2933
  hostedWebSearch: capabilities.hostedTools.webSearch.runnable
@@ -3410,8 +3751,10 @@ function ensureBuiltInMcpServers(settings) {
3410
3751
  function firstPartyMcpBaseUrl(settings) {
3411
3752
  return settings.opengeniMcpUrl ?? `http://127.0.0.1:${settings.apiPort}/v1/workspaces/{workspaceId}/mcp`;
3412
3753
  }
3413
- function firstPartyMcpWorkspaceUrl(settings, workspaceId) {
3414
- const raw = firstPartyMcpBaseUrl(settings);
3754
+ function firstPartyMcpInternalBaseUrl(settings) {
3755
+ return settings.opengeniMcpInternalUrl ?? `http://127.0.0.1:${settings.apiPort}/v1/workspaces/{workspaceId}/mcp`;
3756
+ }
3757
+ function scopedFirstPartyMcpUrl(raw, workspaceId) {
3415
3758
  if (raw.includes("{workspaceId}")) {
3416
3759
  return raw.replaceAll("{workspaceId}", workspaceId);
3417
3760
  }
@@ -3421,6 +3764,12 @@ function firstPartyMcpWorkspaceUrl(settings, workspaceId) {
3421
3764
  url.hash = "";
3422
3765
  return url.toString();
3423
3766
  }
3767
+ function firstPartyMcpWorkspaceUrl(settings, workspaceId) {
3768
+ return scopedFirstPartyMcpUrl(firstPartyMcpBaseUrl(settings), workspaceId);
3769
+ }
3770
+ function firstPartyMcpInternalWorkspaceUrl(settings, workspaceId) {
3771
+ return scopedFirstPartyMcpUrl(firstPartyMcpInternalBaseUrl(settings), workspaceId);
3772
+ }
3424
3773
  function codemodeWorkspaceUrl(settings, workspaceId) {
3425
3774
  if (settings.opengeniMcpUrl) {
3426
3775
  const url2 = new URL(firstPartyMcpWorkspaceUrl(settings, workspaceId));
@@ -3446,8 +3795,18 @@ function firstPartyDocumentsMcpServerUrl(mcpUrl) {
3446
3795
  function firstPartyFilesMcpServerUrl(mcpUrl) {
3447
3796
  return `${mcpUrl.replace(/\/+$/, "")}/files`;
3448
3797
  }
3798
+ var MODAL_DESKTOP_IMAGE_DIGEST_REF = /@sha256:[0-9a-f]{64}$/i;
3799
+ function isDigestPinnedModalDesktopImage(settings) {
3800
+ if (settings.modalImageId) return true;
3801
+ return typeof settings.modalImageRef === "string" && MODAL_DESKTOP_IMAGE_DIGEST_REF.test(settings.modalImageRef);
3802
+ }
3449
3803
  function validateSettings(settings) {
3450
3804
  temporalConnectionOptions(settings);
3805
+ if (settings.goalIdleBackoffMs.some((delayMs) => delayMs > settings.goalIdleBackoffMaxMs)) {
3806
+ throw new Error(
3807
+ `OPENGENI_GOAL_IDLE_BACKOFF_MS entries must not exceed OPENGENI_GOAL_IDLE_BACKOFF_MAX_MS (${settings.goalIdleBackoffMaxMs})`
3808
+ );
3809
+ }
3451
3810
  const allowedFirstPartyMcpTools = new Set(
3452
3811
  settings.allowedFirstPartyMcpTools ?? FIRST_PARTY_MCP_TOOL_NAMES
3453
3812
  );
@@ -3529,6 +3888,53 @@ function validateSettings(settings) {
3529
3888
  "OPENGENI_GOOGLE_DRIVE_CLIENT_ID and OPENGENI_GOOGLE_DRIVE_CLIENT_SECRET must be configured together"
3530
3889
  );
3531
3890
  }
3891
+ if (Boolean(settings.githubPersonalOauthClientId) !== Boolean(settings.githubPersonalOauthClientSecret)) {
3892
+ throw new Error(
3893
+ "OPENGENI_GITHUB_PERSONAL_OAUTH_CLIENT_ID and OPENGENI_GITHUB_PERSONAL_OAUTH_CLIENT_SECRET must be configured together"
3894
+ );
3895
+ }
3896
+ if (settings.githubPersonalOauthEnabled) {
3897
+ if (!settings.integrationsEnabled) {
3898
+ throw new Error(
3899
+ "OPENGENI_INTEGRATIONS_ENABLED=true is required when personal GitHub OAuth is enabled"
3900
+ );
3901
+ }
3902
+ if (settings.productAccessMode !== "managed") {
3903
+ throw new Error(
3904
+ "OPENGENI_GITHUB_PERSONAL_OAUTH_ENABLED=true requires OPENGENI_PRODUCT_ACCESS_MODE=managed"
3905
+ );
3906
+ }
3907
+ if (!settings.githubPersonalOauthClientId || !settings.githubPersonalOauthClientSecret) {
3908
+ throw new Error(
3909
+ "personal GitHub OAuth requires OPENGENI_GITHUB_PERSONAL_OAUTH_CLIENT_ID and OPENGENI_GITHUB_PERSONAL_OAUTH_CLIENT_SECRET"
3910
+ );
3911
+ }
3912
+ if (settings.githubPersonalOauthClientId === settings.githubClientId) {
3913
+ throw new Error(
3914
+ "personal GitHub OAuth must use a different OAuth App client from the OpenGeni GitHub App"
3915
+ );
3916
+ }
3917
+ if (!personalGitHubOAuthCallbackUrl(settings.publicBaseUrl)) {
3918
+ throw new Error(
3919
+ "OPENGENI_PUBLIC_BASE_URL must be a credential-free origin without a path, query, or fragment when personal GitHub OAuth is enabled"
3920
+ );
3921
+ }
3922
+ if (!settings.publicBaseUrl?.startsWith("https://") && !["local", "test"].includes(settings.environment)) {
3923
+ throw new Error(
3924
+ "OPENGENI_PUBLIC_BASE_URL must use https when personal GitHub OAuth is enabled outside local/test"
3925
+ );
3926
+ }
3927
+ if (!settings.integrationsStateSecret) {
3928
+ throw new Error(
3929
+ "OPENGENI_INTEGRATIONS_STATE_SECRET is required when personal GitHub OAuth is enabled"
3930
+ );
3931
+ }
3932
+ if (!settings.environmentsEncryptionKey) {
3933
+ throw new Error(
3934
+ "OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY is required when personal GitHub OAuth is enabled"
3935
+ );
3936
+ }
3937
+ }
3532
3938
  if (Boolean(settings.fikenClientId) !== Boolean(settings.fikenClientSecret)) {
3533
3939
  throw new Error(
3534
3940
  "OPENGENI_FIKEN_OAUTH_CLIENT_ID and OPENGENI_FIKEN_OAUTH_CLIENT_SECRET must be configured together"
@@ -3552,11 +3958,21 @@ function validateSettings(settings) {
3552
3958
  }
3553
3959
  }
3554
3960
  if (settings.googleDriveClientId) {
3961
+ if (!settings.integrationsEnabled) {
3962
+ throw new Error(
3963
+ "OPENGENI_INTEGRATIONS_ENABLED=true is required when the Google Drive integration is configured"
3964
+ );
3965
+ }
3555
3966
  if (!settings.publicBaseUrl) {
3556
3967
  throw new Error(
3557
3968
  "OPENGENI_PUBLIC_BASE_URL is required when the Google Drive integration is configured"
3558
3969
  );
3559
3970
  }
3971
+ if (!googleDriveOAuthCallbackUrl(settings.publicBaseUrl)) {
3972
+ throw new Error(
3973
+ "OPENGENI_PUBLIC_BASE_URL must be a credential-free origin without a path, query, or fragment when the Google Drive integration is configured"
3974
+ );
3975
+ }
3560
3976
  if (!settings.publicBaseUrl.startsWith("https://") && !["local", "test"].includes(settings.environment)) {
3561
3977
  throw new Error(
3562
3978
  "OPENGENI_PUBLIC_BASE_URL must use https when the Google Drive integration is configured outside local/test"
@@ -3568,6 +3984,21 @@ function validateSettings(settings) {
3568
3984
  );
3569
3985
  }
3570
3986
  }
3987
+ if (settings.googleDriveSyncMaxFileBytes > settings.googleDriveSyncMaxBytes) {
3988
+ throw new Error(
3989
+ "OPENGENI_GOOGLE_DRIVE_SYNC_MAX_FILE_BYTES must not exceed OPENGENI_GOOGLE_DRIVE_SYNC_MAX_BYTES"
3990
+ );
3991
+ }
3992
+ if (settings.googleDriveProviderRetryInitialDelayMs > settings.googleDriveProviderRetryMaxDelayMs) {
3993
+ throw new Error(
3994
+ "OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_INITIAL_DELAY_MS must not exceed OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_MAX_DELAY_MS"
3995
+ );
3996
+ }
3997
+ if (settings.googleDriveProviderRetryInitialDelayMs > settings.googleDriveProviderRetryBudgetMs) {
3998
+ throw new Error(
3999
+ "OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_INITIAL_DELAY_MS must not exceed OPENGENI_GOOGLE_DRIVE_PROVIDER_RETRY_BUDGET_MS"
4000
+ );
4001
+ }
3571
4002
  if (Boolean(settings.atlassianClientId) !== Boolean(settings.atlassianClientSecret)) {
3572
4003
  throw new Error(
3573
4004
  "OPENGENI_ATLASSIAN_CLIENT_ID and OPENGENI_ATLASSIAN_CLIENT_SECRET must be configured together"
@@ -3731,6 +4162,18 @@ function validateSettings(settings) {
3731
4162
  sandboxEnvironmentVariableNames(settings);
3732
4163
  sandboxLifecycleHookIds(settings);
3733
4164
  parseSandboxWarmRateJson(settings.sandboxWarmRateMicrosPerSecondJson);
4165
+ if (settings.sandboxBackend === "opensandbox") {
4166
+ if (!/@sha256:[0-9a-f]{64}$/i.test(settings.openSandboxImage ?? "")) {
4167
+ throw new Error(
4168
+ "OPENGENI_OPENSANDBOX_IMAGE must be an immutable OCI reference ending in @sha256:<64 hex characters>"
4169
+ );
4170
+ }
4171
+ if (!objectStorageConfiguredForWorkspaceArchives(settings)) {
4172
+ throw new Error(
4173
+ "OPENGENI_SANDBOX_BACKEND=opensandbox requires configured object storage for portable /workspace archives"
4174
+ );
4175
+ }
4176
+ }
3734
4177
  const serverIds = /* @__PURE__ */ new Set();
3735
4178
  for (const server of settings.mcpServers) {
3736
4179
  if (serverIds.has(server.id)) {
@@ -3742,10 +4185,6 @@ function validateSettings(settings) {
3742
4185
  const reaperPeriod = settings.sandboxLeaseReaperPeriodMs;
3743
4186
  const viewerTtl = settings.sandboxViewerHolderTtlMs;
3744
4187
  const interactionTtl = settings.sandboxInteractionHolderTtlMs;
3745
- const idleGraceMs = settings.sandboxIdleGraceMs;
3746
- const providerLifetimeMs = settings.modalTimeoutSeconds * 1e3;
3747
- const rotationLeadMs = settings.sandboxRotationLeadMs;
3748
- const idleTimeoutMs = effectiveModalIdleTimeoutSeconds(settings) * 1e3;
3749
4188
  if (!(reaperPeriod < viewerTtl)) {
3750
4189
  throw new Error(
3751
4190
  `OPENGENI_SANDBOX_LEASE_REAPER_PERIOD_MS (${reaperPeriod}) must be strictly less than OPENGENI_SANDBOX_VIEWER_HOLDER_TTL_MS (${viewerTtl}): the reaper must run more often than the TTL it polices, or stale viewer holders outlive a full reaper period.`
@@ -3756,35 +4195,49 @@ function validateSettings(settings) {
3756
4195
  `OPENGENI_SANDBOX_LEASE_REAPER_PERIOD_MS (${reaperPeriod}) must be strictly less than OPENGENI_SANDBOX_INTERACTION_HOLDER_TTL_MS (${interactionTtl}): the reaper must run more often than the controller-heartbeat horizon.`
3757
4196
  );
3758
4197
  }
3759
- if (!(idleTimeoutMs <= providerLifetimeMs)) {
3760
- throw new Error(
3761
- `OPENGENI_MODAL_IDLE_TIMEOUT_SECONDS*1000 (${idleTimeoutMs}) must not exceed the hard provider lifetime (OPENGENI_MODAL_TIMEOUT_SECONDS*1000 = ${providerLifetimeMs}): the idle timeout is a floor under the hard lifetime, not above it.`
3762
- );
3763
- }
3764
- if (!(rotationLeadMs < providerLifetimeMs)) {
3765
- throw new Error(
3766
- `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must be strictly less than OPENGENI_MODAL_TIMEOUT_SECONDS*1000 (${providerLifetimeMs}).`
3767
- );
3768
- }
3769
- const captureTimeoutMs = sandboxArchiveCaptureTimeoutMs(settings);
3770
- if (!(rotationLeadMs > captureTimeoutMs + reaperPeriod)) {
3771
- throw new Error(
3772
- `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the durable capture timeout plus one reaper period (${captureTimeoutMs + reaperPeriod}).`
3773
- );
3774
- }
3775
- if (!(viewerTtl < idleTimeoutMs)) {
3776
- throw new Error(
3777
- `OPENGENI_SANDBOX_VIEWER_HOLDER_TTL_MS (${viewerTtl}) must be strictly less than the effective box idle timeout (${idleTimeoutMs}): a viewer holder must be reapable before the box idles out from under it (the provider idle-timeout is the backstop).`
3778
- );
3779
- }
3780
- if (!(interactionTtl < idleTimeoutMs)) {
3781
- throw new Error(
3782
- `OPENGENI_SANDBOX_INTERACTION_HOLDER_TTL_MS (${interactionTtl}) must be strictly less than the effective box idle timeout (${idleTimeoutMs}): a dead browser controller must be reapable before the provider reclaims its placement.`
3783
- );
4198
+ if (settings.sandboxBackend === "modal") {
4199
+ const idleGraceMs = settings.sandboxIdleGraceMs;
4200
+ const lifecycle = effectiveSandboxLifecycle(settings, "modal");
4201
+ const providerLifetimeMs = lifecycle.hardLifetimeMs;
4202
+ const rotationLeadMs = lifecycle.rotationLeadMs;
4203
+ const idleTimeoutMs = lifecycle.providerIdleTimeoutMs;
4204
+ if (!(idleTimeoutMs <= providerLifetimeMs)) {
4205
+ throw new Error(
4206
+ `OPENGENI_MODAL_IDLE_TIMEOUT_SECONDS*1000 (${idleTimeoutMs}) must not exceed the hard provider lifetime (OPENGENI_MODAL_TIMEOUT_SECONDS*1000 = ${providerLifetimeMs}): the idle timeout is a floor under the hard lifetime, not above it.`
4207
+ );
4208
+ }
4209
+ if (!(rotationLeadMs < providerLifetimeMs)) {
4210
+ throw new Error(
4211
+ `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must be strictly less than OPENGENI_MODAL_TIMEOUT_SECONDS*1000 (${providerLifetimeMs}).`
4212
+ );
4213
+ }
4214
+ const captureTimeoutMs = sandboxArchiveCaptureTimeoutMs(settings);
4215
+ if (!(rotationLeadMs > captureTimeoutMs + reaperPeriod)) {
4216
+ throw new Error(
4217
+ `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the durable capture timeout plus one reaper period (${captureTimeoutMs + reaperPeriod}).`
4218
+ );
4219
+ }
4220
+ if (!(viewerTtl < idleTimeoutMs)) {
4221
+ throw new Error(
4222
+ `OPENGENI_SANDBOX_VIEWER_HOLDER_TTL_MS (${viewerTtl}) must be strictly less than the effective box idle timeout (${idleTimeoutMs}): a viewer holder must be reapable before the box idles out from under it (the provider idle-timeout is the backstop).`
4223
+ );
4224
+ }
4225
+ if (!(interactionTtl < idleTimeoutMs)) {
4226
+ throw new Error(
4227
+ `OPENGENI_SANDBOX_INTERACTION_HOLDER_TTL_MS (${interactionTtl}) must be strictly less than the effective box idle timeout (${idleTimeoutMs}): a dead browser controller must be reapable before the provider reclaims its placement.`
4228
+ );
4229
+ }
4230
+ if (!(reaperPeriod + idleGraceMs < idleTimeoutMs)) {
4231
+ throw new Error(
4232
+ `OPENGENI_SANDBOX_LEASE_REAPER_PERIOD_MS + OPENGENI_SANDBOX_IDLE_GRACE_MS (${reaperPeriod} + ${idleGraceMs} = ${reaperPeriod + idleGraceMs}) must be strictly less than the effective box idle timeout (${idleTimeoutMs}): a drained box must SURVIVE its full warm window so the reaper can resume + snapshot /workspace + terminate it on the sweep AFTER the drain grace elapses \u2014 Modal's idle-reap must NOT fire first (or /workspace is lost). Raise OPENGENI_MODAL_IDLE_TIMEOUT_SECONDS (defaults to OPENGENI_MODAL_TIMEOUT_SECONDS) or lower OPENGENI_SANDBOX_IDLE_GRACE_MS.`
4233
+ );
4234
+ }
3784
4235
  }
3785
- if (!(reaperPeriod + idleGraceMs < idleTimeoutMs)) {
4236
+ }
4237
+ if (settings.sandboxDesktopEnabled && settings.sandboxBackend === "modal" && !["local", "test"].includes(settings.environment)) {
4238
+ if (!isDigestPinnedModalDesktopImage(settings)) {
3786
4239
  throw new Error(
3787
- `OPENGENI_SANDBOX_LEASE_REAPER_PERIOD_MS + OPENGENI_SANDBOX_IDLE_GRACE_MS (${reaperPeriod} + ${idleGraceMs} = ${reaperPeriod + idleGraceMs}) must be strictly less than the effective box idle timeout (${idleTimeoutMs}): a drained box must SURVIVE its full warm window so the reaper can resume + snapshot /workspace + terminate it on the sweep AFTER the drain grace elapses \u2014 Modal's idle-reap must NOT fire first (or /workspace is lost). Raise OPENGENI_MODAL_IDLE_TIMEOUT_SECONDS (defaults to OPENGENI_MODAL_TIMEOUT_SECONDS) or lower OPENGENI_SANDBOX_IDLE_GRACE_MS.`
4240
+ "OPENGENI_MODAL_IMAGE_REF must be digest-pinned (registry/name@sha256:\u2026) when OPENGENI_SANDBOX_BACKEND=modal and OPENGENI_SANDBOX_DESKTOP_ENABLED=true. Computer/Browser need docker/desktop.Dockerfile, not the official headless opengeni-sandbox image. Helm desktop.imageRef writes this pin."
3788
4241
  );
3789
4242
  }
3790
4243
  }
@@ -3813,7 +4266,7 @@ function validateSettings(settings) {
3813
4266
  );
3814
4267
  }
3815
4268
  providerIds.add(provider.id);
3816
- if (provider.kind !== "codex-subscription" && !resolveProviderApiKey(provider)) {
4269
+ if (provider.kind !== "codex-subscription" && provider.kind !== "anonymous" && !resolveProviderApiKey(provider)) {
3817
4270
  throw new Error(
3818
4271
  `OPENGENI_MODEL_PROVIDERS_JSON provider ${provider.id} requires a resolvable API key (set apiKey or apiKeyEnv)`
3819
4272
  );
@@ -3910,10 +4363,15 @@ export {
3910
4363
  CapabilityStateV1Schema,
3911
4364
  CapabilitySupportV1,
3912
4365
  DEFAULT_AGENT_INSTRUCTIONS,
4366
+ DEFAULT_GOAL_IDLE_BACKOFF_MAX_MS,
4367
+ DEFAULT_GOAL_IDLE_BACKOFF_MS,
4368
+ GOOGLE_DRIVE_PROVIDER_REQUEST_TIMEOUT_MAX_MS,
4369
+ GOOGLE_DRIVE_PROVIDER_RETRY_DELAY_MAX_MS,
3913
4370
  IntegrationOAuthClientConfigSchema,
3914
4371
  McpServerConnectionRefSchema,
3915
4372
  ModelCapabilitiesV1Schema,
3916
4373
  ModelProviderApi,
4374
+ ModelProviderWireProfile,
3917
4375
  OPENGENI_GATEWAY_MODELS,
3918
4376
  OPENGENI_GATEWAY_PROVIDER_ID,
3919
4377
  OPENGENI_REALTIME_MODEL_ID_PREFIX,
@@ -3943,6 +4401,7 @@ export {
3943
4401
  calculateModelUsageCostBreakdown,
3944
4402
  calculateModelUsageCostMicros,
3945
4403
  calculateVideoGenerationCreditCostMicros,
4404
+ canonicalPublicOrigin,
3946
4405
  canonicalizeConfiguredModelId,
3947
4406
  codemodeWorkspaceUrl,
3948
4407
  collectGitIdentityEnvironment,
@@ -3950,6 +4409,7 @@ export {
3950
4409
  configuredAllowedModels,
3951
4410
  configuredAllowedReasoningEfforts,
3952
4411
  configuredEntitlements,
4412
+ configuredGoogleDriveSyncLimits,
3953
4413
  configuredModelPricing,
3954
4414
  configuredModelPricingSchedules,
3955
4415
  configuredModels,
@@ -3959,11 +4419,16 @@ export {
3959
4419
  dbSearchPath,
3960
4420
  defaultModelPricing,
3961
4421
  effectiveModalIdleTimeoutSeconds,
4422
+ effectiveSandboxLifecycle,
3962
4423
  environmentsEncryptionKeyBytes,
3963
4424
  firstPartyMcpBaseUrl,
4425
+ firstPartyMcpInternalBaseUrl,
4426
+ firstPartyMcpInternalWorkspaceUrl,
3964
4427
  firstPartyMcpWorkspaceUrl,
3965
4428
  gatewayRequestPolicyForUpstreamModel,
3966
4429
  getSettings,
4430
+ googleDriveOAuthCallbackUrl,
4431
+ googleDriveProviderRetryOptions,
3967
4432
  hasGitCredentialRepositorySelection,
3968
4433
  hasGitHubRepositorySelection,
3969
4434
  isDirectOpenAiApiBaseUrl,
@@ -3977,6 +4442,7 @@ export {
3977
4442
  parseSocialOauthClientsJson,
3978
4443
  parseStaticEntitlementsJson,
3979
4444
  parseStaticUsageLimitsJson,
4445
+ personalGitHubOAuthCallbackUrl,
3980
4446
  policyProviderIdForModel,
3981
4447
  productLabelForModelId,
3982
4448
  productShortLabelForModelId,