@opengeni/config 2.1.1 → 3.0.0-canary.36239117573001
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 +76 -1
- package/dist/index.js +156 -3
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +246 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Entitlements, LatencyMode, ReasoningEffort, SandboxBackend, StaticUsageLimits, TurnExecutionPolicyV1, type TurnExecutionLatencyModeSourceV1, type TurnExecutionModelSourceV1, type TurnExecutionReasoningSourceV1, type VideoGenerationResolution, type FirstPartyMcpToolName as FirstPartyMcpToolNameType } from "@opengeni/contracts";
|
|
2
|
+
import type { CodeSearchDeploymentPolicy } from "@opengeni/contracts/code-search";
|
|
2
3
|
export { XAI_SUBSCRIPTION_MODEL_ID_PREFIX } from "@opengeni/xai-subscription";
|
|
3
4
|
import { z } from "zod";
|
|
4
5
|
export declare const DEFAULT_OPENROUTER_MODEL_ID: "openrouter/nvidia/nemotron-3-super-120b-a12b:free";
|
|
@@ -128,8 +129,10 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
128
129
|
analyticsPosthogHost: z.ZodOptional<z.ZodString>;
|
|
129
130
|
analyticsGa4MeasurementId: z.ZodOptional<z.ZodString>;
|
|
130
131
|
publicBaseUrl: z.ZodOptional<z.ZodString>;
|
|
132
|
+
documentationUrl: z.ZodPreprocess<z.ZodDefault<z.ZodNullable<z.ZodURL>>>;
|
|
131
133
|
mcpOauthEnabled: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
|
|
132
|
-
|
|
134
|
+
apiTrustedProxyHops: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
135
|
+
apiTrustedProxyCidrs: z.ZodDefault<z.ZodString>;
|
|
133
136
|
webBaseUrl: z.ZodOptional<z.ZodString>;
|
|
134
137
|
agentReleasesBaseUrl: z.ZodDefault<z.ZodString>;
|
|
135
138
|
agentStableVersion: z.ZodDefault<z.ZodString>;
|
|
@@ -196,6 +199,7 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
196
199
|
computer_targets: "computer_targets";
|
|
197
200
|
connected_machine_enroll_token: "connected_machine_enroll_token";
|
|
198
201
|
connected_machine_remove: "connected_machine_remove";
|
|
202
|
+
custom_mcp_setup_request: "custom_mcp_setup_request";
|
|
199
203
|
editable_artifact_apply: "editable_artifact_apply";
|
|
200
204
|
editable_artifact_create: "editable_artifact_create";
|
|
201
205
|
editable_artifact_export: "editable_artifact_export";
|
|
@@ -368,6 +372,7 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
368
372
|
computer_targets: "computer_targets";
|
|
369
373
|
connected_machine_enroll_token: "connected_machine_enroll_token";
|
|
370
374
|
connected_machine_remove: "connected_machine_remove";
|
|
375
|
+
custom_mcp_setup_request: "custom_mcp_setup_request";
|
|
371
376
|
editable_artifact_apply: "editable_artifact_apply";
|
|
372
377
|
editable_artifact_create: "editable_artifact_create";
|
|
373
378
|
editable_artifact_export: "editable_artifact_export";
|
|
@@ -561,10 +566,12 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
561
566
|
authAllowMetrics: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
|
|
562
567
|
apiHost: z.ZodDefault<z.ZodString>;
|
|
563
568
|
apiPort: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
569
|
+
apiMetricsPort: z.ZodOptional<z.ZodCoercedNumber<unknown>>;
|
|
564
570
|
workerHttpPort: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
565
571
|
opengeniMcpInternalUrl: z.ZodOptional<z.ZodString>;
|
|
566
572
|
opengeniMcpUrl: z.ZodOptional<z.ZodString>;
|
|
567
573
|
corsAllowOriginRegex: z.ZodDefault<z.ZodString>;
|
|
574
|
+
localAllowedOrigins: z.ZodOptional<z.ZodString>;
|
|
568
575
|
openaiProvider: z.ZodDefault<z.ZodEnum<{
|
|
569
576
|
azure: "azure";
|
|
570
577
|
openai: "openai";
|
|
@@ -636,6 +643,16 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
636
643
|
xhigh: "xhigh";
|
|
637
644
|
}>>;
|
|
638
645
|
openaiAllowedReasoningEfforts: z.ZodDefault<z.ZodString>;
|
|
646
|
+
creditsDefaultModel: z.ZodDefault<z.ZodString>;
|
|
647
|
+
creditsDefaultReasoningEffort: z.ZodDefault<z.ZodEnum<{
|
|
648
|
+
high: "high";
|
|
649
|
+
low: "low";
|
|
650
|
+
max: "max";
|
|
651
|
+
medium: "medium";
|
|
652
|
+
minimal: "minimal";
|
|
653
|
+
none: "none";
|
|
654
|
+
xhigh: "xhigh";
|
|
655
|
+
}>>;
|
|
639
656
|
openaiResponsesTransport: z.ZodDefault<z.ZodEnum<{
|
|
640
657
|
http: "http";
|
|
641
658
|
websocket: "websocket";
|
|
@@ -647,6 +664,16 @@ declare const SettingsSchema: z.ZodObject<{
|
|
|
647
664
|
openaiReasoningEncryptedContent: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
|
|
648
665
|
openaiMaxRetries: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
649
666
|
webSearchEnabled: z.ZodDefault<z.ZodPreprocess<z.ZodBoolean>>;
|
|
667
|
+
jevApiKey: z.ZodOptional<z.ZodString>;
|
|
668
|
+
jevBaseUrl: z.ZodDefault<z.ZodString>;
|
|
669
|
+
jevModel: z.ZodDefault<z.ZodString>;
|
|
670
|
+
jevRequestTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
671
|
+
codeSearchMode: z.ZodDefault<z.ZodEnum<{
|
|
672
|
+
default_on: "default_on";
|
|
673
|
+
experiment: "experiment";
|
|
674
|
+
off: "off";
|
|
675
|
+
opt_in: "opt_in";
|
|
676
|
+
}>>;
|
|
650
677
|
agentInstructionsTemplate: z.ZodDefault<z.ZodString>;
|
|
651
678
|
azureOpenaiBaseUrl: z.ZodOptional<z.ZodString>;
|
|
652
679
|
azureOpenaiEndpoint: z.ZodOptional<z.ZodString>;
|
|
@@ -1077,6 +1104,15 @@ export type VoiceInputProviderConfig = {
|
|
|
1077
1104
|
kind: "supergrok-subscription";
|
|
1078
1105
|
experimental: true;
|
|
1079
1106
|
};
|
|
1107
|
+
/** The deployment's Jev key, or undefined when it is missing or a placeholder. */
|
|
1108
|
+
export declare function usableJevApiKey(settings: Pick<Settings, "jevApiKey">): string | undefined;
|
|
1109
|
+
/**
|
|
1110
|
+
* Deployment half of the `code_search` decision. `available` is false when
|
|
1111
|
+
* the mode is off or no usable Jev key is configured; workspaces then cannot
|
|
1112
|
+
* turn it on. `workspaceDefault` applies to workspaces without their own
|
|
1113
|
+
* setting.
|
|
1114
|
+
*/
|
|
1115
|
+
export declare function codeSearchDeploymentPolicy(settings: Pick<Settings, "codeSearchMode" | "jevApiKey">): CodeSearchDeploymentPolicy;
|
|
1080
1116
|
/**
|
|
1081
1117
|
* Reject empty / template secrets so `.env.example` placeholders like
|
|
1082
1118
|
* `your-key` cannot advertise voice input as available and then 401 upstream.
|
|
@@ -2404,6 +2440,20 @@ export interface ConfiguredModel {
|
|
|
2404
2440
|
reasoningEffort: boolean;
|
|
2405
2441
|
hostedWebSearch: boolean;
|
|
2406
2442
|
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Whether a resolved route is the deployment-funded OpenRouter free tier: the
|
|
2445
|
+
* managed OpenRouter provider, which sends every workspace's requests with the
|
|
2446
|
+
* deployment's one OpenRouter key, serving an upstream `:free` variant (the
|
|
2447
|
+
* curated catalog admits nothing else). OpenRouter limits free-variant
|
|
2448
|
+
* requests per account per minute and per day, so each request on this route
|
|
2449
|
+
* spends quota that every turn on the deployment shares. A workspace or
|
|
2450
|
+
* organization OpenRouter connection uses its own account and is not this
|
|
2451
|
+
* route.
|
|
2452
|
+
*/
|
|
2453
|
+
export declare function isManagedOpenRouterFreeRoute(route: {
|
|
2454
|
+
provider: Pick<ResolvedModelProvider, "kind">;
|
|
2455
|
+
configured: Pick<ConfiguredModel, "upstreamModelId">;
|
|
2456
|
+
}): boolean;
|
|
2407
2457
|
export declare const VERCEL_AI_GATEWAY_BASE_URL: "https://ai-gateway.vercel.sh/v1";
|
|
2408
2458
|
export declare const VERCEL_AI_GATEWAY_AI_SDK_BASE_URL: "https://ai-gateway.vercel.sh/v4/ai";
|
|
2409
2459
|
export declare const VERCEL_AI_GATEWAY_CONNECTION_DOMAIN: "ai-gateway.vercel.sh";
|
|
@@ -2960,6 +3010,31 @@ export declare function firstPartyMcpInternalBaseUrl(settings: Settings): string
|
|
|
2960
3010
|
export declare function firstPartyMcpWorkspaceUrl(settings: Settings, workspaceId: string): string;
|
|
2961
3011
|
export declare function firstPartyMcpInternalWorkspaceUrl(settings: Settings, workspaceId: string): string;
|
|
2962
3012
|
export declare function codemodeWorkspaceUrl(settings: Settings, workspaceId: string): string;
|
|
3013
|
+
export type TrustedProxyCidr = {
|
|
3014
|
+
address: string;
|
|
3015
|
+
prefix: number;
|
|
3016
|
+
family: "ipv4" | "ipv6";
|
|
3017
|
+
};
|
|
3018
|
+
/**
|
|
3019
|
+
* Parse `OPENGENI_API_TRUSTED_PROXY_CIDRS`: comma-separated IPv4/IPv6 CIDRs or
|
|
3020
|
+
* single addresses. Throws on any malformed entry so a typo can never widen or
|
|
3021
|
+
* silently disable the trusted proxy set.
|
|
3022
|
+
*/
|
|
3023
|
+
export declare function trustedProxyCidrEntries(raw: string): TrustedProxyCidr[];
|
|
3024
|
+
/**
|
|
3025
|
+
* Parse `OPENGENI_LOCAL_ALLOWED_ORIGINS`: comma-separated exact browser origins
|
|
3026
|
+
* (`http(s)://host[:port]`, no path, query, credentials, or wildcard). Throws on
|
|
3027
|
+
* any malformed entry so a typo can never widen or silently disable the local
|
|
3028
|
+
* browser boundary.
|
|
3029
|
+
*/
|
|
3030
|
+
export declare function localAllowedOriginEntries(raw: string | undefined): string[];
|
|
3031
|
+
/**
|
|
3032
|
+
* Local development only: whether a normalized API path is one a sandbox calls
|
|
3033
|
+
* (Codemode, first-party MCP, and the personal Git broker). The Linux Docker
|
|
3034
|
+
* sandbox route relays only these, and the local API serves only these on the
|
|
3035
|
+
* addresses that only sandboxes use (see `apps/api/src/http/local-browser-boundary.ts`).
|
|
3036
|
+
*/
|
|
3037
|
+
export declare function localSandboxApiRouteAllowed(pathname: string): boolean;
|
|
2963
3038
|
/** Validate one fully resolved, secret-bearing executable catalog. */
|
|
2964
3039
|
export declare function validateModelCatalogSettings(settings: Settings, source?: NodeJS.ProcessEnv): ConfiguredModel[];
|
|
2965
3040
|
/**
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
BillingMode,
|
|
4
4
|
CAPABILITY_DESCRIPTORS,
|
|
5
5
|
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
6
|
+
DEFAULT_OPENGENI_DOCUMENTATION_URL,
|
|
6
7
|
currentAgentLearningToolSelection,
|
|
7
8
|
Entitlements,
|
|
8
9
|
EntitlementsMode,
|
|
@@ -44,6 +45,7 @@ import {
|
|
|
44
45
|
} from "@opengeni/xai-subscription";
|
|
45
46
|
import { XAI_SUBSCRIPTION_MODEL_ID_PREFIX as XAI_SUBSCRIPTION_MODEL_ID_PREFIX2 } from "@opengeni/xai-subscription";
|
|
46
47
|
import { createHash } from "crypto";
|
|
48
|
+
import { isIP } from "net";
|
|
47
49
|
import { z } from "zod";
|
|
48
50
|
var envName = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
49
51
|
var registryId = /^[A-Za-z0-9_-]+$/;
|
|
@@ -231,12 +233,26 @@ var SettingsSchema = z.object({
|
|
|
231
233
|
analyticsPosthogHost: z.string().url().max(2048).optional(),
|
|
232
234
|
analyticsGa4MeasurementId: z.string().max(32).regex(/^G-[A-Z0-9]+$/u).optional(),
|
|
233
235
|
publicBaseUrl: z.string().url().optional(),
|
|
236
|
+
// Product documentation the web console links from its Help menu. Absent
|
|
237
|
+
// means the public OpenGeni docs; `none` hides the link for deployments that
|
|
238
|
+
// publish no documentation of their own.
|
|
239
|
+
documentationUrl: z.preprocess(
|
|
240
|
+
(value) => typeof value === "string" ? value.trim().toLowerCase() === "none" ? null : value.trim() : value,
|
|
241
|
+
z.url({ protocol: /^https?$/u, error: "must be an absolute http(s) URL or none" }).nullable().default(DEFAULT_OPENGENI_DOCUMENTATION_URL)
|
|
242
|
+
),
|
|
234
243
|
// Standards-based OAuth authorization server for external workspace MCP
|
|
235
244
|
// clients. Opt-in because it creates a new public authentication surface.
|
|
236
245
|
mcpOauthEnabled: EnvBoolean.default(false),
|
|
237
|
-
//
|
|
246
|
+
// Client source address for every API rate limit, abuse quota, and auth
|
|
247
|
+
// session record (Better Auth, MCP OAuth registration, enrollment, account
|
|
248
|
+
// setup, login transactions). Forwarded client addresses are ignored by
|
|
249
|
+
// default so a caller cannot choose its own bucket. Operators may trust an
|
|
238
250
|
// exact number of proxy hops only when direct access to the API is blocked.
|
|
239
|
-
|
|
251
|
+
apiTrustedProxyHops: z.coerce.number().int().min(0).max(16).default(0),
|
|
252
|
+
// Optional comma-separated CIDRs (or single addresses) of the proxy that
|
|
253
|
+
// connects to the API. When set, forwarded client addresses are honored
|
|
254
|
+
// only for requests whose transport peer is inside one of them.
|
|
255
|
+
apiTrustedProxyCidrs: z.string().default(""),
|
|
240
256
|
// Browser origin when the web app and API use separate origins in local
|
|
241
257
|
// development. Production normally leaves this unset and uses publicBaseUrl.
|
|
242
258
|
webBaseUrl: z.string().url().optional(),
|
|
@@ -428,6 +444,9 @@ var SettingsSchema = z.object({
|
|
|
428
444
|
authAllowMetrics: EnvBoolean.default(false),
|
|
429
445
|
apiHost: z.string().default("0.0.0.0"),
|
|
430
446
|
apiPort: z.coerce.number().int().positive().default(8e3),
|
|
447
|
+
// When set, GET /metrics is served only on this dedicated internal listener
|
|
448
|
+
// and never on the public API port that an ingress forwards to.
|
|
449
|
+
apiMetricsPort: z.coerce.number().int().positive().optional(),
|
|
431
450
|
workerHttpPort: z.coerce.number().int().positive().default(8001),
|
|
432
451
|
// Worker-side first-party MCP traffic stays on the deployment's internal
|
|
433
452
|
// network. OPENGENI_MCP_URL remains the sandbox/external route used by
|
|
@@ -438,6 +457,11 @@ var SettingsSchema = z.object({
|
|
|
438
457
|
// call the public API with bearer credentials, but never receive credentialed
|
|
439
458
|
// CORS responses.
|
|
440
459
|
corsAllowOriginRegex: z.string().default(String.raw`^https?://(localhost|127\.0\.0\.1)(:\d+)?$`),
|
|
460
|
+
// Local development only (`local` access mode in the `local` environment):
|
|
461
|
+
// extra exact browser origins, comma-separated, that may call the
|
|
462
|
+
// unauthenticated API besides this stack's own web origin. The local browser
|
|
463
|
+
// boundary ignores `corsAllowOriginRegex`.
|
|
464
|
+
localAllowedOrigins: z.string().optional(),
|
|
441
465
|
openaiProvider: z.enum(["openai", "azure"]).default("openai"),
|
|
442
466
|
openaiApiKey: z.string().optional(),
|
|
443
467
|
openaiBaseUrl: z.string().optional(),
|
|
@@ -572,6 +596,18 @@ var SettingsSchema = z.object({
|
|
|
572
596
|
reasoningConfigurationUpdatesEnabled: EnvBoolean.default(false),
|
|
573
597
|
openaiReasoningEffort: ReasoningEffort.default("low"),
|
|
574
598
|
openaiAllowedReasoningEfforts: z.string().default("low,medium,high,xhigh,max"),
|
|
599
|
+
// Default for new chats and scheduled tasks when the workspace has an
|
|
600
|
+
// OpenGeni credit balance, no saved workspace default, and no usable
|
|
601
|
+
// connected subscription, and the deployment default is not already a
|
|
602
|
+
// credits-billed model. Selected only when this model is selectable in the
|
|
603
|
+
// workspace catalog; otherwise the first selectable credits model is used.
|
|
604
|
+
// OPENGENI_CREDITS_DEFAULT_MODEL / OPENGENI_CREDITS_DEFAULT_REASONING_EFFORT.
|
|
605
|
+
creditsDefaultModel: z.string().trim().min(1).max(256).refine((value) => !/[\u000A\u000D|]/u.test(value), {
|
|
606
|
+
message: "credits default model must not contain newlines or the | field separator"
|
|
607
|
+
}).default("gpt-6-luna"),
|
|
608
|
+
// Preferred effort for the credits default. Clamped to the highest effort
|
|
609
|
+
// the selected model supports at or below this value.
|
|
610
|
+
creditsDefaultReasoningEffort: ReasoningEffort.default("xhigh"),
|
|
575
611
|
openaiResponsesTransport: z.enum(["http", "websocket"]).default("http"),
|
|
576
612
|
// Provider-assigned item ids (rs_/msg_/fc_…) in Responses API input are
|
|
577
613
|
// resolved against the provider's server-side response store. That store is
|
|
@@ -597,6 +633,19 @@ var SettingsSchema = z.object({
|
|
|
597
633
|
// merged with the MCP-server tools (getAllTools = [...mcpTools, ...tools])
|
|
598
634
|
// and the sandbox capability tools, never replacing them.
|
|
599
635
|
webSearchEnabled: EnvBoolean.default(true),
|
|
636
|
+
// Jev (TypeSafe's fast judge model) for worker-side agent tools. Without a
|
|
637
|
+
// usable key every Jev-backed feature is off. The key stays on the server
|
|
638
|
+
// (API and worker) and never reaches a sandbox or Connected Machine.
|
|
639
|
+
jevApiKey: z.string().optional(),
|
|
640
|
+
jevBaseUrl: z.string().url().default("https://api.typesafe.ai"),
|
|
641
|
+
jevModel: z.string().trim().min(1).max(128).default("jev-latest"),
|
|
642
|
+
jevRequestTimeoutMs: z.coerce.number().int().positive().max(12e4).default(1e4),
|
|
643
|
+
// Jev-backed `code_search` agent tool. `off` never offers it, `opt_in` offers
|
|
644
|
+
// it only where workspace settings enable it, `default_on` offers it
|
|
645
|
+
// everywhere except workspaces that disable it, and `experiment` gives it to
|
|
646
|
+
// a fixed half of sessions in workspaces without their own setting, for
|
|
647
|
+
// comparison. It also needs jevApiKey.
|
|
648
|
+
codeSearchMode: z.enum(["off", "opt_in", "default_on", "experiment"]).default("off"),
|
|
600
649
|
// Deployment-default agent persona template (the white-label surface). The
|
|
601
650
|
// runtime resolves the effective template per turn as
|
|
602
651
|
// per-session-override > per-workspace override > this default, substitutes
|
|
@@ -1272,6 +1321,15 @@ function personalGitHubOAuthCallbackUrl(publicBaseUrl) {
|
|
|
1272
1321
|
function usableDeploymentSecret(value) {
|
|
1273
1322
|
return isUsableVoiceInputSecret(value) ? value : void 0;
|
|
1274
1323
|
}
|
|
1324
|
+
function usableJevApiKey(settings) {
|
|
1325
|
+
return usableDeploymentSecret(settings.jevApiKey);
|
|
1326
|
+
}
|
|
1327
|
+
function codeSearchDeploymentPolicy(settings) {
|
|
1328
|
+
const available = settings.codeSearchMode !== "off" && usableJevApiKey(settings) !== void 0;
|
|
1329
|
+
if (!available) return { available: false, workspaceDefault: "off" };
|
|
1330
|
+
const workspaceDefault = settings.codeSearchMode === "default_on" ? "on" : settings.codeSearchMode === "experiment" ? "split" : "off";
|
|
1331
|
+
return { available, workspaceDefault };
|
|
1332
|
+
}
|
|
1275
1333
|
function isUsableVoiceInputSecret(value) {
|
|
1276
1334
|
if (value == null) return false;
|
|
1277
1335
|
const trimmed = value.trim();
|
|
@@ -1939,6 +1997,9 @@ var IntegrationOAuthClientConfigSchema = z.object({
|
|
|
1939
1997
|
clientSecret: z.string().min(1).optional(),
|
|
1940
1998
|
tokenEndpointAuthMethod: z.enum(["none", "client_secret_post", "client_secret_basic"]).default("none")
|
|
1941
1999
|
});
|
|
2000
|
+
function isManagedOpenRouterFreeRoute(route) {
|
|
2001
|
+
return route.provider.kind === "openrouter-managed" && route.configured.upstreamModelId.endsWith(":free");
|
|
2002
|
+
}
|
|
1942
2003
|
var VERCEL_AI_GATEWAY_BASE_URL = "https://ai-gateway.vercel.sh/v1";
|
|
1943
2004
|
var VERCEL_AI_GATEWAY_AI_SDK_BASE_URL = "https://ai-gateway.vercel.sh/v4/ai";
|
|
1944
2005
|
var VERCEL_AI_GATEWAY_CONNECTION_DOMAIN = "ai-gateway.vercel.sh";
|
|
@@ -2377,8 +2438,10 @@ function getSettings(source = process.env) {
|
|
|
2377
2438
|
analyticsPosthogHost: optional("OPENGENI_ANALYTICS_POSTHOG_HOST"),
|
|
2378
2439
|
analyticsGa4MeasurementId: optional("OPENGENI_ANALYTICS_GA4_MEASUREMENT_ID"),
|
|
2379
2440
|
publicBaseUrl: optional("OPENGENI_PUBLIC_BASE_URL"),
|
|
2441
|
+
documentationUrl: optional("OPENGENI_DOCUMENTATION_URL"),
|
|
2380
2442
|
mcpOauthEnabled: optional("OPENGENI_MCP_OAUTH_ENABLED"),
|
|
2381
|
-
|
|
2443
|
+
apiTrustedProxyHops: optional("OPENGENI_API_TRUSTED_PROXY_HOPS"),
|
|
2444
|
+
apiTrustedProxyCidrs: optional("OPENGENI_API_TRUSTED_PROXY_CIDRS"),
|
|
2382
2445
|
webBaseUrl: optional("OPENGENI_WEB_BASE_URL"),
|
|
2383
2446
|
agentReleasesBaseUrl: optional("OPENGENI_AGENT_RELEASES_BASE_URL"),
|
|
2384
2447
|
agentStableVersion: optional("OPENGENI_AGENT_STABLE_VERSION"),
|
|
@@ -2466,10 +2529,12 @@ function getSettings(source = process.env) {
|
|
|
2466
2529
|
authAllowMetrics: optional("OPENGENI_AUTH_ALLOW_METRICS"),
|
|
2467
2530
|
apiHost: optional("OPENGENI_API_HOST"),
|
|
2468
2531
|
apiPort: optional("OPENGENI_API_PORT"),
|
|
2532
|
+
apiMetricsPort: optional("OPENGENI_API_METRICS_PORT"),
|
|
2469
2533
|
workerHttpPort: optional("OPENGENI_WORKER_HTTP_PORT"),
|
|
2470
2534
|
opengeniMcpInternalUrl: optional("OPENGENI_MCP_INTERNAL_URL"),
|
|
2471
2535
|
opengeniMcpUrl: optional("OPENGENI_MCP_URL"),
|
|
2472
2536
|
corsAllowOriginRegex: optional("OPENGENI_CORS_ALLOW_ORIGIN_REGEX"),
|
|
2537
|
+
localAllowedOrigins: optional("OPENGENI_LOCAL_ALLOWED_ORIGINS"),
|
|
2473
2538
|
openaiProvider: optional("OPENGENI_OPENAI_PROVIDER"),
|
|
2474
2539
|
openaiApiKey: optional("OPENGENI_OPENAI_API_KEY") ?? optional("OPENAI_API_KEY"),
|
|
2475
2540
|
openaiBaseUrl: optional("OPENGENI_OPENAI_BASE_URL") ?? optional("OPENAI_BASE_URL"),
|
|
@@ -2541,11 +2606,18 @@ function getSettings(source = process.env) {
|
|
|
2541
2606
|
),
|
|
2542
2607
|
openaiReasoningEffort: optional("OPENGENI_OPENAI_REASONING_EFFORT"),
|
|
2543
2608
|
openaiAllowedReasoningEfforts: optional("OPENGENI_OPENAI_ALLOWED_REASONING_EFFORTS"),
|
|
2609
|
+
creditsDefaultModel: optional("OPENGENI_CREDITS_DEFAULT_MODEL"),
|
|
2610
|
+
creditsDefaultReasoningEffort: optional("OPENGENI_CREDITS_DEFAULT_REASONING_EFFORT"),
|
|
2544
2611
|
openaiResponsesTransport: optional("OPENGENI_OPENAI_RESPONSES_TRANSPORT"),
|
|
2545
2612
|
openaiProviderItemIds: optional("OPENGENI_OPENAI_PROVIDER_ITEM_IDS"),
|
|
2546
2613
|
openaiReasoningEncryptedContent: optional("OPENGENI_OPENAI_REASONING_ENCRYPTED_CONTENT"),
|
|
2547
2614
|
openaiMaxRetries: optional("OPENGENI_OPENAI_MAX_RETRIES"),
|
|
2548
2615
|
webSearchEnabled: optional("OPENGENI_WEB_SEARCH_ENABLED"),
|
|
2616
|
+
jevApiKey: optional("OPENGENI_JEV_API_KEY"),
|
|
2617
|
+
jevBaseUrl: optional("OPENGENI_JEV_BASE_URL"),
|
|
2618
|
+
jevModel: optional("OPENGENI_JEV_MODEL"),
|
|
2619
|
+
jevRequestTimeoutMs: optional("OPENGENI_JEV_REQUEST_TIMEOUT_MS"),
|
|
2620
|
+
codeSearchMode: optional("OPENGENI_CODE_SEARCH_MODE"),
|
|
2549
2621
|
agentInstructionsTemplate: optional("OPENGENI_AGENT_INSTRUCTIONS_TEMPLATE"),
|
|
2550
2622
|
azureOpenaiBaseUrl: optional("OPENGENI_AZURE_OPENAI_BASE_URL"),
|
|
2551
2623
|
azureOpenaiEndpoint: optional("OPENGENI_AZURE_OPENAI_ENDPOINT"),
|
|
@@ -4900,8 +4972,61 @@ function isDigestPinnedModalDesktopImage(settings) {
|
|
|
4900
4972
|
if (settings.modalImageId) return true;
|
|
4901
4973
|
return typeof settings.modalImageRef === "string" && MODAL_DESKTOP_IMAGE_DIGEST_REF.test(settings.modalImageRef);
|
|
4902
4974
|
}
|
|
4975
|
+
function trustedProxyCidrEntries(raw) {
|
|
4976
|
+
const entries = [];
|
|
4977
|
+
for (const entry of raw.split(",")) {
|
|
4978
|
+
const value = entry.trim();
|
|
4979
|
+
if (!value) continue;
|
|
4980
|
+
const slash = value.indexOf("/");
|
|
4981
|
+
const address = slash < 0 ? value : value.slice(0, slash);
|
|
4982
|
+
const version = isIP(address);
|
|
4983
|
+
const family = version === 4 ? "ipv4" : version === 6 ? "ipv6" : null;
|
|
4984
|
+
const maxPrefix = family === "ipv4" ? 32 : 128;
|
|
4985
|
+
const prefixText = slash < 0 ? String(maxPrefix) : value.slice(slash + 1);
|
|
4986
|
+
const prefix = /^\d{1,3}$/u.test(prefixText) ? Number(prefixText) : Number.NaN;
|
|
4987
|
+
if (!family || !Number.isInteger(prefix) || prefix < 0 || prefix > maxPrefix) {
|
|
4988
|
+
throw new Error(
|
|
4989
|
+
`OPENGENI_API_TRUSTED_PROXY_CIDRS entry "${value.slice(0, 64)}" is not an IP address or CIDR range`
|
|
4990
|
+
);
|
|
4991
|
+
}
|
|
4992
|
+
entries.push({ address, prefix, family });
|
|
4993
|
+
}
|
|
4994
|
+
return entries;
|
|
4995
|
+
}
|
|
4996
|
+
function localAllowedOriginEntries(raw) {
|
|
4997
|
+
const origins = [];
|
|
4998
|
+
for (const entry of (raw ?? "").split(",")) {
|
|
4999
|
+
const value = entry.trim();
|
|
5000
|
+
if (!value) continue;
|
|
5001
|
+
let url = null;
|
|
5002
|
+
try {
|
|
5003
|
+
url = new URL(value);
|
|
5004
|
+
} catch {
|
|
5005
|
+
url = null;
|
|
5006
|
+
}
|
|
5007
|
+
if (!url || url.protocol !== "http:" && url.protocol !== "https:" || url.username || url.password || url.hostname.includes("*") || url.pathname !== "/" || url.search || url.hash || value.endsWith("?") || value.endsWith("#")) {
|
|
5008
|
+
throw new Error(
|
|
5009
|
+
`OPENGENI_LOCAL_ALLOWED_ORIGINS entry "${value.slice(0, 64)}" is not an exact http(s) origin such as http://127.0.0.1:5173`
|
|
5010
|
+
);
|
|
5011
|
+
}
|
|
5012
|
+
origins.push(url.origin);
|
|
5013
|
+
}
|
|
5014
|
+
return origins;
|
|
5015
|
+
}
|
|
5016
|
+
var LOCAL_SANDBOX_API_ROUTES = [
|
|
5017
|
+
// Codemode calls, journal reads, catalog, and the Site/SDK proxy.
|
|
5018
|
+
/^\/v1\/workspaces\/[^/]+\/codemode(?:\/|$)/u,
|
|
5019
|
+
// First-party MCP, including its /docs and /files servers.
|
|
5020
|
+
/^\/v1\/workspaces\/[^/]+\/mcp(?:\/|$)/u,
|
|
5021
|
+
// The personal GitHub HTTPS smart-Git broker.
|
|
5022
|
+
/^\/v1\/git\/personal\/[A-Za-z0-9_-]{43}\/(?:info\/refs|git-upload-pack|git-receive-pack)$/u
|
|
5023
|
+
];
|
|
5024
|
+
function localSandboxApiRouteAllowed(pathname) {
|
|
5025
|
+
return LOCAL_SANDBOX_API_ROUTES.some((route) => route.test(pathname));
|
|
5026
|
+
}
|
|
4903
5027
|
function validateSettings(settings, source = process.env) {
|
|
4904
5028
|
temporalConnectionOptions(settings);
|
|
5029
|
+
localAllowedOriginEntries(settings.localAllowedOrigins);
|
|
4905
5030
|
if (settings.organizationUserSetupEmailTokenTransport === "query" && !settings.organizationUserSetupQueryEdgeSanitizationConfirmed) {
|
|
4906
5031
|
throw new Error(
|
|
4907
5032
|
"OPENGENI_ORGANIZATION_USER_SETUP_QUERY_EDGE_SANITIZATION_CONFIRMED=true is required when OPENGENI_ORGANIZATION_USER_SETUP_EMAIL_TOKEN_TRANSPORT=query"
|
|
@@ -4984,6 +5109,18 @@ function validateSettings(settings, source = process.env) {
|
|
|
4984
5109
|
);
|
|
4985
5110
|
}
|
|
4986
5111
|
}
|
|
5112
|
+
const retiredTrustedProxyHops = source.OPENGENI_MCP_OAUTH_TRUSTED_PROXY_HOPS?.trim();
|
|
5113
|
+
if (retiredTrustedProxyHops && retiredTrustedProxyHops !== "0") {
|
|
5114
|
+
throw new Error(
|
|
5115
|
+
"OPENGENI_MCP_OAUTH_TRUSTED_PROXY_HOPS was renamed to OPENGENI_API_TRUSTED_PROXY_HOPS, which now sets the client address for every API rate limit and auth session; rename the variable"
|
|
5116
|
+
);
|
|
5117
|
+
}
|
|
5118
|
+
const trustedProxyCidrs = trustedProxyCidrEntries(settings.apiTrustedProxyCidrs);
|
|
5119
|
+
if (trustedProxyCidrs.length > 0 && settings.apiTrustedProxyHops === 0) {
|
|
5120
|
+
throw new Error(
|
|
5121
|
+
"OPENGENI_API_TRUSTED_PROXY_CIDRS requires OPENGENI_API_TRUSTED_PROXY_HOPS greater than 0"
|
|
5122
|
+
);
|
|
5123
|
+
}
|
|
4987
5124
|
if (settings.mcpOauthEnabled) {
|
|
4988
5125
|
if (settings.productAccessMode === "configured") {
|
|
4989
5126
|
throw new Error(
|
|
@@ -5432,6 +5569,16 @@ function validateModelCatalogSettings(settings, source = process.env) {
|
|
|
5432
5569
|
`The default model ${settings.openaiModel} is not executable in the resolved model catalog`
|
|
5433
5570
|
);
|
|
5434
5571
|
}
|
|
5572
|
+
const explicitCreditsDefault = source.OPENGENI_CREDITS_DEFAULT_MODEL?.trim();
|
|
5573
|
+
if (explicitCreditsDefault && settings.modelCatalogSource === "code" && settings.billingMode === "stripe") {
|
|
5574
|
+
const creditsDefaultId = canonicalizeConfiguredModelId(settings, settings.creditsDefaultModel);
|
|
5575
|
+
const creditsDefault = models.find((model) => model.id === creditsDefaultId);
|
|
5576
|
+
if (creditsDefault?.cost !== "credits") {
|
|
5577
|
+
throw new Error(
|
|
5578
|
+
`OPENGENI_CREDITS_DEFAULT_MODEL ${settings.creditsDefaultModel} is not a credits-billed model in the resolved model catalog`
|
|
5579
|
+
);
|
|
5580
|
+
}
|
|
5581
|
+
}
|
|
5435
5582
|
const deploymentProductIds = new Set(
|
|
5436
5583
|
models.filter((model) => model.credentialSource.kind === "deployment").map((model) => model.id)
|
|
5437
5584
|
);
|
|
@@ -5687,6 +5834,7 @@ export {
|
|
|
5687
5834
|
calculateVideoGenerationCreditCostMicros,
|
|
5688
5835
|
canonicalPublicOrigin,
|
|
5689
5836
|
canonicalizeConfiguredModelId,
|
|
5837
|
+
codeSearchDeploymentPolicy,
|
|
5690
5838
|
codemodeWorkspaceUrl,
|
|
5691
5839
|
collectGitIdentityEnvironment,
|
|
5692
5840
|
collectSandboxEnvironment,
|
|
@@ -5727,8 +5875,11 @@ export {
|
|
|
5727
5875
|
hasGitCredentialRepositorySelection,
|
|
5728
5876
|
hasGitHubRepositorySelection,
|
|
5729
5877
|
isDirectOpenAiApiBaseUrl,
|
|
5878
|
+
isManagedOpenRouterFreeRoute,
|
|
5730
5879
|
isModelAvailableForNewSelection,
|
|
5731
5880
|
isUsableVoiceInputSecret,
|
|
5881
|
+
localAllowedOriginEntries,
|
|
5882
|
+
localSandboxApiRouteAllowed,
|
|
5732
5883
|
modelCostClassForConfiguredModel,
|
|
5733
5884
|
parseExposedPorts,
|
|
5734
5885
|
parseIntegrationsOauthClientsJson,
|
|
@@ -5777,6 +5928,8 @@ export {
|
|
|
5777
5928
|
startupRetryOptions,
|
|
5778
5929
|
streamTokenDegraded,
|
|
5779
5930
|
temporalConnectionOptions,
|
|
5931
|
+
trustedProxyCidrEntries,
|
|
5932
|
+
usableJevApiKey,
|
|
5780
5933
|
validateModelCatalogSettings,
|
|
5781
5934
|
voiceInputDeploymentConfigured,
|
|
5782
5935
|
withCodexCatalogProvider,
|