From 64c1dea52530cfb5052a4646230cf672e8552f14 Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Mon, 15 Sep 2025 16:17:26 -0500 Subject: [PATCH 1/6] Add coding plan support to Z.ai provider Adds support for Z.ai's coding plan subscription tiers: - International Coding Plan - China Coding Plan Pulls changes from downstream PR Kilo-Org/kilocode#2402 --- packages/types/src/provider-settings.ts | 6 +++++- packages/types/src/providers/zai.ts | 14 +++++++++++++ src/api/providers/__tests__/zai.spec.ts | 12 +++++++++-- src/api/providers/zai.ts | 5 +++-- .../src/components/settings/providers/ZAi.tsx | 20 ++++++++++--------- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 4dfeacbf07..6d628ddfdf 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -308,9 +308,13 @@ const sambaNovaSchema = apiModelIdProviderModelSchema.extend({ sambaNovaApiKey: z.string().optional(), }) +export const zaiApiLineSchema = z.enum(["international_coding", "international", "china_coding", "china"]) + +export type ZaiApiLine = z.infer + const zaiSchema = apiModelIdProviderModelSchema.extend({ zaiApiKey: z.string().optional(), - zaiApiLine: z.union([z.literal("china"), z.literal("international")]).optional(), + zaiApiLine: zaiApiLineSchema.optional(), }) const fireworksSchema = apiModelIdProviderModelSchema.extend({ diff --git a/packages/types/src/providers/zai.ts b/packages/types/src/providers/zai.ts index f724744827..f9fc437ac0 100644 --- a/packages/types/src/providers/zai.ts +++ b/packages/types/src/providers/zai.ts @@ -1,4 +1,5 @@ import type { ModelInfo } from "../model.js" +import { ZaiApiLine } from "../provider-settings.js" // kilocode_change // Z AI // https://docs.z.ai/guides/llm/glm-4.5 @@ -103,3 +104,16 @@ export const mainlandZAiModels = { } as const satisfies Record export const ZAI_DEFAULT_TEMPERATURE = 0 + +// kilocode_change start +export const zaiApiLineConfigs = { + international_coding: { + name: "International Coding Plan", + baseUrl: "https://api.z.ai/api/coding/paas/v4", + isChina: false, + }, + international: { name: "International Standard", baseUrl: "https://api.z.ai/api/paas/v4", isChina: false }, + china_coding: { name: "China Coding Plan", baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4", isChina: true }, + china: { name: "China Standard", baseUrl: "https://open.bigmodel.cn/api/paas/v4", isChina: true }, +} satisfies Record +// kilocode_change end diff --git a/src/api/providers/__tests__/zai.spec.ts b/src/api/providers/__tests__/zai.spec.ts index a16aa9fcdf..7928a4298d 100644 --- a/src/api/providers/__tests__/zai.spec.ts +++ b/src/api/providers/__tests__/zai.spec.ts @@ -41,7 +41,11 @@ describe("ZAiHandler", () => { it("should use the correct international Z AI base URL", () => { new ZAiHandler({ zaiApiKey: "test-zai-api-key", zaiApiLine: "international" }) - expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://api.z.ai/api/paas/v4" })) + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: "https://api.z.ai/api/paas/v4", + }), + ) }) it("should use the provided API key for international", () => { @@ -109,7 +113,11 @@ describe("ZAiHandler", () => { describe("Default behavior", () => { it("should default to international when no zaiApiLine is specified", () => { const handlerDefault = new ZAiHandler({ zaiApiKey: "test-zai-api-key" }) - expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://api.z.ai/api/paas/v4" })) + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: "https://api.z.ai/api/coding/paas/v4", + }), + ) const model = handlerDefault.getModel() expect(model.id).toBe(internationalZAiDefaultModelId) diff --git a/src/api/providers/zai.ts b/src/api/providers/zai.ts index e37e37f01b..ce5aab9dd9 100644 --- a/src/api/providers/zai.ts +++ b/src/api/providers/zai.ts @@ -6,6 +6,7 @@ import { type InternationalZAiModelId, type MainlandZAiModelId, ZAI_DEFAULT_TEMPERATURE, + zaiApiLineConfigs, } from "@roo-code/types" import type { ApiHandlerOptions } from "../../shared/api" @@ -14,14 +15,14 @@ import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider" export class ZAiHandler extends BaseOpenAiCompatibleProvider { constructor(options: ApiHandlerOptions) { - const isChina = options.zaiApiLine === "china" + const isChina = zaiApiLineConfigs[options.zaiApiLine ?? "international_coding"].isChina const models = isChina ? mainlandZAiModels : internationalZAiModels const defaultModelId = isChina ? mainlandZAiDefaultModelId : internationalZAiDefaultModelId super({ ...options, providerName: "Z AI", - baseURL: isChina ? "https://open.bigmodel.cn/api/paas/v4" : "https://api.z.ai/api/paas/v4", + baseURL: zaiApiLineConfigs[options.zaiApiLine ?? "international_coding"].baseUrl, apiKey: options.zaiApiKey ?? "not-provided", defaultProviderModelId: defaultModelId, providerModels: models, diff --git a/webview-ui/src/components/settings/providers/ZAi.tsx b/webview-ui/src/components/settings/providers/ZAi.tsx index bc23f28346..c7f44510c1 100644 --- a/webview-ui/src/components/settings/providers/ZAi.tsx +++ b/webview-ui/src/components/settings/providers/ZAi.tsx @@ -1,7 +1,7 @@ import { useCallback } from "react" import { VSCodeTextField, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react" -import type { ProviderSettings } from "@roo-code/types" +import { zaiApiLineConfigs, zaiApiLineSchema, type ProviderSettings } from "@roo-code/types" import { useAppTranslation } from "@src/i18n/TranslationContext" import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink" @@ -33,15 +33,17 @@ export const ZAi = ({ apiConfiguration, setApiConfigurationField }: ZAiProps) =>
- - api.z.ai - - - open.bigmodel.cn - + {zaiApiLineSchema.options.map((zaiApiLine) => { + const config = zaiApiLineConfigs[zaiApiLine] + return ( + + {config.name} ({config.baseUrl}) + + ) + })}
{t("settings:providers.zaiEntrypointDescription")} @@ -62,7 +64,7 @@ export const ZAi = ({ apiConfiguration, setApiConfigurationField }: ZAiProps) => {!apiConfiguration?.zaiApiKey && ( Date: Mon, 15 Sep 2025 16:21:56 -0500 Subject: [PATCH 2/6] Remove kilocode_change comments --- packages/types/src/providers/zai.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/types/src/providers/zai.ts b/packages/types/src/providers/zai.ts index f9fc437ac0..b3838c1406 100644 --- a/packages/types/src/providers/zai.ts +++ b/packages/types/src/providers/zai.ts @@ -1,5 +1,5 @@ import type { ModelInfo } from "../model.js" -import { ZaiApiLine } from "../provider-settings.js" // kilocode_change +import { ZaiApiLine } from "../provider-settings.js" // Z AI // https://docs.z.ai/guides/llm/glm-4.5 @@ -105,7 +105,6 @@ export const mainlandZAiModels = { export const ZAI_DEFAULT_TEMPERATURE = 0 -// kilocode_change start export const zaiApiLineConfigs = { international_coding: { name: "International Coding Plan", @@ -116,4 +115,3 @@ export const zaiApiLineConfigs = { china_coding: { name: "China Coding Plan", baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4", isChina: true }, china: { name: "China Standard", baseUrl: "https://open.bigmodel.cn/api/paas/v4", isChina: true }, } satisfies Record -// kilocode_change end From 8a961f264bdef9f6c809076dce3d13e22889989e Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Mon, 15 Sep 2025 18:05:21 -0500 Subject: [PATCH 3/6] feat: add Claude 4.5 Sonnet and Opus models across all providers - Added claude-sonnet-4-5-20250514 and claude-opus-4-5-20250514 to Anthropic provider - Added same models to claude-code provider (imports from anthropic) - Added anthropic.claude-sonnet-4-5-20250514-v1:0 and anthropic.claude-opus-4-5-20250514-v1:0 to Bedrock - Added claude-sonnet-4-5@20250514 and claude-opus-4-5@20250514 to Vertex AI - Updated provider implementations to support new models - Added support for 1M context beta flag for Claude 4.5 Sonnet - Added comprehensive test coverage for new models --- packages/types/src/providers/anthropic.ts | 34 ++++++++++++++++++ packages/types/src/providers/bedrock.ts | 30 ++++++++++++++++ packages/types/src/providers/claude-code.ts | 16 +++++++++ packages/types/src/providers/vertex.ts | 24 +++++++++++++ src/api/providers/__tests__/anthropic.spec.ts | 36 +++++++++++++++++++ src/api/providers/anthropic.ts | 18 +++++++--- .../settings/providers/Anthropic.tsx | 3 +- 7 files changed, 156 insertions(+), 5 deletions(-) diff --git a/packages/types/src/providers/anthropic.ts b/packages/types/src/providers/anthropic.ts index 2cb38537a4..f6057fbcca 100644 --- a/packages/types/src/providers/anthropic.ts +++ b/packages/types/src/providers/anthropic.ts @@ -6,6 +6,28 @@ export type AnthropicModelId = keyof typeof anthropicModels export const anthropicDefaultModelId: AnthropicModelId = "claude-sonnet-4-20250514" export const anthropicModels = { + "claude-sonnet-4-5-20250514": { + maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false. + contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 3.0, // $3 per million input tokens (≤200K context) + outputPrice: 15.0, // $15 per million output tokens (≤200K context) + cacheWritesPrice: 3.75, // $3.75 per million tokens + cacheReadsPrice: 0.3, // $0.30 per million tokens + supportsReasoningBudget: true, + // Tiered pricing for extended context (requires beta flag 'context-1m-2025-08-07') + tiers: [ + { + contextWindow: 1_000_000, // 1M tokens with beta flag + inputPrice: 6.0, // $6 per million input tokens (>200K context) + outputPrice: 22.5, // $22.50 per million output tokens (>200K context) + cacheWritesPrice: 7.5, // $7.50 per million tokens (>200K context) + cacheReadsPrice: 0.6, // $0.60 per million tokens (>200K context) + }, + ], + }, "claude-sonnet-4-20250514": { maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false. contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' @@ -28,6 +50,18 @@ export const anthropicModels = { }, ], }, + "claude-opus-4-5-20250514": { + maxTokens: 32_000, // Overridden to 8k if `enableReasoningEffort` is false. + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 15.0, // $15 per million input tokens + outputPrice: 75.0, // $75 per million output tokens + cacheWritesPrice: 18.75, // $18.75 per million tokens + cacheReadsPrice: 1.5, // $1.50 per million tokens + supportsReasoningBudget: true, + }, "claude-opus-4-1-20250805": { maxTokens: 8192, contextWindow: 200_000, diff --git a/packages/types/src/providers/bedrock.ts b/packages/types/src/providers/bedrock.ts index 67215e7796..a6fff55a7a 100644 --- a/packages/types/src/providers/bedrock.ts +++ b/packages/types/src/providers/bedrock.ts @@ -67,6 +67,21 @@ export const bedrockModels = { maxCachePoints: 1, cachableFields: ["system"], }, + "anthropic.claude-sonnet-4-5-20250514-v1:0": { + maxTokens: 8192, + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + supportsReasoningBudget: true, + inputPrice: 3.0, + outputPrice: 15.0, + cacheWritesPrice: 3.75, + cacheReadsPrice: 0.3, + minTokensPerCachePoint: 1024, + maxCachePoints: 4, + cachableFields: ["system", "messages", "tools"], + }, "anthropic.claude-sonnet-4-20250514-v1:0": { maxTokens: 8192, contextWindow: 200_000, @@ -82,6 +97,21 @@ export const bedrockModels = { maxCachePoints: 4, cachableFields: ["system", "messages", "tools"], }, + "anthropic.claude-opus-4-5-20250514-v1:0": { + maxTokens: 8192, + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + supportsReasoningBudget: true, + inputPrice: 15.0, + outputPrice: 75.0, + cacheWritesPrice: 18.75, + cacheReadsPrice: 1.5, + minTokensPerCachePoint: 1024, + maxCachePoints: 4, + cachableFields: ["system", "messages", "tools"], + }, "anthropic.claude-opus-4-1-20250805-v1:0": { maxTokens: 8192, contextWindow: 200_000, diff --git a/packages/types/src/providers/claude-code.ts b/packages/types/src/providers/claude-code.ts index d9b658319a..a99f89335c 100644 --- a/packages/types/src/providers/claude-code.ts +++ b/packages/types/src/providers/claude-code.ts @@ -40,6 +40,14 @@ export function getClaudeCodeModelId(baseModelId: ClaudeCodeModelId, useVertex = } export const claudeCodeModels = { + "claude-sonnet-4-5-20250514": { + ...anthropicModels["claude-sonnet-4-5-20250514"], + supportsImages: false, + supportsPromptCache: true, // Claude Code does report cache tokens + supportsReasoningEffort: false, + supportsReasoningBudget: false, + requiredReasoningBudget: false, + }, "claude-sonnet-4-20250514": { ...anthropicModels["claude-sonnet-4-20250514"], supportsImages: false, @@ -48,6 +56,14 @@ export const claudeCodeModels = { supportsReasoningBudget: false, requiredReasoningBudget: false, }, + "claude-opus-4-5-20250514": { + ...anthropicModels["claude-opus-4-5-20250514"], + supportsImages: false, + supportsPromptCache: true, // Claude Code does report cache tokens + supportsReasoningEffort: false, + supportsReasoningBudget: false, + requiredReasoningBudget: false, + }, "claude-opus-4-1-20250805": { ...anthropicModels["claude-opus-4-1-20250805"], supportsImages: false, diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 8010fccf8e..d1a1e0b12c 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -163,6 +163,18 @@ export const vertexModels = { inputPrice: 1.25, outputPrice: 5, }, + "claude-sonnet-4-5@20250514": { + maxTokens: 8192, + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 3.0, + outputPrice: 15.0, + cacheWritesPrice: 3.75, + cacheReadsPrice: 0.3, + supportsReasoningBudget: true, + }, "claude-sonnet-4@20250514": { maxTokens: 8192, contextWindow: 200_000, @@ -175,6 +187,18 @@ export const vertexModels = { cacheReadsPrice: 0.3, supportsReasoningBudget: true, }, + "claude-opus-4-5@20250514": { + maxTokens: 8192, + contextWindow: 200_000, + supportsImages: true, + supportsComputerUse: true, + supportsPromptCache: true, + inputPrice: 15.0, + outputPrice: 75.0, + cacheWritesPrice: 18.75, + cacheReadsPrice: 1.5, + supportsReasoningBudget: true, + }, "claude-opus-4-1@20250805": { maxTokens: 8192, contextWindow: 200_000, diff --git a/src/api/providers/__tests__/anthropic.spec.ts b/src/api/providers/__tests__/anthropic.spec.ts index b1d0a2f6b3..a71ddd55f4 100644 --- a/src/api/providers/__tests__/anthropic.spec.ts +++ b/src/api/providers/__tests__/anthropic.spec.ts @@ -264,5 +264,41 @@ describe("AnthropicHandler", () => { expect(result.reasoningBudget).toBeUndefined() expect(result.temperature).toBe(0) }) + + it("should handle Claude 4.5 Sonnet model correctly", () => { + const handler = new AnthropicHandler({ + apiKey: "test-api-key", + apiModelId: "claude-sonnet-4-5-20250514", + }) + const model = handler.getModel() + expect(model.id).toBe("claude-sonnet-4-5-20250514") + expect(model.info.maxTokens).toBe(64000) + expect(model.info.contextWindow).toBe(200000) + expect(model.info.supportsReasoningBudget).toBe(true) + }) + + it("should handle Claude 4.5 Opus model correctly", () => { + const handler = new AnthropicHandler({ + apiKey: "test-api-key", + apiModelId: "claude-opus-4-5-20250514", + }) + const model = handler.getModel() + expect(model.id).toBe("claude-opus-4-5-20250514") + expect(model.info.maxTokens).toBe(32000) + expect(model.info.contextWindow).toBe(200000) + expect(model.info.supportsReasoningBudget).toBe(true) + }) + + it("should enable 1M context for Claude 4.5 Sonnet when beta flag is set", () => { + const handler = new AnthropicHandler({ + apiKey: "test-api-key", + apiModelId: "claude-sonnet-4-5-20250514", + anthropicBeta1MContext: true, + }) + const model = handler.getModel() + expect(model.info.contextWindow).toBe(1000000) + expect(model.info.inputPrice).toBe(6.0) + expect(model.info.outputPrice).toBe(22.5) + }) }) }) diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index cb48492b60..9f328be904 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -45,13 +45,18 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa const cacheControl: CacheControlEphemeral = { type: "ephemeral" } let { id: modelId, betas = [], maxTokens, temperature, reasoning: thinking } = this.getModel() - // Add 1M context beta flag if enabled for Claude Sonnet 4 - if (modelId === "claude-sonnet-4-20250514" && this.options.anthropicBeta1MContext) { + // Add 1M context beta flag if enabled for Claude Sonnet 4 and 4.5 + if ( + (modelId === "claude-sonnet-4-20250514" || modelId === "claude-sonnet-4-5-20250514") && + this.options.anthropicBeta1MContext + ) { betas.push("context-1m-2025-08-07") } switch (modelId) { + case "claude-sonnet-4-5-20250514": case "claude-sonnet-4-20250514": + case "claude-opus-4-5-20250514": case "claude-opus-4-1-20250805": case "claude-opus-4-20250514": case "claude-3-7-sonnet-20250219": @@ -110,7 +115,9 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa // Then check for models that support prompt caching switch (modelId) { + case "claude-sonnet-4-5-20250514": case "claude-sonnet-4-20250514": + case "claude-opus-4-5-20250514": case "claude-opus-4-1-20250805": case "claude-opus-4-20250514": case "claude-3-7-sonnet-20250219": @@ -243,8 +250,11 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa let id = modelId && modelId in anthropicModels ? (modelId as AnthropicModelId) : anthropicDefaultModelId let info: ModelInfo = anthropicModels[id] - // If 1M context beta is enabled for Claude Sonnet 4, update the model info - if (id === "claude-sonnet-4-20250514" && this.options.anthropicBeta1MContext) { + // If 1M context beta is enabled for Claude Sonnet 4 or 4.5, update the model info + if ( + (id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5-20250514") && + this.options.anthropicBeta1MContext + ) { // Use the tier pricing for 1M context const tier = info.tiers?.[0] if (tier) { diff --git a/webview-ui/src/components/settings/providers/Anthropic.tsx b/webview-ui/src/components/settings/providers/Anthropic.tsx index ede2b90208..3aeed2b479 100644 --- a/webview-ui/src/components/settings/providers/Anthropic.tsx +++ b/webview-ui/src/components/settings/providers/Anthropic.tsx @@ -22,7 +22,8 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro const [anthropicBaseUrlSelected, setAnthropicBaseUrlSelected] = useState(!!apiConfiguration?.anthropicBaseUrl) // Check if the current model supports 1M context beta - const supports1MContextBeta = selectedModel?.id === "claude-sonnet-4-20250514" + const supports1MContextBeta = + selectedModel?.id === "claude-sonnet-4-20250514" || selectedModel?.id === "claude-sonnet-4-5-20250514" const handleInputChange = useCallback( ( From 049f239fce26ea081bc6719f65c63655a3538560 Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Mon, 29 Sep 2025 12:09:26 -0500 Subject: [PATCH 4/6] refactor: remove Claude 4.5 Opus model references from providers and tests --- packages/types/src/providers/anthropic.ts | 12 ------------ packages/types/src/providers/bedrock.ts | 15 --------------- packages/types/src/providers/claude-code.ts | 8 -------- packages/types/src/providers/vertex.ts | 12 ------------ src/api/providers/__tests__/anthropic.spec.ts | 12 ------------ src/api/providers/anthropic.ts | 2 -- 6 files changed, 61 deletions(-) diff --git a/packages/types/src/providers/anthropic.ts b/packages/types/src/providers/anthropic.ts index f6057fbcca..e6d839edc6 100644 --- a/packages/types/src/providers/anthropic.ts +++ b/packages/types/src/providers/anthropic.ts @@ -50,18 +50,6 @@ export const anthropicModels = { }, ], }, - "claude-opus-4-5-20250514": { - maxTokens: 32_000, // Overridden to 8k if `enableReasoningEffort` is false. - contextWindow: 200_000, - supportsImages: true, - supportsComputerUse: true, - supportsPromptCache: true, - inputPrice: 15.0, // $15 per million input tokens - outputPrice: 75.0, // $75 per million output tokens - cacheWritesPrice: 18.75, // $18.75 per million tokens - cacheReadsPrice: 1.5, // $1.50 per million tokens - supportsReasoningBudget: true, - }, "claude-opus-4-1-20250805": { maxTokens: 8192, contextWindow: 200_000, diff --git a/packages/types/src/providers/bedrock.ts b/packages/types/src/providers/bedrock.ts index a6fff55a7a..febf051dc5 100644 --- a/packages/types/src/providers/bedrock.ts +++ b/packages/types/src/providers/bedrock.ts @@ -97,21 +97,6 @@ export const bedrockModels = { maxCachePoints: 4, cachableFields: ["system", "messages", "tools"], }, - "anthropic.claude-opus-4-5-20250514-v1:0": { - maxTokens: 8192, - contextWindow: 200_000, - supportsImages: true, - supportsComputerUse: true, - supportsPromptCache: true, - supportsReasoningBudget: true, - inputPrice: 15.0, - outputPrice: 75.0, - cacheWritesPrice: 18.75, - cacheReadsPrice: 1.5, - minTokensPerCachePoint: 1024, - maxCachePoints: 4, - cachableFields: ["system", "messages", "tools"], - }, "anthropic.claude-opus-4-1-20250805-v1:0": { maxTokens: 8192, contextWindow: 200_000, diff --git a/packages/types/src/providers/claude-code.ts b/packages/types/src/providers/claude-code.ts index a99f89335c..63ee5cf388 100644 --- a/packages/types/src/providers/claude-code.ts +++ b/packages/types/src/providers/claude-code.ts @@ -56,14 +56,6 @@ export const claudeCodeModels = { supportsReasoningBudget: false, requiredReasoningBudget: false, }, - "claude-opus-4-5-20250514": { - ...anthropicModels["claude-opus-4-5-20250514"], - supportsImages: false, - supportsPromptCache: true, // Claude Code does report cache tokens - supportsReasoningEffort: false, - supportsReasoningBudget: false, - requiredReasoningBudget: false, - }, "claude-opus-4-1-20250805": { ...anthropicModels["claude-opus-4-1-20250805"], supportsImages: false, diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index d1a1e0b12c..707e11e655 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -187,18 +187,6 @@ export const vertexModels = { cacheReadsPrice: 0.3, supportsReasoningBudget: true, }, - "claude-opus-4-5@20250514": { - maxTokens: 8192, - contextWindow: 200_000, - supportsImages: true, - supportsComputerUse: true, - supportsPromptCache: true, - inputPrice: 15.0, - outputPrice: 75.0, - cacheWritesPrice: 18.75, - cacheReadsPrice: 1.5, - supportsReasoningBudget: true, - }, "claude-opus-4-1@20250805": { maxTokens: 8192, contextWindow: 200_000, diff --git a/src/api/providers/__tests__/anthropic.spec.ts b/src/api/providers/__tests__/anthropic.spec.ts index a71ddd55f4..98c727abbd 100644 --- a/src/api/providers/__tests__/anthropic.spec.ts +++ b/src/api/providers/__tests__/anthropic.spec.ts @@ -277,18 +277,6 @@ describe("AnthropicHandler", () => { expect(model.info.supportsReasoningBudget).toBe(true) }) - it("should handle Claude 4.5 Opus model correctly", () => { - const handler = new AnthropicHandler({ - apiKey: "test-api-key", - apiModelId: "claude-opus-4-5-20250514", - }) - const model = handler.getModel() - expect(model.id).toBe("claude-opus-4-5-20250514") - expect(model.info.maxTokens).toBe(32000) - expect(model.info.contextWindow).toBe(200000) - expect(model.info.supportsReasoningBudget).toBe(true) - }) - it("should enable 1M context for Claude 4.5 Sonnet when beta flag is set", () => { const handler = new AnthropicHandler({ apiKey: "test-api-key", diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index 9f328be904..43538438e2 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -56,7 +56,6 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa switch (modelId) { case "claude-sonnet-4-5-20250514": case "claude-sonnet-4-20250514": - case "claude-opus-4-5-20250514": case "claude-opus-4-1-20250805": case "claude-opus-4-20250514": case "claude-3-7-sonnet-20250219": @@ -117,7 +116,6 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa switch (modelId) { case "claude-sonnet-4-5-20250514": case "claude-sonnet-4-20250514": - case "claude-opus-4-5-20250514": case "claude-opus-4-1-20250805": case "claude-opus-4-20250514": case "claude-3-7-sonnet-20250219": From 5e018407aca44f19bc6d1a404d566be527ab3a0f Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Mon, 29 Sep 2025 12:14:10 -0500 Subject: [PATCH 5/6] refactor: update Claude model identifiers to use new naming convention --- packages/types/src/providers/anthropic.ts | 2 +- packages/types/src/providers/bedrock.ts | 2 +- packages/types/src/providers/claude-code.ts | 4 ++-- packages/types/src/providers/vertex.ts | 2 +- src/api/providers/__tests__/anthropic.spec.ts | 6 +++--- src/api/providers/anthropic.ts | 11 ++++------- .../src/components/settings/providers/Anthropic.tsx | 2 +- 7 files changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/types/src/providers/anthropic.ts b/packages/types/src/providers/anthropic.ts index e6d839edc6..1c0977bd06 100644 --- a/packages/types/src/providers/anthropic.ts +++ b/packages/types/src/providers/anthropic.ts @@ -6,7 +6,7 @@ export type AnthropicModelId = keyof typeof anthropicModels export const anthropicDefaultModelId: AnthropicModelId = "claude-sonnet-4-20250514" export const anthropicModels = { - "claude-sonnet-4-5-20250514": { + "claude-4.5-sonnet": { maxTokens: 64_000, // Overridden to 8k if `enableReasoningEffort` is false. contextWindow: 200_000, // Default 200K, extendable to 1M with beta flag 'context-1m-2025-08-07' supportsImages: true, diff --git a/packages/types/src/providers/bedrock.ts b/packages/types/src/providers/bedrock.ts index febf051dc5..fb5072e60c 100644 --- a/packages/types/src/providers/bedrock.ts +++ b/packages/types/src/providers/bedrock.ts @@ -67,7 +67,7 @@ export const bedrockModels = { maxCachePoints: 1, cachableFields: ["system"], }, - "anthropic.claude-sonnet-4-5-20250514-v1:0": { + "anthropic.claude-4.5-sonnet-v1:0": { maxTokens: 8192, contextWindow: 200_000, supportsImages: true, diff --git a/packages/types/src/providers/claude-code.ts b/packages/types/src/providers/claude-code.ts index 63ee5cf388..fb44b57658 100644 --- a/packages/types/src/providers/claude-code.ts +++ b/packages/types/src/providers/claude-code.ts @@ -40,8 +40,8 @@ export function getClaudeCodeModelId(baseModelId: ClaudeCodeModelId, useVertex = } export const claudeCodeModels = { - "claude-sonnet-4-5-20250514": { - ...anthropicModels["claude-sonnet-4-5-20250514"], + "claude-4.5-sonnet": { + ...anthropicModels["claude-4.5-sonnet"], supportsImages: false, supportsPromptCache: true, // Claude Code does report cache tokens supportsReasoningEffort: false, diff --git a/packages/types/src/providers/vertex.ts b/packages/types/src/providers/vertex.ts index 707e11e655..a066a4102d 100644 --- a/packages/types/src/providers/vertex.ts +++ b/packages/types/src/providers/vertex.ts @@ -163,7 +163,7 @@ export const vertexModels = { inputPrice: 1.25, outputPrice: 5, }, - "claude-sonnet-4-5@20250514": { + "claude-4.5-sonnet": { maxTokens: 8192, contextWindow: 200_000, supportsImages: true, diff --git a/src/api/providers/__tests__/anthropic.spec.ts b/src/api/providers/__tests__/anthropic.spec.ts index 98c727abbd..7b74c87dfc 100644 --- a/src/api/providers/__tests__/anthropic.spec.ts +++ b/src/api/providers/__tests__/anthropic.spec.ts @@ -268,10 +268,10 @@ describe("AnthropicHandler", () => { it("should handle Claude 4.5 Sonnet model correctly", () => { const handler = new AnthropicHandler({ apiKey: "test-api-key", - apiModelId: "claude-sonnet-4-5-20250514", + apiModelId: "claude-4.5-sonnet", }) const model = handler.getModel() - expect(model.id).toBe("claude-sonnet-4-5-20250514") + expect(model.id).toBe("claude-4.5-sonnet") expect(model.info.maxTokens).toBe(64000) expect(model.info.contextWindow).toBe(200000) expect(model.info.supportsReasoningBudget).toBe(true) @@ -280,7 +280,7 @@ describe("AnthropicHandler", () => { it("should enable 1M context for Claude 4.5 Sonnet when beta flag is set", () => { const handler = new AnthropicHandler({ apiKey: "test-api-key", - apiModelId: "claude-sonnet-4-5-20250514", + apiModelId: "claude-4.5-sonnet", anthropicBeta1MContext: true, }) const model = handler.getModel() diff --git a/src/api/providers/anthropic.ts b/src/api/providers/anthropic.ts index 43538438e2..80ef572b5b 100644 --- a/src/api/providers/anthropic.ts +++ b/src/api/providers/anthropic.ts @@ -47,14 +47,14 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa // Add 1M context beta flag if enabled for Claude Sonnet 4 and 4.5 if ( - (modelId === "claude-sonnet-4-20250514" || modelId === "claude-sonnet-4-5-20250514") && + (modelId === "claude-sonnet-4-20250514" || modelId === "claude-4.5-sonnet") && this.options.anthropicBeta1MContext ) { betas.push("context-1m-2025-08-07") } switch (modelId) { - case "claude-sonnet-4-5-20250514": + case "claude-4.5-sonnet": case "claude-sonnet-4-20250514": case "claude-opus-4-1-20250805": case "claude-opus-4-20250514": @@ -114,7 +114,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa // Then check for models that support prompt caching switch (modelId) { - case "claude-sonnet-4-5-20250514": + case "claude-4.5-sonnet": case "claude-sonnet-4-20250514": case "claude-opus-4-1-20250805": case "claude-opus-4-20250514": @@ -249,10 +249,7 @@ export class AnthropicHandler extends BaseProvider implements SingleCompletionHa let info: ModelInfo = anthropicModels[id] // If 1M context beta is enabled for Claude Sonnet 4 or 4.5, update the model info - if ( - (id === "claude-sonnet-4-20250514" || id === "claude-sonnet-4-5-20250514") && - this.options.anthropicBeta1MContext - ) { + if ((id === "claude-sonnet-4-20250514" || id === "claude-4.5-sonnet") && this.options.anthropicBeta1MContext) { // Use the tier pricing for 1M context const tier = info.tiers?.[0] if (tier) { diff --git a/webview-ui/src/components/settings/providers/Anthropic.tsx b/webview-ui/src/components/settings/providers/Anthropic.tsx index 3aeed2b479..224d1965b6 100644 --- a/webview-ui/src/components/settings/providers/Anthropic.tsx +++ b/webview-ui/src/components/settings/providers/Anthropic.tsx @@ -23,7 +23,7 @@ export const Anthropic = ({ apiConfiguration, setApiConfigurationField }: Anthro // Check if the current model supports 1M context beta const supports1MContextBeta = - selectedModel?.id === "claude-sonnet-4-20250514" || selectedModel?.id === "claude-sonnet-4-5-20250514" + selectedModel?.id === "claude-sonnet-4-20250514" || selectedModel?.id === "claude-4.5-sonnet" const handleInputChange = useCallback( ( From ad518b92c598019bfa1a962f378df2c141fee2c9 Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Mon, 29 Sep 2025 12:19:29 -0500 Subject: [PATCH 6/6] revert: remove ZAi provider changes from PR --- packages/types/src/provider-settings.ts | 221 ++++++++++++++++++------ 1 file changed, 166 insertions(+), 55 deletions(-) diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 6d628ddfdf..8434158541 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -27,53 +27,126 @@ import { internationalZAiModels, } from "./providers/index.js" +/** + * constants + */ + +export const DEFAULT_CONSECUTIVE_MISTAKE_LIMIT = 3 + +/** + * DynamicProvider + * + * Dynamic provider requires external API calls in order to get the model list. + */ + +export const dynamicProviders = [ + "openrouter", + "vercel-ai-gateway", + "huggingface", + "litellm", + "deepinfra", + "io-intelligence", + "requesty", + "unbound", + "glama", +] as const + +export type DynamicProvider = (typeof dynamicProviders)[number] + +export const isDynamicProvider = (key: string): key is DynamicProvider => + dynamicProviders.includes(key as DynamicProvider) + +/** + * LocalProvider + * + * Local providers require localhost API calls in order to get the model list. + */ + +export const localProviders = ["ollama", "lmstudio"] as const + +export type LocalProvider = (typeof localProviders)[number] + +export const isLocalProvider = (key: string): key is LocalProvider => localProviders.includes(key as LocalProvider) + +/** + * InternalProvider + * + * Internal providers require internal VSCode API calls in order to get the + * model list. + */ + +export const internalProviders = ["vscode-lm"] as const + +export type InternalProvider = (typeof internalProviders)[number] + +export const isInternalProvider = (key: string): key is InternalProvider => + internalProviders.includes(key as InternalProvider) + +/** + * CustomProvider + * + * Custom providers are completely configurable within Roo Code settings. + */ + +export const customProviders = ["openai"] as const + +export type CustomProvider = (typeof customProviders)[number] + +export const isCustomProvider = (key: string): key is CustomProvider => customProviders.includes(key as CustomProvider) + +/** + * FauxProvider + * + * Faux providers do not make external inference calls and therefore do not have + * model lists. + */ + +export const fauxProviders = ["fake-ai", "human-relay"] as const + +export type FauxProvider = (typeof fauxProviders)[number] + +export const isFauxProvider = (key: string): key is FauxProvider => fauxProviders.includes(key as FauxProvider) + /** * ProviderName */ export const providerNames = [ + ...dynamicProviders, + ...localProviders, + ...internalProviders, + ...customProviders, + ...fauxProviders, "anthropic", - "claude-code", - "glama", - "openrouter", "bedrock", - "vertex", - "openai", - "ollama", - "vscode-lm", - "lmstudio", + "cerebras", + "chutes", + "claude-code", + "doubao", + "deepseek", + "featherless", + "fireworks", "gemini", "gemini-cli", - "openai-native", + "groq", "mistral", "moonshot", - "deepseek", - "deepinfra", - "doubao", + "openai-native", "qwen-code", - "unbound", - "requesty", - "human-relay", - "fake-ai", - "xai", - "groq", - "chutes", - "litellm", - "huggingface", - "cerebras", + "roo", "sambanova", + "vertex", + "xai", "zai", - "fireworks", - "featherless", - "io-intelligence", - "roo", - "vercel-ai-gateway", ] as const export const providerNamesSchema = z.enum(providerNames) export type ProviderName = z.infer +export const isProviderName = (key: unknown): key is ProviderName => + typeof key === "string" && providerNames.includes(key as ProviderName) + /** * ProviderSettingsEntry */ @@ -91,11 +164,6 @@ export type ProviderSettingsEntry = z.infer * ProviderSettings */ -/** - * Default value for consecutive mistake limit - */ -export const DEFAULT_CONSECUTIVE_MISTAKE_LIMIT = 3 - const baseProviderSettingsSchema = z.object({ includeMaxTokens: z.boolean().optional(), diffEnabled: z.boolean().optional(), @@ -124,7 +192,7 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({ apiKey: z.string().optional(), anthropicBaseUrl: z.string().optional(), anthropicUseAuthToken: z.boolean().optional(), - anthropicBeta1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window + anthropicBeta1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window. }) const claudeCodeSchema = apiModelIdProviderModelSchema.extend({ @@ -160,7 +228,7 @@ const bedrockSchema = apiModelIdProviderModelSchema.extend({ awsModelContextWindow: z.number().optional(), awsBedrockEndpointEnabled: z.boolean().optional(), awsBedrockEndpoint: z.string().optional(), - awsBedrock1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window + awsBedrock1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window. }) const vertexSchema = apiModelIdProviderModelSchema.extend({ @@ -190,6 +258,7 @@ const ollamaSchema = baseProviderSettingsSchema.extend({ ollamaModelId: z.string().optional(), ollamaBaseUrl: z.string().optional(), ollamaApiKey: z.string().optional(), + ollamaNumCtx: z.number().int().min(128).optional(), }) const vsCodeLmSchema = baseProviderSettingsSchema.extend({ @@ -335,7 +404,7 @@ const qwenCodeSchema = apiModelIdProviderModelSchema.extend({ }) const rooSchema = apiModelIdProviderModelSchema.extend({ - // No additional fields needed - uses cloud authentication + // No additional fields needed - uses cloud authentication. }) const vercelAiGatewaySchema = baseProviderSettingsSchema.extend({ @@ -440,7 +509,11 @@ export type ProviderSettingsWithId = z.infer[] = [ +/** + * ModelIdKey + */ + +export const modelIdKeys = [ "apiModelId", "glamaModelId", "openRouterModelId", @@ -455,13 +528,63 @@ export const MODEL_ID_KEYS: Partial[] = [ "ioIntelligenceModelId", "vercelAiGatewayModelId", "deepInfraModelId", -] +] as const satisfies readonly (keyof ProviderSettings)[] + +export type ModelIdKey = (typeof modelIdKeys)[number] export const getModelId = (settings: ProviderSettings): string | undefined => { - const modelIdKey = MODEL_ID_KEYS.find((key) => settings[key]) - return modelIdKey ? (settings[modelIdKey] as string) : undefined + const modelIdKey = modelIdKeys.find((key) => settings[key]) + return modelIdKey ? settings[modelIdKey] : undefined +} + +/** + * TypicalProvider + */ + +export type TypicalProvider = Exclude + +export const isTypicalProvider = (key: unknown): key is TypicalProvider => + isProviderName(key) && !isInternalProvider(key) && !isCustomProvider(key) && !isFauxProvider(key) + +export const modelIdKeysByProvider: Record = { + anthropic: "apiModelId", + "claude-code": "apiModelId", + glama: "glamaModelId", + openrouter: "openRouterModelId", + bedrock: "apiModelId", + vertex: "apiModelId", + "openai-native": "openAiModelId", + ollama: "ollamaModelId", + lmstudio: "lmStudioModelId", + gemini: "apiModelId", + "gemini-cli": "apiModelId", + mistral: "apiModelId", + moonshot: "apiModelId", + deepseek: "apiModelId", + deepinfra: "deepInfraModelId", + doubao: "apiModelId", + "qwen-code": "apiModelId", + unbound: "unboundModelId", + requesty: "requestyModelId", + xai: "apiModelId", + groq: "apiModelId", + chutes: "apiModelId", + litellm: "litellmModelId", + huggingface: "huggingFaceModelId", + cerebras: "apiModelId", + sambanova: "apiModelId", + zai: "apiModelId", + fireworks: "apiModelId", + featherless: "apiModelId", + "io-intelligence": "ioIntelligenceModelId", + roo: "apiModelId", + "vercel-ai-gateway": "vercelAiGatewayModelId", } +/** + * ANTHROPIC_STYLE_PROVIDERS + */ + // Providers that use Anthropic-style API protocol. export const ANTHROPIC_STYLE_PROVIDERS: ProviderName[] = ["anthropic", "claude-code", "bedrock"] @@ -482,6 +605,10 @@ export const getApiProtocol = (provider: ProviderName | undefined, modelId?: str return "openai" } +/** + * MODELS_BY_PROVIDER + */ + export const MODELS_BY_PROVIDER: Record< Exclude, { id: ProviderName; label: string; models: string[] } @@ -579,19 +706,3 @@ export const MODELS_BY_PROVIDER: Record< deepinfra: { id: "deepinfra", label: "DeepInfra", models: [] }, "vercel-ai-gateway": { id: "vercel-ai-gateway", label: "Vercel AI Gateway", models: [] }, } - -export const dynamicProviders = [ - "glama", - "huggingface", - "litellm", - "openrouter", - "requesty", - "unbound", - "deepinfra", - "vercel-ai-gateway", -] as const satisfies readonly ProviderName[] - -export type DynamicProvider = (typeof dynamicProviders)[number] - -export const isDynamicProvider = (key: string): key is DynamicProvider => - dynamicProviders.includes(key as DynamicProvider)