From fbdd46389c3a0c03b62f5e9eabe31a85044ef8ce Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Thu, 9 Jul 2026 22:30:53 +0200 Subject: [PATCH] feat(ai): add max thinking level --- packages/agent/CHANGELOG.md | 4 + packages/agent/README.md | 2 +- packages/agent/src/types.ts | 6 +- packages/ai/CHANGELOG.md | 4 + packages/ai/README.md | 6 +- packages/ai/scripts/generate-models.ts | 45 +++++++--- packages/ai/src/api/anthropic-messages.ts | 3 +- packages/ai/src/api/azure-openai-responses.ts | 2 +- .../ai/src/api/bedrock-converse-stream.ts | 11 ++- packages/ai/src/api/google-generative-ai.ts | 2 +- packages/ai/src/api/google-vertex.ts | 2 +- packages/ai/src/api/openai-codex-responses.ts | 2 +- packages/ai/src/api/openai-completions.ts | 2 +- packages/ai/src/api/openai-responses.ts | 2 +- packages/ai/src/api/simple-options.ts | 4 +- packages/ai/src/models.ts | 4 +- .../ai/src/providers/amazon-bedrock.models.ts | 52 ++++++----- packages/ai/src/providers/anthropic.models.ts | 10 ++- .../azure-openai-responses.models.ts | 8 +- .../providers/cloudflare-ai-gateway.models.ts | 10 ++- packages/ai/src/providers/deepseek.models.ts | 4 +- packages/ai/src/providers/fireworks.models.ts | 4 +- .../ai/src/providers/github-copilot.models.ts | 9 +- .../ai/src/providers/openai-codex.models.ts | 6 +- packages/ai/src/providers/openai.models.ts | 8 +- .../ai/src/providers/opencode-go.models.ts | 6 +- packages/ai/src/providers/opencode.models.ts | 16 ++-- .../ai/src/providers/openrouter.models.ts | 30 ++++--- .../src/providers/vercel-ai-gateway.models.ts | 10 ++- .../ai/src/providers/zai-coding-cn.models.ts | 2 +- packages/ai/src/providers/zai.models.ts | 2 +- packages/ai/src/types.ts | 2 +- .../ai/test/codex-websocket-cached-probe.ts | 13 ++- .../ai/test/github-copilot-anthropic.test.ts | 8 +- packages/ai/test/max-thinking.test.ts | 89 +++++++++++++++++++ .../openai-completions-tool-choice.test.ts | 4 +- packages/ai/test/supports-xhigh.test.ts | 54 +++++++---- packages/coding-agent/CHANGELOG.md | 4 + packages/coding-agent/README.md | 2 +- packages/coding-agent/docs/custom-provider.md | 7 +- packages/coding-agent/docs/extensions.md | 2 +- packages/coding-agent/docs/models.md | 7 +- packages/coding-agent/docs/rpc.md | 4 +- packages/coding-agent/docs/sdk.md | 2 +- packages/coding-agent/docs/settings.md | 2 +- packages/coding-agent/docs/themes.md | 8 +- packages/coding-agent/docs/tui.md | 2 +- packages/coding-agent/docs/usage.md | 2 +- .../examples/extensions/preset.ts | 4 +- packages/coding-agent/src/cli/args.ts | 4 +- .../coding-agent/src/core/model-registry.ts | 1 + .../coding-agent/src/core/settings-manager.ts | 7 +- .../components/settings-selector.ts | 3 +- .../components/thinking-selector.ts | 3 +- .../src/modes/interactive/theme/dark.json | 1 + .../src/modes/interactive/theme/light.json | 1 + .../modes/interactive/theme/theme-schema.json | 8 +- .../src/modes/interactive/theme/theme.ts | 18 +++- .../coding-agent/test/max-thinking.test.ts | 45 ++++++++++ .../coding-agent/test/model-resolver.test.ts | 4 +- .../agent-session-model-extension.test.ts | 20 +++++ 61 files changed, 441 insertions(+), 168 deletions(-) create mode 100644 packages/ai/test/max-thinking.test.ts create mode 100644 packages/coding-agent/test/max-thinking.test.ts diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index 71f4775c..fd0fffd0 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added the `max` model thinking level after `xhigh`. + ## [0.80.5] - 2026-07-09 ## [0.80.4] - 2026-07-09 diff --git a/packages/agent/README.md b/packages/agent/README.md index f0fedb81..17eecea5 100644 --- a/packages/agent/README.md +++ b/packages/agent/README.md @@ -164,7 +164,7 @@ const agent = new Agent({ initialState: { systemPrompt: string, model: Model, - thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh", + thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max", tools: AgentTool[], messages: AgentMessage[], }, diff --git a/packages/agent/src/types.ts b/packages/agent/src/types.ts index abfa3de6..37ad9790 100644 --- a/packages/agent/src/types.ts +++ b/packages/agent/src/types.ts @@ -283,10 +283,10 @@ export interface AgentLoopConfig extends SimpleStreamOptions { /** * Thinking/reasoning level for models that support it. - * Note: "xhigh" is only supported by selected model families. Use model thinking-level metadata - * from @earendil-works/pi-ai to detect support for a concrete model. + * Note: "xhigh" and "max" are only supported by selected model families. Use model + * thinking-level metadata from @earendil-works/pi-ai to detect support for a concrete model. */ -export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; +export type ThinkingLevel = "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; /** * Extensible interface for custom app messages. diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 6d006c29..65d4b9f0 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added a separate opt-in `max` thinking level, including native `xhigh` and `max` support for GPT-5.6 and Anthropic adaptive-thinking effort metadata matching Anthropic's documentation: `max` on all adaptive Claude models, native `xhigh` on Opus 4.7/4.8, Sonnet 5, and Fable 5 only. + ### Fixed - Fixed post-compaction output-token budgeting to ignore stale assistant usage from before the compaction boundary ([#6464](https://github.com/earendil-works/pi/issues/6464)). diff --git a/packages/ai/README.md b/packages/ai/README.md index 239f559a..c9db20ac 100644 --- a/packages/ai/README.md +++ b/packages/ai/README.md @@ -730,7 +730,7 @@ if (model.reasoning) { const response = await models.completeSimple(model, { messages: [{ role: 'user', content: 'Solve: 2x + 5 = 13', timestamp: Date.now() }] }, { - reasoning: 'medium' // 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' + reasoning: 'medium' // 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' }); // Access thinking and text blocks @@ -743,6 +743,8 @@ for (const block of response.content) { } ``` +`xhigh` and `max` are model-specific, opt-in levels. Use `getSupportedThinkingLevels(model)` to determine whether a concrete model exposes either level; models such as GPT-5.6 can expose both. + ### Provider-Specific Options (stream/complete) `models.stream()`/`complete()` accept the owning API's full option set. Use `hasApi()` to narrow a dynamically looked-up model to its API for full option typing: @@ -999,7 +1001,7 @@ Custom models can carry `headers` (e.g. proxies behind bot detection) and `compa Some OpenAI-compatible servers do not understand the `developer` role used for reasoning-capable models. For those providers, set `compat.supportsDeveloperRole` to `false` so the system prompt is sent as a `system` message instead. If the server also does not support `reasoning_effort`, set `compat.supportsReasoningEffort` to `false` too. This commonly applies to Ollama, vLLM, SGLang, and similar OpenAI-compatible servers. -Use model-level `thinkingLevelMap` to describe model-specific thinking controls. Keys are pi thinking levels (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`). Missing keys use provider defaults, string values are sent to the provider, and `null` marks a level unsupported. +Use model-level `thinkingLevelMap` to describe model-specific thinking controls. Keys are pi thinking levels (`off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`). Missing standard levels through `high` use provider defaults; `xhigh` and `max` are opt-in and require a non-null map entry. String values are sent to the provider, `null` marks a level unsupported, and maps may skip levels. ```typescript const ollamaReasoningModel: Model<'openai-completions'> = { diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index 20c78a44..74ee764b 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -160,7 +160,7 @@ const ZAI_GLM52_THINKING_LEVEL_MAP = { low: "high", medium: "high", high: "high", - xhigh: "max", + max: "max", } as const; const OPENCODE_GO_GLM52_THINKING_LEVEL_MAP = { off: null, @@ -168,7 +168,7 @@ const OPENCODE_GO_GLM52_THINKING_LEVEL_MAP = { low: null, medium: null, high: "high", - xhigh: "max", + max: "max", } as const; const EAGER_TOOL_INPUT_STREAMING_UNSUPPORTED_ANTHROPIC_MODELS = new Set([ "github-copilot:claude-haiku-4.5", @@ -181,7 +181,7 @@ const DEEPSEEK_V4_THINKING_LEVEL_MAP = { low: null, medium: null, high: "high", - xhigh: "max", + max: "max", } as const; const ANT_LING_RING_THINKING_LEVEL_MAP = { @@ -235,7 +235,7 @@ const GITHUB_COPILOT_EXTENDED_CONTEXT_MODELS = new Set([ const GITHUB_COPILOT_THINKING_LEVEL_OVERRIDES = { "claude-opus-4.7": { minimal: "low" }, "claude-opus-4.8": { minimal: "low" }, - "claude-sonnet-4.6": { minimal: "low", xhigh: "max" }, + "claude-sonnet-4.6": { minimal: "low", max: "max" }, } satisfies Record["thinkingLevelMap"]>>; function mergeThinkingLevelMap(model: Model, map: NonNullable["thinkingLevelMap"]>): void { @@ -271,6 +271,16 @@ function supportsOpenAiXhigh(modelId: string): boolean { ); } +function supportsOpenAiMax(model: Model): boolean { + return ( + model.id.includes("gpt-5.6") && + (model.api === "openai-responses" || + model.api === "azure-openai-responses" || + model.api === "openai-codex-responses" || + model.api === "openai-completions") + ); +} + function isGoogleThinkingApi(model: Model): boolean { return model.api === "google-generative-ai" || model.api === "google-vertex"; } @@ -472,28 +482,41 @@ function applyThinkingLevelMetadata(model: Model): void { if (supportsOpenAiXhigh(model.id)) { mergeThinkingLevelMap(model, { xhigh: "xhigh" }); } + if (supportsOpenAiMax(model)) { + mergeThinkingLevelMap(model, { max: "max" }); + } if (model.provider === "openai" && model.id === "gpt-5.5") { mergeThinkingLevelMap(model, { minimal: null }); } if (model.id.endsWith("gpt-5.5-pro")) { mergeThinkingLevelMap(model, { off: null, minimal: null, low: null }); } - if (model.id.includes("opus-4-6") || model.id.includes("opus-4.6")) { - mergeThinkingLevelMap(model, { xhigh: "max" }); + // Anthropic adaptive-thinking effort support (per Anthropic adaptive thinking docs): + // - "max" is available on all adaptive-thinking Claude models. + // - "xhigh" is only available on Opus 4.7/4.8, Sonnet 5, and Fable 5. + if ( + model.id.includes("opus-4-6") || + model.id.includes("opus-4.6") || + model.id.includes("sonnet-4-6") || + model.id.includes("sonnet-4.6") + ) { + mergeThinkingLevelMap(model, { max: "max" }); } if ( model.id.includes("opus-4-7") || model.id.includes("opus-4.7") || model.id.includes("opus-4-8") || - model.id.includes("opus-4.8") + model.id.includes("opus-4.8") || + model.id.includes("sonnet-5") || + model.id.includes("sonnet.5") ) { - mergeThinkingLevelMap(model, { xhigh: "xhigh" }); + mergeThinkingLevelMap(model, { xhigh: "xhigh", max: "max" }); } if ( (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") && model.id.includes("fable-5") ) { - mergeThinkingLevelMap(model, { off: null, xhigh: "xhigh" }); + mergeThinkingLevelMap(model, { off: null, xhigh: "xhigh", max: "max" }); } if (model.api === "anthropic-messages" && isAnthropicAdaptiveThinkingModel(model.id)) { mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true }); @@ -505,7 +528,7 @@ function applyThinkingLevelMetadata(model: Model): void { mergeThinkingLevelMap( model, model.provider === "openrouter" - ? { ...DEEPSEEK_V4_THINKING_LEVEL_MAP, xhigh: "xhigh" } + ? { ...DEEPSEEK_V4_THINKING_LEVEL_MAP, xhigh: "xhigh", max: null } : DEEPSEEK_V4_THINKING_LEVEL_MAP, ); } @@ -544,7 +567,7 @@ function applyThinkingLevelMetadata(model: Model): void { mergeThinkingLevelMap(model, { xhigh: "xhigh" }); } if (model.provider === "fireworks" && model.id.includes("glm-5p2")) { - mergeThinkingLevelMap(model, { off: "none", minimal: null, low: "high", medium: "high", xhigh: "max" }); + mergeThinkingLevelMap(model, { off: "none", minimal: null, low: "high", medium: "high", max: "max" }); } if (model.provider === "opencode-go" && model.id === "glm-5.2") { mergeThinkingLevelMap(model, OPENCODE_GO_GLM52_THINKING_LEVEL_MAP); diff --git a/packages/ai/src/api/anthropic-messages.ts b/packages/ai/src/api/anthropic-messages.ts index 486be77c..2221ce82 100644 --- a/packages/ai/src/api/anthropic-messages.ts +++ b/packages/ai/src/api/anthropic-messages.ts @@ -742,7 +742,8 @@ export const stream: StreamFunction<"anthropic-messages", AnthropicOptions> = ( /** * Map ThinkingLevel to Anthropic effort levels for adaptive thinking. - * Note: effort "max" is only valid on Opus 4.6, while Opus 4.7+ and Fable 5 support "xhigh". + * Note: effort "max" is available on all adaptive-thinking Claude models, while native + * "xhigh" is only available on Opus 4.7/4.8, Sonnet 5, and Fable 5. */ function mapThinkingLevelToEffort( model: Model<"anthropic-messages">, diff --git a/packages/ai/src/api/azure-openai-responses.ts b/packages/ai/src/api/azure-openai-responses.ts index 04533dd7..b6fcd0b1 100644 --- a/packages/ai/src/api/azure-openai-responses.ts +++ b/packages/ai/src/api/azure-openai-responses.ts @@ -52,7 +52,7 @@ function formatAzureOpenAIError(error: unknown): string { // Azure OpenAI Responses-specific options export interface AzureOpenAIResponsesOptions extends StreamOptions { - reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh"; + reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; reasoningSummary?: "auto" | "detailed" | "concise" | null; azureApiVersion?: string; azureResourceName?: string; diff --git a/packages/ai/src/api/bedrock-converse-stream.ts b/packages/ai/src/api/bedrock-converse-stream.ts index e548f6fc..33494a9e 100644 --- a/packages/ai/src/api/bedrock-converse-stream.ts +++ b/packages/ai/src/api/bedrock-converse-stream.ts @@ -582,7 +582,9 @@ function supportsAdaptiveThinking(modelId: string, modelName?: string): boolean function supportsNativeXhighEffort(model: Model<"bedrock-converse-stream">): boolean { const candidates = getModelMatchCandidates(model.id, model.name); - return candidates.some((s) => s.includes("opus-4-7") || s.includes("opus-4-8") || s.includes("fable-5")); + return candidates.some( + (s) => s.includes("opus-4-7") || s.includes("opus-4-8") || s.includes("sonnet-5") || s.includes("fable-5"), + ); } function mapThinkingLevelToEffort( @@ -1025,11 +1027,12 @@ function buildAdditionalModelRequestFields( low: 2048, medium: 8192, high: 16384, - xhigh: 16384, // Claude doesn't support xhigh, clamp to high + xhigh: 16384, // Budget-based Claude clamps extended levels to high + max: 16384, }; - // Custom budgets override defaults (xhigh not in ThinkingBudgets, use high) - const level = options.reasoning === "xhigh" ? "high" : options.reasoning; + // Custom budgets only cover token-based levels through high. + const level = options.reasoning === "xhigh" || options.reasoning === "max" ? "high" : options.reasoning; const budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning]; return { diff --git a/packages/ai/src/api/google-generative-ai.ts b/packages/ai/src/api/google-generative-ai.ts index c40dce13..b971c219 100644 --- a/packages/ai/src/api/google-generative-ai.ts +++ b/packages/ai/src/api/google-generative-ai.ts @@ -400,7 +400,7 @@ function buildParams( return params; } -type ClampedThinkingLevel = Exclude; +type ClampedThinkingLevel = Exclude; function isGemma4Model(model: Model<"google-generative-ai">): boolean { return /gemma-?4/.test(model.id.toLowerCase()); diff --git a/packages/ai/src/api/google-vertex.ts b/packages/ai/src/api/google-vertex.ts index 3440030c..e6a10043 100644 --- a/packages/ai/src/api/google-vertex.ts +++ b/packages/ai/src/api/google-vertex.ts @@ -498,7 +498,7 @@ function buildParams( return params; } -type ClampedThinkingLevel = Exclude; +type ClampedThinkingLevel = Exclude; function isGemini3ProModel(model: Model<"google-generative-ai">): boolean { return /gemini-3(?:\.\d+)?-pro/.test(model.id.toLowerCase()); diff --git a/packages/ai/src/api/openai-codex-responses.ts b/packages/ai/src/api/openai-codex-responses.ts index 16734a75..772d1ae8 100644 --- a/packages/ai/src/api/openai-codex-responses.ts +++ b/packages/ai/src/api/openai-codex-responses.ts @@ -80,7 +80,7 @@ const CODEX_RESPONSE_STATUSES = new Set([ // ============================================================================ export interface OpenAICodexResponsesOptions extends StreamOptions { - reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh"; + reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; reasoningSummary?: "auto" | "concise" | "detailed" | "off" | "on" | null; serviceTier?: ResponseCreateParamsStreaming["service_tier"]; textVerbosity?: "low" | "medium" | "high"; diff --git a/packages/ai/src/api/openai-completions.ts b/packages/ai/src/api/openai-completions.ts index c1d9f933..32947db4 100644 --- a/packages/ai/src/api/openai-completions.ts +++ b/packages/ai/src/api/openai-completions.ts @@ -109,7 +109,7 @@ function isEncryptedReasoningDetail(detail: unknown): detail is OpenAIEncryptedR export interface OpenAICompletionsOptions extends StreamOptions { toolChoice?: "auto" | "none" | "required" | { type: "function"; function: { name: string } }; - reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh"; + reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; } interface OpenAICompatCacheControl { diff --git a/packages/ai/src/api/openai-responses.ts b/packages/ai/src/api/openai-responses.ts index 3f235268..ca0f845b 100644 --- a/packages/ai/src/api/openai-responses.ts +++ b/packages/ai/src/api/openai-responses.ts @@ -78,7 +78,7 @@ function formatOpenAIResponsesError(error: unknown): string { // OpenAI Responses-specific options export interface OpenAIResponsesOptions extends StreamOptions { - reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh"; + reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; reasoningSummary?: "auto" | "detailed" | "concise" | null; serviceTier?: ResponseCreateParamsStreaming["service_tier"]; } diff --git a/packages/ai/src/api/simple-options.ts b/packages/ai/src/api/simple-options.ts index f1bb29fd..55bfe8df 100644 --- a/packages/ai/src/api/simple-options.ts +++ b/packages/ai/src/api/simple-options.ts @@ -44,8 +44,8 @@ export function buildBaseOptions( }; } -export function clampReasoning(effort: ThinkingLevel | undefined): Exclude | undefined { - return effort === "xhigh" ? "high" : effort; +export function clampReasoning(effort: ThinkingLevel | undefined): Exclude | undefined { + return effort === "xhigh" || effort === "max" ? "high" : effort; } export function adjustMaxTokensForThinking( diff --git a/packages/ai/src/models.ts b/packages/ai/src/models.ts index f9cf27d3..3850814e 100644 --- a/packages/ai/src/models.ts +++ b/packages/ai/src/models.ts @@ -394,7 +394,7 @@ export function calculateCost(model: Model, usage: Usage return usage.cost; } -const EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = ["off", "minimal", "low", "medium", "high", "xhigh"]; +const EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = ["off", "minimal", "low", "medium", "high", "xhigh", "max"]; export function getSupportedThinkingLevels(model: Model): ModelThinkingLevel[] { if (!model.reasoning) return ["off"]; @@ -402,7 +402,7 @@ export function getSupportedThinkingLevels(model: Model) return EXTENDED_THINKING_LEVELS.filter((level) => { const mapped = model.thinkingLevelMap?.[level]; if (mapped === null) return false; - if (level === "xhigh") return mapped !== undefined; + if (level === "xhigh" || level === "max") return mapped !== undefined; return true; }); } diff --git a/packages/ai/src/providers/amazon-bedrock.models.ts b/packages/ai/src/providers/amazon-bedrock.models.ts index e154c08e..aaddca5f 100644 --- a/packages/ai/src/providers/amazon-bedrock.models.ts +++ b/packages/ai/src/providers/amazon-bedrock.models.ts @@ -79,7 +79,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -148,7 +148,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -166,7 +166,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -184,7 +184,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -219,6 +219,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -236,6 +237,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, @@ -270,7 +272,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 16.5, @@ -288,7 +290,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -323,6 +325,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3.3, @@ -340,6 +343,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, @@ -408,7 +412,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 11, @@ -460,7 +464,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5.5, @@ -478,7 +482,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5.5, @@ -496,7 +500,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5.5, @@ -531,6 +535,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3.3, @@ -548,6 +553,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2.2, @@ -565,7 +571,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -617,7 +623,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -635,7 +641,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -653,7 +659,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -688,6 +694,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -705,6 +712,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, @@ -773,7 +781,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -791,7 +799,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -826,6 +834,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -843,6 +852,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, @@ -1508,7 +1518,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -1577,7 +1587,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -1595,7 +1605,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -1613,7 +1623,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -1648,6 +1658,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -1665,6 +1676,7 @@ export const AMAZON_BEDROCK_MODELS = { provider: "amazon-bedrock", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, diff --git a/packages/ai/src/providers/anthropic.models.ts b/packages/ai/src/providers/anthropic.models.ts index bebe482d..23c79b3c 100644 --- a/packages/ai/src/providers/anthropic.models.ts +++ b/packages/ai/src/providers/anthropic.models.ts @@ -12,7 +12,7 @@ export const ANTHROPIC_MODELS = { baseUrl: "https://api.anthropic.com", compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -133,7 +133,7 @@ export const ANTHROPIC_MODELS = { baseUrl: "https://api.anthropic.com", compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -152,7 +152,7 @@ export const ANTHROPIC_MODELS = { baseUrl: "https://api.anthropic.com", compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -171,7 +171,7 @@ export const ANTHROPIC_MODELS = { baseUrl: "https://api.anthropic.com", compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -224,6 +224,7 @@ export const ANTHROPIC_MODELS = { baseUrl: "https://api.anthropic.com", compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -242,6 +243,7 @@ export const ANTHROPIC_MODELS = { baseUrl: "https://api.anthropic.com", compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, diff --git a/packages/ai/src/providers/azure-openai-responses.models.ts b/packages/ai/src/providers/azure-openai-responses.models.ts index 0566bad5..bb7c5159 100644 --- a/packages/ai/src/providers/azure-openai-responses.models.ts +++ b/packages/ai/src/providers/azure-openai-responses.models.ts @@ -613,7 +613,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = { provider: "azure-openai-responses", baseUrl: "", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -631,7 +631,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = { provider: "azure-openai-responses", baseUrl: "", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 1, @@ -649,7 +649,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = { provider: "azure-openai-responses", baseUrl: "", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -667,7 +667,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = { provider: "azure-openai-responses", baseUrl: "", reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2.5, diff --git a/packages/ai/src/providers/cloudflare-ai-gateway.models.ts b/packages/ai/src/providers/cloudflare-ai-gateway.models.ts index 9894a6c8..c0e1033c 100644 --- a/packages/ai/src/providers/cloudflare-ai-gateway.models.ts +++ b/packages/ai/src/providers/cloudflare-ai-gateway.models.ts @@ -120,7 +120,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = { baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -211,7 +211,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = { baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -230,7 +230,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = { baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -249,7 +249,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = { baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -304,6 +304,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = { baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -322,6 +323,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = { baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, diff --git a/packages/ai/src/providers/deepseek.models.ts b/packages/ai/src/providers/deepseek.models.ts index b9bcd95f..b0532ed6 100644 --- a/packages/ai/src/providers/deepseek.models.ts +++ b/packages/ai/src/providers/deepseek.models.ts @@ -12,7 +12,7 @@ export const DEEPSEEK_MODELS = { baseUrl: "https://api.deepseek.com", compat: {"supportsStore":false,"supportsDeveloperRole":false,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 0.14, @@ -31,7 +31,7 @@ export const DEEPSEEK_MODELS = { baseUrl: "https://api.deepseek.com", compat: {"supportsStore":false,"supportsDeveloperRole":false,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 0.435, diff --git a/packages/ai/src/providers/fireworks.models.ts b/packages/ai/src/providers/fireworks.models.ts index fc0ea1ce..1cc83bc8 100644 --- a/packages/ai/src/providers/fireworks.models.ts +++ b/packages/ai/src/providers/fireworks.models.ts @@ -66,7 +66,7 @@ export const FIREWORKS_MODELS = { baseUrl: "https://api.fireworks.ai/inference/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false}, reasoning: true, - thinkingLevelMap: {"off":"none","minimal":null,"low":"high","medium":"high","xhigh":"max"}, + thinkingLevelMap: {"off":"none","minimal":null,"low":"high","medium":"high","max":"max"}, input: ["text"], cost: { input: 1.4, @@ -229,7 +229,7 @@ export const FIREWORKS_MODELS = { baseUrl: "https://api.fireworks.ai/inference/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false}, reasoning: true, - thinkingLevelMap: {"off":"none","minimal":null,"low":"high","medium":"high","xhigh":"max"}, + thinkingLevelMap: {"off":"none","minimal":null,"low":"high","medium":"high","max":"max"}, input: ["text"], cost: { input: 2.1, diff --git a/packages/ai/src/providers/github-copilot.models.ts b/packages/ai/src/providers/github-copilot.models.ts index 12ebaf38..47a2f3d9 100644 --- a/packages/ai/src/providers/github-copilot.models.ts +++ b/packages/ai/src/providers/github-copilot.models.ts @@ -69,7 +69,7 @@ export const GITHUB_COPILOT_MODELS = { headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"}, compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -89,7 +89,7 @@ export const GITHUB_COPILOT_MODELS = { headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"}, input: ["text", "image"], cost: { input: 5, @@ -109,7 +109,7 @@ export const GITHUB_COPILOT_MODELS = { headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"}, input: ["text", "image"], cost: { input: 5, @@ -167,7 +167,7 @@ export const GITHUB_COPILOT_MODELS = { headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"}, compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"minimal":"low","xhigh":"max"}, + thinkingLevelMap: {"max":"max","minimal":"low"}, input: ["text", "image"], cost: { input: 3, @@ -187,6 +187,7 @@ export const GITHUB_COPILOT_MODELS = { headers: {"User-Agent":"GitHubCopilotChat/0.35.0","Editor-Version":"vscode/1.107.0","Editor-Plugin-Version":"copilot-chat/0.35.0","Copilot-Integration-Id":"vscode-chat"}, compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, diff --git a/packages/ai/src/providers/openai-codex.models.ts b/packages/ai/src/providers/openai-codex.models.ts index bccd7077..b0486987 100644 --- a/packages/ai/src/providers/openai-codex.models.ts +++ b/packages/ai/src/providers/openai-codex.models.ts @@ -83,7 +83,7 @@ export const OPENAI_CODEX_MODELS = { provider: "openai-codex", baseUrl: "https://chatgpt.com/backend-api", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"}, input: ["text", "image"], cost: { input: 1, @@ -101,7 +101,7 @@ export const OPENAI_CODEX_MODELS = { provider: "openai-codex", baseUrl: "https://chatgpt.com/backend-api", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"}, input: ["text", "image"], cost: { input: 5, @@ -119,7 +119,7 @@ export const OPENAI_CODEX_MODELS = { provider: "openai-codex", baseUrl: "https://chatgpt.com/backend-api", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"}, input: ["text", "image"], cost: { input: 2.5, diff --git a/packages/ai/src/providers/openai.models.ts b/packages/ai/src/providers/openai.models.ts index e28f3e7a..2da12b19 100644 --- a/packages/ai/src/providers/openai.models.ts +++ b/packages/ai/src/providers/openai.models.ts @@ -613,7 +613,7 @@ export const OPENAI_MODELS = { provider: "openai", baseUrl: "https://api.openai.com/v1", reasoning: true, - thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, + thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -631,7 +631,7 @@ export const OPENAI_MODELS = { provider: "openai", baseUrl: "https://api.openai.com/v1", reasoning: true, - thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, + thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 1, @@ -649,7 +649,7 @@ export const OPENAI_MODELS = { provider: "openai", baseUrl: "https://api.openai.com/v1", reasoning: true, - thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, + thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -667,7 +667,7 @@ export const OPENAI_MODELS = { provider: "openai", baseUrl: "https://api.openai.com/v1", reasoning: true, - thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, + thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2.5, diff --git a/packages/ai/src/providers/opencode-go.models.ts b/packages/ai/src/providers/opencode-go.models.ts index 3f899b9b..3e8709c8 100644 --- a/packages/ai/src/providers/opencode-go.models.ts +++ b/packages/ai/src/providers/opencode-go.models.ts @@ -12,7 +12,7 @@ export const OPENCODE_GO_MODELS = { baseUrl: "https://opencode.ai/zen/go/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 0.14, @@ -31,7 +31,7 @@ export const OPENCODE_GO_MODELS = { baseUrl: "https://opencode.ai/zen/go/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 1.74, @@ -68,7 +68,7 @@ export const OPENCODE_GO_MODELS = { baseUrl: "https://opencode.ai/zen/go/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 1.4, diff --git a/packages/ai/src/providers/opencode.models.ts b/packages/ai/src/providers/opencode.models.ts index 900a6bbe..ad18727a 100644 --- a/packages/ai/src/providers/opencode.models.ts +++ b/packages/ai/src/providers/opencode.models.ts @@ -30,7 +30,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen", compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -100,7 +100,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen", compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -119,7 +119,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen", compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -138,7 +138,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen", compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -191,6 +191,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen", compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -209,6 +210,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen", compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, @@ -227,7 +229,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 0.14, @@ -246,7 +248,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 0, @@ -265,7 +267,7 @@ export const OPENCODE_MODELS = { baseUrl: "https://opencode.ai/zen/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":"max"}, input: ["text"], cost: { input: 1.74, diff --git a/packages/ai/src/providers/openrouter.models.ts b/packages/ai/src/providers/openrouter.models.ts index 67cbbbf6..f2b0eebb 100644 --- a/packages/ai/src/providers/openrouter.models.ts +++ b/packages/ai/src/providers/openrouter.models.ts @@ -282,7 +282,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -301,7 +301,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -320,7 +320,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 30, @@ -339,7 +339,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -358,7 +358,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -413,6 +413,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -431,6 +432,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, @@ -791,7 +793,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter","requiresReasoningContentOnAssistantMessages":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":null,"xhigh":"xhigh"}, input: ["text"], cost: { input: 0.09, @@ -810,7 +812,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter","requiresReasoningContentOnAssistantMessages":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh"}, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","max":null,"xhigh":"xhigh"}, input: ["text"], cost: { input: 0.435, @@ -1486,7 +1488,7 @@ export const OPENROUTER_MODELS = { cacheWrite: 0, }, contextWindow: 1048576, - maxTokens: 512000, + maxTokens: 131072, } satisfies Model<"openai-completions">, "mistralai/codestral-2508": { id: "mistralai/codestral-2508", @@ -2804,7 +2806,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 1, @@ -2823,7 +2825,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 1, @@ -2842,7 +2844,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -2861,7 +2863,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -2880,7 +2882,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2.5, @@ -2899,7 +2901,7 @@ export const OPENROUTER_MODELS = { baseUrl: "https://openrouter.ai/api/v1", compat: {"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2.5, diff --git a/packages/ai/src/providers/vercel-ai-gateway.models.ts b/packages/ai/src/providers/vercel-ai-gateway.models.ts index ca03e0cd..48027249 100644 --- a/packages/ai/src/providers/vercel-ai-gateway.models.ts +++ b/packages/ai/src/providers/vercel-ai-gateway.models.ts @@ -522,7 +522,7 @@ export const VERCEL_AI_GATEWAY_MODELS = { baseUrl: "https://ai-gateway.vercel.sh", compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, + thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 10, @@ -609,7 +609,7 @@ export const VERCEL_AI_GATEWAY_MODELS = { baseUrl: "https://ai-gateway.vercel.sh", compat: {"forceAdaptiveThinking":true}, reasoning: true, - thinkingLevelMap: {"xhigh":"max"}, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -628,7 +628,7 @@ export const VERCEL_AI_GATEWAY_MODELS = { baseUrl: "https://ai-gateway.vercel.sh", compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -647,7 +647,7 @@ export const VERCEL_AI_GATEWAY_MODELS = { baseUrl: "https://ai-gateway.vercel.sh", compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 5, @@ -700,6 +700,7 @@ export const VERCEL_AI_GATEWAY_MODELS = { baseUrl: "https://ai-gateway.vercel.sh", compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -718,6 +719,7 @@ export const VERCEL_AI_GATEWAY_MODELS = { baseUrl: "https://ai-gateway.vercel.sh", compat: {"forceAdaptiveThinking":true}, reasoning: true, + thinkingLevelMap: {"xhigh":"xhigh","max":"max"}, input: ["text", "image"], cost: { input: 2, diff --git a/packages/ai/src/providers/zai-coding-cn.models.ts b/packages/ai/src/providers/zai-coding-cn.models.ts index cd13ebe3..d46a835d 100644 --- a/packages/ai/src/providers/zai-coding-cn.models.ts +++ b/packages/ai/src/providers/zai-coding-cn.models.ts @@ -84,7 +84,7 @@ export const ZAI_CODING_CN_MODELS = { baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"thinkingFormat":"zai","zaiToolStream":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":"high","medium":"high","high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":"high","medium":"high","high":"high","max":"max"}, input: ["text"], cost: { input: 0, diff --git a/packages/ai/src/providers/zai.models.ts b/packages/ai/src/providers/zai.models.ts index ba7f55c4..dd043ed7 100644 --- a/packages/ai/src/providers/zai.models.ts +++ b/packages/ai/src/providers/zai.models.ts @@ -84,7 +84,7 @@ export const ZAI_MODELS = { baseUrl: "https://api.z.ai/api/coding/paas/v4", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"thinkingFormat":"zai","zaiToolStream":true}, reasoning: true, - thinkingLevelMap: {"minimal":null,"low":"high","medium":"high","high":"high","xhigh":"max"}, + thinkingLevelMap: {"minimal":null,"low":"high","medium":"high","high":"high","max":"max"}, input: ["text"], cost: { input: 0, diff --git a/packages/ai/src/types.ts b/packages/ai/src/types.ts index e4f263f4..43b2303a 100644 --- a/packages/ai/src/types.ts +++ b/packages/ai/src/types.ts @@ -71,7 +71,7 @@ export type KnownImagesProvider = "openrouter"; export type ImagesProviderId = KnownImagesProvider | string; -export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh"; +export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; export type ModelThinkingLevel = "off" | ThinkingLevel; export type ThinkingLevelMap = Partial>; export type ChatTemplateKwargValue = diff --git a/packages/ai/test/codex-websocket-cached-probe.ts b/packages/ai/test/codex-websocket-cached-probe.ts index d8154ac1..b5104080 100644 --- a/packages/ai/test/codex-websocket-cached-probe.ts +++ b/packages/ai/test/codex-websocket-cached-probe.ts @@ -19,7 +19,7 @@ import { import { getModel } from "../src/compat.ts"; import type { AssistantMessage, Context, Message, Model, Tool, ToolResultMessage, Transport } from "../src/types.ts"; -type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh"; +type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; interface Args { turns: number; @@ -58,7 +58,14 @@ function parseArgs(argv: string[]): Args { break; case "--reasoning": { const value = required(argv[++i], arg); - if (value !== "minimal" && value !== "low" && value !== "medium" && value !== "high" && value !== "xhigh") { + if ( + value !== "minimal" && + value !== "low" && + value !== "medium" && + value !== "high" && + value !== "xhigh" && + value !== "max" + ) { throw new Error(`Invalid --reasoning: ${value}`); } reasoning = value; @@ -90,7 +97,7 @@ function printHelp(): void { Options: --turns Number of user turns. Default: ${DEFAULT_TURNS} --transport sse | websocket | websocket-cached | auto. Default: websocket-cached - --reasoning minimal | low | medium | high | xhigh. Default: low + --reasoning minimal | low | medium | high | xhigh | max. Default: low --max-tokens Max output tokens per model request. Default: ${DEFAULT_MAX_TOKENS} --session-id Session id for websocket/cache state `); diff --git a/packages/ai/test/github-copilot-anthropic.test.ts b/packages/ai/test/github-copilot-anthropic.test.ts index 74a95418..c16547e6 100644 --- a/packages/ai/test/github-copilot-anthropic.test.ts +++ b/packages/ai/test/github-copilot-anthropic.test.ts @@ -57,12 +57,14 @@ describe("Copilot Claude via Anthropic Messages", () => { it("applies Copilot-specific adaptive thinking effort overrides", () => { const opus47 = getModel("github-copilot", "claude-opus-4.7"); - expect(opus47.thinkingLevelMap).toMatchObject({ minimal: "low", xhigh: "xhigh" }); + expect(opus47.thinkingLevelMap).toMatchObject({ minimal: "low", xhigh: "xhigh", max: "max" }); expect(getSupportedThinkingLevels(opus47)).toContain("xhigh"); + expect(getSupportedThinkingLevels(opus47)).toContain("max"); const sonnet46 = getModel("github-copilot", "claude-sonnet-4.6"); - expect(sonnet46.thinkingLevelMap).toMatchObject({ minimal: "low", xhigh: "max" }); - expect(getSupportedThinkingLevels(sonnet46)).toContain("xhigh"); + expect(sonnet46.thinkingLevelMap).toMatchObject({ minimal: "low", max: "max" }); + expect(getSupportedThinkingLevels(sonnet46)).toContain("max"); + expect(getSupportedThinkingLevels(sonnet46)).not.toContain("xhigh"); }); it("uses Bearer auth, Copilot headers, and valid Anthropic Messages payload", async () => { diff --git a/packages/ai/test/max-thinking.test.ts b/packages/ai/test/max-thinking.test.ts new file mode 100644 index 00000000..f0623a5c --- /dev/null +++ b/packages/ai/test/max-thinking.test.ts @@ -0,0 +1,89 @@ +import { describe, expect, it } from "vitest"; +import { streamSimple as streamSimpleOpenAICodexResponses } from "../src/api/openai-codex-responses.ts"; +import { clampThinkingLevel, getModel, getSupportedThinkingLevels } from "../src/compat.ts"; +import type { Context, Model } from "../src/types.ts"; + +function mockToken(): string { + const payload = Buffer.from( + JSON.stringify({ "https://api.openai.com/auth": { chatgpt_account_id: "acc_test" } }), + "utf8", + ).toString("base64"); + return `aaa.${payload}.bbb`; +} + +describe("max thinking level", () => { + it("is opt-in for ordinary reasoning models", () => { + const model: Model<"openai-completions"> = { + id: "ordinary-reasoning", + name: "Ordinary Reasoning", + api: "openai-completions", + provider: "test", + baseUrl: "https://example.com/v1", + reasoning: true, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 128000, + maxTokens: 4096, + }; + + expect(getSupportedThinkingLevels(model)).toEqual(["off", "minimal", "low", "medium", "high"]); + expect(clampThinkingLevel(model, "max")).toBe("high"); + }); + + it.each(["gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra"] as const)( + "exposes xhigh and max for openai-codex/%s", + (modelId) => { + const model = getModel("openai-codex", modelId); + expect(model).toBeDefined(); + expect(model?.thinkingLevelMap).toMatchObject({ xhigh: "xhigh", max: "max" }); + expect(getSupportedThinkingLevels(model!)).toEqual([ + "off", + "minimal", + "low", + "medium", + "high", + "xhigh", + "max", + ]); + }, + ); + + it("supports a hole between high and max", () => { + const model: Model<"openai-completions"> = { + id: "high-and-max", + name: "High and Max", + api: "openai-completions", + provider: "test", + baseUrl: "https://example.com/v1", + reasoning: true, + thinkingLevelMap: { xhigh: null, max: "max" }, + input: ["text"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: 128000, + maxTokens: 4096, + }; + + expect(getSupportedThinkingLevels(model)).toEqual(["off", "minimal", "low", "medium", "high", "max"]); + expect(clampThinkingLevel(model, "xhigh")).toBe("max"); + }); + + it("sends max to the Codex Responses API", async () => { + const model = getModel("openai-codex", "gpt-5.6-sol")!; + const context: Context = { + systemPrompt: "You are a helpful assistant.", + messages: [{ role: "user", content: "Hello", timestamp: Date.now() }], + }; + let payload: unknown; + + await streamSimpleOpenAICodexResponses(model, context, { + apiKey: mockToken(), + reasoning: "max", + onPayload: (request) => { + payload = request; + throw new Error("payload captured"); + }, + }).result(); + + expect(payload).toMatchObject({ reasoning: { effort: "max", summary: "auto" } }); + }); +}); diff --git a/packages/ai/test/openai-completions-tool-choice.test.ts b/packages/ai/test/openai-completions-tool-choice.test.ts index ce23bdbe..1dd49c79 100644 --- a/packages/ai/test/openai-completions-tool-choice.test.ts +++ b/packages/ai/test/openai-completions-tool-choice.test.ts @@ -305,7 +305,7 @@ describe("openai-completions tool_choice", () => { low: "high", medium: "high", high: "high", - xhigh: "max", + max: "max", }); } }); @@ -316,7 +316,7 @@ describe("openai-completions tool_choice", () => { { reasoning: "low", effort: "high" }, { reasoning: "medium", effort: "high" }, { reasoning: "high", effort: "high" }, - { reasoning: "xhigh", effort: "max" }, + { reasoning: "max", effort: "max" }, ] as const; for (const testCase of cases) { diff --git a/packages/ai/test/supports-xhigh.test.ts b/packages/ai/test/supports-xhigh.test.ts index d52575e8..f7773ae3 100644 --- a/packages/ai/test/supports-xhigh.test.ts +++ b/packages/ai/test/supports-xhigh.test.ts @@ -2,35 +2,47 @@ import { describe, expect, it } from "vitest"; import { getModel, getSupportedThinkingLevels } from "../src/compat.ts"; describe("getSupportedThinkingLevels", () => { - it("includes xhigh for Anthropic Opus 4.6 on anthropic-messages API", () => { + it("includes max but not xhigh for Anthropic Opus 4.6 on anthropic-messages API", () => { const model = getModel("anthropic", "claude-opus-4-6"); expect(model).toBeDefined(); - expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toContain("max"); + expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh"); }); - it("includes xhigh for Anthropic Opus 4.8 on anthropic-messages API", () => { + it("includes xhigh and max for Anthropic Opus 4.8 on anthropic-messages API", () => { const model = getModel("anthropic", "claude-opus-4-8"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toContain("max"); }); - it("includes xhigh for Anthropic Opus 4.8 on anthropic-messages API", () => { - const model = getModel("anthropic", "claude-opus-4-8"); + it("includes max but not xhigh for Anthropic Sonnet 4.6 on anthropic-messages API", () => { + const model = getModel("anthropic", "claude-sonnet-4-6"); + expect(model).toBeDefined(); + expect(getSupportedThinkingLevels(model!)).toContain("max"); + expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh"); + }); + + it("includes xhigh and max for Anthropic Sonnet 5 on anthropic-messages API", () => { + const model = getModel("anthropic", "claude-sonnet-5"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toContain("max"); }); - it("includes xhigh but not off for Anthropic Claude Fable 5 on anthropic-messages API", () => { + it("includes xhigh and max but not off for Anthropic Claude Fable 5 on anthropic-messages API", () => { const model = getModel("anthropic", "claude-fable-5"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toContain("max"); expect(getSupportedThinkingLevels(model!)).not.toContain("off"); }); - it("does not include xhigh for Claude Sonnet 4.5", () => { + it("does not include xhigh or max for Claude Sonnet 4.5", () => { const model = getModel("anthropic", "claude-sonnet-4-5"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).not.toContain("max"); }); it.each(["gpt-5.4", "gpt-5.5", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"] as const)( @@ -43,11 +55,19 @@ describe("getSupportedThinkingLevels", () => { ); it.each(["gpt-5.6", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"] as const)( - "includes xhigh for OpenAI %s models", + "includes xhigh and max for OpenAI %s models", (modelId) => { const model = getModel("openai", modelId); expect(model).toBeDefined(); - expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toEqual([ + "off", + "minimal", + "low", + "medium", + "high", + "xhigh", + "max", + ]); }, ); @@ -63,16 +83,16 @@ describe("getSupportedThinkingLevels", () => { expect(getSupportedThinkingLevels(model!)).toEqual(["medium", "high", "xhigh"]); }); - it("includes only high/xhigh plus off for DeepSeek V4 Flash on the DeepSeek provider", () => { + it("includes only high/max plus off for DeepSeek V4 Flash on the DeepSeek provider", () => { const model = getModel("deepseek", "deepseek-v4-flash"); expect(model).toBeDefined(); - expect(getSupportedThinkingLevels(model!)).toEqual(["off", "high", "xhigh"]); + expect(getSupportedThinkingLevels(model!)).toEqual(["off", "high", "max"]); }); - it("includes only high/xhigh plus off for DeepSeek V4 Flash on opencode-go", () => { + it("includes only high/max plus off for DeepSeek V4 Flash on opencode-go", () => { const model = getModel("opencode-go", "deepseek-v4-flash"); expect(model).toBeDefined(); - expect(getSupportedThinkingLevels(model!)).toEqual(["off", "high", "xhigh"]); + expect(getSupportedThinkingLevels(model!)).toEqual(["off", "high", "max"]); }); it("includes only high plus off for OpenCode Go Kimi K2.6", () => { @@ -102,16 +122,18 @@ describe("getSupportedThinkingLevels", () => { expect(getSupportedThinkingLevels(model!)).toEqual(["off", "high", "xhigh"]); }); - it("includes xhigh for OpenRouter Opus 4.6 (openai-completions API)", () => { + it("includes max but not xhigh for OpenRouter Opus 4.6 (openai-completions API)", () => { const model = getModel("openrouter", "anthropic/claude-opus-4.6"); expect(model).toBeDefined(); - expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toContain("max"); + expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh"); }); - it("includes xhigh but not off for Bedrock Claude Fable 5", () => { + it("includes xhigh and max but not off for Bedrock Claude Fable 5", () => { const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5"); expect(model).toBeDefined(); expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); + expect(getSupportedThinkingLevels(model!)).toContain("max"); expect(getSupportedThinkingLevels(model!)).not.toContain("off"); }); }); diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 54572274..d9071a27 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added + +- Added the opt-in `max` thinking level across CLI, SDK, RPC, model selection, and themes. Custom themes can define `thinkingMax`; existing themes fall back to `thinkingXhigh`. + ## [0.80.5] - 2026-07-09 ## [0.80.4] - 2026-07-09 diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index 1f81990a..dc69b4d2 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -551,7 +551,7 @@ cat README.md | pi -p "Summarize this text" | `--provider ` | Provider (anthropic, openai, google, etc.) | | `--model ` | Model pattern or ID (supports `provider/id` and optional `:`) | | `--api-key ` | API key (overrides env vars) | -| `--thinking ` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | +| `--thinking ` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` | | `--models ` | Comma-separated patterns for Ctrl+P cycling | | `--list-models [search]` | List available models | diff --git a/packages/coding-agent/docs/custom-provider.md b/packages/coding-agent/docs/custom-provider.md index 612d1e60..6a8a38ed 100644 --- a/packages/coding-agent/docs/custom-provider.md +++ b/packages/coding-agent/docs/custom-provider.md @@ -204,7 +204,7 @@ The `api` field determines which streaming implementation is used: | `google-vertex` | Google Vertex AI API | | `bedrock-converse-stream` | Amazon Bedrock Converse API | -Most OpenAI-compatible providers work with `openai-completions`. Use model-level `thinkingLevelMap` for model-specific thinking levels, and `compat` for provider quirks: +Most OpenAI-compatible providers work with `openai-completions`. Use model-level `thinkingLevelMap` for model-specific thinking levels, and `compat` for provider quirks. The `xhigh` and `max` levels are opt-in, require non-null map entries, and may be separated by unsupported holes: ```typescript models: [{ @@ -216,7 +216,8 @@ models: [{ low: null, medium: null, high: "default", - xhigh: "max" + xhigh: null, + max: "max" }, compat: { supportsDeveloperRole: false, // use "system" instead of "developer" @@ -684,7 +685,7 @@ interface ProviderModelConfig { reasoning: boolean; /** Maps pi thinking levels to provider/model-specific values; null marks a level unsupported. */ - thinkingLevelMap?: Partial>; + thinkingLevelMap?: Partial>; /** Supported input types. */ input: ("text" | "image")[]; diff --git a/packages/coding-agent/docs/extensions.md b/packages/coding-agent/docs/extensions.md index d14c1685..e0648b81 100644 --- a/packages/coding-agent/docs/extensions.md +++ b/packages/coding-agent/docs/extensions.md @@ -1657,7 +1657,7 @@ if (model) { Get or set the thinking level. Level is clamped to model capabilities (non-reasoning models always use "off"). Changes emit `thinking_level_select`. ```typescript -const current = pi.getThinkingLevel(); // "off" | "minimal" | "low" | "medium" | "high" | "xhigh" +const current = pi.getThinkingLevel(); // "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" pi.setThinkingLevel("high"); ``` diff --git a/packages/coding-agent/docs/models.md b/packages/coding-agent/docs/models.md index 1183b4d3..93e8835f 100644 --- a/packages/coding-agent/docs/models.md +++ b/packages/coding-agent/docs/models.md @@ -214,13 +214,13 @@ Current behavior: ### Thinking Level Map -Use `thinkingLevelMap` on a model to describe model-specific thinking controls. Keys are pi thinking levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`. +Use `thinkingLevelMap` on a model to describe model-specific thinking controls. Keys are pi thinking levels: `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`. Maps may contain holes; for example, a model can expose `high` and `max` without exposing `xhigh`. Values are tristate: | Value | Meaning | |-------|---------| -| omitted | Level is supported and uses the provider's default mapping | +| omitted | Standard levels through `high` use the provider's default mapping; extended `xhigh` and `max` levels are unsupported | | string | Level is supported and this value is sent to the provider | | `null` | Level is unsupported and hidden/skipped/clamped away | @@ -235,7 +235,8 @@ Example for a model that only supports off, high, and max reasoning: "low": null, "medium": null, "high": "high", - "xhigh": "max" + "xhigh": null, + "max": "max" } } ``` diff --git a/packages/coding-agent/docs/rpc.md b/packages/coding-agent/docs/rpc.md index 89c1c72f..1493f2d5 100644 --- a/packages/coding-agent/docs/rpc.md +++ b/packages/coding-agent/docs/rpc.md @@ -286,9 +286,9 @@ Set the reasoning/thinking level for models that support it. {"type": "set_thinking_level", "level": "high"} ``` -Levels: `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"` +Levels: `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`, `"max"` -Note: `"xhigh"` is only supported by OpenAI codex-max models. +`"xhigh"` and `"max"` are exposed only when supported by the selected model. Some models, including GPT-5.6, expose both. Response: ```json diff --git a/packages/coding-agent/docs/sdk.md b/packages/coding-agent/docs/sdk.md index 7527d916..c84d6afc 100644 --- a/packages/coding-agent/docs/sdk.md +++ b/packages/coding-agent/docs/sdk.md @@ -387,7 +387,7 @@ const available = await modelRegistry.getAvailable(); const { session } = await createAgentSession({ model: opus, - thinkingLevel: "medium", // off, minimal, low, medium, high, xhigh + thinkingLevel: "medium", // off, minimal, low, medium, high, xhigh, max // Models for cycling (Ctrl+P in interactive mode) scopedModels: [ diff --git a/packages/coding-agent/docs/settings.md b/packages/coding-agent/docs/settings.md index 02f21c3c..bcbd2f1a 100644 --- a/packages/coding-agent/docs/settings.md +++ b/packages/coding-agent/docs/settings.md @@ -29,7 +29,7 @@ Use `/trust` in interactive mode to save a project trust decision for future ses |---------|------|---------|-------------| | `defaultProvider` | string | - | Default provider (e.g., `"anthropic"`, `"openai"`) | | `defaultModel` | string | - | Default model ID | -| `defaultThinkingLevel` | string | - | `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"` | +| `defaultThinkingLevel` | string | - | `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`, `"max"` | | `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output | | `showCacheMissNotices` | boolean | `false` | Show transcript notices for significant prompt-cache misses | | `thinkingBudgets` | object | - | Custom token budgets per thinking level | diff --git a/packages/coding-agent/docs/themes.md b/packages/coding-agent/docs/themes.md index 11655128..8bb86951 100644 --- a/packages/coding-agent/docs/themes.md +++ b/packages/coding-agent/docs/themes.md @@ -109,6 +109,7 @@ vim ~/.pi/agent/themes/my-theme.json "thinkingMedium": "#00ffff", "thinkingHigh": "#ff00ff", "thinkingXhigh": "#ff0000", + "thinkingMax": "#ff0088", "bashMode": "#ffaa00" } } @@ -139,13 +140,13 @@ vim ~/.pi/agent/themes/my-theme.json - `name` is required, must be unique, and must not contain `/`. - `vars` is optional. Define reusable colors here, then reference them in `colors`. -- `colors` must define all 51 required tokens. +- `colors` must define all 51 required tokens. `thinkingMax` is optional and falls back to `thinkingXhigh`. The `$schema` field enables editor auto-completion and validation. ## Color Tokens -Every theme must define all 51 color tokens. There are no optional colors. +Every theme must define all 51 required color tokens. `thinkingMax` is optional for compatibility with existing themes; when omitted, it uses `thinkingXhigh`. ### Core UI (11 colors) @@ -216,7 +217,7 @@ Every theme must define all 51 color tokens. There are no optional colors. | `syntaxOperator` | Operators | | `syntaxPunctuation` | Punctuation | -### Thinking Level Borders (6 colors) +### Thinking Level Borders (6 required, 1 optional) Editor border colors indicating thinking level (visual hierarchy from subtle to prominent): @@ -228,6 +229,7 @@ Editor border colors indicating thinking level (visual hierarchy from subtle to | `thinkingMedium` | Medium thinking | | `thinkingHigh` | High thinking | | `thinkingXhigh` | Extra high thinking | +| `thinkingMax` | Maximum thinking; optional, falls back to `thinkingXhigh` | ### Bash Mode (1 color) diff --git a/packages/coding-agent/docs/tui.md b/packages/coding-agent/docs/tui.md index 38ef1986..ca036ee1 100644 --- a/packages/coding-agent/docs/tui.md +++ b/packages/coding-agent/docs/tui.md @@ -424,7 +424,7 @@ renderResult(result, options, theme, context) { | Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` | | Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` | | Syntax | `syntaxComment`, `syntaxKeyword`, `syntaxFunction`, `syntaxVariable`, `syntaxString`, `syntaxNumber`, `syntaxType`, `syntaxOperator`, `syntaxPunctuation` | -| Thinking | `thinkingOff`, `thinkingMinimal`, `thinkingLow`, `thinkingMedium`, `thinkingHigh`, `thinkingXhigh` | +| Thinking | `thinkingOff`, `thinkingMinimal`, `thinkingLow`, `thinkingMedium`, `thinkingHigh`, `thinkingXhigh`, `thinkingMax` | | Modes | `bashMode` | **Background colors** (`theme.bg(color, text)`): diff --git a/packages/coding-agent/docs/usage.md b/packages/coding-agent/docs/usage.md index d87d504e..87fc0545 100644 --- a/packages/coding-agent/docs/usage.md +++ b/packages/coding-agent/docs/usage.md @@ -183,7 +183,7 @@ cat README.md | pi -p "Summarize this text" | `--provider ` | Provider, such as `anthropic`, `openai`, or `google` | | `--model ` | Model pattern or ID; supports `provider/id` and optional `:` | | `--api-key ` | API key, overriding environment variables | -| `--thinking ` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | +| `--thinking ` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` | | `--models ` | Comma-separated patterns for Ctrl+P cycling | | `--list-models [search]` | List available models | diff --git a/packages/coding-agent/examples/extensions/preset.ts b/packages/coding-agent/examples/extensions/preset.ts index b78237ca..39f55642 100644 --- a/packages/coding-agent/examples/extensions/preset.ts +++ b/packages/coding-agent/examples/extensions/preset.ts @@ -52,7 +52,7 @@ interface Preset { /** Model ID (e.g., "claude-sonnet-4-5") */ model?: string; /** Thinking level */ - thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; + thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; /** Tools to enable (replaces default set) */ tools?: string[]; /** Instructions to append to system prompt */ @@ -100,7 +100,7 @@ function loadPresets(cwd: string): PresetsConfig { interface OriginalState { model: Model | undefined; - thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; + thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"; tools: string[]; } diff --git a/packages/coding-agent/src/cli/args.ts b/packages/coding-agent/src/cli/args.ts index f8d4306e..d06a4752 100644 --- a/packages/coding-agent/src/cli/args.ts +++ b/packages/coding-agent/src/cli/args.ts @@ -54,7 +54,7 @@ export interface Args { diagnostics: Array<{ type: "warning" | "error"; message: string }>; } -const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh"] as const; +const VALID_THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"] as const; export function isValidThinkingLevel(level: string): level is ThinkingLevel { return VALID_THINKING_LEVELS.includes(level as ThinkingLevel); @@ -258,7 +258,7 @@ ${chalk.bold("Options:")} Applies to built-in, extension, and custom tools --exclude-tools, -xt Comma-separated denylist of tool names to disable Applies to built-in, extension, and custom tools - --thinking Set thinking level: off, minimal, low, medium, high, xhigh + --thinking Set thinking level: off, minimal, low, medium, high, xhigh, max --extension, -e Load an extension file (can be used multiple times) --no-extensions, -ne Disable extension discovery (explicit -e paths still work) --skill Load a skill file or directory (can be used multiple times) diff --git a/packages/coding-agent/src/core/model-registry.ts b/packages/coding-agent/src/core/model-registry.ts index 2fa599f1..4891de45 100644 --- a/packages/coding-agent/src/core/model-registry.ts +++ b/packages/coding-agent/src/core/model-registry.ts @@ -94,6 +94,7 @@ const ThinkingLevelMapSchema = Type.Object({ medium: Type.Optional(ThinkingLevelMapValueSchema), high: Type.Optional(ThinkingLevelMapValueSchema), xhigh: Type.Optional(ThinkingLevelMapValueSchema), + max: Type.Optional(ThinkingLevelMapValueSchema), }); const ChatTemplateKwargScalarSchema = Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]); diff --git a/packages/coding-agent/src/core/settings-manager.ts b/packages/coding-agent/src/core/settings-manager.ts index 141b984b..c88403ec 100644 --- a/packages/coding-agent/src/core/settings-manager.ts +++ b/packages/coding-agent/src/core/settings-manager.ts @@ -1,3 +1,4 @@ +import type { ThinkingLevel } from "@earendil-works/pi-agent-core"; import type { Transport } from "@earendil-works/pi-ai"; import { randomUUID } from "crypto"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; @@ -83,7 +84,7 @@ export interface Settings { lastChangelogVersion?: string; defaultProvider?: string; defaultModel?: string; - defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; + defaultThinkingLevel?: ThinkingLevel; transport?: TransportSetting; // default: "auto" steeringMode?: "all" | "one-at-a-time"; followUpMode?: "all" | "one-at-a-time"; @@ -736,11 +737,11 @@ export class SettingsManager { this.save(); } - getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined { + getDefaultThinkingLevel(): ThinkingLevel | undefined { return this.settings.defaultThinkingLevel; } - setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void { + setDefaultThinkingLevel(level: ThinkingLevel): void { this.globalSettings.defaultThinkingLevel = level; this.markModified("defaultThinkingLevel"); this.save(); diff --git a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts index 3436b240..9cfe184c 100644 --- a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts @@ -35,7 +35,8 @@ const THINKING_DESCRIPTIONS: Record = { low: "Light reasoning (~2k tokens)", medium: "Moderate reasoning (~8k tokens)", high: "Deep reasoning (~16k tokens)", - xhigh: "Maximum reasoning (~32k tokens)", + xhigh: "Extra-high reasoning (~32k tokens)", + max: "Maximum reasoning", }; const DEFAULT_PROJECT_TRUST_LABELS: Record = { 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 91a3a626..bc71bafc 100644 --- a/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/thinking-selector.ts @@ -14,7 +14,8 @@ const LEVEL_DESCRIPTIONS: Record = { low: "Light reasoning (~2k tokens)", medium: "Moderate reasoning (~8k tokens)", high: "Deep reasoning (~16k tokens)", - xhigh: "Maximum reasoning (~32k tokens)", + xhigh: "Extra-high reasoning (~32k tokens)", + max: "Maximum reasoning", }; /** diff --git a/packages/coding-agent/src/modes/interactive/theme/dark.json b/packages/coding-agent/src/modes/interactive/theme/dark.json index c133e232..d4d50415 100644 --- a/packages/coding-agent/src/modes/interactive/theme/dark.json +++ b/packages/coding-agent/src/modes/interactive/theme/dark.json @@ -75,6 +75,7 @@ "thinkingMedium": "#81a2be", "thinkingHigh": "#b294bb", "thinkingXhigh": "#d183e8", + "thinkingMax": "#ff5fff", "bashMode": "green" }, diff --git a/packages/coding-agent/src/modes/interactive/theme/light.json b/packages/coding-agent/src/modes/interactive/theme/light.json index 0a417b56..ef0d5c30 100644 --- a/packages/coding-agent/src/modes/interactive/theme/light.json +++ b/packages/coding-agent/src/modes/interactive/theme/light.json @@ -74,6 +74,7 @@ "thinkingMedium": "teal", "thinkingHigh": "#875f87", "thinkingXhigh": "#8b008b", + "thinkingMax": "#af005f", "bashMode": "green" }, diff --git a/packages/coding-agent/src/modes/interactive/theme/theme-schema.json b/packages/coding-agent/src/modes/interactive/theme/theme-schema.json index 9d94a12a..4ab36a72 100644 --- a/packages/coding-agent/src/modes/interactive/theme/theme-schema.json +++ b/packages/coding-agent/src/modes/interactive/theme/theme-schema.json @@ -34,7 +34,7 @@ }, "colors": { "type": "object", - "description": "Theme color definitions (all required)", + "description": "Theme color definitions (thinkingMax is optional and falls back to thinkingXhigh)", "required": [ "accent", "border", @@ -287,7 +287,11 @@ }, "thinkingXhigh": { "$ref": "#/$defs/colorValue", - "description": "Thinking level border: xhigh (OpenAI codex-max only)" + "description": "Thinking level border: xhigh" + }, + "thinkingMax": { + "$ref": "#/$defs/colorValue", + "description": "Thinking level border: max (falls back to thinkingXhigh when omitted)" }, "bashMode": { "$ref": "#/$defs/colorValue", diff --git a/packages/coding-agent/src/modes/interactive/theme/theme.ts b/packages/coding-agent/src/modes/interactive/theme/theme.ts index 676bc529..cfd5df55 100644 --- a/packages/coding-agent/src/modes/interactive/theme/theme.ts +++ b/packages/coding-agent/src/modes/interactive/theme/theme.ts @@ -1,5 +1,6 @@ import * as fs from "node:fs"; import * as path from "node:path"; +import type { ThinkingLevel } from "@earendil-works/pi-agent-core"; import { type EditorTheme, getCapabilities, @@ -88,6 +89,7 @@ const ThemeJsonSchema = Type.Object({ thinkingMedium: ColorValueSchema, thinkingHigh: ColorValueSchema, thinkingXhigh: ColorValueSchema, + thinkingMax: Type.Optional(ColorValueSchema), // Bash Mode (1 color) bashMode: ColorValueSchema, }), @@ -149,6 +151,7 @@ export type ThemeColor = | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" + | "thinkingMax" | "bashMode"; export type ThemeBg = @@ -316,6 +319,10 @@ function resolveThemeColors>( return resolved as Record; } +function withThemeColorFallbacks(colors: ThemeJson["colors"]): ThemeJson["colors"] & { thinkingMax: ColorValue } { + return { ...colors, thinkingMax: colors.thinkingMax ?? colors.thinkingXhigh }; +} + // ============================================================================ // Theme Class // ============================================================================ @@ -339,7 +346,8 @@ export class Theme { this.sourceInfo = options.sourceInfo; this.mode = mode; this.fgColors = new Map(); - for (const [key, value] of Object.entries(fgColors) as [ThemeColor, string | number][]) { + const colors = { ...fgColors, thinkingMax: fgColors.thinkingMax ?? fgColors.thinkingXhigh }; + for (const [key, value] of Object.entries(colors) as [ThemeColor, string | number][]) { this.fgColors.set(key, fgAnsi(value, mode)); } this.bgColors = new Map(); @@ -396,7 +404,7 @@ export class Theme { return this.mode; } - getThinkingBorderColor(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): (str: string) => string { + getThinkingBorderColor(level: ThinkingLevel): (str: string) => string { // Map thinking levels to dedicated theme colors switch (level) { case "off": @@ -411,6 +419,8 @@ export class Theme { return (str: string) => this.fg("thinkingHigh", str); case "xhigh": return (str: string) => this.fg("thinkingXhigh", str); + case "max": + return (str: string) => this.fg("thinkingMax", str); default: return (str: string) => this.fg("thinkingOff", str); } @@ -586,7 +596,7 @@ function loadThemeJson(name: string): ThemeJson { function createTheme(themeJson: ThemeJson, mode?: ColorMode, sourcePath?: string): Theme { const colorMode = mode ?? (getCapabilities().trueColor ? "truecolor" : "256color"); - const resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars); + const resolvedColors = resolveThemeColors(withThemeColorFallbacks(themeJson.colors), themeJson.vars); const fgColors: Record = {} as Record; const bgColors: Record = {} as Record; const bgColorKeys: Set = new Set([ @@ -1013,7 +1023,7 @@ export function getResolvedThemeColors(themeName?: string): Record { + for (const dir of tempDirs.splice(0)) { + rmSync(dir, { recursive: true, force: true }); + } +}); + +describe("max thinking level", () => { + it("is accepted by CLI and settings", async () => { + expect(isValidThinkingLevel("max")).toBe(true); + + const settings = SettingsManager.inMemory(); + settings.setDefaultThinkingLevel("max"); + await settings.flush(); + expect(settings.getDefaultThinkingLevel()).toBe("max"); + }); + + it("falls back to thinkingXhigh for legacy themes", () => { + const testDir = mkdtempSync(join(tmpdir(), "pi-max-theme-")); + tempDirs.push(testDir); + const currentDir = dirname(fileURLToPath(import.meta.url)); + const darkTheme = JSON.parse( + readFileSync(join(currentDir, "../src/modes/interactive/theme/dark.json"), "utf8"), + ) as { name: string; colors: Record }; + darkTheme.name = "legacy-theme"; + delete darkTheme.colors.thinkingMax; + const themePath = join(testDir, "legacy-theme.json"); + writeFileSync(themePath, JSON.stringify(darkTheme)); + + const legacyTheme = loadThemeFromPath(themePath); + expect(legacyTheme.getThinkingBorderColor("max")("border")).toBe( + legacyTheme.getThinkingBorderColor("xhigh")("border"), + ); + }); +}); diff --git a/packages/coding-agent/test/model-resolver.test.ts b/packages/coding-agent/test/model-resolver.test.ts index db8bbdb0..24575829 100644 --- a/packages/coding-agent/test/model-resolver.test.ts +++ b/packages/coding-agent/test/model-resolver.test.ts @@ -107,7 +107,7 @@ describe("parseModelPattern", () => { }); test("all valid thinking levels work", () => { - for (const level of ["off", "minimal", "low", "medium", "high", "xhigh"]) { + for (const level of ["off", "minimal", "low", "medium", "high", "xhigh", "max"]) { const result = parseModelPattern(`sonnet:${level}`, allModels); expect(result.model?.id).toBe("claude-sonnet-4-5"); expect(result.thinkingLevel).toBe(level); @@ -520,7 +520,7 @@ describe("resolveCliModel", () => { getAll: () => modelsWithNeuralwatt, } as unknown as Parameters[0]["modelRegistry"]; - for (const level of ["off", "minimal", "low", "medium", "high", "xhigh"]) { + for (const level of ["off", "minimal", "low", "medium", "high", "xhigh", "max"]) { const result = resolveCliModel({ cliModel: `neuralwatt/zai-org/GLM-5.1-FP8:${level}`, modelRegistry: registry, diff --git a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts index 9c15ecf6..39a9243c 100644 --- a/packages/coding-agent/test/suite/agent-session-model-extension.test.ts +++ b/packages/coding-agent/test/suite/agent-session-model-extension.test.ts @@ -78,6 +78,26 @@ describe("AgentSession model and extension characterization", () => { expect(harness.session.cycleThinkingLevel()).toBeUndefined(); }); + it("cycles xhigh before max when both are supported", async () => { + const harness = await createHarness({ models: [{ id: "faux-1", reasoning: true }] }); + harnesses.push(harness); + harness.getModel().thinkingLevelMap = { xhigh: "xhigh", max: "max" }; + + expect(harness.session.getAvailableThinkingLevels()).toEqual([ + "off", + "minimal", + "low", + "medium", + "high", + "xhigh", + "max", + ]); + harness.session.setThinkingLevel("high"); + expect(harness.session.cycleThinkingLevel()).toBe("xhigh"); + expect(harness.session.cycleThinkingLevel()).toBe("max"); + expect(harness.session.cycleThinkingLevel()).toBe("off"); + }); + it("throws when setModel is called without configured auth", async () => { const harness = await createHarness({ models: [