diff --git a/.env.local.example b/.env.local.example index 956b921d..5f8bb1ac 100644 --- a/.env.local.example +++ b/.env.local.example @@ -19,9 +19,9 @@ NEXT_PUBLIC_COMPOSIO_USER_ID=user@example.com # AI Provider API Keys # GPT-5.5 (Azure Foundry) # AZURE_ENDPOINT should be the full V1 endpoint, e.g. https://your-resource.services.ai.azure.com/openai/v1 -AZURE_ENDPOINT=your_azure_endpoint_here -AZURE_API_KEY=your_azure_api_key_here -AZURE_DEPLOYMENT_NAME=gpt-5.5 +# AZURE_ENDPOINT=your_azure_endpoint_here +# AZURE_API_KEY=your_azure_api_key_here +# AZURE_DEPLOYMENT_NAME=gpt-5.5 # Gemini 3.1 Pro (Google Generative AI) GEMINI_3_PRO_API_KEY=your_gemini_3_pro_api_key_here diff --git a/lib/utils/index.ts b/lib/utils/index.ts index 33a2b057..5b558c6a 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -21,6 +21,16 @@ export function generateUUID(): string { */ export { generateUUID as nanoid }; +function isValidHttpsUrl(value: string | undefined): value is string { + if (!value) return false; + try { + const url = new URL(value); + return url.protocol === 'https:'; + } catch { + return false; + } +} + export async function getModel(requireVision: boolean = false) { const selectedModel = await getSelectedModel(); @@ -71,14 +81,14 @@ export async function getModel(requireVision: boolean = false) { } case 'GPT-5.5': - if (azureApiKey && azureEndpoint) { + if (azureApiKey && isValidHttpsUrl(azureEndpoint)) { const azure = createOpenAI({ baseURL: azureEndpoint, apiKey: azureApiKey, }); return azure(azureDeploymentName); } else { - console.error('User selected "GPT-5.5" but AZURE_API_KEY or AZURE_ENDPOINT is not set.'); + console.error('User selected "GPT-5.5" but AZURE_API_KEY or AZURE_ENDPOINT is not set or is not a valid HTTPS URL.'); throw new Error('Selected model is not configured.'); } @@ -87,14 +97,9 @@ export async function getModel(requireVision: boolean = false) { } } - // === Default fallback order: Azure → Gemini → Grok → Bedrock → OpenAI === - if (azureApiKey && azureEndpoint) { - const azure = createOpenAI({ - baseURL: azureEndpoint, - apiKey: azureApiKey, - }); - return azure(azureDeploymentName); - } + // === Default fallback order: Gemini → Grok → Bedrock → OpenAI → Azure === + // Azure is last in the automatic fallback to avoid accidental use of placeholder credentials. + // It is still the primary provider when explicitly selected via the model picker. if (gemini3ProApiKey) { const google = createGoogleGenerativeAI({ @@ -126,10 +131,18 @@ export async function getModel(requireVision: boolean = false) { }); } + if (azureApiKey && isValidHttpsUrl(azureEndpoint)) { + const azure = createOpenAI({ + baseURL: azureEndpoint, + apiKey: azureApiKey, + }); + return azure(azureDeploymentName); + } + // Final fallback if (!openaiApiKey) { throw new Error('No model providers are configured. Please set at least one API key.'); - } + const openai = createOpenAI({ apiKey: openaiApiKey }); return openai('gpt-4o');