diff --git a/packages/agent/src/types.ts b/packages/agent/src/types.ts index ad4da188..46da1492 100644 --- a/packages/agent/src/types.ts +++ b/packages/agent/src/types.ts @@ -25,7 +25,7 @@ export interface Attachment { /** * Thinking/reasoning level for models that support it. - * Note: "xhigh" is only supported by OpenAI codex-max models. + * Note: "xhigh" is only supported by OpenAI gpt-5.1-codex-max, gpt-5.2, and gpt-5.2-codex models. */ export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index b14ab39d..77e36a29 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -98,6 +98,19 @@ export interface SessionStats { cost: number; } +// ============================================================================ +// Constants +// ============================================================================ + +/** Models that support xhigh thinking level */ +const XHIGH_MODELS = ["gpt-5.1-codex-max", "gpt-5.2", "gpt-5.2-codex"]; + +/** Standard thinking levels */ +const THINKING_LEVELS: ThinkingLevel[] = ["off", "minimal", "low", "medium", "high"]; + +/** Thinking levels including xhigh (for supported models) */ +const THINKING_LEVELS_WITH_XHIGH: ThinkingLevel[] = ["off", "minimal", "low", "medium", "high", "xhigh"]; + // ============================================================================ // AgentSession Class // ============================================================================ @@ -637,12 +650,7 @@ export class AgentSession { cycleThinkingLevel(): ThinkingLevel | null { if (!this.supportsThinking()) return null; - const modelId = this.model?.id || ""; - const supportsXhigh = modelId.includes("codex-max"); - const levels: ThinkingLevel[] = supportsXhigh - ? ["off", "minimal", "low", "medium", "high", "xhigh"] - : ["off", "minimal", "low", "medium", "high"]; - + const levels = this.getAvailableThinkingLevels(); const currentIndex = levels.indexOf(this.thinkingLevel); const nextIndex = (currentIndex + 1) % levels.length; const nextLevel = levels[nextIndex]; @@ -651,6 +659,21 @@ export class AgentSession { return nextLevel; } + /** + * Get available thinking levels for current model. + */ + getAvailableThinkingLevels(): ThinkingLevel[] { + return this.supportsXhighThinking() ? THINKING_LEVELS_WITH_XHIGH : THINKING_LEVELS; + } + + /** + * Check if current model supports xhigh thinking level. + */ + supportsXhighThinking(): boolean { + const modelId = this.model?.id || ""; + return XHIGH_MODELS.some((m) => modelId === m || modelId.endsWith(`/${m}`)); + } + /** * Check if current model supports thinking/reasoning. */ diff --git a/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts b/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts index 0c0a86a2..069de5fb 100644 --- a/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts @@ -3,28 +3,40 @@ import { Container, type SelectItem, SelectList } from "@mariozechner/pi-tui"; import { getSelectListTheme } from "../theme/theme.js"; import { DynamicBorder } from "./dynamic-border.js"; +const LEVEL_DESCRIPTIONS: Record = { + off: "No reasoning", + minimal: "Very brief reasoning (~1k tokens)", + low: "Light reasoning (~2k tokens)", + medium: "Moderate reasoning (~8k tokens)", + high: "Deep reasoning (~16k tokens)", + xhigh: "Maximum reasoning (~32k tokens)", +}; + /** * Component that renders a thinking level selector with borders */ export class ThinkingSelectorComponent extends Container { private selectList: SelectList; - constructor(currentLevel: ThinkingLevel, onSelect: (level: ThinkingLevel) => void, onCancel: () => void) { + constructor( + currentLevel: ThinkingLevel, + availableLevels: ThinkingLevel[], + onSelect: (level: ThinkingLevel) => void, + onCancel: () => void, + ) { super(); - const thinkingLevels: SelectItem[] = [ - { value: "off", label: "off", description: "No reasoning" }, - { value: "minimal", label: "minimal", description: "Very brief reasoning (~1k tokens)" }, - { value: "low", label: "low", description: "Light reasoning (~2k tokens)" }, - { value: "medium", label: "medium", description: "Moderate reasoning (~8k tokens)" }, - { value: "high", label: "high", description: "Deep reasoning (~16k tokens)" }, - ]; + const thinkingLevels: SelectItem[] = availableLevels.map((level) => ({ + value: level, + label: level, + description: LEVEL_DESCRIPTIONS[level], + })); // Add top border this.addChild(new DynamicBorder()); // Create selector - this.selectList = new SelectList(thinkingLevels, 5, getSelectListTheme()); + this.selectList = new SelectList(thinkingLevels, thinkingLevels.length, getSelectListTheme()); // Preselect current level const currentIndex = thinkingLevels.findIndex((item) => item.value === currentLevel); diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 90008472..9c651a3b 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -1301,6 +1301,7 @@ export class InteractiveMode { this.showSelector((done) => { const selector = new ThinkingSelectorComponent( this.session.thinkingLevel, + this.session.getAvailableThinkingLevels(), (level) => { this.session.setThinkingLevel(level); this.updateEditorBorderColor();