mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 03:04:28 +00:00
fix: codex thinking handling
This commit is contained in:
parent
22870ae0c2
commit
02b72b49d5
23 changed files with 205 additions and 754 deletions
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -5185,7 +5185,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/lit/-/lit-3.3.2.tgz",
|
||||||
"integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==",
|
"integrity": "sha512-NF9zbsP79l4ao2SNrH3NkfmFgN/hBYSQo90saIVI1o5GpjAdCPVstVzO1MrLOakHoEhYkrtRjPK6Ob521aoYWQ==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lit/reactive-element": "^2.1.0",
|
"@lit/reactive-element": "^2.1.0",
|
||||||
"lit-element": "^4.2.0",
|
"lit-element": "^4.2.0",
|
||||||
|
|
@ -6386,7 +6385,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
|
||||||
"integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
|
"integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/dcastil"
|
"url": "https://github.com/sponsors/dcastil"
|
||||||
|
|
@ -6415,8 +6413,7 @@
|
||||||
"version": "4.1.18",
|
"version": "4.1.18",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",
|
||||||
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
"integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
|
|
@ -6602,7 +6599,6 @@
|
||||||
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
|
"integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==",
|
||||||
"devOptional": true,
|
"devOptional": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "~0.27.0",
|
"esbuild": "~0.27.0",
|
||||||
"get-tsconfig": "^4.7.5"
|
"get-tsconfig": "^4.7.5"
|
||||||
|
|
@ -6682,7 +6678,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz",
|
||||||
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
|
|
@ -7225,6 +7220,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/diff": "^7.0.2",
|
"@types/diff": "^7.0.2",
|
||||||
|
"@types/ms": "^2.1.0",
|
||||||
"@types/node": "^24.3.0",
|
"@types/node": "^24.3.0",
|
||||||
"@types/proper-lockfile": "^4.1.4",
|
"@types/proper-lockfile": "^4.1.4",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- `minimal` thinking level now maps to `minimal` reasoning effort instead of being treated as `low`.
|
||||||
|
|
||||||
## [0.36.0] - 2026-01-05
|
## [0.36.0] - 2026-01-05
|
||||||
|
|
||||||
## [0.35.0] - 2026-01-05
|
## [0.35.0] - 2026-01-05
|
||||||
|
|
|
||||||
|
|
@ -277,11 +277,7 @@ export class Agent {
|
||||||
this._state.error = undefined;
|
this._state.error = undefined;
|
||||||
|
|
||||||
const reasoning: ReasoningEffort | undefined =
|
const reasoning: ReasoningEffort | undefined =
|
||||||
this._state.thinkingLevel === "off"
|
this._state.thinkingLevel === "off" ? undefined : (this._state.thinkingLevel as ReasoningEffort);
|
||||||
? undefined
|
|
||||||
: this._state.thinkingLevel === "minimal"
|
|
||||||
? "low"
|
|
||||||
: (this._state.thinkingLevel as ReasoningEffort);
|
|
||||||
|
|
||||||
const context: AgentContext = {
|
const context: AgentContext = {
|
||||||
systemPrompt: this._state.systemPrompt,
|
systemPrompt: this._state.systemPrompt,
|
||||||
|
|
|
||||||
|
|
@ -454,54 +454,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["low", "medium", "high", "xhigh"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-codex-low",
|
|
||||||
name: "gpt-5.2-codex-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-codex-medium",
|
|
||||||
name: "gpt-5.2-codex-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-codex-high",
|
|
||||||
name: "gpt-5.2-codex-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-codex-xhigh",
|
|
||||||
name: "gpt-5.2-codex-xhigh",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -519,66 +472,6 @@ async function generateModels() {
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
maxTokens: CODEX_MAX_TOKENS,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "gpt-5.2-none",
|
|
||||||
name: "gpt-5.2-none",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-low",
|
|
||||||
name: "gpt-5.2-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-medium",
|
|
||||||
name: "gpt-5.2-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-high",
|
|
||||||
name: "gpt-5.2-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.2-xhigh",
|
|
||||||
name: "gpt-5.2-xhigh",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "gpt-5.1-codex-max",
|
id: "gpt-5.1-codex-max",
|
||||||
name: "GPT-5.1 Codex Max",
|
name: "GPT-5.1 Codex Max",
|
||||||
|
|
@ -586,54 +479,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["low", "medium", "high", "xhigh"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-max-low",
|
|
||||||
name: "gpt-5.1-codex-max-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-max-medium",
|
|
||||||
name: "gpt-5.1-codex-max-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-max-high",
|
|
||||||
name: "gpt-5.1-codex-max-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-max-xhigh",
|
|
||||||
name: "gpt-5.1-codex-max-xhigh",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -646,42 +492,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["low", "medium", "high"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-low",
|
|
||||||
name: "gpt-5.1-codex-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-medium",
|
|
||||||
name: "gpt-5.1-codex-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-high",
|
|
||||||
name: "gpt-5.1-codex-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -694,30 +505,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["medium", "high"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-mini-medium",
|
|
||||||
name: "gpt-5.1-codex-mini-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-codex-mini-high",
|
|
||||||
name: "gpt-5.1-codex-mini-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -730,6 +518,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
|
thinkingLevels: ["medium", "high"],
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -742,30 +531,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["medium", "high"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5-codex-mini-medium",
|
|
||||||
name: "gpt-5-codex-mini-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5-codex-mini-high",
|
|
||||||
name: "gpt-5-codex-mini-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -778,6 +544,7 @@ async function generateModels() {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: CODEX_BASE_URL,
|
baseUrl: CODEX_BASE_URL,
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
|
thinkingLevels: ["low", "medium", "high"],
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
|
|
@ -795,54 +562,6 @@ async function generateModels() {
|
||||||
contextWindow: CODEX_CONTEXT,
|
contextWindow: CODEX_CONTEXT,
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
maxTokens: CODEX_MAX_TOKENS,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
id: "gpt-5.1-none",
|
|
||||||
name: "gpt-5.1-none",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-low",
|
|
||||||
name: "gpt-5.1-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-medium",
|
|
||||||
name: "gpt-5.1-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "gpt-5.1-high",
|
|
||||||
name: "gpt-5.1-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: CODEX_BASE_URL,
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
||||||
contextWindow: CODEX_CONTEXT,
|
|
||||||
maxTokens: CODEX_MAX_TOKENS,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
id: "gpt-5.1-chat-latest",
|
id: "gpt-5.1-chat-latest",
|
||||||
name: "gpt-5.1-chat-latest",
|
name: "gpt-5.1-chat-latest",
|
||||||
|
|
@ -1280,6 +999,9 @@ export const MODELS = {
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
output += `\t\t\treasoning: ${model.reasoning},\n`;
|
output += `\t\t\treasoning: ${model.reasoning},\n`;
|
||||||
|
if (model.thinkingLevels) {
|
||||||
|
output += `\t\t\tthinkingLevels: ${JSON.stringify(model.thinkingLevels)},\n`;
|
||||||
|
}
|
||||||
output += `\t\t\tinput: [${model.input.map(i => `"${i}"`).join(", ")}],\n`;
|
output += `\t\t\tinput: [${model.input.map(i => `"${i}"`).join(", ")}],\n`;
|
||||||
output += `\t\t\tcost: {\n`;
|
output += `\t\t\tcost: {\n`;
|
||||||
output += `\t\t\t\tinput: ${model.cost.input},\n`;
|
output += `\t\t\t\tinput: ${model.cost.input},\n`;
|
||||||
|
|
|
||||||
|
|
@ -2781,6 +2781,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
|
thinkingLevels: ["medium","high"],
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
@ -2815,6 +2816,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
|
thinkingLevels: ["low","medium","high"],
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
@ -2832,40 +2834,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["medium","high"],
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5-codex-mini-high": {
|
|
||||||
id: "gpt-5-codex-mini-high",
|
|
||||||
name: "gpt-5-codex-mini-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5-codex-mini-medium": {
|
|
||||||
id: "gpt-5-codex-mini-medium",
|
|
||||||
name: "gpt-5-codex-mini-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
@ -2951,40 +2920,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["low","medium","high"],
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-high": {
|
|
||||||
id: "gpt-5.1-codex-high",
|
|
||||||
name: "gpt-5.1-codex-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-low": {
|
|
||||||
id: "gpt-5.1-codex-low",
|
|
||||||
name: "gpt-5.1-codex-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
@ -3002,91 +2938,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["low","medium","high","xhigh"],
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-max-high": {
|
|
||||||
id: "gpt-5.1-codex-max-high",
|
|
||||||
name: "gpt-5.1-codex-max-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-max-low": {
|
|
||||||
id: "gpt-5.1-codex-max-low",
|
|
||||||
name: "gpt-5.1-codex-max-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-max-medium": {
|
|
||||||
id: "gpt-5.1-codex-max-medium",
|
|
||||||
name: "gpt-5.1-codex-max-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-max-xhigh": {
|
|
||||||
id: "gpt-5.1-codex-max-xhigh",
|
|
||||||
name: "gpt-5.1-codex-max-xhigh",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-medium": {
|
|
||||||
id: "gpt-5.1-codex-medium",
|
|
||||||
name: "gpt-5.1-codex-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
@ -3104,108 +2956,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["medium","high"],
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-mini-high": {
|
|
||||||
id: "gpt-5.1-codex-mini-high",
|
|
||||||
name: "gpt-5.1-codex-mini-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-codex-mini-medium": {
|
|
||||||
id: "gpt-5.1-codex-mini-medium",
|
|
||||||
name: "gpt-5.1-codex-mini-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-high": {
|
|
||||||
id: "gpt-5.1-high",
|
|
||||||
name: "gpt-5.1-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-low": {
|
|
||||||
id: "gpt-5.1-low",
|
|
||||||
name: "gpt-5.1-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-medium": {
|
|
||||||
id: "gpt-5.1-medium",
|
|
||||||
name: "gpt-5.1-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.1-none": {
|
|
||||||
id: "gpt-5.1-none",
|
|
||||||
name: "gpt-5.1-none",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
@ -3240,159 +2991,7 @@ export const MODELS = {
|
||||||
provider: "openai-codex",
|
provider: "openai-codex",
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
baseUrl: "https://chatgpt.com/backend-api",
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
thinkingLevels: ["low","medium","high","xhigh"],
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-codex-high": {
|
|
||||||
id: "gpt-5.2-codex-high",
|
|
||||||
name: "gpt-5.2-codex-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-codex-low": {
|
|
||||||
id: "gpt-5.2-codex-low",
|
|
||||||
name: "gpt-5.2-codex-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-codex-medium": {
|
|
||||||
id: "gpt-5.2-codex-medium",
|
|
||||||
name: "gpt-5.2-codex-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-codex-xhigh": {
|
|
||||||
id: "gpt-5.2-codex-xhigh",
|
|
||||||
name: "gpt-5.2-codex-xhigh",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-high": {
|
|
||||||
id: "gpt-5.2-high",
|
|
||||||
name: "gpt-5.2-high",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-low": {
|
|
||||||
id: "gpt-5.2-low",
|
|
||||||
name: "gpt-5.2-low",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-medium": {
|
|
||||||
id: "gpt-5.2-medium",
|
|
||||||
name: "gpt-5.2-medium",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-none": {
|
|
||||||
id: "gpt-5.2-none",
|
|
||||||
name: "gpt-5.2-none",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 400000,
|
|
||||||
maxTokens: 128000,
|
|
||||||
} satisfies Model<"openai-codex-responses">,
|
|
||||||
"gpt-5.2-xhigh": {
|
|
||||||
id: "gpt-5.2-xhigh",
|
|
||||||
name: "gpt-5.2-xhigh",
|
|
||||||
api: "openai-codex-responses",
|
|
||||||
provider: "openai-codex",
|
|
||||||
baseUrl: "https://chatgpt.com/backend-api",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0,
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,50 @@
|
||||||
import { MODELS } from "./models.generated.js";
|
import { MODELS } from "./models.generated.js";
|
||||||
import type { Api, KnownProvider, Model, Usage } from "./types.js";
|
import type { Api, KnownProvider, Model, ReasoningEffort, Usage } from "./types.js";
|
||||||
|
|
||||||
const modelRegistry: Map<string, Map<string, Model<Api>>> = new Map();
|
const modelRegistry: Map<string, Map<string, Model<Api>>> = new Map();
|
||||||
|
|
||||||
|
const CODEX_THINKING_SUFFIXES = ["-none", "-minimal", "-low", "-medium", "-high", "-xhigh"];
|
||||||
|
const CODEX_THINKING_LEVELS: Record<string, ReasoningEffort[]> = {
|
||||||
|
"gpt-5.2-codex": ["low", "medium", "high", "xhigh"],
|
||||||
|
"gpt-5.1-codex-max": ["low", "medium", "high", "xhigh"],
|
||||||
|
"gpt-5.1-codex": ["low", "medium", "high"],
|
||||||
|
"gpt-5.1-codex-mini": ["medium", "high"],
|
||||||
|
"codex-mini-latest": ["medium", "high"],
|
||||||
|
"gpt-5-codex-mini": ["medium", "high"],
|
||||||
|
"gpt-5-codex": ["low", "medium", "high"],
|
||||||
|
};
|
||||||
|
|
||||||
|
function isCodexThinkingVariant(modelId: string): boolean {
|
||||||
|
const normalized = modelId.toLowerCase();
|
||||||
|
return CODEX_THINKING_SUFFIXES.some((suffix) => normalized.endsWith(suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCodexModelId(modelId: string): string {
|
||||||
|
const normalized = modelId.toLowerCase();
|
||||||
|
for (const suffix of CODEX_THINKING_SUFFIXES) {
|
||||||
|
if (normalized.endsWith(suffix)) {
|
||||||
|
return modelId.slice(0, modelId.length - suffix.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modelId;
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyCodexThinkingLevels<TApi extends Api>(model: Model<TApi>): Model<TApi> {
|
||||||
|
if (model.provider !== "openai-codex") return model;
|
||||||
|
const thinkingLevels = CODEX_THINKING_LEVELS[model.id];
|
||||||
|
if (!thinkingLevels) return model;
|
||||||
|
return { ...model, thinkingLevels };
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize registry from MODELS on module load
|
// Initialize registry from MODELS on module load
|
||||||
for (const [provider, models] of Object.entries(MODELS)) {
|
for (const [provider, models] of Object.entries(MODELS)) {
|
||||||
const providerModels = new Map<string, Model<Api>>();
|
const providerModels = new Map<string, Model<Api>>();
|
||||||
for (const [id, model] of Object.entries(models)) {
|
for (const [id, model] of Object.entries(models)) {
|
||||||
providerModels.set(id, model as Model<Api>);
|
const typedModel = model as Model<Api>;
|
||||||
|
if (provider === "openai-codex" && isCodexThinkingVariant(typedModel.id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
providerModels.set(id, applyCodexThinkingLevels(typedModel));
|
||||||
}
|
}
|
||||||
modelRegistry.set(provider, providerModels);
|
modelRegistry.set(provider, providerModels);
|
||||||
}
|
}
|
||||||
|
|
@ -21,7 +58,17 @@ export function getModel<TProvider extends KnownProvider, TModelId extends keyof
|
||||||
provider: TProvider,
|
provider: TProvider,
|
||||||
modelId: TModelId,
|
modelId: TModelId,
|
||||||
): Model<ModelApi<TProvider, TModelId>> {
|
): Model<ModelApi<TProvider, TModelId>> {
|
||||||
return modelRegistry.get(provider)?.get(modelId as string) as Model<ModelApi<TProvider, TModelId>>;
|
const providerModels = modelRegistry.get(provider);
|
||||||
|
const direct = providerModels?.get(modelId as string);
|
||||||
|
if (direct) return direct as Model<ModelApi<TProvider, TModelId>>;
|
||||||
|
if (provider === "openai-codex") {
|
||||||
|
const normalized = normalizeCodexModelId(modelId as string);
|
||||||
|
const normalizedModel = providerModels?.get(normalized);
|
||||||
|
if (normalizedModel) {
|
||||||
|
return normalizedModel as Model<ModelApi<TProvider, TModelId>>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return direct as unknown as Model<ModelApi<TProvider, TModelId>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getProviders(): KnownProvider[] {
|
export function getProviders(): KnownProvider[] {
|
||||||
|
|
@ -52,6 +99,9 @@ const XHIGH_MODELS = new Set(["gpt-5.1-codex-max", "gpt-5.2", "gpt-5.2-codex"]);
|
||||||
* Currently only certain OpenAI models support this.
|
* Currently only certain OpenAI models support this.
|
||||||
*/
|
*/
|
||||||
export function supportsXhigh<TApi extends Api>(model: Model<TApi>): boolean {
|
export function supportsXhigh<TApi extends Api>(model: Model<TApi>): boolean {
|
||||||
|
if (model.thinkingLevels) {
|
||||||
|
return model.thinkingLevels.includes("xhigh");
|
||||||
|
}
|
||||||
return XHIGH_MODELS.has(model.id);
|
return XHIGH_MODELS.has(model.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,10 +126,12 @@ export const streamOpenAICodexResponses: StreamFunction<"openai-codex-responses"
|
||||||
context.systemPrompt,
|
context.systemPrompt,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const reasoningEffort = transformedBody.reasoning?.effort ?? null;
|
||||||
const headers = createCodexHeaders(model.headers, accountId, apiKey, transformedBody.prompt_cache_key);
|
const headers = createCodexHeaders(model.headers, accountId, apiKey, transformedBody.prompt_cache_key);
|
||||||
logCodexDebug("codex request", {
|
logCodexDebug("codex request", {
|
||||||
url,
|
url,
|
||||||
model: params.model,
|
model: params.model,
|
||||||
|
reasoningEffort,
|
||||||
headers: redactHeaders(headers),
|
headers: redactHeaders(headers),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -308,11 +308,15 @@ export async function transformRequestBody(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.reasoningEffort !== undefined) {
|
||||||
const reasoningConfig = getReasoningConfig(normalizedModel, options);
|
const reasoningConfig = getReasoningConfig(normalizedModel, options);
|
||||||
body.reasoning = {
|
body.reasoning = {
|
||||||
...body.reasoning,
|
...body.reasoning,
|
||||||
...reasoningConfig,
|
...reasoningConfig,
|
||||||
};
|
};
|
||||||
|
} else {
|
||||||
|
delete body.reasoning;
|
||||||
|
}
|
||||||
|
|
||||||
body.text = {
|
body.text = {
|
||||||
...body.text,
|
...body.text,
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,8 @@ export interface Model<TApi extends Api> {
|
||||||
provider: Provider;
|
provider: Provider;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
reasoning: boolean;
|
reasoning: boolean;
|
||||||
|
/** Supported reasoning levels for this model (excluding "off"). */
|
||||||
|
thinkingLevels?: ReasoningEffort[];
|
||||||
input: ("text" | "image")[];
|
input: ("text" | "image")[];
|
||||||
cost: {
|
cost: {
|
||||||
input: number; // $/million tokens
|
input: number; // $/million tokens
|
||||||
|
|
|
||||||
|
|
@ -145,12 +145,12 @@ describe("AI Providers Abort Tests", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex Provider Abort", () => {
|
describe("OpenAI Codex Provider Abort", () => {
|
||||||
it.skipIf(!openaiCodexToken)("should abort mid-stream", { retry: 3 }, async () => {
|
it.skipIf(!openaiCodexToken)("should abort mid-stream", { retry: 3 }, async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testAbortSignal(llm, { apiKey: openaiCodexToken });
|
await testAbortSignal(llm, { apiKey: openaiCodexToken });
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)("should handle immediate abort", { retry: 3 }, async () => {
|
it.skipIf(!openaiCodexToken)("should handle immediate abort", { retry: 3 }, async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testImmediateAbort(llm, { apiKey: openaiCodexToken });
|
await testImmediateAbort(llm, { apiKey: openaiCodexToken });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -271,9 +271,9 @@ describe("Context overflow error handling", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex (OAuth)", () => {
|
describe("OpenAI Codex (OAuth)", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should detect overflow via isContextOverflow",
|
"gpt-5.2-codex - should detect overflow via isContextOverflow",
|
||||||
async () => {
|
async () => {
|
||||||
const model = getModel("openai-codex", "gpt-5.2-xhigh");
|
const model = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
const result = await testContextOverflow(model, openaiCodexToken!);
|
const result = await testContextOverflow(model, openaiCodexToken!);
|
||||||
logResult(result);
|
logResult(result);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -577,37 +577,37 @@ describe("AI Providers Empty Message Tests", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex Provider Empty Messages", () => {
|
describe("OpenAI Codex Provider Empty Messages", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle empty content array",
|
"gpt-5.2-codex - should handle empty content array",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testEmptyMessage(llm, { apiKey: openaiCodexToken });
|
await testEmptyMessage(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle empty string content",
|
"gpt-5.2-codex - should handle empty string content",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testEmptyStringMessage(llm, { apiKey: openaiCodexToken });
|
await testEmptyStringMessage(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle whitespace-only content",
|
"gpt-5.2-codex - should handle whitespace-only content",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testWhitespaceOnlyMessage(llm, { apiKey: openaiCodexToken });
|
await testWhitespaceOnlyMessage(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle empty assistant message in conversation",
|
"gpt-5.2-codex - should handle empty assistant message in conversation",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testEmptyAssistantMessage(llm, { apiKey: openaiCodexToken });
|
await testEmptyAssistantMessage(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -398,19 +398,19 @@ describe("Tool Results with Images", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex Provider", () => {
|
describe("OpenAI Codex Provider", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle tool result with only image",
|
"gpt-5.2-codex - should handle tool result with only image",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await handleToolWithImageResult(llm, { apiKey: openaiCodexToken });
|
await handleToolWithImageResult(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle tool result with text and image",
|
"gpt-5.2-codex - should handle tool result with text and image",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await handleToolWithTextAndImageResult(llm, { apiKey: openaiCodexToken });
|
await handleToolWithTextAndImageResult(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -879,8 +879,8 @@ describe("Generate E2E Tests", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("OpenAI Codex Provider (gpt-5.2-xhigh)", () => {
|
describe("OpenAI Codex Provider (gpt-5.2-codex)", () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)("should complete basic text generation", { retry: 3 }, async () => {
|
it.skipIf(!openaiCodexToken)("should complete basic text generation", { retry: 3 }, async () => {
|
||||||
await basicTextGeneration(llm, { apiKey: openaiCodexToken });
|
await basicTextGeneration(llm, { apiKey: openaiCodexToken });
|
||||||
|
|
@ -895,7 +895,7 @@ describe("Generate E2E Tests", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)("should handle thinking", { retry: 3 }, async () => {
|
it.skipIf(!openaiCodexToken)("should handle thinking", { retry: 3 }, async () => {
|
||||||
await handleThinking(llm, { apiKey: openaiCodexToken });
|
await handleThinking(llm, { apiKey: openaiCodexToken, reasoningEffort: "high" });
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
it.skipIf(!openaiCodexToken)("should handle multi-turn with thinking and tools", { retry: 3 }, async () => {
|
||||||
|
|
|
||||||
|
|
@ -222,10 +222,10 @@ describe("Token Statistics on Abort", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex Provider", () => {
|
describe("OpenAI Codex Provider", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should include token stats when aborted mid-stream",
|
"gpt-5.2-codex - should include token stats when aborted mid-stream",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testTokensOnAbort(llm, { apiKey: openaiCodexToken });
|
await testTokensOnAbort(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -248,10 +248,10 @@ describe("Tool Call Without Result Tests", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex Provider", () => {
|
describe("OpenAI Codex Provider", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should filter out tool calls without corresponding tool results",
|
"gpt-5.2-codex - should filter out tool calls without corresponding tool results",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const model = getModel("openai-codex", "gpt-5.2-xhigh");
|
const model = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testToolCallWithoutResult(model, { apiKey: openaiCodexToken });
|
await testToolCallWithoutResult(model, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -541,10 +541,10 @@ describe("totalTokens field", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex (OAuth)", () => {
|
describe("OpenAI Codex (OAuth)", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should return totalTokens equal to sum of components",
|
"gpt-5.2-codex - should return totalTokens equal to sum of components",
|
||||||
{ retry: 3, timeout: 60000 },
|
{ retry: 3, timeout: 60000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
|
|
||||||
console.log(`\nOpenAI Codex / ${llm.id}:`);
|
console.log(`\nOpenAI Codex / ${llm.id}:`);
|
||||||
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: openaiCodexToken });
|
const { first, second } = await testTotalTokensWithCache(llm, { apiKey: openaiCodexToken });
|
||||||
|
|
|
||||||
|
|
@ -619,28 +619,28 @@ describe("AI Providers Unicode Surrogate Pair Tests", () => {
|
||||||
|
|
||||||
describe("OpenAI Codex Provider Unicode Handling", () => {
|
describe("OpenAI Codex Provider Unicode Handling", () => {
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle emoji in tool results",
|
"gpt-5.2-codex - should handle emoji in tool results",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testEmojiInToolResults(llm, { apiKey: openaiCodexToken });
|
await testEmojiInToolResults(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle real-world LinkedIn comment data with emoji",
|
"gpt-5.2-codex - should handle real-world LinkedIn comment data with emoji",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testRealWorldLinkedInData(llm, { apiKey: openaiCodexToken });
|
await testRealWorldLinkedInData(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
it.skipIf(!openaiCodexToken)(
|
it.skipIf(!openaiCodexToken)(
|
||||||
"gpt-5.2-xhigh - should handle unpaired high surrogate (0xD83D) in tool results",
|
"gpt-5.2-codex - should handle unpaired high surrogate (0xD83D) in tool results",
|
||||||
{ retry: 3, timeout: 30000 },
|
{ retry: 3, timeout: 30000 },
|
||||||
async () => {
|
async () => {
|
||||||
const llm = getModel("openai-codex", "gpt-5.2-xhigh");
|
const llm = getModel("openai-codex", "gpt-5.2-codex");
|
||||||
await testUnpairedHighSurrogate(llm, { apiKey: openaiCodexToken });
|
await testUnpairedHighSurrogate(llm, { apiKey: openaiCodexToken });
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
- OAuth login UI now uses dedicated dialog component with consistent borders
|
- OAuth login UI now uses dedicated dialog component with consistent borders
|
||||||
- Assume truecolor support for all terminals except `dumb`, empty, or `linux` (fixes colors over SSH)
|
- Assume truecolor support for all terminals except `dumb`, empty, or `linux` (fixes colors over SSH)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Thinking level availability now reflects per-model supported reasoning levels.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Managed binaries (`fd`, `rg`) now stored in `~/.pi/agent/bin/` instead of `tools/`, eliminating false deprecation warnings ([#470](https://github.com/badlogic/pi-mono/pull/470) by [@mcinteerj](https://github.com/mcinteerj))
|
- Managed binaries (`fd`, `rg`) now stored in `~/.pi/agent/bin/` instead of `tools/`, eliminating false deprecation warnings ([#470](https://github.com/badlogic/pi-mono/pull/470) by [@mcinteerj](https://github.com/mcinteerj))
|
||||||
|
|
@ -20,6 +24,7 @@
|
||||||
- Migration warnings now ignore `fd.exe` and `rg.exe` in `tools/` on Windows ([#458](https://github.com/badlogic/pi-mono/pull/458) by [@carlosgtrz](https://github.com/carlosgtrz))
|
- Migration warnings now ignore `fd.exe` and `rg.exe` in `tools/` on Windows ([#458](https://github.com/badlogic/pi-mono/pull/458) by [@carlosgtrz](https://github.com/carlosgtrz))
|
||||||
- CI: add `examples/extensions/with-deps` to workspaces to fix typecheck ([#467](https://github.com/badlogic/pi-mono/pull/467) by [@aliou](https://github.com/aliou))
|
- CI: add `examples/extensions/with-deps` to workspaces to fix typecheck ([#467](https://github.com/badlogic/pi-mono/pull/467) by [@aliou](https://github.com/aliou))
|
||||||
- SDK: passing `extensions: []` now disables extension discovery as documented ([#465](https://github.com/badlogic/pi-mono/pull/465) by [@aliou](https://github.com/aliou))
|
- SDK: passing `extensions: []` now disables extension discovery as documented ([#465](https://github.com/badlogic/pi-mono/pull/465) by [@aliou](https://github.com/aliou))
|
||||||
|
- Legacy Codex model IDs with thinking suffixes resolve to their base models.
|
||||||
|
|
||||||
## [0.36.0] - 2026-01-05
|
## [0.36.0] - 2026-01-05
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/diff": "^7.0.2",
|
"@types/diff": "^7.0.2",
|
||||||
|
"@types/ms": "^2.1.0",
|
||||||
"@types/node": "^24.3.0",
|
"@types/node": "^24.3.0",
|
||||||
"@types/proper-lockfile": "^4.1.4",
|
"@types/proper-lockfile": "^4.1.4",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.7.3",
|
||||||
|
|
|
||||||
|
|
@ -978,16 +978,12 @@ export class AgentSession {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set thinking level.
|
* Set thinking level.
|
||||||
* Clamps to model capabilities: "off" if no reasoning, "high" if xhigh unsupported.
|
* Clamps to model capabilities based on available thinking levels.
|
||||||
* Saves to session and settings.
|
* Saves to session and settings.
|
||||||
*/
|
*/
|
||||||
setThinkingLevel(level: ThinkingLevel): void {
|
setThinkingLevel(level: ThinkingLevel): void {
|
||||||
let effectiveLevel = level;
|
const availableLevels = this.getAvailableThinkingLevels();
|
||||||
if (!this.supportsThinking()) {
|
const effectiveLevel = availableLevels.includes(level) ? level : this._clampThinkingLevel(level, availableLevels);
|
||||||
effectiveLevel = "off";
|
|
||||||
} else if (level === "xhigh" && !this.supportsXhighThinking()) {
|
|
||||||
effectiveLevel = "high";
|
|
||||||
}
|
|
||||||
this.agent.setThinkingLevel(effectiveLevel);
|
this.agent.setThinkingLevel(effectiveLevel);
|
||||||
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
this.sessionManager.appendThinkingLevelChange(effectiveLevel);
|
||||||
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
this.settingsManager.setDefaultThinkingLevel(effectiveLevel);
|
||||||
|
|
@ -1013,6 +1009,14 @@ export class AgentSession {
|
||||||
* Get available thinking levels for current model.
|
* Get available thinking levels for current model.
|
||||||
*/
|
*/
|
||||||
getAvailableThinkingLevels(): ThinkingLevel[] {
|
getAvailableThinkingLevels(): ThinkingLevel[] {
|
||||||
|
if (!this.supportsThinking()) return ["off"];
|
||||||
|
|
||||||
|
const modelLevels = this.model?.thinkingLevels;
|
||||||
|
if (modelLevels && modelLevels.length > 0) {
|
||||||
|
const withOff: ThinkingLevel[] = ["off", ...modelLevels];
|
||||||
|
return THINKING_LEVELS_WITH_XHIGH.filter((level) => withOff.includes(level));
|
||||||
|
}
|
||||||
|
|
||||||
return this.supportsXhighThinking() ? THINKING_LEVELS_WITH_XHIGH : THINKING_LEVELS;
|
return this.supportsXhighThinking() ? THINKING_LEVELS_WITH_XHIGH : THINKING_LEVELS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1030,6 +1034,24 @@ export class AgentSession {
|
||||||
return !!this.model?.reasoning;
|
return !!this.model?.reasoning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _clampThinkingLevel(level: ThinkingLevel, availableLevels: ThinkingLevel[]): ThinkingLevel {
|
||||||
|
const ordered = THINKING_LEVELS_WITH_XHIGH;
|
||||||
|
const available = new Set(availableLevels);
|
||||||
|
const requestedIndex = ordered.indexOf(level);
|
||||||
|
if (requestedIndex === -1) {
|
||||||
|
return availableLevels[0] ?? "off";
|
||||||
|
}
|
||||||
|
for (let i = requestedIndex; i < ordered.length; i++) {
|
||||||
|
const candidate = ordered[i];
|
||||||
|
if (available.has(candidate)) return candidate;
|
||||||
|
}
|
||||||
|
for (let i = requestedIndex - 1; i >= 0; i--) {
|
||||||
|
const candidate = ordered[i];
|
||||||
|
if (available.has(candidate)) return candidate;
|
||||||
|
}
|
||||||
|
return availableLevels[0] ?? "off";
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
// Queue Mode Management
|
// Queue Mode Management
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,16 @@ import type { AuthStorage } from "./auth-storage.js";
|
||||||
|
|
||||||
const Ajv = (AjvModule as any).default || AjvModule;
|
const Ajv = (AjvModule as any).default || AjvModule;
|
||||||
|
|
||||||
|
const ThinkingLevelsSchema = Type.Array(
|
||||||
|
Type.Union([
|
||||||
|
Type.Literal("minimal"),
|
||||||
|
Type.Literal("low"),
|
||||||
|
Type.Literal("medium"),
|
||||||
|
Type.Literal("high"),
|
||||||
|
Type.Literal("xhigh"),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
// Schema for OpenAI compatibility settings
|
// Schema for OpenAI compatibility settings
|
||||||
const OpenAICompatSchema = Type.Object({
|
const OpenAICompatSchema = Type.Object({
|
||||||
supportsStore: Type.Optional(Type.Boolean()),
|
supportsStore: Type.Optional(Type.Boolean()),
|
||||||
|
|
@ -40,6 +50,7 @@ const ModelDefinitionSchema = Type.Object({
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
reasoning: Type.Boolean(),
|
reasoning: Type.Boolean(),
|
||||||
|
thinkingLevels: Type.Optional(ThinkingLevelsSchema),
|
||||||
input: Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")])),
|
input: Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")])),
|
||||||
cost: Type.Object({
|
cost: Type.Object({
|
||||||
input: Type.Number(),
|
input: Type.Number(),
|
||||||
|
|
@ -107,6 +118,14 @@ function resolveApiKeyConfig(keyConfig: string): string | undefined {
|
||||||
return keyConfig;
|
return keyConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeCodexModelId(modelId: string): string {
|
||||||
|
const suffixes = ["-none", "-minimal", "-low", "-medium", "-high", "-xhigh"];
|
||||||
|
const normalized = modelId.toLowerCase();
|
||||||
|
const matchedSuffix = suffixes.find((suffix) => normalized.endsWith(suffix));
|
||||||
|
if (!matchedSuffix) return modelId;
|
||||||
|
return modelId.slice(0, modelId.length - matchedSuffix.length);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model registry - loads and manages models, resolves API keys via AuthStorage.
|
* Model registry - loads and manages models, resolves API keys via AuthStorage.
|
||||||
*/
|
*/
|
||||||
|
|
@ -330,6 +349,7 @@ export class ModelRegistry {
|
||||||
provider: providerName,
|
provider: providerName,
|
||||||
baseUrl: providerConfig.baseUrl!,
|
baseUrl: providerConfig.baseUrl!,
|
||||||
reasoning: modelDef.reasoning,
|
reasoning: modelDef.reasoning,
|
||||||
|
thinkingLevels: modelDef.thinkingLevels,
|
||||||
input: modelDef.input as ("text" | "image")[],
|
input: modelDef.input as ("text" | "image")[],
|
||||||
cost: modelDef.cost,
|
cost: modelDef.cost,
|
||||||
contextWindow: modelDef.contextWindow,
|
contextWindow: modelDef.contextWindow,
|
||||||
|
|
@ -363,7 +383,15 @@ export class ModelRegistry {
|
||||||
* Find a model by provider and ID.
|
* Find a model by provider and ID.
|
||||||
*/
|
*/
|
||||||
find(provider: string, modelId: string): Model<Api> | undefined {
|
find(provider: string, modelId: string): Model<Api> | undefined {
|
||||||
return this.models.find((m) => m.provider === provider && m.id === modelId) ?? undefined;
|
const exact = this.models.find((m) => m.provider === provider && m.id === modelId);
|
||||||
|
if (exact) return exact;
|
||||||
|
if (provider === "openai-codex") {
|
||||||
|
const normalized = normalizeCodexModelId(modelId);
|
||||||
|
if (normalized !== modelId) {
|
||||||
|
return this.models.find((m) => m.provider === provider && m.id === normalized) ?? undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,18 @@ export interface ParsedModelResult {
|
||||||
warning: string | undefined;
|
warning: string | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const THINKING_SUFFIXES = ["-none", "-minimal", "-low", "-medium", "-high", "-xhigh"];
|
||||||
|
|
||||||
|
function stripThinkingSuffix(pattern: string): string {
|
||||||
|
const normalized = pattern.toLowerCase();
|
||||||
|
for (const suffix of THINKING_SUFFIXES) {
|
||||||
|
if (normalized.endsWith(suffix)) {
|
||||||
|
return pattern.slice(0, pattern.length - suffix.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a pattern to extract model and thinking level.
|
* Parse a pattern to extract model and thinking level.
|
||||||
* Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).
|
* Handles models with colons in their IDs (e.g., OpenRouter's :exacto suffix).
|
||||||
|
|
@ -122,6 +134,14 @@ export function parseModelPattern(pattern: string, availableModels: Model<Api>[]
|
||||||
return { model: exactMatch, thinkingLevel: "off", warning: undefined };
|
return { model: exactMatch, thinkingLevel: "off", warning: undefined };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedPattern = stripThinkingSuffix(pattern);
|
||||||
|
if (normalizedPattern !== pattern) {
|
||||||
|
const normalizedMatch = tryMatchModel(normalizedPattern, availableModels);
|
||||||
|
if (normalizedMatch) {
|
||||||
|
return { model: normalizedMatch, thinkingLevel: "off", warning: undefined };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No match - try splitting on last colon if present
|
// No match - try splitting on last colon if present
|
||||||
const lastColonIndex = pattern.lastIndexOf(":");
|
const lastColonIndex = pattern.lastIndexOf(":");
|
||||||
if (lastColonIndex === -1) {
|
if (lastColonIndex === -1) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue