@bitkyc08/opencodex 2.55.0-preview.20260914 → 2.56.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/gui/dist/assets/{index-DH2PUHqr.js → index-D4zuyIxQ.js} +1 -1
- package/gui/dist/index.html +1 -1
- package/package.json +2 -1
- package/src/adapters/base.ts +21 -0
- package/src/adapters/cursor/transport-retry.ts +46 -1
- package/src/adapters/cursor.ts +4 -0
- package/src/adapters/kiro/adapter.ts +42 -1
- package/src/adapters/kiro-retry.ts +23 -4
- package/src/adapters/openai-chat/errors.ts +116 -0
- package/src/adapters/openai-chat/messages.ts +346 -0
- package/src/adapters/openai-chat/passthrough.ts +146 -0
- package/src/adapters/openai-chat/response-events.ts +117 -0
- package/src/adapters/openai-chat/tool-call-validation.ts +200 -0
- package/src/adapters/openai-chat/tool-schema.ts +477 -0
- package/src/adapters/openai-chat/wire.ts +50 -0
- package/src/adapters/openai-chat.ts +33 -1445
- package/src/adapters/openai-responses/canonical-forward.ts +202 -0
- package/src/adapters/openai-responses/image-gen.ts +406 -0
- package/src/adapters/openai-responses/internal.ts +3 -0
- package/src/adapters/openai-responses/passthrough.ts +611 -0
- package/src/adapters/openai-responses/prompt-cache.ts +83 -0
- package/src/adapters/openai-responses/reasoning.ts +220 -0
- package/src/adapters/openai-responses/request-strips.ts +185 -0
- package/src/adapters/openai-responses/tool-output-recovery.ts +509 -0
- package/src/adapters/openai-responses/tool-schema.ts +293 -0
- package/src/adapters/openai-responses/web-search.ts +156 -0
- package/src/adapters/openai-responses.ts +4 -2625
- package/src/bridge/errors.ts +34 -0
- package/src/bridge/internal.ts +174 -0
- package/src/bridge/response-json.ts +624 -0
- package/src/bridge/sse.ts +1444 -0
- package/src/bridge.ts +5 -2204
- package/src/chat/inbound.ts +12 -1
- package/src/codex/account-lifecycle.ts +3 -0
- package/src/codex/account-store.ts +71 -9
- package/src/codex/auth-api/account-list.ts +507 -0
- package/src/codex/auth-api/http.ts +32 -0
- package/src/codex/auth-api/login-flow.ts +554 -0
- package/src/codex/auth-api/login-state.ts +64 -0
- package/src/codex/auth-api/main-account-probe.ts +331 -0
- package/src/codex/auth-api/pool-mode-gate.ts +274 -0
- package/src/codex/auth-api/pool-quota-probe.ts +512 -0
- package/src/codex/auth-api/reset-credit-service.ts +422 -0
- package/src/codex/auth-api/routes.ts +425 -0
- package/src/codex/auth-api/runtime-config.ts +48 -0
- package/src/codex/auth-api.ts +27 -3118
- package/src/codex/auth-context.ts +95 -28
- package/src/codex/catalog/auto-review.ts +507 -0
- package/src/codex/catalog/build-entries.ts +981 -0
- package/src/codex/catalog/combo-member.ts +375 -0
- package/src/codex/catalog/derive-entry.ts +229 -0
- package/src/codex/catalog/effort.ts +0 -1
- package/src/codex/catalog/gated-native-warn.ts +63 -0
- package/src/codex/catalog/gather-capture.ts +533 -0
- package/src/codex/catalog/model-hints.ts +691 -0
- package/src/codex/catalog/model-visibility.ts +304 -0
- package/src/codex/catalog/provider-fetch.ts +52 -2942
- package/src/codex/catalog/provider-models.ts +685 -0
- package/src/codex/catalog/restore.ts +132 -0
- package/src/codex/catalog/retained-sync.ts +706 -0
- package/src/codex/catalog/routed-gather.ts +858 -0
- package/src/codex/catalog/subagent-roster.ts +176 -0
- package/src/codex/catalog/sync.ts +52 -2698
- package/src/codex/inject/config-toml.ts +563 -0
- package/src/codex/inject/remove.ts +192 -0
- package/src/codex/inject/restore.ts +540 -0
- package/src/codex/inject/routing-classify.ts +109 -0
- package/src/codex/inject/routing-target.ts +125 -0
- package/src/codex/inject.ts +81 -1436
- package/src/codex/lineage.ts +458 -0
- package/src/codex/pool-refresh-backoff.ts +152 -0
- package/src/codex/routing/active-account.ts +194 -0
- package/src/codex/routing/cooldown-math.ts +275 -0
- package/src/codex/routing/health-store.ts +402 -0
- package/src/codex/routing/probe-lease.ts +358 -0
- package/src/codex/routing/selection.ts +703 -0
- package/src/codex/routing/thread-affinity.ts +538 -0
- package/src/codex/routing.ts +353 -2234
- package/src/codex/shim-fingerprint.ts +223 -0
- package/src/codex/shim-inspect.ts +175 -0
- package/src/codex/shim-probe.ts +367 -0
- package/src/codex/shim-restore-lock.ts +169 -0
- package/src/codex/shim-state-file.ts +151 -0
- package/src/codex/shim-templates.ts +265 -0
- package/src/codex/shim.ts +48 -1268
- package/src/config/diagnostics.ts +705 -0
- package/src/config/feature-flags.ts +55 -0
- package/src/config/live-reconcile.ts +403 -0
- package/src/config/load-degrade.ts +880 -0
- package/src/config/mutation-lock.ts +244 -0
- package/src/config/openai-tier-backup.ts +268 -0
- package/src/config/persist-unlocked.ts +92 -0
- package/src/config/proxy-env.ts +188 -0
- package/src/config/salvage.ts +244 -0
- package/src/config/schema/config-schema.ts +640 -0
- package/src/config/schema/leaf-validators.ts +855 -0
- package/src/config/warn-memo.ts +28 -0
- package/src/config.ts +234 -4481
- package/src/generated/compatibility-version.json +539 -39
- package/src/lib/request-execution-budget.ts +69 -20
- package/src/lib/spend-reservation-ledger.ts +940 -0
- package/src/lib/upstream-retry.ts +55 -11
- package/src/lib/workflow-budget.ts +553 -30
- package/src/providers/quota/account-cache.ts +441 -0
- package/src/providers/quota/antigravity.ts +295 -0
- package/src/providers/quota/report-cache.ts +320 -0
- package/src/providers/quota/vendor-probes-key.ts +1243 -0
- package/src/providers/quota/vendor-probes-oauth.ts +590 -0
- package/src/providers/quota.ts +324 -3079
- package/src/providers/registry/entries-core.ts +1221 -0
- package/src/providers/registry/entries-extended.ts +1204 -0
- package/src/providers/registry/model-seeds.ts +908 -0
- package/src/providers/registry/types.ts +352 -0
- package/src/providers/registry.ts +24 -3536
- package/src/responses/continuation-ownership.ts +29 -0
- package/src/responses/state/replay-fingerprint.ts +80 -0
- package/src/responses/state/snapshot-codec.ts +104 -0
- package/src/responses/state/spill-failure.ts +118 -0
- package/src/responses/state/spill-queue.ts +665 -0
- package/src/responses/state/temp-recovery.ts +257 -0
- package/src/responses/state.ts +82 -1143
- package/src/routing/identity-domains.ts +449 -0
- package/src/routing/probe-lease.ts +511 -0
- package/src/server/index/bounded-request.ts +88 -0
- package/src/server/index/live-sideband.ts +565 -0
- package/src/server/index/serve-options.ts +1766 -0
- package/src/server/index/startup-warnings.ts +213 -0
- package/src/server/index/websocket-handler.ts +335 -0
- package/src/server/index.ts +40 -2547
- package/src/server/management/route-registry.ts +26 -23
- package/src/server/management/shared.ts +8 -5
- package/src/server/management/workflow-budget-routes.ts +133 -0
- package/src/server/management-api.ts +12 -0
- package/src/server/request-log-conversation.ts +9 -7
- package/src/server/request-log.ts +245 -1
- package/src/server/responses/account-change-state.ts +233 -0
- package/src/server/responses/adapter-continuation.ts +514 -0
- package/src/server/responses/adapter-delivery.ts +214 -0
- package/src/server/responses/adapter-dispatch.ts +971 -0
- package/src/server/responses/compact.ts +59 -4
- package/src/server/responses/completion-policy.ts +33 -0
- package/src/server/responses/core-auth.ts +527 -0
- package/src/server/responses/core-codex-account.ts +859 -0
- package/src/server/responses/core-combo-failure.ts +210 -0
- package/src/server/responses/core-combo.ts +707 -0
- package/src/server/responses/core-errors.ts +152 -0
- package/src/server/responses/core-lifetime.ts +95 -0
- package/src/server/responses/core-normalize.ts +350 -0
- package/src/server/responses/core-opaque-recovery.ts +380 -0
- package/src/server/responses/core-options.ts +159 -0
- package/src/server/responses/core-replay.ts +225 -0
- package/src/server/responses/core.ts +192 -8893
- package/src/server/responses/passthrough-delivery.ts +856 -0
- package/src/server/responses/passthrough-dispatch.ts +1476 -0
- package/src/server/responses/passthrough-execution.ts +54 -0
- package/src/server/responses/request-prepare.ts +970 -0
- package/src/server/responses/request-send-budget.ts +164 -0
- package/src/server/responses/request-sidecar-auth.ts +149 -0
- package/src/server/responses/request-transport.ts +744 -0
- package/src/server/responses/response-effects.ts +157 -0
- package/src/server/responses/run-turn-execution.ts +448 -0
- package/src/server/responses/sidecar-execution.ts +469 -0
- package/src/server/responses-image-gen-repair.ts +1 -1
- package/src/server/workflow-refusal.ts +84 -0
- package/src/types/config.ts +30 -0
- package/src/usage/log.ts +146 -0
- package/src/usage/summary.ts +171 -21
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { effectiveProviderAlias, effectiveProviderAliasDecision } from "../../providers/default-aliases";
|
|
2
|
+
import { initialModelSelectionPending } from "../../providers/initial-model-selection";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { createHash, createHmac, randomBytes } from "node:crypto";
|
|
5
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync } from "node:fs";
|
|
6
|
+
import { delimiter, dirname, join, resolve } from "node:path";
|
|
7
|
+
import { atomicWriteFile, expandUserPath, getConfigDir, websocketsEnabled } from "../../config";
|
|
8
|
+
import { resolveProviderApiKey } from "../../providers/key-store";
|
|
9
|
+
import { CODEX_CONFIG_PATH, CODEX_MODELS_CACHE_PATH, DEFAULT_CATALOG_PATH, readRootTomlString, resolveCodexConfigPath } from "../paths";
|
|
10
|
+
import {
|
|
11
|
+
clearModelCache,
|
|
12
|
+
clearProviderDiscoveryStatus,
|
|
13
|
+
captureModelCacheGeneration,
|
|
14
|
+
DEFAULT_MODEL_CACHE_TTL_MS,
|
|
15
|
+
getFreshCached,
|
|
16
|
+
getStaleCached,
|
|
17
|
+
isModelsFetchCoolingDown,
|
|
18
|
+
isModelCacheGenerationCurrent,
|
|
19
|
+
markModelsFetchFailure,
|
|
20
|
+
markProviderDiscoveryFailed,
|
|
21
|
+
markProviderDiscoveryOk,
|
|
22
|
+
shouldLogDiscoveryFailure,
|
|
23
|
+
setCached,
|
|
24
|
+
type ProviderModelDiscoveryFailure,
|
|
25
|
+
} from "../model-cache";
|
|
26
|
+
import {
|
|
27
|
+
buildModelsRequest,
|
|
28
|
+
getValidAccessTokenSnapshot,
|
|
29
|
+
observeActiveOAuthAccessToken,
|
|
30
|
+
resolveModelsAuthToken,
|
|
31
|
+
type OAuthActiveTokenObservation,
|
|
32
|
+
} from "../../oauth";
|
|
33
|
+
import type { OcxConfig, OcxProviderConfig } from "../../types";
|
|
34
|
+
import { modelInList } from "../../types";
|
|
35
|
+
import { CODEX_REASONING_LEVELS, codexEffortRank, configuredReasoningEfforts, modelRecordValue, sanitizeCodexReasoningEfforts } from "../../reasoning-effort";
|
|
36
|
+
import { isModelVisionSidecarConsumer } from "../../vision/eligibility";
|
|
37
|
+
import { getModelMetadata, getModelMetadataCaseInsensitive, listModelMetadata, resolveMetadataProvider, type ModelMetadata } from "../../generated/model-metadata";
|
|
38
|
+
import { enrichProviderFromRegistry, shouldCaseFoldMetadataModelId } from "../../providers/derive";
|
|
39
|
+
import {
|
|
40
|
+
captureFastPolicyAuthority,
|
|
41
|
+
fastPolicyForModel,
|
|
42
|
+
serviceTierSupportFromPolicy,
|
|
43
|
+
} from "../../providers/service-tier";
|
|
44
|
+
import type { FastPolicyAuthority } from "../../providers/fastwire";
|
|
45
|
+
import { effectiveGoogleMode, getProviderRegistryEntry, providerMatchesRegistryTransport, registryEntryForProviderDestination } from "../../providers/registry";
|
|
46
|
+
import { parseAntigravityAvailableModels, registerAntigravityDiscoveredWireModels } from "../../providers/antigravity-models";
|
|
47
|
+
import { applyProviderContextCap, providerContextCap, resolveUnknownRoutedContextWindow } from "../../providers/context-cap";
|
|
48
|
+
import { clampAutoCompactTokenLimit } from "../../providers/auto-compact-budget";
|
|
49
|
+
import { effectiveModelAliases } from "../../providers/default-aliases";
|
|
50
|
+
import { routedSlug, slugEquals, slugEquivalenceKey, slugsEquivalent } from "../../providers/slug-codec";
|
|
51
|
+
import { CODEX_GPT5_IDENTITY_LINE } from "../../adapters/identity";
|
|
52
|
+
import { filterCursorConfiguredModelsByLiveDiscovery } from "../../adapters/cursor/discovery";
|
|
53
|
+
import { fetchCursorUsableModels } from "../../adapters/cursor/live-models";
|
|
54
|
+
import { recordLiveCursorClaudeModels, recordLiveCursorMaxModeModels } from "../../adapters/cursor/catalog";
|
|
55
|
+
import { fetchQoderModels } from "../../adapters/qoder/live-models";
|
|
56
|
+
import { resolveQoderProfile } from "../../adapters/qoder/profiles";
|
|
57
|
+
import { fetchDevinUsableModels } from "../../adapters/devin/live-models";
|
|
58
|
+
import { isCanonicalOpenAiForwardProvider, OPENAI_API_PROVIDER_ID, OPENAI_CODEX_PROVIDER_ID } from "../../providers/openai-tiers";
|
|
59
|
+
import {
|
|
60
|
+
COMBO_NAMESPACE,
|
|
61
|
+
comboModelId,
|
|
62
|
+
getCombo,
|
|
63
|
+
listComboIds,
|
|
64
|
+
quotaInactiveReason,
|
|
65
|
+
targetKey,
|
|
66
|
+
} from "../../combos";
|
|
67
|
+
import type { NormalizedComboConfig } from "../../combos/types";
|
|
68
|
+
import {
|
|
69
|
+
ProviderOutboundPolicyError,
|
|
70
|
+
providerOutboundGet,
|
|
71
|
+
providerOutboundPost,
|
|
72
|
+
providerRedirectError,
|
|
73
|
+
} from "../../lib/provider-outbound";
|
|
74
|
+
import { redactSecretString } from "../../lib/redact";
|
|
75
|
+
import {
|
|
76
|
+
extractProviderModelItems,
|
|
77
|
+
isRegistryModelDiscoveryUrl,
|
|
78
|
+
readBoundedDiscoveryJson,
|
|
79
|
+
resolveProviderModelDiscovery,
|
|
80
|
+
type ModelDiscoveryResponseFailure,
|
|
81
|
+
type ProviderModelsApiItem,
|
|
82
|
+
type ResolvedProviderModelDiscovery,
|
|
83
|
+
} from "../../providers/model-discovery";
|
|
84
|
+
import { extractGoogleAiStudioModelItems } from "../../providers/google-ai-studio-model-discovery";
|
|
85
|
+
import { applyConfiguredHeadersLast, fetchOllamaShowEnrichment, ollamaShowEnrichable } from "../../providers/ollama-show";
|
|
86
|
+
import upstreamModelsSnapshot from "../data/upstream-models.json";
|
|
87
|
+
import { createAdmissionGate, ResourceAdmissionError, type AdmissionMetrics } from "../../lib/admission";
|
|
88
|
+
import { CODEX_CUSTOM_MODEL_CATALOG_KIND, JAWCODE_CATALOG_AUGMENT_PROVIDERS, catalogModelSlug, shouldExposeRoutedModel } from "./parsing";
|
|
89
|
+
import type { CatalogModel } from "./parsing";
|
|
90
|
+
import { disabledNativeSlugs, hasComboTargets, hasNativeOpenAiCapabilityMetadata, NATIVE_GPT56_MAX_INPUT_TOKENS, nativeContextLimits, nativeOpenAiCapabilityDisplayName, nativeDefaultReasoningEffort, nativeInputModalities, nativeOpenAiAutoCompactTokenLimit, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, nativeOpenAiMaxOutputTokens, nativeOpenAiSlugs, nativeParallelToolCalls, nativeReasoningEfforts } from "./metadata";
|
|
91
|
+
import { deriveComboCatalogModel, normalizedOpenAiApiSignature, openAiApiCollisionWarnings, replaceLastComboCatalogOmissions, warnUncataloguedComboOnce } from "./aggregation";
|
|
92
|
+
import type { ComboCatalogOmission } from "./aggregation";
|
|
93
|
+
import type { CatalogGatherProviderAuthEvidence } from "./filesystem-evidence";
|
|
94
|
+
import type {
|
|
95
|
+
CatalogAdmissionSnapshot,
|
|
96
|
+
CatalogDiscoveryPolicyField,
|
|
97
|
+
CatalogGatherAuthorityIdentity,
|
|
98
|
+
CatalogProviderDiscoveryPolicySnapshot,
|
|
99
|
+
CatalogProcessLocalEvidence,
|
|
100
|
+
CatalogSourceEvidence,
|
|
101
|
+
CatalogTrustedOpenAiApiPolicySnapshot,
|
|
102
|
+
} from "../convergence-types";
|
|
103
|
+
import { CALLABLE_CONFIGURED_COMPATIBILITY_MODELS, applyProviderConfigHints } from "./model-hints";
|
|
104
|
+
|
|
105
|
+
const DATED_VARIANT_YYYYMMDD = /^(\d{4})(\d{2})(\d{2})$/;
|
|
106
|
+
const DATED_VARIANT_YYMMDD = /^(2\d)(\d{2})(\d{2})$/;
|
|
107
|
+
const DATED_VARIANT_MMDD_OR_YYMM = /^(\d{2})(\d{2})$/;
|
|
108
|
+
|
|
109
|
+
/** Whether a Gregorian year contains February 29th. */
|
|
110
|
+
function isLeapYear(year: number): boolean {
|
|
111
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether a month/day pair exists in the given year. Without a year, February 29th is
|
|
116
|
+
* accepted because it occurs in at least one calendar year.
|
|
117
|
+
*/
|
|
118
|
+
function isValidCalendarDate(year: number | undefined, month: number, day: number): boolean {
|
|
119
|
+
if (year !== undefined && (year < 1 || year > 9999)) return false;
|
|
120
|
+
if (month < 1 || month > 12 || day < 1) return false;
|
|
121
|
+
const daysInMonth = [
|
|
122
|
+
31, year === undefined || isLeapYear(year) ? 29 : 28, 31, 30, 31, 30,
|
|
123
|
+
31, 31, 30, 31, 30, 31,
|
|
124
|
+
];
|
|
125
|
+
return day <= daysInMonth[month - 1]!;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Release-date suffixes providers actually publish: `YYYYMMDD` (`-20251001`), `YYMMDD`
|
|
130
|
+
* (`-260806`), `MMDD` (`-0813`) and `YYMM` (`-2512`). A `\d{8}`-only rule matched none of
|
|
131
|
+
* the dated ids on a real multi-provider install, so DeepSeek, Kimi, Mistral, Qwen and
|
|
132
|
+
* Solar aliases all fell through to `droppedConfiguredIds` (#3024).
|
|
133
|
+
*
|
|
134
|
+
* Calendar validation rejects impossible month-end and leap-day values as well as ordinary
|
|
135
|
+
* numeric suffixes such as `-2048`, `-4096` and `-8192`. `-1024` is the one irreducible
|
|
136
|
+
* collision — it is a valid `MMDD` (October 24th) — so it reads as dated. That is a known,
|
|
137
|
+
* accepted cost; the test table pins it so it cannot become a surprise later.
|
|
138
|
+
*
|
|
139
|
+
* Hyphenated ISO suffixes (`-2024-08-06`, `-05-06`) are deliberately out of scope: a
|
|
140
|
+
* hyphenated suffix is ambiguous against ordinary name segments and needs its own call.
|
|
141
|
+
*/
|
|
142
|
+
function isDatedVariantSuffix(suffix: string): boolean {
|
|
143
|
+
const yyyyMmDd = DATED_VARIANT_YYYYMMDD.exec(suffix);
|
|
144
|
+
if (yyyyMmDd) {
|
|
145
|
+
return isValidCalendarDate(
|
|
146
|
+
Number(yyyyMmDd[1]), Number(yyyyMmDd[2]), Number(yyyyMmDd[3]),
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const yyMmDd = DATED_VARIANT_YYMMDD.exec(suffix);
|
|
151
|
+
if (yyMmDd) {
|
|
152
|
+
return isValidCalendarDate(
|
|
153
|
+
2000 + Number(yyMmDd[1]), Number(yyMmDd[2]), Number(yyMmDd[3]),
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const mmDdOrYyMm = DATED_VARIANT_MMDD_OR_YYMM.exec(suffix);
|
|
158
|
+
if (!mmDdOrYyMm) return false;
|
|
159
|
+
const first = Number(mmDdOrYyMm[1]);
|
|
160
|
+
const second = Number(mmDdOrYyMm[2]);
|
|
161
|
+
return isValidCalendarDate(undefined, first, second)
|
|
162
|
+
|| (first >= 20 && first <= 29 && second >= 1 && second <= 12);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Whether `liveId` is a supported dated release of the configured base id. */
|
|
166
|
+
export function isDatedVariantId(liveId: string, configuredId: string): boolean {
|
|
167
|
+
if (!liveId.startsWith(`${configuredId}-`)) return false;
|
|
168
|
+
return isDatedVariantSuffix(liveId.slice(configuredId.length + 1));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export const lastDropWarnSignature = new Map<string, string>();
|
|
172
|
+
let lastWarningReconciledGeneration = 0;
|
|
173
|
+
|
|
174
|
+
export function reconcileProviderFetchWarnings(generation: number): number {
|
|
175
|
+
if (generation <= lastWarningReconciledGeneration) return 0;
|
|
176
|
+
const removed = lastDropWarnSignature.size;
|
|
177
|
+
lastDropWarnSignature.clear();
|
|
178
|
+
lastWarningReconciledGeneration = generation;
|
|
179
|
+
return removed;
|
|
180
|
+
}
|
|
181
|
+
export function warnDroppedConfiguredIdsOnce(name: string, droppedConfiguredIds: string[]): void {
|
|
182
|
+
const signature = [...droppedConfiguredIds].sort().join(",");
|
|
183
|
+
if (lastDropWarnSignature.get(name) === signature) return;
|
|
184
|
+
lastDropWarnSignature.set(name, signature);
|
|
185
|
+
console.warn(
|
|
186
|
+
`[opencodex] Provider model discovery for "${name}" omitted configured model ids; dropping them from the authoritative live catalog: ${droppedConfiguredIds.join(", ")}.`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
export function shouldExposeProviderModel(providerName: string, modelId: string): boolean {
|
|
190
|
+
if (providerName === "opencode-free") return modelId === "big-pickle" || modelId.endsWith("-free");
|
|
191
|
+
// xAI /models advertises both the dated deployment and this floating alias.
|
|
192
|
+
// Keep only grok-4.20-multi-agent-0309; the alias is the same server-side id.
|
|
193
|
+
if (providerName === "xai" && modelId === "grok-4.20-multi-agent-beta-latest") return false;
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function shouldRetainConfiguredProviderModel(
|
|
198
|
+
providerName: string,
|
|
199
|
+
modelId: string,
|
|
200
|
+
prov?: OcxProviderConfig,
|
|
201
|
+
): boolean {
|
|
202
|
+
if (CALLABLE_CONFIGURED_COMPATIBILITY_MODELS[providerName]?.has(modelId)) return true;
|
|
203
|
+
if (providerName === "opencode-free") return modelId === "big-pickle" || modelId.endsWith("-free");
|
|
204
|
+
if (modelInList(prov?.retainModels, modelId)) return true;
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Fold dated-release aliases and retain configured rows that must survive an
|
|
210
|
+
* authoritative live roster (compatibility allow-list, combo targets, Vertex
|
|
211
|
+
* default). Used on every discovery return — live, fresh cache, stale, and
|
|
212
|
+
* failure fallback — so a warm cache captured before a combo existed still
|
|
213
|
+
* surfaces the configured target (OCX-111 / #1308).
|
|
214
|
+
*
|
|
215
|
+
* Cache writes should pass `retainComboTargets: false` so combo retention is
|
|
216
|
+
* re-applied on read against the current capture, not frozen into the TTL entry.
|
|
217
|
+
*/
|
|
218
|
+
export function mergeConfiguredModelsIntoLiveCatalog(opts: {
|
|
219
|
+
name: string;
|
|
220
|
+
provider: OcxProviderConfig;
|
|
221
|
+
models: readonly CatalogModel[];
|
|
222
|
+
configured: readonly CatalogModel[];
|
|
223
|
+
retainConfiguredModelIds?: ReadonlySet<string>;
|
|
224
|
+
contextCap?: number;
|
|
225
|
+
seedVertexDefault?: boolean;
|
|
226
|
+
retainComboTargets?: boolean;
|
|
227
|
+
metadataModelIdCaseFold?: boolean;
|
|
228
|
+
}): { models: CatalogModel[]; droppedConfiguredIds: string[] } {
|
|
229
|
+
const {
|
|
230
|
+
name,
|
|
231
|
+
provider: prov,
|
|
232
|
+
configured,
|
|
233
|
+
retainConfiguredModelIds,
|
|
234
|
+
contextCap,
|
|
235
|
+
seedVertexDefault,
|
|
236
|
+
retainComboTargets = true,
|
|
237
|
+
metadataModelIdCaseFold,
|
|
238
|
+
} = opts;
|
|
239
|
+
const out = [...opts.models];
|
|
240
|
+
const present = new Set(out.map(model => model.id));
|
|
241
|
+
const droppedConfiguredIds: string[] = [];
|
|
242
|
+
for (const candidate of configured) {
|
|
243
|
+
if (present.has(candidate.id)) continue;
|
|
244
|
+
const dated = out.find(live => isDatedVariantId(live.id, candidate.id));
|
|
245
|
+
if (dated) {
|
|
246
|
+
out.push(applyProviderConfigHints(name, prov, { ...dated, id: candidate.id }, contextCap, metadataModelIdCaseFold));
|
|
247
|
+
present.add(candidate.id);
|
|
248
|
+
continue;
|
|
249
|
+
}
|
|
250
|
+
if (
|
|
251
|
+
seedVertexDefault === true
|
|
252
|
+
|| shouldRetainConfiguredProviderModel(name, candidate.id, prov)
|
|
253
|
+
|| (retainComboTargets && retainConfiguredModelIds?.has(candidate.id) === true)
|
|
254
|
+
) {
|
|
255
|
+
out.push(candidate);
|
|
256
|
+
present.add(candidate.id);
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
droppedConfiguredIds.push(candidate.id);
|
|
260
|
+
}
|
|
261
|
+
return { models: out, droppedConfiguredIds };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function filterCatalogVisibleModels(
|
|
265
|
+
models: CatalogModel[],
|
|
266
|
+
config: Pick<OcxConfig, "disabledModels" | "providers">,
|
|
267
|
+
): CatalogModel[] {
|
|
268
|
+
const disabled = new Set(config.disabledModels ?? []);
|
|
269
|
+
const allowByProvider = new Map<string, Set<string>>();
|
|
270
|
+
for (const [name, prov] of Object.entries(config.providers)) {
|
|
271
|
+
const sel = prov.selectedModels;
|
|
272
|
+
// Keyed the way `sync.ts` keys the same list, so a slash-bearing native id and
|
|
273
|
+
// the encoded slug the Codex picker displays are one entry rather than two. A
|
|
274
|
+
// bare `Set(sel)` matched only the native form, so an allowlist written from the
|
|
275
|
+
// displayed slug — which `ocx models remove` also accepts — hid every model it
|
|
276
|
+
// was meant to keep.
|
|
277
|
+
//
|
|
278
|
+
// The key is deliberately lossy: `p/a/b` and `p/a-b` collapse to one entry, so a
|
|
279
|
+
// provider publishing both spellings has them selected together. That is a real
|
|
280
|
+
// limitation, pinned by the tests below and tracked as a follow-up; it is NOT
|
|
281
|
+
// fixed here. Resolving selections against the current roster instead was tried
|
|
282
|
+
// and rejected — the roster is an incomplete dictionary (live discovery can omit
|
|
283
|
+
// a published id), so it produces the same over-grant while additionally
|
|
284
|
+
// disagreeing with the `slugEquivalenceKey` contract `sync.ts` uses at merge time.
|
|
285
|
+
// Two catalog stages with different equivalence relations is the exact bug class
|
|
286
|
+
// this change exists to remove.
|
|
287
|
+
if (Array.isArray(sel) && sel.length > 0) {
|
|
288
|
+
allowByProvider.set(name, new Set(sel.map(model => slugEquivalenceKey(routedSlug(name, model)))));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return models.filter(m => {
|
|
292
|
+
if (initialModelSelectionPending(config.providers[m.provider])) return false;
|
|
293
|
+
const nativeAlias = m.provider === COMBO_NAMESPACE && m.nativeAlias === true;
|
|
294
|
+
// disabledModels may be stored raw (canonical) or encoded (legacy UI writes).
|
|
295
|
+
for (const stored of disabled) {
|
|
296
|
+
// Combo management stores the public alias, while canonical `combo/<id>` references
|
|
297
|
+
// remain valid for backward compatibility through slugEquals below.
|
|
298
|
+
if (m.alias !== undefined && stored === catalogModelSlug(m) && !nativeAlias) return false;
|
|
299
|
+
if (slugEquals(stored, m.provider, m.id)) return false;
|
|
300
|
+
}
|
|
301
|
+
const allow = allowByProvider.get(m.provider);
|
|
302
|
+
return !allow || allow.has(slugEquivalenceKey(routedSlug(m.provider, m.id)));
|
|
303
|
+
});
|
|
304
|
+
}
|