Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export const providerNames = [
"huggingface",
"cerebras",
"sambanova",
"zai",
] as const

export const providerNamesSchema = z.enum(providerNames)
Expand Down Expand Up @@ -257,6 +258,11 @@ const sambaNovaSchema = apiModelIdProviderModelSchema.extend({
sambaNovaApiKey: z.string().optional(),
})

const zaiSchema = apiModelIdProviderModelSchema.extend({
zaiApiKey: z.string().optional(),
zaiApiLine: z.union([z.literal("china"), z.literal("international")]).optional(),
})

const defaultSchema = z.object({
apiProvider: z.undefined(),
})
Expand Down Expand Up @@ -290,6 +296,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv
litellmSchema.merge(z.object({ apiProvider: z.literal("litellm") })),
cerebrasSchema.merge(z.object({ apiProvider: z.literal("cerebras") })),
sambaNovaSchema.merge(z.object({ apiProvider: z.literal("sambanova") })),
zaiSchema.merge(z.object({ apiProvider: z.literal("zai") })),
defaultSchema,
])

Expand Down Expand Up @@ -323,6 +330,7 @@ export const providerSettingsSchema = z.object({
...litellmSchema.shape,
...cerebrasSchema.shape,
...sambaNovaSchema.shape,
...zaiSchema.shape,
...codebaseIndexProviderSchema.shape,
})

Expand Down
1 change: 1 addition & 0 deletions packages/types/src/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from "./vertex.js"
export * from "./vscode-llm.js"
export * from "./xai.js"
export * from "./doubao.js"
export * from "./zai.js"
105 changes: 105 additions & 0 deletions packages/types/src/providers/zai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import type { ModelInfo } from "../model.js"

// Z AI
// https://docs.z.ai/guides/llm/glm-4.5
// https://docs.z.ai/guides/overview/pricing

export type InternationalZAiModelId = keyof typeof internationalZAiModels
export const internationalZAiDefaultModelId: InternationalZAiModelId = "glm-4.5"
export const internationalZAiModels = {
"glm-4.5": {
maxTokens: 98_304,
contextWindow: 131_072,
supportsImages: false,
supportsPromptCache: true,
inputPrice: 0.6,
outputPrice: 2.2,
cacheWritesPrice: 0,
cacheReadsPrice: 0.11,
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.5-air": {
maxTokens: 98_304,
contextWindow: 131_072,
supportsImages: false,
supportsPromptCache: true,
inputPrice: 0.2,
outputPrice: 1.1,
cacheWritesPrice: 0,
cacheReadsPrice: 0.03,
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.",
},
} as const satisfies Record<string, ModelInfo>

export type MainlandZAiModelId = keyof typeof mainlandZAiModels
export const mainlandZAiDefaultModelId: MainlandZAiModelId = "glm-4.5"
export const mainlandZAiModels = {
"glm-4.5": {
maxTokens: 98_304,
contextWindow: 131_072,
supportsImages: false,
supportsPromptCache: true,
inputPrice: 0.29,
outputPrice: 1.14,
cacheWritesPrice: 0,
cacheReadsPrice: 0.057,
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.",
tiers: [
{
contextWindow: 32_000,
inputPrice: 0.21,
outputPrice: 1.0,
cacheReadsPrice: 0.043,
},
{
contextWindow: 128_000,
inputPrice: 0.29,
outputPrice: 1.14,
cacheReadsPrice: 0.057,
},
{
contextWindow: Infinity,
inputPrice: 0.29,
outputPrice: 1.14,
cacheReadsPrice: 0.057,
},
],
},
"glm-4.5-air": {
maxTokens: 98_304,
contextWindow: 131_072,
supportsImages: false,
supportsPromptCache: true,
inputPrice: 0.1,
outputPrice: 0.6,
cacheWritesPrice: 0,
cacheReadsPrice: 0.02,
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.",
tiers: [
{
contextWindow: 32_000,
inputPrice: 0.07,
outputPrice: 0.4,
cacheReadsPrice: 0.014,
},
{
contextWindow: 128_000,
inputPrice: 0.1,
outputPrice: 0.6,
cacheReadsPrice: 0.02,
},
{
contextWindow: Infinity,
inputPrice: 0.1,
outputPrice: 0.6,
cacheReadsPrice: 0.02,
},
],
},
} as const satisfies Record<string, ModelInfo>

