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: 6 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -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
# 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

# Gemini 3.1 Pro (Google Generative AI)
GEMINI_3_PRO_API_KEY=your_gemini_3_pro_api_key_here

Expand Down
8 changes: 8 additions & 0 deletions components/settings/components/model-selection-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ const models = [
badge: "Expert",
badgeVariant: "outline" as const,
},
{
id: "GPT-5.5",
name: "GPT-5.5",
description: "The next generation of OpenAI models, exclusively via Azure Foundry, delivering superior reasoning and efficiency.",
icon: Cpu,
badge: "Premium",
badgeVariant: "default" as const,
},
];

export function ModelSelectionForm({ form }: ModelSelectionFormProps) {
Expand Down
2 changes: 1 addition & 1 deletion lib/actions/suggest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { createStreamableUI, createStreamableValue } from 'ai/rsc'
import { CoreMessage, LanguageModel, streamObject } from 'ai'
import { PartialRelated, relatedSchema } from '@/lib/schema/related'
import { getModel } from '../utils'
import { getModel } from '../utils/model'
import { MapData } from '@/components/map/map-data-context'

export async function getSuggestions(
Expand Down
2 changes: 1 addition & 1 deletion lib/agents/inquire.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Copilot } from '@/components/copilot';
import { createStreamableUI, createStreamableValue } from 'ai/rsc';
import { CoreMessage, LanguageModel, streamObject } from 'ai';
import { PartialInquiry, inquirySchema } from '@/lib/schema/inquiry';
import { getModel } from '../utils';
import { getModel } from '../utils/model';

// Define a plain object type for the inquiry prop
interface InquiryProp {
Expand Down
2 changes: 1 addition & 1 deletion lib/agents/query-suggestor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { CoreMessage, LanguageModel, streamObject } from 'ai'
import { PartialRelated, relatedSchema } from '@/lib/schema/related'
import { Section } from '@/components/section'
import SearchRelated from '@/components/search-related'
import { getModel } from '../utils'
import { getModel } from '../utils/model'

interface CacheEntry {
data: PartialRelated;
Expand Down
2 changes: 1 addition & 1 deletion lib/agents/researcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
import { Section } from '@/components/section'
import { BotMessage } from '@/components/message'
import { getTools } from './tools'
import { getModel } from '../utils'
import { getModel } from '../utils/model'
import { MapProvider } from '@/lib/store/settings'
import { DrawnFeature } from './resolution-search'

Expand Down
2 changes: 1 addition & 1 deletion lib/agents/resolution-search.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CoreMessage, streamObject } from 'ai'
import { getModel } from '@/lib/utils'
import { getModel } from '@/lib/utils/model'
import { z } from 'zod'
import { tavily } from '@tavily/core'

Expand Down
2 changes: 1 addition & 1 deletion lib/agents/task-manager.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CoreMessage, generateObject, LanguageModel } from 'ai'
import { nextActionSchema } from '../schema/next-action'
import { getModel } from '../utils'
import { getModel } from '../utils/model'

// Decide whether inquiry is required for the user input
export async function taskManager(messages: CoreMessage[]) {
Expand Down
2 changes: 1 addition & 1 deletion lib/agents/writer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createStreamableUI, createStreamableValue } from 'ai/rsc'
import { CoreMessage, LanguageModel, streamText as nonexperimental_streamText } from 'ai'
import { Section } from '@/components/section'
import { BotMessage } from '@/components/message'
import { getModel } from '../utils'
import { getModel } from '../utils/model'

export async function writer(
dynamicSystemPrompt: string, // New parameter
Expand Down
14 changes: 6 additions & 8 deletions lib/auth/get-current-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,25 +58,23 @@ export async function getSupabaseUserAndSessionOnServer(): Promise<{
return { user: null, session: null, error: new Error('Missing Supabase environment variables') };
}

const cookieStore = cookies();
const cookieStore = await cookies();
const supabase = createServerClient(supabaseUrl, supabaseAnonKey, {
cookies: {
async get(name: string): Promise<string | undefined> {
const cookie = (await cookieStore).get(name); // Use the correct get method
return cookie?.value; // Return the value or undefined
const cookie = cookieStore.get(name);
return cookie?.value;
},
async set(name: string, value: string, options: CookieOptions): Promise<void> {
try {
const store = await cookieStore;
store.set({ name, value, ...options }); // Set cookie with options
cookieStore.set({ name, value, ...options });
} catch (error) {
// console.warn(`[Auth] Failed to set cookie ${name}:`, error);
}
},
async remove(name: string, options: CookieOptions): Promise<void> {
try {
const store = await cookieStore;
store.set({ name, value: '', ...options, maxAge: 0 }); // Delete cookie by setting maxAge to 0
cookieStore.set({ name, value: '', ...options, maxAge: 0 });
} catch (error) {
// console.warn(`[Auth] Failed to delete cookie ${name}:`, error);
}
Expand Down Expand Up @@ -124,4 +122,4 @@ export async function getCurrentUserIdOnServer(): Promise<string | null> {
return null;
}
return user?.id || null;
}
}
109 changes: 0 additions & 109 deletions lib/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
import { type ClassValue, clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { getSelectedModel } from '@/lib/actions/users'
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 { v4 as uuidv4 } from 'uuid';

export function cn(...inputs: ClassValue[]) {
Expand All @@ -20,107 +15,3 @@ export function generateUUID(): string {
* Returns a UUID v4 string.
*/
export { generateUUID as nanoid };

export async function getModel(requireVision: boolean = false) {
const selectedModel = await getSelectedModel();

const xaiApiKey = process.env.XAI_API_KEY;
const gemini3ProApiKey = process.env.GEMINI_3_PRO_API_KEY;
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
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;

if (selectedModel) {
switch (selectedModel) {
case 'Grok 4.2':
if (xaiApiKey) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
});
try {
return xai('grok-4-fast-non-reasoning');
} catch (error) {
console.error('Selected model "Grok 4.2" is configured but failed to initialize.', error);
throw new Error('Failed to initialize selected model.');
}
} else {
console.error('User selected "Grok 4.2" but XAI_API_KEY is not set.');
throw new Error('Selected model is not configured.');
}
case 'Gemini 3':
case 'Gemini 3.1 Pro':
if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
try {
return google('gemini-3.1-pro-preview');
} catch (error) {
console.error('Selected model "Gemini 3.1 Pro" is configured but failed to initialize.', error);
throw new Error('Failed to initialize selected model.');
}
} else {
console.error('User selected "Gemini 3.1 Pro" but GEMINI_3_PRO_API_KEY is not set.');
throw new Error('Selected model is not configured.');
}
case 'GPT-5.1':
if (openaiApiKey) {
const openai = createOpenAI({
apiKey: openaiApiKey,
});
return openai('gpt-4o');
} else {
console.error('User selected "GPT-5.1" but OPENAI_API_KEY is not set.');
throw new Error('Selected model is not configured.');
}
}
}

// Default behavior: Gemini -> Grok -> Bedrock -> OpenAI
if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
try {
return google('gemini-3.1-pro-preview');
} catch (error) {
console.warn('Gemini 3.1 Pro API unavailable, falling back to next provider:', error);
}
}

if (xaiApiKey) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
});
try {
return xai('grok-4-fast-non-reasoning');
} catch (error) {
console.warn('xAI API unavailable, falling back to next provider:');
}
}

