@yansigit/opencodex 2.32.0 → 2.33.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/gui/dist/assets/index-CIDo4y4k.js +102 -0
- package/gui/dist/assets/index-DrSQdTRd.css +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +8 -5
- package/src/adapters/anthropic.ts +20 -6
- package/src/adapters/azure.ts +20 -4
- package/src/adapters/base.ts +3 -1
- package/src/adapters/command-code.ts +131 -17
- package/src/adapters/cursor/envelope-echo.ts +162 -0
- package/src/adapters/cursor/live-transport.ts +4 -2
- package/src/adapters/cursor/native-exec-fs.ts +13 -12
- package/src/adapters/cursor/native-exec-network.ts +3 -5
- package/src/adapters/cursor/native-exec-policy.ts +47 -0
- package/src/adapters/cursor/native-exec-shell.ts +13 -25
- package/src/adapters/cursor/native-exec.ts +18 -10
- package/src/adapters/cursor/protobuf-events.ts +186 -9
- package/src/adapters/cursor/protobuf-request.ts +53 -18
- package/src/adapters/cursor/request-builder.ts +11 -3
- package/src/adapters/cursor/tool-definitions.ts +49 -2
- package/src/adapters/cursor/tool-result-normalize.ts +21 -8
- package/src/adapters/cursor/types.ts +11 -3
- package/src/adapters/cursor.ts +123 -0
- package/src/adapters/google-aistudio-parser.ts +49 -0
- package/src/adapters/google-antigravity-replay.ts +2 -2
- package/src/adapters/google-antigravity-wire.ts +7 -0
- package/src/adapters/google-errors.ts +6 -2
- package/src/adapters/google-http.ts +30 -7
- package/src/adapters/google-truncation.ts +5 -0
- package/src/adapters/google-wire-compiler.ts +38 -6
- package/src/adapters/google.ts +242 -28
- package/src/adapters/kiro-tools.ts +20 -9
- package/src/adapters/openai-chat.ts +9 -0
- package/src/adapters/openai-responses.ts +2 -1
- package/src/bridge.ts +112 -9
- package/src/chat/inbound.ts +15 -0
- package/src/claude/context-windows.ts +16 -9
- package/src/cli/doctor.ts +2 -2
- package/src/cli/index.ts +10 -3
- package/src/cli/provider.ts +6 -0
- package/src/cli/status.ts +23 -0
- package/src/codex/auth-api.ts +4 -2
- package/src/codex/autostart-health.ts +16 -0
- package/src/codex/catalog/aggregation.ts +12 -12
- package/src/codex/catalog/effort.ts +18 -3
- package/src/codex/catalog/metadata.ts +27 -1
- package/src/codex/catalog/model-metadata.ts +39 -12
- package/src/codex/catalog/parsing.ts +38 -27
- package/src/codex/catalog/provider-fetch.ts +232 -133
- package/src/codex/catalog/sync.ts +1 -1
- package/src/codex/convergence.ts +5 -0
- package/src/codex/shim.ts +56 -3
- package/src/config/provider-validation.ts +37 -0
- package/src/config.ts +78 -2
- package/src/generated/compatibility-version.json +187 -119
- package/src/generated/model-metadata.ts +3 -0
- package/src/images/loop.ts +37 -6
- package/src/lib/azure-identity.ts +154 -0
- package/src/lib/debug.ts +42 -0
- package/src/lib/errors.ts +14 -0
- package/src/lib/provider-outbound.ts +45 -33
- package/src/lib/provider-tls-profile.ts +309 -0
- package/src/lib/proxy-env.ts +49 -0
- package/src/lib/redact.ts +10 -1
- package/src/oauth/aistudio-native-daemon.ts +62 -0
- package/src/oauth/aistudio-session-sync.ts +95 -0
- package/src/oauth/antigravity-routing.ts +282 -236
- package/src/oauth/callback-server.ts +22 -2
- package/src/oauth/command-code.ts +5 -16
- package/src/oauth/google-aistudio-auth.ts +98 -0
- package/src/oauth/google-antigravity.ts +42 -5
- package/src/oauth/index.ts +15 -3
- package/src/oauth/key-providers.ts +8 -0
- package/src/oauth/kimi.ts +9 -1
- package/src/oauth/login-cli.ts +66 -1
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +6 -0
- package/src/providers/antigravity-quota.ts +3 -1
- package/src/providers/api-keys.ts +2 -1
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/derive.ts +5 -1
- package/src/providers/key-failover.ts +5 -1
- package/src/providers/openai-tiers.ts +5 -0
- package/src/providers/provider-id-rewrite.ts +1 -0
- package/src/providers/quota.ts +148 -50
- package/src/providers/registry.ts +27 -4
- package/src/providers/request-pacing.ts +33 -6
- package/src/providers/xai-transport.ts +21 -0
- package/src/responses/google-provider-options.ts +36 -0
- package/src/responses/namespace-tool-compat.ts +84 -4
- package/src/responses/parser.ts +11 -0
- package/src/responses/provider-opaque-metadata.ts +3 -3
- package/src/responses/schema.ts +37 -0
- package/src/responses/state.ts +94 -4
- package/src/router.ts +11 -2
- package/src/routing/account-pool/cooldown.ts +8 -0
- package/src/routing/account-pool/index.ts +1 -0
- package/src/server/aistudio-ws-hub.ts +295 -0
- package/src/server/auth-cors.ts +29 -0
- package/src/server/chat-completions.ts +2 -0
- package/src/server/images.ts +19 -35
- package/src/server/index.ts +94 -0
- package/src/server/management/agent-settings-routes.ts +205 -15
- package/src/server/management/combo-routes.ts +6 -0
- package/src/server/management/config-routes.ts +31 -5
- package/src/server/management/logs-usage-routes.ts +11 -5
- package/src/server/management/model-rows.ts +4 -0
- package/src/server/management/oauth-account-routes.ts +38 -7
- package/src/server/management/provider-routes.ts +113 -15
- package/src/server/management/routing-profile-routes.ts +3 -0
- package/src/server/port-reclaim.ts +19 -1
- package/src/server/request-log-conversation.ts +12 -0
- package/src/server/request-log.ts +23 -1
- package/src/server/responses/agent-task-recovery.ts +1 -1
- package/src/server/responses/compact.ts +30 -1
- package/src/server/responses/core.ts +363 -156
- package/src/server/responses/empty-completion-guard.ts +35 -6
- package/src/server/responses/fetch-helpers.ts +18 -5
- package/src/server/responses/policy-fallback.ts +1 -1
- package/src/server/responses/v2-native-parent-override.ts +59 -0
- package/src/server/responses/ws-upstream.ts +75 -2
- package/src/server/responses-undeclared-tool-guard.ts +90 -8
- package/src/server/ws-bridge.ts +2 -1
- package/src/service.ts +1 -1
- package/src/smoke/fingerprint-cache.ts +133 -0
- package/src/smoke/live-scenarios.ts +33 -0
- package/src/smoke/runner.ts +119 -0
- package/src/types/config.ts +16 -1
- package/src/types/provider.ts +18 -1
- package/src/types/request.ts +30 -0
- package/src/types/tools.ts +51 -0
- package/src/types.ts +6 -0
- package/src/usage/command-code-manifest.ts +116 -0
- package/src/usage/cost.ts +2 -2
- package/src/usage/expected-prices.ts +83 -0
- package/src/usage/log.ts +2 -2
- package/src/usage/summary.ts +34 -12
- package/src/web-search/gemini-executor.ts +6 -4
- package/src/web-search/index.ts +16 -8
- package/src/web-search/loop.ts +42 -6
- package/gui/dist/assets/index-BG43zwVe.js +0 -102
- package/gui/dist/assets/index-CiSI-jrP.css +0 -1
|
@@ -41,11 +41,13 @@ import type { FastPolicyAuthority } from "../../providers/fastwire";
|
|
|
41
41
|
import { effectiveGoogleMode, getProviderRegistryEntry, providerMatchesRegistryTransport } from "../../providers/registry";
|
|
42
42
|
import { parseAntigravityAvailableModels, registerAntigravityDiscoveredWireModels } from "../../providers/antigravity-models";
|
|
43
43
|
import { applyProviderContextCap, providerContextCap, resolveUnknownRoutedContextWindow } from "../../providers/context-cap";
|
|
44
|
-
import {
|
|
44
|
+
import { clampAutoCompactTokenLimit } from "../../providers/auto-compact-budget";
|
|
45
|
+
import { routedSlug, slugEquals, slugEquivalenceKey, slugsEquivalent } from "../../providers/slug-codec";
|
|
45
46
|
import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
|
|
46
47
|
import { filterCursorConfiguredModelsByLiveDiscovery } from "../../adapters/cursor/discovery";
|
|
47
48
|
import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
|
|
48
49
|
import { isCanonicalOpenAiForwardProvider, OPENAI_API_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
|
|
50
|
+
import { globalAiStudioRelayHub } from "../../server/aistudio-ws-hub";
|
|
49
51
|
import {
|
|
50
52
|
COMBO_NAMESPACE,
|
|
51
53
|
comboModelId,
|
|
@@ -60,6 +62,7 @@ import {
|
|
|
60
62
|
providerOutboundPost,
|
|
61
63
|
providerRedirectError,
|
|
62
64
|
} from "../../lib/provider-outbound";
|
|
65
|
+
import { isAntigravityOAuthProvider } from "../../lib/provider-tls-profile";
|
|
63
66
|
import { redactSecretString } from "../../lib/redact";
|
|
64
67
|
import {
|
|
65
68
|
extractProviderModelItems,
|
|
@@ -75,8 +78,7 @@ import { createAdmissionGate, ResourceAdmissionError, type AdmissionMetrics } fr
|
|
|
75
78
|
|
|
76
79
|
import { CODEX_CUSTOM_MODEL_CATALOG_KIND, JAWCODE_CATALOG_AUGMENT_PROVIDERS, catalogModelSlug, shouldExposeRoutedModel } from "./parsing";
|
|
77
80
|
import type { CatalogModel } from "./parsing";
|
|
78
|
-
import {
|
|
79
|
-
import { disabledNativeSlugs, hasComboTargets, isNativeOpenAiCapabilityAliasModel, NATIVE_GPT56_MAX_INPUT_TOKENS, nativeContextLimits, nativeDefaultReasoningEffort, nativeInputModalities, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiSlugs, nativeParallelToolCalls, nativeReasoningEfforts } from "./metadata";
|
|
81
|
+
import { disabledNativeSlugs, hasComboTargets, isNativeOpenAiCapabilityAliasModel, NATIVE_GPT56_MAX_INPUT_TOKENS, nativeContextLimits, nativeDefaultReasoningEffort, nativeInputModalities, nativeOpenAiAutoCompactTokenLimit, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiSlugs, nativeParallelToolCalls, nativeReasoningEfforts } from "./metadata";
|
|
80
82
|
import { deriveComboCatalogModel, normalizedOpenAiApiSignature, openAiApiCollisionWarnings, replaceLastComboCatalogOmissions, warnUncataloguedComboOnce } from "./aggregation";
|
|
81
83
|
import type { ComboCatalogOmission } from "./aggregation";
|
|
82
84
|
import type { CatalogGatherProviderAuthEvidence } from "./filesystem-evidence";
|
|
@@ -572,6 +574,7 @@ function providerCatalogFingerprint(name: string, prov: OcxProviderConfig): Reco
|
|
|
572
574
|
ctx: prov.contextWindow ?? null,
|
|
573
575
|
ctxW: prov.modelContextWindows ?? null,
|
|
574
576
|
maxIn: prov.modelMaxInputTokens ?? null,
|
|
577
|
+
autoCompact: prov.modelAutoCompactTokenLimits ?? null,
|
|
575
578
|
inMod: prov.modelInputModalities ?? null,
|
|
576
579
|
re: prov.modelReasoningEfforts ?? null,
|
|
577
580
|
defRe: prov.modelDefaultReasoningEfforts ?? null,
|
|
@@ -626,6 +629,17 @@ export function configuredMaxInputTokens(prov: OcxProviderConfig, id: string): n
|
|
|
626
629
|
return typeof configured === "number" && configured > 0 ? configured : undefined;
|
|
627
630
|
}
|
|
628
631
|
|
|
632
|
+
export function configuredAutoCompactTokenLimit(
|
|
633
|
+
prov: OcxProviderConfig | undefined,
|
|
634
|
+
id: string,
|
|
635
|
+
): number | undefined {
|
|
636
|
+
if (!prov) return undefined;
|
|
637
|
+
const configured = modelRecordValue(prov.modelAutoCompactTokenLimits, id);
|
|
638
|
+
return typeof configured === "number" && Number.isSafeInteger(configured) && configured > 0
|
|
639
|
+
? configured
|
|
640
|
+
: undefined;
|
|
641
|
+
}
|
|
642
|
+
|
|
629
643
|
function configuredReasoningSummarySupport(prov: OcxProviderConfig | undefined, id: string): boolean | undefined {
|
|
630
644
|
if (!prov) return undefined;
|
|
631
645
|
const explicit = modelRecordValue(prov.modelSupportsReasoningSummaries, id);
|
|
@@ -637,6 +651,7 @@ export function applyProviderConfigHints(name: string, prov: OcxProviderConfig,
|
|
|
637
651
|
void name;
|
|
638
652
|
const configuredCap = configuredContextWindow(prov, model.id);
|
|
639
653
|
const configuredMaxInput = configuredMaxInputTokens(prov, model.id);
|
|
654
|
+
const configuredAutoCompact = configuredAutoCompactTokenLimit(prov, model.id);
|
|
640
655
|
let inputModalities = configuredInputModalities(prov, model.id);
|
|
641
656
|
// Vision-sidecar coverage: `noVisionModels` marks models whose images the PROXY describes
|
|
642
657
|
// (src/vision/index.ts). The catalog must still advertise image input for them — the Codex app
|
|
@@ -663,16 +678,9 @@ export function applyProviderConfigHints(name: string, prov: OcxProviderConfig,
|
|
|
663
678
|
const hintedWindow = discoveredWindow !== undefined
|
|
664
679
|
? (configuredCap !== undefined ? Math.min(discoveredWindow, configuredCap) : discoveredWindow)
|
|
665
680
|
: (configuredCap ?? (providerCap !== undefined ? resolveUnknownRoutedContextWindow(providerCap) : undefined));
|
|
666
|
-
const capFilledMissingWindow = discoveredWindow === undefined && hintedWindow !== undefined;
|
|
667
681
|
const hinted = {
|
|
668
682
|
...modelWithoutServiceTier,
|
|
669
683
|
...(hintedWindow !== undefined ? { contextWindow: hintedWindow } : {}),
|
|
670
|
-
...(discoveredWindow !== undefined
|
|
671
|
-
? { detectedContextWindow: model.detectedContextWindow ?? discoveredWindow }
|
|
672
|
-
: {}),
|
|
673
|
-
...(capFilledMissingWindow && !model.metadataSource
|
|
674
|
-
? { metadataSource: "config_fallback" as const }
|
|
675
|
-
: {}),
|
|
676
684
|
...(inputModalities ? { inputModalities } : {}),
|
|
677
685
|
...(reasoningEfforts !== undefined ? { reasoningEfforts } : {}),
|
|
678
686
|
...(configuredMaxInput !== undefined
|
|
@@ -697,26 +705,31 @@ export function applyProviderConfigHints(name: string, prov: OcxProviderConfig,
|
|
|
697
705
|
...(prov.codexToolMode !== undefined ? { codexToolMode: prov.codexToolMode } : {}),
|
|
698
706
|
};
|
|
699
707
|
const capped = applyProviderContextCap(hinted.contextWindow, providerCap);
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
&& (
|
|
705
|
-
capped !== hinted.contextWindow
|
|
706
|
-
|| (typeof detectedContextWindow === "number" && detectedContextWindow > capped)
|
|
707
|
-
|| hinted.contextCapped === true
|
|
708
|
-
);
|
|
709
|
-
if (providerCap !== undefined && capped !== hinted.contextWindow) {
|
|
710
|
-
return {
|
|
711
|
-
...hinted,
|
|
712
|
-
contextWindow: capped,
|
|
713
|
-
contextCap: providerCap,
|
|
714
|
-
contextCapped,
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
return providerCap !== undefined
|
|
718
|
-
? { ...hinted, contextCap: providerCap, contextCapped }
|
|
708
|
+
const withCap = providerCap !== undefined
|
|
709
|
+
? capped !== hinted.contextWindow
|
|
710
|
+
? { ...hinted, contextWindow: capped, contextCap: providerCap, contextCapped: true }
|
|
711
|
+
: { ...hinted, contextCap: providerCap, contextCapped: false }
|
|
719
712
|
: hinted;
|
|
713
|
+
const contextWindow = typeof withCap.contextWindow === "number" && withCap.contextWindow > 0
|
|
714
|
+
? withCap.contextWindow
|
|
715
|
+
: undefined;
|
|
716
|
+
const boundedMaxInput = typeof withCap.maxInputTokens === "number" && withCap.maxInputTokens > 0
|
|
717
|
+
? (contextWindow !== undefined ? Math.min(withCap.maxInputTokens, contextWindow) : withCap.maxInputTokens)
|
|
718
|
+
: undefined;
|
|
719
|
+
const withHardBounds = boundedMaxInput !== undefined && boundedMaxInput !== withCap.maxInputTokens
|
|
720
|
+
? { ...withCap, maxInputTokens: boundedMaxInput }
|
|
721
|
+
: withCap;
|
|
722
|
+
const softCandidates = [model.autoCompactTokenLimit, configuredAutoCompact]
|
|
723
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
724
|
+
if (contextWindow === undefined || softCandidates.length === 0) return withHardBounds;
|
|
725
|
+
return {
|
|
726
|
+
...withHardBounds,
|
|
727
|
+
autoCompactTokenLimit: clampAutoCompactTokenLimit(
|
|
728
|
+
contextWindow,
|
|
729
|
+
boundedMaxInput,
|
|
730
|
+
Math.min(...softCandidates),
|
|
731
|
+
),
|
|
732
|
+
};
|
|
720
733
|
}
|
|
721
734
|
|
|
722
735
|
export function catalogHintsFromProviderConfig(name: string, prov: OcxProviderConfig, id: string, contextCap?: number): Partial<CatalogModel> {
|
|
@@ -743,6 +756,7 @@ interface ComboCatalogMemberFallback {
|
|
|
743
756
|
readonly contextWindow?: number;
|
|
744
757
|
/** Input ceiling when it is lower than the window (native GPT-5.6: 922k under 1.05M). */
|
|
745
758
|
readonly maxInputTokens?: number;
|
|
759
|
+
readonly autoCompactTokenLimit?: number;
|
|
746
760
|
readonly inputModalities?: readonly string[];
|
|
747
761
|
readonly reasoningEfforts?: readonly string[];
|
|
748
762
|
}
|
|
@@ -771,26 +785,33 @@ export function resolveComboCatalogMember(
|
|
|
771
785
|
if (prov?.disabled === true) return undefined;
|
|
772
786
|
|
|
773
787
|
const withFallbackMetadata = (member: CatalogModel): CatalogModel => {
|
|
774
|
-
if (!fallback) return member;
|
|
775
788
|
const contextWindow = typeof member.contextWindow === "number" && member.contextWindow > 0
|
|
776
789
|
? member.contextWindow
|
|
777
790
|
: undefined;
|
|
778
|
-
const addMaxInput = contextWindow !== undefined
|
|
791
|
+
const addMaxInput = fallback !== undefined && contextWindow !== undefined
|
|
779
792
|
&& !(typeof member.maxInputTokens === "number" && member.maxInputTokens > 0);
|
|
793
|
+
const effectiveMaxInput = addMaxInput
|
|
794
|
+
? Math.min(fallback?.maxInputTokens ?? contextWindow!, contextWindow!)
|
|
795
|
+
: member.maxInputTokens;
|
|
796
|
+
const softCandidates = [member.autoCompactTokenLimit, fallback?.autoCompactTokenLimit]
|
|
797
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
798
|
+
const autoCompactTokenLimit = contextWindow !== undefined && softCandidates.length > 0
|
|
799
|
+
? clampAutoCompactTokenLimit(contextWindow, effectiveMaxInput, Math.min(...softCandidates))
|
|
800
|
+
: member.autoCompactTokenLimit;
|
|
801
|
+
const adjustAutoCompact = autoCompactTokenLimit !== member.autoCompactTokenLimit;
|
|
780
802
|
const addModalities = (!Array.isArray(member.inputModalities) || member.inputModalities.length === 0)
|
|
781
|
-
&& fallback
|
|
803
|
+
&& fallback?.inputModalities !== undefined;
|
|
782
804
|
const addReasoning = member.reasoningEfforts === undefined
|
|
783
|
-
&& fallback
|
|
784
|
-
if (!addMaxInput && !addModalities && !addReasoning) return member;
|
|
805
|
+
&& fallback?.reasoningEfforts !== undefined;
|
|
806
|
+
if (!addMaxInput && !adjustAutoCompact && !addModalities && !addReasoning) return member;
|
|
785
807
|
return {
|
|
786
808
|
...member,
|
|
787
809
|
// Never claim a larger input budget than the window, and prefer the model's own
|
|
788
810
|
// measured ceiling when the fallback carries one.
|
|
789
|
-
...(addMaxInput
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
...(
|
|
793
|
-
...(addReasoning ? { reasoningEfforts: [...fallback.reasoningEfforts!] } : {}),
|
|
811
|
+
...(addMaxInput ? { maxInputTokens: effectiveMaxInput } : {}),
|
|
812
|
+
...(adjustAutoCompact && autoCompactTokenLimit !== undefined ? { autoCompactTokenLimit } : {}),
|
|
813
|
+
...(addModalities ? { inputModalities: [...fallback!.inputModalities!] } : {}),
|
|
814
|
+
...(addReasoning ? { reasoningEfforts: [...fallback!.reasoningEfforts!] } : {}),
|
|
794
815
|
};
|
|
795
816
|
};
|
|
796
817
|
|
|
@@ -871,6 +892,20 @@ export function resolveComboCatalogMember(
|
|
|
871
892
|
const maxInputTokens = effectiveMaxInput !== undefined
|
|
872
893
|
? Math.min(effectiveMaxInput, contextWindow)
|
|
873
894
|
: contextWindow;
|
|
895
|
+
const softCandidates = [
|
|
896
|
+
hinted.autoCompactTokenLimit,
|
|
897
|
+
base.autoCompactTokenLimit,
|
|
898
|
+
fallback?.autoCompactTokenLimit,
|
|
899
|
+
configuredAutoCompactTokenLimit(prov, target.model),
|
|
900
|
+
].filter((value): value is number => typeof value === "number" && value > 0);
|
|
901
|
+
// A generic 128k synthesis is a catalog compatibility fallback, not evidence
|
|
902
|
+
// that a configured soft policy has an authoritative window to clamp against.
|
|
903
|
+
const hasAuthoritativeAutoCompactBasis = hintedContext !== undefined
|
|
904
|
+
|| fallbackContext !== undefined
|
|
905
|
+
|| contextCap !== undefined;
|
|
906
|
+
const autoCompactTokenLimit = hasAuthoritativeAutoCompactBasis && softCandidates.length > 0
|
|
907
|
+
? clampAutoCompactTokenLimit(contextWindow, maxInputTokens, Math.min(...softCandidates))
|
|
908
|
+
: undefined;
|
|
874
909
|
|
|
875
910
|
return {
|
|
876
911
|
...hinted,
|
|
@@ -878,6 +913,7 @@ export function resolveComboCatalogMember(
|
|
|
878
913
|
...(reasoningEfforts !== undefined ? { reasoningEfforts } : {}),
|
|
879
914
|
contextWindow,
|
|
880
915
|
maxInputTokens,
|
|
916
|
+
...(autoCompactTokenLimit !== undefined ? { autoCompactTokenLimit } : {}),
|
|
881
917
|
...(fallbackCapped ? { contextCap, contextCapped: true as const } : {}),
|
|
882
918
|
};
|
|
883
919
|
}
|
|
@@ -1088,9 +1124,6 @@ export function catalogHintsFromModelsApiItem(providerName: string, item: Provid
|
|
|
1088
1124
|
item.max_input_length,
|
|
1089
1125
|
item.max_prompt_tokens,
|
|
1090
1126
|
);
|
|
1091
|
-
// Output ceilings only. A top-level `max_tokens` is ambiguous (some catalogs
|
|
1092
|
-
// use it as context) and generated jawcode `maxTokens` is output-only — never
|
|
1093
|
-
// treat either as a context window.
|
|
1094
1127
|
const maxOutputTokens = positiveSafeInteger(
|
|
1095
1128
|
limits?.max_output_tokens,
|
|
1096
1129
|
item.max_output_tokens,
|
|
@@ -1213,14 +1246,49 @@ async function fetchProviderModelsWithAuth(
|
|
|
1213
1246
|
}
|
|
1214
1247
|
return merged;
|
|
1215
1248
|
};
|
|
1249
|
+
if (prov.googleMode === "ai-studio-web") {
|
|
1250
|
+
clearProviderDiscoveryStatus(name);
|
|
1251
|
+
if (globalAiStudioRelayHub.hasActiveSessions()) {
|
|
1252
|
+
try {
|
|
1253
|
+
const streamRes = await globalAiStudioRelayHub.dispatchStream({
|
|
1254
|
+
url: "https://generativelanguage.googleapis.com/v1beta/models",
|
|
1255
|
+
method: "GET",
|
|
1256
|
+
});
|
|
1257
|
+
let rawBody = "";
|
|
1258
|
+
for await (const chunk of streamRes.chunks) {
|
|
1259
|
+
rawBody += chunk;
|
|
1260
|
+
}
|
|
1261
|
+
const json = JSON.parse(rawBody);
|
|
1262
|
+
if (Array.isArray(json?.models)) {
|
|
1263
|
+
const liveModels: CatalogModel[] = json.models.map((m: any) => {
|
|
1264
|
+
const rawId = typeof m.name === "string" ? m.name.replace(/^models\//, "") : "";
|
|
1265
|
+
return {
|
|
1266
|
+
id: rawId,
|
|
1267
|
+
provider: name,
|
|
1268
|
+
...catalogHintsFromProviderConfig(name, prov, rawId, contextCap),
|
|
1269
|
+
};
|
|
1270
|
+
}).filter((m: any) => Boolean(m.id));
|
|
1271
|
+
if (liveModels.length > 0) {
|
|
1272
|
+
return observed(withConfiguredRetention(liveModels), "authoritative");
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
} catch {
|
|
1276
|
+
/* fallback to configured models */
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
return observed(configured, "authoritative");
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1216
1282
|
// Static catalogs never need an OAuth refresh or an upstream model request. Clear any
|
|
1217
1283
|
// discovery failure left by an older live configuration even when the account is logged out.
|
|
1218
1284
|
if (prov.liveModels === false) {
|
|
1219
1285
|
clearProviderDiscoveryStatus(name);
|
|
1220
1286
|
return observed(configured, "authoritative");
|
|
1221
1287
|
}
|
|
1288
|
+
const cloudCodeAssist = effectiveGoogleMode(name, prov) === "cloud-code-assist";
|
|
1289
|
+
const antigravityOAuth = isAntigravityOAuthProvider(name, prov);
|
|
1222
1290
|
const auth: ModelsAuthResolution = captured.observedAuth ?? (resolveAuth.kind === "refreshing"
|
|
1223
|
-
?
|
|
1291
|
+
? antigravityOAuth && cloudCodeAssist
|
|
1224
1292
|
? await getValidAccessTokenSnapshot(name)
|
|
1225
1293
|
.then(snapshot => ({
|
|
1226
1294
|
apiKey: snapshot.accessToken,
|
|
@@ -1304,14 +1372,14 @@ async function fetchProviderModelsWithAuth(
|
|
|
1304
1372
|
"degraded",
|
|
1305
1373
|
);
|
|
1306
1374
|
}
|
|
1307
|
-
if (prov.authMode === "oauth" && !apiKey) {
|
|
1375
|
+
if ((prov.authMode === "oauth" || antigravityOAuth) && !apiKey) {
|
|
1308
1376
|
// No usable token (logged out, or account marked needsReauth). Still surface the
|
|
1309
1377
|
// configured static catalog so the GUI Models tab / rail counts are not empty —
|
|
1310
1378
|
// matching Cursor's !apiKey → configured degradation and fetch-failure fallback.
|
|
1311
1379
|
return observed(configured, "degraded");
|
|
1312
1380
|
}
|
|
1313
|
-
|
|
1314
|
-
const project = prov.project ?? auth.oauthProjectId;
|
|
1381
|
+
if (antigravityOAuth && !cloudCodeAssist) return observed(configured, "degraded");
|
|
1382
|
+
const project = antigravityOAuth ? auth.oauthProjectId : prov.project ?? auth.oauthProjectId;
|
|
1315
1383
|
if (cloudCodeAssist && !project) return observed(configured, "degraded");
|
|
1316
1384
|
const fresh = getFreshCached(name, ttlMs);
|
|
1317
1385
|
if (fresh) {
|
|
@@ -1328,13 +1396,9 @@ async function fetchProviderModelsWithAuth(
|
|
|
1328
1396
|
const stale = getStaleCached(name);
|
|
1329
1397
|
return observed(
|
|
1330
1398
|
withConfiguredRetention(
|
|
1331
|
-
|
|
1399
|
+
stale
|
|
1332
1400
|
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap))
|
|
1333
|
-
: failedDiscoveryConfigured
|
|
1334
|
-
).map(model => enrichCatalogModelMetadata(model, {
|
|
1335
|
-
liveFresh: false,
|
|
1336
|
-
caps: capsFromProvider(prov, model.id, contextCap),
|
|
1337
|
-
})),
|
|
1401
|
+
: failedDiscoveryConfigured,
|
|
1338
1402
|
),
|
|
1339
1403
|
"degraded",
|
|
1340
1404
|
);
|
|
@@ -1361,14 +1425,12 @@ async function fetchProviderModelsWithAuth(
|
|
|
1361
1425
|
markModelsFetchFailure(name);
|
|
1362
1426
|
markProviderDiscoveryFailed(name, failure);
|
|
1363
1427
|
const stale = getStaleCached(name);
|
|
1364
|
-
const fallbackModels = stale
|
|
1365
|
-
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap))
|
|
1366
|
-
: failedDiscoveryConfigured;
|
|
1367
1428
|
return {
|
|
1368
|
-
models: withConfiguredRetention(
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1429
|
+
models: withConfiguredRetention(
|
|
1430
|
+
stale
|
|
1431
|
+
? withVertexDefaultSeed(applyConfigHintsToCachedModels(name, prov, stale, contextCap))
|
|
1432
|
+
: failedDiscoveryConfigured,
|
|
1433
|
+
),
|
|
1372
1434
|
fallback: stale ? "stale" : "configured",
|
|
1373
1435
|
shouldLog,
|
|
1374
1436
|
};
|
|
@@ -1435,40 +1497,19 @@ async function fetchProviderModelsWithAuth(
|
|
|
1435
1497
|
return observed(models, "degraded");
|
|
1436
1498
|
}
|
|
1437
1499
|
if (antigravity) {
|
|
1438
|
-
const
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
};
|
|
1448
|
-
if (model.contextWindow || model.inputModalities) {
|
|
1449
|
-
snapshotRows.push({
|
|
1450
|
-
id: model.id,
|
|
1451
|
-
...(model.contextWindow ? { contextWindow: model.contextWindow } : {}),
|
|
1452
|
-
...(model.inputModalities ? { inputModalities: model.inputModalities } : {}),
|
|
1453
|
-
observedAt,
|
|
1454
|
-
});
|
|
1455
|
-
}
|
|
1456
|
-
const enriched = enrichCatalogModelMetadata({
|
|
1457
|
-
id: model.id,
|
|
1458
|
-
provider: name,
|
|
1459
|
-
...hints,
|
|
1460
|
-
...(model.contextWindow ? { metadataSource: "live" as const, metadataObservedAt: observedAt } : {}),
|
|
1461
|
-
}, {
|
|
1462
|
-
liveFresh: true,
|
|
1463
|
-
caps: capsFromProvider(prov, model.id, contextCap),
|
|
1464
|
-
});
|
|
1465
|
-
return applyProviderConfigHints(name, prov, enriched, contextCap);
|
|
1466
|
-
});
|
|
1500
|
+
const live = antigravity.map(model => applyProviderConfigHints(name, prov, {
|
|
1501
|
+
id: model.id,
|
|
1502
|
+
provider: name,
|
|
1503
|
+
// CCA only exposes a numeric thinking budget. Until the adapter owns an exact Codex
|
|
1504
|
+
// effort-to-wire mapping for a newly discovered model, do not advertise a false ladder.
|
|
1505
|
+
reasoningEfforts: [],
|
|
1506
|
+
...(model.contextWindow ? { contextWindow: model.contextWindow } : {}),
|
|
1507
|
+
...(model.inputModalities ? { inputModalities: model.inputModalities } : {}),
|
|
1508
|
+
}, contextCap));
|
|
1467
1509
|
const forCache = withConfiguredRetention(live, { retainComboTargets: false });
|
|
1468
1510
|
if (!setCached(name, forCache, Date.now(), cacheGeneration)) {
|
|
1469
1511
|
return observed(withConfiguredRetention(configured), "degraded");
|
|
1470
1512
|
}
|
|
1471
|
-
persistLiveModelMetadata(name, snapshotRows, { writerGeneration: cacheGeneration, observedAt });
|
|
1472
1513
|
registerAntigravityDiscoveredWireModels(prov.baseUrl, antigravity, {
|
|
1473
1514
|
provider: name,
|
|
1474
1515
|
cacheGeneration,
|
|
@@ -1493,30 +1534,22 @@ async function fetchProviderModelsWithAuth(
|
|
|
1493
1534
|
return observed(models, "degraded");
|
|
1494
1535
|
}
|
|
1495
1536
|
const items = extracted.items;
|
|
1496
|
-
const observedAt = new Date().toISOString();
|
|
1497
|
-
const snapshotRows: LiveSnapshotRow[] = [];
|
|
1498
1537
|
const live = items.map(m => {
|
|
1499
1538
|
const ownedBy = boundedOwnedBy(m.owned_by);
|
|
1500
|
-
|
|
1501
|
-
const discovered = Boolean(hints.contextWindow || hints.maxInputTokens || hints.maxOutputTokens
|
|
1502
|
-
|| hints.inputModalities || hints.capabilities || hints.reasoningEfforts);
|
|
1503
|
-
if (discovered) {
|
|
1504
|
-
snapshotRows.push({ id: m.id, ...hints, observedAt });
|
|
1505
|
-
}
|
|
1506
|
-
const enriched = enrichCatalogModelMetadata({
|
|
1539
|
+
return applyProviderConfigHints(name, prov, {
|
|
1507
1540
|
id: m.id,
|
|
1508
1541
|
provider: name,
|
|
1509
1542
|
...(ownedBy ? { owned_by: ownedBy } : {}),
|
|
1510
|
-
...
|
|
1511
|
-
|
|
1512
|
-
}, {
|
|
1513
|
-
liveFresh: true,
|
|
1514
|
-
caps: capsFromProvider(prov, m.id, contextCap),
|
|
1515
|
-
});
|
|
1516
|
-
return applyProviderConfigHints(name, prov, enriched, contextCap);
|
|
1543
|
+
...catalogHintsFromModelsApiItem(name, m),
|
|
1544
|
+
}, contextCap);
|
|
1517
1545
|
})
|
|
1518
1546
|
.filter(m => shouldExposeProviderModel(name, m.id));
|
|
1547
|
+
// Capture the count BEFORE the alias/configured augmentation below pushes extra rows into
|
|
1548
|
+
// `live`; otherwise configured entries would be reported as discovered ones.
|
|
1519
1549
|
const liveModelCount = live.length;
|
|
1550
|
+
// Dated-release aliases + configured retention (compat allow-list, combo targets,
|
|
1551
|
+
// Vertex default). Cache without combo retention so a later gather re-applies the
|
|
1552
|
+
// current capture's retain set on read (warm-cache OCX-111 / #1308).
|
|
1520
1553
|
const forCache = withConfiguredRetention(live, { retainComboTargets: false });
|
|
1521
1554
|
const returned = withConfiguredRetention(forCache, { warnDrops: true });
|
|
1522
1555
|
const droppedConfiguredIds = configured
|
|
@@ -1530,7 +1563,6 @@ async function fetchProviderModelsWithAuth(
|
|
|
1530
1563
|
if (!setCached(name, forCache, Date.now(), cacheGeneration)) {
|
|
1531
1564
|
return observed(withConfiguredRetention(configured), "degraded");
|
|
1532
1565
|
}
|
|
1533
|
-
persistLiveModelMetadata(name, snapshotRows, { writerGeneration: cacheGeneration, observedAt });
|
|
1534
1566
|
markProviderDiscoveryOk(name, liveModelCount);
|
|
1535
1567
|
return observed(returned, "authoritative");
|
|
1536
1568
|
} catch (error) {
|
|
@@ -1641,7 +1673,24 @@ export function filterCatalogVisibleModels(
|
|
|
1641
1673
|
const allowByProvider = new Map<string, Set<string>>();
|
|
1642
1674
|
for (const [name, prov] of Object.entries(config.providers)) {
|
|
1643
1675
|
const sel = prov.selectedModels;
|
|
1644
|
-
|
|
1676
|
+
// Keyed the way `sync.ts` keys the same list, so a slash-bearing native id and
|
|
1677
|
+
// the encoded slug the Codex picker displays are one entry rather than two. A
|
|
1678
|
+
// bare `Set(sel)` matched only the native form, so an allowlist written from the
|
|
1679
|
+
// displayed slug — which `ocx models remove` also accepts — hid every model it
|
|
1680
|
+
// was meant to keep.
|
|
1681
|
+
//
|
|
1682
|
+
// The key is deliberately lossy: `p/a/b` and `p/a-b` collapse to one entry, so a
|
|
1683
|
+
// provider publishing both spellings has them selected together. That is a real
|
|
1684
|
+
// limitation, pinned by the tests below and tracked as a follow-up; it is NOT
|
|
1685
|
+
// fixed here. Resolving selections against the current roster instead was tried
|
|
1686
|
+
// and rejected — the roster is an incomplete dictionary (live discovery can omit
|
|
1687
|
+
// a published id), so it produces the same over-grant while additionally
|
|
1688
|
+
// disagreeing with the `slugEquivalenceKey` contract `sync.ts` uses at merge time.
|
|
1689
|
+
// Two catalog stages with different equivalence relations is the exact bug class
|
|
1690
|
+
// this change exists to remove.
|
|
1691
|
+
if (Array.isArray(sel) && sel.length > 0) {
|
|
1692
|
+
allowByProvider.set(name, new Set(sel.map(model => slugEquivalenceKey(routedSlug(name, model)))));
|
|
1693
|
+
}
|
|
1645
1694
|
}
|
|
1646
1695
|
return models.filter(m => {
|
|
1647
1696
|
const nativeAlias = m.provider === COMBO_NAMESPACE && m.nativeAlias === true;
|
|
@@ -1653,7 +1702,7 @@ export function filterCatalogVisibleModels(
|
|
|
1653
1702
|
if (slugEquals(stored, m.provider, m.id)) return false;
|
|
1654
1703
|
}
|
|
1655
1704
|
const allow = allowByProvider.get(m.provider);
|
|
1656
|
-
return !allow || allow.has(m.id);
|
|
1705
|
+
return !allow || allow.has(slugEquivalenceKey(routedSlug(m.provider, m.id)));
|
|
1657
1706
|
});
|
|
1658
1707
|
}
|
|
1659
1708
|
|
|
@@ -1838,6 +1887,7 @@ async function gatherRoutedModelsUncached(
|
|
|
1838
1887
|
// stay separate fields because routed/API rows of the same family run a wider window.
|
|
1839
1888
|
// Falls back to the window for slugs with no separate ceiling.
|
|
1840
1889
|
maxInputTokens: Math.min(nativeOpenAiMaxInputTokens(slug, openaiContextCap) ?? contextWindow, contextWindow),
|
|
1890
|
+
autoCompactTokenLimit: nativeOpenAiAutoCompactTokenLimit(slug, openaiContextCap),
|
|
1841
1891
|
inputModalities: nativeInputModalities(slug),
|
|
1842
1892
|
reasoningEfforts: nativeReasoningEfforts(slug),
|
|
1843
1893
|
...(nativeParallelToolCalls(slug) ? { parallelToolCalls: true } : {}),
|
|
@@ -1854,18 +1904,23 @@ async function gatherRoutedModelsUncached(
|
|
|
1854
1904
|
for (const id of listComboIds(config)) {
|
|
1855
1905
|
const combo = getCombo(config, id);
|
|
1856
1906
|
if (!combo) continue;
|
|
1907
|
+
const comboNativeLimits = nativeContextLimits(config);
|
|
1857
1908
|
const nativeContextWindow = combo.nativeAlias && combo.alias
|
|
1858
|
-
? nativeOpenAiContextWindow(combo.alias,
|
|
1909
|
+
? nativeOpenAiContextWindow(combo.alias, comboNativeLimits)
|
|
1859
1910
|
: undefined;
|
|
1860
1911
|
const nativeAliasMaxInput = combo.nativeAlias && combo.alias
|
|
1861
1912
|
? (combo.alias.startsWith("gpt-5.6-") || combo.alias.includes("daybreak")
|
|
1862
1913
|
? NATIVE_GPT56_MAX_INPUT_TOKENS
|
|
1863
1914
|
: nativeOpenAiMaxInputTokens(combo.alias) ?? nativeOpenAiContextWindow(combo.alias))
|
|
1864
1915
|
: undefined;
|
|
1916
|
+
const nativeAliasAutoCompact = combo.nativeAlias && combo.alias
|
|
1917
|
+
? nativeOpenAiAutoCompactTokenLimit(combo.alias, comboNativeLimits)
|
|
1918
|
+
: undefined;
|
|
1865
1919
|
const nativeAliasFallback = combo.nativeAlias && combo.alias && nativeContextWindow !== undefined
|
|
1866
1920
|
? {
|
|
1867
1921
|
contextWindow: nativeContextWindow,
|
|
1868
1922
|
...(nativeAliasMaxInput !== undefined ? { maxInputTokens: nativeAliasMaxInput } : {}),
|
|
1923
|
+
...(nativeAliasAutoCompact !== undefined ? { autoCompactTokenLimit: nativeAliasAutoCompact } : {}),
|
|
1869
1924
|
inputModalities: nativeInputModalities(combo.alias),
|
|
1870
1925
|
reasoningEfforts: nativeReasoningEfforts(combo.alias),
|
|
1871
1926
|
}
|
|
@@ -1928,9 +1983,23 @@ async function gatherRoutedModelsUncached(
|
|
|
1928
1983
|
const nativeAliasMaxInputTokens = codexForwardNativeCapabilityAlias
|
|
1929
1984
|
? nativeOpenAiMaxInputTokens(cm.modelId, customNativeLimits)
|
|
1930
1985
|
: undefined;
|
|
1931
|
-
const
|
|
1932
|
-
?
|
|
1933
|
-
:
|
|
1986
|
+
const configuredMaxInput = rawProvider
|
|
1987
|
+
? configuredMaxInputTokens(rawProvider, cm.modelId)
|
|
1988
|
+
: undefined;
|
|
1989
|
+
const hardMaxCandidates = [nativeAliasMaxInputTokens, configuredMaxInput]
|
|
1990
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
1991
|
+
const customMaxInputTokens = hardMaxCandidates.length > 0
|
|
1992
|
+
? Math.min(
|
|
1993
|
+
...hardMaxCandidates,
|
|
1994
|
+
...(customContextWindow !== undefined ? [customContextWindow] : []),
|
|
1995
|
+
)
|
|
1996
|
+
: undefined;
|
|
1997
|
+
const configuredAutoCompact = configuredAutoCompactTokenLimit(rawProvider, cm.modelId);
|
|
1998
|
+
const customAutoCompactTokenLimit = codexForwardNativeCapabilityAlias
|
|
1999
|
+
? nativeOpenAiAutoCompactTokenLimit(cm.modelId, customNativeLimits)
|
|
2000
|
+
: customContextWindow !== undefined && configuredAutoCompact !== undefined
|
|
2001
|
+
? clampAutoCompactTokenLimit(customContextWindow, customMaxInputTokens, configuredAutoCompact)
|
|
2002
|
+
: undefined;
|
|
1934
2003
|
const nativeAliasDefaultEffort = codexForwardNativeCapabilityAlias
|
|
1935
2004
|
? nativeDefaultReasoningEffort(cm.modelId)
|
|
1936
2005
|
: undefined;
|
|
@@ -1951,6 +2020,7 @@ async function gatherRoutedModelsUncached(
|
|
|
1951
2020
|
: codexForwardNativeCapabilityAlias ? { displayName: "Daybreak Blue" } : {}),
|
|
1952
2021
|
...(customContextWindow !== undefined ? { contextWindow: customContextWindow } : {}),
|
|
1953
2022
|
...(customMaxInputTokens !== undefined ? { maxInputTokens: customMaxInputTokens } : {}),
|
|
2023
|
+
...(customAutoCompactTokenLimit !== undefined ? { autoCompactTokenLimit: customAutoCompactTokenLimit } : {}),
|
|
1954
2024
|
...(cm.inputModalities
|
|
1955
2025
|
? { inputModalities: cm.inputModalities }
|
|
1956
2026
|
: codexForwardNativeCapabilityAlias ? { inputModalities: nativeInputModalities(cm.modelId) } : {}),
|
|
@@ -1996,10 +2066,18 @@ async function gatherRoutedModelsUncached(
|
|
|
1996
2066
|
// along when it is actually a member — otherwise a provider default like "xhigh" would
|
|
1997
2067
|
// re-apply onto a narrower custom ladder and override the fallback in applyReasoningLevels.
|
|
1998
2068
|
const effectiveLadder = base.reasoningEfforts ?? replaced?.reasoningEfforts;
|
|
2069
|
+
const mergedMaxInputCandidates = [base.maxInputTokens, replaced?.maxInputTokens]
|
|
2070
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
2071
|
+
const mergedMaxInput = mergedMaxInputCandidates.length > 0
|
|
2072
|
+
? Math.min(...mergedMaxInputCandidates)
|
|
2073
|
+
: undefined;
|
|
1999
2074
|
const merged: CatalogModel = replaced ? {
|
|
2000
2075
|
...base,
|
|
2001
2076
|
...(base.contextWindow === undefined && replaced.contextWindow !== undefined ? { contextWindow: replaced.contextWindow } : {}),
|
|
2002
|
-
...(
|
|
2077
|
+
...(mergedMaxInput !== undefined ? { maxInputTokens: mergedMaxInput } : {}),
|
|
2078
|
+
...(base.autoCompactTokenLimit === undefined && replaced.autoCompactTokenLimit !== undefined
|
|
2079
|
+
? { autoCompactTokenLimit: replaced.autoCompactTokenLimit }
|
|
2080
|
+
: {}),
|
|
2003
2081
|
...(base.inputModalities === undefined && replaced.inputModalities !== undefined ? { inputModalities: replaced.inputModalities } : {}),
|
|
2004
2082
|
...(base.reasoningEfforts === undefined && replaced.reasoningEfforts !== undefined ? { reasoningEfforts: replaced.reasoningEfforts } : {}),
|
|
2005
2083
|
...(base.defaultReasoningEffort === undefined && replaced.defaultReasoningEffort !== undefined
|
|
@@ -2016,14 +2094,36 @@ async function gatherRoutedModelsUncached(
|
|
|
2016
2094
|
// (#349/#344). Deliberately NOT the full applyProviderConfigHints pass — custom rows are a
|
|
2017
2095
|
// user override, so their explicit contextWindow / inputModalities / reasoning fields must be
|
|
2018
2096
|
// preserved verbatim (the hint pass would cap context and overwrite modalities from registry).
|
|
2097
|
+
const mergedContext = typeof merged.contextWindow === "number" && merged.contextWindow > 0
|
|
2098
|
+
? merged.contextWindow
|
|
2099
|
+
: undefined;
|
|
2100
|
+
const boundedMergedMaxInput = typeof merged.maxInputTokens === "number" && merged.maxInputTokens > 0
|
|
2101
|
+
? (mergedContext !== undefined ? Math.min(merged.maxInputTokens, mergedContext) : merged.maxInputTokens)
|
|
2102
|
+
: undefined;
|
|
2103
|
+
const mergedWithHardBounds = boundedMergedMaxInput !== undefined
|
|
2104
|
+
&& boundedMergedMaxInput !== merged.maxInputTokens
|
|
2105
|
+
? { ...merged, maxInputTokens: boundedMergedMaxInput }
|
|
2106
|
+
: merged;
|
|
2107
|
+
const mergedSoftCandidates = [mergedWithHardBounds.autoCompactTokenLimit, configuredAutoCompact]
|
|
2108
|
+
.filter((value): value is number => typeof value === "number" && value > 0);
|
|
2109
|
+
const mergedWithAutoCompact: CatalogModel = mergedContext !== undefined && mergedSoftCandidates.length > 0
|
|
2110
|
+
? {
|
|
2111
|
+
...mergedWithHardBounds,
|
|
2112
|
+
autoCompactTokenLimit: clampAutoCompactTokenLimit(
|
|
2113
|
+
mergedContext,
|
|
2114
|
+
boundedMergedMaxInput,
|
|
2115
|
+
Math.min(...mergedSoftCandidates),
|
|
2116
|
+
),
|
|
2117
|
+
}
|
|
2118
|
+
: mergedWithHardBounds;
|
|
2019
2119
|
const enrichedProvider = enrichedByName.get(cm.provider) ?? rawProvider;
|
|
2020
|
-
if (enrichedProvider && modelInList(enrichedProvider.noVisionModels,
|
|
2021
|
-
const current =
|
|
2120
|
+
if (enrichedProvider && modelInList(enrichedProvider.noVisionModels, mergedWithAutoCompact.id)) {
|
|
2121
|
+
const current = mergedWithAutoCompact.inputModalities ?? ["text"];
|
|
2022
2122
|
if (!current.includes("image")) {
|
|
2023
|
-
return { ...
|
|
2123
|
+
return { ...mergedWithAutoCompact, inputModalities: [...current, "image"] };
|
|
2024
2124
|
}
|
|
2025
2125
|
}
|
|
2026
|
-
return
|
|
2126
|
+
return mergedWithAutoCompact;
|
|
2027
2127
|
});
|
|
2028
2128
|
// Custom rows override discovered rows that encode to the same Codex-facing slug.
|
|
2029
2129
|
const customKeys = new Set(customModels.map(c => routedSlug(c.provider, c.id)));
|
|
@@ -2079,7 +2179,15 @@ function augmentRoutedModelsWithCapturedOpenAiApiRows(
|
|
|
2079
2179
|
? Math.min(officialContext, userContext ?? officialContext, providerCap ?? officialContext)
|
|
2080
2180
|
: undefined;
|
|
2081
2181
|
const maxInputTokens = typeof officialMaxInput === "number"
|
|
2082
|
-
? Math.min(
|
|
2182
|
+
? Math.min(
|
|
2183
|
+
officialMaxInput,
|
|
2184
|
+
userMaxInput ?? officialMaxInput,
|
|
2185
|
+
contextWindow ?? officialMaxInput,
|
|
2186
|
+
)
|
|
2187
|
+
: undefined;
|
|
2188
|
+
const configuredAutoCompact = configuredAutoCompactTokenLimit(configured, id);
|
|
2189
|
+
const autoCompactTokenLimit = contextWindow !== undefined && configuredAutoCompact !== undefined
|
|
2190
|
+
? clampAutoCompactTokenLimit(contextWindow, maxInputTokens, configuredAutoCompact)
|
|
2083
2191
|
: undefined;
|
|
2084
2192
|
return {
|
|
2085
2193
|
provider: OPENAI_API_PROVIDER_ID,
|
|
@@ -2087,6 +2195,7 @@ function augmentRoutedModelsWithCapturedOpenAiApiRows(
|
|
|
2087
2195
|
owned_by: OPENAI_API_PROVIDER_ID,
|
|
2088
2196
|
...(contextWindow ? { contextWindow } : {}),
|
|
2089
2197
|
...(maxInputTokens ? { maxInputTokens } : {}),
|
|
2198
|
+
...(autoCompactTokenLimit !== undefined ? { autoCompactTokenLimit } : {}),
|
|
2090
2199
|
...(policy.modelInputModalities?.[id] ? { inputModalities: [...policy.modelInputModalities[id]!] } : {}),
|
|
2091
2200
|
...(policy.modelReasoningEfforts?.[id] ? { reasoningEfforts: [...policy.modelReasoningEfforts[id]!] } : {}),
|
|
2092
2201
|
};
|
|
@@ -2116,14 +2225,7 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
2116
2225
|
providers?: Record<string, OcxProviderConfig>,
|
|
2117
2226
|
caps?: Pick<OcxConfig, "providerContextCaps">,
|
|
2118
2227
|
): CatalogModel[] {
|
|
2119
|
-
const out = models
|
|
2120
|
-
const provider = providers?.[model.provider];
|
|
2121
|
-
const contextCap = caps ? providerContextCap(caps, model.provider) : undefined;
|
|
2122
|
-
return enrichCatalogModelMetadata(model, {
|
|
2123
|
-
liveFresh: model.metadataSource === "live" && model.metadataStale !== true,
|
|
2124
|
-
caps: capsFromProvider(provider, model.id, contextCap),
|
|
2125
|
-
});
|
|
2126
|
-
});
|
|
2228
|
+
const out = [...models];
|
|
2127
2229
|
const seen = new Set(out.map(m => `${m.provider}/${m.id}`));
|
|
2128
2230
|
for (const provider of providerNames) {
|
|
2129
2231
|
if (!JAWCODE_CATALOG_AUGMENT_PROVIDERS.has(provider)) continue;
|
|
@@ -2142,13 +2244,10 @@ export function augmentRoutedModelsWithMetadata(
|
|
|
2142
2244
|
...(typeof meta.contextWindow === "number" && meta.contextWindow > 0 ? { contextWindow: meta.contextWindow } : {}),
|
|
2143
2245
|
...(Array.isArray(meta.input) && meta.input.length > 0 ? { inputModalities: [...meta.input] } : {}),
|
|
2144
2246
|
};
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
:
|
|
2148
|
-
|
|
2149
|
-
liveFresh: false,
|
|
2150
|
-
caps: capsFromProvider(providers?.[provider], meta.id, contextCap),
|
|
2151
|
-
}));
|
|
2247
|
+
out.push({
|
|
2248
|
+
...model,
|
|
2249
|
+
...(providers?.[provider] ? applyProviderConfigHints(provider, providers[provider], model, contextCap) : {}),
|
|
2250
|
+
});
|
|
2152
2251
|
}
|
|
2153
2252
|
}
|
|
2154
2253
|
return out;
|
|
@@ -1158,7 +1158,7 @@ export function mergeCatalogEntriesForSync(
|
|
|
1158
1158
|
isNativeAliasCatalogEntry(entry) && typeof entry.slug === "string" ? [entry.slug] : []
|
|
1159
1159
|
)),
|
|
1160
1160
|
),
|
|
1161
|
-
openaiContextCap?:
|
|
1161
|
+
openaiContextCap?: NativeContextLimitsInput,
|
|
1162
1162
|
keepNativeChatGptOnV1 = false,
|
|
1163
1163
|
): RawEntry[] {
|
|
1164
1164
|
// Retained for source compatibility with the original helper contract. Raw provider ids must
|