export const ZAI_DEFAULT_TEMPERATURE = 0
3 changes: 3 additions & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
ClaudeCodeHandler,
SambaNovaHandler,
DoubaoHandler,
ZAiHandler,
} from "./providers"

export interface SingleCompletionHandler {
Expand Down Expand Up @@ -124,6 +125,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler {
return new CerebrasHandler(options)
case "sambanova":
return new SambaNovaHandler(options)
case "zai":
return new ZAiHandler(options)
default:
apiProvider satisfies "gemini-cli" | undefined
return new AnthropicHandler(options)
Expand Down
1 change: 1 addition & 0 deletions src/api/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ export { UnboundHandler } from "./unbound"
export { VertexHandler } from "./vertex"
export { VsCodeLmHandler } from "./vscode-lm"
export { XAIHandler } from "./xai"
export { ZAiHandler } from "./zai"
31 changes: 31 additions & 0 deletions src/api/providers/zai.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {
internationalZAiModels,
mainlandZAiModels,
internationalZAiDefaultModelId,
mainlandZAiDefaultModelId,
type InternationalZAiModelId,
type MainlandZAiModelId,
ZAI_DEFAULT_TEMPERATURE,
} from "@roo-code/types"

import type { ApiHandlerOptions } from "../../shared/api"

import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"

export class ZAiHandler extends BaseOpenAiCompatibleProvider<InternationalZAiModelId | MainlandZAiModelId> {
constructor(options: ApiHandlerOptions) {
const isChina = options.zaiApiLine === "china"
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",
apiKey: options.zaiApiKey ?? "not-provided",
defaultProviderModelId: defaultModelId,
providerModels: models,
defaultTemperature: ZAI_DEFAULT_TEMPERATURE,
})
}
}
14 changes: 14 additions & 0 deletions webview-ui/src/components/settings/ApiOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ import {
bedrockDefaultModelId,
vertexDefaultModelId,
sambaNovaDefaultModelId,
internationalZAiDefaultModelId,
mainlandZAiDefaultModelId,
} from "@roo-code/types"

import { vscode } from "@src/utils/vscode"
Expand Down Expand Up @@ -79,6 +81,7 @@ import {
Vertex,
VSCodeLM,
XAI,
ZAi,
} from "./providers"

