@bitkyc08/opencodex 2.23.0 → 2.24.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-rFWrIE11.js → index-CFqJKF2L.js} +12 -12
- package/gui/dist/index.html +1 -1
- package/package.json +1 -1
- package/src/claude/context-windows.ts +15 -3
- package/src/claude/model-info.ts +1 -1
- package/src/codex/catalog/metadata.ts +100 -24
- package/src/codex/catalog/parsing.ts +45 -11
- package/src/codex/catalog/provider-fetch.ts +4 -2
- package/src/codex/catalog/sync.ts +9 -7
- package/src/codex/catalog.ts +1 -1
- package/src/generated/compatibility-version.json +15 -15
- package/src/lib/pinned-http.ts +7 -2
- package/src/lib/windows-elevation.ts +3 -3
- package/src/server/auth-cors.ts +40 -0
- package/src/server/chat-native.ts +32 -6
- package/src/server/management/config-routes.ts +79 -2
- package/src/service.ts +8 -0
- package/src/types.ts +1 -1
package/gui/dist/index.html
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
} catch (e) {}
|
|
17
17
|
})();
|
|
18
18
|
</script>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-CFqJKF2L.js"></script>
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/assets/index-DQsMZzI5.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
package/package.json
CHANGED
|
@@ -14,8 +14,20 @@ import { nativeOpenAiContextWindow, type CatalogModel } from "../codex/catalog";
|
|
|
14
14
|
|
|
15
15
|
const ONE_MILLION = 1_000_000;
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Auto-context defaults (devlog 260712 020, user-approved).
|
|
19
|
+
*
|
|
20
|
+
* The compact window is the token count at which Claude Code starts compacting, and it is
|
|
21
|
+
* also the floor `shouldMarkOneMillion` uses — a model may only carry the marker if it can
|
|
22
|
+
* host this window. 350,000 was chosen when the widest native row advertised 372,000.
|
|
23
|
+
*
|
|
24
|
+
* It now matches the auto-compaction limit the Codex catalog ships for the same models
|
|
25
|
+
* (`nativeAutoCompactLimit`: 829,800 against the 922,000 native window). Leaving the two
|
|
26
|
+
* apart meant one model compacting at 350k under Claude Code and at 829,800 under Codex.
|
|
27
|
+
* The value stays clear of the measured 922,000 ceiling by ~92k, so compaction still has
|
|
28
|
+
* room to run before the upstream refuses.
|
|
29
|
+
*/
|
|
30
|
+
export const AUTO_COMPACT_WINDOW_DEFAULT = 829_800;
|
|
19
31
|
export const AUTO_CONTEXT_FLOOR = 200_000;
|
|
20
32
|
/** Binary-verified accepted range for CLAUDE_CODE_AUTO_COMPACT_WINDOW (2.1.207: pSo=1e5, yDs=1e6). */
|
|
21
33
|
export const AUTO_COMPACT_WINDOW_MIN = 100_000;
|
|
@@ -59,7 +71,7 @@ function inAutoCompactRange(value: number): boolean {
|
|
|
59
71
|
* predicate so marker and threshold never separate (audit 021 #2); an invalid
|
|
60
72
|
* value disables auto marking entirely (the CLI would ignore it, leaving marked
|
|
61
73
|
* sub-1M models without their safety net). Out-of-range CONFIG values fall back
|
|
62
|
-
* to
|
|
74
|
+
* to AUTO_COMPACT_WINDOW_DEFAULT (the management API rejects them; this guards hand-edits).
|
|
63
75
|
*/
|
|
64
76
|
export function resolveAutoContext(claudeCode: AutoContextConfigSlice | undefined, envOverride?: string): AutoContextMode {
|
|
65
77
|
if (claudeCode?.autoContext === false) return AUTO_CONTEXT_OFF;
|
package/src/claude/model-info.ts
CHANGED
|
@@ -129,7 +129,7 @@ export function buildAnthropicModelInfos(
|
|
|
129
129
|
if (seen.has(id)) return;
|
|
130
130
|
seen.add(id);
|
|
131
131
|
// The marker fixes Claude Code's accounting at 1e6, but a model may accept less input
|
|
132
|
-
// than that
|
|
132
|
+
// than that — a routed GPT-5.6 row runs a 1,050,000 window while refusing past 922,000
|
|
133
133
|
// (measured — see devlog/_plan/260817_native_gpt56_1m_context/001_measurement_evidence.md).
|
|
134
134
|
// Advertising the flat 1e6 there would invite mid-session context_length_exceeded, so the
|
|
135
135
|
// variant reports whichever of the two is smaller.
|
|
@@ -100,25 +100,37 @@ export function isUnsupportedOpenAiNativeSlug(slug: string): boolean {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* Advertised
|
|
103
|
+
* Advertised context for the Codex-login native GPT-5.6 family.
|
|
104
104
|
*
|
|
105
|
-
*
|
|
106
|
-
* catalog
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
105
|
+
* This is an OPERATING CAP, not the hard ceiling — the same shape upstream uses. The live
|
|
106
|
+
* catalog reports `context_window: 272000` against a `max_context_window: 872000` for these
|
|
107
|
+
* slugs, and gpt-5.4 runs 272,000 against 1,000,000: the advertised window is always well
|
|
108
|
+
* inside what the model can take.
|
|
109
|
+
*
|
|
110
|
+
* The hard ceiling here was measured on 2026-08-17 against a real Codex-login account:
|
|
111
|
+
* `POST /backend-api/codex/responses` admitted 921,508 input tokens and refused 922,013 with
|
|
112
|
+
* `error.code: context_length_exceeded` on sol, terra and luna alike.
|
|
113
|
+
*
|
|
114
|
+
* Codex spends `context_window * effective_context_window_percent`, which defaults to 95%
|
|
115
|
+
* (codex-rs `openai_models.rs` / `turn_context.rs`). So this value yields a 875,900-token
|
|
116
|
+
* budget and leaves ~46k of headroom under the measured ceiling. An earlier release shipped
|
|
117
|
+
* 1,050,000 here, which spent 997,500 — past what the upstream accepts.
|
|
118
|
+
*
|
|
119
|
+
* Do NOT back-solve this from the ceiling (970,000 would land the budget at 921,500, inside
|
|
120
|
+
* the 1,840-token gap between the last success and the first refusal). The 95% is a safety
|
|
121
|
+
* margin to keep, not a discount to cancel out.
|
|
122
|
+
*
|
|
123
|
+
* Evidence: devlog/_plan/260817_native_gpt56_1m_context/001_measurement_evidence.md
|
|
124
|
+
* and 014_final_922k_with_margin.md.
|
|
113
125
|
*/
|
|
114
|
-
export const NATIVE_GPT56_CONTEXT_WINDOW =
|
|
126
|
+
export const NATIVE_GPT56_CONTEXT_WINDOW = 922_000;
|
|
115
127
|
|
|
116
128
|
/**
|
|
117
|
-
*
|
|
129
|
+
* Hard ceiling: the largest input the native GPT-5.6 family actually accepts (measured).
|
|
118
130
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
131
|
+
* Equal to the advertised window above rather than below it, because that window is already
|
|
132
|
+
* capped under this ceiling. The clamp stays because routed and API-key rows carry the same
|
|
133
|
+
* family at a 1,050,000 window, where 90% (945,000) WOULD overshoot this limit.
|
|
122
134
|
*/
|
|
123
135
|
export const NATIVE_GPT56_MAX_INPUT_TOKENS = 922_000;
|
|
124
136
|
|
|
@@ -158,12 +170,74 @@ const PINNED_NATIVE_CAPABILITY_ENTRIES: Map<string, RawEntry> = new Map(
|
|
|
158
170
|
}),
|
|
159
171
|
);
|
|
160
172
|
|
|
161
|
-
|
|
173
|
+
/**
|
|
174
|
+
* The user-owned levers that narrow a native window, carried together.
|
|
175
|
+
*
|
|
176
|
+
* Both only ever lower: the authoritative window is measured against what the upstream
|
|
177
|
+
* accepts, so a user value above it would re-create the over-advertising this unit fixed.
|
|
178
|
+
*
|
|
179
|
+
* This travels as an ARGUMENT rather than module state on purpose. `grok/sync.ts` runs in
|
|
180
|
+
* the `ocx ensure` parent process, outside the server, so an injected global would never
|
|
181
|
+
* reach it — that failure is recorded in
|
|
182
|
+
* devlog/_plan/260817_native_gpt56_1m_context/006_root_cause_replan.md. Every call site
|
|
183
|
+
* already holds a config or a cap, so passing one more field costs nothing.
|
|
184
|
+
*
|
|
185
|
+
* A bare number is still accepted for the many call sites that only know the cap.
|
|
186
|
+
*/
|
|
187
|
+
export interface NativeContextLimits {
|
|
188
|
+
/** `providerContextCaps.openai` */
|
|
189
|
+
readonly cap?: number;
|
|
190
|
+
/** `providers.openai.contextWindow` — a floor-wide user override. */
|
|
191
|
+
readonly providerWindow?: number;
|
|
192
|
+
/** `providers.openai.modelContextWindows` — per-model, wins over `providerWindow`. */
|
|
193
|
+
readonly modelWindows?: Readonly<Record<string, number>>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export type NativeContextLimitsInput = NativeContextLimits | number | undefined;
|
|
197
|
+
|
|
198
|
+
function positiveInt(value: unknown): number | undefined {
|
|
199
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function asLimits(input: NativeContextLimitsInput): NativeContextLimits {
|
|
203
|
+
if (input === undefined) return {};
|
|
204
|
+
return typeof input === "number" ? { cap: input } : input;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Read both levers out of a config once, for call sites that hold one. */
|
|
208
|
+
export function nativeContextLimits(
|
|
209
|
+
config: Pick<OcxConfig, "providers" | "providerContextCaps">,
|
|
210
|
+
): NativeContextLimits {
|
|
211
|
+
const provider = config.providers?.[OPENAI_CODEX_PROVIDER_ID];
|
|
212
|
+
const modelWindows: Record<string, number> = {};
|
|
213
|
+
for (const [slug, value] of Object.entries(provider?.modelContextWindows ?? {})) {
|
|
214
|
+
const window = positiveInt(value);
|
|
215
|
+
if (window !== undefined) modelWindows[slug] = window;
|
|
216
|
+
}
|
|
217
|
+
return {
|
|
218
|
+
...(positiveInt(providerContextCap(config, OPENAI_CODEX_PROVIDER_ID)) !== undefined
|
|
219
|
+
? { cap: providerContextCap(config, OPENAI_CODEX_PROVIDER_ID) }
|
|
220
|
+
: {}),
|
|
221
|
+
...(positiveInt(provider?.contextWindow) !== undefined ? { providerWindow: provider!.contextWindow } : {}),
|
|
222
|
+
...(Object.keys(modelWindows).length > 0 ? { modelWindows } : {}),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Apply the user levers to an authoritative value. Lowering only, in a fixed order. */
|
|
227
|
+
function narrowToLimits(raw: number | undefined, slug: string, input: NativeContextLimitsInput): number | undefined {
|
|
228
|
+
if (raw === undefined) return undefined;
|
|
229
|
+
const limits = asLimits(input);
|
|
230
|
+
const overlay = positiveInt(limits.modelWindows?.[slug]) ?? positiveInt(limits.providerWindow);
|
|
231
|
+
const narrowed = overlay === undefined ? raw : Math.min(raw, overlay);
|
|
232
|
+
return applyProviderContextCap(narrowed, limits.cap) ?? narrowed;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function nativeOpenAiContextWindow(slug: string, limits?: NativeContextLimitsInput): number | undefined {
|
|
162
236
|
const raw = NATIVE_OPENAI_CONTEXT_OVERRIDES[slug]?.contextWindow
|
|
163
237
|
?? (typeof PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)?.context_window === "number"
|
|
164
238
|
? PINNED_NATIVE_CAPABILITY_ENTRIES.get(slug)!.context_window as number
|
|
165
239
|
: undefined);
|
|
166
|
-
return
|
|
240
|
+
return narrowToLimits(raw, slug, limits);
|
|
167
241
|
}
|
|
168
242
|
|
|
169
243
|
/**
|
|
@@ -173,12 +247,12 @@ export function nativeOpenAiContextWindow(slug: string, contextCap?: number): nu
|
|
|
173
247
|
* A provider context cap lowers this too: a capped 272k window must not keep advertising a
|
|
174
248
|
* 922k input ceiling, or the cap would be cosmetic on every input-side surface.
|
|
175
249
|
*/
|
|
176
|
-
export function nativeOpenAiMaxInputTokens(slug: string,
|
|
250
|
+
export function nativeOpenAiMaxInputTokens(slug: string, limits?: NativeContextLimitsInput): number | undefined {
|
|
177
251
|
const raw = NATIVE_OPENAI_CONTEXT_OVERRIDES[slug]?.maxInputTokens;
|
|
178
252
|
if (raw === undefined) return undefined;
|
|
179
|
-
const window = nativeOpenAiContextWindow(slug,
|
|
180
|
-
const
|
|
181
|
-
return window === undefined ?
|
|
253
|
+
const window = nativeOpenAiContextWindow(slug, limits);
|
|
254
|
+
const narrowed = narrowToLimits(raw, slug, limits) ?? raw;
|
|
255
|
+
return window === undefined ? narrowed : Math.min(narrowed, window);
|
|
182
256
|
}
|
|
183
257
|
|
|
184
258
|
export function nativeInputModalities(slug: string): string[] {
|
|
@@ -291,13 +365,15 @@ export function desktopVisibleNativeSlugs(
|
|
|
291
365
|
]);
|
|
292
366
|
}
|
|
293
367
|
|
|
294
|
-
export function nativeModelRows(config: Pick<OcxConfig, "disabledModels" | "combos" | "providerContextCaps">): Array<{ slug: string; disabled: boolean; contextWindow?: number; maxInputTokens?: number }> {
|
|
368
|
+
export function nativeModelRows(config: Pick<OcxConfig, "disabledModels" | "combos" | "providerContextCaps" | "providers">): Array<{ slug: string; disabled: boolean; contextWindow?: number; maxInputTokens?: number }> {
|
|
295
369
|
const disabled = disabledNativeSlugs(config);
|
|
296
370
|
const shadowed = configuredNativeAliasSlugs(config);
|
|
297
|
-
|
|
371
|
+
// Both user levers, not just the cap: a per-model window set from the dashboard has to show
|
|
372
|
+
// up on the row the dashboard itself renders.
|
|
373
|
+
const limits = nativeContextLimits(config);
|
|
298
374
|
return NATIVE_OPENAI_MODELS.filter(slug => !shadowed.has(slug)).map(slug => {
|
|
299
|
-
const contextWindow = nativeOpenAiContextWindow(slug,
|
|
300
|
-
const maxInputTokens = nativeOpenAiMaxInputTokens(slug,
|
|
375
|
+
const contextWindow = nativeOpenAiContextWindow(slug, limits);
|
|
376
|
+
const maxInputTokens = nativeOpenAiMaxInputTokens(slug, limits);
|
|
301
377
|
return {
|
|
302
378
|
slug,
|
|
303
379
|
disabled: disabled.has(slug),
|
|
@@ -31,7 +31,7 @@ import { redactSecretString } from "../../lib/redact";
|
|
|
31
31
|
import upstreamModelsSnapshot from "../data/upstream-models.json";
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
import { NATIVE_OPENAI_CONTEXT_OVERRIDES, SUPPORTED_NATIVE_OPENAI_SLUGS, UPSTREAM_NATIVE_ENTRIES, isNativeOpenAiCapabilityAliasModel, nativeMultiAgentVersion } from "./metadata";
|
|
34
|
+
import { NATIVE_OPENAI_CONTEXT_OVERRIDES, SUPPORTED_NATIVE_OPENAI_SLUGS, UPSTREAM_NATIVE_ENTRIES, isNativeOpenAiCapabilityAliasModel, nativeMultiAgentVersion, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, type NativeContextLimitsInput } from "./metadata";
|
|
35
35
|
import { trustedAccountBoundNativeCatalogSlug } from "./account-models";
|
|
36
36
|
import { CODEX_NATIVE_ALIAS_CATALOG_KIND } from "./kinds";
|
|
37
37
|
|
|
@@ -269,10 +269,11 @@ export function isNativeOpenAiEntry(entry: RawEntry): boolean {
|
|
|
269
269
|
/**
|
|
270
270
|
* Auto-compaction threshold for a native row.
|
|
271
271
|
*
|
|
272
|
-
* The usual rule is 90% of the window, but a
|
|
273
|
-
* that (GPT-5.6: 922,000 against a 1,050,000 window, where 90% would be 945,000) has to
|
|
272
|
+
* The usual rule is 90% of the window, but a row whose input ceiling sits below that has to
|
|
274
273
|
* clamp to the ceiling instead — otherwise the client keeps filling until upstream answers
|
|
275
|
-
* `context_length_exceeded` and compaction never gets a chance to run.
|
|
274
|
+
* `context_length_exceeded` and compaction never gets a chance to run. Native GPT-5.6 no
|
|
275
|
+
* longer trips this (922,000 window, 829,800 at 90%), but the routed and API-key rows carry
|
|
276
|
+
* the same family at a 1,050,000 window where 90% would be 945,000 — past the ceiling.
|
|
276
277
|
*/
|
|
277
278
|
function nativeAutoCompactLimit(contextWindow: number, maxInputTokens: number | undefined, contextCap?: number): number {
|
|
278
279
|
const ninety = Math.floor(contextWindow * 0.9);
|
|
@@ -281,32 +282,65 @@ function nativeAutoCompactLimit(contextWindow: number, maxInputTokens: number |
|
|
|
281
282
|
return Math.min(ninety, cappedMaxInput, contextWindow);
|
|
282
283
|
}
|
|
283
284
|
|
|
284
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Narrow any already-resolved native window by the user levers.
|
|
287
|
+
*
|
|
288
|
+
* Used for the fields the accessors do not own (`max_context_window`, and preserved rows
|
|
289
|
+
* that carry no static override) so every field on a row lands at the same width.
|
|
290
|
+
*/
|
|
291
|
+
function narrowNativeMaxContextWindow(
|
|
292
|
+
slug: string,
|
|
293
|
+
value: number | undefined,
|
|
294
|
+
limits?: NativeContextLimitsInput,
|
|
295
|
+
): number | undefined {
|
|
296
|
+
if (typeof value !== "number" || value <= 0) return value;
|
|
297
|
+
const resolved = nativeOpenAiContextWindow(slug, limits);
|
|
298
|
+
const authoritative = nativeOpenAiContextWindow(slug);
|
|
299
|
+
// The accessor pair tells us how far the levers moved this slug; apply the same delta to a
|
|
300
|
+
// field the accessor does not model, without ever raising it.
|
|
301
|
+
if (resolved === undefined || authoritative === undefined) return value;
|
|
302
|
+
return Math.min(value, Math.max(resolved, 1));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export function applyNativeOpenAiContextOverride(entry: RawEntry, limits?: NativeContextLimitsInput): void {
|
|
285
306
|
const nativeSlug = trustedAccountBoundNativeCatalogSlug(entry)
|
|
286
307
|
?? (isNativeOpenAiEntry(entry) ? entry.slug as string : undefined);
|
|
287
308
|
if (!nativeSlug) return;
|
|
288
309
|
const override = NATIVE_OPENAI_CONTEXT_OVERRIDES[nativeSlug];
|
|
289
310
|
if (override) {
|
|
311
|
+
// Read the effective values through the accessors rather than re-deriving them from the
|
|
312
|
+
// static table: this function used to apply only the provider cap, so a per-model window
|
|
313
|
+
// the dashboard had already accepted was silently written back at full width here.
|
|
290
314
|
if (typeof override.contextWindow === "number") {
|
|
291
|
-
const contextWindow =
|
|
315
|
+
const contextWindow = nativeOpenAiContextWindow(nativeSlug, limits) ?? override.contextWindow;
|
|
292
316
|
entry.context_window = contextWindow;
|
|
293
|
-
entry.auto_compact_token_limit = nativeAutoCompactLimit(
|
|
317
|
+
entry.auto_compact_token_limit = nativeAutoCompactLimit(
|
|
318
|
+
contextWindow,
|
|
319
|
+
nativeOpenAiMaxInputTokens(nativeSlug, limits) ?? override.maxInputTokens,
|
|
320
|
+
undefined,
|
|
321
|
+
);
|
|
294
322
|
}
|
|
295
323
|
if (typeof override.maxContextWindow === "number") {
|
|
296
|
-
|
|
324
|
+
const maxContextWindow = narrowNativeMaxContextWindow(nativeSlug, override.maxContextWindow, limits);
|
|
325
|
+
entry.max_context_window = maxContextWindow;
|
|
297
326
|
}
|
|
298
327
|
}
|
|
299
328
|
// providerContextCaps.openai is a ceiling for native OpenAI rows regardless of where the
|
|
300
329
|
// advertised window came from (#1430): preserved rows without a hardcoded override (e.g.
|
|
301
330
|
// gpt-5.4-mini) must stay under the cap too, and auto-compaction follows the capped window.
|
|
331
|
+
// The per-model window narrows the same rows for the same reason.
|
|
302
332
|
const currentContext = typeof entry.context_window === "number" ? entry.context_window : undefined;
|
|
303
|
-
const cappedContext =
|
|
333
|
+
const cappedContext = narrowNativeMaxContextWindow(nativeSlug, currentContext, limits);
|
|
304
334
|
if (cappedContext !== currentContext && typeof cappedContext === "number") {
|
|
305
335
|
entry.context_window = cappedContext;
|
|
306
|
-
entry.auto_compact_token_limit = nativeAutoCompactLimit(
|
|
336
|
+
entry.auto_compact_token_limit = nativeAutoCompactLimit(
|
|
337
|
+
cappedContext,
|
|
338
|
+
nativeOpenAiMaxInputTokens(nativeSlug, limits) ?? override?.maxInputTokens,
|
|
339
|
+
undefined,
|
|
340
|
+
);
|
|
307
341
|
}
|
|
308
342
|
const currentMax = typeof entry.max_context_window === "number" ? entry.max_context_window : undefined;
|
|
309
|
-
const cappedMax =
|
|
343
|
+
const cappedMax = narrowNativeMaxContextWindow(nativeSlug, currentMax, limits);
|
|
310
344
|
if (cappedMax !== currentMax) {
|
|
311
345
|
entry.max_context_window = cappedMax;
|
|
312
346
|
}
|
|
@@ -1725,8 +1725,10 @@ async function gatherRoutedModelsUncached(
|
|
|
1725
1725
|
id: slug,
|
|
1726
1726
|
owned_by: "openai",
|
|
1727
1727
|
contextWindow,
|
|
1728
|
-
// Input limit, not the total window
|
|
1729
|
-
// 922,000
|
|
1728
|
+
// Input limit, not the total window. These coincide for native GPT-5.6 today (the
|
|
1729
|
+
// advertised 922,000 window is already capped at its measured ceiling), but the two
|
|
1730
|
+
// stay separate fields because routed/API rows of the same family run a wider window.
|
|
1731
|
+
// Falls back to the window for slugs with no separate ceiling.
|
|
1730
1732
|
maxInputTokens: Math.min(nativeOpenAiMaxInputTokens(slug, openaiContextCap) ?? contextWindow, contextWindow),
|
|
1731
1733
|
inputModalities: nativeInputModalities(slug),
|
|
1732
1734
|
reasoningEfforts: nativeReasoningEfforts(slug),
|
|
@@ -35,7 +35,7 @@ import { codexAccountNamespaceEntries, isMainCodexAccountTarget } from "../accou
|
|
|
35
35
|
|
|
36
36
|
import { CODEX_CUSTOM_MODEL_CATALOG_KIND, CODEX_PROVIDER_MODEL_CATALOG_KIND, activeCodexModelsCachePath, applyCatalogMetadata, applyMultiAgentMode, applyNativeOpenAiContextOverride, applyRoutedCodexToolMode, catalogBackupPathFor, catalogHasRoutedEntries, catalogModelSlug, ensureStrictCatalogFields, findNativeTemplate, isDefaultCatalogPath, isRoutedModelCompatibilityExcluded, legacyCatalogBackupPath, normalizeRoutedCatalogEntry, normalizeServiceTiers, readCatalog, readCatalogBackup, readCodexCatalogPath, readNativeBaseline } from "./parsing";
|
|
37
37
|
import type { CatalogModel, MultiAgentMode, RawCatalog, RawEntry } from "./parsing";
|
|
38
|
-
import { accountBoundNativeOpenAiSlugs, accountBoundNativeOpenAiSlugsBySelector, applyNativeVisibility, CODEX_NATIVE_ALIAS_CATALOG_KIND, desktopAllowlistSuppressedNativeSlugs, disabledNativeSlugs, isNativeAliasCatalogEntry, isUnsupportedOpenAiNativeSlug, NATIVE_OPENAI_MODELS, observedAccountBoundNativeEntries, shouldIncludeAccountBoundNativeOpenAi, shouldIncludeNativeOpenAi, shouldUpgradeToUpstreamEntry, SUPPORTED_NATIVE_OPENAI_SLUGS, upstreamNativeEntry } from "./metadata";
|
|
38
|
+
import { accountBoundNativeOpenAiSlugs, accountBoundNativeOpenAiSlugsBySelector, applyNativeVisibility, CODEX_NATIVE_ALIAS_CATALOG_KIND, desktopAllowlistSuppressedNativeSlugs, disabledNativeSlugs, isNativeAliasCatalogEntry, isUnsupportedOpenAiNativeSlug, NATIVE_OPENAI_MODELS, nativeContextLimits, observedAccountBoundNativeEntries, shouldIncludeAccountBoundNativeOpenAi, shouldIncludeNativeOpenAi, shouldUpgradeToUpstreamEntry, SUPPORTED_NATIVE_OPENAI_SLUGS, upstreamNativeEntry, type NativeContextLimitsInput } from "./metadata";
|
|
39
39
|
import {
|
|
40
40
|
bundledCatalogCacheState,
|
|
41
41
|
loadBundledCodexCatalog,
|
|
@@ -226,7 +226,7 @@ export function effectiveSubagentRoster(
|
|
|
226
226
|
return { candidates, advertised, excluded };
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
export function finishUpstreamNativeEntry(clone: RawEntry, priority: number, contextCap?:
|
|
229
|
+
export function finishUpstreamNativeEntry(clone: RawEntry, priority: number, contextCap?: NativeContextLimitsInput): RawEntry {
|
|
230
230
|
if (priority !== 9) clone.priority = priority;
|
|
231
231
|
applyNativeOpenAiContextOverride(clone, contextCap);
|
|
232
232
|
// GPT-5.6 natives keep their exact upstream ladders (e.g. luna has max but no ultra).
|
|
@@ -279,7 +279,7 @@ export function deriveEntry(
|
|
|
279
279
|
priority: number,
|
|
280
280
|
model?: CatalogModel,
|
|
281
281
|
exactComboSlugs: ReadonlySet<string> = new Set(),
|
|
282
|
-
contextCap?:
|
|
282
|
+
contextCap?: NativeContextLimitsInput,
|
|
283
283
|
): RawEntry {
|
|
284
284
|
const preserveExact = isExactComboCatalogModel(model, exactComboSlugs);
|
|
285
285
|
const codexForwardNativeCapabilityAlias = model?.codexForwardNativeCapabilityAlias === true
|
|
@@ -405,7 +405,7 @@ export interface ObservedCatalogEntryBuildInput {
|
|
|
405
405
|
readonly disabledNativeAccountSlugs: ReadonlySet<string>;
|
|
406
406
|
readonly multiAgentV2Enabled: boolean;
|
|
407
407
|
readonly keepNativeChatGptOnV1?: boolean;
|
|
408
|
-
readonly openaiContextCap?:
|
|
408
|
+
readonly openaiContextCap?: NativeContextLimitsInput;
|
|
409
409
|
/** Additional native ids to clone under account selectors, without creating bare rows. */
|
|
410
410
|
readonly accountNativeSlugs?: readonly string[];
|
|
411
411
|
/** Per-selector account ids; unknown observations must not be copied to unrelated accounts. */
|
|
@@ -424,7 +424,7 @@ export function buildCatalogEntries(
|
|
|
424
424
|
accountSelectors: readonly string[] = [],
|
|
425
425
|
suppressedBareNativeSlugs: ReadonlySet<string> = new Set(),
|
|
426
426
|
disabledNativeAccountSlugs: ReadonlySet<string> = new Set(),
|
|
427
|
-
contextCap?:
|
|
427
|
+
contextCap?: NativeContextLimitsInput,
|
|
428
428
|
accountNativeSlugs?: readonly string[],
|
|
429
429
|
accountNativeSlugsBySelector?: ReadonlyMap<string, readonly string[]>,
|
|
430
430
|
keepNativeChatGptOnV1 = false,
|
|
@@ -760,7 +760,7 @@ export interface ObservedCatalogMergeInput {
|
|
|
760
760
|
readonly accountBoundEntries: readonly RawEntry[];
|
|
761
761
|
readonly suppressedBareNativeSlugs?: ReadonlySet<string>;
|
|
762
762
|
readonly policy: ObservedCatalogMergePolicy;
|
|
763
|
-
readonly openaiContextCap?:
|
|
763
|
+
readonly openaiContextCap?: NativeContextLimitsInput;
|
|
764
764
|
}
|
|
765
765
|
|
|
766
766
|
/**
|
|
@@ -1424,7 +1424,9 @@ function writeRetainedCatalogSync({
|
|
|
1424
1424
|
const hasPhysicalComboProvider = Object.hasOwn(config.providers, COMBO_NAMESPACE);
|
|
1425
1425
|
const includeNativeOpenAi = shouldIncludeNativeOpenAi(config);
|
|
1426
1426
|
const includeAccountBoundNativeOpenAi = shouldIncludeAccountBoundNativeOpenAi(config);
|
|
1427
|
-
|
|
1427
|
+
// Both user levers. Passing only the cap here is what let a per-model window the dashboard
|
|
1428
|
+
// had accepted get written back at full width in the on-disk catalog.
|
|
1429
|
+
const openaiContextCap = nativeContextLimits(config);
|
|
1428
1430
|
const accountSelectors = includeAccountBoundNativeOpenAi
|
|
1429
1431
|
? visibleCodexAccountSelectors(config)
|
|
1430
1432
|
: [];
|
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_MAX_INPUT_TOKENS, NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS, NATIVE_OPENAI_MODELS, configuredNativeAliasSlugs, desktopAllowlistSuppressedNativeSlugs, isNativeAliasCatalogEntry, isNativeOpenAiCapabilityAliasModel, nativeOpenAiCapabilitySourceSlug, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, disabledNativeSlugs, visibleNativeSlugs, desktopVisibleNativeSlugs, nativeModelRows, applyNativeVisibility, observedAccountBoundNativeEntries, observedAccountBoundNativeOpenAiSlugs, upstreamNativeEntry, nativeOpenAiSlugs, listCatalogNativeSlugs, nativeInputModalities, nativeReasoningEfforts, nativeDefaultReasoningEffort, shouldIncludeAccountBoundNativeOpenAi, shouldIncludeNativeOpenAi } from "./catalog/metadata";
|
|
5
|
+
export { accountBoundNativeOpenAiSlugs, accountBoundNativeOpenAiSlugsBySelector, CODEX_NATIVE_ALIAS_CATALOG_KIND, NATIVE_DAYBREAK_BLUE_MODEL, NATIVE_GPT56_MAX_INPUT_TOKENS, NATIVE_OPENAI_CAPABILITY_ALIAS_MODELS, NATIVE_OPENAI_MODELS, configuredNativeAliasSlugs, desktopAllowlistSuppressedNativeSlugs, isNativeAliasCatalogEntry, isNativeOpenAiCapabilityAliasModel, nativeContextLimits, nativeOpenAiCapabilitySourceSlug, nativeOpenAiContextWindow, nativeOpenAiMaxInputTokens, 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";
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
"path": "package.json",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "82a2b976e7b6e80afbf2b72f446758665ef0c78c83adf116f1cad43f2cfbc34b"
|
|
14
14
|
},
|
|
15
15
|
{
|
|
16
16
|
"path": "scripts/model-metadata.source.json",
|
|
@@ -342,7 +342,7 @@
|
|
|
342
342
|
},
|
|
343
343
|
{
|
|
344
344
|
"path": "src/claude/context-windows.ts",
|
|
345
|
-
"sha256": "
|
|
345
|
+
"sha256": "41c66bc19175eace1d367f349a3311a691c3445d5b9f3f16fab7cd351939cb9c"
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
"path": "src/claude/desktop-3p-guard.ts",
|
|
@@ -378,7 +378,7 @@
|
|
|
378
378
|
},
|
|
379
379
|
{
|
|
380
380
|
"path": "src/claude/model-info.ts",
|
|
381
|
-
"sha256": "
|
|
381
|
+
"sha256": "f83181da3d11d47ebdbffcbbfbdfbc860ed2c296f30cdc36d1c7a3bec7061134"
|
|
382
382
|
},
|
|
383
383
|
{
|
|
384
384
|
"path": "src/claude/outbound.ts",
|
|
@@ -662,7 +662,7 @@
|
|
|
662
662
|
},
|
|
663
663
|
{
|
|
664
664
|
"path": "src/codex/catalog.ts",
|
|
665
|
-
"sha256": "
|
|
665
|
+
"sha256": "0c76625e56687be734c75c6be80586e298d8cbb3c471707417708ee522afb5b8"
|
|
666
666
|
},
|
|
667
667
|
{
|
|
668
668
|
"path": "src/codex/catalog/account-models.ts",
|
|
@@ -690,7 +690,7 @@
|
|
|
690
690
|
},
|
|
691
691
|
{
|
|
692
692
|
"path": "src/codex/catalog/metadata.ts",
|
|
693
|
-
"sha256": "
|
|
693
|
+
"sha256": "66d9f4c603a77d34ab44b11b9b4397cc53c6a1e88a4bfb47cbc2a6b25ef20fbc"
|
|
694
694
|
},
|
|
695
695
|
{
|
|
696
696
|
"path": "src/codex/catalog/native-models.ts",
|
|
@@ -698,15 +698,15 @@
|
|
|
698
698
|
},
|
|
699
699
|
{
|
|
700
700
|
"path": "src/codex/catalog/parsing.ts",
|
|
701
|
-
"sha256": "
|
|
701
|
+
"sha256": "18f9a24b0770c52d203f8acc446e43e7fba9e42408cc29b612470acd1f0fee8b"
|
|
702
702
|
},
|
|
703
703
|
{
|
|
704
704
|
"path": "src/codex/catalog/provider-fetch.ts",
|
|
705
|
-
"sha256": "
|
|
705
|
+
"sha256": "cfd71e3d50149f8f04c4d272bb1dd42f1f26bbf276cabb13bb9f21fa5ebf7dc6"
|
|
706
706
|
},
|
|
707
707
|
{
|
|
708
708
|
"path": "src/codex/catalog/sync.ts",
|
|
709
|
-
"sha256": "
|
|
709
|
+
"sha256": "1d944106ef7674207ed73ae1c7c62befafdd6a4144f4436991af50fe2ada8344"
|
|
710
710
|
},
|
|
711
711
|
{
|
|
712
712
|
"path": "src/codex/codex-write-lock.ts",
|
|
@@ -1754,7 +1754,7 @@
|
|
|
1754
1754
|
},
|
|
1755
1755
|
{
|
|
1756
1756
|
"path": "src/lib/pinned-http.ts",
|
|
1757
|
-
"sha256": "
|
|
1757
|
+
"sha256": "ac1cd748e53b16109aaae86194fddac88424b508f00bb2e7c7090869f58c9b22"
|
|
1758
1758
|
},
|
|
1759
1759
|
{
|
|
1760
1760
|
"path": "src/lib/privacy.ts",
|
|
@@ -1854,7 +1854,7 @@
|
|
|
1854
1854
|
},
|
|
1855
1855
|
{
|
|
1856
1856
|
"path": "src/lib/windows-elevation.ts",
|
|
1857
|
-
"sha256": "
|
|
1857
|
+
"sha256": "0dc9864f87be8eed6c8dff80bec938f73fa2836c9f606f0e81c4c020494a8850"
|
|
1858
1858
|
},
|
|
1859
1859
|
{
|
|
1860
1860
|
"path": "src/lib/windows-secret-acl.ts",
|
|
@@ -2282,7 +2282,7 @@
|
|
|
2282
2282
|
},
|
|
2283
2283
|
{
|
|
2284
2284
|
"path": "src/server/auth-cors.ts",
|
|
2285
|
-
"sha256": "
|
|
2285
|
+
"sha256": "1a228cb899ba4b2d10598cae4eaf41de4c0dc27dc0b18b94943f65cf651f386f"
|
|
2286
2286
|
},
|
|
2287
2287
|
{
|
|
2288
2288
|
"path": "src/server/background-lifecycle.ts",
|
|
@@ -2298,7 +2298,7 @@
|
|
|
2298
2298
|
},
|
|
2299
2299
|
{
|
|
2300
2300
|
"path": "src/server/chat-native.ts",
|
|
2301
|
-
"sha256": "
|
|
2301
|
+
"sha256": "18ba244fd5ebd4a1b4a78a4b0aead236a4968a347d91e3130f73e2fc1c7f01f6"
|
|
2302
2302
|
},
|
|
2303
2303
|
{
|
|
2304
2304
|
"path": "src/server/claude-messages.ts",
|
|
@@ -2378,7 +2378,7 @@
|
|
|
2378
2378
|
},
|
|
2379
2379
|
{
|
|
2380
2380
|
"path": "src/server/management/config-routes.ts",
|
|
2381
|
-
"sha256": "
|
|
2381
|
+
"sha256": "90a3722a21edff368f0605300f2e4e2addcc3353ca5d2372d6df99e9ebe03fbd"
|
|
2382
2382
|
},
|
|
2383
2383
|
{
|
|
2384
2384
|
"path": "src/server/management/context.ts",
|
|
@@ -2650,7 +2650,7 @@
|
|
|
2650
2650
|
},
|
|
2651
2651
|
{
|
|
2652
2652
|
"path": "src/service.ts",
|
|
2653
|
-
"sha256": "
|
|
2653
|
+
"sha256": "2091110dc15b31cf2481875cf894e4b16f1dfc10b5f2c81f55d37ae929049fa1"
|
|
2654
2654
|
},
|
|
2655
2655
|
{
|
|
2656
2656
|
"path": "src/stall-timeout.ts",
|
|
@@ -2726,7 +2726,7 @@
|
|
|
2726
2726
|
},
|
|
2727
2727
|
{
|
|
2728
2728
|
"path": "src/types.ts",
|
|
2729
|
-
"sha256": "
|
|
2729
|
+
"sha256": "a2b31962f7d7f54f60b1cb9ed1066eeb5b0fb267cd0d3e4053eea6501b53046e"
|
|
2730
2730
|
},
|
|
2731
2731
|
{
|
|
2732
2732
|
"path": "src/update/badge.ts",
|
package/src/lib/pinned-http.ts
CHANGED
|
@@ -51,6 +51,7 @@ function pinnedHttpRequest(
|
|
|
51
51
|
&& options?.inactivityTimeoutMs === undefined;
|
|
52
52
|
const firstByteTimeoutMs = options?.firstByteTimeoutMs ?? legacyIdleTimeoutMs;
|
|
53
53
|
const inactivityTimeoutMs = options?.inactivityTimeoutMs ?? legacyIdleTimeoutMs;
|
|
54
|
+
const legacyFirstByteDisabled = usesLegacyIdleTimeout && legacyIdleTimeoutMs === 0;
|
|
54
55
|
const maxBytes = options?.maxBytes;
|
|
55
56
|
const headers = new Headers(options?.headers);
|
|
56
57
|
headers.set("host", parsed.host);
|
|
@@ -88,6 +89,7 @@ function pinnedHttpRequest(
|
|
|
88
89
|
};
|
|
89
90
|
const startFirstByteTimer = () => {
|
|
90
91
|
clearFirstByteTimer();
|
|
92
|
+
if (settled || legacyFirstByteDisabled) return;
|
|
91
93
|
firstByteTimer = setTimeout(
|
|
92
94
|
() => fail(new PinnedHttpError("first_byte_timeout", `${context} first byte timed out`)),
|
|
93
95
|
firstByteTimeoutMs,
|
|
@@ -194,8 +196,8 @@ function pinnedHttpRequest(
|
|
|
194
196
|
|
|
195
197
|
const requestFn = parsed.protocol === "https:" ? https.request : http.request;
|
|
196
198
|
req = requestFn(requestOptions, onResponse);
|
|
199
|
+
if (usesLegacyIdleTimeout) startFirstByteTimer();
|
|
197
200
|
const onAbort = () => fail(signal?.reason instanceof Error ? signal.reason : new Error("aborted"));
|
|
198
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
199
201
|
req.on("socket", (socket) => {
|
|
200
202
|
const connectedEvent = parsed.protocol === "https:" ? "secureConnect" : "connect";
|
|
201
203
|
if (!socket.connecting) {
|
|
@@ -233,6 +235,9 @@ function pinnedHttpRequest(
|
|
|
233
235
|
clearFirstByteTimer();
|
|
234
236
|
signal?.removeEventListener("abort", onAbort);
|
|
235
237
|
});
|
|
238
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
239
|
+
if (signal?.aborted && !settled) onAbort();
|
|
240
|
+
if (settled) return;
|
|
236
241
|
req.end(body);
|
|
237
242
|
});
|
|
238
243
|
}
|
|
@@ -262,4 +267,4 @@ export function pinnedHttpPost(
|
|
|
262
267
|
options?: PinnedHttpRequestOptions,
|
|
263
268
|
): Promise<Response> {
|
|
264
269
|
return pinnedHttpRequest(url, pinned, "POST", body, signal, options);
|
|
265
|
-
}
|
|
270
|
+
}
|
|
@@ -648,12 +648,12 @@ export function runWindowsElevatedScheduledTaskRegistration(
|
|
|
648
648
|
"-EncodedCommand",
|
|
649
649
|
encodedCommand,
|
|
650
650
|
]))}`,
|
|
651
|
-
" -Verb RunAs -WindowStyle Hidden -PassThru -Wait",
|
|
651
|
+
" -Verb RunAs -WindowStyle Hidden -PassThru -Wait;",
|
|
652
652
|
`if ($null -eq $p) { exit ${OCX_ELEVATED_UAC_CANCELLED} }`,
|
|
653
|
-
"$null = $p.Handle",
|
|
653
|
+
"$null = $p.Handle;",
|
|
654
654
|
`if ($null -eq $p.ExitCode) { exit ${OCX_ELEVATED_PROTOCOL_FAILED} }`,
|
|
655
655
|
"exit $p.ExitCode",
|
|
656
|
-
].join("
|
|
656
|
+
].join("");
|
|
657
657
|
|
|
658
658
|
return startPowerShellCommand(script).completion.then(result => result.exitCode);
|
|
659
659
|
}
|