mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-17 13:13:35 +08:00
fix: Align OpenAI Codex context windows
ChatGPT Official runs through Codex OAuth, so context accounting should follow the Codex model catalog and its effective context window instead of public API limits. This keeps GPT-5.5 at the same usable window shown by Codex while preserving GPT-5.4's larger Codex window. Constraint: Codex OAuth model metadata applies effective_context_window_percent to raw catalog windows Rejected: Use public API GPT-5.5 1.05M context | Codex app and OAuth runtime clamp this model to the smaller effective window Confidence: high Scope-risk: narrow Directive: Keep ChatGPT Official context values aligned to Codex model catalog behavior, not generic OpenAI API docs Tested: bun test src/services/openaiAuth/models.test.ts src/services/compact/autoCompact.test.ts src/server/__tests__/providers.test.ts Tested: bun run check:server Tested: git diff --check Not-tested: Manual desktop screenshot after rebuilding the app
This commit is contained in:
parent
e437199b81
commit
0c43b270b9
@ -355,6 +355,12 @@ describe('ProviderService', () => {
|
||||
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5.4')
|
||||
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex')
|
||||
expect(typeof env.CLAUDE_CODE_MODEL_CONTEXT_WINDOWS).toBe('string')
|
||||
expect(JSON.parse(env.CLAUDE_CODE_MODEL_CONTEXT_WINDOWS)).toEqual({
|
||||
'gpt-5.3-codex': 258_400,
|
||||
'gpt-5.4': 950_000,
|
||||
'gpt-5.5': 258_400,
|
||||
'gpt-5.4-mini': 258_400,
|
||||
})
|
||||
expect(env.ANTHROPIC_BASE_URL).toBeUndefined()
|
||||
expect(env.ANTHROPIC_API_KEY).toBeUndefined()
|
||||
expect(env.ANTHROPIC_AUTH_TOKEN).toBeUndefined()
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { OPENAI_CODEX_API_ENDPOINT } from '../../services/openaiAuth/client.js'
|
||||
import {
|
||||
OPENAI_CODEX_MODEL_CATALOG,
|
||||
OPENAI_DEFAULT_HAIKU_MODEL,
|
||||
OPENAI_DEFAULT_MAIN_MODEL,
|
||||
OPENAI_DEFAULT_SONNET_MODEL,
|
||||
getOpenAIContextWindowForModel,
|
||||
getOpenAICodexContextWindowForModel,
|
||||
} from '../../services/openaiAuth/models.js'
|
||||
import { MODEL_CONTEXT_WINDOWS_ENV_KEY } from '../../utils/model/modelContextWindows.js'
|
||||
import { getHahaOpenAIOAuthFilePath } from './hahaOpenAIOAuthService.js'
|
||||
@ -28,8 +29,10 @@ const openAIModels: SavedProvider['models'] = {
|
||||
}
|
||||
|
||||
const modelContextWindows = Object.fromEntries(
|
||||
Object.values(openAIModels)
|
||||
.map((model) => [model, getOpenAIContextWindowForModel(model)] as const)
|
||||
OPENAI_CODEX_MODEL_CATALOG.map(
|
||||
({ value }) =>
|
||||
[value, getOpenAICodexContextWindowForModel(value)] as const,
|
||||
)
|
||||
.filter((entry): entry is readonly [string, number] => entry[1] !== null),
|
||||
)
|
||||
|
||||
|
||||
@ -36,6 +36,13 @@ describe('model context window resolution', () => {
|
||||
expect(getContextWindowForModel('glm-4.5-air')).toBe(128_000)
|
||||
})
|
||||
|
||||
test('uses Codex OAuth effective context windows for OpenAI GPT models', () => {
|
||||
expect(getContextWindowForModel('gpt-5.5')).toBe(258_400)
|
||||
expect(getContextWindowForModel('gpt-5.4')).toBe(950_000)
|
||||
expect(getContextWindowForModel('gpt-5.4-mini')).toBe(258_400)
|
||||
expect(getContextWindowForModel('gpt-5.3-codex-spark')).toBe(121_600)
|
||||
})
|
||||
|
||||
test('uses per-model provider overrides before built-in defaults', () => {
|
||||
process.env[MODEL_CONTEXT_WINDOWS_ENV_KEY] = JSON.stringify({
|
||||
'deepseek-v4-pro': 500_000,
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { describe, expect, test } from 'bun:test'
|
||||
import {
|
||||
OPENAI_CODEX_LARGE_EFFECTIVE_CONTEXT_WINDOW,
|
||||
OPENAI_CODEX_SPARK_EFFECTIVE_CONTEXT_WINDOW,
|
||||
OPENAI_CODEX_STANDARD_EFFECTIVE_CONTEXT_WINDOW,
|
||||
OPENAI_DEFAULT_MAIN_MODEL,
|
||||
OPENAI_GPT5_LARGE_CONTEXT_WINDOW,
|
||||
OPENAI_GPT5_STANDARD_CONTEXT_WINDOW,
|
||||
getOpenAIContextWindowForModel,
|
||||
getOpenAICodexContextWindowForModel,
|
||||
isOpenAIResponsesModel,
|
||||
resolveOpenAICodexModel,
|
||||
} from './models.js'
|
||||
@ -22,21 +23,21 @@ describe('openai auth model resolution', () => {
|
||||
expect(resolveOpenAICodexModel('opus')).toBe(OPENAI_DEFAULT_MAIN_MODEL)
|
||||
})
|
||||
|
||||
test('maps large-context GPT-5 models to a 1.05M context window', () => {
|
||||
expect(getOpenAIContextWindowForModel('gpt-5.5')).toBe(
|
||||
OPENAI_GPT5_LARGE_CONTEXT_WINDOW,
|
||||
test('maps Codex OAuth GPT models to effective Codex context windows', () => {
|
||||
expect(getOpenAICodexContextWindowForModel('gpt-5.5')).toBe(
|
||||
OPENAI_CODEX_STANDARD_EFFECTIVE_CONTEXT_WINDOW,
|
||||
)
|
||||
expect(getOpenAIContextWindowForModel('gpt-5.4')).toBe(
|
||||
OPENAI_GPT5_LARGE_CONTEXT_WINDOW,
|
||||
expect(getOpenAICodexContextWindowForModel('gpt-5.4')).toBe(
|
||||
OPENAI_CODEX_LARGE_EFFECTIVE_CONTEXT_WINDOW,
|
||||
)
|
||||
})
|
||||
|
||||
test('maps standard GPT-5 models to a 400k context window', () => {
|
||||
expect(getOpenAIContextWindowForModel('gpt-5.3-codex')).toBe(
|
||||
OPENAI_GPT5_STANDARD_CONTEXT_WINDOW,
|
||||
expect(getOpenAICodexContextWindowForModel('gpt-5.3-codex')).toBe(
|
||||
OPENAI_CODEX_STANDARD_EFFECTIVE_CONTEXT_WINDOW,
|
||||
)
|
||||
expect(getOpenAIContextWindowForModel('gpt-5.4-mini')).toBe(
|
||||
OPENAI_GPT5_STANDARD_CONTEXT_WINDOW,
|
||||
expect(getOpenAICodexContextWindowForModel('gpt-5.4-mini')).toBe(
|
||||
OPENAI_CODEX_STANDARD_EFFECTIVE_CONTEXT_WINDOW,
|
||||
)
|
||||
expect(getOpenAICodexContextWindowForModel('gpt-5.3-codex-spark')).toBe(
|
||||
OPENAI_CODEX_SPARK_EFFECTIVE_CONTEXT_WINDOW,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -1,8 +1,22 @@
|
||||
export const OPENAI_DEFAULT_MAIN_MODEL = 'gpt-5.3-codex'
|
||||
export const OPENAI_DEFAULT_SONNET_MODEL = 'gpt-5.4'
|
||||
export const OPENAI_DEFAULT_HAIKU_MODEL = 'gpt-5.4-mini'
|
||||
export const OPENAI_GPT5_STANDARD_CONTEXT_WINDOW = 400_000
|
||||
export const OPENAI_GPT5_LARGE_CONTEXT_WINDOW = 1_050_000
|
||||
export const OPENAI_CODEX_EFFECTIVE_CONTEXT_PERCENT = 95
|
||||
export const OPENAI_CODEX_STANDARD_CONTEXT_WINDOW = 272_000
|
||||
export const OPENAI_CODEX_LARGE_CONTEXT_WINDOW = 1_000_000
|
||||
export const OPENAI_CODEX_SPARK_CONTEXT_WINDOW = 128_000
|
||||
export const OPENAI_CODEX_STANDARD_EFFECTIVE_CONTEXT_WINDOW = Math.floor(
|
||||
(OPENAI_CODEX_STANDARD_CONTEXT_WINDOW * OPENAI_CODEX_EFFECTIVE_CONTEXT_PERCENT) /
|
||||
100,
|
||||
)
|
||||
export const OPENAI_CODEX_LARGE_EFFECTIVE_CONTEXT_WINDOW = Math.floor(
|
||||
(OPENAI_CODEX_LARGE_CONTEXT_WINDOW * OPENAI_CODEX_EFFECTIVE_CONTEXT_PERCENT) /
|
||||
100,
|
||||
)
|
||||
export const OPENAI_CODEX_SPARK_EFFECTIVE_CONTEXT_WINDOW = Math.floor(
|
||||
(OPENAI_CODEX_SPARK_CONTEXT_WINDOW * OPENAI_CODEX_EFFECTIVE_CONTEXT_PERCENT) /
|
||||
100,
|
||||
)
|
||||
|
||||
export type OpenAIModelCatalogEntry = {
|
||||
value: string
|
||||
@ -80,6 +94,8 @@ export function getOpenAIModelDisplayName(model: string): string | null {
|
||||
switch (model.trim().toLowerCase()) {
|
||||
case 'gpt-5.3-codex':
|
||||
return 'GPT-5.3 Codex'
|
||||
case 'gpt-5.3-codex-spark':
|
||||
return 'GPT-5.3 Codex Spark'
|
||||
case 'gpt-5.5':
|
||||
return 'GPT-5.5'
|
||||
case 'gpt-5.4':
|
||||
@ -101,21 +117,28 @@ export function getOpenAIModelDisplayName(model: string): string | null {
|
||||
}
|
||||
}
|
||||
|
||||
export function getOpenAIContextWindowForModel(model: string): number | null {
|
||||
export function getOpenAICodexContextWindowForModel(
|
||||
model: string,
|
||||
): number | null {
|
||||
const normalized = model.trim().toLowerCase()
|
||||
|
||||
// Current OpenAI model docs split GPT-5-family context windows into
|
||||
// standard 400k models and larger 1.05M models.
|
||||
// Codex OAuth follows the Codex app model catalog, not the public API model
|
||||
// context limits. The catalog applies effective_context_window_percent=95,
|
||||
// and the runtime /context display reports this effective window.
|
||||
if (
|
||||
normalized === 'gpt-5.5' ||
|
||||
normalized === 'gpt-5.5-pro' ||
|
||||
normalized === 'gpt-5.4' ||
|
||||
normalized === 'gpt-5.4-pro'
|
||||
) {
|
||||
return OPENAI_GPT5_LARGE_CONTEXT_WINDOW
|
||||
return OPENAI_CODEX_LARGE_EFFECTIVE_CONTEXT_WINDOW
|
||||
}
|
||||
|
||||
if (normalized === 'gpt-5.3-codex-spark') {
|
||||
return OPENAI_CODEX_SPARK_EFFECTIVE_CONTEXT_WINDOW
|
||||
}
|
||||
|
||||
if (
|
||||
normalized === 'gpt-5.5' ||
|
||||
normalized === 'gpt-5.5-pro' ||
|
||||
normalized === 'gpt-5.4-mini' ||
|
||||
normalized === 'gpt-5.4-nano' ||
|
||||
normalized === 'gpt-5.3-codex' ||
|
||||
@ -130,8 +153,11 @@ export function getOpenAIContextWindowForModel(model: string): number | null {
|
||||
normalized === 'gpt-5-mini' ||
|
||||
normalized === 'gpt-5-nano'
|
||||
) {
|
||||
return OPENAI_GPT5_STANDARD_CONTEXT_WINDOW
|
||||
return OPENAI_CODEX_STANDARD_EFFECTIVE_CONTEXT_WINDOW
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export const getOpenAIContextWindowForModel =
|
||||
getOpenAICodexContextWindowForModel
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// biome-ignore-all assist/source/organizeImports: ANT-ONLY import markers must not be reordered
|
||||
import { CONTEXT_1M_BETA_HEADER } from '../constants/betas.js'
|
||||
import { getOpenAIContextWindowForModel } from '../services/openaiAuth/models.js'
|
||||
import { getOpenAICodexContextWindowForModel } from '../services/openaiAuth/models.js'
|
||||
import { getGlobalConfig } from './config.js'
|
||||
import { isEnvTruthy } from './envUtils.js'
|
||||
import { getCanonicalName } from './model/model.js'
|
||||
@ -84,7 +84,7 @@ export function getContextWindowForModel(
|
||||
return configuredWindow
|
||||
}
|
||||
|
||||
const openAIContextWindow = getOpenAIContextWindowForModel(model)
|
||||
const openAIContextWindow = getOpenAICodexContextWindowForModel(model)
|
||||
if (openAIContextWindow) {
|
||||
return openAIContextWindow
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user