diff --git a/.changeset/abliteration-provider.md b/.changeset/abliteration-provider.md new file mode 100644 index 00000000000..f974cbd78c3 --- /dev/null +++ b/.changeset/abliteration-provider.md @@ -0,0 +1,5 @@ +--- +"roo-cline": patch +--- + +Add abliteration.ai as a provider. diff --git a/apps/cli/src/lib/utils/__tests__/provider.test.ts b/apps/cli/src/lib/utils/__tests__/provider.test.ts index 70d8a2a5557..823e0d86d84 100644 --- a/apps/cli/src/lib/utils/__tests__/provider.test.ts +++ b/apps/cli/src/lib/utils/__tests__/provider.test.ts @@ -17,6 +17,11 @@ describe("getApiKeyFromEnv", () => { expect(getApiKeyFromEnv("anthropic")).toBe("test-anthropic-key") }) + it("should return API key from environment variable for abliteration.ai", () => { + process.env.ABLIT_KEY = "test-abliteration-key" + expect(getApiKeyFromEnv("abliteration")).toBe("test-abliteration-key") + }) + it("should return API key from environment variable for openrouter", () => { process.env.OPENROUTER_API_KEY = "test-openrouter-key" expect(getApiKeyFromEnv("openrouter")).toBe("test-openrouter-key") diff --git a/apps/cli/src/lib/utils/provider.ts b/apps/cli/src/lib/utils/provider.ts index 64aec430c1b..78d495b51f2 100644 --- a/apps/cli/src/lib/utils/provider.ts +++ b/apps/cli/src/lib/utils/provider.ts @@ -3,6 +3,7 @@ import { RooCodeSettings } from "@roo-code/types" import type { SupportedProvider } from "@/types/index.js" const envVarMap: Record = { + abliteration: "ABLIT_KEY", anthropic: "ANTHROPIC_API_KEY", "openai-native": "OPENAI_API_KEY", gemini: "GOOGLE_API_KEY", @@ -28,6 +29,10 @@ export function getProviderSettings( const config: RooCodeSettings = { apiProvider: provider } switch (provider) { + case "abliteration": + if (apiKey) config.abliterationApiKey = apiKey + if (model) config.apiModelId = model + break case "anthropic": if (apiKey) config.apiKey = apiKey if (model) config.apiModelId = model diff --git a/apps/cli/src/types/types.ts b/apps/cli/src/types/types.ts index ecd3922aa1c..0096ffc1a03 100644 --- a/apps/cli/src/types/types.ts +++ b/apps/cli/src/types/types.ts @@ -2,6 +2,7 @@ import type { ProviderName, ReasoningEffortExtended } from "@roo-code/types" import type { OutputFormat } from "./json-events.js" export const supportedProviders = [ + "abliteration", "anthropic", "openai-native", "gemini", diff --git a/packages/types/src/global-settings.ts b/packages/types/src/global-settings.ts index 288f6c2118c..f54c231cc9b 100644 --- a/packages/types/src/global-settings.ts +++ b/packages/types/src/global-settings.ts @@ -252,6 +252,7 @@ export type RooCodeSettings = GlobalSettings & ProviderSettings export const SECRET_STATE_KEYS = [ "apiKey", "openRouterApiKey", + "abliterationApiKey", "awsAccessKey", "awsApiKey", "awsSecretKey", diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 43135577e16..7aca3fdb05c 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -3,6 +3,7 @@ import { z } from "zod" import { modelInfoSchema, reasoningEffortSettingSchema, verbosityLevelsSchema, serviceTierSchema } from "./model.js" import { codebaseIndexProviderSchema } from "./codebase-index.js" import { + abliterationModels, anthropicModels, basetenModels, bedrockModels, @@ -110,6 +111,7 @@ export const providerNames = [ ...internalProviders, ...customProviders, ...fauxProviders, + "abliteration", "anthropic", "bedrock", "baseten", @@ -209,6 +211,10 @@ const anthropicSchema = apiModelIdProviderModelSchema.extend({ anthropicBeta1MContext: z.boolean().optional(), // Enable 'context-1m-2025-08-07' beta for 1M context window. }) +const abliterationSchema = apiModelIdProviderModelSchema.extend({ + abliterationApiKey: z.string().optional(), +}) + const openRouterSchema = baseProviderSettingsSchema.extend({ openRouterApiKey: z.string().optional(), openRouterModelId: z.string().optional(), @@ -399,6 +405,7 @@ const defaultSchema = z.object({ }) export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProvider", [ + abliterationSchema.merge(z.object({ apiProvider: z.literal("abliteration") })), anthropicSchema.merge(z.object({ apiProvider: z.literal("anthropic") })), openRouterSchema.merge(z.object({ apiProvider: z.literal("openrouter") })), bedrockSchema.merge(z.object({ apiProvider: z.literal("bedrock") })), @@ -433,6 +440,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv export const providerSettingsSchema = z.object({ apiProvider: providerNamesWithRetiredSchema.optional(), + ...abliterationSchema.shape, ...anthropicSchema.shape, ...openRouterSchema.shape, ...bedrockSchema.shape, @@ -511,6 +519,7 @@ export const isTypicalProvider = (key: unknown): key is TypicalProvider => isProviderName(key) && !isInternalProvider(key) && !isCustomProvider(key) && !isFauxProvider(key) export const modelIdKeysByProvider: Record = { + abliteration: "apiModelId", anthropic: "apiModelId", openrouter: "openRouterModelId", bedrock: "apiModelId", @@ -576,6 +585,11 @@ export const MODELS_BY_PROVIDER: Record< Exclude, { id: ProviderName; label: string; models: string[] } > = { + abliteration: { + id: "abliteration", + label: "abliteration.ai", + models: Object.keys(abliterationModels), + }, anthropic: { id: "anthropic", label: "Anthropic", diff --git a/packages/types/src/providers/abliteration.ts b/packages/types/src/providers/abliteration.ts new file mode 100644 index 00000000000..7edc083a862 --- /dev/null +++ b/packages/types/src/providers/abliteration.ts @@ -0,0 +1,17 @@ +import type { ModelInfo } from "../model.js" + +// https://docs.abliteration.ai/models +export type AbliterationModelId = "abliterated-model" + +export const abliterationDefaultModelId: AbliterationModelId = "abliterated-model" + +export const abliterationModels = { + "abliterated-model": { + maxTokens: 8192, + contextWindow: 150_000, + supportsImages: true, + supportsPromptCache: false, + description: + "Default abliteration.ai model. Supports OpenAI-compatible chat completions, streaming, tool calling, and vision.", + }, +} as const satisfies Record diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 6c180d5dda4..df38c806bf1 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -1,3 +1,4 @@ +export * from "./abliteration.js" export * from "./anthropic.js" export * from "./baseten.js" export * from "./bedrock.js" @@ -26,6 +27,7 @@ export * from "./vercel-ai-gateway.js" export * from "./zai.js" export * from "./minimax.js" +import { abliterationDefaultModelId } from "./abliteration.js" import { anthropicDefaultModelId } from "./anthropic.js" import { basetenDefaultModelId } from "./baseten.js" import { bedrockDefaultModelId } from "./bedrock.js" @@ -63,6 +65,8 @@ export function getProviderDefaultModelId( options: { isChina?: boolean } = { isChina: false }, ): string { switch (provider) { + case "abliteration": + return abliterationDefaultModelId case "openrouter": return openRouterDefaultModelId case "requesty": diff --git a/src/api/index.ts b/src/api/index.ts index 1891113c03b..1b79e171793 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -7,6 +7,7 @@ import { ApiStream } from "./transform/stream" import { AnthropicHandler, + AbliterationHandler, AwsBedrockHandler, OpenRouterHandler, PoeHandler, @@ -119,6 +120,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { } switch (apiProvider) { + case "abliteration": + return new AbliterationHandler(options) case "anthropic": return new AnthropicHandler(options) case "openrouter": diff --git a/src/api/providers/__tests__/abliteration.spec.ts b/src/api/providers/__tests__/abliteration.spec.ts new file mode 100644 index 00000000000..ffb095e78b3 --- /dev/null +++ b/src/api/providers/__tests__/abliteration.spec.ts @@ -0,0 +1,129 @@ +// npx vitest run src/api/providers/__tests__/abliteration.spec.ts + +import { Anthropic } from "@anthropic-ai/sdk" +import OpenAI from "openai" + +import { abliterationDefaultModelId, abliterationModels } from "@roo-code/types" + +import { AbliterationHandler } from "../abliteration" + +const mockCreate = vi.fn() + +vi.mock("openai", () => ({ + default: vi.fn(() => ({ + chat: { + completions: { + create: mockCreate, + }, + }, + })), +})) + +describe("AbliterationHandler", () => { + let handler: AbliterationHandler + + beforeEach(() => { + vi.clearAllMocks() + handler = new AbliterationHandler({ abliterationApiKey: "test-abliteration-api-key" }) + }) + + it("should use the correct abliteration.ai base URL", () => { + new AbliterationHandler({ abliterationApiKey: "test-abliteration-api-key" }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ baseURL: "https://api.abliteration.ai/v1" })) + }) + + it("should use the provided API key", () => { + const abliterationApiKey = "test-abliteration-api-key" + new AbliterationHandler({ abliterationApiKey }) + expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({ apiKey: abliterationApiKey })) + }) + + it("should throw error when API key is not provided", () => { + expect(() => new AbliterationHandler({})).toThrow("API key is required") + }) + + it("should return default model when no model is specified", () => { + const model = handler.getModel() + expect(model.id).toBe(abliterationDefaultModelId) + expect(model.info).toEqual(abliterationModels[abliterationDefaultModelId]) + }) + + it("should return specified model when valid model is provided", () => { + const handlerWithModel = new AbliterationHandler({ + apiModelId: "abliterated-model", + abliterationApiKey: "test-abliteration-api-key", + }) + const model = handlerWithModel.getModel() + expect(model.id).toBe("abliterated-model") + expect(model.info).toEqual(abliterationModels["abliterated-model"]) + }) + + it("completePrompt method should return text from abliteration.ai API", async () => { + const expectedResponse = "This is a test response from abliteration.ai" + mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: expectedResponse } }] }) + const result = await handler.completePrompt("test prompt") + expect(result).toBe(expectedResponse) + }) + + it("createMessage should yield text content from stream", async () => { + const testContent = "This is test content from abliteration.ai 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 pass correct parameters to abliteration.ai client", async () => { + const modelInfo = abliterationModels[abliterationDefaultModelId] + const handlerWithModel = new AbliterationHandler({ + apiModelId: abliterationDefaultModelId, + abliterationApiKey: "test-abliteration-api-key", + }) + + mockCreate.mockImplementationOnce(() => { + return { + [Symbol.asyncIterator]: () => ({ + async next() { + return { done: true } + }, + }), + } + }) + + const systemPrompt = "Test system prompt for abliteration.ai" + const messages: Anthropic.Messages.MessageParam[] = [ + { role: "user", content: "Test message for abliteration.ai" }, + ] + + const messageGenerator = handlerWithModel.createMessage(systemPrompt, messages) + await messageGenerator.next() + + expect(mockCreate).toHaveBeenCalledWith( + expect.objectContaining({ + model: abliterationDefaultModelId, + max_tokens: modelInfo.maxTokens, + temperature: 0, + messages: expect.arrayContaining([{ role: "system", content: systemPrompt }]), + stream: true, + stream_options: { include_usage: true }, + }), + undefined, + ) + }) +}) diff --git a/src/api/providers/abliteration.ts b/src/api/providers/abliteration.ts new file mode 100644 index 00000000000..6ae3ab961c7 --- /dev/null +++ b/src/api/providers/abliteration.ts @@ -0,0 +1,18 @@ +import { type AbliterationModelId, abliterationDefaultModelId, abliterationModels } from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../shared/api" + +import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider" + +export class AbliterationHandler extends BaseOpenAiCompatibleProvider { + constructor(options: ApiHandlerOptions) { + super({ + ...options, + providerName: "abliteration.ai", + baseURL: "https://api.abliteration.ai/v1", + apiKey: options.abliterationApiKey, + defaultProviderModelId: abliterationDefaultModelId, + providerModels: abliterationModels, + }) + } +} diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index 41aff953d43..8ce554e67f7 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -1,3 +1,4 @@ +export { AbliterationHandler } from "./abliteration" export { AnthropicVertexHandler } from "./anthropic-vertex" export { AnthropicHandler } from "./anthropic" export { AwsBedrockHandler } from "./bedrock" diff --git a/src/shared/ProfileValidator.ts b/src/shared/ProfileValidator.ts index 7246a90177a..ada7177296d 100644 --- a/src/shared/ProfileValidator.ts +++ b/src/shared/ProfileValidator.ts @@ -53,6 +53,7 @@ export class ProfileValidator { switch (profile.apiProvider) { case "openai": return profile.openAiModelId + case "abliteration": case "anthropic": case "openai-native": case "bedrock": diff --git a/src/shared/__tests__/ProfileValidator.spec.ts b/src/shared/__tests__/ProfileValidator.spec.ts index 9bf913cdc27..fae9e134b96 100644 --- a/src/shared/__tests__/ProfileValidator.spec.ts +++ b/src/shared/__tests__/ProfileValidator.spec.ts @@ -168,6 +168,7 @@ describe("ProfileValidator", () => { // Test specific providers that use apiModelId const apiModelProviders = [ + "abliteration", "anthropic", "openai-native", "bedrock", diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index a6e4cc3f5f6..8f4c9c84a7a 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -9,6 +9,7 @@ import { type ProviderSettings, isRetiredProvider, DEFAULT_CONSECUTIVE_MISTAKE_LIMIT, + abliterationDefaultModelId, openRouterDefaultModelId, poeDefaultModelId, requestyDefaultModelId, @@ -94,6 +95,7 @@ import { Fireworks, VercelAiGateway, MiniMax, + Abliteration, } from "./providers" import { MODELS_BY_PROVIDER, PROVIDERS } from "./constants" @@ -362,6 +364,7 @@ const ApiOptions = ({ fireworks: { field: "apiModelId", default: fireworksDefaultModelId }, poe: { field: "apiModelId", default: poeDefaultModelId }, roo: { field: "apiModelId", default: rooDefaultModelId }, + abliteration: { field: "apiModelId", default: abliterationDefaultModelId }, "vercel-ai-gateway": { field: "vercelAiGatewayModelId", default: vercelAiGatewayDefaultModelId }, openai: { field: "openAiModelId" }, ollama: { field: "ollamaModelId" }, @@ -546,6 +549,13 @@ const ApiOptions = ({ /> )} + {selectedProvider === "abliteration" && ( + + )} + {selectedProvider === "openai-codex" && ( >> = { + abliteration: abliterationModels, anthropic: anthropicModels, bedrock: bedrockModels, deepseek: deepSeekModels, @@ -39,6 +41,7 @@ export const MODELS_BY_PROVIDER: Partial void +} + +export const Abliteration = ({ apiConfiguration, setApiConfigurationField }: AbliterationProps) => { + 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?.abliterationApiKey && ( + + {t("settings:providers.getAbliterationApiKey")} + + )} + + ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index 4a64ce9586b..fab34cc2438 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -1,3 +1,4 @@ +export { Abliteration } from "./Abliteration" export { Anthropic } from "./Anthropic" export { Bedrock } from "./Bedrock" export { DeepSeek } from "./DeepSeek" diff --git a/webview-ui/src/components/settings/utils/providerModelConfig.ts b/webview-ui/src/components/settings/utils/providerModelConfig.ts index 59f76862b45..52e0bd383b6 100644 --- a/webview-ui/src/components/settings/utils/providerModelConfig.ts +++ b/webview-ui/src/components/settings/utils/providerModelConfig.ts @@ -1,5 +1,6 @@ import type { ProviderName, ModelInfo, ProviderSettings } from "@roo-code/types" import { + abliterationDefaultModelId, anthropicDefaultModelId, bedrockDefaultModelId, deepSeekDefaultModelId, @@ -26,6 +27,7 @@ export interface ProviderServiceConfig { } export const PROVIDER_SERVICE_CONFIG: Partial> = { + abliteration: { serviceName: "abliteration.ai", serviceUrl: "https://abliteration.ai" }, anthropic: { serviceName: "Anthropic", serviceUrl: "https://console.anthropic.com" }, bedrock: { serviceName: "Amazon Bedrock", serviceUrl: "https://aws.amazon.com/bedrock" }, deepseek: { serviceName: "DeepSeek", serviceUrl: "https://platform.deepseek.com" }, @@ -50,6 +52,7 @@ export const PROVIDER_SERVICE_CONFIG: Partial> = { + abliteration: abliterationDefaultModelId, anthropic: anthropicDefaultModelId, bedrock: bedrockDefaultModelId, deepseek: deepSeekDefaultModelId, diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index 7192d9d4ee4..b21b40f1b73 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -4,6 +4,7 @@ import { type ModelInfo, type ModelRecord, type RouterModels, + abliterationModels, anthropicModels, bedrockModels, deepSeekModels, @@ -174,6 +175,11 @@ function getSelectedModel({ const info = xaiModels[id as keyof typeof xaiModels] return info ? { id, info } : { id, info: undefined } } + case "abliteration": { + const id = apiConfiguration.apiModelId ?? defaultModelId + const info = abliterationModels[id as keyof typeof abliterationModels] + return { id, info } + } case "baseten": { const id = apiConfiguration.apiModelId ?? defaultModelId const info = basetenModels[id as keyof typeof basetenModels] diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 9d4be59b285..442c77ffb95 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "URL base de Poe", "fireworksApiKey": "Clau API de Fireworks", "getFireworksApiKey": "Obtenir clau API de Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Clau API de DeepSeek", "getDeepSeekApiKey": "Obtenir clau API de DeepSeek", "moonshotApiKey": "Clau API de Moonshot", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 6cb1ebc3773..26b68de92f1 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe Basis-URL", "fireworksApiKey": "Fireworks API-Schlüssel", "getFireworksApiKey": "Fireworks API-Schlüssel erhalten", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "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 8ec42367f14..fc355bde2d8 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -445,6 +445,8 @@ "poeBaseUrl": "Poe Base URL", "fireworksApiKey": "Fireworks API Key", "getFireworksApiKey": "Get Fireworks API Key", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API Key", "getDeepSeekApiKey": "Get DeepSeek API Key", "moonshotApiKey": "Moonshot API Key", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index a26b789de4f..77c95e63c72 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "URL base de Poe", "fireworksApiKey": "Clave API de Fireworks", "getFireworksApiKey": "Obtener clave API de Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Clave API de DeepSeek", "getDeepSeekApiKey": "Obtener clave API de DeepSeek", "moonshotApiKey": "Clave API de Moonshot", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index b8e4da391fe..19a41bec176 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "URL de base Poe", "fireworksApiKey": "Clé API Fireworks", "getFireworksApiKey": "Obtenir la clé API Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Clé API DeepSeek", "getDeepSeekApiKey": "Obtenir la clé API DeepSeek", "moonshotApiKey": "Clé API Moonshot", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index 6c602e6441a..68768b912ff 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe बेस URL", "fireworksApiKey": "Fireworks API कुंजी", "getFireworksApiKey": "Fireworks API कुंजी प्राप्त करें", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API कुंजी", "getDeepSeekApiKey": "DeepSeek API कुंजी प्राप्त करें", "moonshotApiKey": "Moonshot API कुंजी", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index bc12a0da481..5f348289d14 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe Base URL", "fireworksApiKey": "Fireworks API Key", "getFireworksApiKey": "Dapatkan Fireworks API Key", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API Key", "getDeepSeekApiKey": "Dapatkan DeepSeek API Key", "moonshotApiKey": "Kunci API Moonshot", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 877032cda90..9c84ce90e91 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "URL base Poe", "fireworksApiKey": "Chiave API Fireworks", "getFireworksApiKey": "Ottieni chiave API Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Chiave API DeepSeek", "getDeepSeekApiKey": "Ottieni chiave API DeepSeek", "moonshotApiKey": "Chiave API Moonshot", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index 7f31d349393..6f5af17f03c 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe ベースURL", "fireworksApiKey": "Fireworks APIキー", "getFireworksApiKey": "Fireworks APIキーを取得", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek APIキー", "getDeepSeekApiKey": "DeepSeek APIキーを取得", "moonshotApiKey": "Moonshot APIキー", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 707719609c4..a802e301a19 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe 기본 URL", "fireworksApiKey": "Fireworks API 키", "getFireworksApiKey": "Fireworks API 키 받기", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API 키", "getDeepSeekApiKey": "DeepSeek API 키 받기", "moonshotApiKey": "Moonshot API 키", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index e54277ade4e..a510ac4be22 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe Basis-URL", "fireworksApiKey": "Fireworks API-sleutel", "getFireworksApiKey": "Fireworks API-sleutel ophalen", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API-sleutel", "getDeepSeekApiKey": "DeepSeek API-sleutel ophalen", "moonshotApiKey": "Moonshot API-sleutel", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 92d2604acb7..929283ae5f6 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Bazowy URL Poe", "fireworksApiKey": "Klucz API Fireworks", "getFireworksApiKey": "Uzyskaj klucz API Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Klucz API DeepSeek", "getDeepSeekApiKey": "Uzyskaj klucz API DeepSeek", "moonshotApiKey": "Klucz API Moonshot", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index cba3599d3cb..b8c165e208a 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "URL base do Poe", "fireworksApiKey": "Chave de API Fireworks", "getFireworksApiKey": "Obter chave de API Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Chave de API DeepSeek", "getDeepSeekApiKey": "Obter chave de API DeepSeek", "moonshotApiKey": "Chave de API Moonshot", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index 524b8a25281..798cd17537e 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Базовый URL Poe", "fireworksApiKey": "Fireworks API-ключ", "getFireworksApiKey": "Получить Fireworks API-ключ", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API-ключ", "getDeepSeekApiKey": "Получить DeepSeek API-ключ", "moonshotApiKey": "Moonshot API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 42ba46f85e1..d22d25feaa4 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe Temel URL", "fireworksApiKey": "Fireworks API Anahtarı", "getFireworksApiKey": "Fireworks API Anahtarı Al", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API Anahtarı", "getDeepSeekApiKey": "DeepSeek API Anahtarı Al", "moonshotApiKey": "Moonshot API Anahtarı", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 11259a45e35..e9d393782cc 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "URL cơ sở Poe", "fireworksApiKey": "Khóa API Fireworks", "getFireworksApiKey": "Lấy khóa API Fireworks", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "Khóa API DeepSeek", "getDeepSeekApiKey": "Lấy khóa API DeepSeek", "moonshotApiKey": "Khóa API Moonshot", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index 80ca437ce77..bc6cb6e769d 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -382,6 +382,8 @@ "poeBaseUrl": "Poe 基础 URL", "fireworksApiKey": "Fireworks API 密钥", "getFireworksApiKey": "获取 Fireworks API 密钥", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API 密钥", "getDeepSeekApiKey": "获取 DeepSeek API 密钥", "moonshotApiKey": "Moonshot API 密钥", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 37c14c8e1bb..ca42e1019f1 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -392,6 +392,8 @@ "poeBaseUrl": "Poe 基礎 URL", "fireworksApiKey": "Fireworks API 金鑰", "getFireworksApiKey": "取得 Fireworks API 金鑰", + "abliterationApiKey": "abliteration.ai API Key", + "getAbliterationApiKey": "Get abliteration.ai API Key", "deepSeekApiKey": "DeepSeek API 金鑰", "getDeepSeekApiKey": "取得 DeepSeek API 金鑰", "moonshotApiKey": "Moonshot API 金鑰", diff --git a/webview-ui/src/utils/validate.ts b/webview-ui/src/utils/validate.ts index f506171acce..899cd1c95d6 100644 --- a/webview-ui/src/utils/validate.ts +++ b/webview-ui/src/utils/validate.ts @@ -38,6 +38,11 @@ export function validateApiConfiguration( function validateModelsAndKeysProvided(apiConfiguration: ProviderSettings): string | undefined { switch (apiConfiguration.apiProvider) { + case "abliteration": + if (!apiConfiguration.abliterationApiKey) { + return i18next.t("settings:validation.apiKey") + } + break case "openrouter": if (!apiConfiguration.openRouterApiKey) { return i18next.t("settings:validation.apiKey")