import { MODELS_BY_PROVIDER, PROVIDERS } from "./constants"
Expand Down Expand Up @@ -306,6 +309,13 @@ const ApiOptions = ({
bedrock: { field: "apiModelId", default: bedrockDefaultModelId },
vertex: { field: "apiModelId", default: vertexDefaultModelId },
sambanova: { field: "apiModelId", default: sambaNovaDefaultModelId },
zai: {
field: "apiModelId",
default:
apiConfiguration.zaiApiLine === "china"
? mainlandZAiDefaultModelId
: internationalZAiDefaultModelId,
},
openai: { field: "openAiModelId" },
ollama: { field: "ollamaModelId" },
lmstudio: { field: "lmStudioModelId" },
Expand Down Expand Up @@ -530,6 +540,10 @@ const ApiOptions = ({
<SambaNova apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} />
)}

{selectedProvider === "zai" && (
<ZAi apiConfiguration={apiConfiguration} setApiConfigurationField={setApiConfigurationField} />
)}

{selectedProvider === "human-relay" && (
<>
<div className="text-sm text-vscode-descriptionForeground">
Expand Down
3 changes: 3 additions & 0 deletions webview-ui/src/components/settings/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
chutesModels,
sambaNovaModels,
doubaoModels,
internationalZAiModels,
} from "@roo-code/types"

export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, ModelInfo>>> = {
Expand All @@ -34,6 +35,7 @@ export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, Mod
groq: groqModels,
chutes: chutesModels,
sambanova: sambaNovaModels,
zai: internationalZAiModels,
}

export const PROVIDERS = [
Expand Down Expand Up @@ -63,4 +65,5 @@ export const PROVIDERS = [
{ value: "chutes", label: "Chutes AI" },
{ value: "litellm", label: "LiteLLM" },
{ value: "sambanova", label: "SambaNova" },
{ value: "zai", label: "Z AI" },
].sort((a, b) => a.label.localeCompare(b.label))
77 changes: 77 additions & 0 deletions webview-ui/src/components/settings/providers/ZAi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useCallback } from "react"
import { VSCodeTextField, VSCodeDropdown, VSCodeOption } from "@vscode/webview-ui-toolkit/react"

import type { ProviderSettings } from "@roo-code/types"

import { useAppTranslation } from "@src/i18n/TranslationContext"
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"

import { inputEventTransform } from "../transforms"
import { cn } from "@/lib/utils"

type ZAiProps = {
apiConfiguration: ProviderSettings
setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void
}

export const ZAi = ({ apiConfiguration, setApiConfigurationField }: ZAiProps) => {
const { t } = useAppTranslation()

const handleInputChange = useCallback(
<K extends keyof ProviderSettings, E>(
field: K,
transform: (event: E) => ProviderSettings[K] = inputEventTransform,
) =>
(event: E | Event) => {
setApiConfigurationField(field, transform(event as E))
},
[setApiConfigurationField],
)

return (
<>
<div>
<label className="block font-medium mb-1">Z AI Entrypoint</label>
<VSCodeDropdown
value={apiConfiguration.zaiApiLine || "international"}
onChange={handleInputChange("zaiApiLine")}
className={cn("w-full")}>
<VSCodeOption value="international" className="p-2">
api.z.ai
</VSCodeOption>
<VSCodeOption value="china" className="p-2">
open.bigmodel.cn
</VSCodeOption>
</VSCodeDropdown>
<div className="text-xs text-vscode-descriptionForeground mt-1">
Please select the appropriate API entrypoint based on your location. If you are in China, choose
open.bigmodel.cn. Otherwise, choose api.z.ai.
</div>
</div>
<div>
<VSCodeTextField
value={apiConfiguration?.zaiApiKey || ""}
type="password"
onInput={handleInputChange("zaiApiKey")}
placeholder={t("settings:placeholders.apiKey")}
className="w-full">
<label className="block font-medium mb-1">Z AI API Key</label>
</VSCodeTextField>
<div className="text-sm text-vscode-descriptionForeground">
{t("settings:providers.apiKeyStorageNotice")}
</div>
{!apiConfiguration?.zaiApiKey && (
<VSCodeButtonLink
href={
apiConfiguration.zaiApiLine === "china"
? "https://open.bigmodel.cn/console/overview"
: "https://z.ai/manage-apikey/apikey-list"
}
appearance="secondary">
Get Z AI API Key
</VSCodeButtonLink>
)}
</div>
</>
)
}
1 change: 1 addition & 0 deletions webview-ui/src/components/settings/providers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ export { Unbound } from "./Unbound"
export { Vertex } from "./Vertex"
export { VSCodeLM } from "./VSCodeLM"
export { XAI } from "./XAI"
export { ZAi } from "./ZAi"
export { LiteLLM } from "./LiteLLM"
12 changes: 12 additions & 0 deletions webview-ui/src/components/ui/hooks/useSelectedModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ import {
sambaNovaDefaultModelId,
doubaoModels,
doubaoDefaultModelId,
internationalZAiDefaultModelId,
mainlandZAiDefaultModelId,
internationalZAiModels,
mainlandZAiModels,
} from "@roo-code/types"

import type { ModelRecord, RouterModels } from "@roo/api"
Expand Down Expand Up @@ -203,6 +207,14 @@ function getSelectedModel({
const info = moonshotModels[id as keyof typeof moonshotModels]
return { id, info }
}
case "zai": {
const isChina = apiConfiguration.zaiApiLine === "china"
const models = isChina ? mainlandZAiModels : internationalZAiModels
const defaultModelId = isChina ? mainlandZAiDefaultModelId : internationalZAiDefaultModelId
const id = apiConfiguration.apiModelId ?? defaultModelId
const info = models[id as keyof typeof models]
return { id, info }
}
case "openai-native": {
const id = apiConfiguration.apiModelId ?? openAiNativeDefaultModelId
const info = openAiNativeModels[id as keyof typeof openAiNativeModels]
Expand Down
Loading