feat(openai-native-codex): remove service tier logic; stop forcing minimal effort; add request timeout; improve auth.json error guidance; update ChatGPT link; clear reasoningEffort on model change\n\n- Remove service_tier handling entirely for Codex (server decides tier)\n- Do not auto-default GPT-5 to minimal for Codex; use model/user defaults only\n- Add AbortController using getApiRequestTimeout() to prevent hanging requests\n- Improve auth.json error messages with Codex CLI guidance\n- Update settings link to chatgpt.com\n- Clear reasoningEffort on model change for Codex like native OpenAI

This commit is contained in:
Hannes Rudolph 2025-09-25 17:06:00 -06:00
parent 353c83276b
commit 43c9f576c7
4 changed files with 28 additions and 26 deletions

View file

@ -9,6 +9,7 @@ import { ApiStream, ApiStreamUsageChunk } from "../transform/stream"
import { getModelParams } from "../transform/model-params"
// Provider prompt content as a TS string module (no loader required)
import codexPromptContent, { overridePrompt } from "./openai-native-codex.prompt"
import { getApiRequestTimeout } from "./utils/timeout-config"
import {
type ModelInfo,
@ -110,14 +111,18 @@ export class OpenAiNativeCodexHandler extends BaseProvider {
try {
raw = await fs.readFile(explicitPath, "utf8")
} catch (e: any) {
throw new Error(`Failed to load ChatGPT OAuth credentials at ${explicitPath}: ${e?.message || e}`)
throw new Error(
`Failed to load ChatGPT OAuth credentials at ${explicitPath}: ${e?.message || e}. Tip: authenticate with the Codex CLI (e.g., "codex login") to create auth.json.`,
)
}
let j: any
try {
j = JSON.parse(raw)
} catch (e: any) {
throw new Error(`Failed to parse ChatGPT OAuth credentials JSON at ${explicitPath}: ${e?.message || e}`)
throw new Error(
`Failed to parse ChatGPT OAuth credentials JSON at ${explicitPath}: ${e?.message || e}. Tip: ensure the file is valid JSON or re-authenticate with "codex login" to regenerate it.`,
)
}
const tokens = (j?.tokens as any) || {}
@ -263,13 +268,7 @@ export class OpenAiNativeCodexHandler extends BaseProvider {
// - Regular "gpt-5" should default to minimal reasoning unless explicitly overridden in settings.
// - The "gpt-5-codex" variant should NOT force minimal; use provided/default effort.
let effectiveEffort: ReasoningEffortWithMinimal | undefined = reasoningEffort
const explicitEffortProvided = typeof (this.options.reasoningEffort as any) === "string"
if (!explicitEffortProvided && model.id === "gpt-5") {
effectiveEffort = "minimal"
}
const requestedTier = (this.options.openAiNativeServiceTier as ServiceTier | undefined) || undefined
const allowedTierNames = new Set(model.info.tiers?.map((t) => t.name).filter(Boolean) || [])
const body: any = {
model: model.id,
input: formattedInput,
@ -286,9 +285,6 @@ export class OpenAiNativeCodexHandler extends BaseProvider {
}),
// ChatGPT codex/responses does not support previous_response_id (stateless).
// Preserve continuity by sending curated prior items in `input`.
...(requestedTier && (requestedTier === "default" || allowedTierNames.has(requestedTier))
? { service_tier: requestedTier }
: {}),
}
if (model.info.supportsVerbosity === true) {
body.text = { verbosity: (verbosity || "medium") as VerbosityLevel }
@ -307,11 +303,16 @@ export class OpenAiNativeCodexHandler extends BaseProvider {
}
if (this.chatgptAccountId) headers["chatgpt-account-id"] = this.chatgptAccountId
let timeoutId: ReturnType<typeof setTimeout> | undefined
try {
const timeoutMs = getApiRequestTimeout()
const controller = new AbortController()
timeoutId = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : undefined
const response = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(requestBody),
signal: controller.signal,
})
if (!response.ok) {
@ -468,7 +469,12 @@ export class OpenAiNativeCodexHandler extends BaseProvider {
} catch (err) {
throw err as Error
} finally {
// no-op
// Clear timeout if set
try {
if (typeof timeoutId !== "undefined") {
clearTimeout(timeoutId as any)
}
} catch {}
}
}
}

View file

@ -788,8 +788,11 @@ const ApiOptions = ({
}
// Clear reasoning effort when switching models to allow the new model's default to take effect
// This is especially important for GPT-5 models which default to "medium"
if (selectedProvider === "openai-native") {
// Applies to both OpenAI Native and ChatGPT Codex providers
if (
selectedProvider === "openai-native" ||
selectedProvider === "openai-native-codex"
) {
setApiConfigurationField("reasoningEffort", undefined)
}
}}>

View file

@ -116,18 +116,11 @@ export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, mod
? (["disable", ...baseAvailableOptions] as ReasoningEffortOption[])
: (baseAvailableOptions as ReadonlyArray<ReasoningEffortOption>)
// Default reasoning effort - use model's default if available
// Special-case for ChatGPT Codex "gpt-5": default to "minimal" unless user overrides
// Default reasoning effort - use model's default if available (no special-case overrides)
const modelDefaultReasoningEffort = modelInfo?.reasoningEffort as ReasoningEffortWithMinimal | undefined
// Special-case for ChatGPT Codex "gpt-5": default to "minimal" unless user overrides
const defaultReasoningEffort: ReasoningEffortOption =
apiConfiguration.apiProvider === "openai-native-codex" &&
selectedModelId === "gpt-5" &&
isReasoningEffortSupported
? "minimal"
: modelInfo?.requiredReasoningEffort
? modelDefaultReasoningEffort || "medium"
: "disable"
const defaultReasoningEffort: ReasoningEffortOption = modelInfo?.requiredReasoningEffort
? modelDefaultReasoningEffort || "medium"
: "disable"
// Current reasoning effort from settings, or fall back to default
const storedReasoningEffort = apiConfiguration.reasoningEffort as ReasoningEffortOption | undefined
const currentReasoningEffort: ReasoningEffortOption = storedReasoningEffort || defaultReasoningEffort

View file

@ -43,7 +43,7 @@ export const OpenAiNativeCodex: React.FC<OpenAiNativeCodexProps> = ({ apiConfigu
</div>
<VSCodeLink
href="https://chat.openai.com"
href="https://chatgpt.com"
className="text-vscode-textLink-foreground mt-2 inline-block text-xs">
Learn more about ChatGPT
</VSCodeLink>