@bitkyc08/opencodex 2.41.0 → 2.43.0-preview.20260906
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/AGENTS_INSTALL.md +2 -2
- package/README.md +31 -0
- package/bin/ocx.mjs +10 -1
- package/gui/dist/assets/index-DS1NE4Jn.css +1 -0
- package/gui/dist/assets/index-VGeQEZ_v.js +112 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/adapters/anthropic-image-codec.ts +304 -0
- package/src/adapters/anthropic-image-normalize.ts +8 -298
- package/src/adapters/anthropic.ts +30 -7
- package/src/adapters/command-code.ts +7 -5
- package/src/adapters/cursor/desktop-executor-contract.ts +15 -0
- package/src/adapters/cursor/images.ts +36 -6
- package/src/adapters/cursor/live-transport.ts +7 -2
- package/src/adapters/cursor/native-exec-desktop.ts +2 -15
- package/src/adapters/cursor/protobuf-request.ts +54 -24
- package/src/adapters/cursor/tool-definitions.ts +5 -670
- package/src/adapters/cursor/tool-guidance.ts +236 -0
- package/src/adapters/cursor/tool-naming.ts +252 -0
- package/src/adapters/cursor/tool-schemas.ts +195 -0
- package/src/adapters/cursor/types.ts +6 -3
- package/src/adapters/exec-tool-result-normalize.ts +1 -1
- package/src/adapters/google-errors.ts +9 -1
- package/src/adapters/google.ts +1 -0
- package/src/adapters/identity.ts +8 -2
- package/src/adapters/kiro-calibration.ts +181 -0
- package/src/adapters/kiro.ts +135 -3
- package/src/adapters/openai-responses.ts +259 -29
- package/src/adapters/responses-code-mode.ts +59 -0
- package/src/adapters/tool-catalog-nudge.ts +1 -1
- package/src/adapters/xai-schema-analysis.ts +86 -0
- package/src/adapters/xai-tool-schema.ts +2 -87
- package/src/adapters/xai-web-search.ts +1 -1
- package/src/bridge.ts +47 -13
- package/src/chat/inbound.ts +11 -3
- package/src/claude/inbound-content-options.ts +60 -0
- package/src/claude/inbound-model-options.ts +142 -0
- package/src/claude/inbound-records.ts +7 -0
- package/src/claude/inbound.ts +10 -202
- package/src/claude/model-info.ts +45 -0
- package/src/cli/account-auth.ts +49 -9
- package/src/cli/account-extended.ts +7 -1
- package/src/cli/capabilities.ts +15 -4
- package/src/cli/claude.ts +232 -39
- package/src/cli/config-command.ts +9 -1
- package/src/cli/dispatch.ts +5 -1
- package/src/cli/doctor.ts +10 -0
- package/src/cli/effort.ts +372 -0
- package/src/cli/export-command.ts +3 -9
- package/src/cli/help.ts +1 -0
- package/src/cli/index.ts +13 -0
- package/src/cli/init.ts +4 -0
- package/src/cli/model-selection-guidance.ts +30 -0
- package/src/cli/models-runtime.ts +3 -2
- package/src/cli/models.ts +8 -3
- package/src/cli/observe.ts +3 -1
- package/src/cli/opencode.ts +4 -1
- package/src/cli/provider-runtime.ts +65 -0
- package/src/cli/provider.ts +8 -0
- package/src/cli/registry.ts +16 -2
- package/src/cli/runtime-api.ts +3 -1
- package/src/cli/star-prompt.ts +22 -6
- package/src/cli/status-probes.ts +168 -0
- package/src/cli/status.ts +5 -168
- package/src/clients/config-export/constants.ts +69 -0
- package/src/clients/config-export/contracts.ts +154 -0
- package/src/clients/config-export/dsh.ts +132 -0
- package/src/clients/config-export/fast-models.ts +29 -0
- package/src/clients/config-export/mcode.ts +83 -0
- package/src/clients/config-export/model-metadata.ts +108 -0
- package/src/clients/config-export/omp.ts +104 -0
- package/src/clients/config-export/zcode.ts +92 -0
- package/src/clients/config-export.ts +18 -710
- package/src/codex/account-lifecycle.ts +20 -3
- package/src/codex/account-usability.ts +2 -0
- package/src/codex/auth-api.ts +272 -32
- package/src/codex/auth-context.ts +328 -24
- package/src/codex/catalog/effort.ts +44 -5
- package/src/codex/catalog/metadata.ts +149 -14
- package/src/codex/catalog/native-models.ts +116 -4
- package/src/codex/catalog/parsing.ts +122 -8
- package/src/codex/catalog/provider-fetch.ts +154 -23
- package/src/codex/catalog/reserve.ts +52 -0
- package/src/codex/catalog/sync.ts +89 -16
- package/src/codex/catalog.ts +1 -1
- package/src/codex/convergence-types.ts +1 -0
- package/src/codex/convergence.ts +2 -0
- package/src/codex/data/upstream-models.json +169 -0
- package/src/codex/forward-transport-headers.ts +25 -0
- package/src/codex/inject.ts +99 -34
- package/src/codex/injected-marker.ts +30 -4
- package/src/codex/journal.ts +14 -0
- package/src/codex/legacy-config-keys.ts +68 -0
- package/src/codex/log-guard/inspect-schema.ts +137 -0
- package/src/codex/log-guard/inspect.ts +2 -134
- package/src/codex/loopback-target.ts +54 -0
- package/src/codex/main-account-cache.ts +63 -1
- package/src/codex/main-account-hard-lock.ts +52 -0
- package/src/codex/main-account.ts +3 -1
- package/src/codex/management-convergence.ts +3 -0
- package/src/codex/model-entitlements.ts +54 -4
- package/src/codex/project-config-warnings.ts +92 -2
- package/src/codex/prompt-layers/encoding.ts +80 -0
- package/src/codex/prompt-layers/paths.ts +54 -0
- package/src/codex/prompt-layers/revision.ts +55 -0
- package/src/codex/prompt-layers/toml-edit.ts +163 -0
- package/src/codex/prompt-layers/toml-read.ts +181 -0
- package/src/codex/prompt-layers.ts +14 -520
- package/src/codex/quota-auto-refresh-state.ts +16 -0
- package/src/codex/quota-auto-refresh.ts +219 -0
- package/src/codex/quota-types.ts +51 -0
- package/src/codex/quota.ts +252 -93
- package/src/codex/reserve-availability.ts +177 -0
- package/src/codex/routing.ts +28 -9
- package/src/codex/shim.ts +53 -11
- package/src/codex/subagent-model-fallback.ts +23 -3
- package/src/combos/failover.ts +125 -7
- package/src/combos/identifiers.ts +89 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/resolve.ts +80 -9
- package/src/combos/types.ts +20 -93
- package/src/config/subagent-models.ts +24 -0
- package/src/config.ts +156 -13
- package/src/generated/compatibility-version.json +474 -178
- package/src/generated/model-metadata.ts +1 -1
- package/src/integrations/journal.ts +65 -4
- package/src/integrations/store.ts +5 -0
- package/src/lab/events/limits.ts +4 -0
- package/src/lib/destination-policy.ts +31 -2
- package/src/lib/errors.ts +39 -0
- package/src/lib/provider-outbound.ts +69 -3
- package/src/lib/proxy-env.ts +22 -0
- package/src/lib/redact-folding.ts +176 -0
- package/src/lib/redact.ts +2 -175
- package/src/lib/state-store-sweeper.ts +20 -6
- package/src/lib/token-estimate.ts +94 -27
- package/src/lib/windows-user-principal.ts +53 -5
- package/src/oauth/account-quota-rank.ts +40 -1
- package/src/oauth/anthropic-routing.ts +99 -3
- package/src/oauth/chatgpt-device.ts +187 -0
- package/src/oauth/chatgpt.ts +31 -4
- package/src/oauth/generic-account-failover.ts +36 -13
- package/src/oauth/index.ts +140 -29
- package/src/oauth/log.ts +3 -0
- package/src/oauth/login-cli.ts +5 -0
- package/src/oauth/meta-muse.ts +117 -15
- package/src/oauth/pool-settings-capability.ts +15 -4
- package/src/providers/api-keys.ts +8 -10
- package/src/providers/default-aliases.ts +39 -0
- package/src/providers/derive.ts +10 -2
- package/src/providers/fastwire.ts +36 -7
- package/src/providers/initial-model-selection-runtime.ts +90 -0
- package/src/providers/initial-model-selection.ts +120 -0
- package/src/providers/key-failover.ts +134 -54
- package/src/providers/key-store.ts +11 -1
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery.ts +76 -0
- package/src/providers/model-rename-startup.ts +72 -8
- package/src/providers/muse-subscription-usage.ts +95 -0
- package/src/providers/openai-sidecar.ts +17 -5
- package/src/providers/openai-tiers-destination.ts +102 -0
- package/src/providers/openai-tiers.ts +2 -99
- package/src/providers/opencode-go-transport.ts +41 -0
- package/src/providers/quota-key-accounts.ts +141 -0
- package/src/providers/quota-types.ts +9 -0
- package/src/providers/quota.ts +625 -98
- package/src/providers/registry.ts +60 -17
- package/src/providers/xai-responses-opt-in.ts +31 -5
- package/src/quota/reset-activation.ts +81 -0
- package/src/quota/reset-detector.ts +305 -0
- package/src/quota/reset-notify-config.ts +162 -0
- package/src/quota/reset-observer.ts +125 -0
- package/src/quota/reset-poller.ts +160 -0
- package/src/quota/reset-seen-store.ts +385 -0
- package/src/quota/reset-sinks.ts +199 -0
- package/src/quota/window-mapping.ts +106 -0
- package/src/responses/apply-patch-envelope.ts +46 -0
- package/src/responses/code-mode-helper-compat.ts +39 -1
- package/src/responses/custom-tool-compat.ts +10 -4
- package/src/responses/hosted-tool-policy.ts +12 -4
- package/src/responses/parser-content.ts +133 -0
- package/src/responses/parser-text-format.ts +24 -0
- package/src/responses/parser-tools.ts +188 -0
- package/src/responses/parser.ts +3 -326
- package/src/responses/state.ts +124 -28
- package/src/router.ts +48 -13
- package/src/routing/analytics.ts +1 -0
- package/src/routing/capability.ts +17 -4
- package/src/server/auth-cors.ts +7 -1
- package/src/server/background-lifecycle.ts +23 -1
- package/src/server/chat-completions.ts +25 -3
- package/src/server/claude-messages.ts +62 -5
- package/src/server/effort-row.ts +1 -1
- package/src/server/fast-row.ts +295 -0
- package/src/server/gui-static.ts +30 -4
- package/src/server/index.ts +122 -28
- package/src/server/live.ts +18 -4
- package/src/server/management/agent-settings-routes.ts +2 -2
- package/src/server/management/combo-routes.ts +37 -9
- package/src/server/management/config-routes.ts +93 -2
- package/src/server/management/integration-routes.ts +108 -0
- package/src/server/management/model-routes.ts +13 -3
- package/src/server/management/model-rows.ts +20 -1
- package/src/server/management/native-integration-routes.ts +4 -1
- package/src/server/management/oauth-account-routes.ts +45 -10
- package/src/server/management/provider-routes.ts +34 -3
- package/src/server/management/quota-reset-routes.ts +57 -0
- package/src/server/management/route-registry.ts +7 -4
- package/src/server/management/shared.ts +19 -5
- package/src/server/management/system-routes.ts +3 -2
- package/src/server/management-api.ts +14 -2
- package/src/server/ports.ts +12 -2
- package/src/server/relay-eager.ts +38 -23
- package/src/server/relay.ts +4 -0
- package/src/server/request-log.ts +6 -0
- package/src/server/responses/codex-ws-correlation.ts +65 -0
- package/src/server/responses/codex-ws-exchange.ts +261 -0
- package/src/server/responses/codex-ws-metadata.ts +134 -0
- package/src/server/responses/codex-ws-pool.ts +162 -0
- package/src/server/responses/codex-ws-request.ts +87 -0
- package/src/server/responses/codex-ws-session.ts +93 -0
- package/src/server/responses/codex-ws-wire.ts +144 -0
- package/src/server/responses/collaboration.ts +41 -1
- package/src/server/responses/compact.ts +105 -12
- package/src/server/responses/core.ts +510 -57
- package/src/server/responses/empty-completion-guard.ts +4 -0
- package/src/server/responses/fetch-helpers.ts +10 -3
- package/src/server/responses/input-admission.ts +16 -9
- package/src/server/responses/responses-field-backfill.ts +1 -1
- package/src/server/responses/ws-upstream.ts +34 -318
- package/src/server/responses-custom-tool-repair.ts +20 -4
- package/src/server/responses-undeclared-tool-guard.ts +100 -8
- package/src/server/safe-response-headers.ts +23 -0
- package/src/server/search.ts +9 -0
- package/src/server/subagent-models-startup.ts +27 -0
- package/src/server/system-env-shell.ts +238 -0
- package/src/server/system-env.ts +7 -234
- package/src/server/ws-bridge.ts +3 -25
- package/src/server/xai-responses-startup.ts +21 -0
- package/src/service-manager-probe.ts +1 -1
- package/src/service.ts +55 -16
- package/src/types/config.ts +108 -12
- package/src/types/provider.ts +36 -7
- package/src/types/request.ts +8 -0
- package/src/types/tools.ts +26 -1
- package/src/types.ts +2 -0
- package/src/update/notify.ts +8 -2
- package/src/usage/cost.ts +38 -28
- package/src/usage/expected-prices.ts +34 -15
- package/src/usage/log.ts +2 -0
- package/src/usage/model-identity.ts +26 -0
- package/src/usage/summary.ts +15 -1
- package/src/vision/describe.ts +6 -0
- package/src/vision/image-rewrite.ts +108 -0
- package/src/vision/index.ts +19 -306
- package/src/vision/plan.ts +205 -0
- package/src/web-search/executor.ts +6 -0
- package/src/web-search/index.ts +8 -1
- package/gui/dist/assets/index-B2YjLA-i.css +0 -1
- package/gui/dist/assets/index-aPup8CKb.js +0 -112
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { OcxConfig } from "../../types";
|
|
2
|
+
import { isEffectiveCodexDesktopAuthless } from "../loopback-target";
|
|
3
|
+
import { CODEX_ACCOUNT_BOUND_CATALOG_KIND } from "./account-models";
|
|
4
|
+
import { NATIVE_RESERVE_MODEL } from "./native-models";
|
|
5
|
+
import type { RawEntry } from "./parsing";
|
|
6
|
+
|
|
7
|
+
export const RESERVE_METADATA_SOURCE_FIELD = "opencodex_reserve_metadata_source";
|
|
8
|
+
/** Validated genuine source metadata on the existing catalog, never an authorization. */
|
|
9
|
+
export const RESERVE_SOURCE_CATALOG_FIELD = "opencodex_reserve_source";
|
|
10
|
+
export const RESERVE_LUNA_METADATA_SOURCE = "gpt-5.6-luna";
|
|
11
|
+
|
|
12
|
+
/** Metadata only: no process-local availability or credential state belongs in a catalog. */
|
|
13
|
+
export interface ReserveCatalogProjection {
|
|
14
|
+
readonly source: RawEntry;
|
|
15
|
+
readonly mainSelectors: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** The caller supplies a validated actual observation and an already context-capped Luna pin. */
|
|
19
|
+
export function createReserveCatalogProjection(
|
|
20
|
+
config: Pick<OcxConfig, "runtimeRole" | "hostname" | "unauthenticatedLoopbackListener" | "codexDesktopAuthless">,
|
|
21
|
+
mainSelectors: readonly string[],
|
|
22
|
+
observedSource: RawEntry | null,
|
|
23
|
+
lunaSource: RawEntry | null,
|
|
24
|
+
): ReserveCatalogProjection | undefined {
|
|
25
|
+
if (!isEffectiveCodexDesktopAuthless(config) || mainSelectors.length === 0) return undefined;
|
|
26
|
+
const original = observedSource ?? lunaSource;
|
|
27
|
+
if (!original) return undefined;
|
|
28
|
+
const source = structuredClone(original);
|
|
29
|
+
source.slug = NATIVE_RESERVE_MODEL;
|
|
30
|
+
source.display_name = observedSource?.display_name ?? "Luna Reserve";
|
|
31
|
+
source.description = "Manual main-account Reserve through OpenCodex; recent upstream permission is required for every request.";
|
|
32
|
+
// This qualified OCX endpoint accepts the selector, not an OpenAI API-key model grant.
|
|
33
|
+
source.supported_in_api = true;
|
|
34
|
+
source[RESERVE_METADATA_SOURCE_FIELD] = observedSource ? NATIVE_RESERVE_MODEL : RESERVE_LUNA_METADATA_SOURCE;
|
|
35
|
+
delete source.available_in_plans;
|
|
36
|
+
delete source.availability_nux;
|
|
37
|
+
delete source.upgrade;
|
|
38
|
+
delete source.opencodex_account_observed_native;
|
|
39
|
+
delete source.opencodex_account_observed_selectors;
|
|
40
|
+
return { source, mainSelectors: [...mainSelectors] };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Exact OCX account projection, never another provider's similarly named model. */
|
|
44
|
+
export function isReserveCatalogProjection(entry: RawEntry): boolean {
|
|
45
|
+
return entry.opencodex_catalog_kind === CODEX_ACCOUNT_BOUND_CATALOG_KIND
|
|
46
|
+
&& typeof entry.slug === "string"
|
|
47
|
+
&& entry.slug.indexOf("/") > 0
|
|
48
|
+
&& entry.slug.indexOf("/") === entry.slug.lastIndexOf("/")
|
|
49
|
+
&& entry.slug.endsWith(`/${NATIVE_RESERVE_MODEL}`)
|
|
50
|
+
&& (entry[RESERVE_METADATA_SOURCE_FIELD] === NATIVE_RESERVE_MODEL
|
|
51
|
+
|| entry[RESERVE_METADATA_SOURCE_FIELD] === RESERVE_LUNA_METADATA_SOURCE);
|
|
52
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { effectiveProviderAlias } from "../../providers/default-aliases";
|
|
2
|
+
import { pendingModelSelectionProviders } from "../../providers/initial-model-selection";
|
|
1
3
|
import { execFileSync } from "node:child_process";
|
|
2
4
|
import { createHash } from "node:crypto";
|
|
3
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -73,7 +75,15 @@ import {
|
|
|
73
75
|
} from "../internal/catalog-writer";
|
|
74
76
|
import { codexRuntimeStatePath } from "../runtime";
|
|
75
77
|
import { accountBoundNativeDisplayName, CODEX_ACCOUNT_BOUND_CATALOG_KIND, trustedAccountBoundNativeCatalogSlug, visibleCodexAccountSelectors } from "./account-models";
|
|
76
|
-
import { ACCOUNT_GATED_NATIVE_OPENAI_MODELS } from "./native-models";
|
|
78
|
+
import { ACCOUNT_GATED_NATIVE_OPENAI_MODELS, NATIVE_RESERVE_MODEL } from "./native-models";
|
|
79
|
+
import { observedReserveCatalogSource } from "./metadata";
|
|
80
|
+
import {
|
|
81
|
+
createReserveCatalogProjection,
|
|
82
|
+
isReserveCatalogProjection,
|
|
83
|
+
RESERVE_LUNA_METADATA_SOURCE,
|
|
84
|
+
RESERVE_SOURCE_CATALOG_FIELD,
|
|
85
|
+
type ReserveCatalogProjection,
|
|
86
|
+
} from "./reserve";
|
|
77
87
|
|
|
78
88
|
export const MAX_SPAWN_AGENT_MODEL_OVERRIDES = 5;
|
|
79
89
|
|
|
@@ -267,17 +277,30 @@ function isExactComboCatalogEntry(
|
|
|
267
277
|
* ids differ by a single dash (`command-code` vs `commandcode`), so relabel them to the
|
|
268
278
|
* lowercase-dash style the opencode presets use: `commandcode-auth/x` and `commandcode-api/x`.
|
|
269
279
|
* The model-id portion also carries a redundant `<vendor>-` prefix (`deepseek-deepseek-v4-flash`)
|
|
270
|
-
* that is dropped for display.
|
|
280
|
+
* that is dropped for display. Google Antigravity is relabeled to the compact `agy/` prefix for
|
|
281
|
+
* the same reason: `google-antigravity/` alone consumes most of the picker row. That prefix comes
|
|
282
|
+
* from the row's own `providerAlias`, decided once per gather flight; `null` means a cross-provider
|
|
283
|
+
* collision suppressed it and the canonical slug stands. This is the raw-slug path only -- a
|
|
284
|
+
* configured `modelAliases` entry is labeled by the effective-alias path in
|
|
285
|
+
* catalog/provider-fetch.ts (#2960) and keeps the canonical provider name. All other providers
|
|
286
|
+
* keep the raw slug exactly as before.
|
|
271
287
|
*/
|
|
272
|
-
function routedDisplayName(slug: string): string {
|
|
288
|
+
function routedDisplayName(slug: string, model?: CatalogModel, config?: Pick<OcxConfig, "providers">): string {
|
|
273
289
|
const slash = slug.indexOf("/");
|
|
274
290
|
if (slash <= 0) return slug;
|
|
275
291
|
const provider = slug.slice(0, slash);
|
|
276
|
-
let
|
|
292
|
+
let modelId = slug.slice(slash + 1);
|
|
293
|
+
if (provider === "google-antigravity") {
|
|
294
|
+
if (model?.providerAlias === null) return slug;
|
|
295
|
+
const alias = (typeof model?.providerAlias === "string" && model.providerAlias.trim().length > 0)
|
|
296
|
+
? model.providerAlias.trim()
|
|
297
|
+
: effectiveProviderAlias(provider, undefined, config);
|
|
298
|
+
return alias ? `${alias}/${modelId}` : slug;
|
|
299
|
+
}
|
|
277
300
|
if (provider === "command-code" || provider === "commandcode") {
|
|
278
|
-
const m =
|
|
279
|
-
if (m &&
|
|
280
|
-
return `${provider === "command-code" ? "commandcode-auth" : "commandcode-api"}/${
|
|
301
|
+
const m = modelId.match(/^([a-z0-9]+)-([a-z0-9]+(?:-[a-z0-9]+)+)$/i);
|
|
302
|
+
if (m && modelId.startsWith(`${m[1]}-${m[1]}-`)) modelId = modelId.slice(m[1]!.length + 1);
|
|
303
|
+
return `${provider === "command-code" ? "commandcode-auth" : "commandcode-api"}/${modelId}`;
|
|
281
304
|
}
|
|
282
305
|
return slug;
|
|
283
306
|
}
|
|
@@ -306,7 +329,7 @@ export function deriveEntry(
|
|
|
306
329
|
if (template || codexForwardNativeCapabilityAlias) {
|
|
307
330
|
const e = JSON.parse(JSON.stringify(codexForwardNativeCapabilityAlias ?? template)) as RawEntry;
|
|
308
331
|
e.slug = slug;
|
|
309
|
-
e.display_name = routedDisplayName(slug);
|
|
332
|
+
e.display_name = routedDisplayName(slug, model);
|
|
310
333
|
e.description = desc;
|
|
311
334
|
e.priority = priority;
|
|
312
335
|
e.visibility = "list";
|
|
@@ -375,7 +398,7 @@ export function deriveEntry(
|
|
|
375
398
|
// Cursor still omits hosted web-search metadata because runTurn bypasses that separate sidecar.
|
|
376
399
|
const isCursorFallback = isRouted && model?.provider === "cursor";
|
|
377
400
|
const entry: RawEntry = {
|
|
378
|
-
slug, display_name: routedDisplayName(slug), description: desc,
|
|
401
|
+
slug, display_name: routedDisplayName(slug, model), description: desc,
|
|
379
402
|
shell_type: "unified_exec", visibility: "list", supported_in_api: true,
|
|
380
403
|
priority, base_instructions: "You are a helpful coding assistant.",
|
|
381
404
|
...(isRouted
|
|
@@ -422,6 +445,8 @@ export interface ObservedCatalogEntryBuildInput {
|
|
|
422
445
|
readonly accountNativeSlugs?: readonly string[];
|
|
423
446
|
/** Per-selector account ids; unknown observations must not be copied to unrelated accounts. */
|
|
424
447
|
readonly accountNativeSlugsBySelector?: ReadonlyMap<string, readonly string[]>;
|
|
448
|
+
/** Codex-only manual selector metadata; deliberately independent of live permission. */
|
|
449
|
+
readonly reserve?: ReserveCatalogProjection;
|
|
425
450
|
}
|
|
426
451
|
|
|
427
452
|
/** Build entries with the process-observed Codex feature state. */
|
|
@@ -478,6 +503,7 @@ export function buildCatalogEntriesFromObservedState({
|
|
|
478
503
|
openaiContextCap,
|
|
479
504
|
accountNativeSlugs,
|
|
480
505
|
accountNativeSlugsBySelector,
|
|
506
|
+
reserve,
|
|
481
507
|
}: ObservedCatalogEntryBuildInput): RawEntry[] {
|
|
482
508
|
// Codex's models-manager sorts by `priority` ASC and advertises the first 5 picker-visible
|
|
483
509
|
// models to spawn_agent (sort_by_key(priority) + MAX_MODEL_OVERRIDES_IN_SPAWN_AGENT=5). Catalog
|
|
@@ -574,15 +600,17 @@ export function buildCatalogEntriesFromObservedState({
|
|
|
574
600
|
const selectorNativeSlugs = accountNativeSlugsBySelector?.get(selector)
|
|
575
601
|
?? accountNativeSlugs
|
|
576
602
|
?? gptSlugs;
|
|
577
|
-
const accountNativeEntries = selectorNativeSlugs.map(slug => (
|
|
603
|
+
const accountNativeEntries = selectorNativeSlugs.filter(slug => slug !== NATIVE_RESERVE_MODEL).map(slug => (
|
|
578
604
|
nativeEntriesBySlug.get(slug)
|
|
579
605
|
?? deriveEntry(template, slug, "OpenAI native model (Codex OAuth passthrough).", 9, undefined, new Set(), openaiContextCap)
|
|
580
606
|
));
|
|
607
|
+
if (reserve?.mainSelectors.includes(selector)) accountNativeEntries.push(reserve.source);
|
|
581
608
|
for (const [nativeIndex, native] of accountNativeEntries.entries()) {
|
|
582
609
|
const nativeSlug = String(native.slug);
|
|
583
610
|
if (disabledNativeAccountSlugs.has(nativeSlug)) continue;
|
|
584
611
|
const e = JSON.parse(JSON.stringify(native)) as RawEntry;
|
|
585
612
|
const catalogSlug = `${selector}/${nativeSlug}`;
|
|
613
|
+
if (nativeSlug === NATIVE_RESERVE_MODEL && disabledNativeAccountSlugs.has(catalogSlug)) continue;
|
|
586
614
|
e.slug = catalogSlug;
|
|
587
615
|
e.display_name = accountBoundNativeDisplayName(selector, native);
|
|
588
616
|
// Codex ignores this OpenCodex extension; preserve the native comp_hash unchanged.
|
|
@@ -656,6 +684,7 @@ export function buildCatalogEntriesFromObservedState({
|
|
|
656
684
|
}
|
|
657
685
|
return applyMultiAgentMode(out, multiAgentMode, multiAgentV2Enabled, {
|
|
658
686
|
keepNativeChatGptOnV1,
|
|
687
|
+
preserveDefaultMultiAgentVersion: isReserveCatalogProjection,
|
|
659
688
|
});
|
|
660
689
|
}
|
|
661
690
|
|
|
@@ -761,6 +790,7 @@ export interface ObservedCatalogMergeInput {
|
|
|
761
790
|
readonly disabledModels: ReadonlySet<string>;
|
|
762
791
|
readonly selectedModelsByProvider: ReadonlyMap<string, ReadonlySet<string>>;
|
|
763
792
|
readonly gatheredProviderNames: ReadonlySet<string>;
|
|
793
|
+
readonly pendingProviderNames?: ReadonlySet<string>;
|
|
764
794
|
readonly degradedProviderNames: ReadonlySet<string>;
|
|
765
795
|
readonly legacyCustomModelSlugs: ReadonlySet<string>;
|
|
766
796
|
readonly multiAgentMode: MultiAgentMode;
|
|
@@ -792,6 +822,7 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
792
822
|
disabledModels,
|
|
793
823
|
selectedModelsByProvider,
|
|
794
824
|
gatheredProviderNames,
|
|
825
|
+
pendingProviderNames = new Set(),
|
|
795
826
|
degradedProviderNames,
|
|
796
827
|
legacyCustomModelSlugs,
|
|
797
828
|
multiAgentMode,
|
|
@@ -841,6 +872,7 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
841
872
|
if (disabledModelKeys.has(key)) return false;
|
|
842
873
|
const slash = slug.indexOf("/");
|
|
843
874
|
const provider = slug.slice(0, slash);
|
|
875
|
+
if (pendingProviderNames.has(provider)) return false;
|
|
844
876
|
const selected = selectedModelKeysByProvider.get(provider);
|
|
845
877
|
if (selected !== undefined && !selected.has(key)) return false;
|
|
846
878
|
return !gatheredProviderNames.has(provider) || degradedProviderNames.has(provider);
|
|
@@ -946,7 +978,7 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
946
978
|
const preserved = normalizeServiceTiers({ ...m, priority: nativePriority(slug, m.priority) });
|
|
947
979
|
// Older natives kept from disk still need the mock top tiers (max + ultra always
|
|
948
980
|
// for subagent max spawns; wire-clamped to the model's real top rung).
|
|
949
|
-
if (!isGpt56NativeSlug(slug)) ensureUltraReasoningLevel(preserved);
|
|
981
|
+
if (!isGpt56NativeSlug(slug) && slug !== NATIVE_RESERVE_MODEL) ensureUltraReasoningLevel(preserved);
|
|
950
982
|
return preserved;
|
|
951
983
|
})
|
|
952
984
|
: [];
|
|
@@ -981,6 +1013,9 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
981
1013
|
typeof entry.slug === "string" ? [[entry.slug, entry] as const] : []
|
|
982
1014
|
));
|
|
983
1015
|
const alignedAccountBoundEntries = detachedAccountBoundEntries.map(entry => {
|
|
1016
|
+
// The explicit Reserve source is already chosen (actual row or documented Luna adaptation).
|
|
1017
|
+
// A generic native merge must not replace its provenance or capability ladder.
|
|
1018
|
+
if (isReserveCatalogProjection(entry)) return entry;
|
|
984
1019
|
const nativeSlug = trustedAccountBoundNativeCatalogSlug(entry);
|
|
985
1020
|
const source = nativeSlug === undefined ? undefined : nativeSourceBySlug.get(nativeSlug);
|
|
986
1021
|
if (!source) return entry;
|
|
@@ -1036,6 +1071,7 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
1036
1071
|
if (freshExactComboEntries.has(entry)) return true;
|
|
1037
1072
|
const slash = slug.indexOf("/");
|
|
1038
1073
|
const provider = slug.slice(0, slash);
|
|
1074
|
+
if (pendingProviderNames.has(provider)) return false;
|
|
1039
1075
|
const selected = selectedModelKeysByProvider.get(provider);
|
|
1040
1076
|
return selected === undefined || selected.has(slugEquivalenceKey(slug));
|
|
1041
1077
|
});
|
|
@@ -1087,17 +1123,18 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
1087
1123
|
}));
|
|
1088
1124
|
for (const slug of policy.nativeBackfillSlugs) observedNativeSlugs.add(slug);
|
|
1089
1125
|
const mergedEntries = [...native, ...managedEntries].map(m => {
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1126
|
+
const reserveProjection = isReserveCatalogProjection(m);
|
|
1127
|
+
const normalized = reserveProjection ? m : normalizeServiceTiers(m);
|
|
1128
|
+
if (!reserveProjection && !isNativeAliasCatalogEntry(normalized)) applyNativeOpenAiContextOverride(normalized, openaiContextCap);
|
|
1092
1129
|
const exactCombo = isExactComboCatalogEntry(m, exactComboSlugs);
|
|
1093
|
-
const e = ensureStrictCatalogFields(normalized, {
|
|
1130
|
+
const e = reserveProjection ? normalized : ensureStrictCatalogFields(normalized, {
|
|
1094
1131
|
preserveExactInputModalities: exactCombo,
|
|
1095
1132
|
isRouted: finalRoutedEntrySet.has(m),
|
|
1096
1133
|
});
|
|
1097
1134
|
// Mock-max universality (260709): preserved routed entries from disk may predate
|
|
1098
1135
|
// the max rung — ensure it here so subagent max spawns validate on every
|
|
1099
1136
|
// reasoning-capable entry. max only: 5.6 exact ladders (luna: no ultra) stay intact.
|
|
1100
|
-
if (!exactCombo) {
|
|
1137
|
+
if (!exactCombo && !reserveProjection) {
|
|
1101
1138
|
const levels = Array.isArray(e.supported_reasoning_levels)
|
|
1102
1139
|
? e.supported_reasoning_levels as Array<{ effort?: string }>
|
|
1103
1140
|
: [];
|
|
@@ -1122,7 +1159,7 @@ export function mergeCatalogEntriesFromObservedState({
|
|
|
1122
1159
|
applyNativeVisibility(mergedEntries, disabledModels, alignedAccountBoundEntries.length > 0, observedNativeSlugs),
|
|
1123
1160
|
multiAgentMode,
|
|
1124
1161
|
multiAgentV2Enabled,
|
|
1125
|
-
{ keepNativeChatGptOnV1 },
|
|
1162
|
+
{ keepNativeChatGptOnV1, preserveDefaultMultiAgentVersion: isReserveCatalogProjection },
|
|
1126
1163
|
);
|
|
1127
1164
|
for (const entry of versionedEntries) {
|
|
1128
1165
|
const kind = entry.opencodex_catalog_kind;
|
|
@@ -1610,6 +1647,36 @@ function writeRetainedCatalogSync({
|
|
|
1610
1647
|
trustedAccountBoundNativeCatalogSlug(entry) !== undefined),
|
|
1611
1648
|
];
|
|
1612
1649
|
const accountTargets = new Map(codexAccountNamespaceEntries(config));
|
|
1650
|
+
const reserveMainSelectors = accountSelectors.filter(selector =>
|
|
1651
|
+
isMainCodexAccountTarget(accountTargets.get(selector) ?? ""));
|
|
1652
|
+
// The active file can own a bare source even when the bundled catalog is the build base.
|
|
1653
|
+
// A previously clamped qualified projection must not shorten a retained genuine ladder.
|
|
1654
|
+
const reserveObservations = [
|
|
1655
|
+
...(onDiskCatalog?.models ?? []),
|
|
1656
|
+
...(read.modelsCache?.models ?? []),
|
|
1657
|
+
...(catalog.models ?? []),
|
|
1658
|
+
];
|
|
1659
|
+
const retainedReserve = onDiskCatalog?.[RESERVE_SOURCE_CATALOG_FIELD];
|
|
1660
|
+
const retainedReserveSource = retainedReserve && typeof retainedReserve === "object" && !Array.isArray(retainedReserve)
|
|
1661
|
+
? observedReserveCatalogSource([retainedReserve as RawEntry], [])
|
|
1662
|
+
: null;
|
|
1663
|
+
const observedReserveSource = observedReserveCatalogSource(
|
|
1664
|
+
// Cache invalidation carries historical bare observations alongside emitted models.
|
|
1665
|
+
// Only unmarked observations are fresh enough to supersede the retained source.
|
|
1666
|
+
reserveObservations.filter(entry => entry.slug === NATIVE_RESERVE_MODEL
|
|
1667
|
+
&& entry.opencodex_account_observed_native === undefined), reserveMainSelectors,
|
|
1668
|
+
) ?? retainedReserveSource ?? observedReserveCatalogSource(reserveObservations, reserveMainSelectors);
|
|
1669
|
+
// This root is read only by OCX. Upstream ModelsResponse ignores unknown root fields.
|
|
1670
|
+
// Retain before final runtime clamping: an omitted row must not turn into Luna next sync.
|
|
1671
|
+
if (observedReserveSource) catalog[RESERVE_SOURCE_CATALOG_FIELD] = structuredClone(observedReserveSource);
|
|
1672
|
+
else delete catalog[RESERVE_SOURCE_CATALOG_FIELD];
|
|
1673
|
+
const lunaSource = upstreamNativeEntry(RESERVE_LUNA_METADATA_SOURCE);
|
|
1674
|
+
const reserve = createReserveCatalogProjection(
|
|
1675
|
+
config,
|
|
1676
|
+
reserveMainSelectors,
|
|
1677
|
+
observedReserveSource,
|
|
1678
|
+
lunaSource ? finishUpstreamNativeEntry(lunaSource, 9, openaiContextCap) : null,
|
|
1679
|
+
);
|
|
1613
1680
|
const accountNativeSlugsBySelector = accountSelectors.length > 0
|
|
1614
1681
|
? new Map([...accountBoundNativeOpenAiSlugsBySelector(config, observedAccountNativeEntries)].map(([selector, slugs]) => {
|
|
1615
1682
|
const target = accountTargets.get(selector);
|
|
@@ -1691,6 +1758,7 @@ function writeRetainedCatalogSync({
|
|
|
1691
1758
|
openaiContextCap,
|
|
1692
1759
|
accountNativeSlugs,
|
|
1693
1760
|
accountNativeSlugsBySelector,
|
|
1761
|
+
reserve,
|
|
1694
1762
|
}).filter(entry => trustedAccountBoundNativeCatalogSlug(entry) !== undefined)
|
|
1695
1763
|
: [];
|
|
1696
1764
|
catalog.models = mergeCatalogEntriesFromObservedState({
|
|
@@ -1704,6 +1772,7 @@ function writeRetainedCatalogSync({
|
|
|
1704
1772
|
disabledModels: new Set(config.disabledModels ?? []),
|
|
1705
1773
|
selectedModelsByProvider,
|
|
1706
1774
|
gatheredProviderNames,
|
|
1775
|
+
pendingProviderNames: pendingModelSelectionProviders(config),
|
|
1707
1776
|
degradedProviderNames,
|
|
1708
1777
|
legacyCustomModelSlugs: legacyCustomModelCatalogSlugs(config),
|
|
1709
1778
|
multiAgentMode,
|
|
@@ -1806,6 +1875,10 @@ export async function syncCatalogModels(
|
|
|
1806
1875
|
config: OcxConfig,
|
|
1807
1876
|
options?: CodexCatalogSyncOptions,
|
|
1808
1877
|
): Promise<RetainedCatalogSyncResult> {
|
|
1878
|
+
if (pendingModelSelectionProviders(config).size) {
|
|
1879
|
+
const { resolvePendingInitialModelSelection } = await import("../../providers/initial-model-selection-runtime");
|
|
1880
|
+
await resolvePendingInitialModelSelection(config);
|
|
1881
|
+
}
|
|
1809
1882
|
const owningCodexHome = getCodexHome();
|
|
1810
1883
|
const preflightRead = readRetainedCatalogSync(config);
|
|
1811
1884
|
if (preflightRead === null) {
|
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, nativeOpenAiMaxOutputTokens, 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_GPT6_ASTRA_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 modelMaxOutputTokens?: Readonly<Record<string, number>>;
|
|
432
433
|
readonly virtualModels?: Readonly<Record<string, Readonly<{ wireModelId: string; reasoningMode: "pro" }>>>;
|
|
433
434
|
readonly modelInputModalities?: Readonly<Record<string, readonly string[]>>;
|
|
434
435
|
readonly modelReasoningEfforts?: Readonly<Record<string, readonly string[]>>;
|
package/src/codex/convergence.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { join } from "node:path";
|
|
|
2
2
|
|
|
3
3
|
import { getConfigDir, saveConfigPreservingClaudeCode, websocketsEnabled, withExpectedConfigGenerationSync } from "../config";
|
|
4
4
|
import { reconcileSuccessfulModelDiscoveries } from "../providers/new-model-policy";
|
|
5
|
+
import { pendingModelSelectionProviders } from "../providers/initial-model-selection";
|
|
5
6
|
import { COMBO_NAMESPACE } from "../combos";
|
|
6
7
|
import { getAuthStorePath } from "../oauth/store";
|
|
7
8
|
import type { OcxConfig } from "../types";
|
|
@@ -351,6 +352,7 @@ function prepareCatalog(
|
|
|
351
352
|
disabledModels: new Set(config.disabledModels ?? []),
|
|
352
353
|
selectedModelsByProvider,
|
|
353
354
|
gatheredProviderNames,
|
|
355
|
+
pendingProviderNames: pendingModelSelectionProviders(config),
|
|
354
356
|
degradedProviderNames,
|
|
355
357
|
legacyCustomModelSlugs: legacyCustomModelCatalogSlugs(config),
|
|
356
358
|
multiAgentMode,
|