From 419ca4cbd9c3b14cf528ec21e96ca48040a7cf24 Mon Sep 17 00:00:00 2001 From: Ben Vargas Date: Thu, 11 Dec 2025 21:17:11 -0700 Subject: [PATCH] feat: v4.1.1 - Add "none" reasoning effort support for GPT-5.2 and GPT-5.1 Add support for `reasoning_effort: "none"` which disables the reasoning phase entirely, resulting in faster responses when reasoning is not needed. Changes: - Add `gpt-5.2-none` and `gpt-5.1-none` model mappings - Update getReasoningConfig() to allow "none" for GPT-5.1/5.2 general purpose - Codex variants auto-convert "none" to "low" (or "medium" for Mini) - Add 4 new unit tests (197 total) - Update documentation with reasoning effort support matrix References: - OpenAI API docs: "gpt-5.1 defaults to none, supports: none, low, medium, high" - Codex CLI: ReasoningEffort enum includes None variant - Codex CLI: docs/config.md lists "none" as valid config option --- CHANGELOG.md | 27 ++++++++++++++ docs/configuration.md | 29 ++++++++++------ lib/request/helpers/model-map.ts | 6 ++-- lib/request/request-transformer.ts | 22 ++++++++++++ package-lock.json | 17 ++++----- package.json | 2 +- test/request-transformer.test.ts | 56 ++++++++++++++++++++++++++++++ 7 files changed, 137 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ebbff26..fb21982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,33 @@ All notable changes to this project are documented here. Dates use the ISO format (YYYY-MM-DD). +## [4.1.1] - 2025-12-11 + +**Minor release**: "none" reasoning effort support for GPT-5.2 and GPT-5.1. + +### Added +- **"none" reasoning effort support**: GPT-5.1 and GPT-5.2 support `reasoning_effort: "none"` which disables the reasoning phase entirely. This can result in faster responses when reasoning is not needed. + - `gpt-5.2-none` - GPT-5.2 with reasoning disabled + - `gpt-5.1-none` - GPT-5.1 with reasoning disabled +- **4 new unit tests** for "none" reasoning behavior (now 197 total unit tests). + +### Technical Details +- `getReasoningConfig()` now detects GPT-5.1 general purpose models (not Codex variants) and allows "none" to pass through. +- GPT-5.2 inherits "none" support as it's newer than GPT-5.1. +- Codex variants (gpt-5.1-codex, gpt-5.1-codex-max, gpt-5.1-codex-mini) do NOT support "none": + - Codex and Codex Max: "none" auto-converts to "low" + - Codex Mini: "none" auto-converts to "medium" (as before) +- Documentation updated with complete reasoning effort support matrix per model family. + +### References +- **OpenAI API docs** (`platform.openai.com/docs/api-reference/chat/create`): "gpt-5.1 defaults to none, which does not perform reasoning. The supported reasoning values for gpt-5.1 are none, low, medium, and high." +- **Codex CLI** (`codex-rs/protocol/src/openai_models.rs`): `ReasoningEffort` enum includes `None` variant with `#[serde(rename_all = "lowercase")]` serialization to `"none"`. +- **Codex CLI** (`codex-rs/core/src/client.rs`): Request builder passes `ReasoningEffort::None` through to API without validation/rejection. +- **Codex CLI** (`docs/config.md`): Documents `model_reasoning_effort = "none"` as valid config option. + +### Notes +- This plugin defaults to "medium" for better coding assistance; users must explicitly set "none" if desired. + ## [4.1.0] - 2025-12-11 **Feature release**: GPT 5.2 model support and image input capabilities. diff --git a/docs/configuration.md b/docs/configuration.md index 3c5bbe9..7ee31d3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -46,28 +46,35 @@ Complete reference for configuring the OpenCode OpenAI Codex Auth Plugin. Controls computational effort for reasoning. -**GPT-5 Values:** -- `minimal` - Fastest, least reasoning +**GPT-5.2 Values** (per OpenAI API docs and Codex CLI `ReasoningEffort` enum): +- `none` - No dedicated reasoning phase (disables reasoning) +- `low` - Light reasoning +- `medium` - Balanced (default) +- `high` - Deep reasoning +- `xhigh` - Extra depth for long-horizon tasks + +**GPT-5.1 Values** (per OpenAI API docs and Codex CLI `ReasoningEffort` enum): +- `none` - No dedicated reasoning phase (disables reasoning) - `low` - Light reasoning - `medium` - Balanced (default) - `high` - Deep reasoning -**GPT-5-Codex Values:** +**GPT-5.1-Codex / GPT-5.1-Codex-Max Values:** - `low` - Fastest for code - `medium` - Balanced (default) - `high` - Maximum code quality +- `xhigh` - Extra depth (Codex Max only) -**GPT-5.1-Codex-Max Values:** -- `none` - No dedicated reasoning phase -- `low` - Light reasoning -- `medium` - Balanced -- `high` - Deep reasoning (default for this family) -- `xhigh` - Extra depth for long-horizon tasks +**GPT-5.1-Codex-Mini Values:** +- `medium` - Balanced (default) +- `high` - Maximum code quality **Notes**: +- `none` is supported for GPT-5.2 and GPT-5.1 (general purpose) per OpenAI API documentation +- `none` is NOT supported for Codex variants - it auto-converts to `low` for Codex or `medium` for Codex Mini - `minimal` auto-converts to `low` for Codex models -- `gpt-5-codex-mini*` and `gpt-5.1-codex-mini*` only support `medium` or `high`; lower settings are clamped to `medium` and `xhigh` downgrades to `high` -- Codex Max supports `none` and `xhigh` and defaults to `high` when not specified +- `xhigh` is only supported for GPT-5.2 and GPT-5.1-Codex-Max; other models downgrade to `high` +- Codex Mini only supports `medium` or `high`; lower settings clamp to `medium` **Example:** ```json diff --git a/lib/request/helpers/model-map.ts b/lib/request/helpers/model-map.ts index e748f91..47fed19 100644 --- a/lib/request/helpers/model-map.ts +++ b/lib/request/helpers/model-map.ts @@ -30,9 +30,10 @@ export const MODEL_MAP: Record = { "gpt-5.1-codex-max-xhigh": "gpt-5.1-codex-max", // ============================================================================ - // GPT-5.2 Models (same reasoning support as Codex Max: low/medium/high/xhigh) + // GPT-5.2 Models (supports none/low/medium/high/xhigh per OpenAI API docs) // ============================================================================ "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", @@ -46,9 +47,10 @@ export const MODEL_MAP: Record = { "gpt-5.1-codex-mini-high": "gpt-5.1-codex-mini", // ============================================================================ - // GPT-5.1 General Purpose Models + // GPT-5.1 General Purpose Models (supports none/low/medium/high per OpenAI API docs) // ============================================================================ "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", diff --git a/lib/request/request-transformer.ts b/lib/request/request-transformer.ts index 70995dc..6b0c87f 100644 --- a/lib/request/request-transformer.ts +++ b/lib/request/request-transformer.ts @@ -146,10 +146,26 @@ export function getReasoningConfig( (normalizedName.includes("nano") || normalizedName.includes("mini")); + // GPT-5.1 general purpose (not codex variants) - supports "none" per OpenAI API docs + const isGpt51General = + (normalizedName.includes("gpt-5.1") || normalizedName.includes("gpt 5.1")) && + !isCodex && + !isCodexMax && + !isCodexMini; + // GPT 5.2 and Codex Max support xhigh reasoning const supportsXhigh = isGpt52 || isCodexMax; + // GPT 5.1 and GPT 5.2 support "none" reasoning per: + // - OpenAI API docs: "gpt-5.1 defaults to none, supports: none, low, medium, high" + // - Codex CLI: ReasoningEffort enum includes None variant (codex-rs/protocol/src/openai_models.rs) + // - Codex CLI: docs/config.md lists "none" as valid for model_reasoning_effort + // - gpt-5.2 (being newer) also supports: none, low, medium, high, xhigh + const supportsNone = isGpt52 || isGpt51General; + // Default based on model type (Codex CLI defaults) + // Note: OpenAI docs say gpt-5.1 defaults to "none", but we default to "medium" + // for better coding assistance unless user explicitly requests "none" const defaultEffort: ReasoningConfig["effort"] = isCodexMini ? "medium" : supportsXhigh @@ -178,6 +194,12 @@ export function getReasoningConfig( effort = "high"; } + // For models that don't support "none", upgrade to "low" + // (Codex models don't support "none" - only GPT-5.1 and GPT-5.2 general purpose do) + if (!supportsNone && effort === "none") { + effort = "low"; + } + // Normalize "minimal" to "low" for Codex families // Codex CLI presets are low/medium/high (or xhigh for Codex Max) if (isCodex && effort === "minimal") { diff --git a/package-lock.json b/package-lock.json index 18c2e3b..49a9cd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -511,6 +511,7 @@ "resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz", "integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==", "license": "MIT", + "peer": true, "dependencies": { "@oslojs/binary": "1.0.0" } @@ -519,13 +520,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz", "integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@oslojs/crypto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.1.tgz", "integrity": "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==", "license": "MIT", + "peer": true, "dependencies": { "@oslojs/asn1": "1.0.0", "@oslojs/binary": "1.0.0" @@ -535,13 +538,15 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@oslojs/jwt": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@oslojs/jwt/-/jwt-0.2.0.tgz", "integrity": "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==", "license": "MIT", + "peer": true, "dependencies": { "@oslojs/encoding": "0.4.1" } @@ -550,7 +555,8 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz", "integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/@polka/url": { "version": "1.0.0-next.29", @@ -903,7 +909,6 @@ "integrity": "sha512-d2L25Y4j+W3ZlNAeMKcy7yDsK425ibcAOO2t7aPTz6gNMH0z2GThtwENCDc0d/Pw9wgyRqE5Px1wkV7naz8ang==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.13.0" } @@ -1280,7 +1285,6 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.10.4.tgz", "integrity": "sha512-YG/fo7zlU3KwrBL5vDpWKisLYiM+nVstBQqfr7gCPbSYURnNEP9BDxEMz8KfsDR9JX0lJWDRNc6nXX31v7ZEyg==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -1377,7 +1381,6 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -1613,7 +1616,6 @@ "integrity": "sha512-ZWyE8YXEXqJrrSLvYgrRP7p62OziLW7xI5HYGWFzOvupfAlrLvURSzv/FyGyy0eidogEM3ujU+kUG1zuHgb6Ug==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.5.0", @@ -1719,7 +1721,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", diff --git a/package.json b/package.json index 918f998..7934447 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "opencode-openai-codex-auth", - "version": "4.1.0", + "version": "4.1.1", "description": "OpenAI ChatGPT (Codex backend) OAuth auth plugin for opencode - use your ChatGPT Plus/Pro subscription instead of API credits", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/test/request-transformer.test.ts b/test/request-transformer.test.ts index 025d6ab..9add464 100644 --- a/test/request-transformer.test.ts +++ b/test/request-transformer.test.ts @@ -825,6 +825,62 @@ describe('Request Transformer Module', () => { expect(result.reasoning?.effort).toBe('high'); }); + it('should preserve none for GPT-5.2', async () => { + const body: RequestBody = { + model: 'gpt-5.2-none', + input: [], + }; + const userConfig: UserConfig = { + global: { reasoningEffort: 'none' }, + models: {}, + }; + const result = await transformRequestBody(body, codexInstructions, userConfig); + expect(result.model).toBe('gpt-5.2'); + expect(result.reasoning?.effort).toBe('none'); + }); + + it('should preserve none for GPT-5.1 general purpose', async () => { + const body: RequestBody = { + model: 'gpt-5.1-none', + input: [], + }; + const userConfig: UserConfig = { + global: { reasoningEffort: 'none' }, + models: {}, + }; + const result = await transformRequestBody(body, codexInstructions, userConfig); + expect(result.model).toBe('gpt-5.1'); + expect(result.reasoning?.effort).toBe('none'); + }); + + it('should upgrade none to low for GPT-5.1-codex (codex does not support none)', async () => { + const body: RequestBody = { + model: 'gpt-5.1-codex', + input: [], + }; + const userConfig: UserConfig = { + global: { reasoningEffort: 'none' }, + models: {}, + }; + const result = await transformRequestBody(body, codexInstructions, userConfig); + expect(result.model).toBe('gpt-5.1-codex'); + expect(result.reasoning?.effort).toBe('low'); + }); + + it('should upgrade none to low for GPT-5.1-codex-max (codex max does not support none)', async () => { + const body: RequestBody = { + model: 'gpt-5.1-codex-max', + input: [], + }; + const userConfig: UserConfig = { + global: { reasoningEffort: 'none' }, + models: {}, + }; + const result = await transformRequestBody(body, codexInstructions, userConfig); + expect(result.model).toBe('gpt-5.1-codex-max'); + expect(result.reasoning?.effort).toBe('low'); + }); + it('should preserve minimal for non-codex models', async () => { const body: RequestBody = { model: 'gpt-5',