diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 03bbe9640a..965566a319 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -25,6 +25,7 @@ body: - AWS Bedrock - Chutes AI - DeepSeek + - Fireworks AI - Glama - Google Gemini - Google Vertex AI diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 6de4d7413f..ad5119b604 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -191,6 +191,7 @@ export const SECRET_STATE_KEYS = [ "codebaseIndexMistralApiKey", "huggingFaceApiKey", "sambaNovaApiKey", + "fireworksApiKey", ] as const satisfies readonly (keyof ProviderSettings)[] export type SecretState = Pick diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 876f5114b6..dc51188df9 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -37,6 +37,7 @@ export const providerNames = [ "cerebras", "sambanova", "zai", + "fireworks", ] as const export const providerNamesSchema = z.enum(providerNames) @@ -263,6 +264,10 @@ const zaiSchema = apiModelIdProviderModelSchema.extend({ zaiApiLine: z.union([z.literal("china"), z.literal("international")]).optional(), }) +const fireworksSchema = apiModelIdProviderModelSchema.extend({ + fireworksApiKey: z.string().optional(), +}) + const defaultSchema = z.object({ apiProvider: z.undefined(), }) @@ -297,6 +302,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv cerebrasSchema.merge(z.object({ apiProvider: z.literal("cerebras") })), sambaNovaSchema.merge(z.object({ apiProvider: z.literal("sambanova") })), zaiSchema.merge(z.object({ apiProvider: z.literal("zai") })), + fireworksSchema.merge(z.object({ apiProvider: z.literal("fireworks") })), defaultSchema, ]) @@ -331,6 +337,7 @@ export const providerSettingsSchema = z.object({ ...cerebrasSchema.shape, ...sambaNovaSchema.shape, ...zaiSchema.shape, + ...fireworksSchema.shape, ...codebaseIndexProviderSchema.shape, }) diff --git a/packages/types/src/providers/fireworks.ts b/packages/types/src/providers/fireworks.ts new file mode 100644 index 0000000000..80858f624e --- /dev/null +++ b/packages/types/src/providers/fireworks.ts @@ -0,0 +1,61 @@ +import type { ModelInfo } from "../model.js" + +export type FireworksModelId = + | "accounts/fireworks/models/kimi-k2-instruct" + | "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507" + | "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct" + | "accounts/fireworks/models/deepseek-r1-0528" + | "accounts/fireworks/models/deepseek-v3" + +export const fireworksDefaultModelId: FireworksModelId = "accounts/fireworks/models/kimi-k2-instruct" + +export const fireworksModels = { + "accounts/fireworks/models/kimi-k2-instruct": { + maxTokens: 16384, + contextWindow: 128000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.6, + outputPrice: 2.5, + 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. Trained with the Muon optimizer, Kimi K2 achieves exceptional performance across frontier knowledge, reasoning, and coding tasks while being meticulously optimized for agentic capabilities.", + }, + "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507": { + maxTokens: 32768, + contextWindow: 256000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.22, + outputPrice: 0.88, + description: "Latest Qwen3 thinking model, competitive against the best closed source models in Jul 2025.", + }, + "accounts/fireworks/models/qwen3-coder-480b-a35b-instruct": { + maxTokens: 32768, + contextWindow: 256000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.45, + outputPrice: 1.8, + description: "Qwen3's most agentic code model to date.", + }, + "accounts/fireworks/models/deepseek-r1-0528": { + maxTokens: 20480, + contextWindow: 160000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 3, + outputPrice: 8, + description: + "05/28 updated checkpoint of Deepseek R1. Its overall performance is now approaching that of leading models, such as O3 and Gemini 2.5 Pro. Compared to the previous version, the upgraded model shows significant improvements in handling complex reasoning tasks, and this version also offers a reduced hallucination rate, enhanced support for function calling, and better experience for vibe coding. Note that fine-tuning for this model is only available through contacting fireworks at https://fireworks.ai/company/contact-us.", + }, + "accounts/fireworks/models/deepseek-v3": { + maxTokens: 16384, + contextWindow: 128000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.9, + outputPrice: 0.9, + description: + "A strong Mixture-of-Experts (MoE) language model with 671B total parameters with 37B activated for each token from Deepseek. Note that fine-tuning for this model is only available through contacting fireworks at https://fireworks.ai/company/contact-us.", + }, +} as const satisfies Record diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index b0e316bf55..0ab27ea3dc 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -23,3 +23,4 @@ export * from "./vscode-llm.js" export * from "./xai.js" export * from "./doubao.js" export * from "./zai.js" +export * from "./fireworks.js" diff --git a/src/api/index.ts b/src/api/index.ts index 3ad3705eba..57b06f7bbd 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -34,6 +34,7 @@ import { SambaNovaHandler, DoubaoHandler, ZAiHandler, + FireworksHandler, } from "./providers" export interface SingleCompletionHandler { @@ -127,6 +128,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { return new SambaNovaHandler(options) case "zai": return new ZAiHandler(options) + case "fireworks": + return new FireworksHandler(options) default: apiProvider satisfies "gemini-cli" | undefined return new AnthropicHandler(options) diff --git a/src/api/providers/__tests__/fireworks.spec.ts b/src/api/providers/__tests__/fireworks.spec.ts new file mode 100644 index 0000000000..21a88e80ba --- /dev/null +++ b/src/api/providers/__tests__/fireworks.spec.ts @@ -0,0 +1,355 @@ +// npx vitest run api/providers/__tests__/fireworks.spec.ts + +import { Anthropic } from "@anthropic-ai/sdk" +import OpenAI from "openai" + +import { type FireworksModelId, fireworksDefaultModelId, fireworksModels } from "@roo-code/types" + +import { FireworksHandler } from "../fireworks" + +// Create mock functions +const mockCreate = vi.fn() + +// Mock OpenAI module +vi.mock("openai", () => ({ + default: vi.fn(() => ({ + chat: { + completions: { + create: mockCreate, + }, + }, + })), +})) + +describe("FireworksHandler", () => { + let handler: FireworksHandler + + beforeEach(() => { + vi.clearAllMocks() + // Set up default mock implementation + mockCreate.mockImplementation(async () => ({ + [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, + }, + } + }, + })) + handler = new FireworksHandler({ fireworksApiKey: "test-key" }) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it("should use the correct Fireworks base URL", () => { + new FireworksHandler({ fireworksApiKey: "test-fireworks-api-key" }) + expect(OpenAI).toHaveBeenCalledWith( + expect.objectContaining({ baseURL: "https://api.fireworks.ai/inference/v1" }), + ) + }) + + it("should use the provided API key", () => { + const fireworksApiKey = "test-fireworks-api-key" + new FireworksHandler({ fireworksApiKey }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: fireworksApiKey })) + }) + + it("should throw error when API key is not provided", () => { + expect(() => new FireworksHandler({})).toThrow("API key is required") + }) + + it("should return default model when no model is specified", () => { + const model = handler.getModel() + expect(model.id).toBe(fireworksDefaultModelId) + expect(model.info).toEqual(expect.objectContaining(fireworksModels[fireworksDefaultModelId])) + }) + + it("should return specified model when valid model is provided", () => { + const testModelId: FireworksModelId = "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507" + const handlerWithModel = new FireworksHandler({ + apiModelId: testModelId, + fireworksApiKey: "test-fireworks-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual(expect.objectContaining(fireworksModels[testModelId])) + }) + + it("should return Kimi K2 Instruct model with correct configuration", () => { + const testModelId: FireworksModelId = "accounts/fireworks/models/kimi-k2-instruct" + const handlerWithModel = new FireworksHandler({ + apiModelId: testModelId, + fireworksApiKey: "test-fireworks-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 16384, + contextWindow: 128000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.6, + outputPrice: 2.5, + description: expect.stringContaining("Kimi K2 is a state-of-the-art mixture-of-experts"), + }), + ) + }) + + it("should return Qwen3 235B model with correct configuration", () => { + const testModelId: FireworksModelId = "accounts/fireworks/models/qwen3-235b-a22b-instruct-2507" + const handlerWithModel = new FireworksHandler({ + apiModelId: testModelId, + fireworksApiKey: "test-fireworks-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 32768, + contextWindow: 256000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.22, + outputPrice: 0.88, + description: + "Latest Qwen3 thinking model, competitive against the best closed source models in Jul 2025.", + }), + ) + }) + + it("should return DeepSeek R1 model with correct configuration", () => { + const testModelId: FireworksModelId = "accounts/fireworks/models/deepseek-r1-0528" + const handlerWithModel = new FireworksHandler({ + apiModelId: testModelId, + fireworksApiKey: "test-fireworks-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 20480, + contextWindow: 160000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 3, + outputPrice: 8, + description: expect.stringContaining("05/28 updated checkpoint of Deepseek R1"), + }), + ) + }) + + it("should return DeepSeek V3 model with correct configuration", () => { + const testModelId: FireworksModelId = "accounts/fireworks/models/deepseek-v3" + const handlerWithModel = new FireworksHandler({ + apiModelId: testModelId, + fireworksApiKey: "test-fireworks-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 16384, + contextWindow: 128000, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.9, + outputPrice: 0.9, + description: expect.stringContaining("strong Mixture-of-Experts (MoE) language model"), + }), + ) + }) + + it("completePrompt method should return text from Fireworks API", async () => { + const expectedResponse = "This is a test response from Fireworks" + 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 = "Fireworks API error" + mockCreate.mockRejectedValueOnce(new Error(errorMessage)) + await expect(handler.completePrompt("test prompt")).rejects.toThrow( + `Fireworks completion error: ${errorMessage}`, + ) + }) + + it("createMessage should yield text content from stream", async () => { + const testContent = "This is test content from Fireworks stream" + + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + next: vi + .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: vi + .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 Fireworks client", async () => { + const modelId: FireworksModelId = "accounts/fireworks/models/kimi-k2-instruct" + const modelInfo = fireworksModels[modelId] + const handlerWithModel = new FireworksHandler({ + apiModelId: modelId, + fireworksApiKey: "test-fireworks-api-key", + }) + + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + async next() { + return { done: true } + }, + }), + } + }) + + const systemPrompt = "Test system prompt for Fireworks" + const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message for Fireworks" }] + + const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages) + await messageGenerator.next() + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: modelId, + max_tokens: modelInfo.maxTokens, + temperature: 0.5, + messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]), + stream: true, + stream_options: { include_usage: true }, + }), + ) + }) + + it("should use default temperature of 0.5", () => { + const testModelId: FireworksModelId = "accounts/fireworks/models/kimi-k2-instruct" + const handlerWithModel = new FireworksHandler({ + apiModelId: testModelId, + fireworksApiKey: "test-fireworks-api-key", + }) + const model = handlerWithModel.getModel() + // The temperature is set in the constructor as defaultTemperature: 0.5 + // This test verifies the handler is configured with the correct default temperature + expect(handlerWithModel).toBeDefined() + }) + + it("should handle empty response in completePrompt", async () => { + mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: null } }] }) + const result = await handler.completePrompt("test prompt") + expect(result).toBe("") + }) + + it("should handle missing choices in completePrompt", async () => { + mockCreate.mockResolvedValueOnce({ choices: [] }) + const result = await handler.completePrompt("test prompt") + expect(result).toBe("") + }) + + it("createMessage should handle stream with multiple chunks", async () => { + mockCreate.mockImplementationOnce(async () => ({ + [Symbol.asyncIterator]: async function* () { + yield { + choices: [ + { + delta: { content: "Hello" }, + index: 0, + }, + ], + usage: null, + } + yield { + choices: [ + { + delta: { content: " world" }, + index: 0, + }, + ], + usage: null, + } + yield { + choices: [ + { + delta: {}, + index: 0, + }, + ], + usage: { + prompt_tokens: 5, + completion_tokens: 10, + total_tokens: 15, + }, + } + }, + })) + + const systemPrompt = "You are a helpful assistant." + const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Hi" }] + + const stream = handler.createMessage(systemPrompt, messages) + const chunks = [] + for await (const chunk of stream) { + chunks.push(chunk) + } + + expect(chunks).toEqual([ + { type: "text", text: "Hello" }, + { type: "text", text: " world" }, + { type: "usage", inputTokens: 5, outputTokens: 10 }, + ]) + }) +}) diff --git a/src/api/providers/fireworks.ts b/src/api/providers/fireworks.ts new file mode 100644 index 0000000000..db29e7bf3f --- /dev/null +++ b/src/api/providers/fireworks.ts @@ -0,0 +1,19 @@ +import { type FireworksModelId, fireworksDefaultModelId, fireworksModels } from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../shared/api" + +import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider" + +export class FireworksHandler extends BaseOpenAiCompatibleProvider { + constructor(options: ApiHandlerOptions) { + super({ + ...options, + providerName: "Fireworks", + baseURL: "https://api.fireworks.ai/inference/v1", + apiKey: options.fireworksApiKey, + defaultProviderModelId: fireworksDefaultModelId, + providerModels: fireworksModels, + defaultTemperature: 0.5, + }) + } +} diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index dfcf87b6c9..890999aa25 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -27,3 +27,4 @@ export { VertexHandler } from "./vertex" export { VsCodeLmHandler } from "./vscode-lm" export { XAIHandler } from "./xai" export { ZAiHandler } from "./zai" +export { FireworksHandler } from "./fireworks" diff --git a/src/shared/ProfileValidator.ts b/src/shared/ProfileValidator.ts index 9cfba84aae..3dc8025ff8 100644 --- a/src/shared/ProfileValidator.ts +++ b/src/shared/ProfileValidator.ts @@ -68,6 +68,7 @@ export class ProfileValidator { case "groq": case "sambanova": case "chutes": + case "fireworks": return profile.apiModelId case "litellm": return profile.litellmModelId diff --git a/src/shared/__tests__/ProfileValidator.spec.ts b/src/shared/__tests__/ProfileValidator.spec.ts index 7ece0d8bf8..fa055a8157 100644 --- a/src/shared/__tests__/ProfileValidator.spec.ts +++ b/src/shared/__tests__/ProfileValidator.spec.ts @@ -193,6 +193,7 @@ describe("ProfileValidator", () => { "groq", "chutes", "sambanova", + "fireworks", ] apiModelProviders.forEach((provider) => { diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 6c521ecfdf..204abe9c0f 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -30,6 +30,7 @@ import { sambaNovaDefaultModelId, internationalZAiDefaultModelId, mainlandZAiDefaultModelId, + fireworksDefaultModelId, } from "@roo-code/types" import { vscode } from "@src/utils/vscode" @@ -82,6 +83,7 @@ import { VSCodeLM, XAI, ZAi, + Fireworks, } from "./providers" import { MODELS_BY_PROVIDER, PROVIDERS } from "./constants" @@ -316,6 +318,7 @@ const ApiOptions = ({ ? mainlandZAiDefaultModelId : internationalZAiDefaultModelId, }, + fireworks: { field: "apiModelId", default: fireworksDefaultModelId }, openai: { field: "openAiModelId" }, ollama: { field: "ollamaModelId" }, lmstudio: { field: "lmStudioModelId" }, @@ -555,6 +558,10 @@ const ApiOptions = ({ )} + {selectedProvider === "fireworks" && ( + + )} + {selectedProviderModels.length > 0 && ( <>
diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index c0ddaf89e1..90192f372b 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -17,6 +17,7 @@ import { sambaNovaModels, doubaoModels, internationalZAiModels, + fireworksModels, } from "@roo-code/types" export const MODELS_BY_PROVIDER: Partial>> = { @@ -36,6 +37,7 @@ export const MODELS_BY_PROVIDER: Partial a.label.localeCompare(b.label)) diff --git a/webview-ui/src/components/settings/providers/Fireworks.tsx b/webview-ui/src/components/settings/providers/Fireworks.tsx new file mode 100644 index 0000000000..bb8eb8aa58 --- /dev/null +++ b/webview-ui/src/components/settings/providers/Fireworks.tsx @@ -0,0 +1,50 @@ +import { useCallback } from "react" +import { VSCodeTextField } 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" + +type FireworksProps = { + apiConfiguration: ProviderSettings + setApiConfigurationField: (field: keyof ProviderSettings, value: ProviderSettings[keyof ProviderSettings]) => void +} + +export const Fireworks = ({ apiConfiguration, setApiConfigurationField }: FireworksProps) => { + 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 ( + <> + + + +
+ {t("settings:providers.apiKeyStorageNotice")} +
+ {!apiConfiguration?.fireworksApiKey && ( + + {t("settings:providers.getFireworksApiKey")} + + )} + + ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index 0f0048df0a..e8428eb66c 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -24,3 +24,4 @@ export { VSCodeLM } from "./VSCodeLM" export { XAI } from "./XAI" export { ZAi } from "./ZAi" export { LiteLLM } from "./LiteLLM" +export { Fireworks } from "./Fireworks" diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index a191014981..2ccf9d4071 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -44,6 +44,8 @@ import { mainlandZAiDefaultModelId, internationalZAiModels, mainlandZAiModels, + fireworksModels, + fireworksDefaultModelId, } from "@roo-code/types" import type { ModelRecord, RouterModels } from "@roo/api" @@ -270,6 +272,11 @@ function getSelectedModel({ const info = sambaNovaModels[id as keyof typeof sambaNovaModels] return { id, info } } + case "fireworks": { + const id = apiConfiguration.apiModelId ?? fireworksDefaultModelId + const info = fireworksModels[id as keyof typeof fireworksModels] + return { id, info } + } // case "anthropic": // case "human-relay": // case "fake-ai": diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 4ab333f48f..e3f2713ffe 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Obtenir clau API de Cerebras", "chutesApiKey": "Clau API de Chutes", "getChutesApiKey": "Obtenir clau API de Chutes", + "fireworksApiKey": "Clau API de Fireworks", + "getFireworksApiKey": "Obtenir clau API de Fireworks", "deepSeekApiKey": "Clau API de DeepSeek", "getDeepSeekApiKey": "Obtenir clau API de DeepSeek", "doubaoApiKey": "Clau API de Doubao", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index ff893c3356..a4a62b8391 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -263,6 +263,8 @@ "getCerebrasApiKey": "Cerebras API-Schlüssel erhalten", "chutesApiKey": "Chutes API-Schlüssel", "getChutesApiKey": "Chutes API-Schlüssel erhalten", + "fireworksApiKey": "Fireworks API-Schlüssel", + "getFireworksApiKey": "Fireworks API-Schlüssel erhalten", "deepSeekApiKey": "DeepSeek API-Schlüssel", "getDeepSeekApiKey": "DeepSeek API-Schlüssel erhalten", "moonshotApiKey": "Moonshot API-Schlüssel", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index a48213110a..8bc6d15b74 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -260,6 +260,8 @@ "getCerebrasApiKey": "Get Cerebras API Key", "chutesApiKey": "Chutes API Key", "getChutesApiKey": "Get Chutes API Key", + "fireworksApiKey": "Fireworks API Key", + "getFireworksApiKey": "Get Fireworks API Key", "deepSeekApiKey": "DeepSeek API Key", "getDeepSeekApiKey": "Get DeepSeek API Key", "doubaoApiKey": "Doubao API Key", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 579426cdb6..e2db1463af 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Obtener clave API de Cerebras", "chutesApiKey": "Clave API de Chutes", "getChutesApiKey": "Obtener clave API de Chutes", + "fireworksApiKey": "Clave API de Fireworks", + "getFireworksApiKey": "Obtener clave API de Fireworks", "deepSeekApiKey": "Clave API de DeepSeek", "getDeepSeekApiKey": "Obtener clave API de DeepSeek", "doubaoApiKey": "Clave API de Doubao", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 52ac1aec34..26018a344b 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Obtenir la clé API Cerebras", "chutesApiKey": "Clé API Chutes", "getChutesApiKey": "Obtenir la clé API Chutes", + "fireworksApiKey": "Clé API Fireworks", + "getFireworksApiKey": "Obtenir la clé API Fireworks", "deepSeekApiKey": "Clé API DeepSeek", "getDeepSeekApiKey": "Obtenir la clé API DeepSeek", "doubaoApiKey": "Clé API Doubao", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 7926ae5ba9..7c8b280427 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Cerebras API कुंजी प्राप्त करें", "chutesApiKey": "Chutes API कुंजी", "getChutesApiKey": "Chutes API कुंजी प्राप्त करें", + "fireworksApiKey": "Fireworks API कुंजी", + "getFireworksApiKey": "Fireworks API कुंजी प्राप्त करें", "deepSeekApiKey": "DeepSeek API कुंजी", "getDeepSeekApiKey": "DeepSeek API कुंजी प्राप्त करें", "doubaoApiKey": "डौबाओ API कुंजी", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 66e7cb53a1..b4f9b113b3 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -265,6 +265,8 @@ "getCerebrasApiKey": "Dapatkan Cerebras API Key", "chutesApiKey": "Chutes API Key", "getChutesApiKey": "Dapatkan Chutes API Key", + "fireworksApiKey": "Fireworks API Key", + "getFireworksApiKey": "Dapatkan Fireworks API Key", "deepSeekApiKey": "DeepSeek API Key", "getDeepSeekApiKey": "Dapatkan DeepSeek API Key", "doubaoApiKey": "Kunci API Doubao", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 4cfe6ff231..82d7b2d041 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Ottieni chiave API Cerebras", "chutesApiKey": "Chiave API Chutes", "getChutesApiKey": "Ottieni chiave API Chutes", + "fireworksApiKey": "Chiave API Fireworks", + "getFireworksApiKey": "Ottieni chiave API Fireworks", "deepSeekApiKey": "Chiave API DeepSeek", "getDeepSeekApiKey": "Ottieni chiave API DeepSeek", "doubaoApiKey": "Chiave API Doubao", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index a83d78ed39..dfa62ab32b 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Cerebras APIキーを取得", "chutesApiKey": "Chutes APIキー", "getChutesApiKey": "Chutes APIキーを取得", + "fireworksApiKey": "Fireworks APIキー", + "getFireworksApiKey": "Fireworks APIキーを取得", "deepSeekApiKey": "DeepSeek APIキー", "getDeepSeekApiKey": "DeepSeek APIキーを取得", "doubaoApiKey": "Doubao APIキー", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 708b1c7ada..219a5de54a 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Cerebras API 키 가져오기", "chutesApiKey": "Chutes API 키", "getChutesApiKey": "Chutes API 키 받기", + "fireworksApiKey": "Fireworks API 키", + "getFireworksApiKey": "Fireworks API 키 받기", "deepSeekApiKey": "DeepSeek API 키", "getDeepSeekApiKey": "DeepSeek API 키 받기", "doubaoApiKey": "Doubao API 키", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index dca4ba5c71..735339bb66 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Cerebras API-sleutel verkrijgen", "chutesApiKey": "Chutes API-sleutel", "getChutesApiKey": "Chutes API-sleutel ophalen", + "fireworksApiKey": "Fireworks API-sleutel", + "getFireworksApiKey": "Fireworks API-sleutel ophalen", "deepSeekApiKey": "DeepSeek API-sleutel", "getDeepSeekApiKey": "DeepSeek API-sleutel ophalen", "doubaoApiKey": "Doubao API-sleutel", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 5037ceb569..e25eee34cf 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Pobierz klucz API Cerebras", "chutesApiKey": "Klucz API Chutes", "getChutesApiKey": "Uzyskaj klucz API Chutes", + "fireworksApiKey": "Klucz API Fireworks", + "getFireworksApiKey": "Uzyskaj klucz API Fireworks", "deepSeekApiKey": "Klucz API DeepSeek", "getDeepSeekApiKey": "Uzyskaj klucz API DeepSeek", "doubaoApiKey": "Klucz API Doubao", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index c862cee357..e7243aa6f6 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Obter chave de API Cerebras", "chutesApiKey": "Chave de API Chutes", "getChutesApiKey": "Obter chave de API Chutes", + "fireworksApiKey": "Chave de API Fireworks", + "getFireworksApiKey": "Obter chave de API Fireworks", "deepSeekApiKey": "Chave de API DeepSeek", "getDeepSeekApiKey": "Obter chave de API DeepSeek", "doubaoApiKey": "Chave de API Doubao", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 25b147f57e..38e986ab88 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Получить Cerebras API-ключ", "chutesApiKey": "Chutes API-ключ", "getChutesApiKey": "Получить Chutes API-ключ", + "fireworksApiKey": "Fireworks API-ключ", + "getFireworksApiKey": "Получить Fireworks API-ключ", "deepSeekApiKey": "DeepSeek API-ключ", "getDeepSeekApiKey": "Получить DeepSeek API-ключ", "doubaoApiKey": "Doubao API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 1aa6ce9783..b4b9fd13e4 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Cerebras API Anahtarını Al", "chutesApiKey": "Chutes API Anahtarı", "getChutesApiKey": "Chutes API Anahtarı Al", + "fireworksApiKey": "Fireworks API Anahtarı", + "getFireworksApiKey": "Fireworks API Anahtarı Al", "deepSeekApiKey": "DeepSeek API Anahtarı", "getDeepSeekApiKey": "DeepSeek API Anahtarı Al", "doubaoApiKey": "Doubao API Anahtarı", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 3449012f9c..cdae509d5e 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "Lấy khóa API Cerebras", "chutesApiKey": "Khóa API Chutes", "getChutesApiKey": "Lấy khóa API Chutes", + "fireworksApiKey": "Khóa API Fireworks", + "getFireworksApiKey": "Lấy khóa API Fireworks", "deepSeekApiKey": "Khóa API DeepSeek", "getDeepSeekApiKey": "Lấy khóa API DeepSeek", "doubaoApiKey": "Khóa API Doubao", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index e7c53cf757..aca901cc3e 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "获取 Cerebras API 密钥", "chutesApiKey": "Chutes API 密钥", "getChutesApiKey": "获取 Chutes API 密钥", + "fireworksApiKey": "Fireworks API 密钥", + "getFireworksApiKey": "获取 Fireworks API 密钥", "deepSeekApiKey": "DeepSeek API 密钥", "getDeepSeekApiKey": "获取 DeepSeek API 密钥", "doubaoApiKey": "豆包 API 密钥", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index cfdcd6e696..db3fc3c2cd 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -261,6 +261,8 @@ "getCerebrasApiKey": "取得 Cerebras API 金鑰", "chutesApiKey": "Chutes API 金鑰", "getChutesApiKey": "取得 Chutes API 金鑰", + "fireworksApiKey": "Fireworks API 金鑰", + "getFireworksApiKey": "取得 Fireworks API 金鑰", "deepSeekApiKey": "DeepSeek API 金鑰", "getDeepSeekApiKey": "取得 DeepSeek API 金鑰", "doubaoApiKey": "豆包 API 金鑰", diff --git a/webview-ui/src/utils/validate.ts b/webview-ui/src/utils/validate.ts index 3b85ef9919..b39060e665 100644 --- a/webview-ui/src/utils/validate.ts +++ b/webview-ui/src/utils/validate.ts @@ -115,6 +115,11 @@ function validateModelsAndKeysProvided(apiConfiguration: ProviderSettings): stri return i18next.t("settings:validation.apiKey") } break + case "fireworks": + if (!apiConfiguration.fireworksApiKey) { + return i18next.t("settings:validation.apiKey") + } + break } return undefined