feat(azure): add model metadata, model picker, rename to Azure AI Foundry

- Add static model metadata for 29 Azure models (from models.dev)
  with Roo-specific flags (reasoning, tools, verbosity) matching
  openAiNativeModels
- Add model picker dropdown to Azure provider settings for model
  capability detection (context window, max tokens, pricing)
- Rename provider label from 'Azure OpenAI' to 'Azure AI Foundry'
  across all 18 locales
- Make API key optional (supports Azure managed identity / Entra ID)
- Update default API version from 2024-08-01-preview to 2025-04-01-preview
- Fix maxOutputTokens validation (filter invalid values <= 0)
- Handler separates deployment name (API calls) from model ID
  (capability lookup) with azureDefaultModelInfo (gpt-4o) fallback
- Remove unhelpful 'Get Azure AI Foundry Access' button
- Prevent stale model IDs from other providers carrying over
- Suppress validation errors on fresh provider selection
This commit is contained in:
Hannes Rudolph 2026-02-05 15:29:11 -07:00
parent 7ac28ac712
commit 926c23c127
30 changed files with 501 additions and 69 deletions

View file

@ -637,8 +637,9 @@ export const MODELS_BY_PROVIDER: Record<
},
azure: {
id: "azure",
label: "Azure OpenAI",
models: [], // Azure uses deployment names configured by the user
label: "Azure AI Foundry",
// Azure uses deployment names configured by the user (not a fixed upstream model ID list)
models: [],
},
bedrock: {
id: "bedrock",

View file

@ -0,0 +1,403 @@
import type { ModelInfo } from "../model.js"
/**
* Azure AI Foundry model metadata.
*
* NOTE:
* - Azure AI Foundry uses *deployment names* at runtime, but Roo still needs underlying model
* capabilities (maxTokens/contextWindow/etc.) for validation and parameter shaping.
* - This list is derived from https://models.dev/api.json (provider: "azure") and intentionally
* restricted to OpenAI/Azure OpenAI-style IDs (gpt-*, o*, codex-*).
*/
export const azureModels = {
"codex-mini": {
maxTokens: 100_000,
contextWindow: 200_000,
supportsImages: false,
supportsPromptCache: true,
inputPrice: 1.5,
outputPrice: 6,
cacheReadsPrice: 0.375,
supportsTemperature: false,
description:
"Codex Mini: Cloud-based software engineering agent powered by codex-1, a version of o3 optimized for coding tasks",
},
"gpt-4": {
maxTokens: 8_192,
contextWindow: 8_192,
supportsImages: false,
supportsPromptCache: false,
inputPrice: 60,
outputPrice: 120,
supportsTemperature: true,
description: "GPT-4",
},
"gpt-4-32k": {
maxTokens: 32_768,
contextWindow: 32_768,
supportsImages: false,
supportsPromptCache: false,
inputPrice: 60,
outputPrice: 120,
supportsTemperature: true,
description: "GPT-4 32K",
},
"gpt-4-turbo": {
maxTokens: 4_096,
contextWindow: 128_000,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 10,
outputPrice: 30,
supportsTemperature: true,
description: "GPT-4 Turbo",
},
"gpt-4-turbo-vision": {
maxTokens: 4_096,
contextWindow: 128_000,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 10,
outputPrice: 30,
supportsTemperature: true,
description: "GPT-4 Turbo Vision",
},
"gpt-4.1": {
maxTokens: 32_768,
contextWindow: 1_047_576,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 2,
outputPrice: 8,
cacheReadsPrice: 0.5,
supportsTemperature: true,
description: "GPT-4.1",
},
"gpt-4.1-mini": {
maxTokens: 32_768,
contextWindow: 1_047_576,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 0.4,
outputPrice: 1.6,
cacheReadsPrice: 0.1,
supportsTemperature: true,
description: "GPT-4.1 mini",
},
"gpt-4.1-nano": {
maxTokens: 32_768,
contextWindow: 1_047_576,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 0.1,
outputPrice: 0.4,
cacheReadsPrice: 0.03,
supportsTemperature: true,
description: "GPT-4.1 nano",
},
"gpt-4o": {
maxTokens: 16_384,
contextWindow: 128_000,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 2.5,
outputPrice: 10,
cacheReadsPrice: 1.25,
supportsTemperature: true,
description: "GPT-4o",
},
"gpt-4o-mini": {
maxTokens: 16_384,
contextWindow: 128_000,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 0.15,
outputPrice: 0.6,
cacheReadsPrice: 0.08,
supportsTemperature: true,
description: "GPT-4o mini",
},
"gpt-5": {
maxTokens: 128_000,
contextWindow: 272_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 1.25,
outputPrice: 10,
cacheReadsPrice: 0.13,
supportsVerbosity: true,
supportsTemperature: false,
description: "GPT-5: The best model for coding and agentic tasks across domains",
},
"gpt-5-codex": {
maxTokens: 128_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
supportsReasoningEffort: ["low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 1.25,
outputPrice: 10,
cacheReadsPrice: 0.13,
supportsTemperature: false,
description: "GPT-5-Codex: A version of GPT-5 optimized for agentic coding in Codex",
},
"gpt-5-mini": {
maxTokens: 128_000,
contextWindow: 272_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 0.25,
outputPrice: 2,
cacheReadsPrice: 0.03,
supportsVerbosity: true,
supportsTemperature: false,
description: "GPT-5 Mini: A faster, more cost-efficient version of GPT-5 for well-defined tasks",
},
"gpt-5-nano": {
maxTokens: 128_000,
contextWindow: 272_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 0.05,
outputPrice: 0.4,
cacheReadsPrice: 0.01,
supportsVerbosity: true,
supportsTemperature: false,
description: "GPT-5 Nano: Fastest, most cost-efficient version of GPT-5",
},
"gpt-5-pro": {
maxTokens: 272_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: false,
supportsReasoningEffort: ["minimal", "low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 15,
outputPrice: 120,
supportsVerbosity: true,
supportsTemperature: false,
description: "GPT-5 Pro",
},
"gpt-5.1": {
maxTokens: 128_000,
contextWindow: 272_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
supportsReasoningEffort: ["none", "low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 1.25,
outputPrice: 10,
cacheReadsPrice: 0.125,
supportsVerbosity: true,
supportsTemperature: false,
description: "GPT-5.1: The best model for coding and agentic tasks across domains",
},
"gpt-5.1-chat": {
maxTokens: 16_384,
contextWindow: 128_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
inputPrice: 1.25,
outputPrice: 10,
cacheReadsPrice: 0.125,
supportsTemperature: false,
description: "GPT-5.1 Chat: Optimized for conversational AI and chat use cases",
},
"gpt-5.1-codex": {
maxTokens: 128_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
supportsReasoningEffort: ["low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 1.25,
outputPrice: 10,
cacheReadsPrice: 0.125,
supportsTemperature: false,
description: "GPT-5.1 Codex: A version of GPT-5.1 optimized for agentic coding in Codex",
},
"gpt-5.1-codex-max": {
maxTokens: 128_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
supportsReasoningEffort: ["low", "medium", "high", "xhigh"],
reasoningEffort: "medium",
inputPrice: 1.25,
outputPrice: 10,
cacheReadsPrice: 0.125,
supportsTemperature: false,
description:
"GPT-5.1 Codex Max: Our most intelligent coding model optimized for long-horizon, agentic coding tasks",
},
"gpt-5.1-codex-mini": {
maxTokens: 128_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
supportsReasoningEffort: ["low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 0.25,
outputPrice: 2,
cacheReadsPrice: 0.025,
supportsTemperature: false,
description: "GPT-5.1 Codex mini: A version of GPT-5.1 optimized for agentic coding in Codex",
},
"gpt-5.2": {
maxTokens: 128_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
supportsReasoningEffort: ["none", "low", "medium", "high", "xhigh"],
reasoningEffort: "medium",
inputPrice: 1.75,
outputPrice: 14,
cacheReadsPrice: 0.125,
supportsVerbosity: true,
supportsTemperature: false,
description: "GPT-5.2: Our flagship model for coding and agentic tasks across industries",
},
"gpt-5.2-chat": {
maxTokens: 16_384,
contextWindow: 128_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
inputPrice: 1.75,
outputPrice: 14,
cacheReadsPrice: 0.175,
supportsTemperature: false,
description: "GPT-5.2 Chat: Optimized for conversational AI and chat use cases",
},
"gpt-5.2-codex": {
maxTokens: 128_000,
contextWindow: 400_000,
includedTools: ["apply_patch"],
excludedTools: ["apply_diff", "write_to_file"],
supportsImages: true,
supportsPromptCache: true,
promptCacheRetention: "24h",
supportsReasoningEffort: ["low", "medium", "high", "xhigh"],
reasoningEffort: "medium",
inputPrice: 1.75,
outputPrice: 14,
cacheReadsPrice: 0.175,
supportsTemperature: false,
description:
"GPT-5.2 Codex: Our most intelligent coding model optimized for long-horizon, agentic coding tasks",
},
o1: {
maxTokens: 100_000,
contextWindow: 200_000,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 15,
outputPrice: 60,
cacheReadsPrice: 7.5,
supportsTemperature: false,
description: "o1",
},
"o1-mini": {
maxTokens: 65_536,
contextWindow: 128_000,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 1.1,
outputPrice: 4.4,
cacheReadsPrice: 0.55,
supportsTemperature: false,
description: "o1-mini",
},
"o1-preview": {
maxTokens: 32_768,
contextWindow: 128_000,
supportsImages: true,
supportsPromptCache: true,
inputPrice: 16.5,
outputPrice: 66,
cacheReadsPrice: 8.25,
supportsTemperature: false,
description: "o1-preview",
},
o3: {
maxTokens: 100_000,
contextWindow: 200_000,
supportsImages: true,
supportsPromptCache: true,
supportsReasoningEffort: ["low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 2,
outputPrice: 8,
cacheReadsPrice: 0.5,
supportsTemperature: false,
description: "o3",
},
"o3-mini": {
maxTokens: 100_000,
contextWindow: 200_000,
supportsImages: false,
supportsPromptCache: true,
supportsReasoningEffort: ["low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 1.1,
outputPrice: 4.4,
cacheReadsPrice: 0.55,
supportsTemperature: false,
description: "o3-mini",
},
"o4-mini": {
maxTokens: 100_000,
contextWindow: 200_000,
supportsImages: true,
supportsPromptCache: true,
supportsReasoningEffort: ["low", "medium", "high"],
reasoningEffort: "medium",
inputPrice: 1.1,
outputPrice: 4.4,
cacheReadsPrice: 0.28,
supportsTemperature: false,
description: "o4-mini",
},
} as const satisfies Record<string, ModelInfo>
export type AzureModelId = keyof typeof azureModels
export const azureDefaultModelId: AzureModelId = "gpt-4o"
export const azureDefaultModelInfo: ModelInfo = azureModels[azureDefaultModelId]

View file

@ -1,4 +1,5 @@
export * from "./anthropic.js"
export * from "./azure.js"
export * from "./baseten.js"
export * from "./bedrock.js"
export * from "./cerebras.js"
@ -34,6 +35,7 @@ export * from "./deepinfra.js"
export * from "./minimax.js"
import { anthropicDefaultModelId } from "./anthropic.js"
import { azureDefaultModelId } from "./azure.js"
import { basetenDefaultModelId } from "./baseten.js"
import { bedrockDefaultModelId } from "./bedrock.js"
import { cerebrasDefaultModelId } from "./cerebras.js"
@ -142,6 +144,8 @@ export function getProviderDefaultModelId(
return qwenCodeDefaultModelId
case "vercel-ai-gateway":
return vercelAiGatewayDefaultModelId
case "azure":
return azureDefaultModelId
case "anthropic":
case "gemini-cli":
case "fake-ai":

View file

@ -506,9 +506,8 @@ export const openAiModelInfoSaneDefaults: ModelInfo = {
outputPrice: 0,
}
// https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation
// https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#api-specs
export const azureOpenAiDefaultApiVersion = "2024-08-01-preview"
// https://learn.microsoft.com/en-us/azure/ai-foundry/openai/api-version-lifecycle
export const azureOpenAiDefaultApiVersion = "2025-04-01-preview"
export const OPENAI_NATIVE_DEFAULT_TEMPERATURE = 0

View file

@ -274,7 +274,7 @@ describe("AzureHandler", () => {
for await (const chunk of stream) {
chunks.push(chunk)
}
}).rejects.toThrow("Azure OpenAI")
}).rejects.toThrow("Azure AI Foundry")
})
})

View file

@ -2,7 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
import { createAzure } from "@ai-sdk/azure"
import { streamText, generateText, ToolSet } from "ai"
import { azureOpenAiDefaultApiVersion, openAiModelInfoSaneDefaults, type ModelInfo } from "@roo-code/types"
import { azureOpenAiDefaultApiVersion, azureModels, azureDefaultModelInfo, type ModelInfo } from "@roo-code/types"
import type { ApiHandlerOptions } from "../../shared/api"
@ -23,7 +23,7 @@ import type { SingleCompletionHandler, ApiHandlerCreateMessageMetadata } from ".
const AZURE_DEFAULT_TEMPERATURE = 0
/**
* Azure OpenAI provider using the dedicated @ai-sdk/azure package.
* Azure AI Foundry provider using the dedicated @ai-sdk/azure package.
* Provides native support for Azure OpenAI deployments with proper resource-based routing.
*/
export class AzureHandler extends BaseProvider implements SingleCompletionHandler {
@ -38,25 +38,29 @@ export class AzureHandler extends BaseProvider implements SingleCompletionHandle
// The @ai-sdk/azure package uses resourceName-based routing
this.provider = createAzure({
resourceName: options.azureResourceName ?? "",
apiKey: options.azureApiKey ?? "not-provided",
apiKey: options.azureApiKey, // Optional — Azure supports managed identity / Entra ID auth
apiVersion: options.azureApiVersion ?? azureOpenAiDefaultApiVersion,
headers: DEFAULT_HEADERS,
})
}
override getModel(): { id: string; info: ModelInfo; maxTokens?: number; temperature?: number } {
// Azure uses deployment names as model IDs
// Use azureDeploymentName if provided, otherwise fall back to apiModelId
const id = this.options.azureDeploymentName ?? this.options.apiModelId ?? ""
const info: ModelInfo = openAiModelInfoSaneDefaults
// Azure uses deployment names for API calls, but apiModelId for model capabilities.
// deploymentId is sent to the Azure API; modelId is used for capability lookup.
const deploymentId = this.options.azureDeploymentName ?? this.options.apiModelId ?? ""
const modelId = this.options.apiModelId ?? deploymentId
const info: ModelInfo =
(azureModels as Record<string, ModelInfo>)[modelId] ??
(azureModels as Record<string, ModelInfo>)[deploymentId] ??
azureDefaultModelInfo
const params = getModelParams({
format: "openai",
modelId: id,
modelId: deploymentId, // deployment name for the API
model: info,
settings: this.options,
defaultTemperature: AZURE_DEFAULT_TEMPERATURE,
})
return { id, info, ...params }
return { id: deploymentId, info, ...params }
}
/**
@ -69,7 +73,7 @@ export class AzureHandler extends BaseProvider implements SingleCompletionHandle
/**
* Process usage metrics from the AI SDK response.
* Azure OpenAI provides standard OpenAI-compatible usage metrics.
* Azure AI Foundry provides standard OpenAI-compatible usage metrics.
*/
protected processUsageMetrics(
usage: {
@ -103,10 +107,13 @@ export class AzureHandler extends BaseProvider implements SingleCompletionHandle
/**
* Get the max tokens parameter to include in the request.
* Returns undefined if no valid maxTokens is configured to let the API use its default.
*/
protected getMaxOutputTokens(): number | undefined {
const { info } = this.getModel()
return this.options.modelMaxTokens || info.maxTokens || undefined
const maxTokens = this.options.modelMaxTokens || info.maxTokens
// Azure AI Foundry API requires maxOutputTokens >= 1, so filter out invalid values
return maxTokens && maxTokens > 0 ? maxTokens : undefined
}
/**
@ -157,7 +164,7 @@ export class AzureHandler extends BaseProvider implements SingleCompletionHandle
}
} catch (error) {
// Handle AI SDK errors (AI_RetryError, AI_APICallError, etc.)
throw handleAiSdkError(error, "Azure OpenAI")
throw handleAiSdkError(error, "Azure AI Foundry")
}
}

View file

@ -5,11 +5,17 @@ export function checkExistKey(config: ProviderSettings | undefined) {
return false
}
// Special case for fake-ai, openai-codex, qwen-code, and roo providers which don't need any configuration.
// Special case for providers which don't need standard API key configuration.
if (config.apiProvider && ["fake-ai", "openai-codex", "qwen-code", "roo"].includes(config.apiProvider)) {
return true
}
// Azure supports managed identity / Entra ID auth (no API key needed).
// Consider it configured if resource name or deployment name is set.
if (config.apiProvider === "azure") {
return !!(config.azureResourceName || config.azureDeploymentName || config.azureApiKey)
}
// Check all secret keys from the centralized SECRET_STATE_KEYS array.
// Filter out keys that are not part of ProviderSettings (global secrets are stored separately)
const providerSecretKeys = SECRET_STATE_KEYS.filter((key) => !GLOBAL_SECRET_KEYS.includes(key as any))

View file

@ -2,6 +2,7 @@ import {
type ProviderName,
type ModelInfo,
anthropicModels,
azureModels,
bedrockModels,
cerebrasModels,
deepSeekModels,
@ -25,6 +26,7 @@ import {
export const MODELS_BY_PROVIDER: Partial<Record<ProviderName, Record<string, ModelInfo>>> = {
anthropic: anthropicModels,
azure: azureModels,
bedrock: bedrockModels,
cerebras: cerebrasModels,
deepseek: deepSeekModels,
@ -50,7 +52,7 @@ export const PROVIDERS = [
{ value: "openrouter", label: "OpenRouter", proxy: false },
{ value: "deepinfra", label: "DeepInfra", proxy: false },
{ value: "anthropic", label: "Anthropic", proxy: false },
{ value: "azure", label: "Azure OpenAI", proxy: false },
{ value: "azure", label: "Azure AI Foundry", proxy: false },
{ value: "cerebras", label: "Cerebras", proxy: false },
{ value: "gemini", label: "Google Gemini", proxy: false },
{ value: "doubao", label: "Doubao", proxy: false },

View file

@ -4,7 +4,6 @@ import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import { type ProviderSettings, azureOpenAiDefaultApiVersion } from "@roo-code/types"
import { useAppTranslation } from "@src/i18n/TranslationContext"
import { VSCodeButtonLink } from "@src/components/common/VSCodeButtonLink"
import { inputEventTransform } from "../transforms"
@ -71,13 +70,6 @@ export const Azure = ({ apiConfiguration, setApiConfigurationField }: AzureProps
<div className="text-sm text-vscode-descriptionForeground -mt-2">
{t("settings:providers.azureApiVersionDescription")}
</div>
{!apiConfiguration?.azureApiKey && (
<VSCodeButtonLink
href="https://azure.microsoft.com/en-us/products/ai-services/openai-service"
appearance="secondary">
{t("settings:providers.getAzureApiKey")}
</VSCodeButtonLink>
)}
</>
)
}

View file

@ -1,6 +1,7 @@
import type { ProviderName, ModelInfo, ProviderSettings } from "@roo-code/types"
import {
anthropicDefaultModelId,
azureDefaultModelId,
bedrockDefaultModelId,
cerebrasDefaultModelId,
deepSeekDefaultModelId,
@ -31,6 +32,10 @@ export interface ProviderServiceConfig {
export const PROVIDER_SERVICE_CONFIG: Partial<Record<ProviderName, ProviderServiceConfig>> = {
anthropic: { serviceName: "Anthropic", serviceUrl: "https://console.anthropic.com" },
azure: {
serviceName: "Azure AI Foundry",
serviceUrl: "https://azure.microsoft.com/en-us/products/ai-foundry/models/openai",
},
bedrock: { serviceName: "Amazon Bedrock", serviceUrl: "https://aws.amazon.com/bedrock" },
cerebras: { serviceName: "Cerebras", serviceUrl: "https://cerebras.ai" },
deepseek: { serviceName: "DeepSeek", serviceUrl: "https://platform.deepseek.com" },
@ -59,6 +64,7 @@ export const PROVIDER_SERVICE_CONFIG: Partial<Record<ProviderName, ProviderServi
export const PROVIDER_DEFAULT_MODEL_IDS: Partial<Record<ProviderName, string>> = {
anthropic: anthropicDefaultModelId,
azure: azureDefaultModelId,
bedrock: bedrockDefaultModelId,
cerebras: cerebrasDefaultModelId,
deepseek: deepSeekDefaultModelId,

View file

@ -28,6 +28,7 @@ import {
featherlessModels,
ioIntelligenceModels,
basetenModels,
azureModels,
qwenCodeModels,
litellmDefaultModelInfo,
lMStudioDefaultModelInfo,
@ -388,9 +389,14 @@ function getSelectedModel({
return { id, info }
}
case "azure": {
// Azure uses deployment names configured by the user
const id = apiConfiguration.azureDeploymentName ?? apiConfiguration.apiModelId ?? ""
return { id, info: undefined }
// apiModelId holds the base model selection (from model picker).
// azureDeploymentName is the deployment name sent to the Azure API.
// Only use apiModelId if it matches a known Azure model (prevents stale values from other providers).
const explicitModelId = apiConfiguration.apiModelId
const matchesAzureModel = explicitModelId && azureModels[explicitModelId as keyof typeof azureModels]
const id = matchesAzureModel ? explicitModelId : defaultModelId
const info = azureModels[id as keyof typeof azureModels]
return { id, info: info || undefined }
}
// case "anthropic":
// case "fake-ai":

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Clau API de Cerebras",
"getCerebrasApiKey": "Obtenir clau API de Cerebras",
"azureResourceName": "Nom del recurs d'Azure",
"azureResourceNameDescription": "El nom del teu recurs Azure OpenAI (p. ex. 'el-meu-recurs-openai').",
"azureResourceNameDescription": "El nom del teu recurs Azure AI Foundry (p. ex. 'el-meu-recurs-openai').",
"azureDeploymentName": "Nom del desplegament d'Azure",
"azureDeploymentNameDescription": "El nom del desplegament del model dins del recurs.",
"azureApiKey": "Clau API d'Azure",
"getAzureApiKey": "Obtenir accés a Azure OpenAI",
"getAzureApiKey": "Obtenir accés a Azure AI Foundry",
"azureApiVersion": "Versió de l'API d'Azure",
"azureApiVersionDescription": "La versió de l'API a utilitzar (p. ex. '2024-10-21'). Deixa buit per al valor per defecte.",
"chutesApiKey": "Clau API de Chutes",

View file

@ -382,11 +382,11 @@
"cerebrasApiKey": "Cerebras API-Schlüssel",
"getCerebrasApiKey": "Cerebras API-Schlüssel erhalten",
"azureResourceName": "Azure Ressourcenname",
"azureResourceNameDescription": "Der Name Ihrer Azure OpenAI-Ressource (z.B. 'meine-openai-ressource').",
"azureResourceNameDescription": "Der Name Ihrer Azure AI Foundry-Ressource (z.B. 'meine-openai-ressource').",
"azureDeploymentName": "Azure Bereitstellungsname",
"azureDeploymentNameDescription": "Der Name Ihrer Modellbereitstellung innerhalb der Ressource.",
"azureApiKey": "Azure API-Schlüssel",
"getAzureApiKey": "Azure OpenAI-Zugang erhalten",
"getAzureApiKey": "Azure AI Foundry-Zugang erhalten",
"azureApiVersion": "Azure API-Version",
"azureApiVersionDescription": "Die zu verwendende API-Version (z.B. '2024-10-21'). Leer lassen für Standardwert.",
"chutesApiKey": "Chutes API-Schlüssel",

View file

@ -443,11 +443,11 @@
"cerebrasApiKey": "Cerebras API Key",
"getCerebrasApiKey": "Get Cerebras API Key",
"azureResourceName": "Azure Resource Name",
"azureResourceNameDescription": "The name of your Azure OpenAI resource (e.g., 'my-openai-resource').",
"azureResourceNameDescription": "The name of your Azure AI Foundry resource (e.g., 'my-openai-resource').",
"azureDeploymentName": "Azure Deployment Name",
"azureDeploymentNameDescription": "The name of your model deployment within the resource.",
"azureApiKey": "Azure API Key",
"getAzureApiKey": "Get Azure OpenAI Access",
"getAzureApiKey": "Get Azure AI Foundry Access",
"azureApiVersion": "Azure API Version",
"azureApiVersionDescription": "The API version to use (e.g., '2024-10-21'). Leave empty for the default.",
"chutesApiKey": "Chutes API Key",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Clave API de Cerebras",
"getCerebrasApiKey": "Obtener clave API de Cerebras",
"azureResourceName": "Nombre del recurso Azure",
"azureResourceNameDescription": "El nombre de tu recurso Azure OpenAI (ej. 'mi-recurso-openai').",
"azureResourceNameDescription": "El nombre de tu recurso Azure AI Foundry (ej. 'mi-recurso-openai').",
"azureDeploymentName": "Nombre del despliegue Azure",
"azureDeploymentNameDescription": "El nombre del despliegue de tu modelo dentro del recurso.",
"azureApiKey": "Clave API de Azure",
"getAzureApiKey": "Obtener acceso a Azure OpenAI",
"getAzureApiKey": "Obtener acceso a Azure AI Foundry",
"azureApiVersion": "Versión de API de Azure",
"azureApiVersionDescription": "La versión de la API a usar (ej. '2024-10-21'). Dejar vacío para usar el valor predeterminado.",
"chutesApiKey": "Clave API de Chutes",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Clé API Cerebras",
"getCerebrasApiKey": "Obtenir la clé API Cerebras",
"azureResourceName": "Nom de la ressource Azure",
"azureResourceNameDescription": "Le nom de votre ressource Azure OpenAI (ex. 'ma-ressource-openai').",
"azureResourceNameDescription": "Le nom de votre ressource Azure AI Foundry (ex. 'ma-ressource-openai').",
"azureDeploymentName": "Nom du déploiement Azure",
"azureDeploymentNameDescription": "Le nom du déploiement de votre modèle dans la ressource.",
"azureApiKey": "Clé API Azure",
"getAzureApiKey": "Obtenir l'accès Azure OpenAI",
"getAzureApiKey": "Obtenir l'accès Azure AI Foundry",
"azureApiVersion": "Version de l'API Azure",
"azureApiVersionDescription": "La version de l'API à utiliser (ex. '2024-10-21'). Laisser vide pour la valeur par défaut.",
"chutesApiKey": "Clé API Chutes",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API कुंजी",
"getCerebrasApiKey": "Cerebras API कुंजी प्राप्त करें",
"azureResourceName": "Azure रिसोर्स नाम",
"azureResourceNameDescription": "आपके Azure OpenAI रिसोर्स का नाम (उदा. 'my-openai-resource')।",
"azureResourceNameDescription": "आपके Azure AI Foundry रिसोर्स का नाम (उदा. 'my-openai-resource')।",
"azureDeploymentName": "Azure डिप्लॉयमेंट नाम",
"azureDeploymentNameDescription": "रिसोर्स के अंदर आपके मॉडल डिप्लॉयमेंट का नाम।",
"azureApiKey": "Azure API कुंजी",
"getAzureApiKey": "Azure OpenAI एक्सेस प्राप्त करें",
"getAzureApiKey": "Azure AI Foundry एक्सेस प्राप्त करें",
"azureApiVersion": "Azure API संस्करण",
"azureApiVersionDescription": "उपयोग करने के लिए API संस्करण (उदा. '2024-10-21')। डिफ़ॉल्ट के लिए खाली छोड़ें।",
"chutesApiKey": "Chutes API कुंजी",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API Key",
"getCerebrasApiKey": "Dapatkan Cerebras API Key",
"azureResourceName": "Nama Resource Azure",
"azureResourceNameDescription": "Nama resource Azure OpenAI Anda (contoh: 'my-openai-resource').",
"azureResourceNameDescription": "Nama resource Azure AI Foundry Anda (contoh: 'my-openai-resource').",
"azureDeploymentName": "Nama Deployment Azure",
"azureDeploymentNameDescription": "Nama deployment model dalam resource.",
"azureApiKey": "Azure API Key",
"getAzureApiKey": "Dapatkan Akses Azure OpenAI",
"getAzureApiKey": "Dapatkan Akses Azure AI Foundry",
"azureApiVersion": "Versi API Azure",
"azureApiVersionDescription": "Versi API yang akan digunakan (contoh: '2024-10-21'). Biarkan kosong untuk nilai default.",
"chutesApiKey": "Chutes API Key",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Chiave API Cerebras",
"getCerebrasApiKey": "Ottieni chiave API Cerebras",
"azureResourceName": "Nome risorsa Azure",
"azureResourceNameDescription": "Il nome della tua risorsa Azure OpenAI (es. 'mia-risorsa-openai').",
"azureResourceNameDescription": "Il nome della tua risorsa Azure AI Foundry (es. 'mia-risorsa-openai').",
"azureDeploymentName": "Nome distribuzione Azure",
"azureDeploymentNameDescription": "Il nome della distribuzione del modello all'interno della risorsa.",
"azureApiKey": "Chiave API Azure",
"getAzureApiKey": "Ottieni accesso Azure OpenAI",
"getAzureApiKey": "Ottieni accesso Azure AI Foundry",
"azureApiVersion": "Versione API Azure",
"azureApiVersionDescription": "La versione dell'API da utilizzare (es. '2024-10-21'). Lascia vuoto per il valore predefinito.",
"chutesApiKey": "Chiave API Chutes",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras APIキー",
"getCerebrasApiKey": "Cerebras APIキーを取得",
"azureResourceName": "Azureリソース名",
"azureResourceNameDescription": "Azure OpenAIリソースの名前(例:'my-openai-resource')。",
"azureResourceNameDescription": "Azure AI Foundryリソースの名前(例:'my-openai-resource')。",
"azureDeploymentName": "Azureデプロイメント名",
"azureDeploymentNameDescription": "リソース内のモデルデプロイメントの名前。",
"azureApiKey": "Azure APIキー",
"getAzureApiKey": "Azure OpenAIアクセスを取得",
"getAzureApiKey": "Azure AI Foundryアクセスを取得",
"azureApiVersion": "Azure APIバージョン",
"azureApiVersionDescription": "使用するAPIバージョン(例:'2024-10-21')。デフォルトを使用する場合は空にしてください。",
"chutesApiKey": "Chutes APIキー",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API 키",
"getCerebrasApiKey": "Cerebras API 키 가져오기",
"azureResourceName": "Azure 리소스 이름",
"azureResourceNameDescription": "Azure OpenAI 리소스 이름 (예: 'my-openai-resource').",
"azureResourceNameDescription": "Azure AI Foundry 리소스 이름 (예: 'my-openai-resource').",
"azureDeploymentName": "Azure 배포 이름",
"azureDeploymentNameDescription": "리소스 내 모델 배포 이름.",
"azureApiKey": "Azure API 키",
"getAzureApiKey": "Azure OpenAI 액세스 받기",
"getAzureApiKey": "Azure AI Foundry 액세스 받기",
"azureApiVersion": "Azure API 버전",
"azureApiVersionDescription": "사용할 API 버전 (예: '2024-10-21'). 기본값을 사용하려면 비워두세요.",
"chutesApiKey": "Chutes API 키",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API-sleutel",
"getCerebrasApiKey": "Cerebras API-sleutel verkrijgen",
"azureResourceName": "Azure Resource-naam",
"azureResourceNameDescription": "De naam van je Azure OpenAI resource (bijv. 'mijn-openai-resource').",
"azureResourceNameDescription": "De naam van je Azure AI Foundry resource (bijv. 'mijn-openai-resource').",
"azureDeploymentName": "Azure Deployment-naam",
"azureDeploymentNameDescription": "De naam van je model deployment binnen de resource.",
"azureApiKey": "Azure API-sleutel",
"getAzureApiKey": "Azure OpenAI-toegang verkrijgen",
"getAzureApiKey": "Azure AI Foundry-toegang verkrijgen",
"azureApiVersion": "Azure API-versie",
"azureApiVersionDescription": "De API-versie om te gebruiken (bijv. '2024-10-21'). Laat leeg voor standaardwaarde.",
"chutesApiKey": "Chutes API-sleutel",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Klucz API Cerebras",
"getCerebrasApiKey": "Pobierz klucz API Cerebras",
"azureResourceName": "Nazwa zasobu Azure",
"azureResourceNameDescription": "Nazwa Twojego zasobu Azure OpenAI (np. 'moj-zasob-openai').",
"azureResourceNameDescription": "Nazwa Twojego zasobu Azure AI Foundry (np. 'moj-zasob-openai').",
"azureDeploymentName": "Nazwa wdrożenia Azure",
"azureDeploymentNameDescription": "Nazwa wdrożenia modelu w zasobie.",
"azureApiKey": "Klucz API Azure",
"getAzureApiKey": "Uzyskaj dostęp do Azure OpenAI",
"getAzureApiKey": "Uzyskaj dostęp do Azure AI Foundry",
"azureApiVersion": "Wersja API Azure",
"azureApiVersionDescription": "Wersja API do użycia (np. '2024-10-21'). Pozostaw puste dla wartości domyślnej.",
"chutesApiKey": "Klucz API Chutes",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Chave de API Cerebras",
"getCerebrasApiKey": "Obter chave de API Cerebras",
"azureResourceName": "Nome do recurso Azure",
"azureResourceNameDescription": "O nome do seu recurso Azure OpenAI (ex: 'meu-recurso-openai').",
"azureResourceNameDescription": "O nome do seu recurso Azure AI Foundry (ex: 'meu-recurso-openai').",
"azureDeploymentName": "Nome da implantação Azure",
"azureDeploymentNameDescription": "O nome da implantação do modelo dentro do recurso.",
"azureApiKey": "Chave de API Azure",
"getAzureApiKey": "Obter acesso ao Azure OpenAI",
"getAzureApiKey": "Obter acesso ao Azure AI Foundry",
"azureApiVersion": "Versão da API Azure",
"azureApiVersionDescription": "A versão da API a ser usada (ex: '2024-10-21'). Deixe vazio para o padrão.",
"chutesApiKey": "Chave de API Chutes",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API-ключ",
"getCerebrasApiKey": "Получить Cerebras API-ключ",
"azureResourceName": "Имя ресурса Azure",
"azureResourceNameDescription": "Имя вашего ресурса Azure OpenAI (напр. 'my-openai-resource').",
"azureResourceNameDescription": "Имя вашего ресурса Azure AI Foundry (напр. 'my-openai-resource').",
"azureDeploymentName": "Имя развертывания Azure",
"azureDeploymentNameDescription": "Имя развертывания модели внутри ресурса.",
"azureApiKey": "API-ключ Azure",
"getAzureApiKey": "Получить доступ к Azure OpenAI",
"getAzureApiKey": "Получить доступ к Azure AI Foundry",
"azureApiVersion": "Версия API Azure",
"azureApiVersionDescription": "Версия API для использования (напр. '2024-10-21'). Оставьте пустым для значения по умолчанию.",
"chutesApiKey": "Chutes API-ключ",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API Anahtarı",
"getCerebrasApiKey": "Cerebras API Anahtarını Al",
"azureResourceName": "Azure Kaynak Adı",
"azureResourceNameDescription": "Azure OpenAI kaynak adınız (örn. 'benim-openai-kaynagim').",
"azureResourceNameDescription": "Azure AI Foundry kaynak adınız (örn. 'benim-openai-kaynagim').",
"azureDeploymentName": "Azure Dağıtım Adı",
"azureDeploymentNameDescription": "Kaynak içindeki model dağıtım adınız.",
"azureApiKey": "Azure API Anahtarı",
"getAzureApiKey": "Azure OpenAI Erişimi Al",
"getAzureApiKey": "Azure AI Foundry Erişimi Al",
"azureApiVersion": "Azure API Sürümü",
"azureApiVersionDescription": "Kullanılacak API sürümü (örn. '2024-10-21'). Varsayılan için boş bırakın.",
"chutesApiKey": "Chutes API Anahtarı",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Khóa API Cerebras",
"getCerebrasApiKey": "Lấy khóa API Cerebras",
"azureResourceName": "Tên tài nguyên Azure",
"azureResourceNameDescription": "Tên tài nguyên Azure OpenAI của bạn (ví dụ: 'my-openai-resource').",
"azureResourceNameDescription": "Tên tài nguyên Azure AI Foundry của bạn (ví dụ: 'my-openai-resource').",
"azureDeploymentName": "Tên triển khai Azure",
"azureDeploymentNameDescription": "Tên triển khai mô hình trong tài nguyên.",
"azureApiKey": "Khóa API Azure",
"getAzureApiKey": "Lấy quyền truy cập Azure OpenAI",
"getAzureApiKey": "Lấy quyền truy cập Azure AI Foundry",
"azureApiVersion": "Phiên bản API Azure",
"azureApiVersionDescription": "Phiên bản API để sử dụng (ví dụ: '2024-10-21'). Để trống để dùng giá trị mặc định.",
"chutesApiKey": "Khóa API Chutes",

View file

@ -380,11 +380,11 @@
"cerebrasApiKey": "Cerebras API 密钥",
"getCerebrasApiKey": "获取 Cerebras API 密钥",
"azureResourceName": "Azure 资源名称",
"azureResourceNameDescription": "您的 Azure OpenAI 资源名称(例如:'my-openai-resource')。",
"azureResourceNameDescription": "您的 Azure AI Foundry 资源名称(例如:'my-openai-resource')。",
"azureDeploymentName": "Azure 部署名称",
"azureDeploymentNameDescription": "资源中的模型部署名称。",
"azureApiKey": "Azure API 密钥",
"getAzureApiKey": "获取 Azure OpenAI 访问权限",
"getAzureApiKey": "获取 Azure AI Foundry 访问权限",
"azureApiVersion": "Azure API 版本",
"azureApiVersionDescription": "要使用的 API 版本(例如:'2024-10-21')。留空使用默认值。",
"chutesApiKey": "Chutes API 密钥",

View file

@ -390,11 +390,11 @@
"cerebrasApiKey": "Cerebras API 金鑰",
"getCerebrasApiKey": "取得 Cerebras API 金鑰",
"azureResourceName": "Azure 資源名稱",
"azureResourceNameDescription": "您的 Azure OpenAI 資源名稱(例如:'my-openai-resource')。",
"azureResourceNameDescription": "您的 Azure AI Foundry 資源名稱(例如:'my-openai-resource')。",
"azureDeploymentName": "Azure 部署名稱",
"azureDeploymentNameDescription": "資源中的模型部署名稱。",
"azureApiKey": "Azure API 金鑰",
"getAzureApiKey": "取得 Azure OpenAI 存取權限",
"getAzureApiKey": "取得 Azure AI Foundry 存取權限",
"azureApiVersion": "Azure API 版本",
"azureApiVersionDescription": "要使用的 API 版本(例如:'2024-10-21')。留空使用預設值。",
"chutesApiKey": "Chutes API 金鑰",

View file

@ -156,9 +156,15 @@ function validateModelsAndKeysProvided(apiConfiguration: ProviderSettings): stri
}
break
case "azure":
if (!apiConfiguration.azureApiKey) {
return i18next.t("settings:validation.apiKey")
// Don't show validation errors when provider is freshly selected (all fields empty)
if (
!apiConfiguration.azureApiKey &&
!apiConfiguration.azureResourceName &&
!apiConfiguration.azureDeploymentName
) {
break
}
// API key is optional — Azure supports managed identity / Entra ID auth
if (!apiConfiguration.azureResourceName) {
return i18next.t("settings:validation.azureResourceName")
}