diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 859792d7c36..06a957ee8bd 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -4,6 +4,7 @@ import { modelInfoSchema, reasoningEffortSettingSchema, verbosityLevelsSchema, s import { codebaseIndexProviderSchema } from "./codebase-index.js" import { anthropicModels, + avianModels, basetenModels, bedrockModels, deepSeekModels, @@ -103,6 +104,7 @@ export const providerNames = [ ...customProviders, ...fauxProviders, "anthropic", + "avian", "bedrock", "baseten", "deepseek", @@ -359,6 +361,10 @@ const zaiSchema = apiModelIdProviderModelSchema.extend({ zaiApiLine: zaiApiLineSchema.optional(), }) +const avianSchema = apiModelIdProviderModelSchema.extend({ + avianApiKey: z.string().optional(), +}) + const fireworksSchema = apiModelIdProviderModelSchema.extend({ fireworksApiKey: z.string().optional(), }) @@ -387,6 +393,7 @@ const defaultSchema = z.object({ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProvider", [ anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })), + avianSchema.merge(z.object({ apiProvider: z.literal("avian") })), openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })), bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })), vertexSchema.merge(z.object({ apiProvider: z.literal("vertex") })), @@ -420,6 +427,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv export const providerSettingsSchema = z.object({ apiProvider: providerNamesWithRetiredSchema.optional(), ...anthropicSchema.shape, + ...avianSchema.shape, ...openRouterSchema.shape, ...bedrockSchema.shape, ...vertexSchema.shape, @@ -497,6 +505,7 @@ export const isTypicalProvider = (key: unknown): key is TypicalProvider => export const modelIdKeysByProvider: Record = { anthropic: "apiModelId", + avian: "apiModelId", openrouter: "openRouterModelId", bedrock: "apiModelId", vertex: "apiModelId", @@ -565,6 +574,11 @@ export const MODELS_BY_PROVIDER: Record< label: "Anthropic", models: Object.keys(anthropicModels), }, + avian: { + id: "avian", + label: "Avian", + models: Object.keys(avianModels), + }, bedrock: { id: "bedrock", label: "Amazon Bedrock", diff --git a/packages/types/src/providers/avian.ts b/packages/types/src/providers/avian.ts new file mode 100644 index 00000000000..006aec25317 --- /dev/null +++ b/packages/types/src/providers/avian.ts @@ -0,0 +1,49 @@ +import type { ModelInfo } from "../model.js" + +// https://avian.io +export type AvianModelId = "deepseek/deepseek-v3.2" | "moonshotai/kimi-k2.5" | "z-ai/glm-5" | "minimax/minimax-m2.5" + +export const avianDefaultModelId: AvianModelId = "deepseek/deepseek-v3.2" + +export const avianModels = { + "deepseek/deepseek-v3.2": { + maxTokens: 65536, + contextWindow: 163840, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.26, + outputPrice: 0.38, + description: + "DeepSeek V3.2 is the latest iteration of the V3 model family with enhanced reasoning capabilities, improved code generation, and better instruction following. 164K context window with 65K max output.", + }, + "moonshotai/kimi-k2.5": { + maxTokens: 8192, + contextWindow: 131072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.45, + outputPrice: 2.2, + description: + "Kimi K2.5 is Moonshot AI's flagship agentic model. It unifies vision and text, thinking and non-thinking modes, and single-agent and multi-agent execution into one model. 131K context window.", + }, + "z-ai/glm-5": { + maxTokens: 16384, + contextWindow: 131072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.3, + outputPrice: 2.55, + description: + "Z.ai GLM-5 is an advanced coding and reasoning model with exceptional performance on complex programming tasks. 131K context window with 16K max output.", + }, + "minimax/minimax-m2.5": { + maxTokens: 1048576, + contextWindow: 1048576, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.3, + outputPrice: 1.1, + description: + "MiniMax M2.5 is a high-performance language model with an industry-leading 1M context window, optimized for long-context understanding and generation tasks.", + }, +} as const satisfies Record diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 6bb959c7056..fdfa64801c6 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -1,4 +1,5 @@ export * from "./anthropic.js" +export * from "./avian.js" export * from "./baseten.js" export * from "./bedrock.js" export * from "./deepseek.js" @@ -26,6 +27,7 @@ export * from "./zai.js" export * from "./minimax.js" import { anthropicDefaultModelId } from "./anthropic.js" +import { avianDefaultModelId } from "./avian.js" import { basetenDefaultModelId } from "./baseten.js" import { bedrockDefaultModelId } from "./bedrock.js" import { deepSeekDefaultModelId } from "./deepseek.js" @@ -101,6 +103,8 @@ export function getProviderDefaultModelId( return vscodeLlmDefaultModelId case "sambanova": return sambaNovaDefaultModelId + case "avian": + return avianDefaultModelId case "fireworks": return fireworksDefaultModelId case "roo": diff --git a/src/api/index.ts b/src/api/index.ts index ebc2682a1a8..e467af18aca 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -7,6 +7,7 @@ import { ApiStream } from "./transform/stream" import { AnthropicHandler, + AvianHandler, AwsBedrockHandler, OpenRouterHandler, VertexHandler, @@ -120,6 +121,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { switch (apiProvider) { case "anthropic": return new AnthropicHandler(options) + case "avian": + return new AvianHandler(options) case "openrouter": return new OpenRouterHandler(options) case "bedrock": diff --git a/src/api/providers/__tests__/avian.spec.ts b/src/api/providers/__tests__/avian.spec.ts new file mode 100644 index 00000000000..4921aa4014a --- /dev/null +++ b/src/api/providers/__tests__/avian.spec.ts @@ -0,0 +1,336 @@ +// npx vitest run src/api/providers/__tests__/avian.spec.ts + +import { Anthropic } from "@anthropic-ai/sdk" +import OpenAI from "openai" + +import { type AvianModelId, avianDefaultModelId, avianModels } from "@roo-code/types" + +import { AvianHandler } from "../avian" + +// Create mock functions +const mockCreate = vi.fn() + +// Mock OpenAI module +vi.mock("openai", () => ({ + default: vi.fn(() => ({ + chat: { + completions: { + create: mockCreate, + }, + }, + })), +})) + +describe("AvianHandler", () => { + let handler: AvianHandler + + 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 AvianHandler({ avianApiKey: "test-key" }) + }) + + afterEach(() => { + vi.restoreAllMocks() + }) + + it("should use the correct Avian base URL", () => { + new AvianHandler({ avianApiKey: "test-avian-api-key" }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://api.avian.io/v1" })) + }) + + it("should use the provided API key", () => { + const avianApiKey = "test-avian-api-key" + new AvianHandler({ avianApiKey }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: avianApiKey })) + }) + + it("should throw error when API key is not provided", () => { + expect(() => new AvianHandler({})).toThrow("API key is required") + }) + + it("should return default model when no model is specified", () => { + const model = handler.getModel() + expect(model.id).toBe(avianDefaultModelId) + expect(model.info).toEqual(expect.objectContaining(avianModels[avianDefaultModelId])) + }) + + it("should return specified model when valid model is provided", () => { + const testModelId: AvianModelId = "moonshotai/kimi-k2.5" + const handlerWithModel = new AvianHandler({ + apiModelId: testModelId, + avianApiKey: "test-avian-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual(expect.objectContaining(avianModels[testModelId])) + }) + + it("should return DeepSeek V3.2 model with correct configuration", () => { + const testModelId: AvianModelId = "deepseek/deepseek-v3.2" + const handlerWithModel = new AvianHandler({ + apiModelId: testModelId, + avianApiKey: "test-avian-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 65536, + contextWindow: 163840, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.26, + outputPrice: 0.38, + description: expect.stringContaining("DeepSeek V3.2"), + }), + ) + }) + + it("should return Kimi K2.5 model with correct configuration", () => { + const testModelId: AvianModelId = "moonshotai/kimi-k2.5" + const handlerWithModel = new AvianHandler({ + apiModelId: testModelId, + avianApiKey: "test-avian-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 8192, + contextWindow: 131072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.45, + outputPrice: 2.2, + description: expect.stringContaining("Kimi K2.5"), + }), + ) + }) + + it("should return GLM-5 model with correct configuration", () => { + const testModelId: AvianModelId = "z-ai/glm-5" + const handlerWithModel = new AvianHandler({ + apiModelId: testModelId, + avianApiKey: "test-avian-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 16384, + contextWindow: 131072, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.3, + outputPrice: 2.55, + description: expect.stringContaining("GLM-5"), + }), + ) + }) + + it("should return MiniMax M2.5 model with correct configuration", () => { + const testModelId: AvianModelId = "minimax/minimax-m2.5" + const handlerWithModel = new AvianHandler({ + apiModelId: testModelId, + avianApiKey: "test-avian-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe(testModelId) + expect(model.info).toEqual( + expect.objectContaining({ + maxTokens: 1048576, + contextWindow: 1048576, + supportsImages: false, + supportsPromptCache: false, + inputPrice: 0.3, + outputPrice: 1.1, + description: expect.stringContaining("MiniMax M2.5"), + }), + ) + }) + + it("completePrompt method should return text from Avian API", async () => { + const expectedResponse = "This is a test response from Avian" + 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 = "Avian API error" + mockCreate.mockRejectedValueOnce(new Error(errorMessage)) + await expect(handler.completePrompt("test prompt")).rejects.toThrow(`Avian completion error: ${errorMessage}`) + }) + + it("createMessage should yield text content from stream", async () => { + const testContent = "This is test content from Avian 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).toMatchObject({ type: "usage", inputTokens: 10, outputTokens: 20 }) + }) + + it("createMessage should pass correct parameters to Avian client", async () => { + const modelId: AvianModelId = "deepseek/deepseek-v3.2" + const modelInfo = avianModels[modelId] + const handlerWithModel = new AvianHandler({ + apiModelId: modelId, + avianApiKey: "test-avian-api-key", + }) + + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + async next() { + return { done: true } + }, + }), + } + }) + + const systemPrompt = "Test system prompt for Avian" + const messages: Anthropic.Messages.MessageParam[] = [{ role: "user", content: "Test message for Avian" }] + + const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages) + await messageGenerator.next() + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: modelId, + temperature: 0, + messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]), + stream: true, + stream_options: { include_usage: true }, + }), + undefined, + ) + }) + + 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[0]).toEqual({ type: "text", text: "Hello" }) + expect(chunks[1]).toEqual({ type: "text", text: " world" }) + expect(chunks[2]).toMatchObject({ type: "usage", inputTokens: 5, outputTokens: 10 }) + }) +}) diff --git a/src/api/providers/avian.ts b/src/api/providers/avian.ts new file mode 100644 index 00000000000..577aedb2972 --- /dev/null +++ b/src/api/providers/avian.ts @@ -0,0 +1,18 @@ +import { type AvianModelId, avianDefaultModelId, avianModels } from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../shared/api" + +import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider" + +export class AvianHandler extends BaseOpenAiCompatibleProvider { + constructor(options: ApiHandlerOptions) { + super({ + ...options, + providerName: "Avian", + baseURL: "https://api.avian.io/v1", + apiKey: options.avianApiKey, + defaultProviderModelId: avianDefaultModelId, + providerModels: avianModels, + }) + } +} diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index b6de7952104..7560fadba8a 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -1,5 +1,6 @@ export { AnthropicVertexHandler } from "./anthropic-vertex" export { AnthropicHandler } from "./anthropic" +export { AvianHandler } from "./avian" export { AwsBedrockHandler } from "./bedrock" export { DeepSeekHandler } from "./deepseek" export { MoonshotHandler } from "./moonshot" diff --git a/src/shared/ProfileValidator.ts b/src/shared/ProfileValidator.ts index 7246a90177a..22dc4310a35 100644 --- a/src/shared/ProfileValidator.ts +++ b/src/shared/ProfileValidator.ts @@ -54,6 +54,7 @@ export class ProfileValidator { case "openai": return profile.openAiModelId case "anthropic": + case "avian": case "openai-native": case "bedrock": case "vertex": diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 4d914a4833a..948daa4dcf1 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -15,6 +15,7 @@ import { openAiNativeDefaultModelId, openAiCodexDefaultModelId, anthropicDefaultModelId, + avianDefaultModelId, qwenCodeDefaultModelId, geminiDefaultModelId, deepSeekDefaultModelId, @@ -67,6 +68,7 @@ import { import { Anthropic, + Avian, Baseten, Bedrock, DeepSeek, @@ -335,6 +337,7 @@ const ApiOptions = ({ unbound: { field: "unboundModelId", default: unboundDefaultModelId }, litellm: { field: "litellmModelId", default: litellmDefaultModelId }, anthropic: { field: "apiModelId", default: anthropicDefaultModelId }, + avian: { field: "apiModelId", default: avianDefaultModelId }, "openai-codex": { field: "apiModelId", default: openAiCodexDefaultModelId }, "qwen-code": { field: "apiModelId", default: qwenCodeDefaultModelId }, "openai-native": { field: "apiModelId", default: openAiNativeDefaultModelId }, @@ -541,6 +544,13 @@ const ApiOptions = ({ /> )} + {selectedProvider === "avian" && ( + + )} + {selectedProvider === "openai-codex" && ( >> = { anthropic: anthropicModels, + avian: avianModels, bedrock: bedrockModels, deepseek: deepSeekModels, moonshot: moonshotModels, @@ -41,6 +43,7 @@ export const MODELS_BY_PROVIDER: Partial void +} + +export const Avian = ({ apiConfiguration, setApiConfigurationField }: AvianProps) => { + 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?.avianApiKey && ( + + {t("settings:providers.getAvianApiKey")} + + )} + + ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index 597caffd1d7..088d7a6f1e7 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -1,4 +1,5 @@ export { Anthropic } from "./Anthropic" +export { Avian } from "./Avian" export { Bedrock } from "./Bedrock" export { DeepSeek } from "./DeepSeek" export { Gemini } from "./Gemini" diff --git a/webview-ui/src/components/settings/utils/providerModelConfig.ts b/webview-ui/src/components/settings/utils/providerModelConfig.ts index fa718143905..ed164ce34ff 100644 --- a/webview-ui/src/components/settings/utils/providerModelConfig.ts +++ b/webview-ui/src/components/settings/utils/providerModelConfig.ts @@ -1,6 +1,7 @@ import type { ProviderName, ModelInfo, ProviderSettings } from "@roo-code/types" import { anthropicDefaultModelId, + avianDefaultModelId, bedrockDefaultModelId, deepSeekDefaultModelId, moonshotDefaultModelId, @@ -27,6 +28,7 @@ export interface ProviderServiceConfig { export const PROVIDER_SERVICE_CONFIG: Partial> = { anthropic: { serviceName: "Anthropic", serviceUrl: "https://console.anthropic.com" }, + avian: { serviceName: "Avian", serviceUrl: "https://avian.io" }, bedrock: { serviceName: "Amazon Bedrock", serviceUrl: "https://aws.amazon.com/bedrock" }, deepseek: { serviceName: "DeepSeek", serviceUrl: "https://platform.deepseek.com" }, moonshot: { serviceName: "Moonshot", serviceUrl: "https://platform.moonshot.cn" }, @@ -51,6 +53,7 @@ export const PROVIDER_SERVICE_CONFIG: Partial> = { anthropic: anthropicDefaultModelId, + avian: avianDefaultModelId, bedrock: bedrockDefaultModelId, deepseek: deepSeekDefaultModelId, moonshot: moonshotDefaultModelId, diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index c32a08990c8..761feda9a39 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -5,6 +5,7 @@ import { type ModelRecord, type RouterModels, anthropicModels, + avianModels, bedrockModels, deepSeekModels, moonshotModels, @@ -302,6 +303,11 @@ function getSelectedModel({ const info = vscodeLlmModels[modelFamily as keyof typeof vscodeLlmModels] return { id, info: { ...openAiModelInfoSaneDefaults, ...info, supportsImages: false } } // VSCode LM API currently doesn't support images. } + case "avian": { + const id = apiConfiguration.apiModelId ?? defaultModelId + const info = avianModels[id as keyof typeof avianModels] + return { id, info } + } case "sambanova": { const id = apiConfiguration.apiModelId ?? defaultModelId const info = sambaNovaModels[id as keyof typeof sambaNovaModels] diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 2c83cabbbcb..88e2ebea68d 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Amplia la finestra de context a 1 milió de tokens per a Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Activa la finestra de context d'1M (Beta)", "vertex1MContextBetaDescription": "Amplia la finestra de context a 1 milió de tokens per a Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Clau API de Baseten", "getBasetenApiKey": "Obtenir clau API de Baseten", "fireworksApiKey": "Clau API de Fireworks", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index c31d29147d4..1e8eded2ebc 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Erweitert das Kontextfenster für Claude Sonnet 4.x / Claude Opus 4.6 auf 1 Million Token", "vertex1MContextBetaLabel": "1M Kontextfenster aktivieren (Beta)", "vertex1MContextBetaDescription": "Erweitert das Kontextfenster für Claude Sonnet 4.x / Claude Opus 4.6 auf 1 Million Token", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API-Schlüssel", "getBasetenApiKey": "Baseten API-Schlüssel erhalten", "fireworksApiKey": "Fireworks API-Schlüssel", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 3b2497aaee7..21344b95aa5 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -441,6 +441,8 @@ "awsBedrock1MContextBetaDescription": "Extends context window to 1 million tokens for Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Enable 1M context window (Beta)", "vertex1MContextBetaDescription": "Extends context window to 1 million tokens for Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API Key", "getBasetenApiKey": "Get Baseten API Key", "fireworksApiKey": "Fireworks API Key", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 6595c4f9079..870dd9217ef 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Amplía la ventana de contexto a 1 millón de tokens para Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Habilitar ventana de contexto de 1M (Beta)", "vertex1MContextBetaDescription": "Amplía la ventana de contexto a 1 millón de tokens para Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Clave API de Baseten", "getBasetenApiKey": "Obtener clave API de Baseten", "fireworksApiKey": "Clave API de Fireworks", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index 56337bda14c..b3f9615ca5f 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Étend la fenêtre de contexte à 1 million de tokens pour Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Activer la fenêtre de contexte de 1M (Bêta)", "vertex1MContextBetaDescription": "Étend la fenêtre de contexte à 1 million de tokens pour Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Clé API Baseten", "getBasetenApiKey": "Obtenir la clé API Baseten", "fireworksApiKey": "Clé API Fireworks", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index abd334bec09..2c6454f3926 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6 के लिए संदर्भ विंडो को 1 मिलियन टोकन तक बढ़ाता है", "vertex1MContextBetaLabel": "1M संदर्भ विंडो सक्षम करें (बीटा)", "vertex1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6 के लिए संदर्भ विंडो को 1 मिलियन टोकन तक बढ़ाता है", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API कुंजी", "getBasetenApiKey": "Baseten API कुंजी प्राप्त करें", "fireworksApiKey": "Fireworks API कुंजी", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 1ebcf2073b6..59f92990281 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Memperluas jendela konteks menjadi 1 juta token untuk Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Aktifkan jendela konteks 1M (Beta)", "vertex1MContextBetaDescription": "Memperluas jendela konteks menjadi 1 juta token untuk Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API Key", "getBasetenApiKey": "Dapatkan Baseten API Key", "fireworksApiKey": "Fireworks API Key", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 4a0c7161654..4c3c1d4b600 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Estende la finestra di contesto a 1 milione di token per Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Abilita finestra di contesto da 1M (Beta)", "vertex1MContextBetaDescription": "Estende la finestra di contesto a 1 milione di token per Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Chiave API Baseten", "getBasetenApiKey": "Ottieni chiave API Baseten", "fireworksApiKey": "Chiave API Fireworks", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index b0d921571af..704ea19eac9 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6のコンテキストウィンドウを100万トークンに拡張します", "vertex1MContextBetaLabel": "1Mコンテキストウィンドウを有効にする(ベータ版)", "vertex1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6のコンテキストウィンドウを100万トークンに拡張します", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten APIキー", "getBasetenApiKey": "Baseten APIキーを取得", "fireworksApiKey": "Fireworks APIキー", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 88fc8e6d79e..e6c4452e70a 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6의 컨텍스트 창을 100만 토큰으로 확장", "vertex1MContextBetaLabel": "1M 컨텍스트 창 활성화 (베타)", "vertex1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6의 컨텍스트 창을 100만 토큰으로 확장", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API 키", "getBasetenApiKey": "Baseten API 키 가져오기", "fireworksApiKey": "Fireworks API 키", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index fcfad37d376..a6318451899 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Breidt het contextvenster uit tot 1 miljoen tokens voor Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "1M contextvenster inschakelen (bèta)", "vertex1MContextBetaDescription": "Breidt het contextvenster uit tot 1 miljoen tokens voor Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API-sleutel", "getBasetenApiKey": "Baseten API-sleutel verkrijgen", "fireworksApiKey": "Fireworks API-sleutel", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index fa48bc6b212..13c2a163471 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Rozszerza okno kontekstowe do 1 miliona tokenów dla Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Włącz okno kontekstowe 1M (Beta)", "vertex1MContextBetaDescription": "Rozszerza okno kontekstowe do 1 miliona tokenów dla Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Klucz API Baseten", "getBasetenApiKey": "Uzyskaj klucz API Baseten", "fireworksApiKey": "Klucz API Fireworks", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index a8387e05121..3a6fe7a051f 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Estende a janela de contexto para 1 milhão de tokens para o Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Ativar janela de contexto de 1M (Beta)", "vertex1MContextBetaDescription": "Estende a janela de contexto para 1 milhão de tokens para o Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Chave de API Baseten", "getBasetenApiKey": "Obter chave de API Baseten", "fireworksApiKey": "Chave de API Fireworks", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index fe24ebee299..e06b61b9756 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Расширяет контекстное окно до 1 миллиона токенов для Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Включить контекстное окно 1M (бета)", "vertex1MContextBetaDescription": "Расширяет контекстное окно до 1 миллиона токенов для Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API-ключ", "getBasetenApiKey": "Получить Baseten API-ключ", "fireworksApiKey": "Fireworks API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 7171718f1c5..76fb8e160e1 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6 için bağlam penceresini 1 milyon token'a genişletir", "vertex1MContextBetaLabel": "1M bağlam penceresini etkinleştir (Beta)", "vertex1MContextBetaDescription": "Claude Sonnet 4.x / Claude Opus 4.6 için bağlam penceresini 1 milyon token'a genişletir", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API Anahtarı", "getBasetenApiKey": "Baseten API Anahtarı Al", "fireworksApiKey": "Fireworks API Anahtarı", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 95b4f2d6863..ba7287d9dc2 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "Mở rộng cửa sổ ngữ cảnh lên 1 triệu token cho Claude Sonnet 4.x / Claude Opus 4.6", "vertex1MContextBetaLabel": "Bật cửa sổ ngữ cảnh 1M (Beta)", "vertex1MContextBetaDescription": "Mở rộng cửa sổ ngữ cảnh lên 1 triệu token cho Claude Sonnet 4.x / Claude Opus 4.6", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Khóa API Baseten", "getBasetenApiKey": "Lấy khóa API Baseten", "fireworksApiKey": "Khóa API Fireworks", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index eeba6bb079d..003bc655086 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -378,6 +378,8 @@ "awsBedrock1MContextBetaDescription": "为 Claude Sonnet 4.x / Claude Opus 4.6 将上下文窗口扩展至 100 万个 token", "vertex1MContextBetaLabel": "启用 1M 上下文窗口 (Beta)", "vertex1MContextBetaDescription": "为 Claude Sonnet 4.x / Claude Opus 4.6 将上下文窗口扩展至 100 万个 token", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API 密钥", "getBasetenApiKey": "获取 Baseten API 密钥", "fireworksApiKey": "Fireworks API 密钥", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 9f4241c3dd9..41c7d1ddce3 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -388,6 +388,8 @@ "awsBedrock1MContextBetaDescription": "為 Claude Sonnet 4.x / Claude Opus 4.6 將上下文視窗擴展至 100 萬個 token", "vertex1MContextBetaLabel": "啟用 1M 上下文視窗 (Beta)", "vertex1MContextBetaDescription": "為 Claude Sonnet 4.x / Claude Opus 4.6 將上下文視窗擴展至 100 萬個 token", + "avianApiKey": "Avian API Key", + "getAvianApiKey": "Get Avian API Key", "basetenApiKey": "Baseten API 金鑰", "getBasetenApiKey": "取得 Baseten API 金鑰", "fireworksApiKey": "Fireworks API 金鑰",