mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 15:04:52 +00:00
Merge PR #536: align openai-codex models list and context window size to codex defaults
closes #536
This commit is contained in:
commit
faa26ffbf9
7 changed files with 81 additions and 413 deletions
|
|
@ -2,6 +2,14 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Breaking Changes
|
||||||
|
|
||||||
|
- Removed OpenAI Codex model aliases (`gpt-5`, `gpt-5-mini`, `gpt-5-nano`, `codex-mini-latest`, `gpt-5-codex`, `gpt-5.1-codex`, `gpt-5.1-chat-latest`). Use canonical model IDs: `gpt-5.1`, `gpt-5.1-codex-max`, `gpt-5.1-codex-mini`, `gpt-5.2`, `gpt-5.2-codex`. ([#536](https://github.com/badlogic/pi-mono/pull/536) by [@ghoulr](https://github.com/ghoulr))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed OpenAI Codex context window from 400,000 to 272,000 tokens to match Codex CLI defaults and prevent 400 errors. ([#536](https://github.com/badlogic/pi-mono/pull/536) by [@ghoulr](https://github.com/ghoulr))
|
||||||
|
|
||||||
## [0.37.8] - 2026-01-07
|
## [0.37.8] - 2026-01-07
|
||||||
|
|
||||||
## [0.37.7] - 2026-01-07
|
## [0.37.7] - 2026-01-07
|
||||||
|
|
|
||||||
|
|
@ -443,37 +443,15 @@ async function generateModels() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenAI Codex (ChatGPT OAuth) models
|
// OpenAI Codex (ChatGPT OAuth) models
|
||||||
|
// NOTE: These are not fetched from models.dev; we keep a small, explicit list to avoid aliases.
|
||||||
|
// Context window is based on observed server limits (400s above ~272k), not marketing numbers.
|
||||||
const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
|
const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
|
||||||
const CODEX_CONTEXT = 400000;
|
const CODEX_CONTEXT = 272000;
|
||||||
const CODEX_MAX_TOKENS = 128000;
|
const CODEX_MAX_TOKENS = 128000;
|
||||||
const codexModels: Model<"openai-codex-responses">[] = [
|
const codexModels: Model<"openai-codex-responses">[] = [
|
||||||
{
|
{
|
||||||
id: "gpt-5.2-codex",
|
id: "gpt-5.1",
|
||||||
name: "GPT-5.2 Codex",
|
name: "GPT-5.1",
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2",
|
|
||||||
name: "GPT-5.2",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-max",
|
|
||||||
name: "GPT-5.1 Codex Max",
|
|
||||||
api: "openai-codex-responses",
|
api: "openai-codex-responses",
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
|
|
@ -484,8 +462,8 @@ async function generateModels() {
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
maxTokens: CODEX_MAX_TOKENS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "gpt-5.1-codex",
|
id: "gpt-5.1-codex-max",
|
||||||
name: "GPT-5.1 Codex",
|
name: "GPT-5.1 Codex Max",
|
||||||
api: "openai-codex-responses",
|
api: "openai-codex-responses",
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
|
|
@ -508,98 +486,26 @@ async function generateModels() {
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
maxTokens: CODEX_MAX_TOKENS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "codex-mini-latest",
|
id: "gpt-5.2",
|
||||||
name: "Codex Mini Latest",
|
name: "GPT-5.2",
|
||||||
api: "openai-codex-responses",
|
api: "openai-codex-responses",
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 1.5, output: 6, cacheRead: 0.375, cacheWrite: 0 },
|
cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
maxTokens: CODEX_MAX_TOKENS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "gpt-5-codex-mini",
|
id: "gpt-5.2-codex",
|
||||||
name: "gpt-5-codex-mini",
|
name: "GPT-5.2 Codex",
|
||||||
api: "openai-codex-responses",
|
api: "openai-codex-responses",
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 },
|
cost: { input: 1.75, output: 14, cacheRead: 0.175, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5-codex",
|
|
||||||
name: "gpt-5-codex",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1",
|
|
||||||
name: "GPT-5.1",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-chat-latest",
|
|
||||||
name: "gpt-5.1-chat-latest",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5",
|
|
||||||
name: "gpt-5",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5-mini",
|
|
||||||
name: "gpt-5-mini",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5-nano",
|
|
||||||
name: "gpt-5-nano",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0.05, output: 0.4, cacheRead: 0.005, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
maxTokens: CODEX_MAX_TOKENS,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -415,6 +415,23 @@ export const MODELS = {
|
||||||
contextWindow: 131072,
|
contextWindow: 131072,
|
||||||
maxTokens: 40960,
|
maxTokens: 40960,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
|
"zai-glm-4.7": {
|
||||||
|
id: "zai-glm-4.7",
|
||||||
|
name: "Z.AI GLM-4.7",
|
||||||
|
api: "openai-completions",
|
||||||
|
provider: "cerebras",
|
||||||
|
baseUrl: "https://api.cerebras.ai/v1",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
cost: {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 131072,
|
||||||
|
maxTokens: 40000,
|
||||||
|
} satisfies Model<"openai-completions">,
|
||||||
},
|
},
|
||||||
"github-copilot": {
|
"github-copilot": {
|
||||||
"claude-haiku-4.5": {
|
"claude-haiku-4.5": {
|
||||||
|
|
@ -2774,108 +2791,6 @@ export const MODELS = {
|
||||||
} satisfies Model<"openai-responses">,
|
} satisfies Model<"openai-responses">,
|
||||||
},
|
},
|
||||||
"openai-codex": {
|
"openai-codex": {
|
||||||
"codex-mini-latest": {
|
|
||||||
id: "codex-mini-latest",
|
|
||||||
name: "Codex Mini Latest",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.5,
|
|
||||||
output: 6,
|
|
||||||
cacheRead: 0.375,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5": {
|
|
||||||
id: "gpt-5",
|
|
||||||
name: "gpt-5",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.25,
|
|
||||||
output: 10,
|
|
||||||
cacheRead: 0.125,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5-codex": {
|
|
||||||
id: "gpt-5-codex",
|
|
||||||
name: "gpt-5-codex",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.25,
|
|
||||||
output: 10,
|
|
||||||
cacheRead: 0.125,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5-codex-mini": {
|
|
||||||
id: "gpt-5-codex-mini",
|
|
||||||
name: "gpt-5-codex-mini",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0.25,
|
|
||||||
output: 2,
|
|
||||||
cacheRead: 0.025,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5-mini": {
|
|
||||||
id: "gpt-5-mini",
|
|
||||||
name: "gpt-5-mini",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0.25,
|
|
||||||
output: 2,
|
|
||||||
cacheRead: 0.025,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5-nano": {
|
|
||||||
id: "gpt-5-nano",
|
|
||||||
name: "gpt-5-nano",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0.05,
|
|
||||||
output: 0.4,
|
|
||||||
cacheRead: 0.005,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1": {
|
"gpt-5.1": {
|
||||||
id: "gpt-5.1",
|
id: "gpt-5.1",
|
||||||
name: "GPT-5.1",
|
name: "GPT-5.1",
|
||||||
|
|
@ -2890,41 +2805,7 @@ export const MODELS = {
|
||||||
cacheRead: 0.125,
|
cacheRead: 0.125,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 400000,
|
contextWindow: 272000,
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-chat-latest": {
|
|
||||||
id: "gpt-5.1-chat-latest",
|
|
||||||
name: "gpt-5.1-chat-latest",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.25,
|
|
||||||
output: 10,
|
|
||||||
cacheRead: 0.125,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex": {
|
|
||||||
id: "gpt-5.1-codex",
|
|
||||||
name: "GPT-5.1 Codex",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 1.25,
|
|
||||||
output: 10,
|
|
||||||
cacheRead: 0.125,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
maxTokens: 128000,
|
||||||
} satisfies Model<"openai-codex-responses">,
|
} satisfies Model<"openai-codex-responses">,
|
||||||
"gpt-5.1-codex-max": {
|
"gpt-5.1-codex-max": {
|
||||||
|
|
@ -2941,7 +2822,7 @@ export const MODELS = {
|
||||||
cacheRead: 0.125,
|
cacheRead: 0.125,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 400000,
|
contextWindow: 272000,
|
||||||
maxTokens: 128000,
|
maxTokens: 128000,
|
||||||
} satisfies Model<"openai-codex-responses">,
|
} satisfies Model<"openai-codex-responses">,
|
||||||
"gpt-5.1-codex-mini": {
|
"gpt-5.1-codex-mini": {
|
||||||
|
|
@ -2958,7 +2839,7 @@ export const MODELS = {
|
||||||
cacheRead: 0.025,
|
cacheRead: 0.025,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 400000,
|
contextWindow: 272000,
|
||||||
maxTokens: 128000,
|
maxTokens: 128000,
|
||||||
} satisfies Model<"openai-codex-responses">,
|
} satisfies Model<"openai-codex-responses">,
|
||||||
"gpt-5.2": {
|
"gpt-5.2": {
|
||||||
|
|
@ -2975,7 +2856,7 @@ export const MODELS = {
|
||||||
cacheRead: 0.175,
|
cacheRead: 0.175,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 400000,
|
contextWindow: 272000,
|
||||||
maxTokens: 128000,
|
maxTokens: 128000,
|
||||||
} satisfies Model<"openai-codex-responses">,
|
} satisfies Model<"openai-codex-responses">,
|
||||||
"gpt-5.2-codex": {
|
"gpt-5.2-codex": {
|
||||||
|
|
@ -2992,7 +2873,7 @@ export const MODELS = {
|
||||||
cacheRead: 0.175,
|
cacheRead: 0.175,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 400000,
|
contextWindow: 272000,
|
||||||
maxTokens: 128000,
|
maxTokens: 128000,
|
||||||
} satisfies Model<"openai-codex-responses">,
|
} satisfies Model<"openai-codex-responses">,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,6 @@ import { buildCodexPiBridge } from "./openai-codex/prompts/pi-codex-bridge.js";
|
||||||
import { buildCodexSystemPrompt } from "./openai-codex/prompts/system-prompt.js";
|
import { buildCodexSystemPrompt } from "./openai-codex/prompts/system-prompt.js";
|
||||||
import {
|
import {
|
||||||
type CodexRequestOptions,
|
type CodexRequestOptions,
|
||||||
normalizeModel,
|
|
||||||
type RequestBody,
|
type RequestBody,
|
||||||
transformRequestBody,
|
transformRequestBody,
|
||||||
} from "./openai-codex/request-transformer.js";
|
} from "./openai-codex/request-transformer.js";
|
||||||
|
|
@ -111,8 +110,7 @@ export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses"
|
||||||
params.tools = convertTools(context.tools);
|
params.tools = convertTools(context.tools);
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedModel = normalizeModel(params.model);
|
const codexInstructions = await getCodexInstructions(params.model);
|
||||||
const codexInstructions = await getCodexInstructions(normalizedModel);
|
|
||||||
const bridgeText = buildCodexPiBridge(context.tools);
|
const bridgeText = buildCodexPiBridge(context.tools);
|
||||||
const systemPrompt = buildCodexSystemPrompt({
|
const systemPrompt = buildCodexSystemPrompt({
|
||||||
codexInstructions,
|
codexInstructions,
|
||||||
|
|
@ -120,7 +118,6 @@ export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses"
|
||||||
userSystemPrompt: context.systemPrompt,
|
userSystemPrompt: context.systemPrompt,
|
||||||
});
|
});
|
||||||
|
|
||||||
params.model = normalizedModel;
|
|
||||||
params.instructions = systemPrompt.instructions;
|
params.instructions = systemPrompt.instructions;
|
||||||
|
|
||||||
const codexOptions: CodexRequestOptions = {
|
const codexOptions: CodexRequestOptions = {
|
||||||
|
|
|
||||||
|
|
@ -44,17 +44,17 @@ export type CacheMetadata = {
|
||||||
url: string;
|
url: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getModelFamily(normalizedModel: string): ModelFamily {
|
export function getModelFamily(model: string): ModelFamily {
|
||||||
if (normalizedModel.includes("gpt-5.2-codex") || normalizedModel.includes("gpt 5.2 codex")) {
|
if (model.includes("gpt-5.2-codex") || model.includes("gpt 5.2 codex")) {
|
||||||
return "gpt-5.2-codex";
|
return "gpt-5.2-codex";
|
||||||
}
|
}
|
||||||
if (normalizedModel.includes("codex-max")) {
|
if (model.includes("codex-max")) {
|
||||||
return "codex-max";
|
return "codex-max";
|
||||||
}
|
}
|
||||||
if (normalizedModel.includes("codex") || normalizedModel.startsWith("codex-")) {
|
if (model.includes("codex") || model.startsWith("codex-")) {
|
||||||
return "codex";
|
return "codex";
|
||||||
}
|
}
|
||||||
if (normalizedModel.includes("gpt-5.2")) {
|
if (model.includes("gpt-5.2")) {
|
||||||
return "gpt-5.2";
|
return "gpt-5.2";
|
||||||
}
|
}
|
||||||
return "gpt-5.1";
|
return "gpt-5.1";
|
||||||
|
|
@ -96,8 +96,8 @@ async function getLatestReleaseTag(): Promise<string> {
|
||||||
throw new Error("Failed to determine latest release tag from GitHub");
|
throw new Error("Failed to determine latest release tag from GitHub");
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCodexInstructions(normalizedModel = "gpt-5.1-codex"): Promise<string> {
|
export async function getCodexInstructions(model = "gpt-5.1-codex"): Promise<string> {
|
||||||
const modelFamily = getModelFamily(normalizedModel);
|
const modelFamily = getModelFamily(model);
|
||||||
const promptFile = PROMPT_FILES[modelFamily];
|
const promptFile = PROMPT_FILES[modelFamily];
|
||||||
const cacheDir = getCacheDir();
|
const cacheDir = getCacheDir();
|
||||||
const cacheFile = join(cacheDir, CACHE_FILES[modelFamily]);
|
const cacheFile = join(cacheDir, CACHE_FILES[modelFamily]);
|
||||||
|
|
|
||||||
|
|
@ -41,155 +41,26 @@ export interface RequestBody {
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MODEL_MAP: Record<string, string> = {
|
function clampReasoningEffort(model: string, effort: ReasoningConfig["effort"]): ReasoningConfig["effort"] {
|
||||||
"gpt-5.1-codex": "gpt-5.1-codex",
|
// Codex backend expects exact model IDs. Do not normalize model names here.
|
||||||
"gpt-5.1-codex-low": "gpt-5.1-codex",
|
|
||||||
"gpt-5.1-codex-medium": "gpt-5.1-codex",
|
|
||||||
"gpt-5.1-codex-high": "gpt-5.1-codex",
|
|
||||||
"gpt-5.1-codex-max": "gpt-5.1-codex-max",
|
|
||||||
"gpt-5.1-codex-max-low": "gpt-5.1-codex-max",
|
|
||||||
"gpt-5.1-codex-max-medium": "gpt-5.1-codex-max",
|
|
||||||
"gpt-5.1-codex-max-high": "gpt-5.1-codex-max",
|
|
||||||
"gpt-5.1-codex-max-xhigh": "gpt-5.1-codex-max",
|
|
||||||
"gpt-5.2": "gpt-5.2",
|
|
||||||
"gpt-5.2-none": "gpt-5.2",
|
|
||||||
"gpt-5.2-low": "gpt-5.2",
|
|
||||||
"gpt-5.2-medium": "gpt-5.2",
|
|
||||||
"gpt-5.2-high": "gpt-5.2",
|
|
||||||
"gpt-5.2-xhigh": "gpt-5.2",
|
|
||||||
"gpt-5.2-codex": "gpt-5.2-codex",
|
|
||||||
"gpt-5.2-codex-low": "gpt-5.2-codex",
|
|
||||||
"gpt-5.2-codex-medium": "gpt-5.2-codex",
|
|
||||||
"gpt-5.2-codex-high": "gpt-5.2-codex",
|
|
||||||
"gpt-5.2-codex-xhigh": "gpt-5.2-codex",
|
|
||||||
"gpt-5.1-codex-mini": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5.1-codex-mini-medium": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5.1-codex-mini-high": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5.1": "gpt-5.1",
|
|
||||||
"gpt-5.1-none": "gpt-5.1",
|
|
||||||
"gpt-5.1-low": "gpt-5.1",
|
|
||||||
"gpt-5.1-medium": "gpt-5.1",
|
|
||||||
"gpt-5.1-high": "gpt-5.1",
|
|
||||||
"gpt-5.1-chat-latest": "gpt-5.1",
|
|
||||||
"gpt-5-codex": "gpt-5.1-codex",
|
|
||||||
"codex-mini-latest": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5-codex-mini": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5-codex-mini-medium": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5-codex-mini-high": "gpt-5.1-codex-mini",
|
|
||||||
"gpt-5": "gpt-5.1",
|
|
||||||
"gpt-5-mini": "gpt-5.1",
|
|
||||||
"gpt-5-nano": "gpt-5.1",
|
|
||||||
};
|
|
||||||
|
|
||||||
function getNormalizedModel(modelId: string): string | undefined {
|
|
||||||
if (MODEL_MAP[modelId]) return MODEL_MAP[modelId];
|
|
||||||
const lowerModelId = modelId.toLowerCase();
|
|
||||||
const match = Object.keys(MODEL_MAP).find((key) => key.toLowerCase() === lowerModelId);
|
|
||||||
return match ? MODEL_MAP[match] : undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function normalizeModel(model: string | undefined): string {
|
|
||||||
if (!model) return "gpt-5.1";
|
|
||||||
|
|
||||||
const modelId = model.includes("/") ? model.split("/").pop()! : model;
|
const modelId = model.includes("/") ? model.split("/").pop()! : model;
|
||||||
const mappedModel = getNormalizedModel(modelId);
|
|
||||||
if (mappedModel) return mappedModel;
|
|
||||||
|
|
||||||
const normalized = modelId.toLowerCase();
|
// gpt-5.1 does not support xhigh.
|
||||||
|
if (modelId === "gpt-5.1" && effort === "xhigh") {
|
||||||
if (normalized.includes("gpt-5.2-codex") || normalized.includes("gpt 5.2 codex")) {
|
return "high";
|
||||||
return "gpt-5.2-codex";
|
|
||||||
}
|
|
||||||
if (normalized.includes("gpt-5.2") || normalized.includes("gpt 5.2")) {
|
|
||||||
return "gpt-5.2";
|
|
||||||
}
|
|
||||||
if (normalized.includes("gpt-5.1-codex-max") || normalized.includes("gpt 5.1 codex max")) {
|
|
||||||
return "gpt-5.1-codex-max";
|
|
||||||
}
|
|
||||||
if (normalized.includes("gpt-5.1-codex-mini") || normalized.includes("gpt 5.1 codex mini")) {
|
|
||||||
return "gpt-5.1-codex-mini";
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
normalized.includes("codex-mini-latest") ||
|
|
||||||
normalized.includes("gpt-5-codex-mini") ||
|
|
||||||
normalized.includes("gpt 5 codex mini")
|
|
||||||
) {
|
|
||||||
return "codex-mini-latest";
|
|
||||||
}
|
|
||||||
if (normalized.includes("gpt-5.1-codex") || normalized.includes("gpt 5.1 codex")) {
|
|
||||||
return "gpt-5.1-codex";
|
|
||||||
}
|
|
||||||
if (normalized.includes("gpt-5.1") || normalized.includes("gpt 5.1")) {
|
|
||||||
return "gpt-5.1";
|
|
||||||
}
|
|
||||||
if (normalized.includes("codex")) {
|
|
||||||
return "gpt-5.1-codex";
|
|
||||||
}
|
|
||||||
if (normalized.includes("gpt-5") || normalized.includes("gpt 5")) {
|
|
||||||
return "gpt-5.1";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "gpt-5.1";
|
// gpt-5.1-codex-mini only supports medium/high.
|
||||||
|
if (modelId === "gpt-5.1-codex-mini") {
|
||||||
|
return effort === "high" || effort === "xhigh" ? "high" : "medium";
|
||||||
|
}
|
||||||
|
|
||||||
|
return effort;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReasoningConfig(modelName: string | undefined, options: CodexRequestOptions = {}): ReasoningConfig {
|
function getReasoningConfig(model: string, options: CodexRequestOptions): ReasoningConfig {
|
||||||
const normalizedName = modelName?.toLowerCase() ?? "";
|
|
||||||
|
|
||||||
const isGpt52Codex = normalizedName.includes("gpt-5.2-codex") || normalizedName.includes("gpt 5.2 codex");
|
|
||||||
const isGpt52General = (normalizedName.includes("gpt-5.2") || normalizedName.includes("gpt 5.2")) && !isGpt52Codex;
|
|
||||||
const isCodexMax = normalizedName.includes("codex-max") || normalizedName.includes("codex max");
|
|
||||||
const isCodexMini =
|
|
||||||
normalizedName.includes("codex-mini") ||
|
|
||||||
normalizedName.includes("codex mini") ||
|
|
||||||
normalizedName.includes("codex_mini") ||
|
|
||||||
normalizedName.includes("codex-mini-latest");
|
|
||||||
const isCodex = normalizedName.includes("codex") && !isCodexMini;
|
|
||||||
const isLightweight = !isCodexMini && (normalizedName.includes("nano") || normalizedName.includes("mini"));
|
|
||||||
const isGpt51General =
|
|
||||||
(normalizedName.includes("gpt-5.1") || normalizedName.includes("gpt 5.1")) &&
|
|
||||||
!isCodex &&
|
|
||||||
!isCodexMax &&
|
|
||||||
!isCodexMini;
|
|
||||||
|
|
||||||
const supportsXhigh = isGpt52General || isGpt52Codex || isCodexMax;
|
|
||||||
const supportsNone = isGpt52General || isGpt51General;
|
|
||||||
|
|
||||||
const defaultEffort: ReasoningConfig["effort"] = isCodexMini
|
|
||||||
? "medium"
|
|
||||||
: supportsXhigh
|
|
||||||
? "high"
|
|
||||||
: isLightweight
|
|
||||||
? "minimal"
|
|
||||||
: "medium";
|
|
||||||
|
|
||||||
let effort = options.reasoningEffort || defaultEffort;
|
|
||||||
|
|
||||||
if (isCodexMini) {
|
|
||||||
if (effort === "minimal" || effort === "low" || effort === "none") {
|
|
||||||
effort = "medium";
|
|
||||||
}
|
|
||||||
if (effort === "xhigh") {
|
|
||||||
effort = "high";
|
|
||||||
}
|
|
||||||
if (effort !== "high" && effort !== "medium") {
|
|
||||||
effort = "medium";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportsXhigh && effort === "xhigh") {
|
|
||||||
effort = "high";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportsNone && effort === "none") {
|
|
||||||
effort = "low";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCodex && effort === "minimal") {
|
|
||||||
effort = "low";
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
effort,
|
effort: clampReasoningEffort(model, options.reasoningEffort as ReasoningConfig["effort"]),
|
||||||
summary: options.reasoningSummary ?? "auto",
|
summary: options.reasoningSummary ?? "auto",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -213,9 +84,6 @@ export async function transformRequestBody(
|
||||||
options: CodexRequestOptions = {},
|
options: CodexRequestOptions = {},
|
||||||
prompt?: { instructions: string; developerMessages: string[] },
|
prompt?: { instructions: string; developerMessages: string[] },
|
||||||
): Promise<RequestBody> {
|
): Promise<RequestBody> {
|
||||||
const normalizedModel = normalizeModel(body.model);
|
|
||||||
|
|
||||||
body.model = normalizedModel;
|
|
||||||
body.store = false;
|
body.store = false;
|
||||||
body.stream = true;
|
body.stream = true;
|
||||||
|
|
||||||
|
|
@ -270,7 +138,7 @@ export async function transformRequestBody(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.reasoningEffort !== undefined) {
|
if (options.reasoningEffort !== undefined) {
|
||||||
const reasoningConfig = getReasoningConfig(normalizedModel, options);
|
const reasoningConfig = getReasoningConfig(body.model, options);
|
||||||
body.reasoning = {
|
body.reasoning = {
|
||||||
...body.reasoning,
|
...body.reasoning,
|
||||||
...reasoningConfig,
|
...reasoningConfig,
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,7 @@ import { tmpdir } from "node:os";
|
||||||
import { join } from "node:path";
|
import { join } from "node:path";
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
import { getCodexInstructions } from "../src/providers/openai-codex/prompts/codex.js";
|
import { getCodexInstructions } from "../src/providers/openai-codex/prompts/codex.js";
|
||||||
import {
|
import { type RequestBody, transformRequestBody } from "../src/providers/openai-codex/request-transformer.js";
|
||||||
normalizeModel,
|
|
||||||
type RequestBody,
|
|
||||||
transformRequestBody,
|
|
||||||
} from "../src/providers/openai-codex/request-transformer.js";
|
|
||||||
import { parseCodexError } from "../src/providers/openai-codex/response-handler.js";
|
import { parseCodexError } from "../src/providers/openai-codex/response-handler.js";
|
||||||
|
|
||||||
const DEFAULT_PROMPT_PREFIX =
|
const DEFAULT_PROMPT_PREFIX =
|
||||||
|
|
@ -59,9 +55,21 @@ describe("openai-codex request transformer", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("openai-codex model normalization", () => {
|
describe("openai-codex reasoning effort clamping", () => {
|
||||||
it("maps space-separated codex-mini names to codex-mini-latest", () => {
|
it("clamps gpt-5.1 xhigh to high", async () => {
|
||||||
expect(normalizeModel("gpt 5 codex mini")).toBe("codex-mini-latest");
|
const body: RequestBody = { model: "gpt-5.1", input: [] };
|
||||||
|
const transformed = await transformRequestBody(body, { reasoningEffort: "xhigh" });
|
||||||
|
expect(transformed.reasoning?.effort).toBe("high");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("clamps gpt-5.1-codex-mini to medium/high only", async () => {
|
||||||
|
const body: RequestBody = { model: "gpt-5.1-codex-mini", input: [] };
|
||||||
|
|
||||||
|
const low = await transformRequestBody({ ...body }, { reasoningEffort: "low" });
|
||||||
|
expect(low.reasoning?.effort).toBe("medium");
|
||||||
|
|
||||||
|
const xhigh = await transformRequestBody({ ...body }, { reasoningEffort: "xhigh" });
|
||||||
|
expect(xhigh.reasoning?.effort).toBe("high");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue