@bitkyc08/opencodex 2.40.0 → 2.41.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 +4 -0
- package/gui/dist/assets/index-B2YjLA-i.css +1 -0
- package/gui/dist/assets/{index-BHe2rl_C.js → index-aPup8CKb.js} +20 -20
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/meta.svg +1 -0
- package/package.json +4 -3
- package/src/adapters/cursor/catalog.ts +71 -29
- package/src/adapters/cursor/claude-id.ts +76 -0
- package/src/adapters/cursor/discovery.ts +16 -3
- package/src/adapters/cursor/effort-map.ts +27 -12
- package/src/adapters/google.ts +39 -2
- package/src/adapters/openai-responses.ts +14 -1
- package/src/cli/claude.ts +11 -2
- package/src/cli/connect.ts +7 -1
- package/src/cli/registry.ts +1 -1
- package/src/cli/status.ts +19 -4
- package/src/client/connect.ts +5 -1
- package/src/client/hub-client.ts +29 -5
- package/src/clients/config-export.ts +12 -2
- package/src/codex/catalog/aggregation.ts +8 -0
- package/src/codex/catalog/metadata.ts +5 -0
- package/src/codex/catalog/parsing.ts +2 -0
- package/src/codex/catalog/provider-fetch.ts +163 -26
- package/src/codex/catalog.ts +1 -1
- package/src/codex/convergence-types.ts +1 -0
- package/src/codex/desired-state.ts +18 -11
- package/src/combos/failover.ts +185 -6
- package/src/combos/index.ts +6 -0
- package/src/combos/resolve.ts +43 -6
- package/src/config.ts +5 -1
- package/src/generated/compatibility-version.json +85 -61
- package/src/generated/model-metadata.ts +1 -1
- package/src/grok/sync.ts +10 -2
- package/src/integrations/cursor-effort-table.ts +143 -0
- package/src/integrations/state.ts +1 -1
- package/src/integrations/writer.ts +2 -2
- package/src/lib/app-owned-memory-stores.ts +27 -8
- package/src/lib/bounded-body.ts +16 -1
- package/src/oauth/generic-account-failover.ts +2 -2
- package/src/oauth/index.ts +11 -0
- package/src/oauth/meta-muse.ts +235 -0
- package/src/providers/antigravity-models.ts +71 -13
- package/src/providers/command-code-efforts.ts +15 -0
- package/src/providers/free-directory.ts +4 -1
- package/src/providers/registry.ts +116 -8
- package/src/responses/code-mode-helper-compat.ts +4 -1
- package/src/responses/state.ts +5 -4
- package/src/server/auth-cors.ts +241 -56
- package/src/server/chat-completions.ts +11 -2
- package/src/server/chat-native.ts +30 -4
- package/src/server/claude-messages.ts +17 -3
- package/src/server/effort-row.ts +131 -0
- package/src/server/index.ts +67 -38
- package/src/server/management/api-key-rotation.ts +2 -1
- package/src/server/management/api-key-usage.ts +97 -43
- package/src/server/management/context.ts +3 -0
- package/src/server/management/cursor-integration-routes.ts +36 -7
- package/src/server/management/logs-usage-routes.ts +64 -87
- package/src/server/management/provider-routes.ts +218 -1
- package/src/server/management/route-registry.ts +1 -0
- package/src/server/management/usage-aggregate-cache.ts +464 -0
- package/src/server/management/usage-summary-cache.ts +4 -0
- package/src/server/models-capabilities.ts +60 -5
- package/src/server/responses/core.ts +61 -7
- package/src/types/config.ts +10 -1
- package/src/types/tools.ts +12 -9
- package/src/usage/expected-prices.ts +43 -7
- package/src/usage/ledger-scanner.ts +448 -0
- package/src/usage/log.ts +1 -1
- package/src/usage/summary.ts +915 -655
- package/src/web-search/index.ts +1 -1
- package/gui/dist/assets/index-CJSb3HPe.css +0 -1
|
@@ -49,7 +49,7 @@ import { routedSlug, slugEquals, slugEquivalenceKey, slugsEquivalent } from "../
|
|
|
49
49
|
import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
|
|
50
50
|
import { filterCursorConfiguredModelsByLiveDiscovery } from "../../adapters/cursor/discovery";
|
|
51
51
|
import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
|
|
52
|
-
import { recordLiveCursorMaxModeModels } from "../../adapters/cursor/catalog";
|
|
52
|
+
import { recordLiveCursorClaudeModels, recordLiveCursorMaxModeModels } from "../../adapters/cursor/catalog";
|
|
53
53
|
import { isCanonicalOpenAiForwardProvider, OPENAI_API_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
|
|
54
54
|
import {
|
|
55
55
|
COMBO_NAMESPACE,
|
|
@@ -81,7 +81,7 @@ import { createAdmissionGate, ResourceAdmissionError, type AdmissionMetrics } fr
|
|
|
81
81
|
|
|
82
82
|
import { CODEX_CUSTOM_MODEL_CATALOG_KIND, JAWCODE_CATALOG_AUGMENT_PROVIDERS, catalogModelSlug, shouldExposeRoutedModel } from "./parsing";
|
|
83
83
|
import type { CatalogModel } from "./parsing";
|
|
84
|
-
import { disabledNativeSlugs, hasComboTargets, isNativeOpenAiCapabilityAliasModel, NATIVE_GPT56_MAX_INPUT_TOKENS, nativeContextLimits, nativeDefaultReasoningEffort, nativeInputModalities, nativeOpenAiAutoCompactTokenLimit, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiSlugs, nativeParallelToolCalls, nativeReasoningEfforts } from "./metadata";
|
|
84
|
+
import { disabledNativeSlugs, hasComboTargets, isNativeOpenAiCapabilityAliasModel, NATIVE_GPT56_MAX_INPUT_TOKENS, nativeContextLimits, nativeDefaultReasoningEffort, nativeInputModalities, nativeOpenAiAutoCompactTokenLimit, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiMaxOutputTokens, nativeOpenAiSlugs, nativeParallelToolCalls, nativeReasoningEfforts } from "./metadata";
|
|
85
85
|
import { deriveComboCatalogModel, normalizedOpenAiApiSignature, openAiApiCollisionWarnings, replaceLastComboCatalogOmissions, warnUncataloguedComboOnce } from "./aggregation";
|
|
86
86
|
import type { ComboCatalogOmission } from "./aggregation";
|
|
87
87
|
import type { CatalogGatherProviderAuthEvidence } from "./filesystem-evidence";
|
|
@@ -163,6 +163,7 @@ interface CapturedProviderGather {
|
|
|
163
163
|
readonly policy: CatalogProviderDiscoveryPolicySnapshot;
|
|
164
164
|
readonly request: CapturedModelsRequest;
|
|
165
165
|
readonly fastPolicyAuthority: FastPolicyAuthority;
|
|
166
|
+
readonly metadataModelIdCaseFold: boolean;
|
|
166
167
|
readonly observedAuth?: ModelsAuthResolution;
|
|
167
168
|
/**
|
|
168
169
|
* Configured model ids this provider must keep even when live discovery omits
|
|
@@ -379,6 +380,7 @@ function captureTrustedOpenAiApiPolicy(
|
|
|
379
380
|
models: entry.models,
|
|
380
381
|
...(entry.modelContextWindows ? { modelContextWindows: entry.modelContextWindows } : {}),
|
|
381
382
|
...(entry.modelMaxInputTokens ? { modelMaxInputTokens: entry.modelMaxInputTokens } : {}),
|
|
383
|
+
...(entry.virtualModels ? { virtualModels: entry.virtualModels } : {}),
|
|
382
384
|
...(entry.modelInputModalities ? { modelInputModalities: entry.modelInputModalities } : {}),
|
|
383
385
|
...(entry.modelReasoningEfforts ? { modelReasoningEfforts: entry.modelReasoningEfforts } : {}),
|
|
384
386
|
});
|
|
@@ -422,6 +424,7 @@ function captureProviderGather(
|
|
|
422
424
|
registryTransportMatch,
|
|
423
425
|
configured,
|
|
424
426
|
);
|
|
427
|
+
const metadataModelIdCaseFold = shouldCaseFoldMetadataModelId(name);
|
|
425
428
|
const observedAuth = authResolver.kind === "observed"
|
|
426
429
|
&& provider.authMode !== "forward"
|
|
427
430
|
&& provider.liveModels !== false
|
|
@@ -458,6 +461,7 @@ function captureProviderGather(
|
|
|
458
461
|
policy,
|
|
459
462
|
request,
|
|
460
463
|
fastPolicyAuthority,
|
|
464
|
+
metadataModelIdCaseFold,
|
|
461
465
|
...(observedAuth ? { observedAuth: Object.freeze({ ...observedAuth }) } : {}),
|
|
462
466
|
...(retainConfiguredModelIds && retainConfiguredModelIds.size > 0
|
|
463
467
|
? { retainConfiguredModelIds }
|
|
@@ -579,6 +583,7 @@ function providerCatalogFingerprint(name: string, prov: OcxProviderConfig): Reco
|
|
|
579
583
|
ctx: prov.contextWindow ?? null,
|
|
580
584
|
ctxW: prov.modelContextWindows ?? null,
|
|
581
585
|
maxIn: prov.modelMaxInputTokens ?? null,
|
|
586
|
+
maxOut: prov.modelMaxOutputTokens ?? null,
|
|
582
587
|
autoCompact: prov.modelAutoCompactTokenLimits ?? null,
|
|
583
588
|
inMod: prov.modelInputModalities ?? null,
|
|
584
589
|
re: prov.modelReasoningEfforts ?? null,
|
|
@@ -645,6 +650,44 @@ export function configuredMaxInputTokens(prov: OcxProviderConfig, id: string): n
|
|
|
645
650
|
return typeof configured === "number" && configured > 0 ? configured : undefined;
|
|
646
651
|
}
|
|
647
652
|
|
|
653
|
+
function generatedMaxOutputTokens(
|
|
654
|
+
providerName: string,
|
|
655
|
+
id: string,
|
|
656
|
+
metadataId = id,
|
|
657
|
+
metadataModelIdCaseFold?: boolean,
|
|
658
|
+
): number | undefined {
|
|
659
|
+
const metadataProvider = providerName === OPENAI_API_PROVIDER_ID || providerName === OPENAI_CODEX_PROVIDER_ID
|
|
660
|
+
? "openai"
|
|
661
|
+
: resolveMetadataProvider(providerName);
|
|
662
|
+
if (!metadataProvider) return undefined;
|
|
663
|
+
const metadata = getModelMetadata(metadataProvider, metadataId)
|
|
664
|
+
?? ((metadataModelIdCaseFold ?? (providerName === OPENAI_API_PROVIDER_ID || providerName === OPENAI_CODEX_PROVIDER_ID
|
|
665
|
+
? false
|
|
666
|
+
: shouldCaseFoldMetadataModelId(providerName)))
|
|
667
|
+
? getModelMetadataCaseInsensitive(metadataProvider, metadataId)
|
|
668
|
+
: undefined);
|
|
669
|
+
return positiveSafeInteger(metadata?.maxTokens);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
function routedMaxOutputTokens(
|
|
673
|
+
providerName: string,
|
|
674
|
+
provider: OcxProviderConfig,
|
|
675
|
+
model: CatalogModel,
|
|
676
|
+
metadataId = model.id,
|
|
677
|
+
metadataModelIdCaseFold?: boolean,
|
|
678
|
+
): number | undefined {
|
|
679
|
+
const discovered = positiveSafeInteger(model.maxOutputTokens);
|
|
680
|
+
const generated = generatedMaxOutputTokens(providerName, model.id, metadataId, metadataModelIdCaseFold);
|
|
681
|
+
const configured = positiveSafeInteger(
|
|
682
|
+
modelRecordValue(provider.modelMaxOutputTokens, model.id),
|
|
683
|
+
);
|
|
684
|
+
const authoritative = discovered ?? generated;
|
|
685
|
+
if (configured === undefined) return authoritative;
|
|
686
|
+
return authoritative === undefined
|
|
687
|
+
? configured
|
|
688
|
+
: Math.min(authoritative, configured);
|
|
689
|
+
}
|
|
690
|
+
|
|
648
691
|
export function configuredAutoCompactTokenLimit(
|
|
649
692
|
prov: OcxProviderConfig | undefined,
|
|
650
693
|
id: string,
|
|
@@ -679,10 +722,17 @@ function configuredVerbositySupport(name: string, prov: OcxProviderConfig | unde
|
|
|
679
722
|
return prov.supportsVerbosity;
|
|
680
723
|
}
|
|
681
724
|
|
|
682
|
-
export function applyProviderConfigHints(
|
|
725
|
+
export function applyProviderConfigHints(
|
|
726
|
+
name: string,
|
|
727
|
+
prov: OcxProviderConfig,
|
|
728
|
+
model: CatalogModel,
|
|
729
|
+
providerCap?: number,
|
|
730
|
+
metadataModelIdCaseFold?: boolean,
|
|
731
|
+
): CatalogModel {
|
|
683
732
|
const displayName = configuredModelDisplayName(prov, model.id);
|
|
684
733
|
const configuredCap = configuredContextWindow(prov, model.id);
|
|
685
734
|
const configuredMaxInput = configuredMaxInputTokens(prov, model.id);
|
|
735
|
+
const maxOutputTokens = routedMaxOutputTokens(name, prov, model, model.id, metadataModelIdCaseFold);
|
|
686
736
|
const configuredAutoCompact = configuredAutoCompactTokenLimit(prov, model.id);
|
|
687
737
|
let inputModalities = configuredInputModalities(prov, model.id);
|
|
688
738
|
// The shared vision-sidecar consumer predicate keeps catalog advertisement and request-time
|
|
@@ -727,6 +777,7 @@ export function applyProviderConfigHints(name: string, prov: OcxProviderConfig,
|
|
|
727
777
|
: configuredMaxInput,
|
|
728
778
|
}
|
|
729
779
|
: {}),
|
|
780
|
+
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
730
781
|
...(defaultReasoningEffort ? { defaultReasoningEffort } : {}),
|
|
731
782
|
...(typeof supportsReasoningSummaries === "boolean" ? { supportsReasoningSummaries } : {}),
|
|
732
783
|
...(typeof supportsVerbosity === "boolean" ? { supportsVerbosity } : {}),
|
|
@@ -769,14 +820,26 @@ export function applyProviderConfigHints(name: string, prov: OcxProviderConfig,
|
|
|
769
820
|
};
|
|
770
821
|
}
|
|
771
822
|
|
|
772
|
-
export function catalogHintsFromProviderConfig(
|
|
773
|
-
|
|
823
|
+
export function catalogHintsFromProviderConfig(
|
|
824
|
+
name: string,
|
|
825
|
+
prov: OcxProviderConfig,
|
|
826
|
+
id: string,
|
|
827
|
+
contextCap?: number,
|
|
828
|
+
metadataModelIdCaseFold?: boolean,
|
|
829
|
+
): Partial<CatalogModel> {
|
|
830
|
+
const hinted = applyProviderConfigHints(name, prov, { id, provider: name }, contextCap, metadataModelIdCaseFold);
|
|
774
831
|
const { provider: _provider, id: _id, ...hints } = hinted;
|
|
775
832
|
return hints;
|
|
776
833
|
}
|
|
777
834
|
|
|
778
|
-
export function applyConfigHintsToCachedModels(
|
|
779
|
-
|
|
835
|
+
export function applyConfigHintsToCachedModels(
|
|
836
|
+
name: string,
|
|
837
|
+
prov: OcxProviderConfig,
|
|
838
|
+
models: CatalogModel[],
|
|
839
|
+
contextCap?: number,
|
|
840
|
+
metadataModelIdCaseFold?: boolean,
|
|
841
|
+
): CatalogModel[] {
|
|
842
|
+
return models.map(model => applyProviderConfigHints(name, prov, model, contextCap, metadataModelIdCaseFold));
|
|
780
843
|
}
|
|
781
844
|
|
|
782
845
|
|
|
@@ -793,6 +856,7 @@ interface ComboCatalogMemberFallback {
|
|
|
793
856
|
readonly contextWindow?: number;
|
|
794
857
|
/** Input ceiling when it is lower than the window (native GPT-5.6: 922k under 1.05M). */
|
|
795
858
|
readonly maxInputTokens?: number;
|
|
859
|
+
readonly maxOutputTokens?: number;
|
|
796
860
|
readonly autoCompactTokenLimit?: number;
|
|
797
861
|
readonly inputModalities?: readonly string[];
|
|
798
862
|
readonly reasoningEfforts?: readonly string[];
|
|
@@ -814,6 +878,7 @@ export function resolveComboCatalogMember(
|
|
|
814
878
|
providers: ReadonlyMap<string, OcxProviderConfig>,
|
|
815
879
|
contextCap?: number,
|
|
816
880
|
fallback?: ComboCatalogMemberFallback,
|
|
881
|
+
metadataModelIdCaseFold?: boolean,
|
|
817
882
|
): CatalogModel | undefined {
|
|
818
883
|
const existing = memberByKey.get(targetKey(target));
|
|
819
884
|
const prov = providers.get(target.provider);
|
|
@@ -827,6 +892,10 @@ export function resolveComboCatalogMember(
|
|
|
827
892
|
: undefined;
|
|
828
893
|
const addMaxInput = fallback !== undefined && contextWindow !== undefined
|
|
829
894
|
&& !(typeof member.maxInputTokens === "number" && member.maxInputTokens > 0);
|
|
895
|
+
const addMaxOutput = fallback !== undefined
|
|
896
|
+
&& typeof fallback.maxOutputTokens === "number"
|
|
897
|
+
&& fallback.maxOutputTokens > 0
|
|
898
|
+
&& !(typeof member.maxOutputTokens === "number" && member.maxOutputTokens > 0);
|
|
830
899
|
const effectiveMaxInput = addMaxInput
|
|
831
900
|
? Math.min(fallback?.maxInputTokens ?? contextWindow!, contextWindow!)
|
|
832
901
|
: member.maxInputTokens;
|
|
@@ -840,12 +909,13 @@ export function resolveComboCatalogMember(
|
|
|
840
909
|
&& fallback?.inputModalities !== undefined;
|
|
841
910
|
const addReasoning = member.reasoningEfforts === undefined
|
|
842
911
|
&& fallback?.reasoningEfforts !== undefined;
|
|
843
|
-
if (!addMaxInput && !adjustAutoCompact && !addModalities && !addReasoning) return member;
|
|
912
|
+
if (!addMaxInput && !addMaxOutput && !adjustAutoCompact && !addModalities && !addReasoning) return member;
|
|
844
913
|
return {
|
|
845
914
|
...member,
|
|
846
915
|
// Never claim a larger input budget than the window, and prefer the model's own
|
|
847
916
|
// measured ceiling when the fallback carries one.
|
|
848
917
|
...(addMaxInput ? { maxInputTokens: effectiveMaxInput } : {}),
|
|
918
|
+
...(addMaxOutput ? { maxOutputTokens: fallback!.maxOutputTokens } : {}),
|
|
849
919
|
...(adjustAutoCompact && autoCompactTokenLimit !== undefined ? { autoCompactTokenLimit } : {}),
|
|
850
920
|
...(addModalities ? { inputModalities: [...fallback!.inputModalities!] } : {}),
|
|
851
921
|
...(addReasoning ? { reasoningEfforts: [...fallback!.reasoningEfforts!] } : {}),
|
|
@@ -882,7 +952,7 @@ export function resolveComboCatalogMember(
|
|
|
882
952
|
provider: target.provider,
|
|
883
953
|
};
|
|
884
954
|
const hinted = prov
|
|
885
|
-
? applyProviderConfigHints(target.provider, prov, base, contextCap)
|
|
955
|
+
? applyProviderConfigHints(target.provider, prov, base, contextCap, metadataModelIdCaseFold)
|
|
886
956
|
: base;
|
|
887
957
|
const hintedContext = typeof hinted.contextWindow === "number" && hinted.contextWindow > 0
|
|
888
958
|
? hinted.contextWindow
|
|
@@ -923,6 +993,8 @@ export function resolveComboCatalogMember(
|
|
|
923
993
|
?? (prov ? configuredReasoningEfforts(prov, target.model) : undefined)
|
|
924
994
|
?? base.reasoningEfforts
|
|
925
995
|
?? (fallback?.reasoningEfforts ? [...fallback.reasoningEfforts] : undefined);
|
|
996
|
+
const maxOutputTokens = positiveSafeInteger(hinted.maxOutputTokens, base.maxOutputTokens)
|
|
997
|
+
?? (existing || prov ? positiveSafeInteger(fallback?.maxOutputTokens) : undefined);
|
|
926
998
|
// The model's own measured input ceiling still applies when discovery gave us nothing:
|
|
927
999
|
// GPT-5.6 advertises a 1.05M window but refuses input past 922k.
|
|
928
1000
|
const effectiveMaxInput = knownMaxInput ?? fallbackMaxInput;
|
|
@@ -950,6 +1022,7 @@ export function resolveComboCatalogMember(
|
|
|
950
1022
|
...(reasoningEfforts !== undefined ? { reasoningEfforts } : {}),
|
|
951
1023
|
contextWindow,
|
|
952
1024
|
maxInputTokens,
|
|
1025
|
+
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
953
1026
|
...(autoCompactTokenLimit !== undefined ? { autoCompactTokenLimit } : {}),
|
|
954
1027
|
...(fallbackCapped ? { contextCap, contextCapped: true as const } : {}),
|
|
955
1028
|
};
|
|
@@ -1233,6 +1306,12 @@ export function catalogHintsFromModelsApiItem(providerName: string, item: Provid
|
|
|
1233
1306
|
plainRecord(item.meta)?.n_ctx_train,
|
|
1234
1307
|
);
|
|
1235
1308
|
const maxInputTokens = positiveSafeInteger(limits?.max_input_tokens, item.max_input_tokens);
|
|
1309
|
+
const maxOutputTokens = positiveSafeInteger(
|
|
1310
|
+
capabilityRecord?.max_output_tokens,
|
|
1311
|
+
limits?.max_output_tokens,
|
|
1312
|
+
metadata?.max_output_tokens,
|
|
1313
|
+
item.max_output_tokens,
|
|
1314
|
+
);
|
|
1236
1315
|
// Some OpenAI-compatible catalogs expose the selectable ladder under
|
|
1237
1316
|
// `reasoning_parameters.efforts` instead of the older `reasoning_efforts` key.
|
|
1238
1317
|
// Treat both as model metadata: otherwise a valid upstream capability disappears
|
|
@@ -1260,6 +1339,7 @@ export function catalogHintsFromModelsApiItem(providerName: string, item: Provid
|
|
|
1260
1339
|
return {
|
|
1261
1340
|
...(contextWindow && contextWindow > 0 ? { contextWindow } : {}),
|
|
1262
1341
|
...(maxInputTokens && maxInputTokens > 0 ? { maxInputTokens } : {}),
|
|
1342
|
+
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
1263
1343
|
...(reasoningEfforts !== undefined ? { reasoningEfforts } : {}),
|
|
1264
1344
|
...(inputModalities ? { inputModalities } : {}),
|
|
1265
1345
|
...(capabilities ? { capabilities } : {}),
|
|
@@ -1305,7 +1385,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1305
1385
|
contextCap: number | undefined,
|
|
1306
1386
|
resolveAuth: ModelsAuthResolver,
|
|
1307
1387
|
): Promise<ProviderModelsResult> {
|
|
1308
|
-
const { name, provider: prov, discovery, request } = captured;
|
|
1388
|
+
const { name, provider: prov, discovery, request, metadataModelIdCaseFold } = captured;
|
|
1309
1389
|
const observed = (
|
|
1310
1390
|
models: CatalogModel[],
|
|
1311
1391
|
state: CatalogGatherProviderModelOutcome["state"],
|
|
@@ -1330,7 +1410,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1330
1410
|
const configured: CatalogModel[] = configuredIds.map(id => ({
|
|
1331
1411
|
id,
|
|
1332
1412
|
provider: name,
|
|
1333
|
-
...catalogHintsFromProviderConfig(name, prov, id, contextCap),
|
|
1413
|
+
...catalogHintsFromProviderConfig(name, prov, id, contextCap, metadataModelIdCaseFold),
|
|
1334
1414
|
}));
|
|
1335
1415
|
const withConfiguredRetention = (
|
|
1336
1416
|
models: CatalogModel[],
|
|
@@ -1345,6 +1425,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1345
1425
|
contextCap,
|
|
1346
1426
|
seedVertexDefault,
|
|
1347
1427
|
retainComboTargets: options?.retainComboTargets,
|
|
1428
|
+
metadataModelIdCaseFold,
|
|
1348
1429
|
});
|
|
1349
1430
|
if (
|
|
1350
1431
|
options?.warnDrops === true
|
|
@@ -1383,7 +1464,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1383
1464
|
: [{
|
|
1384
1465
|
id: prov.defaultModel,
|
|
1385
1466
|
provider: name,
|
|
1386
|
-
...catalogHintsFromProviderConfig(name, prov, prov.defaultModel, contextCap),
|
|
1467
|
+
...catalogHintsFromProviderConfig(name, prov, prov.defaultModel, contextCap, metadataModelIdCaseFold),
|
|
1387
1468
|
}];
|
|
1388
1469
|
const vertexDefaultSeed = seedVertexDefault ? configured[0] : undefined;
|
|
1389
1470
|
const withVertexDefaultSeed = (models: CatalogModel[]): CatalogModel[] => (
|
|
@@ -1400,7 +1481,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1400
1481
|
const cachedCursor = getFreshCached(name, ttlMs);
|
|
1401
1482
|
if (cachedCursor) {
|
|
1402
1483
|
return observed(
|
|
1403
|
-
withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cachedCursor)),
|
|
1484
|
+
withConfiguredRetention(applyConfigHintsToCachedModels(name, prov, cachedCursor, undefined, metadataModelIdCaseFold)),
|
|
1404
1485
|
"authoritative",
|
|
1405
1486
|
);
|
|
1406
1487
|
}
|
|
@@ -1408,7 +1489,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1408
1489
|
const cooling = getStaleCached(name);
|
|
1409
1490
|
return observed(
|
|
1410
1491
|
withConfiguredRetention(
|
|
1411
|
-
cooling ? applyConfigHintsToCachedModels(name, prov, cooling) : configured,
|
|
1492
|
+
cooling ? applyConfigHintsToCachedModels(name, prov, cooling, undefined, metadataModelIdCaseFold) : configured,
|
|
1412
1493
|
),
|
|
1413
1494
|
"degraded",
|
|
1414
1495
|
);
|
|
@@ -1422,9 +1503,6 @@ async function fetchProviderModelsWithAuth(
|
|
|
1422
1503
|
});
|
|
1423
1504
|
if (liveResult.ok) {
|
|
1424
1505
|
const available = filterCursorConfiguredModelsByLiveDiscovery(configured, liveResult.models);
|
|
1425
|
-
// Live Max-Mode evidence feeds the umbrella resolver's ultra gate
|
|
1426
|
-
// (devlog 260828_cursor_umbrella_catalog; union with static evidence).
|
|
1427
|
-
recordLiveCursorMaxModeModels(liveResult.maxModeModels ?? []);
|
|
1428
1506
|
const result = available.length > 0 ? available : configured;
|
|
1429
1507
|
// Cache the discovery-filtered roster without combo retention so a later
|
|
1430
1508
|
// gather can re-apply the current capture's retain set on read.
|
|
@@ -1432,6 +1510,13 @@ async function fetchProviderModelsWithAuth(
|
|
|
1432
1510
|
if (!setCached(name, forCache, Date.now(), cacheGeneration)) {
|
|
1433
1511
|
return observed(withConfiguredRetention(configured), "degraded");
|
|
1434
1512
|
}
|
|
1513
|
+
// Publish roster-derived state only for a discovery the cache accepted: a stale
|
|
1514
|
+
// in-flight capture (generation revoked by a credential/config change) must not
|
|
1515
|
+
// overwrite the spelling or Max-Mode evidence of the newer one.
|
|
1516
|
+
recordLiveCursorClaudeModels(liveResult.models);
|
|
1517
|
+
// Live Max-Mode evidence feeds the umbrella resolver's ultra gate
|
|
1518
|
+
// (devlog 260828_cursor_umbrella_catalog; union with static evidence).
|
|
1519
|
+
recordLiveCursorMaxModeModels(liveResult.maxModeModels ?? []);
|
|
1435
1520
|
markProviderDiscoveryOk(name, liveResult.models.length);
|
|
1436
1521
|
return observed(withConfiguredRetention(forCache, { warnDrops: true }), "authoritative");
|
|
1437
1522
|
}
|
|
@@ -1445,7 +1530,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1445
1530
|
const staleCursor = getStaleCached(name);
|
|
1446
1531
|
return observed(
|
|
1447
1532
|
withConfiguredRetention(
|
|
1448
|
-
staleCursor ? applyConfigHintsToCachedModels(name, prov, staleCursor) : configured,
|
|
1533
|
+
staleCursor ? applyConfigHintsToCachedModels(name, prov, staleCursor, undefined, metadataModelIdCaseFold) : configured,
|
|
1449
1534
|
),
|
|
1450
1535
|
"degraded",
|
|
1451
1536
|
);
|
|
@@ -1463,7 +1548,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1463
1548
|
if (fresh) {
|
|
1464
1549
|
return observed(
|
|
1465
1550
|
withConfiguredRetention(
|
|
1466
|
-
withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, fresh, contextCap)),
|
|
1551
|
+
withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, fresh, contextCap, metadataModelIdCaseFold)),
|
|
1467
1552
|
),
|
|
1468
1553
|
"authoritative",
|
|
1469
1554
|
); // dedups Codex's frequent /v1/models polling within the TTL
|
|
@@ -1475,7 +1560,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1475
1560
|
return observed(
|
|
1476
1561
|
withConfiguredRetention(
|
|
1477
1562
|
stale
|
|
1478
|
-
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap))
|
|
1563
|
+
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold))
|
|
1479
1564
|
: failedDiscoveryConfigured,
|
|
1480
1565
|
),
|
|
1481
1566
|
"degraded",
|
|
@@ -1515,7 +1600,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1515
1600
|
return {
|
|
1516
1601
|
models: withConfiguredRetention(
|
|
1517
1602
|
stale
|
|
1518
|
-
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap))
|
|
1603
|
+
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap, metadataModelIdCaseFold))
|
|
1519
1604
|
: failedDiscoveryConfigured,
|
|
1520
1605
|
),
|
|
1521
1606
|
fallback: stale ? "stale" : "configured",
|
|
@@ -1592,7 +1677,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1592
1677
|
reasoningEfforts: [],
|
|
1593
1678
|
...(model.contextWindow ? { contextWindow: model.contextWindow } : {}),
|
|
1594
1679
|
...(model.inputModalities ? { inputModalities: model.inputModalities } : {}),
|
|
1595
|
-
}, contextCap));
|
|
1680
|
+
}, contextCap, metadataModelIdCaseFold));
|
|
1596
1681
|
const forCache = withConfiguredRetention(live, { retainComboTargets: false });
|
|
1597
1682
|
if (!setCached(name, forCache, Date.now(), cacheGeneration)) {
|
|
1598
1683
|
return observed(withConfiguredRetention(configured), "degraded");
|
|
@@ -1655,7 +1740,7 @@ async function fetchProviderModelsWithAuth(
|
|
|
1655
1740
|
provider: name,
|
|
1656
1741
|
...(ownedBy ? { owned_by: ownedBy } : {}),
|
|
1657
1742
|
...discoveredHints,
|
|
1658
|
-
}, contextCap);
|
|
1743
|
+
}, contextCap, metadataModelIdCaseFold);
|
|
1659
1744
|
})
|
|
1660
1745
|
.filter(m => shouldExposeProviderModel(name, m.id));
|
|
1661
1746
|
// Capture the count BEFORE the alias/configured augmentation below pushes extra rows into
|
|
@@ -1752,6 +1837,7 @@ export function mergeConfiguredModelsIntoLiveCatalog(opts: {
|
|
|
1752
1837
|
contextCap?: number;
|
|
1753
1838
|
seedVertexDefault?: boolean;
|
|
1754
1839
|
retainComboTargets?: boolean;
|
|
1840
|
+
metadataModelIdCaseFold?: boolean;
|
|
1755
1841
|
}): { models: CatalogModel[]; droppedConfiguredIds: string[] } {
|
|
1756
1842
|
const {
|
|
1757
1843
|
name,
|
|
@@ -1761,6 +1847,7 @@ export function mergeConfiguredModelsIntoLiveCatalog(opts: {
|
|
|
1761
1847
|
contextCap,
|
|
1762
1848
|
seedVertexDefault,
|
|
1763
1849
|
retainComboTargets = true,
|
|
1850
|
+
metadataModelIdCaseFold,
|
|
1764
1851
|
} = opts;
|
|
1765
1852
|
const out = [...opts.models];
|
|
1766
1853
|
const present = new Set(out.map(model => model.id));
|
|
@@ -1769,7 +1856,7 @@ export function mergeConfiguredModelsIntoLiveCatalog(opts: {
|
|
|
1769
1856
|
if (present.has(candidate.id)) continue;
|
|
1770
1857
|
const dated = out.find(live => isDatedVariantId(live.id, candidate.id));
|
|
1771
1858
|
if (dated) {
|
|
1772
|
-
out.push(applyProviderConfigHints(name, prov, { ...dated, id: candidate.id }, contextCap));
|
|
1859
|
+
out.push(applyProviderConfigHints(name, prov, { ...dated, id: candidate.id }, contextCap, metadataModelIdCaseFold));
|
|
1773
1860
|
present.add(candidate.id);
|
|
1774
1861
|
continue;
|
|
1775
1862
|
}
|
|
@@ -1955,7 +2042,16 @@ async function gatherRoutedModelsUncached(
|
|
|
1955
2042
|
config,
|
|
1956
2043
|
capture.openAiApiPolicy,
|
|
1957
2044
|
);
|
|
1958
|
-
const
|
|
2045
|
+
const metadataModelIdCaseFoldByProvider = new Map(
|
|
2046
|
+
activeProviders.map(provider => [provider.name, provider.metadataModelIdCaseFold]),
|
|
2047
|
+
);
|
|
2048
|
+
const all = augmentRoutedModelsWithMetadata(
|
|
2049
|
+
apiAugmented,
|
|
2050
|
+
activeProviders.map(provider => provider.name),
|
|
2051
|
+
config.providers,
|
|
2052
|
+
config,
|
|
2053
|
+
metadataModelIdCaseFoldByProvider,
|
|
2054
|
+
)
|
|
1959
2055
|
// Drop image/video generation models (e.g. Grok image/video) by default. Cursor's static catalog
|
|
1960
2056
|
// intentionally mirrors Cursor's public model table, including Gemini image preview, so the
|
|
1961
2057
|
// exposure decision goes through shouldExposeRoutedModel (single choke point).
|
|
@@ -2009,6 +2105,9 @@ async function gatherRoutedModelsUncached(
|
|
|
2009
2105
|
// stay separate fields because routed/API rows of the same family run a wider window.
|
|
2010
2106
|
// Falls back to the window for slugs with no separate ceiling.
|
|
2011
2107
|
maxInputTokens: Math.min(nativeOpenAiMaxInputTokens(slug, openaiContextCap) ?? contextWindow, contextWindow),
|
|
2108
|
+
...(nativeOpenAiMaxOutputTokens(slug) !== undefined
|
|
2109
|
+
? { maxOutputTokens: nativeOpenAiMaxOutputTokens(slug) }
|
|
2110
|
+
: {}),
|
|
2012
2111
|
autoCompactTokenLimit: nativeOpenAiAutoCompactTokenLimit(slug, openaiContextCap),
|
|
2013
2112
|
inputModalities: nativeInputModalities(slug),
|
|
2014
2113
|
reasoningEfforts: nativeReasoningEfforts(slug),
|
|
@@ -2042,6 +2141,9 @@ async function gatherRoutedModelsUncached(
|
|
|
2042
2141
|
? {
|
|
2043
2142
|
contextWindow: nativeContextWindow,
|
|
2044
2143
|
...(nativeAliasMaxInput !== undefined ? { maxInputTokens: nativeAliasMaxInput } : {}),
|
|
2144
|
+
...(nativeOpenAiMaxOutputTokens(combo.alias) !== undefined
|
|
2145
|
+
? { maxOutputTokens: nativeOpenAiMaxOutputTokens(combo.alias) }
|
|
2146
|
+
: {}),
|
|
2045
2147
|
...(nativeAliasAutoCompact !== undefined ? { autoCompactTokenLimit: nativeAliasAutoCompact } : {}),
|
|
2046
2148
|
inputModalities: nativeInputModalities(combo.alias),
|
|
2047
2149
|
reasoningEfforts: nativeReasoningEfforts(combo.alias),
|
|
@@ -2054,6 +2156,7 @@ async function gatherRoutedModelsUncached(
|
|
|
2054
2156
|
enrichedByName,
|
|
2055
2157
|
providerContextCap(config, target.provider),
|
|
2056
2158
|
nativeAliasFallback,
|
|
2159
|
+
metadataModelIdCaseFoldByProvider.get(target.provider),
|
|
2057
2160
|
))
|
|
2058
2161
|
.filter((member): member is CatalogModel => member !== undefined);
|
|
2059
2162
|
const derived = deriveComboCatalogModel(id, combo, members);
|
|
@@ -2105,6 +2208,9 @@ async function gatherRoutedModelsUncached(
|
|
|
2105
2208
|
const nativeAliasMaxInputTokens = codexForwardNativeCapabilityAlias
|
|
2106
2209
|
? nativeOpenAiMaxInputTokens(cm.modelId, customNativeLimits)
|
|
2107
2210
|
: undefined;
|
|
2211
|
+
const nativeAliasMaxOutputTokens = codexForwardNativeCapabilityAlias
|
|
2212
|
+
? nativeOpenAiMaxOutputTokens(cm.modelId)
|
|
2213
|
+
: undefined;
|
|
2108
2214
|
const configuredMaxInput = rawProvider
|
|
2109
2215
|
? configuredMaxInputTokens(rawProvider, cm.modelId)
|
|
2110
2216
|
: undefined;
|
|
@@ -2116,6 +2222,13 @@ async function gatherRoutedModelsUncached(
|
|
|
2116
2222
|
...(customContextWindow !== undefined ? [customContextWindow] : []),
|
|
2117
2223
|
)
|
|
2118
2224
|
: undefined;
|
|
2225
|
+
const customMaxOutputTokens = rawProvider
|
|
2226
|
+
? routedMaxOutputTokens(cm.provider, rawProvider, {
|
|
2227
|
+
id: cm.modelId,
|
|
2228
|
+
provider: cm.provider,
|
|
2229
|
+
...(nativeAliasMaxOutputTokens !== undefined ? { maxOutputTokens: nativeAliasMaxOutputTokens } : {}),
|
|
2230
|
+
}, cm.modelId, metadataModelIdCaseFoldByProvider.get(cm.provider))
|
|
2231
|
+
: nativeAliasMaxOutputTokens;
|
|
2119
2232
|
const configuredAutoCompact = configuredAutoCompactTokenLimit(rawProvider, cm.modelId);
|
|
2120
2233
|
const customAutoCompactTokenLimit = codexForwardNativeCapabilityAlias
|
|
2121
2234
|
? nativeOpenAiAutoCompactTokenLimit(cm.modelId, customNativeLimits)
|
|
@@ -2142,6 +2255,7 @@ async function gatherRoutedModelsUncached(
|
|
|
2142
2255
|
: codexForwardNativeCapabilityAlias ? { displayName: "Daybreak Blue" } : {}),
|
|
2143
2256
|
...(customContextWindow !== undefined ? { contextWindow: customContextWindow } : {}),
|
|
2144
2257
|
...(customMaxInputTokens !== undefined ? { maxInputTokens: customMaxInputTokens } : {}),
|
|
2258
|
+
...(customMaxOutputTokens !== undefined ? { maxOutputTokens: customMaxOutputTokens } : {}),
|
|
2145
2259
|
...(customAutoCompactTokenLimit !== undefined ? { autoCompactTokenLimit: customAutoCompactTokenLimit } : {}),
|
|
2146
2260
|
...(cm.inputModalities
|
|
2147
2261
|
? { inputModalities: cm.inputModalities }
|
|
@@ -2193,10 +2307,16 @@ async function gatherRoutedModelsUncached(
|
|
|
2193
2307
|
const mergedMaxInput = mergedMaxInputCandidates.length > 0
|
|
2194
2308
|
? Math.min(...mergedMaxInputCandidates)
|
|
2195
2309
|
: undefined;
|
|
2310
|
+
const mergedMaxOutputCandidates = [base.maxOutputTokens, replaced?.maxOutputTokens]
|
|
2311
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
2312
|
+
const mergedMaxOutput = mergedMaxOutputCandidates.length > 0
|
|
2313
|
+
? Math.min(...mergedMaxOutputCandidates)
|
|
2314
|
+
: undefined;
|
|
2196
2315
|
const merged: CatalogModel = replaced ? {
|
|
2197
2316
|
...base,
|
|
2198
2317
|
...(base.contextWindow === undefined && replaced.contextWindow !== undefined ? { contextWindow: replaced.contextWindow } : {}),
|
|
2199
2318
|
...(mergedMaxInput !== undefined ? { maxInputTokens: mergedMaxInput } : {}),
|
|
2319
|
+
...(mergedMaxOutput !== undefined ? { maxOutputTokens: mergedMaxOutput } : {}),
|
|
2200
2320
|
...(base.autoCompactTokenLimit === undefined && replaced.autoCompactTokenLimit !== undefined
|
|
2201
2321
|
? { autoCompactTokenLimit: replaced.autoCompactTokenLimit }
|
|
2202
2322
|
: {}),
|
|
@@ -2331,12 +2451,19 @@ function augmentRoutedModelsWithCapturedOpenAiApiRows(
|
|
|
2331
2451
|
const autoCompactTokenLimit = contextWindow !== undefined && configuredAutoCompact !== undefined
|
|
2332
2452
|
? clampAutoCompactTokenLimit(contextWindow, maxInputTokens, configuredAutoCompact)
|
|
2333
2453
|
: undefined;
|
|
2454
|
+
const maxOutputTokens = routedMaxOutputTokens(
|
|
2455
|
+
OPENAI_API_PROVIDER_ID,
|
|
2456
|
+
configured,
|
|
2457
|
+
existingById.get(id) ?? { provider: OPENAI_API_PROVIDER_ID, id },
|
|
2458
|
+
policy.virtualModels?.[id]?.wireModelId ?? id,
|
|
2459
|
+
);
|
|
2334
2460
|
return {
|
|
2335
2461
|
provider: OPENAI_API_PROVIDER_ID,
|
|
2336
2462
|
id,
|
|
2337
2463
|
owned_by: OPENAI_API_PROVIDER_ID,
|
|
2338
2464
|
...(contextWindow ? { contextWindow } : {}),
|
|
2339
2465
|
...(maxInputTokens ? { maxInputTokens } : {}),
|
|
2466
|
+
...(maxOutputTokens !== undefined ? { maxOutputTokens } : {}),
|
|
2340
2467
|
...(autoCompactTokenLimit !== undefined ? { autoCompactTokenLimit } : {}),
|
|
2341
2468
|
...(policy.modelInputModalities?.[id] ? { inputModalities: [...policy.modelInputModalities[id]!] } : {}),
|
|
2342
2469
|
...(policy.modelReasoningEfforts?.[id] ? { reasoningEfforts: [...policy.modelReasoningEfforts[id]!] } : {}),
|
|
@@ -2366,6 +2493,7 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
2366
2493
|
providerNames: string[],
|
|
2367
2494
|
providers?: Record<string, OcxProviderConfig>,
|
|
2368
2495
|
caps?: Pick<OcxConfig, "providerContextCaps">,
|
|
2496
|
+
metadataModelIdCaseFoldByProvider?: ReadonlyMap<string, boolean>,
|
|
2369
2497
|
): CatalogModel[] {
|
|
2370
2498
|
const out = [...models];
|
|
2371
2499
|
const seen = new Set(out.map(m => `${m.provider}/${m.id}`));
|
|
@@ -2384,11 +2512,20 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
2384
2512
|
id: meta.id,
|
|
2385
2513
|
owned_by: provider,
|
|
2386
2514
|
...(typeof meta.contextWindow === "number" && meta.contextWindow > 0 ? { contextWindow: meta.contextWindow } : {}),
|
|
2515
|
+
...(typeof meta.maxTokens === "number" && meta.maxTokens > 0 ? { maxOutputTokens: meta.maxTokens } : {}),
|
|
2387
2516
|
...(Array.isArray(meta.input) && meta.input.length > 0 ? { inputModalities: [...meta.input] } : {}),
|
|
2388
2517
|
};
|
|
2389
2518
|
out.push({
|
|
2390
2519
|
...model,
|
|
2391
|
-
...(providers?.[provider]
|
|
2520
|
+
...(providers?.[provider]
|
|
2521
|
+
? applyProviderConfigHints(
|
|
2522
|
+
provider,
|
|
2523
|
+
providers[provider],
|
|
2524
|
+
model,
|
|
2525
|
+
contextCap,
|
|
2526
|
+
metadataModelIdCaseFoldByProvider?.get(provider),
|
|
2527
|
+
)
|
|
2528
|
+
: {}),
|
|
2392
2529
|
});
|
|
2393
2530
|
}
|
|
2394
2531
|
}
|
package/src/codex/catalog.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Public surface preserved exactly; importers keep using "src/codex/catalog".
|
|
3
3
|
export { isMediaGenerationModelId, shouldExposeRoutedModel, readCodexCatalogPath, readCatalog, normalizeRoutedCatalogEntry, catalogModelSlug, filterSupportedNativeSlugs, catalogModelSupportsReasoningSummaries } from "./catalog/parsing";
|
|
4
4
|
export type { CatalogModel, MultiAgentMode } from "./catalog/parsing";
|
|
5
|
-
export { accountBoundNativeOpenAiSlugs, accountBoundNativeOpenAiSlugsBySelector, CODEX_NATIVE_ALIAS_CATALOG_KIND, NATIVE_DAYBREAK_BLUE_MODEL, NATIVE_GPT56_CONTEXT_WINDOW, NATIVE_GPT56_MAX_INPUT_TOKENS, NATIVE_GPT56_OPT_IN_CONTEXT_WINDOW, NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS, NATIVE_OPENAI_MODELS, configuredNativeAliasSlugs, desktopAllowlistSuppressedNativeSlugs, isNativeAliasCatalogEntry, isNativeOpenAiCapabilityAliasModel, nativeContextLimits, nativeOpenAiCapabilitySourceSlug, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiContextTier, disabledNativeSlugs, visibleNativeSlugs, desktopVisibleNativeSlugs, nativeModelRows, applyNativeVisibility, observedAccountBoundNativeEntries, observedAccountBoundNativeOpenAiSlugs, upstreamNativeEntry, nativeOpenAiSlugs, listCatalogNativeSlugs, nativeInputModalities, nativeReasoningEfforts, nativeDefaultReasoningEffort, shouldIncludeAccountBoundNativeOpenAi, shouldIncludeNativeOpenAi, type NativeContextLimits, type NativeContextLimitsInput } from "./catalog/metadata";
|
|
5
|
+
export { accountBoundNativeOpenAiSlugs, accountBoundNativeOpenAiSlugsBySelector, CODEX_NATIVE_ALIAS_CATALOG_KIND, NATIVE_DAYBREAK_BLUE_MODEL, NATIVE_GPT56_CONTEXT_WINDOW, NATIVE_GPT56_MAX_INPUT_TOKENS, NATIVE_GPT56_OPT_IN_CONTEXT_WINDOW, NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS, NATIVE_OPENAI_MODELS, configuredNativeAliasSlugs, desktopAllowlistSuppressedNativeSlugs, isNativeAliasCatalogEntry, isNativeOpenAiCapabilityAliasModel, nativeContextLimits, nativeOpenAiCapabilitySourceSlug, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiMaxOutputTokens, nativeOpenAiContextTier, disabledNativeSlugs, visibleNativeSlugs, desktopVisibleNativeSlugs, nativeModelRows, applyNativeVisibility, observedAccountBoundNativeEntries, observedAccountBoundNativeOpenAiSlugs, upstreamNativeEntry, nativeOpenAiSlugs, listCatalogNativeSlugs, nativeInputModalities, nativeReasoningEfforts, nativeDefaultReasoningEffort, shouldIncludeAccountBoundNativeOpenAi, shouldIncludeNativeOpenAi, type NativeContextLimits, type NativeContextLimitsInput } 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
8
|
export { applyProviderConfigHints, isDatedVariantId, filterCatalogVisibleModels, gatherRoutedModels, clearGatherRoutedModelsInflight, augmentRoutedModelsWithRegistryOpenAiApiRows, augmentRoutedModelsWithMetadata, resolveComboCatalogMember, configuredComboTargetModelsByProvider } from "./catalog/provider-fetch";
|
|
@@ -429,6 +429,7 @@ export interface CatalogTrustedOpenAiApiPolicySnapshot {
|
|
|
429
429
|
readonly models?: readonly string[];
|
|
430
430
|
readonly modelContextWindows?: Readonly<Record<string, number>>;
|
|
431
431
|
readonly modelMaxInputTokens?: Readonly<Record<string, number>>;
|
|
432
|
+
readonly virtualModels?: Readonly<Record<string, Readonly<{ wireModelId: string; reasoningMode: "pro" }>>>;
|
|
432
433
|
readonly modelInputModalities?: Readonly<Record<string, readonly string[]>>;
|
|
433
434
|
readonly modelReasoningEfforts?: Readonly<Record<string, readonly string[]>>;
|
|
434
435
|
}
|
|
@@ -71,15 +71,25 @@ export function codexIntegrationEnabled(config: Pick<OcxConfig, "clientIntegrati
|
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
/** Whether a Codex sync is permitted for this admitted config snapshot. */
|
|
74
|
-
|
|
74
|
+
type LocalClientSyncConfig = Pick<
|
|
75
|
+
OcxConfig,
|
|
76
|
+
"clientIntegrations" | "runtimeRole" | "unauthenticatedLoopbackListener"
|
|
77
|
+
>;
|
|
78
|
+
|
|
79
|
+
function localClientSyncAllowed(config: LocalClientSyncConfig): boolean {
|
|
80
|
+
return config.runtimeRole !== "hub"
|
|
81
|
+
|| config.unauthenticatedLoopbackListener?.enabled === true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function shouldSyncCodexOnStart(config: LocalClientSyncConfig): boolean {
|
|
75
85
|
// A hub is a server for OTHER machines: it must not rewrite its own host's
|
|
76
86
|
// Codex/Claude/Grok client configs on startup (interview decision Q6, and the
|
|
77
87
|
// first clisu-oracle dogfood boot proved the failure mode — the hub marked
|
|
78
88
|
// /readyz failed because it tried to run the full local client sync).
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
return codexIntegrationEnabled(config);
|
|
89
|
+
// A hub can be a local client only through its explicitly enabled loopback
|
|
90
|
+
// listener. The public hub bind remains outside this gate and still requires
|
|
91
|
+
// admission; an explicit client OFF continues to win.
|
|
92
|
+
return localClientSyncAllowed(config) && codexIntegrationEnabled(config);
|
|
83
93
|
}
|
|
84
94
|
|
|
85
95
|
/**
|
|
@@ -189,7 +199,7 @@ export function setClaudeDesktopIntegrationEnabled(enabled: boolean): CodexDesir
|
|
|
189
199
|
*/
|
|
190
200
|
export async function syncCodexOnStartIfEnabled(
|
|
191
201
|
port: number,
|
|
192
|
-
config:
|
|
202
|
+
config: LocalClientSyncConfig,
|
|
193
203
|
sync: CodexStartupSync = defaultStartupSync,
|
|
194
204
|
readinessGate?: ReadinessGate,
|
|
195
205
|
): Promise<{ ran: boolean; catalogWritten: boolean; cacheSynced: boolean }> {
|
|
@@ -232,9 +242,6 @@ async function defaultStartupSync(port: number): Promise<CodexStartupSyncOutcome
|
|
|
232
242
|
* startup and its diagnostic is worth printing. This only answers whether to
|
|
233
243
|
* attempt the sync at all.
|
|
234
244
|
*/
|
|
235
|
-
export function shouldSyncGrokOnStart(config:
|
|
236
|
-
|
|
237
|
-
// host's client configs on startup.
|
|
238
|
-
if (config.runtimeRole === "hub") return false;
|
|
239
|
-
return grokIntegrationEnabled(config);
|
|
245
|
+
export function shouldSyncGrokOnStart(config: LocalClientSyncConfig): boolean {
|
|
246
|
+
return localClientSyncAllowed(config) && grokIntegrationEnabled(config);
|
|
240
247
|
}
|