diff --git a/packages/types/src/providers/openai.ts b/packages/types/src/providers/openai.ts index 5f114e41f6..b090509bc2 100644 --- a/packages/types/src/providers/openai.ts +++ b/packages/types/src/providers/openai.ts @@ -705,3 +705,34 @@ export const azureOpenAiDefaultApiVersion = "2024-08-01-preview" export const OPENAI_NATIVE_DEFAULT_TEMPERATURE = 0 export const OPENAI_AZURE_AI_INFERENCE_PATH = "/models/chat/completions" + +/** + * Returns true when the base URL belongs to Azure AI Inference. + * These endpoints use the regular OpenAI client and expect a model identifier, + * even when the Azure compatibility flag is enabled. + */ +export function isAzureAiInferenceBaseUrl(baseUrl?: string): boolean { + try { + const host = new URL(baseUrl ?? "").host + return host.endsWith(".services.ai.azure.com") + } catch { + return false + } +} + +/** + * Returns true when the base URL and/or flag indicate an Azure OpenAI endpoint. + * Azure AI Inference endpoints (*.services.ai.azure.com) return false — the + * backend routes those through the plain OpenAI client, not AzureOpenAI. + */ +export function isAzureOpenAiBaseUrl(baseUrl?: string, useAzure?: boolean): boolean { + if (isAzureAiInferenceBaseUrl(baseUrl)) return false + if (useAzure) return true + + try { + const host = new URL(baseUrl ?? "").host + return host === "azure.com" || host.endsWith(".azure.com") + } catch { + return false + } +} diff --git a/src/api/providers/__tests__/openai.spec.ts b/src/api/providers/__tests__/openai.spec.ts index e8146a999a..38550533a5 100644 --- a/src/api/providers/__tests__/openai.spec.ts +++ b/src/api/providers/__tests__/openai.spec.ts @@ -3,8 +3,12 @@ import { OpenAiHandler, getOpenAiModels } from "../openai" import { ApiHandlerOptions } from "../../../shared/api" import { Anthropic } from "@anthropic-ai/sdk" -import OpenAI from "openai" -import { openAiModelInfoSaneDefaults, DEEP_SEEK_DEFAULT_TEMPERATURE } from "@roo-code/types" +import OpenAI, { AzureOpenAI } from "openai" +import { + openAiModelInfoSaneDefaults, + DEEP_SEEK_DEFAULT_TEMPERATURE, + azureOpenAiDefaultApiVersion, +} from "@roo-code/types" import { Package } from "../../../shared/package" import { makeApiHandlerOptions } from "../../../test-utils/api" import { asyncStreamFrom, collectStream } from "../../../test-utils/stream" @@ -20,6 +24,7 @@ const mockCreate = vitest.fn() vitest.mock("openai", () => { const mockConstructor = vitest.fn() + const mockAzureConstructor = vitest.fn() return { __esModule: true, default: mockConstructor.mockImplementation(function () { @@ -74,6 +79,7 @@ vitest.mock("openai", () => { }, } }), + AzureOpenAI: mockAzureConstructor, } }) @@ -126,6 +132,43 @@ describe("OpenAiHandler", () => { timeout: MOCK_TIMEOUT_MS, }) }) + + it.each([ + ["https://resource.openai.azure.com", "https://resource.openai.azure.com/openai"], + ["https://resource.openai.azure.com/", "https://resource.openai.azure.com/openai"], + ["https://resource.openai.azure.com/openai", "https://resource.openai.azure.com/openai"], + ["https://resource.openai.azure.com/openai/", "https://resource.openai.azure.com/openai"], + ])("normalizes Azure OpenAI base URL %s", (openAiBaseUrl, expectedBaseUrl) => { + new OpenAiHandler({ ...mockOptions, openAiBaseUrl }) + + expect(vi.mocked(AzureOpenAI)).toHaveBeenLastCalledWith( + expect.objectContaining({ + baseURL: expectedBaseUrl, + apiKey: mockOptions.openAiApiKey, + apiVersion: azureOpenAiDefaultApiVersion, + defaultHeaders: expect.any(Object), + timeout: MOCK_TIMEOUT_MS, + }), + ) + }) + + it("normalizes reverse-proxy URLs when Azure mode is enabled", () => { + new OpenAiHandler({ + ...mockOptions, + openAiBaseUrl: "https://models.example.com/azure/", + openAiUseAzure: true, + }) + + expect(vi.mocked(AzureOpenAI)).toHaveBeenLastCalledWith( + expect.objectContaining({ + baseURL: "https://models.example.com/azure/openai", + apiKey: mockOptions.openAiApiKey, + apiVersion: azureOpenAiDefaultApiVersion, + defaultHeaders: expect.any(Object), + timeout: MOCK_TIMEOUT_MS, + }), + ) + }) }) describe("createMessage", () => { @@ -854,6 +897,16 @@ describe("OpenAiHandler", () => { expect(azureHandler.getModel().id).toBe(azureOptions.openAiModelId) }) + it("should keep Azure AI Inference precedence when Azure mode is enabled", () => { + vi.mocked(OpenAI).mockClear() + vi.mocked(AzureOpenAI).mockClear() + + new OpenAiHandler({ ...azureOptions, openAiUseAzure: true }) + + expect(vi.mocked(OpenAI)).toHaveBeenCalled() + expect(vi.mocked(AzureOpenAI)).not.toHaveBeenCalled() + }) + it("should handle streaming responses with Azure AI Inference Service", async () => { const azureHandler = new OpenAiHandler(azureOptions) const systemPrompt = "You are a helpful assistant." diff --git a/src/api/providers/openai.ts b/src/api/providers/openai.ts index 9545068794..5b4476fdef 100644 --- a/src/api/providers/openai.ts +++ b/src/api/providers/openai.ts @@ -5,6 +5,8 @@ import axios from "axios" import { type ModelInfo, azureOpenAiDefaultApiVersion, + isAzureAiInferenceBaseUrl, + isAzureOpenAiBaseUrl, openAiModelInfoSaneDefaults, DEEP_SEEK_DEFAULT_TEMPERATURE, OPENAI_AZURE_AI_INFERENCE_PATH, @@ -40,8 +42,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl const baseURL = this.options.openAiBaseUrl || "https://api.openai.com/v1" const apiKey = this.options.openAiApiKey ?? "not-provided" const isAzureAiInference = this._isAzureAiInference(this.options.openAiBaseUrl) - const urlHost = this._getUrlHost(this.options.openAiBaseUrl) - const isAzureOpenAi = urlHost === "azure.com" || urlHost.endsWith(".azure.com") || options.openAiUseAzure + const isAzureOpenAi = isAzureOpenAiBaseUrl(this.options.openAiBaseUrl, options.openAiUseAzure) const headers = { ...DEFAULT_HEADERS, @@ -60,8 +61,9 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl } else if (isAzureOpenAi) { // Azure API shape slightly differs from the core API shape: // https://github.com/openai/openai-node?tab=readme-ov-file#microsoft-azure-openai + const azureBaseURL = `${baseURL.replace(/\/openai\/?$/i, "").replace(/\/$/, "")}/openai` this.client = new AzureOpenAI({ - baseURL, + baseURL: azureBaseURL, apiKey, apiVersion: this.options.azureApiVersion || azureOpenAiDefaultApiVersion, defaultHeaders: headers, @@ -520,8 +522,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl } protected _isAzureAiInference(baseUrl?: string): boolean { - const urlHost = this._getUrlHost(baseUrl) - return urlHost.endsWith(".services.ai.azure.com") + return isAzureAiInferenceBaseUrl(baseUrl) } /** diff --git a/webview-ui/src/components/settings/providers/OpenAICompatible.tsx b/webview-ui/src/components/settings/providers/OpenAICompatible.tsx index 8b11c128c7..f9a021812b 100644 --- a/webview-ui/src/components/settings/providers/OpenAICompatible.tsx +++ b/webview-ui/src/components/settings/providers/OpenAICompatible.tsx @@ -10,6 +10,7 @@ import { type OrganizationAllowList, type ExtensionMessage, azureOpenAiDefaultApiVersion, + isAzureOpenAiBaseUrl, openAiModelInfoSaneDefaults, } from "@roo-code/types" @@ -42,6 +43,7 @@ export const OpenAICompatible = ({ simplifySettings, }: OpenAICompatibleProps) => { const { t } = useAppTranslation() + const isAzureOpenAi = isAzureOpenAiBaseUrl(apiConfiguration?.openAiBaseUrl, apiConfiguration?.openAiUseAzure) const [azureApiVersionSelected, setAzureApiVersionSelected] = useState(!!apiConfiguration?.azureApiVersion) @@ -129,7 +131,11 @@ export const OpenAICompatible = ({ value={apiConfiguration?.openAiBaseUrl || ""} type="url" onInput={handleInputChange("openAiBaseUrl")} - placeholder={t("settings:placeholders.baseUrl")} + placeholder={ + isAzureOpenAi + ? t("settings:providers.azureOpenAiBaseUrlPlaceholder") + : t("settings:placeholders.baseUrl") + } className="w-full"> @@ -147,12 +153,18 @@ export const OpenAICompatible = ({ defaultModelId="gpt-4o" models={openAiModels} modelIdKey="openAiModelId" + label={isAzureOpenAi ? t("settings:providers.azureOpenAiDeploymentName") : undefined} serviceName="OpenAI" serviceUrl="https://platform.openai.com" organizationAllowList={organizationAllowList} errorMessage={modelValidationError} simplifySettings={simplifySettings} /> + {isAzureOpenAi && ( +
+ {t("settings:providers.azureOpenAiDeploymentNameDescription")} +
+ )} ({ })) // Mock other components +const { mockModelPicker } = vi.hoisted(() => ({ mockModelPicker: vi.fn() })) + vi.mock("../../ModelPicker", () => ({ - ModelPicker: () =>
Model Picker
, + ModelPicker: (props: any) => { + mockModelPicker(props) + return
Model Picker
+ }, })) vi.mock("../../R1FormatSetting", () => ({ @@ -144,6 +149,78 @@ describe("OpenAICompatible Component - includeMaxTokens checkbox", () => { }) }) + describe("Azure OpenAI guidance", () => { + it.each([ + { openAiBaseUrl: "https://resource.openai.azure.com/" }, + { openAiBaseUrl: "https://models.example.com", openAiUseAzure: true }, + ])("shows Azure-specific endpoint and deployment guidance", (apiConfiguration) => { + render( + , + ) + + expect(screen.getByPlaceholderText("settings:providers.azureOpenAiBaseUrlPlaceholder")).toBeInTheDocument() + expect(mockModelPicker).toHaveBeenLastCalledWith( + expect.objectContaining({ label: "settings:providers.azureOpenAiDeploymentName" }), + ) + expect(screen.getByText("settings:providers.azureOpenAiDeploymentNameDescription")).toBeInTheDocument() + }) + + it("keeps generic OpenAI-compatible guidance for non-Azure endpoints", () => { + render( + , + ) + + expect(screen.getByPlaceholderText("settings:placeholders.baseUrl")).toBeInTheDocument() + expect(mockModelPicker).toHaveBeenLastCalledWith(expect.objectContaining({ label: undefined })) + expect( + screen.queryByText("settings:providers.azureOpenAiDeploymentNameDescription"), + ).not.toBeInTheDocument() + }) + + it("keeps generic OpenAI-compatible guidance for Azure AI Inference endpoints", () => { + render( + , + ) + + expect(mockModelPicker).toHaveBeenLastCalledWith(expect.objectContaining({ label: undefined })) + expect( + screen.queryByText("settings:providers.azureOpenAiDeploymentNameDescription"), + ).not.toBeInTheDocument() + }) + + it("keeps generic guidance when Azure AI Inference uses the Azure compatibility flag", () => { + render( + , + ) + + expect(screen.getByPlaceholderText("settings:placeholders.baseUrl")).toBeInTheDocument() + expect(mockModelPicker).toHaveBeenLastCalledWith(expect.objectContaining({ label: undefined })) + }) + }) + describe("Initial State", () => { it("should show checkbox as checked when includeMaxTokens is true", () => { const apiConfiguration: Partial = { diff --git a/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.visual.fixture.tsx b/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.visual.fixture.tsx new file mode 100644 index 0000000000..a84a3a056f --- /dev/null +++ b/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.visual.fixture.tsx @@ -0,0 +1,66 @@ +/* v8 ignore file -- Playwright component fixture is covered by the visual test. */ +import React from "react" +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" + +import { type ProviderSettings } from "@roo-code/types" + +import { TranslationContext as AppTranslationContext } from "@/i18n/TranslationContext" +import { TranslationContext as PlaywrightTranslationContext } from "@src/i18n/TranslationContext" +import { TooltipProvider } from "@src/components/ui/tooltip" +import { OpenAICompatible } from "../OpenAICompatible" +import enSettings from "@/i18n/locales/en/settings.json" + +function flattenTranslations(obj: Record, prefix = "settings:"): Record { + const result: Record = {} + for (const [key, value] of Object.entries(obj)) { + const fullKey = `${prefix}${key}` + if (typeof value === "string") { + result[fullKey] = value + } else if (value !== null && typeof value === "object" && !Array.isArray(value)) { + Object.assign(result, flattenTranslations(value as Record, `${fullKey}.`)) + } + } + return result +} + +const translations = flattenTranslations(enSettings as Record) + +const queryClient = new QueryClient({ + defaultOptions: { + queries: { retry: false }, + }, +}) + +const apiConfiguration: ProviderSettings = { + apiProvider: "openai", + openAiBaseUrl: "", + openAiModelId: "my-gpt4o-deployment", + openAiUseAzure: true, +} + +export const OpenAICompatibleAzureFixture = () => ( + translations[key] ?? key, + i18n: null as unknown as typeof import("../../../../i18n/setup").default, + }}> + translations[key] ?? key, + i18n: null as unknown as typeof import("../../../../i18n/setup").default, + }}> + + +
+ {}} + organizationAllowList={{ allowAll: true, providers: {} }} + simplifySettings + /> +
+
+
+
+
+) diff --git a/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.visual.tsx b/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.visual.tsx new file mode 100644 index 0000000000..17a98118bd --- /dev/null +++ b/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.visual.tsx @@ -0,0 +1,34 @@ +import React from "react" + +import { expect, test } from "../../../../../playwright/coverage-fixture" +import { OpenAICompatibleAzureFixture } from "./OpenAICompatible.visual.fixture" + +test("renders Azure OpenAI endpoint and deployment guidance in the VS Code dark theme", async ({ mount, page }) => { + // The full provider bundle leaves a bare Zod reference after CT tree-shaking. + await page.evaluate(() => Object.assign(globalThis, { z: undefined })) + const component = await mount() + + await component.evaluate((element) => { + const { document } = element.ownerDocument.defaultView! + document.documentElement.className = "vscode-dark" + document.body.className = "vscode-dark" + document.body.dataset.vscodeThemeId = "Default Dark Modern" + }) + + await expect + .poll(() => + component.evaluate((element) => { + return getComputedStyle(element.ownerDocument.body) + .getPropertyValue("--vscode-editor-background") + .trim() + }), + ) + .toBe("#1e1e1e") + + await component.evaluate(async () => { + await document.fonts.ready + await new Promise((resolve) => requestAnimationFrame(() => resolve())) + }) + + await expect(component).toHaveScreenshot("openai-compatible-azure-guidance-dark.png") +}) diff --git a/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png new file mode 100644 index 0000000000..11e4289cc7 Binary files /dev/null and b/webview-ui/src/components/settings/providers/__tests__/__screenshots__/openai-compatible-azure-guidance-dark.png differ diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 49331e3707..73827b1ec1 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "Clau API d'OpenAI", "apiKey": "Clau API", "openAiBaseUrl": "URL base", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nom de desplegament d'Azure", + "azureOpenAiDeploymentNameDescription": "Introduïu el nom del desplegament d'Azure AI Studio, no el nom del model subjacent.", "getOpenAiApiKey": "Obtenir clau API d'OpenAI", "mistralApiKey": "Clau API de Mistral", "getMistralApiKey": "Obtenir clau API de Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index 5a8c05551f..8078037525 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "OpenAI API-Schlüssel", "apiKey": "API-Schlüssel", "openAiBaseUrl": "Basis-URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure-Bereitstellungsname", + "azureOpenAiDeploymentNameDescription": "Gib den Bereitstellungsnamen aus Azure AI Studio ein, nicht den Namen des zugrunde liegenden Modells.", "getOpenAiApiKey": "OpenAI API-Schlüssel erhalten", "mistralApiKey": "Mistral API-Schlüssel", "getMistralApiKey": "Mistral / Codestral API-Schlüssel erhalten", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index 2aacc322f0..14a7476a75 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -575,6 +575,9 @@ "openAiApiKey": "OpenAI API Key", "apiKey": "API Key", "openAiBaseUrl": "Base URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure deployment name", + "azureOpenAiDeploymentNameDescription": "Enter the deployment name from Azure AI Studio, not the underlying model name.", "getOpenAiApiKey": "Get OpenAI API Key", "mistralApiKey": "Mistral API Key", "getMistralApiKey": "Get Mistral / Codestral API Key", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 3f99fc1b14..e629e43b50 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "Clave API de OpenAI", "apiKey": "Clave API", "openAiBaseUrl": "URL base", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nombre de implementación de Azure", + "azureOpenAiDeploymentNameDescription": "Introduce el nombre de la implementación de Azure AI Studio, no el nombre del modelo subyacente.", "getOpenAiApiKey": "Obtener clave API de OpenAI", "mistralApiKey": "Clave API de Mistral", "getMistralApiKey": "Obtener clave API de Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index ac0e6afb22..6048e2274c 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "Clé API OpenAI", "apiKey": "Clé API", "openAiBaseUrl": "URL de base", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nom du déploiement Azure", + "azureOpenAiDeploymentNameDescription": "Saisissez le nom du déploiement défini dans Azure AI Studio, et non le nom du modèle sous-jacent.", "getOpenAiApiKey": "Obtenir la clé API OpenAI", "mistralApiKey": "Clé API Mistral", "getMistralApiKey": "Obtenir la clé API Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index b720a5db83..28d0b8699b 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "OpenAI API कुंजी", "apiKey": "API कुंजी", "openAiBaseUrl": "बेस URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure परिनियोजन नाम", + "azureOpenAiDeploymentNameDescription": "अंतर्निहित मॉडल नाम के बजाय Azure AI Studio में दिया गया परिनियोजन नाम दर्ज करें।", "getOpenAiApiKey": "OpenAI API कुंजी प्राप्त करें", "mistralApiKey": "Mistral API कुंजी", "getMistralApiKey": "Mistral / Codestral API कुंजी प्राप्त करें", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index c46cc5acf1..bf049395c4 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "OpenAI API Key", "apiKey": "API Key", "openAiBaseUrl": "Base URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nama deployment Azure", + "azureOpenAiDeploymentNameDescription": "Masukkan nama deployment dari Azure AI Studio, bukan nama model dasarnya.", "getOpenAiApiKey": "Dapatkan OpenAI API Key", "mistralApiKey": "Mistral API Key", "getMistralApiKey": "Dapatkan Mistral / Codestral API Key", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index ff00dacca7..577a74a77a 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "Chiave API OpenAI", "apiKey": "Chiave API", "openAiBaseUrl": "URL base", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nome della distribuzione Azure", + "azureOpenAiDeploymentNameDescription": "Inserisci il nome della distribuzione configurato in Azure AI Studio, non il nome del modello sottostante.", "getOpenAiApiKey": "Ottieni chiave API OpenAI", "mistralApiKey": "Chiave API Mistral", "getMistralApiKey": "Ottieni chiave API Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index cdcb377cc9..1113ac32a6 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "OpenAI APIキー", "apiKey": "APIキー", "openAiBaseUrl": "ベースURL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure デプロイ名", + "azureOpenAiDeploymentNameDescription": "基盤モデル名ではなく、Azure AI Studio のデプロイ名を入力してください。", "getOpenAiApiKey": "OpenAI APIキーを取得", "mistralApiKey": "Mistral APIキー", "getMistralApiKey": "Mistral / Codestral APIキーを取得", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index 4a7845ac2a..27e8493bd4 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -495,6 +495,9 @@ "apiKey": "API 키", "openAiApiKey": "OpenAI API 키", "openAiBaseUrl": "기본 URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure 배포 이름", + "azureOpenAiDeploymentNameDescription": "기반 모델 이름이 아닌 Azure AI Studio의 배포 이름을 입력하세요.", "getOpenAiApiKey": "OpenAI API 키 받기", "mistralApiKey": "Mistral API 키", "getMistralApiKey": "Mistral / Codestral API 키 받기", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index 768018c3ef..394cdd48f2 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -495,6 +495,9 @@ "apiKey": "API-sleutel", "openAiApiKey": "OpenAI API-sleutel", "openAiBaseUrl": "Basis-URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Naam van Azure-implementatie", + "azureOpenAiDeploymentNameDescription": "Voer de implementatienaam uit Azure AI Studio in, niet de naam van het onderliggende model.", "getOpenAiApiKey": "OpenAI API-sleutel ophalen", "mistralApiKey": "Mistral API-sleutel", "getMistralApiKey": "Mistral / Codestral API-sleutel ophalen", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 37b37df875..864e4ffde1 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -495,6 +495,9 @@ "apiKey": "Klucz API", "openAiApiKey": "Klucz API OpenAI", "openAiBaseUrl": "URL bazowy", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nazwa wdrożenia Azure", + "azureOpenAiDeploymentNameDescription": "Wprowadź nazwę wdrożenia z Azure AI Studio, a nie nazwę bazowego modelu.", "getOpenAiApiKey": "Uzyskaj klucz API OpenAI", "mistralApiKey": "Klucz API Mistral", "getMistralApiKey": "Uzyskaj klucz API Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index c3b91d6b58..a1948a0218 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -495,6 +495,9 @@ "apiKey": "Chave de API", "openAiApiKey": "Chave de API OpenAI", "openAiBaseUrl": "URL Base", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Nome da implantação do Azure", + "azureOpenAiDeploymentNameDescription": "Insira o nome da implantação configurado no Azure AI Studio, não o nome do modelo subjacente.", "getOpenAiApiKey": "Obter chave de API OpenAI", "mistralApiKey": "Chave de API Mistral", "getMistralApiKey": "Obter chave de API Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index c428b31ec1..f36fe62539 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -495,6 +495,9 @@ "apiKey": "API-ключ", "openAiApiKey": "OpenAI API-ключ", "openAiBaseUrl": "Базовый URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Имя развёртывания Azure", + "azureOpenAiDeploymentNameDescription": "Введите имя развёртывания из Azure AI Studio, а не имя базовой модели.", "getOpenAiApiKey": "Получить OpenAI API-ключ", "mistralApiKey": "Mistral API-ключ", "getMistralApiKey": "Получить Mistral / Codestral API-ключ", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index bccb1c08aa..9099677679 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "OpenAI API Anahtarı", "apiKey": "API Anahtarı", "openAiBaseUrl": "Temel URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure dağıtım adı", + "azureOpenAiDeploymentNameDescription": "Temel model adı yerine Azure AI Studio'daki dağıtım adını girin.", "getOpenAiApiKey": "OpenAI API Anahtarı Al", "mistralApiKey": "Mistral API Anahtarı", "getMistralApiKey": "Mistral / Codestral API Anahtarı Al", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 6b20b9a9a9..c66b236165 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "Khóa API OpenAI", "apiKey": "Khóa API", "openAiBaseUrl": "URL cơ sở", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Tên triển khai Azure", + "azureOpenAiDeploymentNameDescription": "Nhập tên triển khai trong Azure AI Studio, không phải tên mô hình cơ sở.", "getOpenAiApiKey": "Lấy khóa API OpenAI", "mistralApiKey": "Khóa API Mistral", "getMistralApiKey": "Lấy khóa API Mistral / Codestral", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index c206c26108..22742e0e0e 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -495,6 +495,9 @@ "openAiApiKey": "OpenAI API 密钥", "apiKey": "API 密钥", "openAiBaseUrl": "OpenAI 基础 URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure 部署名称", + "azureOpenAiDeploymentNameDescription": "请输入 Azure AI Studio 中的部署名称,而不是底层模型名称。", "getOpenAiApiKey": "获取 OpenAI API 密钥", "mistralApiKey": "Mistral API 密钥", "getMistralApiKey": "获取 Mistral / Codestral API 密钥", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 64eb5e0b29..4255a2e697 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -522,6 +522,9 @@ "openAiApiKey": "OpenAI API 金鑰", "apiKey": "API 金鑰", "openAiBaseUrl": "基礎 URL", + "azureOpenAiBaseUrlPlaceholder": "https://.openai.azure.com/openai", + "azureOpenAiDeploymentName": "Azure 部署名稱", + "azureOpenAiDeploymentNameDescription": "請輸入 Azure AI Studio 中的部署名稱,而不是底層模型名稱。", "getOpenAiApiKey": "取得 OpenAI API 金鑰", "mistralApiKey": "Mistral API 金鑰", "getMistralApiKey": "取得 Mistral/Codestral API 金鑰",