if (awsAccessKeyId && awsSecretAccessKey) {
const bedrock = createAmazonBedrock({
bedrockOptions: {
region: awsRegion,
credentials: {
accessKeyId: awsAccessKeyId,
secretAccessKey: awsSecretAccessKey,
},
},
});
const model = bedrock(bedrockModelId, {
additionalModelRequestFields: { top_k: 350 },
});
return model;
}

const openai = createOpenAI({
apiKey: openaiApiKey,
});
return openai('gpt-4o');
}
119 changes: 119 additions & 0 deletions lib/utils/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { getSelectedModel } from '@/lib/actions/users'
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'

export async function getModel(requireVision: boolean = false) {
const selectedModel = await getSelectedModel();

const xaiApiKey = process.env.XAI_API_KEY;
const gemini3ProApiKey = process.env.GEMINI_3_PRO_API_KEY;
const awsAccessKeyId = process.env.AWS_ACCESS_KEY_ID;
const awsSecretAccessKey = process.env.AWS_SECRET_ACCESS_KEY;
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 azureEndpoint = process.env.AZURE_ENDPOINT;
const azureApiKey = process.env.AZURE_API_KEY;
const azureDeploymentName = process.env.AZURE_DEPLOYMENT_NAME || 'gpt-5.5';

if (selectedModel) {
switch (selectedModel) {
case 'Grok 4.2':
if (xaiApiKey) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
});
return xai('grok-4-fast-non-reasoning');
} else {
console.error('User selected "Grok 4.2" but XAI_API_KEY is not set.');
throw new Error('Selected model is not configured.');
}

case 'Gemini 3':
case 'Gemini 3.1 Pro':
if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
return google('gemini-3.1-pro-preview');
} else {
console.error('User selected "Gemini 3.1 Pro" but GEMINI_3_PRO_API_KEY is not set.');
throw new Error('Selected model is not configured.');
}

case 'GPT-5.1':
if (openaiApiKey) {
const openai = createOpenAI({ apiKey: openaiApiKey });
return openai('gpt-4o');
} else {
console.error('User selected "GPT-5.1" but OPENAI_API_KEY is not set.');
throw new Error('Selected model is not configured.');
}

case 'GPT-5.5':
if (azureApiKey && 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.');
throw new Error('Selected model is not configured.');
}

default:
console.warn(`Unknown selected model: ${selectedModel}, falling back to default.`);
}
}

// === Default fallback order: Azure → Gemini → Grok → Bedrock → OpenAI ===
if (azureApiKey && azureEndpoint) {
const azure = createOpenAI({
baseURL: azureEndpoint,
apiKey: azureApiKey,
});
return azure(azureDeploymentName);
}

if (gemini3ProApiKey) {
const google = createGoogleGenerativeAI({
apiKey: gemini3ProApiKey,
});
return google('gemini-3.1-pro-preview');
}

if (xaiApiKey) {
const xai = createXai({
apiKey: xaiApiKey,
baseURL: 'https://api.x.ai/v1',
});
return xai('grok-4-fast-non-reasoning');
}

if (awsAccessKeyId && awsSecretAccessKey) {
const bedrock = createAmazonBedrock({
bedrockOptions: {
region: awsRegion,
credentials: {
accessKeyId: awsAccessKeyId,
secretAccessKey: awsSecretAccessKey,
},
},
});
return bedrock(bedrockModelId, {
additionalModelRequestFields: { top_k: 350 },
});
}

// 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');
}
2 changes: 1 addition & 1 deletion mapbox_mcp/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useCallback, useRef, useEffect } from 'react';
import { generateText } from 'ai';
import { getModel } from '@/lib/utils';
import { getModel } from '@/lib/utils/model';

// Define Tool type locally if needed
type Tool = {
Expand Down