+
)
-}
+})
+
+SearchRelated.displayName = 'SearchRelated'
export default SearchRelated
diff --git a/lib/actions/chat.ts b/lib/actions/chat.ts
index f36f2cf6..dcb16278 100644
--- a/lib/actions/chat.ts
+++ b/lib/actions/chat.ts
@@ -20,9 +20,17 @@ import { users } from '@/lib/db/schema'
import { eq } from 'drizzle-orm'
import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'
+// Helper to validate UUID format
+function isValidUUID(id: string): boolean {
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
+ // Loosened regex for internal mock UUIDs or different versions
+ const looseUuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
+ return looseUuidRegex.test(id);
+}
+
export async function getChats(userId?: string | null): Promise
{
- if (!userId) {
- console.warn('getChats called without userId, returning empty array.')
+ if (!userId || !isValidUUID(userId)) {
+ console.warn('getChats called with invalid userId:', userId)
return []
}
@@ -36,8 +44,8 @@ export async function getChats(userId?: string | null): Promise {
}
export async function getChat(id: string, userId: string): Promise {
- if (!userId) {
- console.warn('getChat called without userId.')
+ if (!userId || !isValidUUID(userId)) {
+ console.warn('getChat called with invalid userId:', userId)
return null;
}
try {
@@ -69,9 +77,9 @@ export async function clearChats(
userId?: string | null
): Promise<{ error?: string } | void> {
const currentUserId = userId || (await getCurrentUserIdOnServer())
- if (!currentUserId) {
- console.error('clearChats: No user ID provided or found.')
- return { error: 'User ID is required to clear chats' }
+ if (!currentUserId || !isValidUUID(currentUserId)) {
+ console.error('clearChats: Invalid user ID:', currentUserId)
+ return { error: 'Valid User ID is required to clear chats' }
}
try {
@@ -94,6 +102,11 @@ export async function saveChat(chat: OldChatType, userId: string): Promise {
- if (!userId) return { error: 'User ID is required' }
+ if (!userId || !isValidUUID(userId)) return { error: 'Valid User ID is required' }
if (!prompt) return { error: 'Prompt is required' }
try {
@@ -169,7 +182,7 @@ export async function saveSystemPrompt(
export async function getSystemPrompt(
userId: string
): Promise {
- if (!userId) return null
+ if (!userId || !isValidUUID(userId)) return null
try {
const result = await db.select({ systemPrompt: users.systemPrompt })
diff --git a/lib/agents/query-suggestor.tsx b/lib/agents/query-suggestor.tsx
index de2b3749..e54866be 100644
--- a/lib/agents/query-suggestor.tsx
+++ b/lib/agents/query-suggestor.tsx
@@ -18,7 +18,7 @@ export async function querySuggestor(
let finalRelatedQueries: PartialRelated = {}
const result = await streamObject({
- model: (await getModel()) as LanguageModel,
+ model: (await getModel(false, "auxiliary")) as LanguageModel,
system: `As a professional web researcher, your task is to generate a set of three queries that explore the subject matter more deeply, building upon the initial query and the information uncovered in its search results.
For instance, if the original query was "Starship's third test flight key milestones", your output should follow this format:
diff --git a/lib/auth/get-current-user.ts b/lib/auth/get-current-user.ts
index 6d08ba09..5534f364 100644
--- a/lib/auth/get-current-user.ts
+++ b/lib/auth/get-current-user.ts
@@ -9,7 +9,7 @@ const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
const AUTH_DISABLED_FLAG =
process.env.AUTH_DISABLED_FOR_DEV === 'true' &&
process.env.NODE_ENV !== 'production';
-const MOCK_USER_ID = 'dev-user-001'; // A consistent mock user ID for dev mode
+const MOCK_USER_ID = '00000000-0000-0000-0000-000000000001'; // A valid UUID for dev mode
/**
* Retrieves the Supabase user and session object in server-side contexts
@@ -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 {
- const cookie = (await cookieStore).get(name); // Use the correct get method
- return cookie?.value; // Return the value or undefined
+ get(name: string): string | undefined {
+ const cookie = cookieStore.get(name);
+ return cookie?.value;
},
- async set(name: string, value: string, options: CookieOptions): Promise {
+ set(name: string, value: string, options: CookieOptions): 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 {
+ remove(name: string, options: CookieOptions): 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);
}
@@ -124,4 +122,4 @@ export async function getCurrentUserIdOnServer(): Promise {
return null;
}
return user?.id || null;
-}
\ No newline at end of file
+}
diff --git a/lib/schema/related.tsx b/lib/schema/related.tsx
index 77fc3835..7c8233ff 100644
--- a/lib/schema/related.tsx
+++ b/lib/schema/related.tsx
@@ -8,7 +8,7 @@ export const relatedSchema = z.object({
query: z.string()
})
)
- .length(3)
+ .min(1).max(3)
})
export type PartialRelated = DeepPartial
diff --git a/lib/utils/index.ts b/lib/utils/index.ts
index 15565281..9e904d10 100644
--- a/lib/utils/index.ts
+++ b/lib/utils/index.ts
@@ -21,7 +21,7 @@ export function generateUUID(): string {
*/
export { generateUUID as nanoid };
-export async function getModel(requireVision: boolean = false) {
+export async function getModel(requireVision: boolean = false, tier: 'primary' | 'auxiliary' = 'primary') {
const selectedModel = await getSelectedModel();
const xaiApiKey = process.env.XAI_API_KEY;
@@ -29,7 +29,9 @@ export async function getModel(requireVision: boolean = false) {
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 bedrockModelId = tier === 'auxiliary'
+ ? (process.env.BEDROCK_AUXILIARY_MODEL_ID || 'anthropic.claude-3-haiku-20240307-v1:0')
+ : (process.env.BEDROCK_MODEL_ID || 'anthropic.claude-3-5-sonnet-20241022-v2:0');
const openaiApiKey = process.env.OPENAI_API_KEY;
if (selectedModel) {
@@ -57,9 +59,10 @@ export async function getModel(requireVision: boolean = false) {
apiKey: gemini3ProApiKey,
});
try {
- return google('gemini-3.1-pro-preview');
+ const modelName = tier === 'auxiliary' ? 'gemini-1.5-flash' : 'gemini-3.1-pro-preview';
+ return google(modelName);
} catch (error) {
- console.error('Selected model "Gemini 3.1 Pro" is configured but failed to initialize.', error);
+ console.error(`Selected model "${tier === 'auxiliary' ? 'Gemini 2.0 Flash Lite' : 'Gemini 3.1 Pro'}" is configured but failed to initialize.`, error);
throw new Error('Failed to initialize selected model.');
}
} else {
@@ -71,7 +74,7 @@ export async function getModel(requireVision: boolean = false) {
const openai = createOpenAI({
apiKey: openaiApiKey,
});
- return openai('gpt-4o');
+ return openai(tier === 'auxiliary' ? 'gpt-4o-mini' : '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.');
@@ -85,9 +88,10 @@ export async function getModel(requireVision: boolean = false) {
apiKey: gemini3ProApiKey,
});
try {
- return google('gemini-3.1-pro-preview');
+ const modelName = tier === 'auxiliary' ? 'gemini-1.5-flash' : 'gemini-3.1-pro-preview';
+ return google(modelName);
} catch (error) {
- console.warn('Gemini 3.1 Pro API unavailable, falling back to next provider:', error);
+ console.warn(`${tier === 'auxiliary' ? 'Gemini 2.0 Flash Lite' : 'Gemini 3.1 Pro'} API unavailable, falling back to next provider:`, error);
}
}
@@ -122,5 +126,5 @@ export async function getModel(requireVision: boolean = false) {
const openai = createOpenAI({
apiKey: openaiApiKey,
});
- return openai('gpt-4o');
+ return openai(tier === 'auxiliary' ? 'gpt-4o-mini' : 'gpt-4o');
}