feat(ai): add max thinking level

This commit is contained in:
Mario Zechner
2026-07-09 22:30:53 +02:00
parent 8973ae28ab
commit fbdd46389c
61 changed files with 441 additions and 168 deletions
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased] ## [Unreleased]
### Added
- Added the `max` model thinking level after `xhigh`.
## [0.80.5] - 2026-07-09 ## [0.80.5] - 2026-07-09
## [0.80.4] - 2026-07-09 ## [0.80.4] - 2026-07-09
+1 -1
View File
@@ -164,7 +164,7 @@ const agent = new Agent({
initialState: { initialState: {
systemPrompt: string, systemPrompt: string,
model: Model<any>, model: Model<any>,
thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh", thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max",
tools: AgentTool<any>[], tools: AgentTool<any>[],
messages: AgentMessage[], messages: AgentMessage[],
}, },
+3 -3
View File
@@ -283,10 +283,10 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
/** /**
* Thinking/reasoning level for models that support it. * Thinking/reasoning level for models that support it.
* Note: "xhigh" is only supported by selected model families. Use model thinking-level metadata * Note: "xhigh" and "max" are only supported by selected model families. Use model
* from @earendil-works/pi-ai to detect support for a concrete 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. * Extensible interface for custom app messages.
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased] ## [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
- 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)). - 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)).
+4 -2
View File
@@ -730,7 +730,7 @@ if (model.reasoning) {
const response = await models.completeSimple(model, { const response = await models.completeSimple(model, {
messages: [{ role: 'user', content: 'Solve: 2x + 5 = 13', timestamp: Date.now() }] 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 // 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) ### 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: `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. 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 ```typescript
const ollamaReasoningModel: Model<'openai-completions'> = { const ollamaReasoningModel: Model<'openai-completions'> = {
+34 -11
View File
@@ -160,7 +160,7 @@ const ZAI_GLM52_THINKING_LEVEL_MAP = {
low: "high", low: "high",
medium: "high", medium: "high",
high: "high", high: "high",
xhigh: "max", max: "max",
} as const; } as const;
const OPENCODE_GO_GLM52_THINKING_LEVEL_MAP = { const OPENCODE_GO_GLM52_THINKING_LEVEL_MAP = {
off: null, off: null,
@@ -168,7 +168,7 @@ const OPENCODE_GO_GLM52_THINKING_LEVEL_MAP = {
low: null, low: null,
medium: null, medium: null,
high: "high", high: "high",
xhigh: "max", max: "max",
} as const; } as const;
const EAGER_TOOL_INPUT_STREAMING_UNSUPPORTED_ANTHROPIC_MODELS = new Set([ const EAGER_TOOL_INPUT_STREAMING_UNSUPPORTED_ANTHROPIC_MODELS = new Set([
"github-copilot:claude-haiku-4.5", "github-copilot:claude-haiku-4.5",
@@ -181,7 +181,7 @@ const DEEPSEEK_V4_THINKING_LEVEL_MAP = {
low: null, low: null,
medium: null, medium: null,
high: "high", high: "high",
xhigh: "max", max: "max",
} as const; } as const;
const ANT_LING_RING_THINKING_LEVEL_MAP = { 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 = { const GITHUB_COPILOT_THINKING_LEVEL_OVERRIDES = {
"claude-opus-4.7": { minimal: "low" }, "claude-opus-4.7": { minimal: "low" },
"claude-opus-4.8": { 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<string, NonNullable<Model<Api>["thinkingLevelMap"]>>; } satisfies Record<string, NonNullable<Model<Api>["thinkingLevelMap"]>>;
function mergeThinkingLevelMap(model: Model<any>, map: NonNullable<Model<any>["thinkingLevelMap"]>): void { function mergeThinkingLevelMap(model: Model<any>, map: NonNullable<Model<any>["thinkingLevelMap"]>): void {
@@ -271,6 +271,16 @@ function supportsOpenAiXhigh(modelId: string): boolean {
); );
} }
function supportsOpenAiMax(model: Model<Api>): 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<any>): boolean { function isGoogleThinkingApi(model: Model<any>): boolean {
return model.api === "google-generative-ai" || model.api === "google-vertex"; return model.api === "google-generative-ai" || model.api === "google-vertex";
} }
@@ -472,28 +482,41 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
if (supportsOpenAiXhigh(model.id)) { if (supportsOpenAiXhigh(model.id)) {
mergeThinkingLevelMap(model, { xhigh: "xhigh" }); mergeThinkingLevelMap(model, { xhigh: "xhigh" });
} }
if (supportsOpenAiMax(model)) {
mergeThinkingLevelMap(model, { max: "max" });
}
if (model.provider === "openai" && model.id === "gpt-5.5") { if (model.provider === "openai" && model.id === "gpt-5.5") {
mergeThinkingLevelMap(model, { minimal: null }); mergeThinkingLevelMap(model, { minimal: null });
} }
if (model.id.endsWith("gpt-5.5-pro")) { if (model.id.endsWith("gpt-5.5-pro")) {
mergeThinkingLevelMap(model, { off: null, minimal: null, low: null }); mergeThinkingLevelMap(model, { off: null, minimal: null, low: null });
} }
if (model.id.includes("opus-4-6") || model.id.includes("opus-4.6")) { // Anthropic adaptive-thinking effort support (per Anthropic adaptive thinking docs):
mergeThinkingLevelMap(model, { xhigh: "max" }); // - "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 ( if (
model.id.includes("opus-4-7") || model.id.includes("opus-4-7") ||
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("opus-4.8") ||
model.id.includes("sonnet-5") ||
model.id.includes("sonnet.5")
) { ) {
mergeThinkingLevelMap(model, { xhigh: "xhigh" }); mergeThinkingLevelMap(model, { xhigh: "xhigh", max: "max" });
} }
if ( if (
(model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") && (model.api === "anthropic-messages" || model.api === "bedrock-converse-stream") &&
model.id.includes("fable-5") 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)) { if (model.api === "anthropic-messages" && isAnthropicAdaptiveThinkingModel(model.id)) {
mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true }); mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true });
@@ -505,7 +528,7 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
mergeThinkingLevelMap( mergeThinkingLevelMap(
model, model,
model.provider === "openrouter" model.provider === "openrouter"
? { ...DEEPSEEK_V4_THINKING_LEVEL_MAP, xhigh: "xhigh" } ? { ...DEEPSEEK_V4_THINKING_LEVEL_MAP, xhigh: "xhigh", max: null }
: DEEPSEEK_V4_THINKING_LEVEL_MAP, : DEEPSEEK_V4_THINKING_LEVEL_MAP,
); );
} }
@@ -544,7 +567,7 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
mergeThinkingLevelMap(model, { xhigh: "xhigh" }); mergeThinkingLevelMap(model, { xhigh: "xhigh" });
} }
if (model.provider === "fireworks" && model.id.includes("glm-5p2")) { 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") { if (model.provider === "opencode-go" && model.id === "glm-5.2") {
mergeThinkingLevelMap(model, OPENCODE_GO_GLM52_THINKING_LEVEL_MAP); mergeThinkingLevelMap(model, OPENCODE_GO_GLM52_THINKING_LEVEL_MAP);
+2 -1
View File
@@ -742,7 +742,8 @@ export const stream: StreamFunction<"anthropic-messages", AnthropicOptions> = (
/** /**
* Map ThinkingLevel to Anthropic effort levels for adaptive thinking. * 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( function mapThinkingLevelToEffort(
model: Model<"anthropic-messages">, model: Model<"anthropic-messages">,
@@ -52,7 +52,7 @@ function formatAzureOpenAIError(error: unknown): string {
// Azure OpenAI Responses-specific options // Azure OpenAI Responses-specific options
export interface AzureOpenAIResponsesOptions extends StreamOptions { export interface AzureOpenAIResponsesOptions extends StreamOptions {
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh"; reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
reasoningSummary?: "auto" | "detailed" | "concise" | null; reasoningSummary?: "auto" | "detailed" | "concise" | null;
azureApiVersion?: string; azureApiVersion?: string;
azureResourceName?: string; azureResourceName?: string;
@@ -582,7 +582,9 @@ function supportsAdaptiveThinking(modelId: string, modelName?: string): boolean
function supportsNativeXhighEffort(model: Model<"bedrock-converse-stream">): boolean { function supportsNativeXhighEffort(model: Model<"bedrock-converse-stream">): boolean {
const candidates = getModelMatchCandidates(model.id, model.name); 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( function mapThinkingLevelToEffort(
@@ -1025,11 +1027,12 @@ function buildAdditionalModelRequestFields(
low: 2048, low: 2048,
medium: 8192, medium: 8192,
high: 16384, 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) // Custom budgets only cover token-based levels through high.
const level = options.reasoning === "xhigh" ? "high" : options.reasoning; const level = options.reasoning === "xhigh" || options.reasoning === "max" ? "high" : options.reasoning;
const budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning]; const budget = options.thinkingBudgets?.[level] ?? defaultBudgets[options.reasoning];
return { return {
+1 -1
View File
@@ -400,7 +400,7 @@ function buildParams(
return params; return params;
} }
type ClampedThinkingLevel = Exclude<ThinkingLevel, "xhigh">; type ClampedThinkingLevel = Exclude<ThinkingLevel, "xhigh" | "max">;
function isGemma4Model(model: Model<"google-generative-ai">): boolean { function isGemma4Model(model: Model<"google-generative-ai">): boolean {
return /gemma-?4/.test(model.id.toLowerCase()); return /gemma-?4/.test(model.id.toLowerCase());
+1 -1
View File
@@ -498,7 +498,7 @@ function buildParams(
return params; return params;
} }
type ClampedThinkingLevel = Exclude<PiThinkingLevel, "xhigh">; type ClampedThinkingLevel = Exclude<PiThinkingLevel, "xhigh" | "max">;
function isGemini3ProModel(model: Model<"google-generative-ai">): boolean { function isGemini3ProModel(model: Model<"google-generative-ai">): boolean {
return /gemini-3(?:\.\d+)?-pro/.test(model.id.toLowerCase()); return /gemini-3(?:\.\d+)?-pro/.test(model.id.toLowerCase());
@@ -80,7 +80,7 @@ const CODEX_RESPONSE_STATUSES = new Set<CodexResponseStatus>([
// ============================================================================ // ============================================================================
export interface OpenAICodexResponsesOptions extends StreamOptions { 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; reasoningSummary?: "auto" | "concise" | "detailed" | "off" | "on" | null;
serviceTier?: ResponseCreateParamsStreaming["service_tier"]; serviceTier?: ResponseCreateParamsStreaming["service_tier"];
textVerbosity?: "low" | "medium" | "high"; textVerbosity?: "low" | "medium" | "high";
+1 -1
View File
@@ -109,7 +109,7 @@ function isEncryptedReasoningDetail(detail: unknown): detail is OpenAIEncryptedR
export interface OpenAICompletionsOptions extends StreamOptions { export interface OpenAICompletionsOptions extends StreamOptions {
toolChoice?: "auto" | "none" | "required" | { type: "function"; function: { name: string } }; toolChoice?: "auto" | "none" | "required" | { type: "function"; function: { name: string } };
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh"; reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
} }
interface OpenAICompatCacheControl { interface OpenAICompatCacheControl {
+1 -1
View File
@@ -78,7 +78,7 @@ function formatOpenAIResponsesError(error: unknown): string {
// OpenAI Responses-specific options // OpenAI Responses-specific options
export interface OpenAIResponsesOptions extends StreamOptions { export interface OpenAIResponsesOptions extends StreamOptions {
reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh"; reasoningEffort?: "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
reasoningSummary?: "auto" | "detailed" | "concise" | null; reasoningSummary?: "auto" | "detailed" | "concise" | null;
serviceTier?: ResponseCreateParamsStreaming["service_tier"]; serviceTier?: ResponseCreateParamsStreaming["service_tier"];
} }
+2 -2
View File
@@ -44,8 +44,8 @@ export function buildBaseOptions(
}; };
} }
export function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh"> | undefined { export function clampReasoning(effort: ThinkingLevel | undefined): Exclude<ThinkingLevel, "xhigh" | "max"> | undefined {
return effort === "xhigh" ? "high" : effort; return effort === "xhigh" || effort === "max" ? "high" : effort;
} }
export function adjustMaxTokensForThinking( export function adjustMaxTokensForThinking(
+2 -2
View File
@@ -394,7 +394,7 @@ export function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage
return usage.cost; 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<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] { export function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {
if (!model.reasoning) return ["off"]; if (!model.reasoning) return ["off"];
@@ -402,7 +402,7 @@ export function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>)
return EXTENDED_THINKING_LEVELS.filter((level) => { return EXTENDED_THINKING_LEVELS.filter((level) => {
const mapped = model.thinkingLevelMap?.[level]; const mapped = model.thinkingLevelMap?.[level];
if (mapped === null) return false; if (mapped === null) return false;
if (level === "xhigh") return mapped !== undefined; if (level === "xhigh" || level === "max") return mapped !== undefined;
return true; return true;
}); });
} }
@@ -79,7 +79,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -148,7 +148,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -166,7 +166,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -184,7 +184,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -219,6 +219,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -236,6 +237,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -270,7 +272,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 16.5, input: 16.5,
@@ -288,7 +290,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -323,6 +325,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3.3, input: 3.3,
@@ -340,6 +343,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -408,7 +412,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 11, input: 11,
@@ -460,7 +464,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5.5, input: 5.5,
@@ -478,7 +482,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5.5, input: 5.5,
@@ -496,7 +500,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5.5, input: 5.5,
@@ -531,6 +535,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3.3, input: 3.3,
@@ -548,6 +553,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com", baseUrl: "https://bedrock-runtime.eu-central-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2.2, input: 2.2,
@@ -565,7 +571,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -617,7 +623,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -635,7 +641,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -653,7 +659,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -688,6 +694,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -705,6 +712,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -773,7 +781,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -791,7 +799,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -826,6 +834,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -843,6 +852,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -1508,7 +1518,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -1577,7 +1587,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -1595,7 +1605,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -1613,7 +1623,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -1648,6 +1658,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -1665,6 +1676,7 @@ export const AMAZON_BEDROCK_MODELS = {
provider: "amazon-bedrock", provider: "amazon-bedrock",
baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -12,7 +12,7 @@ export const ANTHROPIC_MODELS = {
baseUrl: "https://api.anthropic.com", baseUrl: "https://api.anthropic.com",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -133,7 +133,7 @@ export const ANTHROPIC_MODELS = {
baseUrl: "https://api.anthropic.com", baseUrl: "https://api.anthropic.com",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -152,7 +152,7 @@ export const ANTHROPIC_MODELS = {
baseUrl: "https://api.anthropic.com", baseUrl: "https://api.anthropic.com",
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -171,7 +171,7 @@ export const ANTHROPIC_MODELS = {
baseUrl: "https://api.anthropic.com", baseUrl: "https://api.anthropic.com",
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -224,6 +224,7 @@ export const ANTHROPIC_MODELS = {
baseUrl: "https://api.anthropic.com", baseUrl: "https://api.anthropic.com",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -242,6 +243,7 @@ export const ANTHROPIC_MODELS = {
baseUrl: "https://api.anthropic.com", baseUrl: "https://api.anthropic.com",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -613,7 +613,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = {
provider: "azure-openai-responses", provider: "azure-openai-responses",
baseUrl: "", baseUrl: "",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -631,7 +631,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = {
provider: "azure-openai-responses", provider: "azure-openai-responses",
baseUrl: "", baseUrl: "",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 1, input: 1,
@@ -649,7 +649,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = {
provider: "azure-openai-responses", provider: "azure-openai-responses",
baseUrl: "", baseUrl: "",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -667,7 +667,7 @@ export const AZURE_OPENAI_RESPONSES_MODELS = {
provider: "azure-openai-responses", provider: "azure-openai-responses",
baseUrl: "", baseUrl: "",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2.5, input: 2.5,
@@ -120,7 +120,7 @@ export const CLOUDFLARE_AI_GATEWAY_MODELS = {
baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic", baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, 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", baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, 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", baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, 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", baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, 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", baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, 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", baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true}, compat: {"sendSessionAffinityHeaders":true,"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
+2 -2
View File
@@ -12,7 +12,7 @@ export const DEEPSEEK_MODELS = {
baseUrl: "https://api.deepseek.com", baseUrl: "https://api.deepseek.com",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0.14, input: 0.14,
@@ -31,7 +31,7 @@ export const DEEPSEEK_MODELS = {
baseUrl: "https://api.deepseek.com", baseUrl: "https://api.deepseek.com",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0.435, input: 0.435,
@@ -66,7 +66,7 @@ export const FIREWORKS_MODELS = {
baseUrl: "https://api.fireworks.ai/inference/v1", baseUrl: "https://api.fireworks.ai/inference/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false}, compat: {"supportsStore":false,"supportsDeveloperRole":false},
reasoning: true, 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"], input: ["text"],
cost: { cost: {
input: 1.4, input: 1.4,
@@ -229,7 +229,7 @@ export const FIREWORKS_MODELS = {
baseUrl: "https://api.fireworks.ai/inference/v1", baseUrl: "https://api.fireworks.ai/inference/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false}, compat: {"supportsStore":false,"supportsDeveloperRole":false},
reasoning: true, 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"], input: ["text"],
cost: { cost: {
input: 2.1, input: 2.1,
@@ -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"}, 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}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, 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"}, 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}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, 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"}, 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}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, 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"}, 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}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"minimal":"low","xhigh":"max"}, thinkingLevelMap: {"max":"max","minimal":"low"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, 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"}, 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}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -83,7 +83,7 @@ export const OPENAI_CODEX_MODELS = {
provider: "openai-codex", provider: "openai-codex",
baseUrl: "https://chatgpt.com/backend-api", baseUrl: "https://chatgpt.com/backend-api",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 1, input: 1,
@@ -101,7 +101,7 @@ export const OPENAI_CODEX_MODELS = {
provider: "openai-codex", provider: "openai-codex",
baseUrl: "https://chatgpt.com/backend-api", baseUrl: "https://chatgpt.com/backend-api",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -119,7 +119,7 @@ export const OPENAI_CODEX_MODELS = {
provider: "openai-codex", provider: "openai-codex",
baseUrl: "https://chatgpt.com/backend-api", baseUrl: "https://chatgpt.com/backend-api",
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","minimal":"low"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max","minimal":"low"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2.5, input: 2.5,
+4 -4
View File
@@ -613,7 +613,7 @@ export const OPENAI_MODELS = {
provider: "openai", provider: "openai",
baseUrl: "https://api.openai.com/v1", baseUrl: "https://api.openai.com/v1",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -631,7 +631,7 @@ export const OPENAI_MODELS = {
provider: "openai", provider: "openai",
baseUrl: "https://api.openai.com/v1", baseUrl: "https://api.openai.com/v1",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 1, input: 1,
@@ -649,7 +649,7 @@ export const OPENAI_MODELS = {
provider: "openai", provider: "openai",
baseUrl: "https://api.openai.com/v1", baseUrl: "https://api.openai.com/v1",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -667,7 +667,7 @@ export const OPENAI_MODELS = {
provider: "openai", provider: "openai",
baseUrl: "https://api.openai.com/v1", baseUrl: "https://api.openai.com/v1",
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":"none","xhigh":"xhigh"}, thinkingLevelMap: {"off":"none","xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2.5, input: 2.5,
@@ -12,7 +12,7 @@ export const OPENCODE_GO_MODELS = {
baseUrl: "https://opencode.ai/zen/go/v1", baseUrl: "https://opencode.ai/zen/go/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0.14, input: 0.14,
@@ -31,7 +31,7 @@ export const OPENCODE_GO_MODELS = {
baseUrl: "https://opencode.ai/zen/go/v1", baseUrl: "https://opencode.ai/zen/go/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true,"thinkingFormat":"deepseek"},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 1.74, input: 1.74,
@@ -68,7 +68,7 @@ export const OPENCODE_GO_MODELS = {
baseUrl: "https://opencode.ai/zen/go/v1", baseUrl: "https://opencode.ai/zen/go/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens"},
reasoning: true, 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"], input: ["text"],
cost: { cost: {
input: 1.4, input: 1.4,
+9 -7
View File
@@ -30,7 +30,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen", baseUrl: "https://opencode.ai/zen",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -100,7 +100,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen", baseUrl: "https://opencode.ai/zen",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -119,7 +119,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen", baseUrl: "https://opencode.ai/zen",
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -138,7 +138,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen", baseUrl: "https://opencode.ai/zen",
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -191,6 +191,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen", baseUrl: "https://opencode.ai/zen",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -209,6 +210,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen", baseUrl: "https://opencode.ai/zen",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -227,7 +229,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen/v1", baseUrl: "https://opencode.ai/zen/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0.14, input: 0.14,
@@ -246,7 +248,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen/v1", baseUrl: "https://opencode.ai/zen/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","requiresReasoningContentOnAssistantMessages":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0, input: 0,
@@ -265,7 +267,7 @@ export const OPENCODE_MODELS = {
baseUrl: "https://opencode.ai/zen/v1", baseUrl: "https://opencode.ai/zen/v1",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"maxTokensField":"max_tokens","supportsLongCacheRetention":false,"requiresReasoningContentOnAssistantMessages":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 1.74, input: 1.74,
+16 -14
View File
@@ -282,7 +282,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -301,7 +301,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -320,7 +320,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 30, input: 30,
@@ -339,7 +339,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -358,7 +358,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -413,6 +413,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -431,6 +432,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"}, compat: {"thinkingFormat":"openrouter","cacheControlFormat":"anthropic"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -791,7 +793,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter","requiresReasoningContentOnAssistantMessages":true}, compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter","requiresReasoningContentOnAssistantMessages":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0.09, input: 0.09,
@@ -810,7 +812,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter","requiresReasoningContentOnAssistantMessages":true}, compat: {"supportsDeveloperRole":false,"thinkingFormat":"openrouter","requiresReasoningContentOnAssistantMessages":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0.435, input: 0.435,
@@ -1486,7 +1488,7 @@ export const OPENROUTER_MODELS = {
cacheWrite: 0, cacheWrite: 0,
}, },
contextWindow: 1048576, contextWindow: 1048576,
maxTokens: 512000, maxTokens: 131072,
} satisfies Model<"openai-completions">, } satisfies Model<"openai-completions">,
"mistralai/codestral-2508": { "mistralai/codestral-2508": {
id: "mistralai/codestral-2508", id: "mistralai/codestral-2508",
@@ -2804,7 +2806,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter"}, compat: {"thinkingFormat":"openrouter"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 1, input: 1,
@@ -2823,7 +2825,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter"}, compat: {"thinkingFormat":"openrouter"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 1, input: 1,
@@ -2842,7 +2844,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter"}, compat: {"thinkingFormat":"openrouter"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -2861,7 +2863,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter"}, compat: {"thinkingFormat":"openrouter"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -2880,7 +2882,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter"}, compat: {"thinkingFormat":"openrouter"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2.5, input: 2.5,
@@ -2899,7 +2901,7 @@ export const OPENROUTER_MODELS = {
baseUrl: "https://openrouter.ai/api/v1", baseUrl: "https://openrouter.ai/api/v1",
compat: {"thinkingFormat":"openrouter"}, compat: {"thinkingFormat":"openrouter"},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2.5, input: 2.5,
@@ -522,7 +522,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
baseUrl: "https://ai-gateway.vercel.sh", baseUrl: "https://ai-gateway.vercel.sh",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"off":null,"xhigh":"xhigh"}, thinkingLevelMap: {"off":null,"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 10, input: 10,
@@ -609,7 +609,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
baseUrl: "https://ai-gateway.vercel.sh", baseUrl: "https://ai-gateway.vercel.sh",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"max"}, thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -628,7 +628,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
baseUrl: "https://ai-gateway.vercel.sh", baseUrl: "https://ai-gateway.vercel.sh",
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -647,7 +647,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
baseUrl: "https://ai-gateway.vercel.sh", baseUrl: "https://ai-gateway.vercel.sh",
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false}, compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh"}, thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 5, input: 5,
@@ -700,6 +700,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
baseUrl: "https://ai-gateway.vercel.sh", baseUrl: "https://ai-gateway.vercel.sh",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 3, input: 3,
@@ -718,6 +719,7 @@ export const VERCEL_AI_GATEWAY_MODELS = {
baseUrl: "https://ai-gateway.vercel.sh", baseUrl: "https://ai-gateway.vercel.sh",
compat: {"forceAdaptiveThinking":true}, compat: {"forceAdaptiveThinking":true},
reasoning: true, reasoning: true,
thinkingLevelMap: {"xhigh":"xhigh","max":"max"},
input: ["text", "image"], input: ["text", "image"],
cost: { cost: {
input: 2, input: 2,
@@ -84,7 +84,7 @@ export const ZAI_CODING_CN_MODELS = {
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4", baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"thinkingFormat":"zai","zaiToolStream":true}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"thinkingFormat":"zai","zaiToolStream":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0, input: 0,
+1 -1
View File
@@ -84,7 +84,7 @@ export const ZAI_MODELS = {
baseUrl: "https://api.z.ai/api/coding/paas/v4", baseUrl: "https://api.z.ai/api/coding/paas/v4",
compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"thinkingFormat":"zai","zaiToolStream":true}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"thinkingFormat":"zai","zaiToolStream":true},
reasoning: 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"], input: ["text"],
cost: { cost: {
input: 0, input: 0,
+1 -1
View File
@@ -71,7 +71,7 @@ export type KnownImagesProvider = "openrouter";
export type ImagesProviderId = KnownImagesProvider | string; 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 ModelThinkingLevel = "off" | ThinkingLevel;
export type ThinkingLevelMap = Partial<Record<ModelThinkingLevel, string | null>>; export type ThinkingLevelMap = Partial<Record<ModelThinkingLevel, string | null>>;
export type ChatTemplateKwargValue = export type ChatTemplateKwargValue =
@@ -19,7 +19,7 @@ import {
import { getModel } from "../src/compat.ts"; import { getModel } from "../src/compat.ts";
import type { AssistantMessage, Context, Message, Model, Tool, ToolResultMessage, Transport } from "../src/types.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 { interface Args {
turns: number; turns: number;
@@ -58,7 +58,14 @@ function parseArgs(argv: string[]): Args {
break; break;
case "--reasoning": { case "--reasoning": {
const value = required(argv[++i], arg); 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}`); throw new Error(`Invalid --reasoning: ${value}`);
} }
reasoning = value; reasoning = value;
@@ -90,7 +97,7 @@ function printHelp(): void {
Options: Options:
--turns <n> Number of user turns. Default: ${DEFAULT_TURNS} --turns <n> Number of user turns. Default: ${DEFAULT_TURNS}
--transport <mode> sse | websocket | websocket-cached | auto. Default: websocket-cached --transport <mode> sse | websocket | websocket-cached | auto. Default: websocket-cached
--reasoning <level> minimal | low | medium | high | xhigh. Default: low --reasoning <level> minimal | low | medium | high | xhigh | max. Default: low
--max-tokens <n> Max output tokens per model request. Default: ${DEFAULT_MAX_TOKENS} --max-tokens <n> Max output tokens per model request. Default: ${DEFAULT_MAX_TOKENS}
--session-id <id> Session id for websocket/cache state --session-id <id> Session id for websocket/cache state
`); `);
@@ -57,12 +57,14 @@ describe("Copilot Claude via Anthropic Messages", () => {
it("applies Copilot-specific adaptive thinking effort overrides", () => { it("applies Copilot-specific adaptive thinking effort overrides", () => {
const opus47 = getModel("github-copilot", "claude-opus-4.7"); 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("xhigh");
expect(getSupportedThinkingLevels(opus47)).toContain("max");
const sonnet46 = getModel("github-copilot", "claude-sonnet-4.6"); const sonnet46 = getModel("github-copilot", "claude-sonnet-4.6");
expect(sonnet46.thinkingLevelMap).toMatchObject({ minimal: "low", xhigh: "max" }); expect(sonnet46.thinkingLevelMap).toMatchObject({ minimal: "low", max: "max" });
expect(getSupportedThinkingLevels(sonnet46)).toContain("xhigh"); expect(getSupportedThinkingLevels(sonnet46)).toContain("max");
expect(getSupportedThinkingLevels(sonnet46)).not.toContain("xhigh");
}); });
it("uses Bearer auth, Copilot headers, and valid Anthropic Messages payload", async () => { it("uses Bearer auth, Copilot headers, and valid Anthropic Messages payload", async () => {
+89
View File
@@ -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" } });
});
});
@@ -305,7 +305,7 @@ describe("openai-completions tool_choice", () => {
low: "high", low: "high",
medium: "high", medium: "high",
high: "high", high: "high",
xhigh: "max", max: "max",
}); });
} }
}); });
@@ -316,7 +316,7 @@ describe("openai-completions tool_choice", () => {
{ reasoning: "low", effort: "high" }, { reasoning: "low", effort: "high" },
{ reasoning: "medium", effort: "high" }, { reasoning: "medium", effort: "high" },
{ reasoning: "high", effort: "high" }, { reasoning: "high", effort: "high" },
{ reasoning: "xhigh", effort: "max" }, { reasoning: "max", effort: "max" },
] as const; ] as const;
for (const testCase of cases) { for (const testCase of cases) {
+38 -16
View File
@@ -2,35 +2,47 @@ import { describe, expect, it } from "vitest";
import { getModel, getSupportedThinkingLevels } from "../src/compat.ts"; import { getModel, getSupportedThinkingLevels } from "../src/compat.ts";
describe("getSupportedThinkingLevels", () => { 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"); const model = getModel("anthropic", "claude-opus-4-6");
expect(model).toBeDefined(); 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"); const model = getModel("anthropic", "claude-opus-4-8");
expect(model).toBeDefined(); expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
expect(getSupportedThinkingLevels(model!)).toContain("max");
}); });
it("includes xhigh for Anthropic Opus 4.8 on anthropic-messages API", () => { it("includes max but not xhigh for Anthropic Sonnet 4.6 on anthropic-messages API", () => {
const model = getModel("anthropic", "claude-opus-4-8"); 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(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); 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"); const model = getModel("anthropic", "claude-fable-5");
expect(model).toBeDefined(); expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
expect(getSupportedThinkingLevels(model!)).toContain("max");
expect(getSupportedThinkingLevels(model!)).not.toContain("off"); 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"); const model = getModel("anthropic", "claude-sonnet-4-5");
expect(model).toBeDefined(); expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).not.toContain("xhigh"); 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)( 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)( 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) => { (modelId) => {
const model = getModel("openai", modelId); const model = getModel("openai", modelId);
expect(model).toBeDefined(); 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"]); 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"); const model = getModel("deepseek", "deepseek-v4-flash");
expect(model).toBeDefined(); 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"); const model = getModel("opencode-go", "deepseek-v4-flash");
expect(model).toBeDefined(); 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", () => { 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"]); 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"); const model = getModel("openrouter", "anthropic/claude-opus-4.6");
expect(model).toBeDefined(); 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"); const model = getModel("amazon-bedrock", "global.anthropic.claude-fable-5");
expect(model).toBeDefined(); expect(model).toBeDefined();
expect(getSupportedThinkingLevels(model!)).toContain("xhigh"); expect(getSupportedThinkingLevels(model!)).toContain("xhigh");
expect(getSupportedThinkingLevels(model!)).toContain("max");
expect(getSupportedThinkingLevels(model!)).not.toContain("off"); expect(getSupportedThinkingLevels(model!)).not.toContain("off");
}); });
}); });
+4
View File
@@ -2,6 +2,10 @@
## [Unreleased] ## [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.5] - 2026-07-09
## [0.80.4] - 2026-07-09 ## [0.80.4] - 2026-07-09
+1 -1
View File
@@ -551,7 +551,7 @@ cat README.md | pi -p "Summarize this text"
| `--provider <name>` | Provider (anthropic, openai, google, etc.) | | `--provider <name>` | Provider (anthropic, openai, google, etc.) |
| `--model <pattern>` | Model pattern or ID (supports `provider/id` and optional `:<thinking>`) | | `--model <pattern>` | Model pattern or ID (supports `provider/id` and optional `:<thinking>`) |
| `--api-key <key>` | API key (overrides env vars) | | `--api-key <key>` | API key (overrides env vars) |
| `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | | `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` |
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling | | `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling |
| `--list-models [search]` | List available models | | `--list-models [search]` | List available models |
@@ -204,7 +204,7 @@ The `api` field determines which streaming implementation is used:
| `google-vertex` | Google Vertex AI API | | `google-vertex` | Google Vertex AI API |
| `bedrock-converse-stream` | Amazon Bedrock Converse 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 ```typescript
models: [{ models: [{
@@ -216,7 +216,8 @@ models: [{
low: null, low: null,
medium: null, medium: null,
high: "default", high: "default",
xhigh: "max" xhigh: null,
max: "max"
}, },
compat: { compat: {
supportsDeveloperRole: false, // use "system" instead of "developer" supportsDeveloperRole: false, // use "system" instead of "developer"
@@ -684,7 +685,7 @@ interface ProviderModelConfig {
reasoning: boolean; reasoning: boolean;
/** Maps pi thinking levels to provider/model-specific values; null marks a level unsupported. */ /** Maps pi thinking levels to provider/model-specific values; null marks a level unsupported. */
thinkingLevelMap?: Partial<Record<"off" | "minimal" | "low" | "medium" | "high" | "xhigh", string | null>>; thinkingLevelMap?: Partial<Record<"off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max", string | null>>;
/** Supported input types. */ /** Supported input types. */
input: ("text" | "image")[]; input: ("text" | "image")[];
+1 -1
View File
@@ -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`. Get or set the thinking level. Level is clamped to model capabilities (non-reasoning models always use "off"). Changes emit `thinking_level_select`.
```typescript ```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"); pi.setThinkingLevel("high");
``` ```
+4 -3
View File
@@ -214,13 +214,13 @@ Current behavior:
### Thinking Level Map ### 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: Values are tristate:
| Value | Meaning | | 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 | | string | Level is supported and this value is sent to the provider |
| `null` | Level is unsupported and hidden/skipped/clamped away | | `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, "low": null,
"medium": null, "medium": null,
"high": "high", "high": "high",
"xhigh": "max" "xhigh": null,
"max": "max"
} }
} }
``` ```
+2 -2
View File
@@ -286,9 +286,9 @@ Set the reasoning/thinking level for models that support it.
{"type": "set_thinking_level", "level": "high"} {"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: Response:
```json ```json
+1 -1
View File
@@ -387,7 +387,7 @@ const available = await modelRegistry.getAvailable();
const { session } = await createAgentSession({ const { session } = await createAgentSession({
model: opus, 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) // Models for cycling (Ctrl+P in interactive mode)
scopedModels: [ scopedModels: [
+1 -1
View File
@@ -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"`) | | `defaultProvider` | string | - | Default provider (e.g., `"anthropic"`, `"openai"`) |
| `defaultModel` | string | - | Default model ID | | `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 | | `hideThinkingBlock` | boolean | `false` | Hide thinking blocks in output |
| `showCacheMissNotices` | boolean | `false` | Show transcript notices for significant prompt-cache misses | | `showCacheMissNotices` | boolean | `false` | Show transcript notices for significant prompt-cache misses |
| `thinkingBudgets` | object | - | Custom token budgets per thinking level | | `thinkingBudgets` | object | - | Custom token budgets per thinking level |
+5 -3
View File
@@ -109,6 +109,7 @@ vim ~/.pi/agent/themes/my-theme.json
"thinkingMedium": "#00ffff", "thinkingMedium": "#00ffff",
"thinkingHigh": "#ff00ff", "thinkingHigh": "#ff00ff",
"thinkingXhigh": "#ff0000", "thinkingXhigh": "#ff0000",
"thinkingMax": "#ff0088",
"bashMode": "#ffaa00" "bashMode": "#ffaa00"
} }
} }
@@ -139,13 +140,13 @@ vim ~/.pi/agent/themes/my-theme.json
- `name` is required, must be unique, and must not contain `/`. - `name` is required, must be unique, and must not contain `/`.
- `vars` is optional. Define reusable colors here, then reference them in `colors`. - `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. The `$schema` field enables editor auto-completion and validation.
## Color Tokens ## 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) ### Core UI (11 colors)
@@ -216,7 +217,7 @@ Every theme must define all 51 color tokens. There are no optional colors.
| `syntaxOperator` | Operators | | `syntaxOperator` | Operators |
| `syntaxPunctuation` | Punctuation | | `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): 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 | | `thinkingMedium` | Medium thinking |
| `thinkingHigh` | High thinking | | `thinkingHigh` | High thinking |
| `thinkingXhigh` | Extra high thinking | | `thinkingXhigh` | Extra high thinking |
| `thinkingMax` | Maximum thinking; optional, falls back to `thinkingXhigh` |
### Bash Mode (1 color) ### Bash Mode (1 color)
+1 -1
View File
@@ -424,7 +424,7 @@ renderResult(result, options, theme, context) {
| Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` | | Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` |
| Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` | | Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` |
| Syntax | `syntaxComment`, `syntaxKeyword`, `syntaxFunction`, `syntaxVariable`, `syntaxString`, `syntaxNumber`, `syntaxType`, `syntaxOperator`, `syntaxPunctuation` | | 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` | | Modes | `bashMode` |
**Background colors** (`theme.bg(color, text)`): **Background colors** (`theme.bg(color, text)`):
+1 -1
View File
@@ -183,7 +183,7 @@ cat README.md | pi -p "Summarize this text"
| `--provider <name>` | Provider, such as `anthropic`, `openai`, or `google` | | `--provider <name>` | Provider, such as `anthropic`, `openai`, or `google` |
| `--model <pattern>` | Model pattern or ID; supports `provider/id` and optional `:<thinking>` | | `--model <pattern>` | Model pattern or ID; supports `provider/id` and optional `:<thinking>` |
| `--api-key <key>` | API key, overriding environment variables | | `--api-key <key>` | API key, overriding environment variables |
| `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh` | | `--thinking <level>` | `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max` |
| `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling | | `--models <patterns>` | Comma-separated patterns for Ctrl+P cycling |
| `--list-models [search]` | List available models | | `--list-models [search]` | List available models |
@@ -52,7 +52,7 @@ interface Preset {
/** Model ID (e.g., "claude-sonnet-4-5") */ /** Model ID (e.g., "claude-sonnet-4-5") */
model?: string; model?: string;
/** Thinking level */ /** Thinking level */
thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
/** Tools to enable (replaces default set) */ /** Tools to enable (replaces default set) */
tools?: string[]; tools?: string[];
/** Instructions to append to system prompt */ /** Instructions to append to system prompt */
@@ -100,7 +100,7 @@ function loadPresets(cwd: string): PresetsConfig {
interface OriginalState { interface OriginalState {
model: Model<Api> | undefined; model: Model<Api> | undefined;
thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; thinkingLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
tools: string[]; tools: string[];
} }
+2 -2
View File
@@ -54,7 +54,7 @@ export interface Args {
diagnostics: Array<{ type: "warning" | "error"; message: string }>; 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 { export function isValidThinkingLevel(level: string): level is ThinkingLevel {
return VALID_THINKING_LEVELS.includes(level as ThinkingLevel); return VALID_THINKING_LEVELS.includes(level as ThinkingLevel);
@@ -258,7 +258,7 @@ ${chalk.bold("Options:")}
Applies to built-in, extension, and custom tools Applies to built-in, extension, and custom tools
--exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable --exclude-tools, -xt <tools> Comma-separated denylist of tool names to disable
Applies to built-in, extension, and custom tools Applies to built-in, extension, and custom tools
--thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh, max
--extension, -e <path> Load an extension file (can be used multiple times) --extension, -e <path> Load an extension file (can be used multiple times)
--no-extensions, -ne Disable extension discovery (explicit -e paths still work) --no-extensions, -ne Disable extension discovery (explicit -e paths still work)
--skill <path> Load a skill file or directory (can be used multiple times) --skill <path> Load a skill file or directory (can be used multiple times)
@@ -94,6 +94,7 @@ const ThinkingLevelMapSchema = Type.Object({
medium: Type.Optional(ThinkingLevelMapValueSchema), medium: Type.Optional(ThinkingLevelMapValueSchema),
high: Type.Optional(ThinkingLevelMapValueSchema), high: Type.Optional(ThinkingLevelMapValueSchema),
xhigh: Type.Optional(ThinkingLevelMapValueSchema), xhigh: Type.Optional(ThinkingLevelMapValueSchema),
max: Type.Optional(ThinkingLevelMapValueSchema),
}); });
const ChatTemplateKwargScalarSchema = Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]); const ChatTemplateKwargScalarSchema = Type.Union([Type.String(), Type.Number(), Type.Boolean(), Type.Null()]);
@@ -1,3 +1,4 @@
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
import type { Transport } from "@earendil-works/pi-ai"; import type { Transport } from "@earendil-works/pi-ai";
import { randomUUID } from "crypto"; import { randomUUID } from "crypto";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"; import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -83,7 +84,7 @@ export interface Settings {
lastChangelogVersion?: string; lastChangelogVersion?: string;
defaultProvider?: string; defaultProvider?: string;
defaultModel?: string; defaultModel?: string;
defaultThinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"; defaultThinkingLevel?: ThinkingLevel;
transport?: TransportSetting; // default: "auto" transport?: TransportSetting; // default: "auto"
steeringMode?: "all" | "one-at-a-time"; steeringMode?: "all" | "one-at-a-time";
followUpMode?: "all" | "one-at-a-time"; followUpMode?: "all" | "one-at-a-time";
@@ -736,11 +737,11 @@ export class SettingsManager {
this.save(); this.save();
} }
getDefaultThinkingLevel(): "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined { getDefaultThinkingLevel(): ThinkingLevel | undefined {
return this.settings.defaultThinkingLevel; return this.settings.defaultThinkingLevel;
} }
setDefaultThinkingLevel(level: "off" | "minimal" | "low" | "medium" | "high" | "xhigh"): void { setDefaultThinkingLevel(level: ThinkingLevel): void {
this.globalSettings.defaultThinkingLevel = level; this.globalSettings.defaultThinkingLevel = level;
this.markModified("defaultThinkingLevel"); this.markModified("defaultThinkingLevel");
this.save(); this.save();
@@ -35,7 +35,8 @@ const THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {
low: "Light reasoning (~2k tokens)", low: "Light reasoning (~2k tokens)",
medium: "Moderate reasoning (~8k tokens)", medium: "Moderate reasoning (~8k tokens)",
high: "Deep reasoning (~16k 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<DefaultProjectTrust, string> = { const DEFAULT_PROJECT_TRUST_LABELS: Record<DefaultProjectTrust, string> = {
@@ -14,7 +14,8 @@ const LEVEL_DESCRIPTIONS: Record<ThinkingLevel, string> = {
low: "Light reasoning (~2k tokens)", low: "Light reasoning (~2k tokens)",
medium: "Moderate reasoning (~8k tokens)", medium: "Moderate reasoning (~8k tokens)",
high: "Deep reasoning (~16k tokens)", high: "Deep reasoning (~16k tokens)",
xhigh: "Maximum reasoning (~32k tokens)", xhigh: "Extra-high reasoning (~32k tokens)",
max: "Maximum reasoning",
}; };
/** /**
@@ -75,6 +75,7 @@
"thinkingMedium": "#81a2be", "thinkingMedium": "#81a2be",
"thinkingHigh": "#b294bb", "thinkingHigh": "#b294bb",
"thinkingXhigh": "#d183e8", "thinkingXhigh": "#d183e8",
"thinkingMax": "#ff5fff",
"bashMode": "green" "bashMode": "green"
}, },
@@ -74,6 +74,7 @@
"thinkingMedium": "teal", "thinkingMedium": "teal",
"thinkingHigh": "#875f87", "thinkingHigh": "#875f87",
"thinkingXhigh": "#8b008b", "thinkingXhigh": "#8b008b",
"thinkingMax": "#af005f",
"bashMode": "green" "bashMode": "green"
}, },
@@ -34,7 +34,7 @@
}, },
"colors": { "colors": {
"type": "object", "type": "object",
"description": "Theme color definitions (all required)", "description": "Theme color definitions (thinkingMax is optional and falls back to thinkingXhigh)",
"required": [ "required": [
"accent", "accent",
"border", "border",
@@ -287,7 +287,11 @@
}, },
"thinkingXhigh": { "thinkingXhigh": {
"$ref": "#/$defs/colorValue", "$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": { "bashMode": {
"$ref": "#/$defs/colorValue", "$ref": "#/$defs/colorValue",
@@ -1,5 +1,6 @@
import * as fs from "node:fs"; import * as fs from "node:fs";
import * as path from "node:path"; import * as path from "node:path";
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
import { import {
type EditorTheme, type EditorTheme,
getCapabilities, getCapabilities,
@@ -88,6 +89,7 @@ const ThemeJsonSchema = Type.Object({
thinkingMedium: ColorValueSchema, thinkingMedium: ColorValueSchema,
thinkingHigh: ColorValueSchema, thinkingHigh: ColorValueSchema,
thinkingXhigh: ColorValueSchema, thinkingXhigh: ColorValueSchema,
thinkingMax: Type.Optional(ColorValueSchema),
// Bash Mode (1 color) // Bash Mode (1 color)
bashMode: ColorValueSchema, bashMode: ColorValueSchema,
}), }),
@@ -149,6 +151,7 @@ export type ThemeColor =
| "thinkingMedium" | "thinkingMedium"
| "thinkingHigh" | "thinkingHigh"
| "thinkingXhigh" | "thinkingXhigh"
| "thinkingMax"
| "bashMode"; | "bashMode";
export type ThemeBg = export type ThemeBg =
@@ -316,6 +319,10 @@ function resolveThemeColors<T extends Record<string, ColorValue>>(
return resolved as Record<keyof T, string | number>; return resolved as Record<keyof T, string | number>;
} }
function withThemeColorFallbacks(colors: ThemeJson["colors"]): ThemeJson["colors"] & { thinkingMax: ColorValue } {
return { ...colors, thinkingMax: colors.thinkingMax ?? colors.thinkingXhigh };
}
// ============================================================================ // ============================================================================
// Theme Class // Theme Class
// ============================================================================ // ============================================================================
@@ -339,7 +346,8 @@ export class Theme {
this.sourceInfo = options.sourceInfo; this.sourceInfo = options.sourceInfo;
this.mode = mode; this.mode = mode;
this.fgColors = new Map(); 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.fgColors.set(key, fgAnsi(value, mode));
} }
this.bgColors = new Map(); this.bgColors = new Map();
@@ -396,7 +404,7 @@ export class Theme {
return this.mode; 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 // Map thinking levels to dedicated theme colors
switch (level) { switch (level) {
case "off": case "off":
@@ -411,6 +419,8 @@ export class Theme {
return (str: string) => this.fg("thinkingHigh", str); return (str: string) => this.fg("thinkingHigh", str);
case "xhigh": case "xhigh":
return (str: string) => this.fg("thinkingXhigh", str); return (str: string) => this.fg("thinkingXhigh", str);
case "max":
return (str: string) => this.fg("thinkingMax", str);
default: default:
return (str: string) => this.fg("thinkingOff", str); 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 { function createTheme(themeJson: ThemeJson, mode?: ColorMode, sourcePath?: string): Theme {
const colorMode = mode ?? (getCapabilities().trueColor ? "truecolor" : "256color"); 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<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>; const fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;
const bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>; const bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;
const bgColorKeys: Set<string> = new Set([ const bgColorKeys: Set<string> = new Set([
@@ -1013,7 +1023,7 @@ export function getResolvedThemeColors(themeName?: string): Record<string, strin
const name = themeName ?? currentThemeName ?? getDefaultTheme(); const name = themeName ?? currentThemeName ?? getDefaultTheme();
const isLight = name === "light"; const isLight = name === "light";
const themeJson = loadThemeJson(name); const themeJson = loadThemeJson(name);
const resolved = resolveThemeColors(themeJson.colors, themeJson.vars); const resolved = resolveThemeColors(withThemeColorFallbacks(themeJson.colors), themeJson.vars);
// Default text color for empty values (terminal uses default fg color) // Default text color for empty values (terminal uses default fg color)
const defaultText = isLight ? "#000000" : "#e5e5e7"; const defaultText = isLight ? "#000000" : "#e5e5e7";
@@ -0,0 +1,45 @@
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import { afterEach, describe, expect, it } from "vitest";
import { isValidThinkingLevel } from "../src/cli/args.ts";
import { SettingsManager } from "../src/core/settings-manager.ts";
import { loadThemeFromPath } from "../src/modes/interactive/theme/theme.ts";
const tempDirs: string[] = [];
afterEach(() => {
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<string, unknown> };
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"),
);
});
});
@@ -107,7 +107,7 @@ describe("parseModelPattern", () => {
}); });
test("all valid thinking levels work", () => { 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); const result = parseModelPattern(`sonnet:${level}`, allModels);
expect(result.model?.id).toBe("claude-sonnet-4-5"); expect(result.model?.id).toBe("claude-sonnet-4-5");
expect(result.thinkingLevel).toBe(level); expect(result.thinkingLevel).toBe(level);
@@ -520,7 +520,7 @@ describe("resolveCliModel", () => {
getAll: () => modelsWithNeuralwatt, getAll: () => modelsWithNeuralwatt,
} as unknown as Parameters<typeof resolveCliModel>[0]["modelRegistry"]; } as unknown as Parameters<typeof resolveCliModel>[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({ const result = resolveCliModel({
cliModel: `neuralwatt/zai-org/GLM-5.1-FP8:${level}`, cliModel: `neuralwatt/zai-org/GLM-5.1-FP8:${level}`,
modelRegistry: registry, modelRegistry: registry,
@@ -78,6 +78,26 @@ describe("AgentSession model and extension characterization", () => {
expect(harness.session.cycleThinkingLevel()).toBeUndefined(); 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 () => { it("throws when setModel is called without configured auth", async () => {
const harness = await createHarness({ const harness = await createHarness({
models: [ models: [