Merge pull request #5251 from yzhg1983/fix/anthropic-opus-temperature
fix(ai): suppress deprecated temperature param for Claude Opus 4.7+
This commit is contained in:
@@ -191,6 +191,11 @@ function isAnthropicAdaptiveThinkingModel(modelId: string): boolean {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isAnthropicTemperatureUnsupportedModel(modelId: string): boolean {
|
||||||
|
const id = modelId.toLowerCase();
|
||||||
|
return id.includes("opus-4-7") || id.includes("opus-4.7") || id.includes("opus-4-8") || id.includes("opus-4.8");
|
||||||
|
}
|
||||||
|
|
||||||
function mergeAnthropicMessagesCompat(model: Model<Api>, compat: AnthropicMessagesCompat): void {
|
function mergeAnthropicMessagesCompat(model: Model<Api>, compat: AnthropicMessagesCompat): void {
|
||||||
model.compat = { ...(model.compat as AnthropicMessagesCompat | undefined), ...compat };
|
model.compat = { ...(model.compat as AnthropicMessagesCompat | undefined), ...compat };
|
||||||
}
|
}
|
||||||
@@ -244,6 +249,9 @@ function applyThinkingLevelMetadata(model: Model<any>): void {
|
|||||||
if (model.api === "anthropic-messages" && isAnthropicAdaptiveThinkingModel(model.id)) {
|
if (model.api === "anthropic-messages" && isAnthropicAdaptiveThinkingModel(model.id)) {
|
||||||
mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true });
|
mergeAnthropicMessagesCompat(model, { forceAdaptiveThinking: true });
|
||||||
}
|
}
|
||||||
|
if (model.api === "anthropic-messages" && isAnthropicTemperatureUnsupportedModel(model.id)) {
|
||||||
|
mergeAnthropicMessagesCompat(model, { supportsTemperature: false });
|
||||||
|
}
|
||||||
if (model.api === "openai-completions" && model.id.includes("deepseek-v4")) {
|
if (model.api === "openai-completions" && model.id.includes("deepseek-v4")) {
|
||||||
mergeThinkingLevelMap(
|
mergeThinkingLevelMap(
|
||||||
model,
|
model,
|
||||||
|
|||||||
@@ -1850,7 +1850,7 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "anthropic",
|
provider: "anthropic",
|
||||||
baseUrl: "https://api.anthropic.com",
|
baseUrl: "https://api.anthropic.com",
|
||||||
compat: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -1869,7 +1869,7 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "anthropic",
|
provider: "anthropic",
|
||||||
baseUrl: "https://api.anthropic.com",
|
baseUrl: "https://api.anthropic.com",
|
||||||
compat: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -2958,7 +2958,26 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "cloudflare-ai-gateway",
|
provider: "cloudflare-ai-gateway",
|
||||||
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: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
|
reasoning: true,
|
||||||
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
|
input: ["text", "image"],
|
||||||
|
cost: {
|
||||||
|
input: 5,
|
||||||
|
output: 25,
|
||||||
|
cacheRead: 0.5,
|
||||||
|
cacheWrite: 6.25,
|
||||||
|
},
|
||||||
|
contextWindow: 1000000,
|
||||||
|
maxTokens: 128000,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"claude-opus-4-8": {
|
||||||
|
id: "claude-opus-4-8",
|
||||||
|
name: "Claude Opus 4.8",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "cloudflare-ai-gateway",
|
||||||
|
baseUrl: "https://gateway.ai.cloudflare.com/v1/{CLOUDFLARE_ACCOUNT_ID}/{CLOUDFLARE_GATEWAY_ID}/anthropic",
|
||||||
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -3916,7 +3935,7 @@ export const MODELS = {
|
|||||||
provider: "github-copilot",
|
provider: "github-copilot",
|
||||||
baseUrl: "https://api.individual.githubcopilot.com",
|
baseUrl: "https://api.individual.githubcopilot.com",
|
||||||
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,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -3936,7 +3955,7 @@ export const MODELS = {
|
|||||||
provider: "github-copilot",
|
provider: "github-copilot",
|
||||||
baseUrl: "https://api.individual.githubcopilot.com",
|
baseUrl: "https://api.individual.githubcopilot.com",
|
||||||
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,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -7259,7 +7278,7 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "opencode",
|
provider: "opencode",
|
||||||
baseUrl: "https://opencode.ai/zen",
|
baseUrl: "https://opencode.ai/zen",
|
||||||
compat: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -7278,7 +7297,7 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "opencode",
|
provider: "opencode",
|
||||||
baseUrl: "https://opencode.ai/zen",
|
baseUrl: "https://opencode.ai/zen",
|
||||||
compat: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -8540,23 +8559,6 @@ export const MODELS = {
|
|||||||
contextWindow: 2000000,
|
contextWindow: 2000000,
|
||||||
maxTokens: 30000,
|
maxTokens: 30000,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"baidu/ernie-4.5-21b-a3b": {
|
|
||||||
id: "baidu/ernie-4.5-21b-a3b",
|
|
||||||
name: "Baidu: ERNIE 4.5 21B A3B",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "openrouter",
|
|
||||||
baseUrl: "https://openrouter.ai/api/v1",
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 0.07,
|
|
||||||
output: 0.28,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 131072,
|
|
||||||
maxTokens: 8000,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"baidu/ernie-4.5-vl-28b-a3b": {
|
"baidu/ernie-4.5-vl-28b-a3b": {
|
||||||
id: "baidu/ernie-4.5-vl-28b-a3b",
|
id: "baidu/ernie-4.5-vl-28b-a3b",
|
||||||
name: "Baidu: ERNIE 4.5 VL 28B A3B",
|
name: "Baidu: ERNIE 4.5 VL 28B A3B",
|
||||||
@@ -9397,6 +9399,23 @@ export const MODELS = {
|
|||||||
contextWindow: 131072,
|
contextWindow: 131072,
|
||||||
maxTokens: 4096,
|
maxTokens: 4096,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
|
"meta-llama/llama-4-maverick": {
|
||||||
|
id: "meta-llama/llama-4-maverick",
|
||||||
|
name: "Meta: Llama 4 Maverick",
|
||||||
|
api: "openai-completions",
|
||||||
|
provider: "openrouter",
|
||||||
|
baseUrl: "https://openrouter.ai/api/v1",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text", "image"],
|
||||||
|
cost: {
|
||||||
|
input: 0.15,
|
||||||
|
output: 0.6,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 1048576,
|
||||||
|
maxTokens: 16384,
|
||||||
|
} satisfies Model<"openai-completions">,
|
||||||
"meta-llama/llama-4-scout": {
|
"meta-llama/llama-4-scout": {
|
||||||
id: "meta-llama/llama-4-scout",
|
id: "meta-llama/llama-4-scout",
|
||||||
name: "Meta: Llama 4 Scout",
|
name: "Meta: Llama 4 Scout",
|
||||||
@@ -9482,23 +9501,6 @@ export const MODELS = {
|
|||||||
contextWindow: 204800,
|
contextWindow: 204800,
|
||||||
maxTokens: 196608,
|
maxTokens: 196608,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"minimax/minimax-m2.5:free": {
|
|
||||||
id: "minimax/minimax-m2.5:free",
|
|
||||||
name: "MiniMax: MiniMax M2.5 (free)",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "openrouter",
|
|
||||||
baseUrl: "https://openrouter.ai/api/v1",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 0,
|
|
||||||
output: 0,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 204800,
|
|
||||||
maxTokens: 8192,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"minimax/minimax-m2.7": {
|
"minimax/minimax-m2.7": {
|
||||||
id: "minimax/minimax-m2.7",
|
id: "minimax/minimax-m2.7",
|
||||||
name: "MiniMax: MiniMax M2.7",
|
name: "MiniMax: MiniMax M2.7",
|
||||||
@@ -9508,13 +9510,13 @@ export const MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.27899999999999997,
|
input: 0.26,
|
||||||
output: 1.2,
|
output: 1.2,
|
||||||
cacheRead: 0,
|
cacheRead: 0,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 204800,
|
contextWindow: 204800,
|
||||||
maxTokens: 131072,
|
maxTokens: 4096,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"mistralai/codestral-2508": {
|
"mistralai/codestral-2508": {
|
||||||
id: "mistralai/codestral-2508",
|
id: "mistralai/codestral-2508",
|
||||||
@@ -10916,13 +10918,13 @@ export const MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.03,
|
input: 0.029,
|
||||||
output: 0.14,
|
output: 0.14,
|
||||||
cacheRead: 0,
|
cacheRead: 0,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 131072,
|
contextWindow: 131072,
|
||||||
maxTokens: 131072,
|
maxTokens: 4096,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"openai/gpt-oss-20b:free": {
|
"openai/gpt-oss-20b:free": {
|
||||||
id: "openai/gpt-oss-20b:free",
|
id: "openai/gpt-oss-20b:free",
|
||||||
@@ -11230,23 +11232,6 @@ export const MODELS = {
|
|||||||
contextWindow: 131072,
|
contextWindow: 131072,
|
||||||
maxTokens: 16384,
|
maxTokens: 16384,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"qwen/qwen-2.5-7b-instruct": {
|
|
||||||
id: "qwen/qwen-2.5-7b-instruct",
|
|
||||||
name: "Qwen: Qwen2.5 7B Instruct",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "openrouter",
|
|
||||||
baseUrl: "https://openrouter.ai/api/v1",
|
|
||||||
reasoning: false,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 0.04,
|
|
||||||
output: 0.09999999999999999,
|
|
||||||
cacheRead: 0,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 131072,
|
|
||||||
maxTokens: 32768,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"qwen/qwen-plus": {
|
"qwen/qwen-plus": {
|
||||||
id: "qwen/qwen-plus",
|
id: "qwen/qwen-plus",
|
||||||
name: "Qwen: Qwen-Plus",
|
name: "Qwen: Qwen-Plus",
|
||||||
@@ -11358,13 +11343,13 @@ export const MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.14950000000000002,
|
input: 0.09999999999999999,
|
||||||
output: 1.495,
|
output: 0.09999999999999999,
|
||||||
cacheRead: 0,
|
cacheRead: 0.09999999999999999,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 262144,
|
contextWindow: 262144,
|
||||||
maxTokens: 4096,
|
maxTokens: 262144,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"qwen/qwen3-30b-a3b": {
|
"qwen/qwen3-30b-a3b": {
|
||||||
id: "qwen/qwen3-30b-a3b",
|
id: "qwen/qwen3-30b-a3b",
|
||||||
@@ -11800,13 +11785,13 @@ export const MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.13899999999999998,
|
input: 0.14,
|
||||||
output: 1,
|
output: 1,
|
||||||
cacheRead: 0,
|
cacheRead: 0.049999999999999996,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 262144,
|
contextWindow: 262144,
|
||||||
maxTokens: 4096,
|
maxTokens: 262144,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"qwen/qwen3.5-397b-a17b": {
|
"qwen/qwen3.5-397b-a17b": {
|
||||||
id: "qwen/qwen3.5-397b-a17b",
|
id: "qwen/qwen3.5-397b-a17b",
|
||||||
@@ -12148,23 +12133,6 @@ export const MODELS = {
|
|||||||
contextWindow: 32768,
|
contextWindow: 32768,
|
||||||
maxTokens: 32768,
|
maxTokens: 32768,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"upstage/solar-pro-3": {
|
|
||||||
id: "upstage/solar-pro-3",
|
|
||||||
name: "Upstage: Solar Pro 3",
|
|
||||||
api: "openai-completions",
|
|
||||||
provider: "openrouter",
|
|
||||||
baseUrl: "https://openrouter.ai/api/v1",
|
|
||||||
reasoning: true,
|
|
||||||
input: ["text"],
|
|
||||||
cost: {
|
|
||||||
input: 0.15,
|
|
||||||
output: 0.6,
|
|
||||||
cacheRead: 0.015,
|
|
||||||
cacheWrite: 0,
|
|
||||||
},
|
|
||||||
contextWindow: 128000,
|
|
||||||
maxTokens: 4096,
|
|
||||||
} satisfies Model<"openai-completions">,
|
|
||||||
"x-ai/grok-4.20": {
|
"x-ai/grok-4.20": {
|
||||||
id: "x-ai/grok-4.20",
|
id: "x-ai/grok-4.20",
|
||||||
name: "xAI: Grok 4.20",
|
name: "xAI: Grok 4.20",
|
||||||
@@ -13451,7 +13419,7 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "vercel-ai-gateway",
|
provider: "vercel-ai-gateway",
|
||||||
baseUrl: "https://ai-gateway.vercel.sh",
|
baseUrl: "https://ai-gateway.vercel.sh",
|
||||||
compat: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -13470,7 +13438,7 @@ export const MODELS = {
|
|||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
provider: "vercel-ai-gateway",
|
provider: "vercel-ai-gateway",
|
||||||
baseUrl: "https://ai-gateway.vercel.sh",
|
baseUrl: "https://ai-gateway.vercel.sh",
|
||||||
compat: {"forceAdaptiveThinking":true},
|
compat: {"forceAdaptiveThinking":true,"supportsTemperature":false},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
thinkingLevelMap: {"xhigh":"xhigh"},
|
thinkingLevelMap: {"xhigh":"xhigh"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
@@ -15264,6 +15232,23 @@ export const MODELS = {
|
|||||||
contextWindow: 200000,
|
contextWindow: 200000,
|
||||||
maxTokens: 8000,
|
maxTokens: 8000,
|
||||||
} satisfies Model<"anthropic-messages">,
|
} satisfies Model<"anthropic-messages">,
|
||||||
|
"stepfun/step-3.7-flash": {
|
||||||
|
id: "stepfun/step-3.7-flash",
|
||||||
|
name: "Step 3.7 Flash",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "vercel-ai-gateway",
|
||||||
|
baseUrl: "https://ai-gateway.vercel.sh",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text", "image"],
|
||||||
|
cost: {
|
||||||
|
input: 0.19999999999999998,
|
||||||
|
output: 1.15,
|
||||||
|
cacheRead: 0.04,
|
||||||
|
cacheWrite: 0,
|
||||||
|
},
|
||||||
|
contextWindow: 256000,
|
||||||
|
maxTokens: 256000,
|
||||||
|
} satisfies Model<"anthropic-messages">,
|
||||||
"xai/grok-4.1-fast-non-reasoning": {
|
"xai/grok-4.1-fast-non-reasoning": {
|
||||||
id: "xai/grok-4.1-fast-non-reasoning",
|
id: "xai/grok-4.1-fast-non-reasoning",
|
||||||
name: "Grok 4.1 Fast Non-Reasoning",
|
name: "Grok 4.1 Fast Non-Reasoning",
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ function getAnthropicCompat(
|
|||||||
sendSessionAffinityHeaders:
|
sendSessionAffinityHeaders:
|
||||||
model.compat?.sendSessionAffinityHeaders ?? !!(isFireworks || isCloudflareAiGatewayAnthropic),
|
model.compat?.sendSessionAffinityHeaders ?? !!(isFireworks || isCloudflareAiGatewayAnthropic),
|
||||||
supportsCacheControlOnTools: model.compat?.supportsCacheControlOnTools ?? !isFireworks,
|
supportsCacheControlOnTools: model.compat?.supportsCacheControlOnTools ?? !isFireworks,
|
||||||
|
supportsTemperature: model.compat?.supportsTemperature ?? true,
|
||||||
allowEmptySignature: model.compat?.allowEmptySignature ?? false,
|
allowEmptySignature: model.compat?.allowEmptySignature ?? false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -896,15 +897,10 @@ function buildParams(
|
|||||||
options?: AnthropicOptions,
|
options?: AnthropicOptions,
|
||||||
): MessageCreateParamsStreaming {
|
): MessageCreateParamsStreaming {
|
||||||
const { cacheControl } = getCacheControl(model, options?.cacheRetention);
|
const { cacheControl } = getCacheControl(model, options?.cacheRetention);
|
||||||
|
const compat = getAnthropicCompat(model);
|
||||||
const params: MessageCreateParamsStreaming = {
|
const params: MessageCreateParamsStreaming = {
|
||||||
model: model.id,
|
model: model.id,
|
||||||
messages: convertMessages(
|
messages: convertMessages(context.messages, model, isOAuthToken, cacheControl, compat.allowEmptySignature),
|
||||||
context.messages,
|
|
||||||
model,
|
|
||||||
isOAuthToken,
|
|
||||||
cacheControl,
|
|
||||||
getAnthropicCompat(model).allowEmptySignature,
|
|
||||||
),
|
|
||||||
max_tokens: options?.maxTokens ?? model.maxTokens,
|
max_tokens: options?.maxTokens ?? model.maxTokens,
|
||||||
stream: true,
|
stream: true,
|
||||||
};
|
};
|
||||||
@@ -936,13 +932,12 @@ function buildParams(
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temperature is incompatible with extended thinking (adaptive or budget-based).
|
// Temperature is incompatible with extended thinking and unsupported on Claude Opus 4.7+.
|
||||||
if (options?.temperature !== undefined && !options?.thinkingEnabled) {
|
if (options?.temperature !== undefined && !options?.thinkingEnabled && compat.supportsTemperature) {
|
||||||
params.temperature = options.temperature;
|
params.temperature = options.temperature;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.tools && context.tools.length > 0) {
|
if (context.tools && context.tools.length > 0) {
|
||||||
const compat = getAnthropicCompat(model);
|
|
||||||
params.tools = convertTools(
|
params.tools = convertTools(
|
||||||
context.tools,
|
context.tools,
|
||||||
isOAuthToken,
|
isOAuthToken,
|
||||||
|
|||||||
@@ -451,6 +451,12 @@ export interface AnthropicMessagesCompat {
|
|||||||
* Default: true.
|
* Default: true.
|
||||||
*/
|
*/
|
||||||
supportsCacheControlOnTools?: boolean;
|
supportsCacheControlOnTools?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether the model accepts the Anthropic `temperature` request field.
|
||||||
|
* Claude Opus 4.7+ rejects non-default temperature values.
|
||||||
|
* Default: true.
|
||||||
|
*/
|
||||||
|
supportsTemperature?: boolean;
|
||||||
/**
|
/**
|
||||||
* Whether to force adaptive thinking (`thinking.type: "adaptive"` plus
|
* Whether to force adaptive thinking (`thinking.type: "adaptive"` plus
|
||||||
* `output_config.effort`) regardless of the model id. Built-in models that
|
* `output_config.effort`) regardless of the model id. Built-in models that
|
||||||
|
|||||||
104
packages/ai/test/anthropic-temperature-compat.test.ts
Normal file
104
packages/ai/test/anthropic-temperature-compat.test.ts
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { getModel } from "../src/models.ts";
|
||||||
|
import { streamSimple } from "../src/stream.ts";
|
||||||
|
import type { Context, Model, SimpleStreamOptions } from "../src/types.ts";
|
||||||
|
|
||||||
|
interface AnthropicTemperaturePayload {
|
||||||
|
temperature?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PayloadCaptured extends Error {
|
||||||
|
constructor() {
|
||||||
|
super("payload captured");
|
||||||
|
this.name = "PayloadCaptured";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeContext(): Context {
|
||||||
|
return {
|
||||||
|
messages: [{ role: "user", content: "Hello", timestamp: Date.now() }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeCustomModel(compat?: Model<"anthropic-messages">["compat"]): Model<"anthropic-messages"> {
|
||||||
|
return {
|
||||||
|
id: "vendor--claude-opus-4-7",
|
||||||
|
name: "Vendor Proxy Opus 4.7",
|
||||||
|
api: "anthropic-messages",
|
||||||
|
provider: "vendor-proxy",
|
||||||
|
baseUrl: "http://127.0.0.1:9",
|
||||||
|
reasoning: true,
|
||||||
|
input: ["text"],
|
||||||
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||||
|
contextWindow: 200000,
|
||||||
|
maxTokens: 32000,
|
||||||
|
compat,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function capturePayload(
|
||||||
|
model: Model<"anthropic-messages">,
|
||||||
|
options?: SimpleStreamOptions,
|
||||||
|
): Promise<AnthropicTemperaturePayload> {
|
||||||
|
let capturedPayload: AnthropicTemperaturePayload | undefined;
|
||||||
|
|
||||||
|
const payloadCaptureModel: Model<"anthropic-messages"> = {
|
||||||
|
...model,
|
||||||
|
baseUrl: "http://127.0.0.1:9",
|
||||||
|
};
|
||||||
|
|
||||||
|
const s = streamSimple(payloadCaptureModel, makeContext(), {
|
||||||
|
...options,
|
||||||
|
apiKey: "fake-key",
|
||||||
|
onPayload: (payload) => {
|
||||||
|
capturedPayload = payload as AnthropicTemperaturePayload;
|
||||||
|
throw new PayloadCaptured();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await s.result();
|
||||||
|
|
||||||
|
if (!capturedPayload) {
|
||||||
|
throw new Error("Expected payload to be captured before request failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
return capturedPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("Anthropic temperature compatibility", () => {
|
||||||
|
it("omits temperature for Claude Opus 4.7", async () => {
|
||||||
|
const payload = await capturePayload(getModel("anthropic", "claude-opus-4-7"), { temperature: 0 });
|
||||||
|
|
||||||
|
expect(payload.temperature).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits temperature for Claude Opus 4.8", async () => {
|
||||||
|
const payload = await capturePayload(getModel("anthropic", "claude-opus-4-8"), { temperature: 0 });
|
||||||
|
|
||||||
|
expect(payload.temperature).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits default temperature for Claude Opus 4.7", async () => {
|
||||||
|
const payload = await capturePayload(getModel("anthropic", "claude-opus-4-7"), { temperature: 1 });
|
||||||
|
|
||||||
|
expect(payload.temperature).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps temperature for Claude Opus 4.6", async () => {
|
||||||
|
const payload = await capturePayload(getModel("anthropic", "claude-opus-4-6"), { temperature: 0 });
|
||||||
|
|
||||||
|
expect(payload.temperature).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps temperature for Claude Sonnet 4.6", async () => {
|
||||||
|
const payload = await capturePayload(getModel("anthropic", "claude-sonnet-4-6"), { temperature: 0 });
|
||||||
|
|
||||||
|
expect(payload.temperature).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("omits temperature for custom models with supportsTemperature disabled", async () => {
|
||||||
|
const payload = await capturePayload(makeCustomModel({ supportsTemperature: false }), { temperature: 0 });
|
||||||
|
|
||||||
|
expect(payload.temperature).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user