mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Add Z AI provider (#6657)
Co-authored-by: wangshan <shan.wang@aminer.cn>
This commit is contained in:
parent
f24c1e69a3
commit
a921d059e1
30 changed files with 558 additions and 0 deletions
|
|
@ -36,6 +36,7 @@ export const providerNames = [
|
|||
"huggingface",
|
||||
"cerebras",
|
||||
"sambanova",
|
||||
"zai",
|
||||
] as const
|
||||
|
||||
export const providerNamesSchema = z.enum(providerNames)
|
||||
|
|
@ -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(),
|
||||
})
|
||||
|
|
@ -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,
|
||||
])
|
||||
|
||||
|
|
@ -323,6 +330,7 @@ export const providerSettingsSchema = z.object({
|
|||
...litellmSchema.shape,
|
||||
...cerebrasSchema.shape,
|
||||
...sambaNovaSchema.shape,
|
||||
...zaiSchema.shape,
|
||||
...codebaseIndexProviderSchema.shape,
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -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
packages/types/src/providers/zai.ts
Normal file
105
packages/types/src/providers/zai.ts
Normal file
|
|
@ -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
|
||||
|
|
@ -33,6 +33,7 @@ import {
|
|||
ClaudeCodeHandler,
|
||||
SambaNovaHandler,
|
||||
DoubaoHandler,
|
||||
ZAiHandler,
|
||||
} from "./providers"
|
||||
|
||||
export interface SingleCompletionHandler {
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
231
src/api/providers/__tests__/zai.spec.ts
Normal file
231
src/api/providers/__tests__/zai.spec.ts
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
// npx vitest run src/api/providers/__tests__/zai.spec.ts
|
||||
|
||||
// Mock vscode first to avoid import errors
|
||||
vitest.mock("vscode", () => ({}))
|
||||
|
||||
import OpenAI from "openai"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
|
||||
import {
|
||||
type InternationalZAiModelId,
|
||||
type MainlandZAiModelId,
|
||||
internationalZAiDefaultModelId,
|
||||
mainlandZAiDefaultModelId,
|
||||
internationalZAiModels,
|
||||
mainlandZAiModels,
|
||||
ZAI_DEFAULT_TEMPERATURE,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { ZAiHandler } from "../zai"
|
||||
|
||||
vitest.mock("openai", () => {
|
||||
const createMock = vitest.fn()
|
||||
return {
|
||||
default: vitest.fn(() => ({ chat: { completions: { create: createMock } } })),
|
||||
}
|
||||
})
|
||||
|
||||
describe("ZAiHandler", () => {
|
||||
let handler: ZAiHandler
|
||||
let mockCreate: any
|
||||
|
||||
beforeEach(() => {
|
||||
vitest.clearAllMocks()
|
||||
mockCreate = (OpenAI as unknown as any)().chat.completions.create
|
||||
})
|
||||
|
||||
describe("International Z AI", () => {
|
||||
beforeEach(() => {
|
||||
handler = new ZAiHandler({ zaiApiKey: "test-zai-api-key", zaiApiLine: "international" })
|
||||
})
|
||||
|
||||
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" }))
|
||||
})
|
||||
|
||||
it("should use the provided API key for international", () => {
|
||||
const zaiApiKey = "test-zai-api-key"
|
||||
new ZAiHandler({ zaiApiKey, zaiApiLine: "international" })
|
||||
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: zaiApiKey }))
|
||||
})
|
||||
|
||||
it("should return international default model when no model is specified", () => {
|
||||
const model = handler.getModel()
|
||||
expect(model.id).toBe(internationalZAiDefaultModelId)
|
||||
expect(model.info).toEqual(internationalZAiModels[internationalZAiDefaultModelId])
|
||||
})
|
||||
|
||||
it("should return specified international model when valid model is provided", () => {
|
||||
const testModelId: InternationalZAiModelId = "glm-4.5-air"
|
||||
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])
|
||||
})
|
||||
})
|
||||
|
||||
describe("China Z AI", () => {
|
||||
beforeEach(() => {
|
||||
handler = new ZAiHandler({ zaiApiKey: "test-zai-api-key", zaiApiLine: "china" })
|
||||
})
|
||||
|
||||
it("should use the correct China Z AI base URL", () => {
|
||||
new ZAiHandler({ zaiApiKey: "test-zai-api-key", zaiApiLine: "china" })
|
||||
expect(OpenAI).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ baseURL: "https://open.bigmodel.cn/api/paas/v4" }),
|
||||
)
|
||||
})
|
||||
|
||||
it("should use the provided API key for China", () => {
|
||||
const zaiApiKey = "test-zai-api-key"
|
||||
new ZAiHandler({ zaiApiKey, zaiApiLine: "china" })
|
||||
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: zaiApiKey }))
|
||||
})
|
||||
|
||||
it("should return China default model when no model is specified", () => {
|
||||
const model = handler.getModel()
|
||||
expect(model.id).toBe(mainlandZAiDefaultModelId)
|
||||
expect(model.info).toEqual(mainlandZAiModels[mainlandZAiDefaultModelId])
|
||||
})
|
||||
|
||||
it("should return specified China model when valid model is provided", () => {
|
||||
const testModelId: MainlandZAiModelId = "glm-4.5-air"
|
||||
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])
|
||||
})
|
||||
})
|
||||
|
||||
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" }))
|
||||
|
||||
const model = handlerDefault.getModel()
|
||||
expect(model.id).toBe(internationalZAiDefaultModelId)
|
||||
expect(model.info).toEqual(internationalZAiModels[internationalZAiDefaultModelId])
|
||||
})
|
||||
|
||||
it("should use 'not-provided' as default API key when none is specified", () => {
|
||||
new ZAiHandler({ zaiApiLine: "international" })
|
||||
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: "not-provided" }))
|
||||
})
|
||||
})
|
||||
|
||||
describe("API Methods", () => {
|
||||
beforeEach(() => {
|
||||
handler = new ZAiHandler({ zaiApiKey: "test-zai-api-key", zaiApiLine: "international" })
|
||||
})
|
||||
|
||||
it("completePrompt method should return text from Z AI API", async () => {
|
||||
const expectedResponse = "This is a test response from Z AI"
|
||||
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] })
|
||||
const result = await handler.completePrompt("test prompt")
|
||||
expect(result).toBe(expectedResponse)
|
||||
})
|
||||
|
||||
it("should handle errors in completePrompt", async () => {
|
||||
const errorMessage = "Z AI API error"
|
||||
mockCreate.mockRejectedValueOnce(new Error(errorMessage))
|
||||
await expect(handler.completePrompt("test prompt")).rejects.toThrow(
|
||||
`Z AI completion error: ${errorMessage}`,
|
||||
)
|
||||
})
|
||||
|
||||
it("createMessage should yield text content from stream", async () => {
|
||||
const testContent = "This is test content from Z AI stream"
|
||||
|
||||
mockCreate.mockImplementationOnce(() => {
|
||||
return {
|
||||
[Symbol.asyncIterator]: () => ({
|
||||
next: vitest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
done: false,
|
||||
value: { choices: [{ delta: { content: testContent } }] },
|
||||
})
|
||||
.mockResolvedValueOnce({ done: true }),
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
const stream = handler.createMessage("system prompt", [])
|
||||
const firstChunk = await stream.next()
|
||||
|
||||
expect(firstChunk.done).toBe(false)
|
||||
expect(firstChunk.value).toEqual({ type: "text", text: testContent })
|
||||
})
|
||||
|
||||
it("createMessage should yield usage data from stream", async () => {
|
||||
mockCreate.mockImplementationOnce(() => {
|
||||
return {
|
||||
[Symbol.asyncIterator]: () => ({
|
||||
next: vitest
|
||||
.fn()
|
||||
.mockResolvedValueOnce({
|
||||
done: false,
|
||||
value: {
|
||||
choices: [{ delta: {} }],
|
||||
usage: { prompt_tokens: 10, completion_tokens: 20 },
|
||||
},
|
||||
})
|
||||
.mockResolvedValueOnce({ done: true }),
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
const stream = handler.createMessage("system prompt", [])
|
||||
const firstChunk = await stream.next()
|
||||
|
||||
expect(firstChunk.done).toBe(false)
|
||||
expect(firstChunk.value).toEqual({ type: "usage", inputTokens: 10, outputTokens: 20 })
|
||||
})
|
||||
|
||||
it("createMessage should pass correct parameters to Z AI client", async () => {
|
||||
const modelId: InternationalZAiModelId = "glm-4.5"
|
||||
const modelInfo = internationalZAiModels[modelId]
|
||||
const handlerWithModel = new ZAiHandler({
|
||||
apiModelId: modelId,
|
||||
zaiApiKey: "test-zai-api-key",
|
||||
zaiApiLine: "international",
|
||||
})
|
||||
|
||||
mockCreate.mockImplementationOnce(() => {
|
||||
return {
|
||||
[Symbol.asyncIterator]: () => ({
|
||||
async next() {
|
||||
return { done: true }
|
||||
},
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
const systemPrompt = "Test system prompt for Z AI"
|
||||
const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message for Z AI" }]
|
||||
|
||||
const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages)
|
||||
await messageGenerator.next()
|
||||
|
||||
expect(mockCreate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
model: modelId,
|
||||
max_tokens: modelInfo.maxTokens,
|
||||
temperature: ZAI_DEFAULT_TEMPERATURE,
|
||||
messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]),
|
||||
stream: true,
|
||||
stream_options: { include_usage: true },
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -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
src/api/providers/zai.ts
Normal file
31
src/api/providers/zai.ts
Normal file
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,8 @@ import {
|
|||
bedrockDefaultModelId,
|
||||
vertexDefaultModelId,
|
||||
sambaNovaDefaultModelId,
|
||||
internationalZAiDefaultModelId,
|
||||
mainlandZAiDefaultModelId,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import { vscode } from "@src/utils/vscode"
|
||||
|
|
@ -79,6 +81,7 @@ import {
|
|||
Vertex,
|
||||
VSCodeLM,
|
||||
XAI,
|
||||
ZAi,
|
||||
} from "./providers"
|
||||
|
||||
import { MODELS_BY_PROVIDER, PROVIDERS } from "./constants"
|
||||
|
|
@ -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" },
|
||||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import {
|
|||
chutesModels,
|
||||
sambaNovaModels,
|
||||
doubaoModels,
|
||||
internationalZAiModels,
|
||||
} from "@roo-code/types"
|
||||
|
||||
export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, ModelInfo>>> = {
|
||||
|
|
@ -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 = [
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
76
webview-ui/src/components/settings/providers/ZAi.tsx
Normal file
76
webview-ui/src/components/settings/providers/ZAi.tsx
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
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">{t("settings:providers.zaiEntrypoint")}</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">
|
||||
{t("settings:providers.zaiEntrypointDescription")}
|
||||
</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">{t("settings:providers.zaiApiKey")}</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">
|
||||
{t("settings:providers.getZaiApiKey")}
|
||||
</VSCodeButtonLink>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ import {
|
|||
sambaNovaDefaultModelId,
|
||||
doubaoModels,
|
||||
doubaoDefaultModelId,
|
||||
internationalZAiDefaultModelId,
|
||||
mainlandZAiDefaultModelId,
|
||||
internationalZAiModels,
|
||||
mainlandZAiModels,
|
||||
} from "@roo-code/types"
|
||||
|
||||
import type { ModelRecord, RouterModels } from "@roo/api"
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/ca/settings.json
generated
4
webview-ui/src/i18n/locales/ca/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Clau API de Moonshot",
|
||||
"getMoonshotApiKey": "Obtenir clau API de Moonshot",
|
||||
"moonshotBaseUrl": "Punt d'entrada de Moonshot",
|
||||
"zaiApiKey": "Clau API de Z AI",
|
||||
"getZaiApiKey": "Obtenir clau API de Z AI",
|
||||
"zaiEntrypoint": "Punt d'entrada de Z AI",
|
||||
"zaiEntrypointDescription": "Si us plau, seleccioneu el punt d'entrada de l'API apropiat segons la vostra ubicació. Si sou a la Xina, trieu open.bigmodel.cn. Altrament, trieu api.z.ai.",
|
||||
"geminiApiKey": "Clau API de Gemini",
|
||||
"getGroqApiKey": "Obtenir clau API de Groq",
|
||||
"groqApiKey": "Clau API de Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/de/settings.json
generated
4
webview-ui/src/i18n/locales/de/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API-Schlüssel",
|
||||
"getMoonshotApiKey": "Moonshot API-Schlüssel erhalten",
|
||||
"moonshotBaseUrl": "Moonshot-Einstiegspunkt",
|
||||
"zaiApiKey": "Z AI API-Schlüssel",
|
||||
"getZaiApiKey": "Z AI API-Schlüssel erhalten",
|
||||
"zaiEntrypoint": "Z AI Einstiegspunkt",
|
||||
"zaiEntrypointDescription": "Bitte wählen Sie den entsprechenden API-Einstiegspunkt basierend auf Ihrem Standort. Wenn Sie sich in China befinden, wählen Sie open.bigmodel.cn. Andernfalls wählen Sie api.z.ai.",
|
||||
"geminiApiKey": "Gemini API-Schlüssel",
|
||||
"getGroqApiKey": "Groq API-Schlüssel erhalten",
|
||||
"groqApiKey": "Groq API-Schlüssel",
|
||||
|
|
|
|||
|
|
@ -267,6 +267,10 @@
|
|||
"moonshotApiKey": "Moonshot API Key",
|
||||
"getMoonshotApiKey": "Get Moonshot API Key",
|
||||
"moonshotBaseUrl": "Moonshot Entrypoint",
|
||||
"zaiApiKey": "Z AI API Key",
|
||||
"getZaiApiKey": "Get Z AI API Key",
|
||||
"zaiEntrypoint": "Z AI Entrypoint",
|
||||
"zaiEntrypointDescription": "Please select the appropriate API entrypoint based on your location. If you are in China, choose open.bigmodel.cn. Otherwise, choose api.z.ai.",
|
||||
"geminiApiKey": "Gemini API Key",
|
||||
"getGroqApiKey": "Get Groq API Key",
|
||||
"groqApiKey": "Groq API Key",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/es/settings.json
generated
4
webview-ui/src/i18n/locales/es/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Clave API de Moonshot",
|
||||
"getMoonshotApiKey": "Obtener clave API de Moonshot",
|
||||
"moonshotBaseUrl": "Punto de entrada de Moonshot",
|
||||
"zaiApiKey": "Clave API de Z AI",
|
||||
"getZaiApiKey": "Obtener clave API de Z AI",
|
||||
"zaiEntrypoint": "Punto de entrada de Z AI",
|
||||
"zaiEntrypointDescription": "Por favor, seleccione el punto de entrada de API apropiado según su ubicación. Si está en China, elija open.bigmodel.cn. De lo contrario, elija api.z.ai.",
|
||||
"geminiApiKey": "Clave API de Gemini",
|
||||
"getGroqApiKey": "Obtener clave API de Groq",
|
||||
"groqApiKey": "Clave API de Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/fr/settings.json
generated
4
webview-ui/src/i18n/locales/fr/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Clé API Moonshot",
|
||||
"getMoonshotApiKey": "Obtenir la clé API Moonshot",
|
||||
"moonshotBaseUrl": "Point d'entrée Moonshot",
|
||||
"zaiApiKey": "Clé API Z AI",
|
||||
"getZaiApiKey": "Obtenir la clé API Z AI",
|
||||
"zaiEntrypoint": "Point d'entrée Z AI",
|
||||
"zaiEntrypointDescription": "Veuillez sélectionner le point d'entrée API approprié en fonction de votre emplacement. Si vous êtes en Chine, choisissez open.bigmodel.cn. Sinon, choisissez api.z.ai.",
|
||||
"geminiApiKey": "Clé API Gemini",
|
||||
"getGroqApiKey": "Obtenir la clé API Groq",
|
||||
"groqApiKey": "Clé API Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/hi/settings.json
generated
4
webview-ui/src/i18n/locales/hi/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API कुंजी",
|
||||
"getMoonshotApiKey": "Moonshot API कुंजी प्राप्त करें",
|
||||
"moonshotBaseUrl": "Moonshot प्रवेश बिंदु",
|
||||
"zaiApiKey": "Z AI API कुंजी",
|
||||
"getZaiApiKey": "Z AI API कुंजी प्राप्त करें",
|
||||
"zaiEntrypoint": "Z AI प्रवेश बिंदु",
|
||||
"zaiEntrypointDescription": "कृपया अपने स्थान के आधार पर उपयुक्त API प्रवेश बिंदु का चयन करें। यदि आप चीन में हैं, तो open.bigmodel.cn चुनें। अन्यथा, api.z.ai चुनें।",
|
||||
"geminiApiKey": "Gemini API कुंजी",
|
||||
"getGroqApiKey": "Groq API कुंजी प्राप्त करें",
|
||||
"groqApiKey": "Groq API कुंजी",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/id/settings.json
generated
4
webview-ui/src/i18n/locales/id/settings.json
generated
|
|
@ -272,6 +272,10 @@
|
|||
"moonshotApiKey": "Kunci API Moonshot",
|
||||
"getMoonshotApiKey": "Dapatkan Kunci API Moonshot",
|
||||
"moonshotBaseUrl": "Titik Masuk Moonshot",
|
||||
"zaiApiKey": "Kunci API Z AI",
|
||||
"getZaiApiKey": "Dapatkan Kunci API Z AI",
|
||||
"zaiEntrypoint": "Titik Masuk Z AI",
|
||||
"zaiEntrypointDescription": "Silakan pilih titik masuk API yang sesuai berdasarkan lokasi Anda. Jika Anda berada di China, pilih open.bigmodel.cn. Jika tidak, pilih api.z.ai.",
|
||||
"geminiApiKey": "Gemini API Key",
|
||||
"getGroqApiKey": "Dapatkan Groq API Key",
|
||||
"groqApiKey": "Groq API Key",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/it/settings.json
generated
4
webview-ui/src/i18n/locales/it/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Chiave API Moonshot",
|
||||
"getMoonshotApiKey": "Ottieni chiave API Moonshot",
|
||||
"moonshotBaseUrl": "Punto di ingresso Moonshot",
|
||||
"zaiApiKey": "Chiave API Z AI",
|
||||
"getZaiApiKey": "Ottieni chiave API Z AI",
|
||||
"zaiEntrypoint": "Punto di ingresso Z AI",
|
||||
"zaiEntrypointDescription": "Si prega di selezionare il punto di ingresso API appropriato in base alla propria posizione. Se ti trovi in Cina, scegli open.bigmodel.cn. Altrimenti, scegli api.z.ai.",
|
||||
"geminiApiKey": "Chiave API Gemini",
|
||||
"getGroqApiKey": "Ottieni chiave API Groq",
|
||||
"groqApiKey": "Chiave API Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/ja/settings.json
generated
4
webview-ui/src/i18n/locales/ja/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot APIキー",
|
||||
"getMoonshotApiKey": "Moonshot APIキーを取得",
|
||||
"moonshotBaseUrl": "Moonshot エントリーポイント",
|
||||
"zaiApiKey": "Z AI APIキー",
|
||||
"getZaiApiKey": "Z AI APIキーを取得",
|
||||
"zaiEntrypoint": "Z AI エントリーポイント",
|
||||
"zaiEntrypointDescription": "お住まいの地域に応じて適切な API エントリーポイントを選択してください。中国にお住まいの場合は open.bigmodel.cn を選択してください。それ以外の場合は api.z.ai を選択してください。",
|
||||
"geminiApiKey": "Gemini APIキー",
|
||||
"getGroqApiKey": "Groq APIキーを取得",
|
||||
"groqApiKey": "Groq APIキー",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/ko/settings.json
generated
4
webview-ui/src/i18n/locales/ko/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API 키",
|
||||
"getMoonshotApiKey": "Moonshot API 키 받기",
|
||||
"moonshotBaseUrl": "Moonshot 엔트리포인트",
|
||||
"zaiApiKey": "Z AI API 키",
|
||||
"getZaiApiKey": "Z AI API 키 받기",
|
||||
"zaiEntrypoint": "Z AI 엔트리포인트",
|
||||
"zaiEntrypointDescription": "위치에 따라 적절한 API 엔트리포인트를 선택하세요. 중국에 있다면 open.bigmodel.cn을 선택하세요. 그렇지 않으면 api.z.ai를 선택하세요.",
|
||||
"geminiApiKey": "Gemini API 키",
|
||||
"getGroqApiKey": "Groq API 키 받기",
|
||||
"groqApiKey": "Groq API 키",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/nl/settings.json
generated
4
webview-ui/src/i18n/locales/nl/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API-sleutel",
|
||||
"getMoonshotApiKey": "Moonshot API-sleutel ophalen",
|
||||
"moonshotBaseUrl": "Moonshot-ingangspunt",
|
||||
"zaiApiKey": "Z AI API-sleutel",
|
||||
"getZaiApiKey": "Z AI API-sleutel ophalen",
|
||||
"zaiEntrypoint": "Z AI-ingangspunt",
|
||||
"zaiEntrypointDescription": "Selecteer het juiste API-ingangspunt op basis van uw locatie. Als u zich in China bevindt, kies dan open.bigmodel.cn. Anders kiest u api.z.ai.",
|
||||
"geminiApiKey": "Gemini API-sleutel",
|
||||
"getGroqApiKey": "Groq API-sleutel ophalen",
|
||||
"groqApiKey": "Groq API-sleutel",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/pl/settings.json
generated
4
webview-ui/src/i18n/locales/pl/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Klucz API Moonshot",
|
||||
"getMoonshotApiKey": "Uzyskaj klucz API Moonshot",
|
||||
"moonshotBaseUrl": "Punkt wejścia Moonshot",
|
||||
"zaiApiKey": "Klucz API Z AI",
|
||||
"getZaiApiKey": "Uzyskaj klucz API Z AI",
|
||||
"zaiEntrypoint": "Punkt wejścia Z AI",
|
||||
"zaiEntrypointDescription": "Wybierz odpowiedni punkt wejścia API w zależności od swojej lokalizacji. Jeśli jesteś w Chinach, wybierz open.bigmodel.cn. W przeciwnym razie wybierz api.z.ai.",
|
||||
"geminiApiKey": "Klucz API Gemini",
|
||||
"getGroqApiKey": "Uzyskaj klucz API Groq",
|
||||
"groqApiKey": "Klucz API Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/pt-BR/settings.json
generated
4
webview-ui/src/i18n/locales/pt-BR/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Chave de API Moonshot",
|
||||
"getMoonshotApiKey": "Obter chave de API Moonshot",
|
||||
"moonshotBaseUrl": "Ponto de entrada Moonshot",
|
||||
"zaiApiKey": "Chave de API Z AI",
|
||||
"getZaiApiKey": "Obter chave de API Z AI",
|
||||
"zaiEntrypoint": "Ponto de entrada Z AI",
|
||||
"zaiEntrypointDescription": "Selecione o ponto de entrada da API apropriado com base na sua localização. Se você estiver na China, escolha open.bigmodel.cn. Caso contrário, escolha api.z.ai.",
|
||||
"geminiApiKey": "Chave de API Gemini",
|
||||
"getGroqApiKey": "Obter chave de API Groq",
|
||||
"groqApiKey": "Chave de API Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/ru/settings.json
generated
4
webview-ui/src/i18n/locales/ru/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API-ключ",
|
||||
"getMoonshotApiKey": "Получить Moonshot API-ключ",
|
||||
"moonshotBaseUrl": "Точка входа Moonshot",
|
||||
"zaiApiKey": "Z AI API-ключ",
|
||||
"getZaiApiKey": "Получить Z AI API-ключ",
|
||||
"zaiEntrypoint": "Точка входа Z AI",
|
||||
"zaiEntrypointDescription": "Пожалуйста, выберите подходящую точку входа API в зависимости от вашего местоположения. Если вы находитесь в Китае, выберите open.bigmodel.cn. В противном случае выберите api.z.ai.",
|
||||
"geminiApiKey": "Gemini API-ключ",
|
||||
"getGroqApiKey": "Получить Groq API-ключ",
|
||||
"groqApiKey": "Groq API-ключ",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/tr/settings.json
generated
4
webview-ui/src/i18n/locales/tr/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API Anahtarı",
|
||||
"getMoonshotApiKey": "Moonshot API Anahtarı Al",
|
||||
"moonshotBaseUrl": "Moonshot Giriş Noktası",
|
||||
"zaiApiKey": "Z AI API Anahtarı",
|
||||
"getZaiApiKey": "Z AI API Anahtarı Al",
|
||||
"zaiEntrypoint": "Z AI Giriş Noktası",
|
||||
"zaiEntrypointDescription": "Konumunuza göre uygun API giriş noktasını seçin. Çin'de iseniz open.bigmodel.cn'yi seçin. Aksi takdirde api.z.ai'yi seçin.",
|
||||
"geminiApiKey": "Gemini API Anahtarı",
|
||||
"getGroqApiKey": "Groq API Anahtarı Al",
|
||||
"groqApiKey": "Groq API Anahtarı",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/vi/settings.json
generated
4
webview-ui/src/i18n/locales/vi/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Khóa API Moonshot",
|
||||
"getMoonshotApiKey": "Lấy khóa API Moonshot",
|
||||
"moonshotBaseUrl": "Điểm vào Moonshot",
|
||||
"zaiApiKey": "Khóa API Z AI",
|
||||
"getZaiApiKey": "Lấy khóa API Z AI",
|
||||
"zaiEntrypoint": "Điểm vào Z AI",
|
||||
"zaiEntrypointDescription": "Vui lòng chọn điểm vào API phù hợp dựa trên vị trí của bạn. Nếu bạn ở Trung Quốc, hãy chọn open.bigmodel.cn. Ngược lại, hãy chọn api.z.ai.",
|
||||
"geminiApiKey": "Khóa API Gemini",
|
||||
"getGroqApiKey": "Lấy khóa API Groq",
|
||||
"groqApiKey": "Khóa API Groq",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/zh-CN/settings.json
generated
4
webview-ui/src/i18n/locales/zh-CN/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API 密钥",
|
||||
"getMoonshotApiKey": "获取 Moonshot API 密钥",
|
||||
"moonshotBaseUrl": "Moonshot 服务站点",
|
||||
"zaiApiKey": "Z AI API 密钥",
|
||||
"getZaiApiKey": "获取 Z AI API 密钥",
|
||||
"zaiEntrypoint": "Z AI 服务站点",
|
||||
"zaiEntrypointDescription": "请根据您的位置选择适当的 API 服务站点。如果您在中国,请选择 open.bigmodel.cn。否则,请选择 api.z.ai。",
|
||||
"geminiApiKey": "Gemini API 密钥",
|
||||
"getGroqApiKey": "获取 Groq API 密钥",
|
||||
"groqApiKey": "Groq API 密钥",
|
||||
|
|
|
|||
4
webview-ui/src/i18n/locales/zh-TW/settings.json
generated
4
webview-ui/src/i18n/locales/zh-TW/settings.json
generated
|
|
@ -268,6 +268,10 @@
|
|||
"moonshotApiKey": "Moonshot API 金鑰",
|
||||
"getMoonshotApiKey": "取得 Moonshot API 金鑰",
|
||||
"moonshotBaseUrl": "Moonshot 服務站點",
|
||||
"zaiApiKey": "Z AI API 金鑰",
|
||||
"getZaiApiKey": "取得 Z AI API 金鑰",
|
||||
"zaiEntrypoint": "Z AI 服務站點",
|
||||
"zaiEntrypointDescription": "請根據您的位置選擇適當的 API 服務站點。如果您在中國,請選擇 open.bigmodel.cn。否則,請選擇 api.z.ai。",
|
||||
"geminiApiKey": "Gemini API 金鑰",
|
||||
"getGroqApiKey": "取得 Groq API 金鑰",
|
||||
"groqApiKey": "Groq API 金鑰",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue