@opengeni/config 0.10.1 → 0.10.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/config",
3
- "version": "0.10.1",
3
+ "version": "0.10.6",
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.9",
37
- "@opengeni/contracts": "^0.31.1",
36
+ "@opengeni/codex": "^0.2.10",
37
+ "@opengeni/contracts": "^0.35.0",
38
38
  "zod": "^4.2.1"
39
39
  },
40
40
  "engines": {
package/src/index.ts CHANGED
@@ -108,7 +108,7 @@ export const DEFAULT_AGENT_INSTRUCTIONS = [
108
108
  "Follow the user's task and any enabled pack or skill instructions for the current role.",
109
109
  "Work inside the sandbox workspace and use filesystem and shell tools when useful.",
110
110
  "Repository resources are mounted under repos/<host>/<owner>/<repo> unless the session specifies another collision-free mount path.",
111
- "File resources are mounted under files/<file-id>/ unless the session specifies another mount path.",
111
+ "File resources are mounted under .opengeni/files/<file-id>/ unless the session specifies another mount path.",
112
112
  "Attached files are mounted read-only; copy them before modifying.",
113
113
  "Bundled skills are under .agents/ and can include infrastructure, marketing, or other role-specific guidance.",
114
114
  "Use Checkov, Terraform, Azure CLI, git provider CLIs, and repository tools when relevant; gh, glab, and az repos are pre-authenticated when the host brokers matching git credentials.",
@@ -432,7 +432,7 @@ const SettingsSchema = z.object({
432
432
  // match the UI danger flip (UsageBar danger at pct >= 90). OPENGENI_CODEX_ROTATION_NEAR_EXHAUSTION_PCT.
433
433
  codexRotationNearExhaustionPct: z.coerce.number().int().min(1).max(100).default(90),
434
434
  openaiReasoningEffort: ReasoningEffort.default("low"),
435
- openaiAllowedReasoningEfforts: z.string().default("low,medium,high,xhigh"),
435
+ openaiAllowedReasoningEfforts: z.string().default("low,medium,high,xhigh,max"),
436
436
  openaiResponsesTransport: z.enum(["http", "websocket"]).default("http"),
437
437
  // Provider-assigned item ids (rs_/msg_/fc_…) in Responses API input are
438
438
  // resolved against the provider's server-side response store. That store is
@@ -1176,6 +1176,8 @@ export const ModelCapabilitiesV1Schema = z
1176
1176
  codeExecution: CapabilityStateV1Schema,
1177
1177
  }),
1178
1178
  inputModalities: z.array(ModelModalityV1).min(1),
1179
+ /** Exact MIME types accepted as typed `input_file`; `text/*` is allowed. */
1180
+ inputFileMediaTypes: z.array(z.string()).default([]),
1179
1181
  outputModalities: z.array(ModelModalityV1).min(1),
1180
1182
  transports: z.object({
1181
1183
  sse: CapabilityStateV1Schema,
@@ -1415,7 +1417,7 @@ export interface ConfiguredModel {
1415
1417
  capabilities: ModelCapabilitiesV1;
1416
1418
  requestPolicy?: {
1417
1419
  gateway: {
1418
- only: [string];
1420
+ only: [string, ...string[]];
1419
1421
  caching: "auto" | "none";
1420
1422
  };
1421
1423
  };
@@ -1430,27 +1432,74 @@ export interface ConfiguredModel {
1430
1432
  }
1431
1433
 
1432
1434
  export const VERCEL_AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh/v1" as const;
1435
+ export const VERCEL_AI_GATEWAY_AI_SDK_BASE_URL = "https://ai-gateway.vercel.sh/v4/ai" as const;
1433
1436
  export const OPENGENI_GATEWAY_PROVIDER_ID = "opengeni-gateway" as const;
1434
1437
  export const WORKSPACE_GATEWAY_PROVIDER_ID = "workspace-gateway" as const;
1435
1438
  export const WORKSPACE_GATEWAY_MODEL_ID_PREFIX = "workspace-gateway/" as const;
1436
1439
  export const VERCEL_AI_GATEWAY_CONNECTION_DOMAIN = "ai-gateway.vercel.sh" as const;
1437
1440
  export const VERCEL_AI_GATEWAY_CONNECTION_ROLE = "vercel_ai_gateway" as const;
1438
1441
 
1442
+ export const CODEX_REALTIME_MODEL_ID = "gpt-live-1-boulder-alpha" as const;
1443
+ export const OPENGENI_REALTIME_MODEL_ID_PREFIX = "opengeni-gateway/" as const;
1444
+ export const WORKSPACE_REALTIME_MODEL_ID_PREFIX = "workspace-gateway/" as const;
1445
+
1446
+ /** Curated voice models exposed through AI Gateway's normalized realtime API. */
1447
+ export const AI_GATEWAY_REALTIME_MODELS = {
1448
+ openaiRealtime21: {
1449
+ upstreamModelId: "openai/gpt-realtime-2.1",
1450
+ managedModelId: `${OPENGENI_REALTIME_MODEL_ID_PREFIX}openai/gpt-realtime-2.1`,
1451
+ workspaceModelId: `${WORKSPACE_REALTIME_MODEL_ID_PREFIX}openai/gpt-realtime-2.1`,
1452
+ label: "GPT Realtime 2.1",
1453
+ description: "Best overall voice intelligence",
1454
+ },
1455
+ openaiRealtimeMini: {
1456
+ upstreamModelId: "openai/gpt-realtime-mini",
1457
+ managedModelId: `${OPENGENI_REALTIME_MODEL_ID_PREFIX}openai/gpt-realtime-mini`,
1458
+ workspaceModelId: `${WORKSPACE_REALTIME_MODEL_ID_PREFIX}openai/gpt-realtime-mini`,
1459
+ label: "GPT Realtime Mini",
1460
+ description: "Faster, lighter live voice",
1461
+ },
1462
+ grokVoiceThinkFast20: {
1463
+ upstreamModelId: "xai/grok-voice-think-fast-2.0",
1464
+ managedModelId: `${OPENGENI_REALTIME_MODEL_ID_PREFIX}xai/grok-voice-think-fast-2.0`,
1465
+ workspaceModelId: `${WORKSPACE_REALTIME_MODEL_ID_PREFIX}xai/grok-voice-think-fast-2.0`,
1466
+ label: "Grok Voice Think Fast 2.0",
1467
+ description: "Fast, natural xAI voice",
1468
+ },
1469
+ } as const;
1470
+
1471
+ export type AiGatewayRealtimeModel =
1472
+ (typeof AI_GATEWAY_REALTIME_MODELS)[keyof typeof AI_GATEWAY_REALTIME_MODELS];
1473
+
1474
+ export function resolveAiGatewayRealtimeModel(
1475
+ modelId: string,
1476
+ ): { source: "managed" | "workspace"; upstreamModelId: string } | null {
1477
+ for (const model of Object.values(AI_GATEWAY_REALTIME_MODELS)) {
1478
+ if (model.managedModelId === modelId) {
1479
+ return { source: "managed", upstreamModelId: model.upstreamModelId };
1480
+ }
1481
+ if (model.workspaceModelId === modelId) {
1482
+ return { source: "workspace", upstreamModelId: model.upstreamModelId };
1483
+ }
1484
+ }
1485
+ return null;
1486
+ }
1487
+
1439
1488
  export const OPENGENI_GATEWAY_MODELS = {
1440
1489
  deepseek: {
1441
1490
  productId: "deepseek-v4-flash-0731",
1442
1491
  workspaceProductId: `${WORKSPACE_GATEWAY_MODEL_ID_PREFIX}deepseek-v4-flash-0731`,
1443
1492
  upstreamModelId: "deepseek/deepseek-v4-flash-0731",
1444
1493
  label: "DeepSeek V4 Flash 0731",
1445
- provider: "deepinfra",
1494
+ providers: ["baseten", "novita", "deepinfra"],
1446
1495
  implicitCaching: true,
1447
1496
  },
1448
1497
  kimi: {
1449
- productId: "kimi-k3-fast",
1450
- workspaceProductId: `${WORKSPACE_GATEWAY_MODEL_ID_PREFIX}kimi-k3-fast`,
1451
- upstreamModelId: "moonshotai/kimi-k3-fast",
1452
- label: "Kimi K3 Fast",
1453
- provider: "wafer",
1498
+ productId: "kimi-k3",
1499
+ workspaceProductId: `${WORKSPACE_GATEWAY_MODEL_ID_PREFIX}kimi-k3`,
1500
+ upstreamModelId: "moonshotai/kimi-k3",
1501
+ label: "Kimi K3",
1502
+ providers: ["baseten", "fireworks"],
1454
1503
  implicitCaching: true,
1455
1504
  },
1456
1505
  } as const;
@@ -1529,24 +1578,24 @@ export const defaultModelPricing: Record<string, ModelPricingScheduleV1> = {
1529
1578
  },
1530
1579
  ],
1531
1580
  },
1532
- // Vercel AI Gateway endpoint prices, provider-pinned in the runtime.
1533
- // Snapshot: 2026-08-02. Both pinned routes returned discounted implicit
1534
- // cache reads in live Gateway responses. Wafer/Kimi reported $0.45/M even
1535
- // though the provider-discovery flag currently says otherwise; bill from
1536
- // the response-backed rate, not that inconsistent boolean.
1581
+ // Conservative Vercel AI Gateway fallback prices. Normal managed Gateway
1582
+ // billing uses the exact response Gateway `cost` / `inferenceCost` and applies
1583
+ // the same margin. These token rates are used only if that
1584
+ // metadata is absent. DeepSeek therefore carries the highest approved route
1585
+ // (Novita); both approved Kimi routes have the same list price.
1537
1586
  [OPENGENI_GATEWAY_MODELS.deepseek.productId]: {
1538
1587
  default: {
1539
- inputMicrosPerMillionTokens: 90_000,
1540
- cachedInputMicrosPerMillionTokens: 18_000,
1541
- outputMicrosPerMillionTokens: 180_000,
1588
+ inputMicrosPerMillionTokens: 140_000,
1589
+ cachedInputMicrosPerMillionTokens: 28_000,
1590
+ outputMicrosPerMillionTokens: 280_000,
1542
1591
  marginBps: 2_500,
1543
1592
  },
1544
1593
  },
1545
1594
  [OPENGENI_GATEWAY_MODELS.kimi.productId]: {
1546
1595
  default: {
1547
- inputMicrosPerMillionTokens: 4_500_000,
1548
- cachedInputMicrosPerMillionTokens: 450_000,
1549
- outputMicrosPerMillionTokens: 22_500_000,
1596
+ inputMicrosPerMillionTokens: 3_000_000,
1597
+ cachedInputMicrosPerMillionTokens: 300_000,
1598
+ outputMicrosPerMillionTokens: 15_000_000,
1550
1599
  marginBps: 2_500,
1551
1600
  },
1552
1601
  },
@@ -2224,6 +2273,7 @@ function normalizeCapabilities(capabilities: ModelCapabilitiesV1): ModelCapabili
2224
2273
  inputModalities: [...parsed.inputModalities].sort(
2225
2274
  (left, right) => (MODALITY_ORDER.get(left) ?? 0) - (MODALITY_ORDER.get(right) ?? 0),
2226
2275
  ),
2276
+ inputFileMediaTypes: [...new Set(parsed.inputFileMediaTypes)].sort(),
2227
2277
  outputModalities: [...parsed.outputModalities].sort(
2228
2278
  (left, right) => (MODALITY_ORDER.get(left) ?? 0) - (MODALITY_ORDER.get(right) ?? 0),
2229
2279
  ),
@@ -2236,7 +2286,7 @@ function normalizeCapabilities(capabilities: ModelCapabilitiesV1): ModelCapabili
2236
2286
 
2237
2287
  function legacyModelCapabilities(
2238
2288
  settings: Settings,
2239
- input: { reasoningEffort: boolean; hostedWebSearch: boolean },
2289
+ input: { reasoningEffort: boolean; hostedWebSearch: boolean; vision?: boolean },
2240
2290
  ): ModelCapabilitiesV1 {
2241
2291
  const reasoningEfforts = input.reasoningEffort ? configuredAllowedReasoningEfforts(settings) : [];
2242
2292
  return normalizeCapabilities({
@@ -2257,7 +2307,14 @@ function legacyModelCapabilities(
2257
2307
  xSearch: { upstream: "unknown", runnable: false },
2258
2308
  codeExecution: { upstream: "unknown", runnable: false },
2259
2309
  },
2260
- inputModalities: ["text"],
2310
+ inputModalities: input.vision ? ["text", "image"] : ["text"],
2311
+ inputFileMediaTypes: [
2312
+ "application/json",
2313
+ "application/pdf",
2314
+ "application/x-yaml",
2315
+ "application/yaml",
2316
+ "text/*",
2317
+ ],
2261
2318
  outputModalities: ["text"],
2262
2319
  transports: {
2263
2320
  sse: { upstream: "unknown", runnable: true },
@@ -2279,7 +2336,7 @@ export function gatewayRequestPolicyForUpstreamModel(
2279
2336
  }
2280
2337
  return {
2281
2338
  gateway: {
2282
- only: [model.provider],
2339
+ only: [...model.providers] as [string, ...string[]],
2283
2340
  caching: model.implicitCaching ? "auto" : "none",
2284
2341
  },
2285
2342
  };
@@ -2287,7 +2344,7 @@ export function gatewayRequestPolicyForUpstreamModel(
2287
2344
 
2288
2345
  function gatewayModelCapabilities(
2289
2346
  settings: Settings,
2290
- input: { implicitCaching: boolean; vision: boolean },
2347
+ input: { implicitCaching: boolean; vision: boolean; inputFileMediaTypes?: string[] },
2291
2348
  ): ModelCapabilitiesV1 {
2292
2349
  const legacy = legacyModelCapabilities(settings, {
2293
2350
  reasoningEffort: true,
@@ -2297,6 +2354,7 @@ function gatewayModelCapabilities(
2297
2354
  ...legacy,
2298
2355
  functionCalling: { upstream: "supported", runnable: true },
2299
2356
  inputModalities: input.vision ? ["text", "image"] : ["text"],
2357
+ inputFileMediaTypes: input.inputFileMediaTypes ?? [],
2300
2358
  transports: {
2301
2359
  ...legacy.transports,
2302
2360
  sse: { upstream: "supported", runnable: true },
@@ -2304,8 +2362,8 @@ function gatewayModelCapabilities(
2304
2362
  promptCaching: input.implicitCaching
2305
2363
  ? { upstream: "supported", runnable: true, mode: "implicit" }
2306
2364
  : { upstream: "unsupported", runnable: false, mode: "none" },
2307
- // "Fast" is part of Kimi's product name, not OpenGeni's separately billed
2308
- // latency mode. Both Gateway products expose only standard here.
2365
+ // Both Gateway products expose one reviewed route policy and no separately
2366
+ // billed latency mode.
2309
2367
  latencyModes: [{ id: "standard", upstream: "supported", runnable: true }],
2310
2368
  });
2311
2369
  }
@@ -2317,19 +2375,23 @@ function gatewayRegistryProvider(
2317
2375
  | { kind: "vercel-gateway-workspace"; apiKey?: string },
2318
2376
  ): RegistryProvider {
2319
2377
  const workspace = input.kind === "vercel-gateway-workspace";
2320
- const models = [OPENGENI_GATEWAY_MODELS.deepseek, OPENGENI_GATEWAY_MODELS.kimi].map((model) => ({
2321
- id: workspace ? model.workspaceProductId : model.productId,
2322
- upstreamModelId: model.upstreamModelId,
2323
- label: model.label,
2324
- capabilities: gatewayModelCapabilities(settings, {
2325
- implicitCaching: model.implicitCaching,
2326
- vision: model === OPENGENI_GATEWAY_MODELS.kimi,
2327
- }),
2328
- contextWindowTokens: 1_000_000,
2329
- effectiveContextWindowTokens: 900_000,
2330
- autoCompactTokenLimit: 850_000,
2331
- toolOutputTruncationTokens: settings.modelToolOutputTruncationTokens,
2332
- }));
2378
+ const models = [OPENGENI_GATEWAY_MODELS.deepseek, OPENGENI_GATEWAY_MODELS.kimi].map((model) => {
2379
+ const kimi = model === OPENGENI_GATEWAY_MODELS.kimi;
2380
+ return {
2381
+ id: workspace ? model.workspaceProductId : model.productId,
2382
+ upstreamModelId: model.upstreamModelId,
2383
+ label: model.label,
2384
+ capabilities: gatewayModelCapabilities(settings, {
2385
+ implicitCaching: model.implicitCaching,
2386
+ vision: kimi,
2387
+ inputFileMediaTypes: kimi ? ["application/pdf"] : [],
2388
+ }),
2389
+ contextWindowTokens: 1_000_000,
2390
+ effectiveContextWindowTokens: 900_000,
2391
+ autoCompactTokenLimit: 850_000,
2392
+ toolOutputTruncationTokens: settings.modelToolOutputTruncationTokens,
2393
+ };
2394
+ });
2333
2395
  return {
2334
2396
  kind: input.kind,
2335
2397
  id: workspace ? WORKSPACE_GATEWAY_PROVIDER_ID : OPENGENI_GATEWAY_PROVIDER_ID,
@@ -2705,6 +2767,7 @@ export function withCodexCatalogProvider(settings: Settings): Settings {
2705
2767
  ...legacyModelCapabilities(settings, {
2706
2768
  reasoningEffort: true,
2707
2769
  hostedWebSearch: true,
2770
+ vision: slug.startsWith("gpt-5.6-"),
2708
2771
  }),
2709
2772
  ...(builtinPromptCachingForModel(`${CODEX_MODEL_ID_PREFIX}${slug}`)
2710
2773
  ? {
@@ -2891,6 +2954,7 @@ export function configuredModels(settings: Settings): ConfiguredModel[] {
2891
2954
  ...legacyModelCapabilities(settings, {
2892
2955
  reasoningEffort: true,
2893
2956
  hostedWebSearch: settings.webSearchEnabled,
2957
+ vision: id.startsWith("gpt-5.6-"),
2894
2958
  }),
2895
2959
  ...(builtinPromptCachingForModel(id)
2896
2960
  ? { promptCaching: builtinPromptCachingForModel(id)! }
@@ -3316,6 +3380,39 @@ export function calculateModelUsageCostMicros(
3316
3380
  return total;
3317
3381
  }
3318
3382
 
3383
+ /**
3384
+ * Convert AI Gateway's exact USD inference cost to OpenGeni credit micros and
3385
+ * apply the configured model margin. Decimal arithmetic is integer-only so a
3386
+ * sub-micro provider charge cannot be lost to floating-point rounding.
3387
+ */
3388
+ export function calculateGatewayReportedCostMicros(
3389
+ settings: Settings,
3390
+ model: string,
3391
+ inferenceCostUsd: string,
3392
+ options?: { inputTokens?: number },
3393
+ ): number {
3394
+ const schedule = configuredModelPricingSchedules(settings)[model];
3395
+ if (!schedule) {
3396
+ throw new Error(`Missing model pricing for ${model}`);
3397
+ }
3398
+ const pricing = selectModelPricing(schedule, positiveInt(options?.inputTokens));
3399
+ const match = /^(0|[1-9]\d*)(?:\.(\d{1,18}))?$/.exec(inferenceCostUsd);
3400
+ if (!match) {
3401
+ throw new Error("Invalid AI Gateway inference cost");
3402
+ }
3403
+ const fraction = match[2] ?? "";
3404
+ const decimalDigits = BigInt(`${match[1]}${fraction}`);
3405
+ const decimalScale = 10n ** BigInt(fraction.length);
3406
+ const marginBps = BigInt(10_000 + (pricing.marginBps ?? 0));
3407
+ const numerator = decimalDigits * 1_000_000n * marginBps;
3408
+ const denominator = decimalScale * 10_000n;
3409
+ const micros = (numerator + denominator - 1n) / denominator;
3410
+ if (micros > BigInt(Number.MAX_SAFE_INTEGER)) {
3411
+ throw new Error("AI Gateway inference cost exceeds the supported billing range");
3412
+ }
3413
+ return Number(micros);
3414
+ }
3415
+
3319
3416
  export function configuredAllowedReasoningEfforts(
3320
3417
  settings: Settings,
3321
3418
  ): Array<z.infer<typeof ReasoningEffort>> {