// --------------------------------------------------------------------------- // Reasoning option parsing // // The MCP `reasoning` parameter is a hardcoded allow-list of `gpt-5.4` model // variants paired with a Codex reasoning-effort level. Everything flowing // through the tools is one of the exact strings in REASONING_OPTIONS — we // split it into `{ model, effort }` at the boundary so the adapter chain can // pass the two fields independently to Codex (`reasoningEffort` on // thread/start, `effort` on turn/start). // --------------------------------------------------------------------------- export type ReasoningEffortLevel = 'low' | 'medium' | 'high' | 'xhigh'; /** The only model we expose. Hardcoded — do not add variants without intent. */ export const ALLOWED_MODEL = 'gpt-5.4'; /** * The full set of accepted `reasoning` values. Order matters for display: * medium/high first (the common cases), xhigh next (exceptional research), * low last (rare, kept for completeness). */ export const REASONING_OPTIONS = [ 'gpt-5.4(medium)', 'gpt-5.4(high)', 'gpt-5.4(xhigh)', 'gpt-5.4(low)', ] as const; export type ReasoningOption = (typeof REASONING_OPTIONS)[number]; const REASONING_PATTERN = /^(gpt-5\.4)\((low|medium|high|xhigh)\)$/; export interface ParsedReasoning { model: string; effort: ReasoningEffortLevel; } export function isReasoningOption(value: unknown): value is ReasoningOption { return typeof value === 'string' && (REASONING_OPTIONS as readonly string[]).includes(value); } /** * Parse a `reasoning` value such as `gpt-5.4(high)` into its model id and * reasoning-effort level. Throws on any value not in {@link REASONING_OPTIONS}. */ export function parseReasoning(value: string): ParsedReasoning { const match = REASONING_PATTERN.exec(value); if (!match) { throw new Error( `Invalid reasoning option "${value}". Allowed: ${REASONING_OPTIONS.join(', ')}`, ); } return { model: match[1]!, effort: match[2] as ReasoningEffortLevel, }; }