diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 5262e7602d68..a66aae08a243 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -377,7 +377,7 @@ const sambaNovaSchema = apiModelIdProviderModelSchema.extend({ sambaNovaApiKey: z.string().optional(), }) -export const zaiApiLineSchema = z.enum(["international_coding", "china_coding"]) +export const zaiApiLineSchema = z.enum(["international_coding", "international", "china_coding", "china"]) export type ZaiApiLine = z.infer diff --git a/packages/types/src/providers/zai.ts b/packages/types/src/providers/zai.ts index b4049b812283..e593894ade71 100644 --- a/packages/types/src/providers/zai.ts +++ b/packages/types/src/providers/zai.ts @@ -1,8 +1,8 @@ import type { ModelInfo } from "../model.js" -import { ZaiApiLine } from "../provider-settings.js" // Z AI // https://docs.z.ai/guides/llm/glm-4.5 +// https://docs.z.ai/guides/llm/glm-4.6 // https://docs.z.ai/guides/overview/pricing export type InternationalZAiModelId = keyof typeof internationalZAiModels @@ -20,6 +20,30 @@ export const internationalZAiModels = { description: "GLM-4.5 is Zhipu's latest featured model. Its comprehensive capabilities in reasoning, coding, and agent reach the state-of-the-art (SOTA) level among open-source models, with a context length of up to 128k.", }, + "glm-4.6": { + maxTokens: 98_304, + contextWindow: 204_800, + supportsImages: false, + supportsPromptCache: true, + inputPrice: 0.6, + outputPrice: 2.2, + cacheWritesPrice: 0, + cacheReadsPrice: 0.11, + description: + "GLM-4.6 is Zhipu's newest model with an extended context window of up to 200k tokens, providing enhanced capabilities for processing longer documents and conversations.", + }, + "glm-4.5v": { + maxTokens: 16_384, + contextWindow: 64_000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 0.6, + outputPrice: 1.8, + cacheWritesPrice: 0, + cacheReadsPrice: 0.11, + // International pricing tiers for GLM-4.5V are not publicly documented as of 2025-10-20; mainland tiers are defined below. + description: "GLM-4.5V is Zhipu's new generation of visual reasoning models based on the MOE architecture.", + }, "glm-4.5-air": { maxTokens: 98_304, contextWindow: 131_072, @@ -32,17 +56,49 @@ export const internationalZAiModels = { description: "GLM-4.5-Air is the lightweight version of GLM-4.5. It balances performance and cost-effectiveness, and can flexibly switch to hybrid thinking models.", }, - "glm-4.6": { + "glm-4.5-x": { maxTokens: 98_304, - contextWindow: 204_800, + contextWindow: 131_072, supportsImages: false, supportsPromptCache: true, - inputPrice: 0.6, - outputPrice: 2.2, + inputPrice: 2.2, + outputPrice: 8.9, cacheWritesPrice: 0, - cacheReadsPrice: 0.11, - description: - "GLM-4.6 is Zhipu's newest model with an extended context window of up to 200k tokens, providing enhanced capabilities for processing longer documents and conversations.", + cacheReadsPrice: 0.45, + description: "GLM-4.5-X is the extended version with enhanced capabilities and performance for complex tasks.", + }, + "glm-4.5-airx": { + maxTokens: 98_304, + contextWindow: 131_072, + supportsImages: false, + supportsPromptCache: true, + inputPrice: 1.1, + outputPrice: 4.5, + cacheWritesPrice: 0, + cacheReadsPrice: 0.22, + description: "GLM-4.5-AirX is the extended version of GLM-4.5-Air with enhanced capabilities.", + }, + "glm-4-32b-0414-128k": { + maxTokens: 98_304, + contextWindow: 131_072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.1, + outputPrice: 0.1, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + description: "GLM-4-32B is a 32 billion parameter model with 128k context length, optimized for efficiency.", + }, + "glm-4.5-flash": { + maxTokens: 98_304, + contextWindow: 131_072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0, + outputPrice: 0, + cacheWritesPrice: 0, + cacheReadsPrice: 0, + description: "Zhipu's most advanced free model to date.", }, } as const satisfies Record @@ -113,6 +169,37 @@ export const mainlandZAiModels = { }, ], }, + "glm-4.5v": { + maxTokens: 16_384, + contextWindow: 64_000, + supportsImages: true, + supportsPromptCache: true, + inputPrice: 0.6, + outputPrice: 1.8, + cacheWritesPrice: 0, + cacheReadsPrice: 0.11, + description: "GLM-4.5V is Zhipu's new generation of visual reasoning models based on the MOE architecture.", + tiers: [ + { + contextWindow: 32_000, + inputPrice: 0.21, + outputPrice: 0.4, + cacheReadsPrice: 0.06, + }, + { + contextWindow: 64_000, + inputPrice: 0.6, + outputPrice: 1.8, + cacheReadsPrice: 0.11, + }, + { + contextWindow: Infinity, + inputPrice: 0.6, + outputPrice: 1.8, + cacheReadsPrice: 0.11, + }, + ], + }, "glm-4.6": { maxTokens: 98_304, contextWindow: 204_800, @@ -155,15 +242,15 @@ export const mainlandZAiModels = { export const ZAI_DEFAULT_TEMPERATURE = 0 +type ZaiApiLineLiteral = "international_coding" | "international" | "china_coding" | "china" + export const zaiApiLineConfigs = { international_coding: { name: "International Coding Plan", baseUrl: "https://api.z.ai/api/coding/paas/v4", isChina: false, }, - china_coding: { - name: "China Coding Plan", - baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4", - isChina: true, - }, -} satisfies Record + 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 diff --git a/src/api/providers/__tests__/zai.spec.ts b/src/api/providers/__tests__/zai.spec.ts index bb892960889f..937794106db4 100644 --- a/src/api/providers/__tests__/zai.spec.ts +++ b/src/api/providers/__tests__/zai.spec.ts @@ -84,6 +84,20 @@ describe("ZAiHandler", () => { expect(model.info).toEqual(internationalZAiModels[testModelId]) expect(model.info.contextWindow).toBe(204_800) }) + + it("should return GLM-4.5V international model with image support", () => { + const testModelId: InternationalZAiModelId = "glm-4.5v" + const handlerWithModel = new ZAiHandler({ + apiModelId: testModelId, + zaiApiKey: "test-zai-api-key", + zaiApiLine: "international", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual(internationalZAiModels[testModelId]) + expect(model.info.supportsImages).toBe(true) + expect(model.info.contextWindow).toBe(64_000) + }) }) describe("China Z AI", () => { @@ -134,6 +148,25 @@ describe("ZAiHandler", () => { expect(model.info).toEqual(mainlandZAiModels[testModelId]) expect(model.info.contextWindow).toBe(204_800) }) + + it("should return GLM-4.5V China model with image support", () => { + const testModelId: MainlandZAiModelId = "glm-4.5v" + const handlerWithModel = new ZAiHandler({ + apiModelId: testModelId, + zaiApiKey: "test-zai-api-key", + zaiApiLine: "china", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual(mainlandZAiModels[testModelId]) + expect(model.info.supportsImages).toBe(true) + expect(model.info.contextWindow).toBe(64_000) + }) + + it("should include tiers for GLM-4.5V China model", () => { + const info = mainlandZAiModels["glm-4.5v"] + expect(info.tiers?.length).toBe(3) + }) }) describe("Default behavior", () => { diff --git a/src/api/providers/zai.ts b/src/api/providers/zai.ts index ce5aab9dd9f8..c0cae24a09e2 100644 --- a/src/api/providers/zai.ts +++ b/src/api/providers/zai.ts @@ -3,29 +3,47 @@ import { mainlandZAiModels, internationalZAiDefaultModelId, mainlandZAiDefaultModelId, - type InternationalZAiModelId, - type MainlandZAiModelId, ZAI_DEFAULT_TEMPERATURE, - zaiApiLineConfigs, } from "@roo-code/types" import type { ApiHandlerOptions } from "../../shared/api" +import type { InternationalZAiModelId, MainlandZAiModelId, ModelInfo } from "@roo-code/types" import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider" -export class ZAiHandler extends BaseOpenAiCompatibleProvider { +type ZAiModelId = InternationalZAiModelId | MainlandZAiModelId + +// Local mapping to avoid cross-package runtime dependency issues in CI +type ZaiApiLineLocal = "international_coding" | "international" | "china_coding" | "china" +const ZAI_LINE_CONFIGS: Record = { + 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 }, +} + +export class ZAiHandler extends BaseOpenAiCompatibleProvider { constructor(options: ApiHandlerOptions) { - const isChina = zaiApiLineConfigs[options.zaiApiLine ?? "international_coding"].isChina - const models = isChina ? mainlandZAiModels : internationalZAiModels + const line = (options.zaiApiLine ?? "international_coding") as ZaiApiLineLocal + const { isChina, baseUrl } = ZAI_LINE_CONFIGS[line] + const defaultModelId = isChina ? mainlandZAiDefaultModelId : internationalZAiDefaultModelId + const providerModels = (isChina ? mainlandZAiModels : internationalZAiModels) as unknown as Record< + ZAiModelId, + ModelInfo + > super({ ...options, providerName: "Z AI", - baseURL: zaiApiLineConfigs[options.zaiApiLine ?? "international_coding"].baseUrl, + baseURL: baseUrl, apiKey: options.zaiApiKey ?? "not-provided", defaultProviderModelId: defaultModelId, - providerModels: models, + providerModels, defaultTemperature: ZAI_DEFAULT_TEMPERATURE, }) }