@opengeni/config 2.1.0 → 2.1.1
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 +23 -0
- package/dist/index.js +75 -7
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +120 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/config",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "OpenGeni runtime configuration: settings resolution, deployment knobs, and config validation shared across the server packages.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@opengeni/codex": "^0.2.
|
|
37
|
-
"@opengeni/contracts": "^5.1.
|
|
36
|
+
"@opengeni/codex": "^0.2.26",
|
|
37
|
+
"@opengeni/contracts": "^5.1.1",
|
|
38
38
|
"@opengeni/xai-subscription": "^0.1.4",
|
|
39
39
|
"zod": "^4.2.1"
|
|
40
40
|
},
|
package/src/index.ts
CHANGED
|
@@ -63,6 +63,9 @@ export const DEFAULT_MODEL_COST_POLICY_JSON = JSON.stringify({
|
|
|
63
63
|
// a configured request timeout may never consume the entire durable claim.
|
|
64
64
|
export const SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS = 60 * 60_000;
|
|
65
65
|
export const SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS = 10_000;
|
|
66
|
+
// Deadline rotation gives retained legacy commands a bounded stop window
|
|
67
|
+
// before capturing the still-running sandbox's current files.
|
|
68
|
+
export const SANDBOX_DEADLINE_COMMAND_STOP_GRACE_MS = 120_000;
|
|
66
69
|
export const SANDBOX_SNAPSHOT_MAX_TIMEOUT_MS =
|
|
67
70
|
SANDBOX_ARCHIVE_CAPTURE_MAX_TIMEOUT_MS - SANDBOX_ARCHIVE_CAPTURE_SETTLEMENT_GRACE_MS;
|
|
68
71
|
export const GOOGLE_DRIVE_PROVIDER_REQUEST_TIMEOUT_MAX_MS = 60_000;
|
|
@@ -353,6 +356,9 @@ const SettingsSchema = z.object({
|
|
|
353
356
|
// variable out to disable it).
|
|
354
357
|
organizationTenancyCanonicalActivationEnabled: EnvBoolean.default(false),
|
|
355
358
|
billingMode: BillingMode.default("disabled"),
|
|
359
|
+
// Explicit launch gate for the one-time $10 verified self-service signup grant.
|
|
360
|
+
// A migration or deployment alone must not start issuing live credits.
|
|
361
|
+
verifiedSignupTrialCreditsEnabled: EnvBoolean.default(false),
|
|
356
362
|
entitlementsMode: EntitlementsMode.default("none"),
|
|
357
363
|
usageLimitsMode: UsageLimitsMode.default("none"),
|
|
358
364
|
staticEntitlementsJson: z.string().default("{}"),
|
|
@@ -1216,6 +1222,7 @@ const SettingsSchema = z.object({
|
|
|
1216
1222
|
// Shape: { "modal": 5, "runloop": 4, ... }. Backends absent here meter
|
|
1217
1223
|
// warm-seconds but accrue NO warm_cost / debit (rate 0).
|
|
1218
1224
|
sandboxWarmRateMicrosPerSecondJson: z.string().default("{}"),
|
|
1225
|
+
sandboxWarmBillingMode: z.enum(["usage_only", "shadow", "credits"]).default("usage_only"),
|
|
1219
1226
|
// Per-workspace warm cap (cumulative warm-seconds since the start of the UTC
|
|
1220
1227
|
// month, summed over sandbox.warm_seconds). 0 = unbounded. A workspace over the
|
|
1221
1228
|
// cap force-drains its VIEWER-ONLY boxes (guarded AND turn_holders=0 — a paying
|
|
@@ -1251,6 +1258,13 @@ const SettingsSchema = z.object({
|
|
|
1251
1258
|
documentEmbeddingDimensions: z.coerce.number().int().positive().default(3072),
|
|
1252
1259
|
documentEmbeddingApiKey: z.string().optional(),
|
|
1253
1260
|
documentEmbeddingBaseUrl: z.string().url().optional(),
|
|
1261
|
+
documentEmbeddingBillingMode: z.enum(["usage_only", "shadow", "credits"]).default("usage_only"),
|
|
1262
|
+
// Explicit commercial cutover. Existing queued revisions remain unpriced;
|
|
1263
|
+
// only jobs created at or after this instant may enter the paid rail.
|
|
1264
|
+
documentEmbeddingCreditsActivatedAt: z.iso.datetime().optional(),
|
|
1265
|
+
// Customer tariff for the exact UTF-8 bytes sent to the embedder. Zero leaves
|
|
1266
|
+
// the paid mode unavailable; no commercial rate is selected by this PR.
|
|
1267
|
+
documentEmbeddingRateMicrosPerMillionBytes: z.coerce.number().int().nonnegative().default(0),
|
|
1254
1268
|
documentCurationProvider: z.enum(["openai", "heuristic", "none"]).default("openai"),
|
|
1255
1269
|
documentCurationModel: z.string().min(1).default("gpt-4o-mini"),
|
|
1256
1270
|
documentCurationApiKey: z.string().optional(),
|
|
@@ -3074,6 +3088,7 @@ export function getSettings(source: NodeJS.ProcessEnv = process.env): Settings {
|
|
|
3074
3088
|
"OPENGENI_ORGANIZATION_TENANCY_CANONICAL_ACTIVATION_ENABLED",
|
|
3075
3089
|
),
|
|
3076
3090
|
billingMode: optional("OPENGENI_BILLING_MODE"),
|
|
3091
|
+
verifiedSignupTrialCreditsEnabled: optional("OPENGENI_VERIFIED_SIGNUP_TRIAL_CREDITS_ENABLED"),
|
|
3077
3092
|
entitlementsMode: optional("OPENGENI_ENTITLEMENTS_MODE"),
|
|
3078
3093
|
usageLimitsMode: optional("OPENGENI_USAGE_LIMITS_MODE"),
|
|
3079
3094
|
staticEntitlementsJson: optional("OPENGENI_STATIC_ENTITLEMENTS_JSON"),
|
|
@@ -3360,6 +3375,7 @@ export function getSettings(source: NodeJS.ProcessEnv = process.env): Settings {
|
|
|
3360
3375
|
sandboxWarmRateMicrosPerSecondJson: optional(
|
|
3361
3376
|
"OPENGENI_SANDBOX_WARM_RATE_MICROS_PER_SECOND_JSON",
|
|
3362
3377
|
),
|
|
3378
|
+
sandboxWarmBillingMode: optional("OPENGENI_SANDBOX_WARM_BILLING_MODE"),
|
|
3363
3379
|
sandboxMaxWarmSecondsPerWorkspace: optional("OPENGENI_SANDBOX_MAX_WARM_SECONDS_PER_WORKSPACE"),
|
|
3364
3380
|
sandboxPreparationProfiles: optional("OPENGENI_SANDBOX_PREPARATION_PROFILES"),
|
|
3365
3381
|
sandboxEnvAllowlist: optional("OPENGENI_SANDBOX_ENV_ALLOWLIST"),
|
|
@@ -3389,6 +3405,13 @@ export function getSettings(source: NodeJS.ProcessEnv = process.env): Settings {
|
|
|
3389
3405
|
documentEmbeddingDimensions: optional("OPENGENI_DOCUMENT_EMBEDDING_DIMENSIONS"),
|
|
3390
3406
|
documentEmbeddingApiKey: optional("OPENGENI_DOCUMENT_EMBEDDING_API_KEY"),
|
|
3391
3407
|
documentEmbeddingBaseUrl: optional("OPENGENI_DOCUMENT_EMBEDDING_BASE_URL"),
|
|
3408
|
+
documentEmbeddingBillingMode: optional("OPENGENI_DOCUMENT_EMBEDDING_BILLING_MODE"),
|
|
3409
|
+
documentEmbeddingCreditsActivatedAt: optional(
|
|
3410
|
+
"OPENGENI_DOCUMENT_EMBEDDING_CREDITS_ACTIVATED_AT",
|
|
3411
|
+
),
|
|
3412
|
+
documentEmbeddingRateMicrosPerMillionBytes: optional(
|
|
3413
|
+
"OPENGENI_DOCUMENT_EMBEDDING_RATE_MICROS_PER_MILLION_BYTES",
|
|
3414
|
+
),
|
|
3392
3415
|
documentCurationProvider: optional("OPENGENI_DOCUMENT_CURATION_PROVIDER"),
|
|
3393
3416
|
documentCurationModel: optional("OPENGENI_DOCUMENT_CURATION_MODEL"),
|
|
3394
3417
|
documentCurationApiKey: optional("OPENGENI_DOCUMENT_CURATION_API_KEY"),
|
|
@@ -3447,7 +3470,21 @@ export function getSettings(source: NodeJS.ProcessEnv = process.env): Settings {
|
|
|
3447
3470
|
: parsed.sandboxIdleGraceMs,
|
|
3448
3471
|
sandboxRotationLeadMs:
|
|
3449
3472
|
raw.sandboxRotationLeadMs === undefined && parsed.sandboxBackend === "modal"
|
|
3450
|
-
? Math.min(
|
|
3473
|
+
? Math.min(
|
|
3474
|
+
3_600_000,
|
|
3475
|
+
Math.max(
|
|
3476
|
+
Math.floor((parsed.modalTimeoutSeconds * 1000) / 2),
|
|
3477
|
+
SANDBOX_DEADLINE_COMMAND_STOP_GRACE_MS +
|
|
3478
|
+
sandboxArchiveCaptureTimeoutMs({
|
|
3479
|
+
sandboxSnapshotTimeoutMs: Math.max(
|
|
3480
|
+
parsed.sandboxSnapshotTimeoutMs,
|
|
3481
|
+
parsed.sandboxDrainSnapshotTimeoutMs ?? parsed.sandboxSnapshotTimeoutMs,
|
|
3482
|
+
),
|
|
3483
|
+
}) +
|
|
3484
|
+
2 * parsed.sandboxLeaseReaperPeriodMs +
|
|
3485
|
+
1,
|
|
3486
|
+
),
|
|
3487
|
+
)
|
|
3451
3488
|
: parsed.sandboxRotationLeadMs,
|
|
3452
3489
|
mcpServers: ensureBuiltInMcpServers(parsed),
|
|
3453
3490
|
};
|
|
@@ -4729,6 +4766,33 @@ function legacyImplicitOpenAiDefinitionVersionFor(
|
|
|
4729
4766
|
});
|
|
4730
4767
|
}
|
|
4731
4768
|
|
|
4769
|
+
function legacyCodexAstraImplicitCachingDefinitionVersionFor(
|
|
4770
|
+
model: ConfiguredModel,
|
|
4771
|
+
provider: ResolvedModelProvider,
|
|
4772
|
+
): string | null {
|
|
4773
|
+
// The GPT-6 rollout only made the already-implicit Codex cache discoverable.
|
|
4774
|
+
// Bound this compatibility to that product/transport and exact declaration;
|
|
4775
|
+
// never normalize explicit caching, another capability, or another model.
|
|
4776
|
+
if (
|
|
4777
|
+
model.id !== "codex/gpt-6-astra" ||
|
|
4778
|
+
model.upstreamModelId !== "gpt-6-astra" ||
|
|
4779
|
+
provider.id !== CODEX_PROVIDER_ID ||
|
|
4780
|
+
provider.kind !== "codex-subscription" ||
|
|
4781
|
+
provider.api !== "responses" ||
|
|
4782
|
+
provider.wireProfile !== "openai" ||
|
|
4783
|
+
canonicalJson(model.capabilities.promptCaching) !==
|
|
4784
|
+
canonicalJson({ upstream: "supported", runnable: true, mode: "implicit" })
|
|
4785
|
+
) {
|
|
4786
|
+
return null;
|
|
4787
|
+
}
|
|
4788
|
+
const { definitionVersion: _definitionVersion, ...modelWithoutVersion } = model;
|
|
4789
|
+
const { promptCaching: _promptCaching, ...capabilities } = model.capabilities;
|
|
4790
|
+
// Recompute, rather than allowlisting an incident hash: all other current
|
|
4791
|
+
// fields must still reproduce the accepted digest. Do not compose this with
|
|
4792
|
+
// the older wire-profile compatibility or rewrite the accepted policy.
|
|
4793
|
+
return definitionVersionFor({ ...modelWithoutVersion, capabilities }, provider);
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4732
4796
|
/**
|
|
4733
4797
|
* The built-in provider's stable id: "openai" on the OpenAI platform, "azure"
|
|
4734
4798
|
* on Azure. Exported because the workspace model-policy gate must attribute
|
|
@@ -5421,6 +5485,16 @@ export function resolveTurnExecutionPolicyV1(
|
|
|
5421
5485
|
});
|
|
5422
5486
|
}
|
|
5423
5487
|
|
|
5488
|
+
/** Explicit accepted execution identity matches, but its definition digest differs. */
|
|
5489
|
+
export class TurnExecutionPolicyDefinitionMismatchError extends Error {
|
|
5490
|
+
readonly code = "turn_execution_policy_definition_mismatch";
|
|
5491
|
+
|
|
5492
|
+
constructor() {
|
|
5493
|
+
super("Turn execution policy does not match the current provider definition");
|
|
5494
|
+
this.name = "TurnExecutionPolicyDefinitionMismatchError";
|
|
5495
|
+
}
|
|
5496
|
+
}
|
|
5497
|
+
|
|
5424
5498
|
/**
|
|
5425
5499
|
* Parse-time validation lives in @opengeni/contracts; this verifier binds a
|
|
5426
5500
|
* present snapshot to the current executable definition and exact turn row.
|
|
@@ -5474,17 +5548,23 @@ export function assertTurnExecutionPolicyMatchesConfigV1(
|
|
|
5474
5548
|
);
|
|
5475
5549
|
const definitionVersionMatches =
|
|
5476
5550
|
parsed.definitionVersion === resolved.model.definitionVersion ||
|
|
5477
|
-
parsed.definitionVersion === legacyImplicitOpenAiDefinitionVersion
|
|
5478
|
-
|
|
5551
|
+
parsed.definitionVersion === legacyImplicitOpenAiDefinitionVersion ||
|
|
5552
|
+
parsed.definitionVersion ===
|
|
5553
|
+
legacyCodexAstraImplicitCachingDefinitionVersionFor(resolved.model, resolved.provider);
|
|
5554
|
+
const identityMismatched =
|
|
5479
5555
|
parsed.providerId !== resolved.provider.id ||
|
|
5480
5556
|
parsed.upstreamModelId !== resolved.model.upstreamModelId ||
|
|
5481
5557
|
parsed.wireApi !== resolved.model.api ||
|
|
5482
|
-
!definitionVersionMatches ||
|
|
5483
5558
|
canonicalJson(parsed.credentialSource) !== canonicalJson(resolved.model.credentialSource) ||
|
|
5484
5559
|
canonicalJson(parsed.billing) !== canonicalJson(resolved.model.billing);
|
|
5485
|
-
|
|
5560
|
+
// Identity/source changes must never enter a rollout-retry classification,
|
|
5561
|
+
// even when their definition digest also differs.
|
|
5562
|
+
if (identityMismatched) {
|
|
5486
5563
|
throw new Error("Turn execution policy does not match the current provider definition");
|
|
5487
5564
|
}
|
|
5565
|
+
if (!definitionVersionMatches) {
|
|
5566
|
+
throw new TurnExecutionPolicyDefinitionMismatchError();
|
|
5567
|
+
}
|
|
5488
5568
|
return { policy: parsed, provider: resolved.provider, model: resolved.model };
|
|
5489
5569
|
}
|
|
5490
5570
|
|
|
@@ -7038,7 +7118,36 @@ function validateSettings(settings: Settings, source: NodeJS.ProcessEnv = proces
|
|
|
7038
7118
|
sandboxEnvironmentVariableNames(settings);
|
|
7039
7119
|
sandboxLifecycleHookIds(settings);
|
|
7040
7120
|
// Fail fast on a malformed warm-rate table (P2.1).
|
|
7041
|
-
parseSandboxWarmRateJson(settings.sandboxWarmRateMicrosPerSecondJson);
|
|
7121
|
+
const warmRates = parseSandboxWarmRateJson(settings.sandboxWarmRateMicrosPerSecondJson);
|
|
7122
|
+
// The meter rounds each settled interval to whole USD micros. Fractional
|
|
7123
|
+
// micros/second would make the total depend on heartbeat frequency; only
|
|
7124
|
+
// integer rates have interval-independent settlement at the same elapsed time.
|
|
7125
|
+
if (
|
|
7126
|
+
settings.sandboxWarmBillingMode === "credits" &&
|
|
7127
|
+
Object.values(warmRates).some((rate) => !Number.isSafeInteger(rate))
|
|
7128
|
+
) {
|
|
7129
|
+
throw new Error(
|
|
7130
|
+
"OPENGENI_SANDBOX_WARM_RATE_MICROS_PER_SECOND_JSON paid rates must be safe integers",
|
|
7131
|
+
);
|
|
7132
|
+
}
|
|
7133
|
+
if (
|
|
7134
|
+
settings.documentEmbeddingBillingMode === "credits" &&
|
|
7135
|
+
settings.documentEmbeddingProvider === "openai" &&
|
|
7136
|
+
settings.documentEmbeddingRateMicrosPerMillionBytes <= 0
|
|
7137
|
+
) {
|
|
7138
|
+
throw new Error(
|
|
7139
|
+
"OPENGENI_DOCUMENT_EMBEDDING_RATE_MICROS_PER_MILLION_BYTES must be positive when paid OpenAI embedding billing is enabled",
|
|
7140
|
+
);
|
|
7141
|
+
}
|
|
7142
|
+
if (
|
|
7143
|
+
settings.documentEmbeddingBillingMode === "credits" &&
|
|
7144
|
+
settings.documentEmbeddingProvider === "openai" &&
|
|
7145
|
+
!settings.documentEmbeddingCreditsActivatedAt
|
|
7146
|
+
) {
|
|
7147
|
+
throw new Error(
|
|
7148
|
+
"OPENGENI_DOCUMENT_EMBEDDING_CREDITS_ACTIVATED_AT is required for paid OpenAI embeddings",
|
|
7149
|
+
);
|
|
7150
|
+
}
|
|
7042
7151
|
if (settings.sandboxBackend === "opensandbox") {
|
|
7043
7152
|
if (!/@sha256:[0-9a-f]{64}$/i.test(settings.openSandboxImage ?? "")) {
|
|
7044
7153
|
throw new Error(
|
|
@@ -7113,11 +7222,13 @@ function validateSettings(settings: Settings, source: NodeJS.ProcessEnv = proces
|
|
|
7113
7222
|
ordinaryCaptureTimeoutMs,
|
|
7114
7223
|
drainCaptureTimeoutMs,
|
|
7115
7224
|
);
|
|
7116
|
-
|
|
7225
|
+
const requiredRotationLeadMs =
|
|
7226
|
+
SANDBOX_DEADLINE_COMMAND_STOP_GRACE_MS + providerDeadlineCaptureTimeoutMs + 2 * reaperPeriod;
|
|
7227
|
+
if (!(rotationLeadMs > requiredRotationLeadMs)) {
|
|
7117
7228
|
throw new Error(
|
|
7118
7229
|
`OPENGENI_SANDBOX_ROTATION_LEAD_MS (${rotationLeadMs}) must exceed the ` +
|
|
7119
|
-
`largest durable snapshot or drain capture timeout
|
|
7120
|
-
`(${
|
|
7230
|
+
`legacy command stop grace, largest durable snapshot or drain capture timeout, and two reaper periods ` +
|
|
7231
|
+
`(${requiredRotationLeadMs}), including for persisted Modal ` +
|
|
7121
7232
|
`leases after a default-backend rollout.`,
|
|
7122
7233
|
);
|
|
7123
7234
|
}
|