@bitkyc08/opencodex 2.7.43-preview.20260728 → 2.8.0
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/README.md +8 -1
- package/bin/ocx.mjs +47 -22
- package/gui/dist/assets/index-BDjpkcRN.js +67 -0
- package/gui/dist/assets/index-BHsKRFh9.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic.ts +15 -6
- package/src/adapters/cursor/discovery.ts +4 -1
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/cursor/native-exec-shell.ts +18 -6
- package/src/adapters/cursor/protobuf-events.ts +24 -2
- package/src/adapters/cursor/protobuf-request.ts +1 -2
- package/src/adapters/cursor/tool-definitions.ts +68 -29
- package/src/adapters/google-wire-compiler.ts +4 -0
- package/src/adapters/google.ts +128 -2
- package/src/adapters/identity.ts +12 -2
- package/src/adapters/kiro.ts +64 -7
- package/src/adapters/mimo-free.ts +2 -0
- package/src/adapters/openai-responses.ts +246 -59
- package/src/claude/agents-inject.ts +5 -0
- package/src/claude/alias.ts +94 -14
- package/src/claude/inbound.ts +26 -9
- package/src/claude/outbound.ts +6 -3
- package/src/cli/account-auth.ts +1 -1
- package/src/cli/agent-driven.ts +37 -0
- package/src/cli/catalog-prewarm.ts +24 -0
- package/src/cli/claude.ts +35 -10
- package/src/cli/doctor.ts +71 -19
- package/src/cli/help.ts +42 -6
- package/src/cli/index.ts +93 -19
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/opencode.ts +701 -0
- package/src/cli/provider-runtime.ts +3 -0
- package/src/cli/provider.ts +31 -10
- package/src/cli/star-prompt.ts +79 -18
- package/src/cli/status.ts +47 -13
- package/src/cli/v2.ts +10 -1
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-lifecycle.ts +4 -1
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +149 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-store.ts +2 -0
- package/src/codex/account-usability.ts +6 -1
- package/src/codex/app-server-processes.ts +511 -0
- package/src/codex/auth-api.ts +293 -34
- package/src/codex/auth-collision.ts +2 -1
- package/src/codex/auth-context.ts +60 -17
- package/src/codex/catalog/bundled.ts +9 -2
- package/src/codex/catalog/parsing.ts +42 -2
- package/src/codex/catalog/provider-fetch.ts +264 -70
- package/src/codex/catalog/sync.ts +45 -8
- package/src/codex/catalog.ts +2 -2
- package/src/codex/features.ts +524 -5
- package/src/codex/history-provider.ts +145 -1
- package/src/codex/inject.ts +114 -14
- package/src/codex/main-account.ts +2 -8
- package/src/codex/pool-rotation.ts +186 -0
- package/src/codex/quota.ts +92 -2
- package/src/codex/routing.ts +695 -106
- package/src/codex/runtime.ts +10 -1
- package/src/codex/shim.ts +4 -1
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +2 -0
- package/src/codex/sync.ts +3 -0
- package/src/config.ts +574 -25
- package/src/generated/jawcode-model-metadata.ts +12 -12
- package/src/github/star-state.ts +191 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +111 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +789 -0
- package/src/images/plan.ts +133 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +6 -20
- package/src/lib/config-ownership.ts +327 -0
- package/src/lib/crash-guard.ts +2 -0
- package/src/lib/destination-policy.ts +132 -7
- package/src/lib/pinned-http.ts +151 -0
- package/src/lib/process-control.ts +2 -2
- package/src/lib/provider-outbound.ts +167 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/shadow-call.ts +30 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/win-exec.ts +12 -2
- package/src/lib/windows-elevation.ts +81 -3
- package/src/lib/windows-secret-acl.ts +189 -12
- package/src/lib/winsw.ts +2 -0
- package/src/oauth/anthropic-routing.ts +570 -0
- package/src/oauth/health.ts +6 -0
- package/src/oauth/index.ts +310 -75
- package/src/oauth/key-providers.ts +38 -8
- package/src/oauth/kimi.ts +2 -0
- package/src/oauth/kiro-credentials.ts +373 -12
- package/src/oauth/kiro.ts +424 -43
- package/src/oauth/login-cli.ts +33 -6
- package/src/oauth/store.ts +56 -4
- package/src/oauth/types.ts +11 -0
- package/src/providers/alibaba-region-migration.ts +16 -3
- package/src/providers/antigravity-models.ts +3 -0
- package/src/providers/api-keys.ts +13 -6
- package/src/providers/derive.ts +8 -2
- package/src/providers/key-failover.ts +24 -4
- package/src/providers/model-discovery.ts +356 -0
- package/src/providers/quota.ts +233 -29
- package/src/providers/registry.ts +125 -3
- package/src/responses/parser.ts +11 -0
- package/src/responses/state.ts +22 -8
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +19 -7
- package/src/server/auth-cors.ts +114 -24
- package/src/server/claude-messages.ts +8 -1
- package/src/server/gui-static.ts +30 -6
- package/src/server/images.ts +303 -9
- package/src/server/index.ts +77 -9
- package/src/server/lifecycle.ts +25 -1
- package/src/server/live.ts +75 -25
- package/src/server/management/agent-settings-routes.ts +106 -8
- package/src/server/management/combo-routes.ts +7 -0
- package/src/server/management/config-routes.ts +22 -7
- package/src/server/management/context.ts +11 -1
- package/src/server/management/logs-usage-routes.ts +167 -3
- package/src/server/management/model-routes.ts +46 -13
- package/src/server/management/oauth-account-routes.ts +163 -17
- package/src/server/management/provider-routes.ts +73 -10
- package/src/server/management/shared.ts +2 -2
- package/src/server/management/sidebar-routes.ts +39 -0
- package/src/server/management/system-restart.ts +172 -0
- package/src/server/management/system-routes.ts +33 -10
- package/src/server/management-api.ts +5 -3
- package/src/server/management-auth.ts +216 -0
- package/src/server/proxy-liveness.ts +14 -3
- package/src/server/responses/compact.ts +21 -13
- package/src/server/responses/core.ts +614 -172
- package/src/server/responses/upstream-error.ts +48 -0
- package/src/server/responses-image-gen-repair.ts +118 -0
- package/src/server/responses-item-id-repair.ts +10 -85
- package/src/server/sse-payload-rewrite.ts +116 -0
- package/src/server/startup-action-control.ts +30 -14
- package/src/server/system-env.ts +28 -10
- package/src/service.ts +284 -19
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +1504 -28
- package/src/storage/policy-job.ts +387 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +53 -0
- package/src/storage/policy.ts +522 -0
- package/src/storage/restore-job.ts +253 -0
- package/src/storage/restore-worker.ts +52 -0
- package/src/storage/storage-mutation-coordinator.ts +109 -0
- package/src/storage/worker-lifecycle.ts +81 -0
- package/src/tray/windows.ts +34 -4
- package/src/types.ts +107 -1
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +36 -18
- package/src/update/job.ts +111 -16
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/usage/debug.ts +2 -0
- package/src/usage/expected-prices.ts +6 -5
- package/src/usage/log.ts +12 -0
- package/src/web-search/loop.ts +57 -16
- package/gui/dist/assets/index-CjKFJHSC.js +0 -65
- package/gui/dist/assets/index-DfVGuN88.css +0 -1
|
@@ -24,7 +24,7 @@ import { modelInList } from "../../types";
|
|
|
24
24
|
import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
|
|
25
25
|
import { getJawcodeModelMetadata, getJawcodeModelMetadataCaseInsensitive, listJawcodeModelMetadata, resolveJawcodeProvider } from "../../generated/jawcode-model-metadata";
|
|
26
26
|
import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
|
|
27
|
-
import { getProviderRegistryEntry } from "../../providers/registry";
|
|
27
|
+
import { getProviderRegistryEntry, providerMatchesRegistryTransport } from "../../providers/registry";
|
|
28
28
|
import { applyProviderContextCap, providerContextCap } from "../../providers/context-cap";
|
|
29
29
|
import { routedSlug, slugEquals, slugsEquivalent } from "../../providers/slug-codec";
|
|
30
30
|
import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
|
|
@@ -39,8 +39,19 @@ import {
|
|
|
39
39
|
targetKey,
|
|
40
40
|
} from "../../combos";
|
|
41
41
|
import type { NormalizedComboConfig } from "../../combos/types";
|
|
42
|
-
import {
|
|
42
|
+
import {
|
|
43
|
+
ProviderOutboundPolicyError,
|
|
44
|
+
providerOutboundGet,
|
|
45
|
+
providerRedirectError,
|
|
46
|
+
} from "../../lib/provider-outbound";
|
|
43
47
|
import { redactSecretString } from "../../lib/redact";
|
|
48
|
+
import {
|
|
49
|
+
extractProviderModelItems,
|
|
50
|
+
readBoundedDiscoveryJson,
|
|
51
|
+
resolveProviderModelDiscovery,
|
|
52
|
+
type ModelDiscoveryResponseFailure,
|
|
53
|
+
type ProviderModelsApiItem,
|
|
54
|
+
} from "../../providers/model-discovery";
|
|
44
55
|
import upstreamModelsSnapshot from "../data/upstream-models.json";
|
|
45
56
|
|
|
46
57
|
|
|
@@ -50,25 +61,72 @@ import { disabledNativeSlugs, hasComboTargets, nativeInputModalities, nativeOpen
|
|
|
50
61
|
import { deriveComboCatalogModel, normalizedOpenAiApiSignature, openAiApiCollisionWarnings, replaceLastComboCatalogOmissions, warnUncataloguedComboOnce } from "./aggregation";
|
|
51
62
|
import type { ComboCatalogOmission } from "./aggregation";
|
|
52
63
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
/** Concurrent gatherRoutedModels callers with the same catalog identity share one live discovery.
|
|
65
|
+
* Keyed by gatherFlightKey so a different config cannot join or evict the wrong flight. */
|
|
66
|
+
interface GatherFlightResult {
|
|
67
|
+
models: CatalogModel[];
|
|
68
|
+
comboOmissions: ComboCatalogOmission[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const gatherInflight = new Map<string, Promise<GatherFlightResult>>();
|
|
72
|
+
|
|
73
|
+
function stableJson(value: unknown): string {
|
|
74
|
+
return JSON.stringify(value, (_key, nested) => {
|
|
75
|
+
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
|
|
76
|
+
return Object.fromEntries(Object.entries(nested as Record<string, unknown>).sort(([a], [b]) => a.localeCompare(b)));
|
|
77
|
+
}
|
|
78
|
+
return nested;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function providerCatalogFingerprint(name: string, prov: OcxProviderConfig): Record<string, unknown> {
|
|
83
|
+
return {
|
|
84
|
+
n: name,
|
|
85
|
+
live: prov.liveModels !== false,
|
|
86
|
+
base: prov.baseUrl ?? "",
|
|
87
|
+
adapter: prov.adapter ?? "",
|
|
88
|
+
models: [...(prov.models ?? [])].sort(),
|
|
89
|
+
selected: [...(prov.selectedModels ?? [])].sort(),
|
|
90
|
+
defaultModel: prov.defaultModel ?? null,
|
|
91
|
+
ctx: prov.contextWindow ?? null,
|
|
92
|
+
ctxW: prov.modelContextWindows ?? null,
|
|
93
|
+
maxIn: prov.modelMaxInputTokens ?? null,
|
|
94
|
+
inMod: prov.modelInputModalities ?? null,
|
|
95
|
+
re: prov.modelReasoningEfforts ?? null,
|
|
96
|
+
defRe: prov.modelDefaultReasoningEfforts ?? null,
|
|
97
|
+
rsSum: prov.modelSupportsReasoningSummaries ?? null,
|
|
98
|
+
rsDel: prov.modelReasoningSummaryDelivery ?? null,
|
|
99
|
+
noVis: [...(prov.noVisionModels ?? [])].sort(),
|
|
100
|
+
ptc: prov.parallelToolCalls ?? null,
|
|
101
|
+
gMode: prov.googleMode ?? null,
|
|
61
102
|
};
|
|
62
|
-
}
|
|
103
|
+
}
|
|
63
104
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
105
|
+
function gatherFlightKey(config: OcxConfig): string {
|
|
106
|
+
const providers = Object.entries(config.providers)
|
|
107
|
+
.filter(([, prov]) => prov.disabled !== true)
|
|
108
|
+
.map(([name, prov]) => providerCatalogFingerprint(name, prov))
|
|
109
|
+
.sort((a, b) => String(a.n).localeCompare(String(b.n)));
|
|
110
|
+
const assembly = stableJson({
|
|
111
|
+
providers,
|
|
112
|
+
disabledModels: [...(config.disabledModels ?? [])].sort(),
|
|
113
|
+
combos: config.combos ?? {},
|
|
114
|
+
customModels: (config.customModels ?? []).map((cm) => ({
|
|
115
|
+
p: cm.provider,
|
|
116
|
+
m: cm.modelId,
|
|
117
|
+
d: cm.displayName ?? null,
|
|
118
|
+
cw: cm.contextWindow ?? null,
|
|
119
|
+
im: cm.inputModalities ?? null,
|
|
120
|
+
})),
|
|
121
|
+
caps: config.providerContextCaps ?? null,
|
|
122
|
+
});
|
|
123
|
+
const digest = createHash("sha256").update(assembly).digest("hex").slice(0, 16);
|
|
124
|
+
return `${digest}#${config.modelCacheTtlMs ?? DEFAULT_MODEL_CACHE_TTL_MS}`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Drop in-flight gather so tests / full cache clears do not reuse a stale promise. */
|
|
128
|
+
export function clearGatherRoutedModelsInflight(): void {
|
|
129
|
+
gatherInflight.clear();
|
|
72
130
|
}
|
|
73
131
|
|
|
74
132
|
export function configuredContextWindow(prov: OcxProviderConfig, id: string): number | undefined {
|
|
@@ -193,31 +251,134 @@ export function isGlm52ModelId(id: string): boolean {
|
|
|
193
251
|
return normalized === "glm-5.2" || normalized === "glm-5.2[1m]";
|
|
194
252
|
}
|
|
195
253
|
|
|
254
|
+
function plainRecord(value: unknown): Record<string, unknown> | undefined {
|
|
255
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
256
|
+
? value as Record<string, unknown>
|
|
257
|
+
: undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const MODEL_DISCOVERY_METADATA_CONTROL_CHARS = /[\u0000-\u001f\u007f-\u009f\u2028\u2029]/;
|
|
261
|
+
|
|
262
|
+
function positiveSafeInteger(...values: unknown[]): number | undefined {
|
|
263
|
+
return values.find(value => typeof value === "number" && Number.isSafeInteger(value) && value > 0) as number | undefined;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function normalizedMetadataString(raw: string, maxLength: number): string | undefined {
|
|
267
|
+
if (raw.length > maxLength * 4 || MODEL_DISCOVERY_METADATA_CONTROL_CHARS.test(raw)) return undefined;
|
|
268
|
+
const normalized = raw.trim().toLowerCase().replace(/\s+/g, "-").slice(0, maxLength);
|
|
269
|
+
return normalized || undefined;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function normalizedStringList(value: unknown, maxItems = 32, maxLength = 64): string[] | undefined {
|
|
273
|
+
if (!Array.isArray(value)) return undefined;
|
|
274
|
+
const out: string[] = [];
|
|
275
|
+
const maxInspectedItems = Math.max(maxItems * 8, maxItems);
|
|
276
|
+
for (let i = 0; i < value.length && i < maxInspectedItems; i += 1) {
|
|
277
|
+
const raw = value[i];
|
|
278
|
+
if (typeof raw !== "string") continue;
|
|
279
|
+
const normalized = normalizedMetadataString(raw, maxLength);
|
|
280
|
+
if (normalized && !out.includes(normalized)) out.push(normalized);
|
|
281
|
+
if (out.length >= maxItems) break;
|
|
282
|
+
}
|
|
283
|
+
return out.length > 0 ? out : undefined;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function modelCapabilities(item: ProviderModelsApiItem): string[] | undefined {
|
|
287
|
+
const metadata = plainRecord(item.metadata);
|
|
288
|
+
const metadataCapabilities = metadata?.capabilities;
|
|
289
|
+
const capabilityRecord = plainRecord(metadataCapabilities) ?? plainRecord(item.capabilities);
|
|
290
|
+
const out = new Set<string>();
|
|
291
|
+
for (const list of [item.capabilities, item.features, item.supported_features, metadataCapabilities]) {
|
|
292
|
+
for (const capability of normalizedStringList(list) ?? []) out.add(capability);
|
|
293
|
+
}
|
|
294
|
+
const capabilityFields = capabilityRecord ?? {};
|
|
295
|
+
let inspectedCapabilityFields = 0;
|
|
296
|
+
for (const key in capabilityFields) {
|
|
297
|
+
if (!Object.hasOwn(capabilityFields, key)) continue;
|
|
298
|
+
inspectedCapabilityFields += 1;
|
|
299
|
+
if (inspectedCapabilityFields > 256 || out.size >= 32) break;
|
|
300
|
+
if (capabilityFields[key] === true) {
|
|
301
|
+
const normalized = normalizedMetadataString(key, 64);
|
|
302
|
+
if (normalized) out.add(normalized);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
for (const field of ["supports_tools", "supports_tool_calling", "supports_function_calling"] as const) {
|
|
306
|
+
if (item[field] === true) out.add("tools");
|
|
307
|
+
}
|
|
308
|
+
for (const field of ["supports_reasoning", "reasoning"] as const) {
|
|
309
|
+
if (item[field] === true) out.add("reasoning");
|
|
310
|
+
}
|
|
311
|
+
return out.size > 0 ? [...out].filter(Boolean).slice(0, 32) : undefined;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function modelInputModalities(
|
|
315
|
+
item: ProviderModelsApiItem,
|
|
316
|
+
capabilities: readonly string[] | undefined,
|
|
317
|
+
): string[] | undefined {
|
|
318
|
+
const metadata = plainRecord(item.metadata);
|
|
319
|
+
const capabilityRecord = plainRecord(metadata?.capabilities) ?? plainRecord(item.capabilities);
|
|
320
|
+
const explicit = normalizedStringList(
|
|
321
|
+
item.input_modalities
|
|
322
|
+
?? item.modalities
|
|
323
|
+
?? metadata?.input_modalities
|
|
324
|
+
?? capabilityRecord?.input_modalities,
|
|
325
|
+
8,
|
|
326
|
+
24,
|
|
327
|
+
)?.filter(value => (
|
|
328
|
+
// Codex parses `input_modalities` as a closed enum of text | image | audio. A provider that
|
|
329
|
+
// advertises anything else (zenmux reports "video") must not reach the catalog: Codex rejects
|
|
330
|
+
// the whole file, so plugins, apps and MCP servers all stop loading over one model's metadata.
|
|
331
|
+
value === "text" || value === "image" || value === "audio"
|
|
332
|
+
));
|
|
333
|
+
if (explicit && explicit.length > 0) return explicit;
|
|
334
|
+
if (capabilityRecord?.vision === false) return ["text"];
|
|
335
|
+
if (capabilityRecord?.vision === true || capabilities?.some(value => value === "vision" || value === "image-input")) {
|
|
336
|
+
return ["text", "image"];
|
|
337
|
+
}
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
|
|
196
341
|
export function catalogHintsFromModelsApiItem(providerName: string, item: ProviderModelsApiItem): Partial<CatalogModel> {
|
|
197
|
-
const
|
|
198
|
-
const
|
|
342
|
+
const metadata = plainRecord(item.metadata);
|
|
343
|
+
const capabilityRecord = plainRecord(metadata?.capabilities) ?? plainRecord(item.capabilities);
|
|
344
|
+
const limits = plainRecord(metadata?.limits);
|
|
199
345
|
const contextWindow =
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
346
|
+
positiveSafeInteger(
|
|
347
|
+
limits?.max_context_length,
|
|
348
|
+
item.context_length,
|
|
349
|
+
item.context_size,
|
|
350
|
+
item.max_model_len,
|
|
351
|
+
item.max_context_length,
|
|
352
|
+
);
|
|
353
|
+
const maxInputTokens = positiveSafeInteger(limits?.max_input_tokens, item.max_input_tokens);
|
|
354
|
+
const rawReasoningEfforts = capabilityRecord?.reasoning_effort ?? item.reasoning_efforts;
|
|
355
|
+
const listedReasoningEfforts = normalizedStringList(rawReasoningEfforts, 8, 24);
|
|
356
|
+
const reasoningEfforts = listedReasoningEfforts
|
|
357
|
+
? sanitizeCodexReasoningEfforts(listedReasoningEfforts)
|
|
358
|
+
: typeof rawReasoningEfforts === "boolean"
|
|
359
|
+
? (rawReasoningEfforts
|
|
360
|
+
? ((providerName === "neuralwatt" || providerName === "zai") && isGlm52ModelId(item.id)
|
|
361
|
+
? ["low", "medium", "high", "xhigh", "max"]
|
|
362
|
+
: ["low", "medium", "high", "xhigh"])
|
|
363
|
+
: [])
|
|
364
|
+
: undefined;
|
|
365
|
+
const capabilities = modelCapabilities(item);
|
|
366
|
+
const inputModalities = modelInputModalities(item, capabilities);
|
|
214
367
|
return {
|
|
215
368
|
...(contextWindow && contextWindow > 0 ? { contextWindow } : {}),
|
|
369
|
+
...(maxInputTokens && maxInputTokens > 0 ? { maxInputTokens } : {}),
|
|
216
370
|
...(reasoningEfforts !== undefined ? { reasoningEfforts } : {}),
|
|
217
371
|
...(inputModalities ? { inputModalities } : {}),
|
|
372
|
+
...(capabilities ? { capabilities } : {}),
|
|
218
373
|
};
|
|
219
374
|
}
|
|
220
375
|
|
|
376
|
+
function boundedOwnedBy(value: unknown): string | undefined {
|
|
377
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 256) return undefined;
|
|
378
|
+
if (MODEL_DISCOVERY_METADATA_CONTROL_CHARS.test(value)) return undefined;
|
|
379
|
+
return value;
|
|
380
|
+
}
|
|
381
|
+
|
|
221
382
|
export async function fetchProviderModels(name: string, prov: OcxProviderConfig, ttlMs: number, contextCap?: number): Promise<CatalogModel[]> {
|
|
222
383
|
if (prov.authMode === "forward") return []; // ChatGPT backend has no /models
|
|
223
384
|
const apiKey = await resolveModelsAuthToken(name, prov);
|
|
@@ -299,6 +460,7 @@ export async function fetchProviderModels(name: string, prov: OcxProviderConfig,
|
|
|
299
460
|
const stale = getStaleCached(name);
|
|
300
461
|
return stale ? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap)) : failedDiscoveryConfigured;
|
|
301
462
|
}
|
|
463
|
+
const discovery = resolveProviderModelDiscovery(name, prov);
|
|
302
464
|
const { url, headers } = buildModelsRequest(prov, apiKey, name);
|
|
303
465
|
const urlClass = new URL(url).hostname.endsWith("aiplatform.googleapis.com")
|
|
304
466
|
? "vertex-aiplatform"
|
|
@@ -322,21 +484,20 @@ export async function fetchProviderModels(name: string, prov: OcxProviderConfig,
|
|
|
322
484
|
};
|
|
323
485
|
};
|
|
324
486
|
try {
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
487
|
+
const res = await providerOutboundGet(name, prov, url, {
|
|
488
|
+
headers,
|
|
489
|
+
signal: AbortSignal.timeout(8000),
|
|
328
490
|
});
|
|
329
|
-
|
|
330
|
-
|
|
491
|
+
const redirectError = await providerRedirectError(res, url);
|
|
492
|
+
if (redirectError) {
|
|
493
|
+
const { models, fallback, shouldLog } = failedDiscoveryFallback({ reason: "http", httpStatus: res.status });
|
|
331
494
|
if (shouldLog) {
|
|
332
495
|
console.warn(
|
|
333
|
-
`[opencodex] Provider model discovery for "${name}"
|
|
496
|
+
`[opencodex] Provider model discovery for "${name}" ${redirectError} [urlClass=${urlClass}, fallback=${fallback}].`,
|
|
334
497
|
);
|
|
335
498
|
}
|
|
336
499
|
return models;
|
|
337
500
|
}
|
|
338
|
-
|
|
339
|
-
const res = await fetch(url, { headers, signal: AbortSignal.timeout(8000) });
|
|
340
501
|
if (!res.ok) {
|
|
341
502
|
const { models, fallback, shouldLog } = failedDiscoveryFallback({ reason: "http", httpStatus: res.status });
|
|
342
503
|
if (shouldLog) {
|
|
@@ -350,15 +511,14 @@ export async function fetchProviderModels(name: string, prov: OcxProviderConfig,
|
|
|
350
511
|
const contentType = (
|
|
351
512
|
res.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() || "missing"
|
|
352
513
|
).slice(0, 80);
|
|
353
|
-
const
|
|
354
|
-
|
|
355
|
-
try {
|
|
356
|
-
json = JSON.parse(body) as unknown;
|
|
357
|
-
} catch {
|
|
514
|
+
const bounded = await readBoundedDiscoveryJson(res, discovery.maxResponseBytes);
|
|
515
|
+
if (!bounded.ok) {
|
|
358
516
|
const { models, fallback, shouldLog } = failedDiscoveryFallback({ reason: "invalid_response" });
|
|
359
|
-
const diagnostic =
|
|
360
|
-
?
|
|
361
|
-
:
|
|
517
|
+
const diagnostic = bounded.reason === "response_too_large"
|
|
518
|
+
? `exceeded the ${discovery.maxResponseBytes}-byte response limit`
|
|
519
|
+
: contentType === "application/json" || contentType.endsWith("+json")
|
|
520
|
+
? "returned invalid JSON in a 2xx response"
|
|
521
|
+
: "returned a non-JSON 2xx response";
|
|
362
522
|
if (shouldLog) {
|
|
363
523
|
console.warn(
|
|
364
524
|
`[opencodex] Provider model discovery for "${name}" ${diagnostic} [status=${res.status}, contentType=${contentType}, urlClass=${urlClass}, fallback=${fallback}].`,
|
|
@@ -366,25 +526,32 @@ export async function fetchProviderModels(name: string, prov: OcxProviderConfig,
|
|
|
366
526
|
}
|
|
367
527
|
return models;
|
|
368
528
|
}
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
: undefined;
|
|
372
|
-
if (!isProviderModelsApiItems(data)) {
|
|
529
|
+
const extracted = extractProviderModelItems(bounded.value, discovery);
|
|
530
|
+
if (!extracted.ok) {
|
|
373
531
|
const { models, fallback, shouldLog } = failedDiscoveryFallback({ reason: "invalid_response" });
|
|
532
|
+
const diagnostic: Record<ModelDiscoveryResponseFailure, string> = {
|
|
533
|
+
response_too_large: "returned an oversized 2xx response",
|
|
534
|
+
invalid_json: "returned invalid JSON in a 2xx response",
|
|
535
|
+
invalid_shape: "returned malformed 2xx data",
|
|
536
|
+
too_many_models: `exceeded the ${discovery.maxModels}-row model limit`,
|
|
537
|
+
};
|
|
374
538
|
if (shouldLog) {
|
|
375
539
|
console.warn(
|
|
376
|
-
`[opencodex] Provider model discovery for "${name}"
|
|
540
|
+
`[opencodex] Provider model discovery for "${name}" ${diagnostic[extracted.reason]} [status=${res.status}, contentType=${contentType}, urlClass=${urlClass}, fallback=${fallback}].`,
|
|
377
541
|
);
|
|
378
542
|
}
|
|
379
543
|
return models;
|
|
380
544
|
}
|
|
381
|
-
const items =
|
|
382
|
-
const live = items.map(m =>
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
545
|
+
const items = extracted.items;
|
|
546
|
+
const live = items.map(m => {
|
|
547
|
+
const ownedBy = boundedOwnedBy(m.owned_by);
|
|
548
|
+
return applyProviderConfigHints(name, prov, {
|
|
549
|
+
id: m.id,
|
|
550
|
+
provider: name,
|
|
551
|
+
...(ownedBy ? { owned_by: ownedBy } : {}),
|
|
552
|
+
...catalogHintsFromModelsApiItem(name, m),
|
|
553
|
+
}, contextCap);
|
|
554
|
+
})
|
|
388
555
|
.filter(m => shouldExposeProviderModel(name, m.id));
|
|
389
556
|
// Capture the count BEFORE the alias/configured augmentation below pushes extra rows into
|
|
390
557
|
// `live`; otherwise configured entries would be reported as discovered ones.
|
|
@@ -421,6 +588,15 @@ export async function fetchProviderModels(name: string, prov: OcxProviderConfig,
|
|
|
421
588
|
setCached(name, live);
|
|
422
589
|
return live;
|
|
423
590
|
} catch (error) {
|
|
591
|
+
if (error instanceof ProviderOutboundPolicyError) {
|
|
592
|
+
const { models, fallback, shouldLog } = failedDiscoveryFallback({ reason: "blocked" });
|
|
593
|
+
if (shouldLog) {
|
|
594
|
+
console.warn(
|
|
595
|
+
`[opencodex] Provider model discovery for "${name}" was blocked by destination policy: ${error.message} [urlClass=${urlClass}, fallback=${fallback}].`,
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
return models;
|
|
599
|
+
}
|
|
424
600
|
const { models, fallback, shouldLog } = failedDiscoveryFallback({ reason: "network" });
|
|
425
601
|
if (shouldLog) {
|
|
426
602
|
console.warn(
|
|
@@ -469,7 +645,29 @@ export async function gatherRoutedModels(
|
|
|
469
645
|
config: OcxConfig,
|
|
470
646
|
options?: { comboOmissions?: ComboCatalogOmission[] },
|
|
471
647
|
): Promise<CatalogModel[]> {
|
|
472
|
-
|
|
648
|
+
const key = gatherFlightKey(config);
|
|
649
|
+
let promise = gatherInflight.get(key);
|
|
650
|
+
if (!promise) {
|
|
651
|
+
// Claim the slot synchronously before any await so same-key callers join this flight.
|
|
652
|
+
// Distinct keys keep their own entries — a second config must not evict the first.
|
|
653
|
+
const flight = gatherRoutedModelsUncached(config).finally(() => {
|
|
654
|
+
if (gatherInflight.get(key) === flight) gatherInflight.delete(key);
|
|
655
|
+
});
|
|
656
|
+
gatherInflight.set(key, flight);
|
|
657
|
+
promise = flight;
|
|
658
|
+
}
|
|
659
|
+
const { models, comboOmissions } = await promise;
|
|
660
|
+
if (options?.comboOmissions) {
|
|
661
|
+
options.comboOmissions.length = 0;
|
|
662
|
+
options.comboOmissions.push(...comboOmissions);
|
|
663
|
+
}
|
|
664
|
+
return models;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
async function gatherRoutedModelsUncached(
|
|
668
|
+
config: OcxConfig,
|
|
669
|
+
): Promise<GatherFlightResult> {
|
|
670
|
+
// Flight-local list: joiners copy from the resolved promise, not a process-global last write.
|
|
473
671
|
const localOmissions: ComboCatalogOmission[] = [];
|
|
474
672
|
const ttlMs = config.modelCacheTtlMs ?? DEFAULT_MODEL_CACHE_TTL_MS;
|
|
475
673
|
// Persisted provider entries can predate newer registry fields (noVisionModels,
|
|
@@ -551,10 +749,6 @@ export async function gatherRoutedModels(
|
|
|
551
749
|
else warnUncataloguedComboOnce(id, combo, members, localOmissions);
|
|
552
750
|
}
|
|
553
751
|
replaceLastComboCatalogOmissions(localOmissions);
|
|
554
|
-
if (options?.comboOmissions) {
|
|
555
|
-
options.comboOmissions.length = 0;
|
|
556
|
-
options.comboOmissions.push(...localOmissions);
|
|
557
|
-
}
|
|
558
752
|
all.sort((a, b) => (a.provider === b.provider ? a.id.localeCompare(b.id) : a.provider.localeCompare(b.provider)));
|
|
559
753
|
// Enriched (registry-hydrated) provider clones, keyed by name — the same view used above so
|
|
560
754
|
// custom rows get the same noVisionModels / inputModalities treatment as discovered rows.
|
|
@@ -588,7 +782,7 @@ export async function gatherRoutedModels(
|
|
|
588
782
|
// Custom rows override discovered rows that encode to the same Codex-facing slug.
|
|
589
783
|
const customKeys = new Set(customModels.map(c => routedSlug(c.provider, c.id)));
|
|
590
784
|
const deduped = all.filter(m => !customKeys.has(routedSlug(m.provider, m.id)));
|
|
591
|
-
return [...deduped, ...customModels];
|
|
785
|
+
return { models: [...deduped, ...customModels], comboOmissions: localOmissions };
|
|
592
786
|
}
|
|
593
787
|
|
|
594
788
|
export function augmentRoutedModelsWithRegistryOpenAiApiRows(
|
|
@@ -596,7 +790,7 @@ export function augmentRoutedModelsWithRegistryOpenAiApiRows(
|
|
|
596
790
|
config: OcxConfig,
|
|
597
791
|
): CatalogModel[] {
|
|
598
792
|
const configured = config.providers[OPENAI_API_PROVIDER_ID];
|
|
599
|
-
if (!configured || configured.disabled === true) return models;
|
|
793
|
+
if (!configured || configured.disabled === true || !providerMatchesRegistryTransport(OPENAI_API_PROVIDER_ID, configured)) return models;
|
|
600
794
|
const entry = getProviderRegistryEntry(OPENAI_API_PROVIDER_ID);
|
|
601
795
|
if (!entry?.models) return models;
|
|
602
796
|
|
|
@@ -35,8 +35,9 @@ import { activeCodexModelsCachePath, applyJawcodeCatalogMetadata, applyMultiAgen
|
|
|
35
35
|
import type { CatalogModel, MultiAgentMode, RawEntry } from "./parsing";
|
|
36
36
|
import { applyNativeVisibility, disabledNativeSlugs, isUnsupportedOpenAiNativeSlug, nativeOpenAiSlugs, shouldUpgradeToUpstreamEntry, upstreamNativeEntry } from "./metadata";
|
|
37
37
|
import { loadCatalogForSync, resetBundledCatalogCacheForTests } from "./bundled";
|
|
38
|
+
import { isMultiAgentV2Enabled } from "../features";
|
|
38
39
|
import { applyCatalogModelMetadata, applyReasoningLevels, catalogEntryEfforts, clampCatalogModelsToCodexSupport, ensureGpt56ReasoningLevels, ensureUltraReasoningLevel, isGpt56NativeSlug } from "./effort";
|
|
39
|
-
import { filterCatalogVisibleModels, gatherRoutedModels, lastDropWarnSignature } from "./provider-fetch";
|
|
40
|
+
import { clearGatherRoutedModelsInflight, filterCatalogVisibleModels, gatherRoutedModels, lastDropWarnSignature } from "./provider-fetch";
|
|
40
41
|
import { clearLastComboCatalogOmissions, comboCatalogWarningSignatures, comboMasqueradeCollisionWarnings, exactComboCatalogSlugs, openAiApiCollisionWarnings, resolveSlugAliasCollisions, slugAliasCollisionWarnings, warnComboMasqueradeCollisionOnce } from "./aggregation";
|
|
41
42
|
import type { ComboCatalogOmission } from "./aggregation";
|
|
42
43
|
|
|
@@ -50,6 +51,26 @@ export type SubagentRosterExclusionReason =
|
|
|
50
51
|
| "surface_incompatible"
|
|
51
52
|
| "outside_display_limit";
|
|
52
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Whether a catalog entry may be offered as a V2 subagent model.
|
|
56
|
+
*
|
|
57
|
+
* Upstream (codex-rs 92938d880) requires `multi_agent_version === "v2"` exactly,
|
|
58
|
+
* because upstream assumes a single backend serves every model. opencodex routes
|
|
59
|
+
* many providers, so that equality would reject the cross-provider spawns this
|
|
60
|
+
* proxy exists to enable.
|
|
61
|
+
*
|
|
62
|
+
* Decision (option B, devlog 260730_codex_rs_upstream_v2_live_handoff/060): any
|
|
63
|
+
* model opencodex actually routes is eligible. An entry pinned to a DIFFERENT
|
|
64
|
+
* multi-agent backend (`v1`) stays excluded, because that pin is a real capability
|
|
65
|
+
* statement rather than an absence of information. An unpinned entry (null or
|
|
66
|
+
* absent) is a routed or unpinned-native model and is allowed. The three-way
|
|
67
|
+
* distinction is the substance; do not flatten it into a truthiness check.
|
|
68
|
+
*/
|
|
69
|
+
export function isEligibleV2SubagentEntry(entry: RawEntry): boolean {
|
|
70
|
+
const pinned = entry.multi_agent_version;
|
|
71
|
+
return pinned === "v2" || pinned === null || pinned === undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
53
74
|
export interface EffectiveSubagentModel {
|
|
54
75
|
model: string;
|
|
55
76
|
efforts: string[];
|
|
@@ -86,7 +107,7 @@ export function effectiveSubagentRoster(
|
|
|
86
107
|
.map((entry, index) => ({ entry, index }))
|
|
87
108
|
.filter(({ entry }) => typeof entry.slug === "string")
|
|
88
109
|
.filter(({ entry }) => entry.visibility === "list")
|
|
89
|
-
.filter(({ entry }) => surface !== "v2" || entry
|
|
110
|
+
.filter(({ entry }) => surface !== "v2" || isEligibleV2SubagentEntry(entry))
|
|
90
111
|
.sort((left, right) => {
|
|
91
112
|
const leftPriority = typeof left.entry.priority === "number" && Number.isFinite(left.entry.priority)
|
|
92
113
|
? left.entry.priority : Number.MAX_SAFE_INTEGER;
|
|
@@ -110,7 +131,7 @@ export function effectiveSubagentRoster(
|
|
|
110
131
|
if (entry.visibility !== "list") {
|
|
111
132
|
return [{ configured: model, catalogModel, reason: "picker_hidden" }];
|
|
112
133
|
}
|
|
113
|
-
if (surface === "v2" && entry
|
|
134
|
+
if (surface === "v2" && !isEligibleV2SubagentEntry(entry)) {
|
|
114
135
|
return [{ configured: model, catalogModel, reason: "surface_incompatible" }];
|
|
115
136
|
}
|
|
116
137
|
if (!candidates.some(candidate => candidate.model === catalogModel)) {
|
|
@@ -284,7 +305,7 @@ export function buildCatalogEntries(
|
|
|
284
305
|
delete entry.prefer_websockets;
|
|
285
306
|
}
|
|
286
307
|
}
|
|
287
|
-
return applyMultiAgentMode(out, multiAgentMode);
|
|
308
|
+
return applyMultiAgentMode(out, multiAgentMode, isMultiAgentV2Enabled());
|
|
288
309
|
}
|
|
289
310
|
|
|
290
311
|
export function resetCatalogRuntimeStateForTests(): void {
|
|
@@ -296,6 +317,7 @@ export function resetCatalogRuntimeStateForTests(): void {
|
|
|
296
317
|
comboMasqueradeCollisionWarnings.clear();
|
|
297
318
|
clearLastComboCatalogOmissions();
|
|
298
319
|
clearModelCache();
|
|
320
|
+
clearGatherRoutedModelsInflight();
|
|
299
321
|
}
|
|
300
322
|
|
|
301
323
|
export function orderForSubagents(goModels: CatalogModel[], featured?: string[]): CatalogModel[] {
|
|
@@ -329,9 +351,11 @@ export function mergeCatalogEntriesForSync(
|
|
|
329
351
|
multiAgentMode: MultiAgentMode = "default",
|
|
330
352
|
exactComboSlugs: ReadonlySet<string> = new Set(),
|
|
331
353
|
hasPhysicalComboProvider = false,
|
|
354
|
+
includeNativeOpenAi = true,
|
|
332
355
|
): RawEntry[] {
|
|
333
356
|
const rank = new Map(featured.map((slug, i) => [slug, i] as const));
|
|
334
|
-
const native =
|
|
357
|
+
const native = includeNativeOpenAi
|
|
358
|
+
? catalogModels
|
|
335
359
|
.filter(m => typeof m.slug === "string"
|
|
336
360
|
&& !(m.slug as string).includes("/")
|
|
337
361
|
&& m.owned_by !== COMBO_NAMESPACE
|
|
@@ -367,11 +391,14 @@ export function mergeCatalogEntriesForSync(
|
|
|
367
391
|
// for subagent max spawns; wire-clamped to the model's real top rung).
|
|
368
392
|
if (!isGpt56NativeSlug(slug)) ensureUltraReasoningLevel(preserved);
|
|
369
393
|
return preserved;
|
|
370
|
-
})
|
|
394
|
+
})
|
|
395
|
+
: [];
|
|
371
396
|
|
|
372
397
|
// Backfill any native OpenAI slug that the on-disk catalog is missing (e.g. gpt-5.5), so a
|
|
373
398
|
// routed provider exposing the same id can never delete the native OpenAI/Codex base row.
|
|
399
|
+
// Skip when no enabled canonical openai provider exists (#636) — bare gpt-* would 404.
|
|
374
400
|
const nativeSlugs = new Set(native.flatMap(m => typeof m.slug === "string" ? [m.slug] : []));
|
|
401
|
+
if (includeNativeOpenAi) {
|
|
375
402
|
for (const slug of nativeOpenAiSlugs()) {
|
|
376
403
|
if (nativeSlugs.has(slug)) continue;
|
|
377
404
|
nativeSlugs.add(slug);
|
|
@@ -382,6 +409,7 @@ export function mergeCatalogEntriesForSync(
|
|
|
382
409
|
: 9;
|
|
383
410
|
native.push(deriveEntry(template ? JSON.parse(JSON.stringify(template)) : null, slug, "OpenAI native model (Codex OAuth passthrough).", priority));
|
|
384
411
|
}
|
|
412
|
+
}
|
|
385
413
|
|
|
386
414
|
const freshSlugs = new Set(
|
|
387
415
|
routedEntries.flatMap(entry => typeof entry.slug === "string" ? [entry.slug] : []),
|
|
@@ -451,7 +479,7 @@ export function mergeCatalogEntriesForSync(
|
|
|
451
479
|
});
|
|
452
480
|
// Native enable/disable (single choke point: bare slugs in `disabledModels`). Runs as the
|
|
453
481
|
// LAST pass so the upstream-upgrade branch above can never clobber a hide flag back to list.
|
|
454
|
-
return applyMultiAgentMode(applyNativeVisibility(mergedEntries, disabledNative), multiAgentMode);
|
|
482
|
+
return applyMultiAgentMode(applyNativeVisibility(mergedEntries, disabledNative), multiAgentMode, isMultiAgentV2Enabled());
|
|
455
483
|
}
|
|
456
484
|
|
|
457
485
|
export async function syncCatalogModels(config: OcxConfig): Promise<{
|
|
@@ -497,7 +525,16 @@ export async function syncCatalogModels(config: OcxConfig): Promise<{
|
|
|
497
525
|
// native AND routed so the advertised flag matches the implemented endpoint (phase 120.4) and a
|
|
498
526
|
// native template can never leak supports_websockets while the flag is off.
|
|
499
527
|
const wsEnabled = websocketsEnabled(config);
|
|
500
|
-
|
|
528
|
+
const enabledProviders = Object.entries(config.providers ?? {})
|
|
529
|
+
.filter(([, prov]) => prov.disabled !== true);
|
|
530
|
+
const hasCanonicalOpenai = enabledProviders.some(([name, prov]) =>
|
|
531
|
+
name === "openai" && isCanonicalOpenAiForwardProvider(prov),
|
|
532
|
+
);
|
|
533
|
+
// #636: when the user only configured non-OpenAI providers (e.g. kimi), do not advertise
|
|
534
|
+
// bare gpt-* rows that hard-404 via NoEnabledOpenAiProviderError. Keep natives when no
|
|
535
|
+
// providers are configured yet (fresh install / catalog bootstrap tests).
|
|
536
|
+
const includeNativeOpenAi = enabledProviders.length === 0 || hasCanonicalOpenai;
|
|
537
|
+
catalog.models = mergeCatalogEntriesForSync(catalog.models ?? [], goEntries, baseline, featured, wsEnabled, goIds, template, disabledNativeSlugs(config), gatheredProviderNames, multiAgentMode, exactComboSlugs, hasPhysicalComboProvider, includeNativeOpenAi);
|
|
501
538
|
clampCatalogModelsToCodexSupport(catalog.models);
|
|
502
539
|
|
|
503
540
|
atomicWriteFile(catalogPath, JSON.stringify(catalog, null, 2) + "\n");
|
package/src/codex/catalog.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// AUTO-SPLIT facade: original catalog.ts body moved into ./catalog/* modules.
|
|
2
2
|
// Public surface preserved exactly; importers keep using "src/codex/catalog".
|
|
3
|
-
export { isMediaGenerationModelId, readCodexCatalogPath, normalizeRoutedCatalogEntry, catalogModelSlug, filterSupportedNativeSlugs, catalogModelSupportsReasoningSummaries } from "./catalog/parsing";
|
|
3
|
+
export { isMediaGenerationModelId, shouldExposeRoutedModel, readCodexCatalogPath, normalizeRoutedCatalogEntry, catalogModelSlug, filterSupportedNativeSlugs, catalogModelSupportsReasoningSummaries } from "./catalog/parsing";
|
|
4
4
|
export type { CatalogModel, MultiAgentMode } from "./catalog/parsing";
|
|
5
5
|
export { NATIVE_OPENAI_MODELS, nativeOpenAiContextWindow, disabledNativeSlugs, visibleNativeSlugs, nativeModelRows, applyNativeVisibility, upstreamNativeEntry, nativeOpenAiSlugs, listCatalogNativeSlugs } from "./catalog/metadata";
|
|
6
6
|
export { isSpawnableCodexCandidate, codexExecInvocation, loadBundledCodexCatalog, materializeBundledCodexCatalog, loadCatalogTemplate } from "./catalog/bundled";
|
|
7
7
|
export { nativeEffortClamp, shouldApplyNativeEffortClamp, catalogModelEfforts, codexSupportedReasoningEfforts, clampedDefaultEffort, clampEntryToCodexSupportedEfforts, clampCatalogModelsToCodexSupport } from "./catalog/effort";
|
|
8
|
-
export { applyProviderConfigHints, isDatedVariantId, filterCatalogVisibleModels, gatherRoutedModels, augmentRoutedModelsWithRegistryOpenAiApiRows, augmentRoutedModelsWithJawcodeMetadata } from "./catalog/provider-fetch";
|
|
8
|
+
export { applyProviderConfigHints, isDatedVariantId, filterCatalogVisibleModels, gatherRoutedModels, clearGatherRoutedModelsInflight, augmentRoutedModelsWithRegistryOpenAiApiRows, augmentRoutedModelsWithJawcodeMetadata } from "./catalog/provider-fetch";
|
|
9
9
|
export { deriveComboCatalogModel, exactComboCatalogSlugs, getLastComboCatalogOmissions, resetOpenAiApiCatalogWarningStateForTests, uniqueCatalogModelsForPublicList, uniqueCatalogModelsForRawPublicList, buildComboCatalogOmission, comboCatalogOmissionReason, summarizeComboCatalogOmissions } from "./catalog/aggregation";
|
|
10
10
|
export type { ComboCatalogOmission, ComboCatalogOmissionReason } from "./catalog/aggregation";
|
|
11
11
|
export { MAX_SPAWN_AGENT_MODEL_OVERRIDES, effectiveSubagentRoster, buildCatalogEntries, resetCatalogRuntimeStateForTests, orderForSubagents, mergeCatalogEntriesForSync, syncCatalogModels, restoreCodexCatalog, invalidateCodexModelsCache } from "./catalog/sync";
|