Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 24 additions & 11 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -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.');
}

Expand All @@ -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({
Expand Down Expand Up @@ -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');
Expand Down