diff --git a/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx b/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx index a2b417c6a5..7e686433b7 100644 --- a/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx +++ b/apps/web/src/components/organizations/byok/BYOKKeysManager.tsx @@ -43,12 +43,14 @@ import { DirectUserByokInferenceProviderIdSchema, UserByokProviderIdSchema, VercelUserByokInferenceProviderIdSchema, + AzureCredentialsSchema, BedrockCredentialsSchema, VertexCredentialsSchema, type VercelUserByokInferenceProviderId, } from '@/lib/ai-gateway/providers/openrouter/inference-provider-id'; import { DIRECT_BYOK_PROVIDERS_META } from '@/lib/ai-gateway/providers/direct-byok/direct-byok-meta'; import { getCodingPlanManagedKeyLabel } from '@/components/subscriptions/coding-plans/coding-plan-provider'; +import { cn } from '@/lib/utils'; import * as z from 'zod'; // Exhaustive map of Vercel BYOK providers to their display names. The `satisfies` @@ -56,6 +58,7 @@ import * as z from 'zod'; // VercelUserByokInferenceProviderIdSchema. const VERCEL_BYOK_PROVIDER_NAMES = { anthropic: 'Anthropic', + azure: 'Azure Foundry (experimental)', bedrock: 'AWS Bedrock', deepseek: 'DeepSeek', openai: 'OpenAI', @@ -279,11 +282,13 @@ export function BYOKKeysManager({ organizationId }: BYOKKeysManagerProps) { const validateStructuredCredentials = (providerId: string, value: string): string | null => { if (!value) return null; const schema = - providerId === VercelUserByokInferenceProviderIdSchema.enum.bedrock - ? BedrockCredentialsSchema - : providerId === VercelUserByokInferenceProviderIdSchema.enum.vertex - ? VertexCredentialsSchema - : null; + providerId === VercelUserByokInferenceProviderIdSchema.enum.azure + ? AzureCredentialsSchema + : providerId === VercelUserByokInferenceProviderIdSchema.enum.bedrock + ? BedrockCredentialsSchema + : providerId === VercelUserByokInferenceProviderIdSchema.enum.vertex + ? VertexCredentialsSchema + : null; if (!schema) return null; let parsed: unknown; try { @@ -293,6 +298,11 @@ export function BYOKKeysManager({ organizationId }: BYOKKeysManagerProps) { } const result = schema.safeParse(parsed); if (!result.success) { + if (providerId === VercelUserByokInferenceProviderIdSchema.enum.azure) { + return result.error.issues.some(issue => issue.path[0] === 'modelMappings') + ? 'Each model mapping must include gatewayModelSlug and customModelId.' + : 'Enter JSON with apiKey and resourceName.'; + } if (providerId === VercelUserByokInferenceProviderIdSchema.enum.bedrock) { return 'Enter JSON with apiKey and region, or accessKeyId, secretAccessKey, and region. Use only one authentication method.'; } @@ -394,6 +404,10 @@ export function BYOKKeysManager({ organizationId }: BYOKKeysManagerProps) { const getProviderModels = (providerId: string): string[] => { return supportedModels?.[providerId] ?? []; }; + const usesStructuredCredentials = + selectedProvider === VercelUserByokInferenceProviderIdSchema.enum.azure || + selectedProvider === VercelUserByokInferenceProviderIdSchema.enum.bedrock || + selectedProvider === VercelUserByokInferenceProviderIdSchema.enum.vertex; return (
@@ -579,42 +593,71 @@ export function BYOKKeysManager({ organizationId }: BYOKKeysManagerProps) {
- {selectedProvider === VercelUserByokInferenceProviderIdSchema.enum.bedrock || - selectedProvider === VercelUserByokInferenceProviderIdSchema.enum.vertex ? ( + {usesStructuredCredentials ? ( <> -