diff --git a/.env.local.example b/.env.local.example index e52eec0c..cbe3c452 100644 --- a/.env.local.example +++ b/.env.local.example @@ -17,6 +17,12 @@ NEXT_PUBLIC_COMPOSIO_USER_ID=user@example.com # NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN=your_mapbox_public_token_here # AI Provider API Keys +# Azure AI Foundry (Azure OpenAI) +AZURE_RESOURCE_NAME=your_azure_resource_name_here +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/app/actions.tsx b/app/actions.tsx index 50e985bf..3547909f 100644 --- a/app/actions.tsx +++ b/app/actions.tsx @@ -397,7 +397,16 @@ async function submit(formData?: FormData, skip?: boolean) { } as CoreMessage) } - const userId = 'anonymous' + let actualUserId: string | null = null; + try { + const { getCurrentUserIdOnServer } = await import( + '@/lib/auth/get-current-user' + ) + actualUserId = await getCurrentUserIdOnServer() + } catch (authError) { + console.error('Error retrieving user ID in submit:', authError); + } + const userId = actualUserId || 'anonymous' const currentSystemPrompt = (await getSystemPrompt(userId)) || '' const mapProvider = formData?.get('mapProvider') as 'mapbox' | 'google' diff --git a/bun.lock b/bun.lock index f101e5d7..d123cca0 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "dependencies": { "@ai-sdk/amazon-bedrock": "^1.1.6", "@ai-sdk/anthropic": "^1.2.12", + "@ai-sdk/azure": "^3.0.64", "@ai-sdk/google": "^1.2.22", "@ai-sdk/openai": "^1.3.24", "@ai-sdk/xai": "^1.2.18", @@ -111,6 +112,8 @@ "@ai-sdk/anthropic": ["@ai-sdk/anthropic@1.2.12", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-YSzjlko7JvuiyQFmI9RN1tNZdEiZxc+6xld/0tq/VkJaHpEzGAb1yiNxxvmYVcjvfu/PcvCxAAYXmTYQQ63IHQ=="], + "@ai-sdk/azure": ["@ai-sdk/azure@3.0.64", "", { "dependencies": { "@ai-sdk/openai": "3.0.63", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-jNcgI9tPzpuPJhAvB6twCiH9UGOOBFRPxFWOuDI4qts347q/+iFtc+AvkrKU/JsbSSwGeeW4qslQRri4SmWipg=="], + "@ai-sdk/google": ["@ai-sdk/google@1.2.22", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-Ppxu3DIieF1G9pyQ5O1Z646GYR0gkC57YdBqXJ82qvCdhEhZHu0TWhmnOoeIWe2olSbuDeoOY+MfJrW8dzS3Hw=="], "@ai-sdk/openai": ["@ai-sdk/openai@1.3.24", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "@ai-sdk/provider-utils": "2.2.8" }, "peerDependencies": { "zod": "^3.0.0" } }, "sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q=="], @@ -655,6 +658,8 @@ "@so-ric/colorspace": ["@so-ric/colorspace@1.1.6", "", { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw=="], + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + "@supabase/auth-js": ["@supabase/auth-js@2.90.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-vxb66dgo6h3yyPbR06735Ps+dK3hj0JwS8w9fdQPVZQmocSTlKUW5MfxSy99mN0XqCCuLMQ3jCEiIIUU23e9ng=="], "@supabase/functions-js": ["@supabase/functions-js@2.90.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-x9mV9dF1Lam9qL3zlpP6mSM5C9iqMPtF5B/tU1Jj/F0ufX5mjDf9ghVBaErVxmrQJRL4+iMKWKY2GnODkpS8tw=="], @@ -2549,6 +2554,12 @@ "@ai-sdk/anthropic/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], + "@ai-sdk/azure/@ai-sdk/openai": ["@ai-sdk/openai@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4yY/m8a57MNNVoJCsXuNblKf6BO4yuAuLKRX4tzSNffBEBSp1FlcWdPE0Z4FkqUeS0AJhYSSqp0GIiA/cIcDNA=="], + + "@ai-sdk/azure/@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="], + + "@ai-sdk/azure/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="], + "@ai-sdk/google/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], "@ai-sdk/google/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.2.8", "", { "dependencies": { "@ai-sdk/provider": "1.1.3", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.23.8" } }, "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA=="], @@ -2781,6 +2792,8 @@ "yargs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + "@ai-sdk/azure/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + "@ai-sdk/react/@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/provider@1.1.3", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg=="], "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], diff --git a/components/settings/components/model-selection-form.tsx b/components/settings/components/model-selection-form.tsx index bc6164ba..95dae1ea 100644 --- a/components/settings/components/model-selection-form.tsx +++ b/components/settings/components/model-selection-form.tsx @@ -58,6 +58,14 @@ const models = [ badge: "Expert", badgeVariant: "outline" as const, }, + { + id: "Azure GPT 5.5", + name: "Azure GPT 5.5", + description: "Enterprise-grade intelligence powered by Azure AI Foundry, delivering high-reliability and security.", + icon: Cpu, + badge: "Enterprise", + badgeVariant: "outline" as const, + }, ]; export function ModelSelectionForm({ form }: ModelSelectionFormProps) { diff --git a/lib/actions/chat.ts b/lib/actions/chat.ts index f36f2cf6..ac010ca6 100644 --- a/lib/actions/chat.ts +++ b/lib/actions/chat.ts @@ -169,17 +169,21 @@ export async function saveSystemPrompt( export async function getSystemPrompt( userId: string ): Promise { - if (!userId) return null + if (!userId || userId === 'anonymous') return null try { + // console.log(`getSystemPrompt: Fetching prompt for user: ${userId}`); const result = await db.select({ systemPrompt: users.systemPrompt }) .from(users) .where(eq(users.id, userId)) .limit(1); return result[0]?.systemPrompt || null; - } catch (error) { - console.error('getSystemPrompt: Error:', error) + } catch (error: any) { + console.error('getSystemPrompt: Error:', error.message || error); + if (error.stack) { + console.error('getSystemPrompt: Stack trace:', error.stack); + } return null } } diff --git a/lib/utils/index.ts b/lib/utils/index.ts index 15565281..81220a29 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -5,7 +5,9 @@ import { createOpenAI } from '@ai-sdk/openai' import { createGoogleGenerativeAI } from '@ai-sdk/google' import { createAmazonBedrock } from '@ai-sdk/amazon-bedrock' import { createXai } from '@ai-sdk/xai'; +import { createAzure } from '@ai-sdk/azure'; import { v4 as uuidv4 } from 'uuid'; +import { LanguageModel } from 'ai' export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) @@ -21,7 +23,7 @@ export function generateUUID(): string { */ export { generateUUID as nanoid }; -export async function getModel(requireVision: boolean = false) { +export async function getModel(requireVision: boolean = false): Promise { const selectedModel = await getSelectedModel(); const xaiApiKey = process.env.XAI_API_KEY; @@ -31,6 +33,10 @@ export async function getModel(requireVision: boolean = false) { const awsRegion = process.env.AWS_REGION; const bedrockModelId = process.env.BEDROCK_MODEL_ID || 'anthropic.claude-3-5-sonnet-20241022-v2:0'; const openaiApiKey = process.env.OPENAI_API_KEY; + const azureResourceName = process.env.AZURE_RESOURCE_NAME; + const azureApiKey = process.env.AZURE_API_KEY; + const azureEndpoint = process.env.AZURE_ENDPOINT; + const azureDeploymentName = process.env.AZURE_DEPLOYMENT_NAME || 'gpt-5.5'; if (selectedModel) { switch (selectedModel) { @@ -76,10 +82,61 @@ export async function getModel(requireVision: boolean = false) { console.error('User selected "GPT-5.1" but OPENAI_API_KEY is not set.'); throw new Error('Selected model is not configured.'); } + case 'Azure GPT 5.5': + if (azureEndpoint && azureApiKey) { + const azureOpenAI = createOpenAI({ + baseURL: azureEndpoint, + apiKey: azureApiKey, + }); + try { + return azureOpenAI(azureDeploymentName); + } catch (error) { + console.error('Selected model "Azure GPT 5.5" (via endpoint) failed to initialize.', error); + throw new Error('Failed to initialize selected model.'); + } + } else if (azureResourceName && azureApiKey) { + const azure = createAzure({ + resourceName: azureResourceName, + apiKey: azureApiKey, + }); + try { + return azure(azureDeploymentName) as unknown as LanguageModel; + } catch (error) { + console.error('Selected model "Azure GPT 5.5" (via resource) failed to initialize.', error); + throw new Error('Failed to initialize selected model.'); + } + } else { + console.error('User selected "Azure GPT 5.5" but Azure environment variables are not set.'); + throw new Error('Selected model is not configured.'); + } + } + } + + // Default behavior: Azure -> Gemini -> Grok -> Bedrock -> OpenAI + if (azureEndpoint && azureApiKey) { + const azureOpenAI = createOpenAI({ + baseURL: azureEndpoint, + apiKey: azureApiKey, + }); + try { + return azureOpenAI(azureDeploymentName); + } catch (error) { + console.warn('Azure OpenAI API (via endpoint) unavailable, falling back to next provider:', error); + } + } + + if (azureResourceName && azureApiKey) { + const azure = createAzure({ + resourceName: azureResourceName, + apiKey: azureApiKey, + }); + try { + return azure(azureDeploymentName) as unknown as LanguageModel; + } catch (error) { + console.warn('Azure OpenAI API (via resource) unavailable, falling back to next provider:', error); } } - // Default behavior: Gemini -> Grok -> Bedrock -> OpenAI if (gemini3ProApiKey) { const google = createGoogleGenerativeAI({ apiKey: gemini3ProApiKey, @@ -103,6 +160,7 @@ export async function getModel(requireVision: boolean = false) { } } + if (awsAccessKeyId && awsSecretAccessKey) { const bedrock = createAmazonBedrock({ bedrockOptions: { diff --git a/package.json b/package.json index 87066925..1bb5f735 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "dependencies": { "@ai-sdk/amazon-bedrock": "^1.1.6", "@ai-sdk/anthropic": "^1.2.12", + "@ai-sdk/azure": "^3.0.64", "@ai-sdk/google": "^1.2.22", "@ai-sdk/openai": "^1.3.24", "@ai-sdk/xai": "^1.2.18",