@opengeni/config 0.11.0 → 0.13.2

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
@@ -10,6 +10,7 @@ import {
10
10
  ReasoningEffort,
11
11
  SandboxBackend,
12
12
  SessionMcpApprovalPolicy,
13
+ SEEDANCE_2_5_MODEL_ID,
13
14
  StaticUsageLimits,
14
15
  TurnExecutionPolicyV1,
15
16
  UsageLimitsMode
@@ -28,6 +29,11 @@ import { createHash } from "crypto";
28
29
  import { z } from "zod";
29
30
  var envName = /^[A-Za-z_][A-Za-z0-9_]*$/;
30
31
  var registryId = /^[A-Za-z0-9_-]+$/;
32
+ var SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS = 60 * 6e4;
33
+ var SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS = 1e4;
34
+ var SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS = SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS - SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS;
35
+ var SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS = 60 * 6e4;
36
+ var SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS = 1e4;
31
37
  var EnvBoolean = z.preprocess((value) => {
32
38
  if (typeof value !== "string") {
33
39
  return value;
@@ -171,6 +177,12 @@ var SettingsSchema = z.object({
171
177
  turnWorkerMaxConcurrentTurns: z.coerce.number().int().positive().max(2e3).default(16),
172
178
  turnWorkerTargetCpuUsage: z.coerce.number().positive().max(1).default(0.8),
173
179
  turnWorkerTargetMemoryUsage: z.coerce.number().positive().max(0.8).default(0.75),
180
+ // Admission and emergency recovery are deliberately separate control loops.
181
+ // The Temporal tuner stops polling at the lower target; only genuine danger
182
+ // may invoke the disruptive graceful-drain fallback.
183
+ turnWorkerEmergencyMemoryUsage: z.coerce.number().min(0.85).max(0.95).default(0.9),
184
+ turnWorkerMemoryGuardIntervalMs: z.coerce.number().int().min(1e3).max(6e4).default(5e3),
185
+ turnWorkerMemoryGuardSustainMs: z.coerce.number().int().min(5e3).max(3e5).default(3e4),
174
186
  observabilityStructuredLogs: EnvBoolean.default(false),
175
187
  observabilityMetricsEnabled: EnvBoolean.default(true),
176
188
  observabilityOtlpEndpoint: z.string().url().optional(),
@@ -192,7 +204,10 @@ var SettingsSchema = z.object({
192
204
  // Explicit operator-controlled promotion pointer for `/agent/latest/*`.
193
205
  // Versioned agent releases are immutable; changing this setting promotes or
194
206
  // rolls back the stable channel without moving or deleting a provider tag.
195
- agentStableVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).default("0.1.9"),
207
+ agentStableVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).default("0.1.14"),
208
+ // Optional independent beta-channel pointer. When unset, the beta update
209
+ // manifest route is unavailable rather than silently serving stable.
210
+ agentBetaVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).optional(),
196
211
  productAccessMode: ProductAccessMode.default("local"),
197
212
  billingMode: BillingMode.default("disabled"),
198
213
  entitlementsMode: EntitlementsMode.default("none"),
@@ -210,8 +225,7 @@ var SettingsSchema = z.object({
210
225
  // holder of stream:control gets 403 until this flips. Keeps stream:control a
211
226
  // declared-but-inert permission so later hardening is a flag flip.
212
227
  streamControlEnabled: EnvBoolean.default(false),
213
- toolspaceEnabled: EnvBoolean.default(false),
214
- toolspaceMaxCallsPerTurn: z.coerce.number().int().positive().default(200),
228
+ codemodeMaxCallsPerTurn: z.coerce.number().int().positive().default(200),
215
229
  // Optional release-coherent bootstrap hint for custom rigs/connected machines
216
230
  // that do not carry the stock-image ogtool binary. Exact stable versions only:
217
231
  // the agent must never guess a tag or silently install `latest`.
@@ -221,11 +235,15 @@ var SettingsSchema = z.object({
221
235
  integrationsStateSecret: z.string().optional(),
222
236
  integrationsAllowPrivateNetworkTargets: EnvBoolean.default(false),
223
237
  integrationsOauthClientsJson: z.string().default("{}"),
238
+ gmailRestAdapterEnabled: EnvBoolean.default(false),
224
239
  slackClientId: z.string().optional(),
225
240
  slackClientSecret: z.string().optional(),
226
241
  slackSigningSecret: z.string().optional(),
227
242
  googleDriveClientId: z.string().optional(),
228
243
  googleDriveClientSecret: z.string().optional(),
244
+ googleDriveWorkspaceEventsEnabled: EnvBoolean.optional(),
245
+ atlassianClientId: z.string().optional(),
246
+ atlassianClientSecret: z.string().optional(),
229
247
  // Undefined is meaningful: the migration boundary persists the product
230
248
  // default of 3 when no deployment override is supplied.
231
249
  maxNestedAgentDepth: z.coerce.number().int().nonnegative().max(MAX_NESTED_AGENT_DEPTH).optional(),
@@ -296,6 +314,20 @@ var SettingsSchema = z.object({
296
314
  // Gateway models below are added to the managed-credit catalog. Workspace
297
315
  // Gateway keys use the encrypted connection broker and never this secret.
298
316
  vercelAiGatewayApiKey: z.string().optional(),
317
+ /** Image adapter route; native hosted providers ignore this model. */
318
+ imageGenerationModel: z.string().trim().min(1).max(256).default("openai/gpt-image-2"),
319
+ /** Durable video generation uses the workspace-owned Gateway credential. */
320
+ videoGenerationPollIntervalMs: z.coerce.number().int().min(1e3).max(6e4).default(5e3),
321
+ videoGenerationRecoveryDeadlineMs: z.coerce.number().int().min(6e4).max(24 * 60 * 6e4).default(2 * 60 * 6e4),
322
+ videoGenerationReferenceUrlTtlSeconds: z.coerce.number().int().min(300).max(6 * 60 * 60).default(60 * 60),
323
+ videoGenerationMaxConcurrentPerWorkspace: z.coerce.number().int().min(1).max(16).default(2),
324
+ videoGenerationWorkspaceQuotaBytes: z.coerce.number().int().positive().max(Number.MAX_SAFE_INTEGER).default(20 * 1024 * 1024 * 1024),
325
+ videoGenerationTempDirectory: z.string().trim().min(1).max(1024).default("/tmp/opengeni-video"),
326
+ videoGenerationFfprobePath: z.string().trim().min(1).max(1024).default("ffprobe"),
327
+ // OpenGeni's customer price, not a claim about the provider's delayed cost report.
328
+ // The durable operation freezes the exact resulting price before provider submit.
329
+ videoGenerationCredit480pMicrosPerSecond: z.coerce.number().int().positive().max(1e7).default(155e3),
330
+ videoGenerationCredit720pMicrosPerSecond: z.coerce.number().int().positive().max(1e7).default(35e4),
299
331
  // Native composer voice input (browser MediaRecorder → API transcription).
300
332
  // Provider credentials stay server-side; ClientConfig only projects availability
301
333
  // and hard ceilings. Selection happens once before audio is sent — never retry
@@ -364,6 +396,11 @@ var SettingsSchema = z.object({
364
396
  // compatibility diagnosis.
365
397
  // OPENGENI_CODEX_TOOL_SEARCH_ENABLED
366
398
  codexToolSearchEnabled: EnvBoolean.default(true),
399
+ // Provider-neutral progressive disclosure for direct OpenAI/Azure native
400
+ // client search and ordinary-function generic dispatch. Kept separate from
401
+ // the Codex rollout so an emergency Codex opt-out cannot disable every model.
402
+ // OPENGENI_LAZY_TOOL_SEARCH_ENABLED
403
+ lazyToolSearchEnabled: EnvBoolean.default(true),
367
404
  // credential allocator atomic, workspace-local credential allocation. Default OFF is a
368
405
  // deliberate rolling-deploy fence: migrate + roll every worker first, then
369
406
  // enable. Turning it off restores the legacy sticky selector without a schema
@@ -421,6 +458,13 @@ var SettingsSchema = z.object({
421
458
  disableOpenaiTracing: EnvBoolean.default(false),
422
459
  sandboxBackend: SandboxBackend.default("docker"),
423
460
  dockerImage: z.string().default("opengeni-sandbox:local"),
461
+ // Explicit deployment contract: the configured base sandbox image contains
462
+ // the verified, self-contained native artifact runtime at its fixed image
463
+ // paths. Disabled by default so arbitrary/custom provider images never make
464
+ // document/spreadsheet/presentation skills appear when their runtime is
465
+ // absent. Per-pack/per-rig image overrides fail closed in the worker even
466
+ // when this base-image contract is enabled.
467
+ sandboxArtifactRuntimeEnabled: EnvBoolean.default(false),
424
468
  dockerExposedPorts: z.string().default(""),
425
469
  dockerNetwork: z.string().optional(),
426
470
  // When the worker itself runs in a container and talks to a host Docker daemon,
@@ -477,15 +521,14 @@ var SettingsSchema = z.object({
477
521
  // SOONER than the hard lifetime; the boot invariant forbids a value that would
478
522
  // reap before reaperPeriod + idleGrace elapses.
479
523
  modalIdleTimeoutSeconds: z.coerce.number().int().positive().optional(),
480
- // /workspace FILE PERSISTENCE across warm/cold cycles. Defaults to
481
- // `snapshot_filesystem` so EVERY box is created persistence-capable: the reaper
482
- // snapshots the live box before it terminates a drained group, and a later
483
- // cold-restore hydrates a fresh box from that snapshot (sandbox-file-persistence).
484
- // `snapshot_filesystem` requires the manifest declare NO ephemeralPersistencePaths
485
- // (buildManifest never sets entry.ephemeral, so it never downgrades to tar). Set
486
- // OPENGENI_MODAL_WORKSPACE_PERSISTENCE=tar to opt back out (no native snapshot;
487
- // the reaper persists a tar archive — same store+hydrate plumbing, slower).
488
- modalWorkspacePersistence: z.enum(["tar", "snapshot_filesystem", "snapshot_directory"]).default("snapshot_filesystem"),
524
+ // /workspace FILE PERSISTENCE across warm/cold cycles. Directory snapshots
525
+ // preserve only the durable user workspace, so provider recovery does not
526
+ // restore an entire machine image or replace the selected rig/base image.
527
+ // Existing serialized sessions retain their original persistence mode and
528
+ // remain recoverable; this default governs newly created Modal sandboxes.
529
+ // `snapshot_filesystem` remains available for explicit compatibility and
530
+ // immutable rig-image materialization. `tar` is the portable fallback.
531
+ modalWorkspacePersistence: z.enum(["tar", "snapshot_filesystem", "snapshot_directory"]).default("snapshot_directory"),
489
532
  // Shared desktop toggle: this module reads it for the 6080 port-merge; the
490
533
  // owner module (P4.x) acts on it to launch the display stack.
491
534
  sandboxDesktopEnabled: EnvBoolean.default(false),
@@ -613,10 +656,13 @@ var SettingsSchema = z.object({
613
656
  // the deploy-staging IaC secret/configmap pattern.
614
657
  sandboxSelfhostedEnabled: EnvBoolean.default(false),
615
658
  // Gates the op-stream (streaming exec) transport to Connected Machines. The
616
- // runner must ALSO advertise Capabilities.op_stream; default off, and legacy
617
- // request/reply exec is the permanent fallback. EnvBoolean (NOT
659
+ // runner must ALSO advertise Capabilities.op_stream. Streaming is the default
660
+ // because it is the only transport that can keep a command alive without an
661
+ // arbitrary request/reply wall while still supporting replay and cancellation.
662
+ // Older runners remain usable when an explicit positive exec timeout is set.
663
+ // EnvBoolean (NOT
618
664
  // z.coerce.boolean(), which coerces "false" -> true).
619
- agentOpStreamEnabled: EnvBoolean.default(false),
665
+ agentOpStreamEnabled: EnvBoolean.default(true),
620
666
  // The HMAC secret the control plane signs the enrollment bearer credential with
621
667
  // (the `oge_` envelope the agent presents back to the control plane). Optional:
622
668
  // when ABSENT and sandboxSelfhostedEnabled is on, the poll route reports the
@@ -674,23 +720,15 @@ var SettingsSchema = z.object({
674
720
  selfhostedNatsControlUser: z.string().optional(),
675
721
  selfhostedNatsControlPassword: z.string().optional(),
676
722
  // --- selfhosted (Connected Machine) control/exec op deadlines ---------------
677
- // The control plane splits its op deadline in two. CONTROL ops (ping / fs / git /
678
- // desktop / pty) must stay responsive so a machine's liveness is never masked by a
679
- // slow op, so they use the short control timeout. EXEC gets its OWN, larger budget:
680
- // a real command (compile, test run, dependency install) routinely outlives the
681
- // control timeout, and before the split a long command was killed at the ~30s
682
- // control wall. The agent kills the exec child at this deadline; the wire waits
683
- // slightly longer (SELFHOSTED_EXEC_REPLY_GRACE_MS) for the typed timed-out reply.
684
- //
685
- // The exec default is a DELIBERATELY MODEST 2min (not 5): the agent-side admission
686
- // pool is (until a later agent release) a FLAT 8 permits with no per-class split,
687
- // so 8 slow execs holding a permit for 5 minutes would blanket-DRAIN every fs/git
688
- // op — shipping the amplifier before the class-aware-admission fix. 2min still
689
- // clears the large majority of the observed >30s exec tail; genuinely long jobs run
690
- // in the background (see the exec-deadline hint) or raise the knob per deployment.
691
- // Knobs: OPENGENI_SANDBOX_SELFHOSTED_EXEC_TIMEOUT_MS (default 2min) and
723
+ // CONTROL ops (ping / fs / git / desktop / pty) keep a short request timeout so
724
+ // liveness failures surface promptly. EXEC duration is a different concern: by
725
+ // default it is unbounded (0), exactly like a command launched by an unrestricted
726
+ // local agent. The op-stream transport keeps control liveness, replay, and explicit
727
+ // cancellation independent of command duration. A deployment may opt into a hard
728
+ // process deadline by setting a positive value; 0 never schedules a process kill.
729
+ // Knobs: OPENGENI_SANDBOX_SELFHOSTED_EXEC_TIMEOUT_MS (default 0 = none) and
692
730
  // OPENGENI_SANDBOX_SELFHOSTED_CONTROL_TIMEOUT_MS (default 30s).
693
- sandboxSelfhostedExecTimeoutMs: z.coerce.number().int().positive().default(12e4),
731
+ sandboxSelfhostedExecTimeoutMs: z.coerce.number().int().nonnegative().default(0),
694
732
  sandboxSelfhostedControlTimeoutMs: z.coerce.number().int().positive().default(3e4),
695
733
  // --- sandbox lease cadences (cadence invariant validated at boot below) ---
696
734
  // reaperPeriod < viewerHolderTTL, and reaperPeriod + idleGrace < the EFFECTIVE
@@ -701,6 +739,10 @@ var SettingsSchema = z.object({
701
739
  // snapshotted before the box dies (sandbox-file-persistence).
702
740
  sandboxLeaseReaperPeriodMs: z.coerce.number().int().positive().default(3e4),
703
741
  sandboxViewerHolderTtlMs: z.coerce.number().int().positive().default(9e4),
742
+ // A BrowserSession controller refreshes its durable resource and exact
743
+ // interaction lease holder together. This longer crash horizon tolerates API
744
+ // replacement while still releasing a placement whose controller died.
745
+ sandboxInteractionHolderTtlMs: z.coerce.number().int().positive().default(18e4),
704
746
  // The DRAIN grace: how long a refcount-0 (draining) lease stays WARM before the
705
747
  // reaper resume-by-ids the box and terminates it. This is the cost-vs-snappiness
706
748
  // dial — when the user navigates away the box keeps refcount 0, but it survives
@@ -726,7 +768,7 @@ var SettingsSchema = z.object({
726
768
  // graceful shutdown, or become permission to GC an older archive. Timeout is
727
769
  // treated exactly like a failed best-effort snapshot. Knob:
728
770
  // OPENGENI_SANDBOX_SNAPSHOT_TIMEOUT_MS. Default 60s.
729
- sandboxSnapshotTimeoutMs: z.coerce.number().int().positive().default(6e4),
771
+ sandboxSnapshotTimeoutMs: z.coerce.number().int().positive().max(SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS).default(6e4),
730
772
  // Begin a controlled snapshot/quiesce/drain/rematerialize transition this far
731
773
  // ahead of a finite provider deadline. Modal's 24h creation clock cannot be
732
774
  // extended; the logical sandbox outlives it by moving to one successor box.
@@ -736,13 +778,12 @@ var SettingsSchema = z.object({
736
778
  // an operator deliberately wants more rotation headroom; the boot invariant
737
779
  // still requires it to remain below the provider lifetime.
738
780
  sandboxRotationLeadMs: z.coerce.number().int().positive().default(36e5),
739
- // Bound each global reaper pass so a rollout that discovers many legacy boxes
740
- // with unknown creation clocks cannot create a provider/API thundering herd.
741
- // One is the safe admission default: the reaper services provider transitions
742
- // sequentially, so claiming a wider batch would fence boxes before the same
743
- // sweep can service them. Larger fleets may raise this only as an explicit,
744
- // observed deployment choice.
745
- sandboxRotationBatchSize: z.coerce.number().int().positive().max(500).default(1),
781
+ // Bound provider-deadline rotation admission independently of execution.
782
+ // Every admitted box receives its own durable drain child; the control worker
783
+ // limits provider I/O to 32 concurrent activities. Matching that bound avoids
784
+ // both the old one-box-per-tick deadline backlog and an unbounded provider/API
785
+ // burst. Operators may tune this for a differently-sized worker pool.
786
+ sandboxRotationBatchSize: z.coerce.number().int().positive().max(500).default(32),
746
787
  // expires_at refresh window for a held lease (>> the turn 10s heartbeat so a
747
788
  // single missed heartbeat never TTL-reaps a live turn). The warming TTL is the
748
789
  // window a cold->warming spawner has to commit warm before a reaper resets it.
@@ -971,7 +1012,11 @@ var ModelCapabilitiesV1Schema = z.object({
971
1012
  hostedTools: z.object({
972
1013
  webSearch: CapabilityStateV1Schema,
973
1014
  xSearch: CapabilityStateV1Schema,
974
- codeExecution: CapabilityStateV1Schema
1015
+ codeExecution: CapabilityStateV1Schema,
1016
+ imageGeneration: CapabilityStateV1Schema.default({
1017
+ upstream: "unknown",
1018
+ runnable: false
1019
+ })
975
1020
  }),
976
1021
  inputModalities: z.array(ModelModalityV1).min(1),
977
1022
  /** Exact MIME types accepted as typed `input_file`; `text/*` is allowed. */
@@ -1340,6 +1385,9 @@ function getSettings() {
1340
1385
  turnWorkerMaxConcurrentTurns: optional("OPENGENI_TURN_WORKER_MAX_CONCURRENT_TURNS"),
1341
1386
  turnWorkerTargetCpuUsage: optional("OPENGENI_TURN_WORKER_TARGET_CPU_USAGE"),
1342
1387
  turnWorkerTargetMemoryUsage: optional("OPENGENI_TURN_WORKER_TARGET_MEMORY_USAGE"),
1388
+ turnWorkerEmergencyMemoryUsage: optional("OPENGENI_TURN_WORKER_EMERGENCY_MEMORY_USAGE"),
1389
+ turnWorkerMemoryGuardIntervalMs: optional("OPENGENI_TURN_WORKER_MEMORY_GUARD_INTERVAL_MS"),
1390
+ turnWorkerMemoryGuardSustainMs: optional("OPENGENI_TURN_WORKER_MEMORY_GUARD_SUSTAIN_MS"),
1343
1391
  observabilityStructuredLogs: optional("OPENGENI_OBSERVABILITY_STRUCTURED_LOGS"),
1344
1392
  observabilityMetricsEnabled: optional("OPENGENI_OBSERVABILITY_METRICS_ENABLED"),
1345
1393
  observabilityOtlpEndpoint: optional("OPENGENI_OTEL_EXPORTER_OTLP_ENDPOINT") ?? optional("OTEL_EXPORTER_OTLP_ENDPOINT"),
@@ -1354,6 +1402,7 @@ function getSettings() {
1354
1402
  webBaseUrl: optional("OPENGENI_WEB_BASE_URL"),
1355
1403
  agentReleasesBaseUrl: optional("OPENGENI_AGENT_RELEASES_BASE_URL"),
1356
1404
  agentStableVersion: optional("OPENGENI_AGENT_STABLE_VERSION"),
1405
+ agentBetaVersion: optional("OPENGENI_AGENT_BETA_VERSION"),
1357
1406
  productAccessMode: optional("OPENGENI_PRODUCT_ACCESS_MODE"),
1358
1407
  billingMode: optional("OPENGENI_BILLING_MODE"),
1359
1408
  entitlementsMode: optional("OPENGENI_ENTITLEMENTS_MODE"),
@@ -1363,8 +1412,7 @@ function getSettings() {
1363
1412
  delegationSecret: optional("OPENGENI_DELEGATION_SECRET"),
1364
1413
  streamTokenSecret: optional("OPENGENI_STREAM_TOKEN_SECRET"),
1365
1414
  streamControlEnabled: optional("OPENGENI_STREAM_CONTROL_ENABLED"),
1366
- toolspaceEnabled: optional("OPENGENI_TOOLSPACE_ENABLED"),
1367
- toolspaceMaxCallsPerTurn: optional("OPENGENI_TOOLSPACE_MAX_CALLS_PER_TURN"),
1415
+ codemodeMaxCallsPerTurn: optional("OPENGENI_CODEMODE_MAX_CALLS_PER_TURN"),
1368
1416
  ogtoolPackageSpec: optional("OPENGENI_OGTOOL_PACKAGE_SPEC"),
1369
1417
  environmentsEncryptionKey: optional("OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY"),
1370
1418
  integrationsEnabled: optional("OPENGENI_INTEGRATIONS_ENABLED"),
@@ -1373,11 +1421,15 @@ function getSettings() {
1373
1421
  "OPENGENI_INTEGRATIONS_ALLOW_PRIVATE_NETWORK_TARGETS"
1374
1422
  ),
1375
1423
  integrationsOauthClientsJson: optional("OPENGENI_INTEGRATIONS_OAUTH_CLIENTS_JSON"),
1424
+ gmailRestAdapterEnabled: optional("OPENGENI_GMAIL_REST_ADAPTER_ENABLED"),
1376
1425
  slackClientId: optional("OPENGENI_SLACK_CLIENT_ID"),
1377
1426
  slackClientSecret: optional("OPENGENI_SLACK_CLIENT_SECRET"),
1378
1427
  slackSigningSecret: optional("OPENGENI_SLACK_SIGNING_SECRET"),
1379
1428
  googleDriveClientId: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_ID"),
1380
1429
  googleDriveClientSecret: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_SECRET"),
1430
+ googleDriveWorkspaceEventsEnabled: optional("OPENGENI_GOOGLE_DRIVE_WORKSPACE_EVENTS_ENABLED"),
1431
+ atlassianClientId: optional("OPENGENI_ATLASSIAN_CLIENT_ID"),
1432
+ atlassianClientSecret: optional("OPENGENI_ATLASSIAN_CLIENT_SECRET"),
1381
1433
  maxNestedAgentDepth: optional("OPENGENI_MAX_NESTED_AGENT_DEPTH"),
1382
1434
  socialOauthClientsJson: optional("OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON"),
1383
1435
  goalMaxAutoContinuations: optional("OPENGENI_GOAL_MAX_AUTO_CONTINUATIONS"),
@@ -1404,6 +1456,24 @@ function getSettings() {
1404
1456
  openaiModel: optional("OPENGENI_OPENAI_MODEL"),
1405
1457
  openaiAllowedModels: optional("OPENGENI_OPENAI_ALLOWED_MODELS"),
1406
1458
  vercelAiGatewayApiKey: optional("OPENGENI_VERCEL_AI_GATEWAY_API_KEY"),
1459
+ imageGenerationModel: optional("OPENGENI_IMAGE_GENERATION_MODEL"),
1460
+ videoGenerationPollIntervalMs: optional("OPENGENI_VIDEO_GENERATION_POLL_INTERVAL_MS"),
1461
+ videoGenerationRecoveryDeadlineMs: optional("OPENGENI_VIDEO_GENERATION_RECOVERY_DEADLINE_MS"),
1462
+ videoGenerationReferenceUrlTtlSeconds: optional(
1463
+ "OPENGENI_VIDEO_GENERATION_REFERENCE_URL_TTL_SECONDS"
1464
+ ),
1465
+ videoGenerationMaxConcurrentPerWorkspace: optional(
1466
+ "OPENGENI_VIDEO_GENERATION_MAX_CONCURRENT_PER_WORKSPACE"
1467
+ ),
1468
+ videoGenerationWorkspaceQuotaBytes: optional("OPENGENI_VIDEO_GENERATION_WORKSPACE_QUOTA_BYTES"),
1469
+ videoGenerationTempDirectory: optional("OPENGENI_VIDEO_GENERATION_TEMP_DIRECTORY"),
1470
+ videoGenerationFfprobePath: optional("OPENGENI_VIDEO_GENERATION_FFPROBE_PATH"),
1471
+ videoGenerationCredit480pMicrosPerSecond: optional(
1472
+ "OPENGENI_VIDEO_GENERATION_CREDIT_480P_MICROS_PER_SECOND"
1473
+ ),
1474
+ videoGenerationCredit720pMicrosPerSecond: optional(
1475
+ "OPENGENI_VIDEO_GENERATION_CREDIT_720P_MICROS_PER_SECOND"
1476
+ ),
1407
1477
  voiceInputMaxDurationSeconds: optional("OPENGENI_VOICE_INPUT_MAX_DURATION_SECONDS"),
1408
1478
  voiceInputMaxSizeBytes: optional("OPENGENI_VOICE_INPUT_MAX_SIZE_BYTES"),
1409
1479
  voiceInputResumableEnabled: optional("OPENGENI_VOICE_INPUT_RESUMABLE_ENABLED"),
@@ -1435,6 +1505,7 @@ function getSettings() {
1435
1505
  codexSubscriptionEnabled: optional("OPENGENI_CODEX_SUBSCRIPTION_ENABLED"),
1436
1506
  codexConnectedAppsEnabled: optional("OPENGENI_CODEX_CONNECTED_APPS_ENABLED"),
1437
1507
  codexToolSearchEnabled: optional("OPENGENI_CODEX_TOOL_SEARCH_ENABLED"),
1508
+ lazyToolSearchEnabled: optional("OPENGENI_LAZY_TOOL_SEARCH_ENABLED"),
1438
1509
  codexCredentialLeasingEnabled: optional("OPENGENI_CODEX_CREDENTIAL_LEASING_ENABLED"),
1439
1510
  codexFleetPolicyShadowEnabled: optional("OPENGENI_CODEX_FLEET_POLICY_SHADOW_ENABLED"),
1440
1511
  codexProductSku: optional("OPENGENI_CODEX_PRODUCT_SKU"),
@@ -1455,6 +1526,7 @@ function getSettings() {
1455
1526
  disableOpenaiTracing: optional("OPENGENI_DISABLE_OPENAI_TRACING"),
1456
1527
  sandboxBackend: optional("OPENGENI_SANDBOX_BACKEND"),
1457
1528
  dockerImage: optional("OPENGENI_DOCKER_IMAGE"),
1529
+ sandboxArtifactRuntimeEnabled: optional("OPENGENI_SANDBOX_ARTIFACT_RUNTIME_ENABLED"),
1458
1530
  dockerExposedPorts: optional("OPENGENI_DOCKER_EXPOSED_PORTS"),
1459
1531
  dockerNetwork: optional("OPENGENI_DOCKER_NETWORK"),
1460
1532
  dockerWorkspaceBaseDir: optional("OPENGENI_DOCKER_WORKSPACE_BASE_DIR"),
@@ -1537,6 +1609,7 @@ function getSettings() {
1537
1609
  sandboxSelfhostedControlTimeoutMs: optional("OPENGENI_SANDBOX_SELFHOSTED_CONTROL_TIMEOUT_MS"),
1538
1610
  sandboxLeaseReaperPeriodMs: optional("OPENGENI_SANDBOX_LEASE_REAPER_PERIOD_MS"),
1539
1611
  sandboxViewerHolderTtlMs: optional("OPENGENI_SANDBOX_VIEWER_HOLDER_TTL_MS"),
1612
+ sandboxInteractionHolderTtlMs: optional("OPENGENI_SANDBOX_INTERACTION_HOLDER_TTL_MS"),
1540
1613
  sandboxIdleGraceMs: optional("OPENGENI_SANDBOX_IDLE_GRACE_MS"),
1541
1614
  sandboxSnapshotIntervalMs: optional("OPENGENI_SANDBOX_SNAPSHOT_INTERVAL_MS"),
1542
1615
  sandboxSnapshotTimeoutMs: optional("OPENGENI_SANDBOX_SNAPSHOT_TIMEOUT_MS"),
@@ -1627,8 +1700,15 @@ function effectiveModalIdleTimeoutSeconds(settings) {
1627
1700
  }
1628
1701
  function sandboxArchiveCaptureTimeoutMs(settings) {
1629
1702
  return Math.min(
1630
- 60 * 6e4,
1631
- Math.max(settings.sandboxSnapshotTimeoutMs + 3e4, settings.sandboxSnapshotTimeoutMs * 2)
1703
+ SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS,
1704
+ settings.sandboxSnapshotTimeoutMs + SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS
1705
+ );
1706
+ }
1707
+ function sandboxLifecycleTransitionWaitMs(settings) {
1708
+ const captureTimeoutMs = sandboxArchiveCaptureTimeoutMs(settings);
1709
+ return Math.min(
1710
+ SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS,
1711
+ settings.sandboxLeaseReaperPeriodMs + captureTimeoutMs + SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS
1632
1712
  );
1633
1713
  }
1634
1714
  function collectSandboxEnvironment(settings, source = process.env) {
@@ -1856,7 +1936,11 @@ function legacyModelCapabilities(settings, input) {
1856
1936
  runnable: input.hostedWebSearch
1857
1937
  },
1858
1938
  xSearch: { upstream: "unknown", runnable: false },
1859
- codeExecution: { upstream: "unknown", runnable: false }
1939
+ codeExecution: { upstream: "unknown", runnable: false },
1940
+ imageGeneration: {
1941
+ upstream: input.hostedImageGeneration ? "supported" : "unknown",
1942
+ runnable: input.hostedImageGeneration ?? false
1943
+ }
1860
1944
  },
1861
1945
  inputModalities: input.vision ? ["text", "image"] : ["text"],
1862
1946
  inputFileMediaTypes: [
@@ -2029,6 +2113,18 @@ function builtinPromptCachingForModel(modelId) {
2029
2113
  const slug = modelId.startsWith(CODEX_MODEL_ID_PREFIX) ? modelId.slice(CODEX_MODEL_ID_PREFIX.length) : modelId;
2030
2114
  return slug.startsWith("gpt-5.6-") ? { upstream: "supported", runnable: true, mode: "implicit" } : void 0;
2031
2115
  }
2116
+ function builtinHostedImageGenerationForModel(settings, modelId) {
2117
+ return settings.openaiProvider === "openai" && isDirectOpenAiApiBaseUrl(settings.openaiBaseUrl) && ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"].includes(modelId);
2118
+ }
2119
+ function isDirectOpenAiApiBaseUrl(baseUrl) {
2120
+ if (baseUrl === void 0) return true;
2121
+ try {
2122
+ const parsed = new URL(baseUrl);
2123
+ return parsed.protocol === "https:" && parsed.hostname === "api.openai.com" && parsed.port === "" && parsed.username === "" && parsed.password === "" && parsed.search === "" && parsed.hash === "" && parsed.pathname.replace(/\/+$/, "") === "/v1";
2124
+ } catch {
2125
+ return false;
2126
+ }
2127
+ }
2032
2128
  function serviceTierForLatencyMode(providerId, latencyMode) {
2033
2129
  if (latencyMode === "standard") {
2034
2130
  return void 0;
@@ -2320,6 +2416,7 @@ function configuredModels(settings) {
2320
2416
  ...legacyModelCapabilities(settings, {
2321
2417
  reasoningEffort: true,
2322
2418
  hostedWebSearch: settings.webSearchEnabled,
2419
+ hostedImageGeneration: builtinHostedImageGenerationForModel(settings, id),
2323
2420
  vision: id.startsWith("gpt-5.6-")
2324
2421
  }),
2325
2422
  ...builtinPromptCachingForModel(id) ? { promptCaching: builtinPromptCachingForModel(id) } : {},
@@ -2563,6 +2660,9 @@ function configuredEntitlements(settings) {
2563
2660
  };
2564
2661
  }
2565
2662
  function calculateModelUsageCostMicros(settings, model, usage, options) {
2663
+ return calculateModelUsageCostBreakdown(settings, model, usage, options).creditCostMicros;
2664
+ }
2665
+ function calculateModelUsageCostBreakdown(settings, model, usage, options) {
2566
2666
  const schedule = configuredModelPricingSchedules(settings)[model];
2567
2667
  if (!schedule) {
2568
2668
  throw new Error(`Missing model pricing for ${model}`);
@@ -2576,10 +2676,12 @@ function calculateModelUsageCostMicros(settings, model, usage, options) {
2576
2676
  (rawCostByPricing.get(pricing) ?? 0) + calculateEntryCostMicros(pricing, entry)
2577
2677
  );
2578
2678
  }
2579
- let total = 0;
2679
+ let providerCostMicros = 0;
2680
+ let creditCostMicros = 0;
2580
2681
  for (const [pricing, rawCost] of rawCostByPricing) {
2581
2682
  const marginBps = pricing.marginBps ?? 0;
2582
- total += Math.ceil(rawCost * (1e4 + marginBps) / 1e4);
2683
+ providerCostMicros += rawCost;
2684
+ creditCostMicros += Math.ceil(rawCost * (1e4 + marginBps) / 1e4);
2583
2685
  }
2584
2686
  const latencyMode = options?.latencyMode ?? "standard";
2585
2687
  if (latencyMode !== "standard") {
@@ -2592,12 +2694,16 @@ function calculateModelUsageCostMicros(settings, model, usage, options) {
2592
2694
  (mode) => mode.id === latencyMode && mode.runnable
2593
2695
  )?.billingMultiplierBps;
2594
2696
  if (multiplierBps && multiplierBps > 0) {
2595
- total = Math.ceil(total * multiplierBps / 1e4);
2697
+ providerCostMicros = Math.ceil(providerCostMicros * multiplierBps / 1e4);
2698
+ creditCostMicros = Math.ceil(creditCostMicros * multiplierBps / 1e4);
2596
2699
  }
2597
2700
  }
2598
- return total;
2701
+ return { providerCostMicros, creditCostMicros };
2599
2702
  }
2600
2703
  function calculateGatewayReportedCostMicros(settings, model, inferenceCostUsd, options) {
2704
+ return calculateGatewayReportedCostBreakdown(settings, model, inferenceCostUsd, options).creditCostMicros;
2705
+ }
2706
+ function calculateGatewayReportedCostBreakdown(settings, model, inferenceCostUsd, options) {
2601
2707
  const schedule = configuredModelPricingSchedules(settings)[model];
2602
2708
  if (!schedule) {
2603
2709
  throw new Error(`Missing model pricing for ${model}`);
@@ -2610,14 +2716,33 @@ function calculateGatewayReportedCostMicros(settings, model, inferenceCostUsd, o
2610
2716
  const fraction = match[2] ?? "";
2611
2717
  const decimalDigits = BigInt(`${match[1]}${fraction}`);
2612
2718
  const decimalScale = 10n ** BigInt(fraction.length);
2719
+ const providerNumerator = decimalDigits * 1000000n;
2720
+ const providerMicros = (providerNumerator + decimalScale - 1n) / decimalScale;
2613
2721
  const marginBps = BigInt(1e4 + (pricing.marginBps ?? 0));
2614
- const numerator = decimalDigits * 1000000n * marginBps;
2722
+ const numerator = providerNumerator * marginBps;
2615
2723
  const denominator = decimalScale * 10000n;
2616
- const micros = (numerator + denominator - 1n) / denominator;
2617
- if (micros > BigInt(Number.MAX_SAFE_INTEGER)) {
2724
+ const creditMicros = (numerator + denominator - 1n) / denominator;
2725
+ if (providerMicros > BigInt(Number.MAX_SAFE_INTEGER) || creditMicros > BigInt(Number.MAX_SAFE_INTEGER)) {
2618
2726
  throw new Error("AI Gateway inference cost exceeds the supported billing range");
2619
2727
  }
2620
- return Number(micros);
2728
+ return {
2729
+ providerCostMicros: Number(providerMicros),
2730
+ creditCostMicros: Number(creditMicros)
2731
+ };
2732
+ }
2733
+ function calculateVideoGenerationCreditCostMicros(settings, input) {
2734
+ if (input.modelId !== SEEDANCE_2_5_MODEL_ID) {
2735
+ throw new Error(`Missing video generation credit pricing for ${input.modelId}`);
2736
+ }
2737
+ if (!Number.isSafeInteger(input.durationSeconds) || input.durationSeconds < 1) {
2738
+ throw new Error("Video generation duration is invalid for credit pricing");
2739
+ }
2740
+ const rate = input.resolution === "480p" ? settings.videoGenerationCredit480pMicrosPerSecond : settings.videoGenerationCredit720pMicrosPerSecond;
2741
+ const cost = rate * input.durationSeconds;
2742
+ if (!Number.isSafeInteger(cost) || cost <= 0 || cost > 1e9) {
2743
+ throw new Error("Video generation credit price exceeds the supported range");
2744
+ }
2745
+ return cost;
2621
2746
  }
2622
2747
  function configuredAllowedReasoningEfforts(settings) {
2623
2748
  return uniqueValues([
@@ -2735,16 +2860,13 @@ function stableSandboxEnvironmentForRun(settings, workspaceEnvironment = {}, opt
2735
2860
  environment.OPENGENI_GIT_CLI_WRAPPER_DIR ??= `${home}/.opengeni/bin`;
2736
2861
  environment.PATH = prependPathEntry(environment.PATH, environment.OPENGENI_GIT_CLI_WRAPPER_DIR);
2737
2862
  }
2738
- if (settings.toolspaceEnabled) {
2739
- environment.OPENGENI_TOOLSPACE_TOKEN_FILE ??= settings.sandboxBackend === "selfhosted" ? "$HOME/.opengeni/toolspace-token" : `${environment.HOME ?? descriptor.workspaceRoot}/.opengeni/toolspace-token`;
2863
+ if (settings.sandboxBackend !== "selfhosted" && resolveFirstPartyDelegationSecret(settings)) {
2864
+ environment.OPENGENI_CODEMODE_TOKEN_FILE ??= `${environment.HOME ?? descriptor.workspaceRoot}/.opengeni/codemode-token`;
2740
2865
  if (settings.ogtoolPackageSpec) {
2741
2866
  environment.OPENGENI_OGTOOL_PACKAGE_SPEC ??= settings.ogtoolPackageSpec;
2742
2867
  }
2743
2868
  if (options.workspaceId) {
2744
- environment.OPENGENI_TOOLSPACE_URL ??= firstPartyMcpWorkspaceUrl(
2745
- settings,
2746
- options.workspaceId
2747
- );
2869
+ environment.OPENGENI_CODEMODE_URL ??= codemodeWorkspaceUrl(settings, options.workspaceId);
2748
2870
  }
2749
2871
  }
2750
2872
  return environment;
@@ -3118,6 +3240,7 @@ function ensureBuiltInMcpServers(settings) {
3118
3240
  "search_documents",
3119
3241
  "fetch_document_chunk",
3120
3242
  "list_document_bases",
3243
+ "list_indexed_documents",
3121
3244
  "knowledge_search",
3122
3245
  "knowledge_fetch",
3123
3246
  "memory_search",
@@ -3143,6 +3266,14 @@ function firstPartyMcpWorkspaceUrl(settings, workspaceId) {
3143
3266
  url.hash = "";
3144
3267
  return url.toString();
3145
3268
  }
3269
+ function codemodeWorkspaceUrl(settings, workspaceId) {
3270
+ const url = new URL(firstPartyMcpWorkspaceUrl(settings, workspaceId));
3271
+ if (!url.pathname.endsWith("/mcp")) {
3272
+ throw new Error("First-party MCP URL cannot be projected to the Codemode endpoint");
3273
+ }
3274
+ url.pathname = `${url.pathname.slice(0, -4)}/codemode`;
3275
+ return url.toString();
3276
+ }
3146
3277
  function firstPartyMcpServerUrl(settings) {
3147
3278
  return firstPartyMcpBaseUrl(settings);
3148
3279
  }
@@ -3154,9 +3285,6 @@ function firstPartyFilesMcpServerUrl(mcpUrl) {
3154
3285
  }
3155
3286
  function validateSettings(settings) {
3156
3287
  temporalConnectionOptions(settings);
3157
- if (settings.toolspaceEnabled && !settings.delegationSecret) {
3158
- throw new Error("OPENGENI_DELEGATION_SECRET is required when OPENGENI_TOOLSPACE_ENABLED=true");
3159
- }
3160
3288
  if (settings.productAccessMode === "managed") {
3161
3289
  if (!settings.publicBaseUrl) {
3162
3290
  throw new Error(
@@ -3206,11 +3334,6 @@ function validateSettings(settings) {
3206
3334
  );
3207
3335
  }
3208
3336
  if (settings.slackClientId) {
3209
- if (!settings.slackSigningSecret) {
3210
- throw new Error(
3211
- "OPENGENI_SLACK_SIGNING_SECRET is required when the OpenGeni Slack app is configured"
3212
- );
3213
- }
3214
3337
  if (!settings.publicBaseUrl) {
3215
3338
  throw new Error(
3216
3339
  "OPENGENI_PUBLIC_BASE_URL is required when the OpenGeni Slack app is configured"
@@ -3249,6 +3372,28 @@ function validateSettings(settings) {
3249
3372
  );
3250
3373
  }
3251
3374
  }
3375
+ if (Boolean(settings.atlassianClientId) !== Boolean(settings.atlassianClientSecret)) {
3376
+ throw new Error(
3377
+ "OPENGENI_ATLASSIAN_CLIENT_ID and OPENGENI_ATLASSIAN_CLIENT_SECRET must be configured together"
3378
+ );
3379
+ }
3380
+ if (settings.atlassianClientId) {
3381
+ if (!settings.publicBaseUrl) {
3382
+ throw new Error(
3383
+ "OPENGENI_PUBLIC_BASE_URL is required when the Atlassian integration is configured"
3384
+ );
3385
+ }
3386
+ if (!settings.publicBaseUrl.startsWith("https://") && !["local", "test"].includes(settings.environment)) {
3387
+ throw new Error(
3388
+ "OPENGENI_PUBLIC_BASE_URL must use https when the Atlassian integration is configured outside local/test"
3389
+ );
3390
+ }
3391
+ if (!settings.integrationsStateSecret) {
3392
+ throw new Error(
3393
+ "OPENGENI_INTEGRATIONS_STATE_SECRET is required when the Atlassian integration is configured"
3394
+ );
3395
+ }
3396
+ }
3252
3397
  parseIntegrationsOauthClientsJson(settings.integrationsOauthClientsJson);
3253
3398
  parseSocialOauthClientsJson(settings.socialOauthClientsJson);
3254
3399
  if (settings.productAccessMode === "configured" && !["local", "test"].includes(settings.environment) && !settings.delegationSecret && !settings.authRequired) {
@@ -3400,6 +3545,7 @@ function validateSettings(settings) {
3400
3545
  {
3401
3546
  const reaperPeriod = settings.sandboxLeaseReaperPeriodMs;
3402
3547
  const viewerTtl = settings.sandboxViewerHolderTtlMs;
3548
+ const interactionTtl = settings.sandboxInteractionHolderTtlMs;
3403
3549
  const idleGraceMs = settings.sandboxIdleGraceMs;
3404
3550
  const providerLifetimeMs = settings.modalTimeoutSeconds * 1e3;
3405
3551
  const rotationLeadMs = settings.sandboxRotationLeadMs;
@@ -3409,6 +3555,11 @@ function validateSettings(settings) {
3409
3555
  `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.`
3410
3556
  );
3411
3557
  }
3558
+ if (!(reaperPeriod < interactionTtl)) {
3559
+ throw new Error(
3560
+ `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.`
3561
+ );
3562
+ }
3412
3563
  if (!(idleTimeoutMs <= providerLifetimeMs)) {
3413
3564
  throw new Error(
3414
3565
  `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.`
@@ -3419,9 +3570,10 @@ function validateSettings(settings) {
3419
3570
  `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must be strictly less than OPENGENI_MODAL_TIMEOUT_SECONDS*1000 (${providerLifetimeMs}).`
3420
3571
  );
3421
3572
  }
3422
- if (!(rotationLeadMs > settings.sandboxSnapshotTimeoutMs + 2 * reaperPeriod)) {
3573
+ const captureTimeoutMs = sandboxArchiveCaptureTimeoutMs(settings);
3574
+ if (!(rotationLeadMs > captureTimeoutMs + reaperPeriod)) {
3423
3575
  throw new Error(
3424
- `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the snapshot timeout plus two reaper periods (${settings.sandboxSnapshotTimeoutMs + 2 * reaperPeriod}).`
3576
+ `OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the durable capture timeout plus one reaper period (${captureTimeoutMs + reaperPeriod}).`
3425
3577
  );
3426
3578
  }
3427
3579
  if (!(viewerTtl < idleTimeoutMs)) {
@@ -3429,6 +3581,11 @@ function validateSettings(settings) {
3429
3581
  `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).`
3430
3582
  );
3431
3583
  }
3584
+ if (!(interactionTtl < idleTimeoutMs)) {
3585
+ throw new Error(
3586
+ `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.`
3587
+ );
3588
+ }
3432
3589
  if (!(reaperPeriod + idleGraceMs < idleTimeoutMs)) {
3433
3590
  throw new Error(
3434
3591
  `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.`
@@ -3565,7 +3722,12 @@ export {
3565
3722
  OPENGENI_GATEWAY_PROVIDER_ID,
3566
3723
  OPENGENI_REALTIME_MODEL_ID_PREFIX,
3567
3724
  RegistryProviderKind,
3725
+ SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS,
3726
+ SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS,
3727
+ SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS,
3728
+ SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS,
3568
3729
  SANDBOX_REQUIRED_ENV,
3730
+ SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS,
3569
3731
  SocialOAuthClientConfigSchema,
3570
3732
  VERCEL_AI_GATEWAY_AI_SDK_BASE_URL,
3571
3733
  VERCEL_AI_GATEWAY_BASE_URL,
@@ -3577,9 +3739,13 @@ export {
3577
3739
  applyGitAuthPointerEnvironment,
3578
3740
  assertTurnExecutionPolicyMatchesConfigV1,
3579
3741
  builtinProviderId,
3742
+ calculateGatewayReportedCostBreakdown,
3580
3743
  calculateGatewayReportedCostMicros,
3744
+ calculateModelUsageCostBreakdown,
3581
3745
  calculateModelUsageCostMicros,
3746
+ calculateVideoGenerationCreditCostMicros,
3582
3747
  canonicalizeConfiguredModelId,
3748
+ codemodeWorkspaceUrl,
3583
3749
  collectGitIdentityEnvironment,
3584
3750
  collectSandboxEnvironment,
3585
3751
  configuredAllowedModels,
@@ -3601,6 +3767,7 @@ export {
3601
3767
  getSettings,
3602
3768
  hasGitCredentialRepositorySelection,
3603
3769
  hasGitHubRepositorySelection,
3770
+ isDirectOpenAiApiBaseUrl,
3604
3771
  isUsableVoiceInputSecret,
3605
3772
  parseExposedPorts,
3606
3773
  parseIntegrationsOauthClientsJson,
@@ -3632,6 +3799,7 @@ export {
3632
3799
  sandboxArchiveCaptureTimeoutMs,
3633
3800
  sandboxEnvironmentVariableNames,
3634
3801
  sandboxLifecycleHookIds,
3802
+ sandboxLifecycleTransitionWaitMs,
3635
3803
  sandboxPreparationProfiles,
3636
3804
  sandboxWarmRateMicrosPerSecond,
3637
3805
  selectModelPricing,