@opengeni/config 0.12.1 → 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.d.ts +69 -3
- package/dist/index.js +219 -50
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +330 -50
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,7 @@ 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.
|
|
207
|
+
agentStableVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).default("0.1.14"),
|
|
196
208
|
// Optional independent beta-channel pointer. When unset, the beta update
|
|
197
209
|
// manifest route is unavailable rather than silently serving stable.
|
|
198
210
|
agentBetaVersion: z.string().regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/u).optional(),
|
|
@@ -213,8 +225,7 @@ var SettingsSchema = z.object({
|
|
|
213
225
|
// holder of stream:control gets 403 until this flips. Keeps stream:control a
|
|
214
226
|
// declared-but-inert permission so later hardening is a flag flip.
|
|
215
227
|
streamControlEnabled: EnvBoolean.default(false),
|
|
216
|
-
|
|
217
|
-
toolspaceMaxCallsPerTurn: z.coerce.number().int().positive().default(200),
|
|
228
|
+
codemodeMaxCallsPerTurn: z.coerce.number().int().positive().default(200),
|
|
218
229
|
// Optional release-coherent bootstrap hint for custom rigs/connected machines
|
|
219
230
|
// that do not carry the stock-image ogtool binary. Exact stable versions only:
|
|
220
231
|
// the agent must never guess a tag or silently install `latest`.
|
|
@@ -224,11 +235,15 @@ var SettingsSchema = z.object({
|
|
|
224
235
|
integrationsStateSecret: z.string().optional(),
|
|
225
236
|
integrationsAllowPrivateNetworkTargets: EnvBoolean.default(false),
|
|
226
237
|
integrationsOauthClientsJson: z.string().default("{}"),
|
|
238
|
+
gmailRestAdapterEnabled: EnvBoolean.default(false),
|
|
227
239
|
slackClientId: z.string().optional(),
|
|
228
240
|
slackClientSecret: z.string().optional(),
|
|
229
241
|
slackSigningSecret: z.string().optional(),
|
|
230
242
|
googleDriveClientId: z.string().optional(),
|
|
231
243
|
googleDriveClientSecret: z.string().optional(),
|
|
244
|
+
googleDriveWorkspaceEventsEnabled: EnvBoolean.optional(),
|
|
245
|
+
atlassianClientId: z.string().optional(),
|
|
246
|
+
atlassianClientSecret: z.string().optional(),
|
|
232
247
|
// Undefined is meaningful: the migration boundary persists the product
|
|
233
248
|
// default of 3 when no deployment override is supplied.
|
|
234
249
|
maxNestedAgentDepth: z.coerce.number().int().nonnegative().max(MAX_NESTED_AGENT_DEPTH).optional(),
|
|
@@ -299,6 +314,20 @@ var SettingsSchema = z.object({
|
|
|
299
314
|
// Gateway models below are added to the managed-credit catalog. Workspace
|
|
300
315
|
// Gateway keys use the encrypted connection broker and never this secret.
|
|
301
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),
|
|
302
331
|
// Native composer voice input (browser MediaRecorder → API transcription).
|
|
303
332
|
// Provider credentials stay server-side; ClientConfig only projects availability
|
|
304
333
|
// and hard ceilings. Selection happens once before audio is sent — never retry
|
|
@@ -367,6 +396,11 @@ var SettingsSchema = z.object({
|
|
|
367
396
|
// compatibility diagnosis.
|
|
368
397
|
// OPENGENI_CODEX_TOOL_SEARCH_ENABLED
|
|
369
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),
|
|
370
404
|
// credential allocator atomic, workspace-local credential allocation. Default OFF is a
|
|
371
405
|
// deliberate rolling-deploy fence: migrate + roll every worker first, then
|
|
372
406
|
// enable. Turning it off restores the legacy sticky selector without a schema
|
|
@@ -424,6 +458,13 @@ var SettingsSchema = z.object({
|
|
|
424
458
|
disableOpenaiTracing: EnvBoolean.default(false),
|
|
425
459
|
sandboxBackend: SandboxBackend.default("docker"),
|
|
426
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),
|
|
427
468
|
dockerExposedPorts: z.string().default(""),
|
|
428
469
|
dockerNetwork: z.string().optional(),
|
|
429
470
|
// When the worker itself runs in a container and talks to a host Docker daemon,
|
|
@@ -480,15 +521,14 @@ var SettingsSchema = z.object({
|
|
|
480
521
|
// SOONER than the hard lifetime; the boot invariant forbids a value that would
|
|
481
522
|
// reap before reaperPeriod + idleGrace elapses.
|
|
482
523
|
modalIdleTimeoutSeconds: z.coerce.number().int().positive().optional(),
|
|
483
|
-
// /workspace FILE PERSISTENCE across warm/cold cycles.
|
|
484
|
-
//
|
|
485
|
-
//
|
|
486
|
-
//
|
|
487
|
-
//
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
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"),
|
|
492
532
|
// Shared desktop toggle: this module reads it for the 6080 port-merge; the
|
|
493
533
|
// owner module (P4.x) acts on it to launch the display stack.
|
|
494
534
|
sandboxDesktopEnabled: EnvBoolean.default(false),
|
|
@@ -699,6 +739,10 @@ var SettingsSchema = z.object({
|
|
|
699
739
|
// snapshotted before the box dies (sandbox-file-persistence).
|
|
700
740
|
sandboxLeaseReaperPeriodMs: z.coerce.number().int().positive().default(3e4),
|
|
701
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),
|
|
702
746
|
// The DRAIN grace: how long a refcount-0 (draining) lease stays WARM before the
|
|
703
747
|
// reaper resume-by-ids the box and terminates it. This is the cost-vs-snappiness
|
|
704
748
|
// dial — when the user navigates away the box keeps refcount 0, but it survives
|
|
@@ -724,7 +768,7 @@ var SettingsSchema = z.object({
|
|
|
724
768
|
// graceful shutdown, or become permission to GC an older archive. Timeout is
|
|
725
769
|
// treated exactly like a failed best-effort snapshot. Knob:
|
|
726
770
|
// OPENGENI_SANDBOX_SNAPSHOT_TIMEOUT_MS. Default 60s.
|
|
727
|
-
sandboxSnapshotTimeoutMs: z.coerce.number().int().positive().default(6e4),
|
|
771
|
+
sandboxSnapshotTimeoutMs: z.coerce.number().int().positive().max(SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS).default(6e4),
|
|
728
772
|
// Begin a controlled snapshot/quiesce/drain/rematerialize transition this far
|
|
729
773
|
// ahead of a finite provider deadline. Modal's 24h creation clock cannot be
|
|
730
774
|
// extended; the logical sandbox outlives it by moving to one successor box.
|
|
@@ -734,13 +778,12 @@ var SettingsSchema = z.object({
|
|
|
734
778
|
// an operator deliberately wants more rotation headroom; the boot invariant
|
|
735
779
|
// still requires it to remain below the provider lifetime.
|
|
736
780
|
sandboxRotationLeadMs: z.coerce.number().int().positive().default(36e5),
|
|
737
|
-
// Bound
|
|
738
|
-
//
|
|
739
|
-
//
|
|
740
|
-
//
|
|
741
|
-
//
|
|
742
|
-
|
|
743
|
-
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),
|
|
744
787
|
// expires_at refresh window for a held lease (>> the turn 10s heartbeat so a
|
|
745
788
|
// single missed heartbeat never TTL-reaps a live turn). The warming TTL is the
|
|
746
789
|
// window a cold->warming spawner has to commit warm before a reaper resets it.
|
|
@@ -969,7 +1012,11 @@ var ModelCapabilitiesV1Schema = z.object({
|
|
|
969
1012
|
hostedTools: z.object({
|
|
970
1013
|
webSearch: CapabilityStateV1Schema,
|
|
971
1014
|
xSearch: CapabilityStateV1Schema,
|
|
972
|
-
codeExecution: CapabilityStateV1Schema
|
|
1015
|
+
codeExecution: CapabilityStateV1Schema,
|
|
1016
|
+
imageGeneration: CapabilityStateV1Schema.default({
|
|
1017
|
+
upstream: "unknown",
|
|
1018
|
+
runnable: false
|
|
1019
|
+
})
|
|
973
1020
|
}),
|
|
974
1021
|
inputModalities: z.array(ModelModalityV1).min(1),
|
|
975
1022
|
/** Exact MIME types accepted as typed `input_file`; `text/*` is allowed. */
|
|
@@ -1338,6 +1385,9 @@ function getSettings() {
|
|
|
1338
1385
|
turnWorkerMaxConcurrentTurns: optional("OPENGENI_TURN_WORKER_MAX_CONCURRENT_TURNS"),
|
|
1339
1386
|
turnWorkerTargetCpuUsage: optional("OPENGENI_TURN_WORKER_TARGET_CPU_USAGE"),
|
|
1340
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"),
|
|
1341
1391
|
observabilityStructuredLogs: optional("OPENGENI_OBSERVABILITY_STRUCTURED_LOGS"),
|
|
1342
1392
|
observabilityMetricsEnabled: optional("OPENGENI_OBSERVABILITY_METRICS_ENABLED"),
|
|
1343
1393
|
observabilityOtlpEndpoint: optional("OPENGENI_OTEL_EXPORTER_OTLP_ENDPOINT") ?? optional("OTEL_EXPORTER_OTLP_ENDPOINT"),
|
|
@@ -1362,8 +1412,7 @@ function getSettings() {
|
|
|
1362
1412
|
delegationSecret: optional("OPENGENI_DELEGATION_SECRET"),
|
|
1363
1413
|
streamTokenSecret: optional("OPENGENI_STREAM_TOKEN_SECRET"),
|
|
1364
1414
|
streamControlEnabled: optional("OPENGENI_STREAM_CONTROL_ENABLED"),
|
|
1365
|
-
|
|
1366
|
-
toolspaceMaxCallsPerTurn: optional("OPENGENI_TOOLSPACE_MAX_CALLS_PER_TURN"),
|
|
1415
|
+
codemodeMaxCallsPerTurn: optional("OPENGENI_CODEMODE_MAX_CALLS_PER_TURN"),
|
|
1367
1416
|
ogtoolPackageSpec: optional("OPENGENI_OGTOOL_PACKAGE_SPEC"),
|
|
1368
1417
|
environmentsEncryptionKey: optional("OPENGENI_ENVIRONMENTS_ENCRYPTION_KEY"),
|
|
1369
1418
|
integrationsEnabled: optional("OPENGENI_INTEGRATIONS_ENABLED"),
|
|
@@ -1372,11 +1421,15 @@ function getSettings() {
|
|
|
1372
1421
|
"OPENGENI_INTEGRATIONS_ALLOW_PRIVATE_NETWORK_TARGETS"
|
|
1373
1422
|
),
|
|
1374
1423
|
integrationsOauthClientsJson: optional("OPENGENI_INTEGRATIONS_OAUTH_CLIENTS_JSON"),
|
|
1424
|
+
gmailRestAdapterEnabled: optional("OPENGENI_GMAIL_REST_ADAPTER_ENABLED"),
|
|
1375
1425
|
slackClientId: optional("OPENGENI_SLACK_CLIENT_ID"),
|
|
1376
1426
|
slackClientSecret: optional("OPENGENI_SLACK_CLIENT_SECRET"),
|
|
1377
1427
|
slackSigningSecret: optional("OPENGENI_SLACK_SIGNING_SECRET"),
|
|
1378
1428
|
googleDriveClientId: optional("OPENGENI_GOOGLE_DRIVE_CLIENT_ID"),
|
|
1379
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"),
|
|
1380
1433
|
maxNestedAgentDepth: optional("OPENGENI_MAX_NESTED_AGENT_DEPTH"),
|
|
1381
1434
|
socialOauthClientsJson: optional("OPENGENI_SOCIAL_OAUTH_CLIENTS_JSON"),
|
|
1382
1435
|
goalMaxAutoContinuations: optional("OPENGENI_GOAL_MAX_AUTO_CONTINUATIONS"),
|
|
@@ -1403,6 +1456,24 @@ function getSettings() {
|
|
|
1403
1456
|
openaiModel: optional("OPENGENI_OPENAI_MODEL"),
|
|
1404
1457
|
openaiAllowedModels: optional("OPENGENI_OPENAI_ALLOWED_MODELS"),
|
|
1405
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
|
+
),
|
|
1406
1477
|
voiceInputMaxDurationSeconds: optional("OPENGENI_VOICE_INPUT_MAX_DURATION_SECONDS"),
|
|
1407
1478
|
voiceInputMaxSizeBytes: optional("OPENGENI_VOICE_INPUT_MAX_SIZE_BYTES"),
|
|
1408
1479
|
voiceInputResumableEnabled: optional("OPENGENI_VOICE_INPUT_RESUMABLE_ENABLED"),
|
|
@@ -1434,6 +1505,7 @@ function getSettings() {
|
|
|
1434
1505
|
codexSubscriptionEnabled: optional("OPENGENI_CODEX_SUBSCRIPTION_ENABLED"),
|
|
1435
1506
|
codexConnectedAppsEnabled: optional("OPENGENI_CODEX_CONNECTED_APPS_ENABLED"),
|
|
1436
1507
|
codexToolSearchEnabled: optional("OPENGENI_CODEX_TOOL_SEARCH_ENABLED"),
|
|
1508
|
+
lazyToolSearchEnabled: optional("OPENGENI_LAZY_TOOL_SEARCH_ENABLED"),
|
|
1437
1509
|
codexCredentialLeasingEnabled: optional("OPENGENI_CODEX_CREDENTIAL_LEASING_ENABLED"),
|
|
1438
1510
|
codexFleetPolicyShadowEnabled: optional("OPENGENI_CODEX_FLEET_POLICY_SHADOW_ENABLED"),
|
|
1439
1511
|
codexProductSku: optional("OPENGENI_CODEX_PRODUCT_SKU"),
|
|
@@ -1454,6 +1526,7 @@ function getSettings() {
|
|
|
1454
1526
|
disableOpenaiTracing: optional("OPENGENI_DISABLE_OPENAI_TRACING"),
|
|
1455
1527
|
sandboxBackend: optional("OPENGENI_SANDBOX_BACKEND"),
|
|
1456
1528
|
dockerImage: optional("OPENGENI_DOCKER_IMAGE"),
|
|
1529
|
+
sandboxArtifactRuntimeEnabled: optional("OPENGENI_SANDBOX_ARTIFACT_RUNTIME_ENABLED"),
|
|
1457
1530
|
dockerExposedPorts: optional("OPENGENI_DOCKER_EXPOSED_PORTS"),
|
|
1458
1531
|
dockerNetwork: optional("OPENGENI_DOCKER_NETWORK"),
|
|
1459
1532
|
dockerWorkspaceBaseDir: optional("OPENGENI_DOCKER_WORKSPACE_BASE_DIR"),
|
|
@@ -1536,6 +1609,7 @@ function getSettings() {
|
|
|
1536
1609
|
sandboxSelfhostedControlTimeoutMs: optional("OPENGENI_SANDBOX_SELFHOSTED_CONTROL_TIMEOUT_MS"),
|
|
1537
1610
|
sandboxLeaseReaperPeriodMs: optional("OPENGENI_SANDBOX_LEASE_REAPER_PERIOD_MS"),
|
|
1538
1611
|
sandboxViewerHolderTtlMs: optional("OPENGENI_SANDBOX_VIEWER_HOLDER_TTL_MS"),
|
|
1612
|
+
sandboxInteractionHolderTtlMs: optional("OPENGENI_SANDBOX_INTERACTION_HOLDER_TTL_MS"),
|
|
1539
1613
|
sandboxIdleGraceMs: optional("OPENGENI_SANDBOX_IDLE_GRACE_MS"),
|
|
1540
1614
|
sandboxSnapshotIntervalMs: optional("OPENGENI_SANDBOX_SNAPSHOT_INTERVAL_MS"),
|
|
1541
1615
|
sandboxSnapshotTimeoutMs: optional("OPENGENI_SANDBOX_SNAPSHOT_TIMEOUT_MS"),
|
|
@@ -1626,8 +1700,15 @@ function effectiveModalIdleTimeoutSeconds(settings) {
|
|
|
1626
1700
|
}
|
|
1627
1701
|
function sandboxArchiveCaptureTimeoutMs(settings) {
|
|
1628
1702
|
return Math.min(
|
|
1629
|
-
|
|
1630
|
-
|
|
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
|
|
1631
1712
|
);
|
|
1632
1713
|
}
|
|
1633
1714
|
function collectSandboxEnvironment(settings, source = process.env) {
|
|
@@ -1855,7 +1936,11 @@ function legacyModelCapabilities(settings, input) {
|
|
|
1855
1936
|
runnable: input.hostedWebSearch
|
|
1856
1937
|
},
|
|
1857
1938
|
xSearch: { upstream: "unknown", runnable: false },
|
|
1858
|
-
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
|
+
}
|
|
1859
1944
|
},
|
|
1860
1945
|
inputModalities: input.vision ? ["text", "image"] : ["text"],
|
|
1861
1946
|
inputFileMediaTypes: [
|
|
@@ -2028,6 +2113,18 @@ function builtinPromptCachingForModel(modelId) {
|
|
|
2028
2113
|
const slug = modelId.startsWith(CODEX_MODEL_ID_PREFIX) ? modelId.slice(CODEX_MODEL_ID_PREFIX.length) : modelId;
|
|
2029
2114
|
return slug.startsWith("gpt-5.6-") ? { upstream: "supported", runnable: true, mode: "implicit" } : void 0;
|
|
2030
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
|
+
}
|
|
2031
2128
|
function serviceTierForLatencyMode(providerId, latencyMode) {
|
|
2032
2129
|
if (latencyMode === "standard") {
|
|
2033
2130
|
return void 0;
|
|
@@ -2319,6 +2416,7 @@ function configuredModels(settings) {
|
|
|
2319
2416
|
...legacyModelCapabilities(settings, {
|
|
2320
2417
|
reasoningEffort: true,
|
|
2321
2418
|
hostedWebSearch: settings.webSearchEnabled,
|
|
2419
|
+
hostedImageGeneration: builtinHostedImageGenerationForModel(settings, id),
|
|
2322
2420
|
vision: id.startsWith("gpt-5.6-")
|
|
2323
2421
|
}),
|
|
2324
2422
|
...builtinPromptCachingForModel(id) ? { promptCaching: builtinPromptCachingForModel(id) } : {},
|
|
@@ -2562,6 +2660,9 @@ function configuredEntitlements(settings) {
|
|
|
2562
2660
|
};
|
|
2563
2661
|
}
|
|
2564
2662
|
function calculateModelUsageCostMicros(settings, model, usage, options) {
|
|
2663
|
+
return calculateModelUsageCostBreakdown(settings, model, usage, options).creditCostMicros;
|
|
2664
|
+
}
|
|
2665
|
+
function calculateModelUsageCostBreakdown(settings, model, usage, options) {
|
|
2565
2666
|
const schedule = configuredModelPricingSchedules(settings)[model];
|
|
2566
2667
|
if (!schedule) {
|
|
2567
2668
|
throw new Error(`Missing model pricing for ${model}`);
|
|
@@ -2575,10 +2676,12 @@ function calculateModelUsageCostMicros(settings, model, usage, options) {
|
|
|
2575
2676
|
(rawCostByPricing.get(pricing) ?? 0) + calculateEntryCostMicros(pricing, entry)
|
|
2576
2677
|
);
|
|
2577
2678
|
}
|
|
2578
|
-
let
|
|
2679
|
+
let providerCostMicros = 0;
|
|
2680
|
+
let creditCostMicros = 0;
|
|
2579
2681
|
for (const [pricing, rawCost] of rawCostByPricing) {
|
|
2580
2682
|
const marginBps = pricing.marginBps ?? 0;
|
|
2581
|
-
|
|
2683
|
+
providerCostMicros += rawCost;
|
|
2684
|
+
creditCostMicros += Math.ceil(rawCost * (1e4 + marginBps) / 1e4);
|
|
2582
2685
|
}
|
|
2583
2686
|
const latencyMode = options?.latencyMode ?? "standard";
|
|
2584
2687
|
if (latencyMode !== "standard") {
|
|
@@ -2591,12 +2694,16 @@ function calculateModelUsageCostMicros(settings, model, usage, options) {
|
|
|
2591
2694
|
(mode) => mode.id === latencyMode && mode.runnable
|
|
2592
2695
|
)?.billingMultiplierBps;
|
|
2593
2696
|
if (multiplierBps && multiplierBps > 0) {
|
|
2594
|
-
|
|
2697
|
+
providerCostMicros = Math.ceil(providerCostMicros * multiplierBps / 1e4);
|
|
2698
|
+
creditCostMicros = Math.ceil(creditCostMicros * multiplierBps / 1e4);
|
|
2595
2699
|
}
|
|
2596
2700
|
}
|
|
2597
|
-
return
|
|
2701
|
+
return { providerCostMicros, creditCostMicros };
|
|
2598
2702
|
}
|
|
2599
2703
|
function calculateGatewayReportedCostMicros(settings, model, inferenceCostUsd, options) {
|
|
2704
|
+
return calculateGatewayReportedCostBreakdown(settings, model, inferenceCostUsd, options).creditCostMicros;
|
|
2705
|
+
}
|
|
2706
|
+
function calculateGatewayReportedCostBreakdown(settings, model, inferenceCostUsd, options) {
|
|
2600
2707
|
const schedule = configuredModelPricingSchedules(settings)[model];
|
|
2601
2708
|
if (!schedule) {
|
|
2602
2709
|
throw new Error(`Missing model pricing for ${model}`);
|
|
@@ -2609,14 +2716,33 @@ function calculateGatewayReportedCostMicros(settings, model, inferenceCostUsd, o
|
|
|
2609
2716
|
const fraction = match[2] ?? "";
|
|
2610
2717
|
const decimalDigits = BigInt(`${match[1]}${fraction}`);
|
|
2611
2718
|
const decimalScale = 10n ** BigInt(fraction.length);
|
|
2719
|
+
const providerNumerator = decimalDigits * 1000000n;
|
|
2720
|
+
const providerMicros = (providerNumerator + decimalScale - 1n) / decimalScale;
|
|
2612
2721
|
const marginBps = BigInt(1e4 + (pricing.marginBps ?? 0));
|
|
2613
|
-
const numerator =
|
|
2722
|
+
const numerator = providerNumerator * marginBps;
|
|
2614
2723
|
const denominator = decimalScale * 10000n;
|
|
2615
|
-
const
|
|
2616
|
-
if (
|
|
2724
|
+
const creditMicros = (numerator + denominator - 1n) / denominator;
|
|
2725
|
+
if (providerMicros > BigInt(Number.MAX_SAFE_INTEGER) || creditMicros > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
2617
2726
|
throw new Error("AI Gateway inference cost exceeds the supported billing range");
|
|
2618
2727
|
}
|
|
2619
|
-
return
|
|
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;
|
|
2620
2746
|
}
|
|
2621
2747
|
function configuredAllowedReasoningEfforts(settings) {
|
|
2622
2748
|
return uniqueValues([
|
|
@@ -2734,16 +2860,13 @@ function stableSandboxEnvironmentForRun(settings, workspaceEnvironment = {}, opt
|
|
|
2734
2860
|
environment.OPENGENI_GIT_CLI_WRAPPER_DIR ??= `${home}/.opengeni/bin`;
|
|
2735
2861
|
environment.PATH = prependPathEntry(environment.PATH, environment.OPENGENI_GIT_CLI_WRAPPER_DIR);
|
|
2736
2862
|
}
|
|
2737
|
-
if (settings.
|
|
2738
|
-
environment.
|
|
2863
|
+
if (settings.sandboxBackend !== "selfhosted" && resolveFirstPartyDelegationSecret(settings)) {
|
|
2864
|
+
environment.OPENGENI_CODEMODE_TOKEN_FILE ??= `${environment.HOME ?? descriptor.workspaceRoot}/.opengeni/codemode-token`;
|
|
2739
2865
|
if (settings.ogtoolPackageSpec) {
|
|
2740
2866
|
environment.OPENGENI_OGTOOL_PACKAGE_SPEC ??= settings.ogtoolPackageSpec;
|
|
2741
2867
|
}
|
|
2742
2868
|
if (options.workspaceId) {
|
|
2743
|
-
environment.
|
|
2744
|
-
settings,
|
|
2745
|
-
options.workspaceId
|
|
2746
|
-
);
|
|
2869
|
+
environment.OPENGENI_CODEMODE_URL ??= codemodeWorkspaceUrl(settings, options.workspaceId);
|
|
2747
2870
|
}
|
|
2748
2871
|
}
|
|
2749
2872
|
return environment;
|
|
@@ -3117,6 +3240,7 @@ function ensureBuiltInMcpServers(settings) {
|
|
|
3117
3240
|
"search_documents",
|
|
3118
3241
|
"fetch_document_chunk",
|
|
3119
3242
|
"list_document_bases",
|
|
3243
|
+
"list_indexed_documents",
|
|
3120
3244
|
"knowledge_search",
|
|
3121
3245
|
"knowledge_fetch",
|
|
3122
3246
|
"memory_search",
|
|
@@ -3142,6 +3266,14 @@ function firstPartyMcpWorkspaceUrl(settings, workspaceId) {
|
|
|
3142
3266
|
url.hash = "";
|
|
3143
3267
|
return url.toString();
|
|
3144
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
|
+
}
|
|
3145
3277
|
function firstPartyMcpServerUrl(settings) {
|
|
3146
3278
|
return firstPartyMcpBaseUrl(settings);
|
|
3147
3279
|
}
|
|
@@ -3153,9 +3285,6 @@ function firstPartyFilesMcpServerUrl(mcpUrl) {
|
|
|
3153
3285
|
}
|
|
3154
3286
|
function validateSettings(settings) {
|
|
3155
3287
|
temporalConnectionOptions(settings);
|
|
3156
|
-
if (settings.toolspaceEnabled && !settings.delegationSecret) {
|
|
3157
|
-
throw new Error("OPENGENI_DELEGATION_SECRET is required when OPENGENI_TOOLSPACE_ENABLED=true");
|
|
3158
|
-
}
|
|
3159
3288
|
if (settings.productAccessMode === "managed") {
|
|
3160
3289
|
if (!settings.publicBaseUrl) {
|
|
3161
3290
|
throw new Error(
|
|
@@ -3205,11 +3334,6 @@ function validateSettings(settings) {
|
|
|
3205
3334
|
);
|
|
3206
3335
|
}
|
|
3207
3336
|
if (settings.slackClientId) {
|
|
3208
|
-
if (!settings.slackSigningSecret) {
|
|
3209
|
-
throw new Error(
|
|
3210
|
-
"OPENGENI_SLACK_SIGNING_SECRET is required when the OpenGeni Slack app is configured"
|
|
3211
|
-
);
|
|
3212
|
-
}
|
|
3213
3337
|
if (!settings.publicBaseUrl) {
|
|
3214
3338
|
throw new Error(
|
|
3215
3339
|
"OPENGENI_PUBLIC_BASE_URL is required when the OpenGeni Slack app is configured"
|
|
@@ -3248,6 +3372,28 @@ function validateSettings(settings) {
|
|
|
3248
3372
|
);
|
|
3249
3373
|
}
|
|
3250
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
|
+
}
|
|
3251
3397
|
parseIntegrationsOauthClientsJson(settings.integrationsOauthClientsJson);
|
|
3252
3398
|
parseSocialOauthClientsJson(settings.socialOauthClientsJson);
|
|
3253
3399
|
if (settings.productAccessMode === "configured" && !["local", "test"].includes(settings.environment) && !settings.delegationSecret && !settings.authRequired) {
|
|
@@ -3399,6 +3545,7 @@ function validateSettings(settings) {
|
|
|
3399
3545
|
{
|
|
3400
3546
|
const reaperPeriod = settings.sandboxLeaseReaperPeriodMs;
|
|
3401
3547
|
const viewerTtl = settings.sandboxViewerHolderTtlMs;
|
|
3548
|
+
const interactionTtl = settings.sandboxInteractionHolderTtlMs;
|
|
3402
3549
|
const idleGraceMs = settings.sandboxIdleGraceMs;
|
|
3403
3550
|
const providerLifetimeMs = settings.modalTimeoutSeconds * 1e3;
|
|
3404
3551
|
const rotationLeadMs = settings.sandboxRotationLeadMs;
|
|
@@ -3408,6 +3555,11 @@ function validateSettings(settings) {
|
|
|
3408
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.`
|
|
3409
3556
|
);
|
|
3410
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
|
+
}
|
|
3411
3563
|
if (!(idleTimeoutMs <= providerLifetimeMs)) {
|
|
3412
3564
|
throw new Error(
|
|
3413
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.`
|
|
@@ -3418,9 +3570,10 @@ function validateSettings(settings) {
|
|
|
3418
3570
|
`OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must be strictly less than OPENGENI_MODAL_TIMEOUT_SECONDS*1000 (${providerLifetimeMs}).`
|
|
3419
3571
|
);
|
|
3420
3572
|
}
|
|
3421
|
-
|
|
3573
|
+
const captureTimeoutMs = sandboxArchiveCaptureTimeoutMs(settings);
|
|
3574
|
+
if (!(rotationLeadMs > captureTimeoutMs + reaperPeriod)) {
|
|
3422
3575
|
throw new Error(
|
|
3423
|
-
`OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the
|
|
3576
|
+
`OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the durable capture timeout plus one reaper period (${captureTimeoutMs + reaperPeriod}).`
|
|
3424
3577
|
);
|
|
3425
3578
|
}
|
|
3426
3579
|
if (!(viewerTtl < idleTimeoutMs)) {
|
|
@@ -3428,6 +3581,11 @@ function validateSettings(settings) {
|
|
|
3428
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).`
|
|
3429
3582
|
);
|
|
3430
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
|
+
}
|
|
3431
3589
|
if (!(reaperPeriod + idleGraceMs < idleTimeoutMs)) {
|
|
3432
3590
|
throw new Error(
|
|
3433
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.`
|
|
@@ -3564,7 +3722,12 @@ export {
|
|
|
3564
3722
|
OPENGENI_GATEWAY_PROVIDER_ID,
|
|
3565
3723
|
OPENGENI_REALTIME_MODEL_ID_PREFIX,
|
|
3566
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,
|
|
3567
3729
|
SANDBOX_REQUIRED_ENV,
|
|
3730
|
+
SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS,
|
|
3568
3731
|
SocialOAuthClientConfigSchema,
|
|
3569
3732
|
VERCEL_AI_GATEWAY_AI_SDK_BASE_URL,
|
|
3570
3733
|
VERCEL_AI_GATEWAY_BASE_URL,
|
|
@@ -3576,9 +3739,13 @@ export {
|
|
|
3576
3739
|
applyGitAuthPointerEnvironment,
|
|
3577
3740
|
assertTurnExecutionPolicyMatchesConfigV1,
|
|
3578
3741
|
builtinProviderId,
|
|
3742
|
+
calculateGatewayReportedCostBreakdown,
|
|
3579
3743
|
calculateGatewayReportedCostMicros,
|
|
3744
|
+
calculateModelUsageCostBreakdown,
|
|
3580
3745
|
calculateModelUsageCostMicros,
|
|
3746
|
+
calculateVideoGenerationCreditCostMicros,
|
|
3581
3747
|
canonicalizeConfiguredModelId,
|
|
3748
|
+
codemodeWorkspaceUrl,
|
|
3582
3749
|
collectGitIdentityEnvironment,
|
|
3583
3750
|
collectSandboxEnvironment,
|
|
3584
3751
|
configuredAllowedModels,
|
|
@@ -3600,6 +3767,7 @@ export {
|
|
|
3600
3767
|
getSettings,
|
|
3601
3768
|
hasGitCredentialRepositorySelection,
|
|
3602
3769
|
hasGitHubRepositorySelection,
|
|
3770
|
+
isDirectOpenAiApiBaseUrl,
|
|
3603
3771
|
isUsableVoiceInputSecret,
|
|
3604
3772
|
parseExposedPorts,
|
|
3605
3773
|
parseIntegrationsOauthClientsJson,
|
|
@@ -3631,6 +3799,7 @@ export {
|
|
|
3631
3799
|
sandboxArchiveCaptureTimeoutMs,
|
|
3632
3800
|
sandboxEnvironmentVariableNames,
|
|
3633
3801
|
sandboxLifecycleHookIds,
|
|
3802
|
+
sandboxLifecycleTransitionWaitMs,
|
|
3634
3803
|
sandboxPreparationProfiles,
|
|
3635
3804
|
sandboxWarmRateMicrosPerSecond,
|
|
3636
3805
|
selectModelPricing,
|