From ef9e6f3f1d82002ff60c8108bb350a988ce5d6c2 Mon Sep 17 00:00:00 2001 From: CellenLee <99465814+CellenLee@users.noreply.github.com> Date: Fri, 18 Jul 2025 00:39:34 +0800 Subject: [PATCH 1/2] feat: add moonshot provider --- packages/types/src/global-settings.ts | 1 + packages/types/src/provider-settings.ts | 10 + packages/types/src/providers/index.ts | 1 + packages/types/src/providers/moonshot.ts | 22 ++ src/api/index.ts | 4 + src/api/providers/__tests__/moonshot.spec.ts | 297 ++++++++++++++++++ src/api/providers/index.ts | 1 + src/api/providers/moonshot.ts | 39 +++ .../__tests__/checkExistApiConfig.spec.ts | 1 + .../src/components/settings/ApiOptions.tsx | 7 + .../src/components/settings/constants.ts | 3 + .../settings/providers/Moonshot.tsx | 73 +++++ .../components/settings/providers/index.ts | 1 + .../components/ui/hooks/useSelectedModel.ts | 8 + webview-ui/src/i18n/locales/ca/settings.json | 3 + webview-ui/src/i18n/locales/de/settings.json | 3 + webview-ui/src/i18n/locales/en/settings.json | 3 + webview-ui/src/i18n/locales/es/settings.json | 3 + webview-ui/src/i18n/locales/fr/settings.json | 3 + webview-ui/src/i18n/locales/hi/settings.json | 3 + webview-ui/src/i18n/locales/id/settings.json | 3 + webview-ui/src/i18n/locales/it/settings.json | 3 + webview-ui/src/i18n/locales/ja/settings.json | 3 + webview-ui/src/i18n/locales/ko/settings.json | 3 + webview-ui/src/i18n/locales/nl/settings.json | 3 + webview-ui/src/i18n/locales/pl/settings.json | 3 + .../src/i18n/locales/pt-BR/settings.json | 3 + webview-ui/src/i18n/locales/ru/settings.json | 3 + webview-ui/src/i18n/locales/tr/settings.json | 3 + webview-ui/src/i18n/locales/vi/settings.json | 3 + .../src/i18n/locales/zh-CN/settings.json | 3 + .../src/i18n/locales/zh-TW/settings.json | 3 + 32 files changed, 522 insertions(+) create mode 100644 packages/types/src/providers/moonshot.ts create mode 100644 src/api/providers/__tests__/moonshot.spec.ts create mode 100644 src/api/providers/moonshot.ts create mode 100644 webview-ui/src/components/settings/providers/Moonshot.tsx diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index cf163e26a6..a8763207c6 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -140,6 +140,7 @@ export const SECRET_STATE_KEYS = [ "geminiApiKey", "openAiNativeApiKey", "deepSeekApiKey", + "moonshotApiKey", "mistralApiKey", "unboundApiKey", "requestyApiKey", diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index be74ae6bb4..6ed7c2c7b9 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -22,6 +22,7 @@ export const providerNames = [ "gemini-cli", "openai-native", "mistral", + "moonshot", "deepseek", "unbound", "requesty", @@ -186,6 +187,13 @@ const deepSeekSchema = apiModelIdProviderModelSchema.extend({ deepSeekApiKey: z.string().optional(), }) +const moonshotSchema = apiModelIdProviderModelSchema.extend({ + moonshotBaseUrl: z + .union([z.literal("https://api.moonshot.ai/v1"), z.literal("https://api.moonshot.cn/v1")]) + .optional(), + moonshotApiKey: z.string().optional(), +}) + const unboundSchema = baseProviderSettingsSchema.extend({ unboundApiKey: z.string().optional(), unboundModelId: z.string().optional(), @@ -240,6 +248,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv openAiNativeSchema.merge(z.object({ apiProvider: z.literal("openai-native") })), mistralSchema.merge(z.object({ apiProvider: z.literal("mistral") })), deepSeekSchema.merge(z.object({ apiProvider: z.literal("deepseek") })), + moonshotSchema.merge(z.object({ apiProvider: z.literal("moonshot") })), unboundSchema.merge(z.object({ apiProvider: z.literal("unbound") })), requestySchema.merge(z.object({ apiProvider: z.literal("requesty") })), humanRelaySchema.merge(z.object({ apiProvider: z.literal("human-relay") })), @@ -268,6 +277,7 @@ export const providerSettingsSchema = z.object({ ...openAiNativeSchema.shape, ...mistralSchema.shape, ...deepSeekSchema.shape, + ...moonshotSchema.shape, ...unboundSchema.shape, ...requestySchema.shape, ...humanRelaySchema.shape, diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 267401bd91..e4e506b8a7 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -9,6 +9,7 @@ export * from "./groq.js" export * from "./lite-llm.js" export * from "./lm-studio.js" export * from "./mistral.js" +export * from "./moonshot.js" export * from "./ollama.js" export * from "./openai.js" export * from "./openrouter.js" diff --git a/packages/types/src/providers/moonshot.ts b/packages/types/src/providers/moonshot.ts new file mode 100644 index 0000000000..d7e542077d --- /dev/null +++ b/packages/types/src/providers/moonshot.ts @@ -0,0 +1,22 @@ +import type { ModelInfo } from "../model.js" + +// https://platform.moonshot.ai/ +export type MoonshotModelId = keyof typeof moonshotModels + +export const moonshotDefaultModelId: MoonshotModelId = "kimi-k2-0711-preview" + +export const moonshotModels = { + "kimi-k2-0711-preview": { + maxTokens: 32_000, + contextWindow: 131_072, + supportsImages: false, + supportsPromptCache: true, + inputPrice: 0.6, // $0.60 per million tokens (cache miss) + outputPrice: 2.5, // $2.50 per million tokens + cacheWritesPrice: 0, // $0 per million tokens (cache miss) + cacheReadsPrice: 0.15, // $0.15 per million tokens (cache hit) + description: `Kimi K2 is a state-of-the-art mixture-of-experts (MoE) language model with 32 billion activated parameters and 1 trillion total parameters.`, + }, +} as const satisfies Record + +export const MOONSHOT_DEFAULT_TEMPERATURE = 0.6 diff --git a/src/api/index.ts b/src/api/index.ts index 960209f714..4598a711b2 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -17,6 +17,7 @@ import { GeminiHandler, OpenAiNativeHandler, DeepSeekHandler, + MoonshotHandler, MistralHandler, VsCodeLmHandler, UnboundHandler, @@ -89,6 +90,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { return new OpenAiNativeHandler(options) case "deepseek": return new DeepSeekHandler(options) + case "moonshot": + return new MoonshotHandler(options) case "vscode-lm": return new VsCodeLmHandler(options) case "mistral": @@ -110,6 +113,7 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { case "litellm": return new LiteLLMHandler(options) default: + apiProvider satisfies "gemini-cli" | undefined return new AnthropicHandler(options) } } diff --git a/src/api/providers/__tests__/moonshot.spec.ts b/src/api/providers/__tests__/moonshot.spec.ts new file mode 100644 index 0000000000..586dd5598e --- /dev/null +++ b/src/api/providers/__tests__/moonshot.spec.ts @@ -0,0 +1,297 @@ +// Mocks must come first, before imports +const mockCreate = vi.fn() +vi.mock("openai", () => { + return { + __esModule: true, + default: vi.fn().mockImplementation(() => ({ + chat: { + completions: { + create: mockCreate.mockImplementation(async (options) => { + if (!options.stream) { + return { + id: "test-completion", + choices: [ + { + message: { role: "assistant", content: "Test response", refusal: null }, + finish_reason: "stop", + index: 0, + }, + ], + usage: { + prompt_tokens: 10, + completion_tokens: 5, + total_tokens: 15, + cached_tokens: 2, + }, + } + } + + // Return async iterator for streaming + return { + [Symbol.asyncIterator]: async function* () { + yield { + choices: [ + { + delta: { content: "Test response" }, + index: 0, + }, + ], + usage: null, + } + yield { + choices: [ + { + delta: {}, + index: 0, + }, + ], + usage: { + prompt_tokens: 10, + completion_tokens: 5, + total_tokens: 15, + cached_tokens: 2, + }, + } + }, + } + }), + }, + }, + })), + } +}) + +import OpenAI from "openai" +import type { Anthropic } from "@anthropic-ai/sdk" + +import { moonshotDefaultModelId } from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../../shared/api" + +import { MoonshotHandler } from "../moonshot" + +describe("MoonshotHandler", () => { + let handler: MoonshotHandler + let mockOptions: ApiHandlerOptions + + beforeEach(() => { + mockOptions = { + moonshotApiKey: "test-api-key", + apiModelId: "moonshot-chat", + moonshotBaseUrl: "https://api.moonshot.ai/v1", + } + handler = new MoonshotHandler(mockOptions) + vi.clearAllMocks() + }) + + describe("constructor", () => { + it("should initialize with provided options", () => { + expect(handler).toBeInstanceOf(MoonshotHandler) + expect(handler.getModel().id).toBe(mockOptions.apiModelId) + }) + + it.skip("should throw error if API key is missing", () => { + expect(() => { + new MoonshotHandler({ + ...mockOptions, + moonshotApiKey: undefined, + }) + }).toThrow("Moonshot API key is required") + }) + + it("should use default model ID if not provided", () => { + const handlerWithoutModel = new MoonshotHandler({ + ...mockOptions, + apiModelId: undefined, + }) + expect(handlerWithoutModel.getModel().id).toBe(moonshotDefaultModelId) + }) + + it("should use default base URL if not provided", () => { + const handlerWithoutBaseUrl = new MoonshotHandler({ + ...mockOptions, + moonshotBaseUrl: undefined, + }) + expect(handlerWithoutBaseUrl).toBeInstanceOf(MoonshotHandler) + // The base URL is passed to OpenAI client internally + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: "https://api.moonshot.ai/v1", + }), + ) + }) + + it("should use chinese base URL if provided", () => { + const customBaseUrl = "https://api.moonshot.cn/v1" + const handlerWithCustomUrl = new MoonshotHandler({ + ...mockOptions, + moonshotBaseUrl: customBaseUrl, + }) + expect(handlerWithCustomUrl).toBeInstanceOf(MoonshotHandler) + // The custom base URL is passed to OpenAI client + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ + baseURL: customBaseUrl, + }), + ) + }) + + it("should set includeMaxTokens to true", () => { + // Create a new handler and verify OpenAI client was called with includeMaxTokens + const _handler = new MoonshotHandler(mockOptions) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: mockOptions.moonshotApiKey })) + }) + }) + + describe("getModel", () => { + it("should return model info for valid model ID", () => { + const model = handler.getModel() + expect(model.id).toBe(mockOptions.apiModelId) + expect(model.info).toBeDefined() + expect(model.info.maxTokens).toBe(32_000) + expect(model.info.contextWindow).toBe(131_072) + expect(model.info.supportsImages).toBe(false) + expect(model.info.supportsPromptCache).toBe(true) // Should be true now + }) + + it("should return provided model ID with default model info if model does not exist", () => { + const handlerWithInvalidModel = new MoonshotHandler({ + ...mockOptions, + apiModelId: "invalid-model", + }) + const model = handlerWithInvalidModel.getModel() + expect(model.id).toBe("invalid-model") // Returns provided ID + expect(model.info).toBeDefined() + // With the current implementation, it's the same object reference when using default model info + expect(model.info).toBe(handler.getModel().info) + // Should have the same base properties + expect(model.info.contextWindow).toBe(handler.getModel().info.contextWindow) + // And should have supportsPromptCache set to true + expect(model.info.supportsPromptCache).toBe(true) + }) + + it("should return default model if no model ID is provided", () => { + const handlerWithoutModel = new MoonshotHandler({ + ...mockOptions, + apiModelId: undefined, + }) + const model = handlerWithoutModel.getModel() + expect(model.id).toBe(moonshotDefaultModelId) + expect(model.info).toBeDefined() + expect(model.info.supportsPromptCache).toBe(true) + }) + + it("should include model parameters from getModelParams", () => { + const model = handler.getModel() + expect(model).toHaveProperty("temperature") + expect(model).toHaveProperty("maxTokens") + }) + }) + + describe("createMessage", () => { + const systemPrompt = "You are a helpful assistant." + const messages: Anthropic.Messages.MessageParam[] = [ + { + role: "user", + content: [ + { + type: "text" as const, + text: "Hello!", + }, + ], + }, + ] + + it("should handle streaming responses", async () => { + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + expect(chunks.length).toBeGreaterThan(0) + const textChunks = chunks.filter((chunk) => chunk.type === "text") + expect(textChunks).toHaveLength(1) + expect(textChunks[0].text).toBe("Test response") + }) + + it("should include usage information", async () => { + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + const usageChunks = chunks.filter((chunk) => chunk.type === "usage") + expect(usageChunks.length).toBeGreaterThan(0) + expect(usageChunks[0].inputTokens).toBe(10) + expect(usageChunks[0].outputTokens).toBe(5) + }) + + it("should include cache metrics in usage information", async () => { + const stream = handler.createMessage(systemPrompt, messages) + const chunks: any[] = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + const usageChunks = chunks.filter((chunk) => chunk.type === "usage") + expect(usageChunks.length).toBeGreaterThan(0) + expect(usageChunks[0].cacheWriteTokens).toBe(0) + expect(usageChunks[0].cacheReadTokens).toBe(2) + }) + }) + + describe("processUsageMetrics", () => { + it("should correctly process usage metrics including cache information", () => { + // We need to access the protected method, so we'll create a test subclass + class TestMoonshotHandler extends MoonshotHandler { + public testProcessUsageMetrics(usage: any) { + return this.processUsageMetrics(usage) + } + } + + const testHandler = new TestMoonshotHandler(mockOptions) + + const usage = { + prompt_tokens: 100, + completion_tokens: 50, + total_tokens: 150, + cached_tokens: 20, + } + + const result = testHandler.testProcessUsageMetrics(usage) + + expect(result.type).toBe("usage") + expect(result.inputTokens).toBe(100) + expect(result.outputTokens).toBe(50) + expect(result.cacheWriteTokens).toBe(0) + expect(result.cacheReadTokens).toBe(20) + }) + + it("should handle missing cache metrics gracefully", () => { + class TestMoonshotHandler extends MoonshotHandler { + public testProcessUsageMetrics(usage: any) { + return this.processUsageMetrics(usage) + } + } + + const testHandler = new TestMoonshotHandler(mockOptions) + + const usage = { + prompt_tokens: 100, + completion_tokens: 50, + total_tokens: 150, + // No cached_tokens + } + + const result = testHandler.testProcessUsageMetrics(usage) + + expect(result.type).toBe("usage") + expect(result.inputTokens).toBe(100) + expect(result.outputTokens).toBe(50) + expect(result.cacheWriteTokens).toBe(0) + expect(result.cacheReadTokens).toBeUndefined() + }) + }) +}) diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index 93df5c58ff..89d4c203ad 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -4,6 +4,7 @@ export { AwsBedrockHandler } from "./bedrock" export { ChutesHandler } from "./chutes" export { ClaudeCodeHandler } from "./claude-code" export { DeepSeekHandler } from "./deepseek" +export { MoonshotHandler } from "./moonshot" export { FakeAIHandler } from "./fake-ai" export { GeminiHandler } from "./gemini" export { GlamaHandler } from "./glama" diff --git a/src/api/providers/moonshot.ts b/src/api/providers/moonshot.ts new file mode 100644 index 0000000000..2dbd347fd4 --- /dev/null +++ b/src/api/providers/moonshot.ts @@ -0,0 +1,39 @@ +import { moonshotModels, moonshotDefaultModelId } from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../shared/api" + +import type { ApiStreamUsageChunk } from "../transform/stream" +import { getModelParams } from "../transform/model-params" + +import { OpenAiHandler } from "./openai" + +export class MoonshotHandler extends OpenAiHandler { + constructor(options: ApiHandlerOptions) { + super({ + ...options, + openAiApiKey: options.moonshotApiKey ?? "not-provided", + openAiModelId: options.apiModelId ?? moonshotDefaultModelId, + openAiBaseUrl: options.moonshotBaseUrl ?? "https://api.moonshot.ai/v1", + openAiStreamingEnabled: true, + includeMaxTokens: true, + }) + } + + override getModel() { + const id = this.options.apiModelId ?? moonshotDefaultModelId + const info = moonshotModels[id as keyof typeof moonshotModels] || moonshotModels[moonshotDefaultModelId] + const params = getModelParams({ format: "openai", modelId: id, model: info, settings: this.options }) + return { id, info, ...params } + } + + // Override to handle DeepSeek's usage metrics, including caching. + protected override processUsageMetrics(usage: any): ApiStreamUsageChunk { + return { + type: "usage", + inputTokens: usage?.prompt_tokens || 0, + outputTokens: usage?.completion_tokens || 0, + cacheWriteTokens: 0, + cacheReadTokens: usage?.cached_tokens, + } + } +} diff --git a/src/shared/__tests__/checkExistApiConfig.spec.ts b/src/shared/__tests__/checkExistApiConfig.spec.ts index 7bc9e1d576..7696f00cc0 100644 --- a/src/shared/__tests__/checkExistApiConfig.spec.ts +++ b/src/shared/__tests__/checkExistApiConfig.spec.ts @@ -53,6 +53,7 @@ describe("checkExistKey", () => { geminiApiKey: undefined, openAiNativeApiKey: undefined, deepSeekApiKey: undefined, + moonshotApiKey: undefined, mistralApiKey: undefined, vsCodeLmModelSelector: undefined, requestyApiKey: undefined, diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 06994b16b9..072f55e7bc 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -18,6 +18,7 @@ import { claudeCodeDefaultModelId, geminiDefaultModelId, deepSeekDefaultModelId, + moonshotDefaultModelId, mistralDefaultModelId, xaiDefaultModelId, groqDefaultModelId, @@ -61,6 +62,7 @@ import { LMStudio, LiteLLM, Mistral, + Moonshot, Ollama, OpenAI, OpenAICompatible, @@ -286,6 +288,7 @@ const ApiOptions = ({ "openai-native": { field: "apiModelId", default: openAiNativeDefaultModelId }, gemini: { field: "apiModelId", default: geminiDefaultModelId }, deepseek: { field: "apiModelId", default: deepSeekDefaultModelId }, + moonshot: { field: "apiModelId", default: moonshotDefaultModelId }, mistral: { field: "apiModelId", default: mistralDefaultModelId }, xai: { field: "apiModelId", default: xaiDefaultModelId }, groq: { field: "apiModelId", default: groqDefaultModelId }, @@ -463,6 +466,10 @@ const ApiOptions = ({ )} + {selectedProvider === "moonshot" && ( + + )} + {selectedProvider === "vscode-lm" && ( )} diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index bbee8f990d..1140e4c0bc 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -5,6 +5,7 @@ import { bedrockModels, claudeCodeModels, deepSeekModels, + moonshotModels, geminiModels, mistralModels, openAiNativeModels, @@ -19,6 +20,7 @@ export const MODELS_BY_PROVIDER: Partial void +} + +export const Moonshot = ({ apiConfiguration, setApiConfigurationField }: MoonshotProps) => { + const { t } = useAppTranslation() + + const handleInputChange = useCallback( + ( + field: K, + transform: (event: E) => ProviderSettings[K] = inputEventTransform, + ) => + (event: E | Event) => { + setApiConfigurationField(field, transform(event as E)) + }, + [setApiConfigurationField], + ) + + return ( + <> +
+ + + + api.moonshot.ai + + + api.moonshot.cn + + +
+
+ + + +
+ {t("settings:providers.apiKeyStorageNotice")} +
+ {!apiConfiguration?.moonshotApiKey && ( + + {t("settings:providers.getMoonshotApiKey")} + + )} +
+ + ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index b195607430..54974f7200 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -8,6 +8,7 @@ export { Glama } from "./Glama" export { Groq } from "./Groq" export { LMStudio } from "./LMStudio" export { Mistral } from "./Mistral" +export { Moonshot } from "./Moonshot" export { Ollama } from "./Ollama" export { OpenAI } from "./OpenAI" export { OpenAICompatible } from "./OpenAICompatible" diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index 40c1ff2431..928ebb42f4 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -8,6 +8,8 @@ import { bedrockModels, deepSeekDefaultModelId, deepSeekModels, + moonshotDefaultModelId, + moonshotModels, geminiDefaultModelId, geminiModels, mistralDefaultModelId, @@ -162,6 +164,11 @@ function getSelectedModel({ const info = deepSeekModels[id as keyof typeof deepSeekModels] return { id, info } } + case "moonshot": { + const id = apiConfiguration.apiModelId ?? moonshotDefaultModelId + const info = moonshotModels[id as keyof typeof moonshotModels] + return { id, info } + } case "openai-native": { const id = apiConfiguration.apiModelId ?? openAiNativeDefaultModelId const info = openAiNativeModels[id as keyof typeof openAiNativeModels] @@ -211,6 +218,7 @@ function getSelectedModel({ // case "human-relay": // case "fake-ai": default: { + provider satisfies "anthropic" | "gemini-cli" | "human-relay" | "fake-ai" const id = apiConfiguration.apiModelId ?? anthropicDefaultModelId const info = anthropicModels[id as keyof typeof anthropicModels] return { id, info } diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 15018e64ab..342cf281b7 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Obtenir clau API de Chutes", "deepSeekApiKey": "Clau API de DeepSeek", "getDeepSeekApiKey": "Obtenir clau API de DeepSeek", + "moonshotApiKey": "Clau API de Moonshot", + "getMoonshotApiKey": "Obtenir clau API de Moonshot", + "moonshotBaseUrl": "Punt d'entrada de Moonshot", "geminiApiKey": "Clau API de Gemini", "getGroqApiKey": "Obtenir clau API de Groq", "groqApiKey": "Clau API de Groq", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index bb5ed1146b..f471f0e289 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Chutes API-Schlüssel erhalten", "deepSeekApiKey": "DeepSeek API-Schlüssel", "getDeepSeekApiKey": "DeepSeek API-Schlüssel erhalten", + "moonshotApiKey": "Moonshot API-Schlüssel", + "getMoonshotApiKey": "Moonshot API-Schlüssel erhalten", + "moonshotBaseUrl": "Moonshot-Einstiegspunkt", "geminiApiKey": "Gemini API-Schlüssel", "getGroqApiKey": "Groq API-Schlüssel erhalten", "groqApiKey": "Groq API-Schlüssel", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 728e856502..519e7bf6e7 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Get Chutes API Key", "deepSeekApiKey": "DeepSeek API Key", "getDeepSeekApiKey": "Get DeepSeek API Key", + "moonshotApiKey": "Moonshot API Key", + "getMoonshotApiKey": "Get Moonshot API Key", + "moonshotBaseUrl": "Moonshot Entrypoint", "geminiApiKey": "Gemini API Key", "getGroqApiKey": "Get Groq API Key", "groqApiKey": "Groq API Key", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 5836933b46..e113b36bcd 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Obtener clave API de Chutes", "deepSeekApiKey": "Clave API de DeepSeek", "getDeepSeekApiKey": "Obtener clave API de DeepSeek", + "moonshotApiKey": "Clave API de Moonshot", + "getMoonshotApiKey": "Obtener clave API de Moonshot", + "moonshotBaseUrl": "Punto de entrada de Moonshot", "geminiApiKey": "Clave API de Gemini", "getGroqApiKey": "Obtener clave API de Groq", "groqApiKey": "Clave API de Groq", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 833a789e5a..51bcdf220d 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Obtenir la clé API Chutes", "deepSeekApiKey": "Clé API DeepSeek", "getDeepSeekApiKey": "Obtenir la clé API DeepSeek", + "moonshotApiKey": "Clé API Moonshot", + "getMoonshotApiKey": "Obtenir la clé API Moonshot", + "moonshotBaseUrl": "Point d'entrée Moonshot", "geminiApiKey": "Clé API Gemini", "getGroqApiKey": "Obtenir la clé API Groq", "groqApiKey": "Clé API Groq", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 0749943508..a838219ac7 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Chutes API कुंजी प्राप्त करें", "deepSeekApiKey": "DeepSeek API कुंजी", "getDeepSeekApiKey": "DeepSeek API कुंजी प्राप्त करें", + "moonshotApiKey": "Moonshot API कुंजी", + "getMoonshotApiKey": "Moonshot API कुंजी प्राप्त करें", + "moonshotBaseUrl": "Moonshot प्रवेश बिंदु", "geminiApiKey": "Gemini API कुंजी", "getGroqApiKey": "Groq API कुंजी प्राप्त करें", "groqApiKey": "Groq API कुंजी", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 4a0c51d39d..3c6fa9f856 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -253,6 +253,9 @@ "getChutesApiKey": "Dapatkan Chutes API Key", "deepSeekApiKey": "DeepSeek API Key", "getDeepSeekApiKey": "Dapatkan DeepSeek API Key", + "moonshotApiKey": "Kunci API Moonshot", + "getMoonshotApiKey": "Dapatkan Kunci API Moonshot", + "moonshotBaseUrl": "Titik Masuk Moonshot", "geminiApiKey": "Gemini API Key", "getGroqApiKey": "Dapatkan Groq API Key", "groqApiKey": "Groq API Key", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 9d9be82868..c868932911 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Ottieni chiave API Chutes", "deepSeekApiKey": "Chiave API DeepSeek", "getDeepSeekApiKey": "Ottieni chiave API DeepSeek", + "moonshotApiKey": "Chiave API Moonshot", + "getMoonshotApiKey": "Ottieni chiave API Moonshot", + "moonshotBaseUrl": "Punto di ingresso Moonshot", "geminiApiKey": "Chiave API Gemini", "getGroqApiKey": "Ottieni chiave API Groq", "groqApiKey": "Chiave API Groq", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 9fc03cbfb1..2c1de324b7 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Chutes APIキーを取得", "deepSeekApiKey": "DeepSeek APIキー", "getDeepSeekApiKey": "DeepSeek APIキーを取得", + "moonshotApiKey": "Moonshot APIキー", + "getMoonshotApiKey": "Moonshot APIキーを取得", + "moonshotBaseUrl": "Moonshot エントリーポイント", "geminiApiKey": "Gemini APIキー", "getGroqApiKey": "Groq APIキーを取得", "groqApiKey": "Groq APIキー", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 219daa05a4..cbd6b04a69 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Chutes API 키 받기", "deepSeekApiKey": "DeepSeek API 키", "getDeepSeekApiKey": "DeepSeek API 키 받기", + "moonshotApiKey": "Moonshot API 키", + "getMoonshotApiKey": "Moonshot API 키 받기", + "moonshotBaseUrl": "Moonshot 엔트리포인트", "geminiApiKey": "Gemini API 키", "getGroqApiKey": "Groq API 키 받기", "groqApiKey": "Groq API 키", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index e184f4d85e..2761b7be2a 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Chutes API-sleutel ophalen", "deepSeekApiKey": "DeepSeek API-sleutel", "getDeepSeekApiKey": "DeepSeek API-sleutel ophalen", + "moonshotApiKey": "Moonshot API-sleutel", + "getMoonshotApiKey": "Moonshot API-sleutel ophalen", + "moonshotBaseUrl": "Moonshot-ingangspunt", "geminiApiKey": "Gemini API-sleutel", "getGroqApiKey": "Groq API-sleutel ophalen", "groqApiKey": "Groq API-sleutel", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 23d3ce707d..7c0428ad21 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Uzyskaj klucz API Chutes", "deepSeekApiKey": "Klucz API DeepSeek", "getDeepSeekApiKey": "Uzyskaj klucz API DeepSeek", + "moonshotApiKey": "Klucz API Moonshot", + "getMoonshotApiKey": "Uzyskaj klucz API Moonshot", + "moonshotBaseUrl": "Punkt wejścia Moonshot", "geminiApiKey": "Klucz API Gemini", "getGroqApiKey": "Uzyskaj klucz API Groq", "groqApiKey": "Klucz API Groq", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index 102036622c..7282eca883 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Obter chave de API Chutes", "deepSeekApiKey": "Chave de API DeepSeek", "getDeepSeekApiKey": "Obter chave de API DeepSeek", + "moonshotApiKey": "Chave de API Moonshot", + "getMoonshotApiKey": "Obter chave de API Moonshot", + "moonshotBaseUrl": "Ponto de entrada Moonshot", "geminiApiKey": "Chave de API Gemini", "getGroqApiKey": "Obter chave de API Groq", "groqApiKey": "Chave de API Groq", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 5952dd8c89..d165bcf136 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Получить Chutes API-ключ", "deepSeekApiKey": "DeepSeek API-ключ", "getDeepSeekApiKey": "Получить DeepSeek API-ключ", + "moonshotApiKey": "Moonshot API-ключ", + "getMoonshotApiKey": "Получить Moonshot API-ключ", + "moonshotBaseUrl": "Точка входа Moonshot", "geminiApiKey": "Gemini API-ключ", "getGroqApiKey": "Получить Groq API-ключ", "groqApiKey": "Groq API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 625ca4d5ea..883d2019ea 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Chutes API Anahtarı Al", "deepSeekApiKey": "DeepSeek API Anahtarı", "getDeepSeekApiKey": "DeepSeek API Anahtarı Al", + "moonshotApiKey": "Moonshot API Anahtarı", + "getMoonshotApiKey": "Moonshot API Anahtarı Al", + "moonshotBaseUrl": "Moonshot Giriş Noktası", "geminiApiKey": "Gemini API Anahtarı", "getGroqApiKey": "Groq API Anahtarı Al", "groqApiKey": "Groq API Anahtarı", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 52a9db5b93..163d3277be 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "Lấy khóa API Chutes", "deepSeekApiKey": "Khóa API DeepSeek", "getDeepSeekApiKey": "Lấy khóa API DeepSeek", + "moonshotApiKey": "Khóa API Moonshot", + "getMoonshotApiKey": "Lấy khóa API Moonshot", + "moonshotBaseUrl": "Điểm vào Moonshot", "geminiApiKey": "Khóa API Gemini", "getGroqApiKey": "Lấy khóa API Groq", "groqApiKey": "Khóa API Groq", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 151ee9e744..67f066edcd 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "获取 Chutes API 密钥", "deepSeekApiKey": "DeepSeek API 密钥", "getDeepSeekApiKey": "获取 DeepSeek API 密钥", + "moonshotApiKey": "Moonshot API 密钥", + "getMoonshotApiKey": "获取 Moonshot API 密钥", + "moonshotBaseUrl": "Moonshot 服务站点", "geminiApiKey": "Gemini API 密钥", "getGroqApiKey": "获取 Groq API 密钥", "groqApiKey": "Groq API 密钥", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index ab4caeea5b..98e0542d57 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -249,6 +249,9 @@ "getChutesApiKey": "取得 Chutes API 金鑰", "deepSeekApiKey": "DeepSeek API 金鑰", "getDeepSeekApiKey": "取得 DeepSeek API 金鑰", + "moonshotApiKey": "Moonshot API 金鑰", + "getMoonshotApiKey": "取得 Moonshot API 金鑰", + "moonshotBaseUrl": "Moonshot 服務站點", "geminiApiKey": "Gemini API 金鑰", "getGroqApiKey": "取得 Groq API 金鑰", "groqApiKey": "Groq API 金鑰", From 94fcc435d4d975f0490b0621306574c85285bef9 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 22 Jul 2025 00:22:27 -0400 Subject: [PATCH 2/2] Update src/api/providers/moonshot.ts Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com> --- src/api/providers/moonshot.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/providers/moonshot.ts b/src/api/providers/moonshot.ts index 2dbd347fd4..f04b369d1c 100644 --- a/src/api/providers/moonshot.ts +++ b/src/api/providers/moonshot.ts @@ -26,7 +26,7 @@ export class MoonshotHandler extends OpenAiHandler { return { id, info, ...params } } - // Override to handle DeepSeek's usage metrics, including caching. + // Override to handle Moonshot's usage metrics, including caching. protected override processUsageMetrics(usage: any): ApiStreamUsageChunk { return { type: "usage",