-
-
Notifications
You must be signed in to change notification settings - Fork 6
Supabase #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Supabase #327
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,6 +17,7 @@ import { inquire, researcher, taskManager, querySuggestor, resolutionSearch } fr | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The geospatialTool (if used by agents like researcher) now manages its own MCP client. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { writer } from '@/lib/agents/writer' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { saveChat, getSystemPrompt } from '@/lib/actions/chat' // Added getSystemPrompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { retrieveContext } from '@/lib/actions/rag' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Chat, AIMessage } from '@/lib/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { UserMessage } from '@/components/user-message' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { BotMessage } from '@/components/message' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -284,6 +285,11 @@ async function submit(formData?: FormData, skip?: boolean) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const userId = 'anonymous' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentSystemPrompt = (await getSystemPrompt(userId)) || '' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const retrievedContext = await retrieveContext(userInput, aiState.get().chatId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const augmentedSystemPrompt = retrievedContext.length > 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? `Context: ${retrievedContext.join('\n')}\n${currentSystemPrompt}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : currentSystemPrompt | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async function processEvents() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let action: any = { object: { next: 'proceed' } } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!skip) action = (await taskManager(messages)) ?? action | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -320,7 +326,7 @@ async function submit(formData?: FormData, skip?: boolean) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : answer.length === 0 && !errorOccurred | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { fullResponse, hasError, toolResponses } = await researcher( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| currentSystemPrompt, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| augmentedSystemPrompt, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Inconsistent system prompt usage breaks RAG integration. Line 329 correctly uses Apply this diff to fix the inconsistency: const latestMessages = modifiedMessages.slice(maxMessages * -1)
answer = await writer(
- currentSystemPrompt,
+ augmentedSystemPrompt,
uiStream,
streamText,
latestMessages
)Also applies to: 372-377 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uiStream, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| streamText, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -565,14 +571,23 @@ export const getUIStateFromAIState = (aiState: AIState): UIState => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // New messages will store the content array or string directly | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messageContent = content | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const location = (message as any).locations | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| component: ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <UserMessage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content={messageContent} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chatId={chatId} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| showShare={index === 0 && !isSharePage} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <UserMessage | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content={messageContent} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chatId={chatId} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| showShare={index === 0 && !isSharePage} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {location && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <GeoJsonLayer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id={`${id}-geojson`} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data={location.geojson} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+585
to
+590
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
SuggestionAdd a proper import for the layer component (adjust the path to your actual component), and guard against missing import { GeoJsonLayer } from '@/components/map/geojson-layer'
...
{location?.geojson && (
<GeoJsonLayer id={`${id}-geojson`} data={location.geojson} />
)}Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this suggestion
Comment on lines
+574
to
+590
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix: Scope the location variable to prevent switch case leakage. The Apply this diff to wrap the declaration in a block: case 'user':
switch (type) {
case 'input':
- case 'input_related':
+ case 'input_related': {
let messageContent: string | any[]
try {
// For backward compatibility with old messages that stored a JSON string
const json = JSON.parse(content as string)
messageContent =
type === 'input' ? json.input : json.related_query
} catch (e) {
// New messages will store the content array or string directly
messageContent = content
}
const location = (message as any).locations
return {
id,
component: (
<>
<UserMessage
content={messageContent}
chatId={chatId}
showShare={index === 0 && !isSharePage}
/>
{location && (
<GeoJsonLayer
id={`${id}-geojson`}
data={location.geojson}
/>
)}
</>
)
}
+ }
case 'inquiry':📝 Committable suggestion
Suggested change
🧰 Tools🪛 Biome (2.1.2)[error] 574-574: Other switch clauses can erroneously access this declaration. The declaration is defined in this switch clause: Safe fix: Wrap the declaration in a block. (lint/correctness/noSwitchDeclarations) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| case 'inquiry': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,11 +1,9 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { NextResponse, NextRequest } from 'next/server'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { saveChat, createMessage, NewChat, NewMessage } from '@/lib/actions/chat-db'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { saveChat } from '@/lib/actions/chat'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // import { generateUUID } from '@/lib/utils'; // Assuming generateUUID is in lib/utils as per PR context - not needed for PKs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { type Chat } from '@/lib/types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { v4 as uuidv4 } from 'uuid'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // This is a simplified POST handler. PR #533's version might be more complex, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // potentially handling streaming AI responses and then saving. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For now, this focuses on the database interaction part. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function POST(request: NextRequest) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const userId = await getCurrentUserIdOnServer(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -14,47 +12,35 @@ export async function POST(request: NextRequest) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const body = await request.json(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Example: Distinguish between creating a new chat vs. adding a message to existing chat | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The actual structure of `body` would depend on client-side implementation. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Let's assume a simple case: creating a new chat with an initial message. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { title, initialMessageContent, role = 'user' } = body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { title, initialMessageContent, role = 'user' } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| = body; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!initialMessageContent) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Initial message content is required' }, { status: 400 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const newChatData: NewChat = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // id: generateUUID(), // Drizzle schema now has defaultRandom for UUIDs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const newChat: Chat = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: uuidv4(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: title || 'New Chat', // Default title if not provided | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // createdAt: new Date(), // Handled by defaultNow() in schema | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| visibility: 'private', // Default visibility | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Use a transaction if creating chat and first message together | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For simplicity here, let's assume saveChat handles chat creation and returns ID, then we create a message. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // A more robust `saveChat` might create the chat and first message in one go. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The `saveChat` in chat-db.ts is designed to handle this. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const firstMessage: Omit<NewMessage, 'chatId'> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // id: generateUUID(), // Drizzle schema now has defaultRandom for UUIDs | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // chatId is omitted as it will be set by saveChat | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| role: role as NewMessage['role'], // Ensure role type matches schema expectation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: initialMessageContent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // createdAt: new Date(), // Handled by defaultNow() in schema, not strictly needed here | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| title: title || 'New Chat', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: '', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| messages: [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: uuidv4(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| role: role, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| content: initialMessageContent, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: new Date(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+22
to
36
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Initialize
- const newChat: Chat = {
+ const newChat: Chat = {
id: uuidv4(),
userId: userId,
title: title || 'New Chat',
createdAt: new Date(),
- path: '',
+ path: `/search/${/* chat id */ ''}`, // set after id is known
messages: [Or compute after the id is set: - const newChat: Chat = {
- id: uuidv4(),
+ const chatId = uuidv4()
+ const newChat: Chat = {
+ id: chatId,
userId: userId,
title: title || 'New Chat',
createdAt: new Date(),
- path: '',
+ path: `/search/${chatId}`,
messages: [📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The saveChat in chat-db.ts is designed to take initial messages. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const savedChatId = await saveChat(newChatData, [firstMessage]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const savedChatId = await saveChat(newChat, userId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!savedChatId) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Failed to save chat' }, { status: 500 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fetch the newly created chat and message to return (optional, but good for client) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // For now, just return success and the new chat ID. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ message: 'Chat created successfully', chatId: savedChatId }, { status: 201 }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,6 @@ | ||
| // Content for app/api/chats/all/route.ts | ||
| import { NextResponse } from 'next/server'; | ||
| import { clearHistory as dbClearHistory } from '@/lib/actions/chat-db'; | ||
| import { clearChats } from '@/lib/actions/chat'; | ||
| import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'; | ||
| import { revalidatePath } from 'next/cache'; // For revalidating after clearing | ||
|
|
||
| export async function DELETE() { | ||
| try { | ||
|
|
@@ -11,26 +9,18 @@ export async function DELETE() { | |
| return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); | ||
| } | ||
|
|
||
| const success = await dbClearHistory(userId); | ||
| if (success) { | ||
| revalidatePath('/'); // Revalidate home or relevant pages | ||
| revalidatePath('/search'); // Revalidate search path | ||
| return NextResponse.json({ message: 'History cleared successfully' }, { status: 200 }); | ||
| } else { | ||
| // This case might be redundant if dbClearHistory throws an error on failure, | ||
| // but kept for explicitness if it returns false for "no error but nothing done". | ||
| return NextResponse.json({ error: 'Failed to clear history' }, { status: 500 }); | ||
| const result = await clearChats(userId); | ||
| if (result && 'error' in result) { | ||
| return NextResponse.json({ error: result.error }, { status: 500 }); | ||
| } | ||
|
|
||
| return NextResponse.json({ message: 'History cleared successfully' }, { status: 200 }); | ||
|
|
||
|
Comment on lines
+12
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This API route will still succeed even if SuggestionAfter refactoring |
||
| } catch (error) { | ||
| console.error('Error clearing history via API:', error); | ||
| let errorMessage = 'Internal Server Error clearing history'; | ||
| if (error instanceof Error && error.message) { | ||
| // Use the error message from dbClearHistory if available (e.g., "User ID is required") | ||
| // This depends on dbClearHistory actually throwing or returning specific error messages. | ||
| // The current dbClearHistory in chat.ts returns {error: ...} which won't be caught here as an Error instance directly. | ||
| // However, the dbClearHistory in chat-db.ts returns boolean. | ||
| // Let's assume if dbClearHistory from chat-db.ts (which returns boolean) fails, it's a generic 500. | ||
| // If it were to throw, that would be caught. | ||
| errorMessage = error.message | ||
| } | ||
| return NextResponse.json({ error: errorMessage }, { status: 500 }); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||||||||||||||||||||||||||||||||||
| import { NextResponse, NextRequest } from 'next/server'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { getChatsPage } from '@/lib/actions/chat-db'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { getChats } from '@/lib/actions/chat'; | ||||||||||||||||||||||||||||||||||||||||||||
| import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| export async function GET(request: NextRequest) { | ||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -9,24 +9,8 @@ export async function GET(request: NextRequest) { | |||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const { searchParams } = new URL(request.url); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const DEFAULT_LIMIT = 20; | ||||||||||||||||||||||||||||||||||||||||||||
| const MAX_LIMIT = 100; | ||||||||||||||||||||||||||||||||||||||||||||
| const DEFAULT_OFFSET = 0; | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| let limit = parseInt(searchParams.get('limit') || '', 10); | ||||||||||||||||||||||||||||||||||||||||||||
| if (isNaN(limit) || limit < 1 || limit > MAX_LIMIT) { | ||||||||||||||||||||||||||||||||||||||||||||
| limit = DEFAULT_LIMIT; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| let offset = parseInt(searchParams.get('offset') || '', 10); | ||||||||||||||||||||||||||||||||||||||||||||
| if (isNaN(offset) || offset < 0) { | ||||||||||||||||||||||||||||||||||||||||||||
| offset = DEFAULT_OFFSET; | ||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| const result = await getChatsPage(userId, limit, offset); | ||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json(result); | ||||||||||||||||||||||||||||||||||||||||||||
| const chats = await getChats(userId); | ||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ chats }); | ||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+12
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainPotential scalability issue: Removed pagination. The endpoint now returns all chats at once instead of supporting pagination. For users with many chats (hundreds or thousands), this could cause:
Verify that this is intentional and that there are practical limits on the number of chats per user, or consider re-introducing pagination or implementing a reasonable limit. Check if there are database-level or application-level limits on chat count: 🏁 Script executed: #!/bin/bash
# Description: Check for chat limits in persistence layer and schema
# Search for limits in persistence functions
rg -nP 'limit|LIMIT' lib/supabase/persistence.ts lib/actions/chat.ts -C 2
# Search for RLS policies or constraints in migrations
fd -e sql . -x cat {} \; | grep -i "limit\|check\|constraint" -C 2Length of output: 2718 🏁 Script executed: #!/bin/bash
# Description: Locate and inspect the getChats implementation to see if it includes any implicit limits or pagination
rg -nP 'getChats' -n -C10 lib/actions/chat.ts || rg -nP 'getChats' -n -C10 lib/supabase/persistence.tsLength of output: 905 Missing user filter and pagination in getChats
🤖 Prompt for AI Agents
Comment on lines
+12
to
+13
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider reintroducing pagination for scalability. Removing pagination means all chats for a user are loaded in a single request. For users with hundreds or thousands of chats, this could cause:
If the previous pagination was removed intentionally (e.g., because most users have few chats), consider adding it back with sensible defaults: export async function GET(request: NextRequest) {
try {
const userId = await getCurrentUserIdOnServer();
if (!userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
+ const { searchParams } = new URL(request.url);
+ const limit = Math.min(parseInt(searchParams.get('limit') || '50'), 100);
+ const offset = Math.max(parseInt(searchParams.get('offset') || '0'), 0);
+
- const chats = await getChats(userId);
+ const chats = await getChats(userId, { limit, offset });
return NextResponse.json({ chats });
} catch (error) {
console.error('Error fetching chats:', error);
return NextResponse.json({ error: 'Internal Server Error fetching chats' }, { status: 500 });
}
}Alternatively, if pagination is truly unnecessary, add a comment explaining the rationale. 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||
| } catch (error) { | ||||||||||||||||||||||||||||||||||||||||||||
| console.error('Error fetching chats:', error); | ||||||||||||||||||||||||||||||||||||||||||||
| return NextResponse.json({ error: 'Internal Server Error fetching chats' }, { status: 500 }); | ||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,76 +1,51 @@ | ||
| import { notFound, redirect } from 'next/navigation'; | ||
| import { Chat } from '@/components/chat'; | ||
| import { getChat, getChatMessages } from '@/lib/actions/chat'; // Added getChatMessages | ||
| import { getChat, getChatMessages } from '@/lib/actions/chat'; | ||
| import { AI } from '@/app/actions'; | ||
| import { MapDataProvider } from '@/components/map/map-data-context'; | ||
| import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'; // For server-side auth | ||
| import type { AIMessage } from '@/lib/types'; // For AIMessage type | ||
| import type { Message as DrizzleMessage } from '@/lib/actions/chat-db'; // For DrizzleMessage type | ||
| import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'; | ||
| import type { AIMessage } from '@/lib/types'; | ||
|
|
||
| export const maxDuration = 60; | ||
|
|
||
| export interface SearchPageProps { | ||
| params: Promise<{ id: string }>; // Keep as is for now | ||
| params: Promise<{ id: string }>; | ||
| } | ||
|
|
||
| export async function generateMetadata({ params }: SearchPageProps) { | ||
| const { id } = await params; // Keep as is for now | ||
| // TODO: Metadata generation might need authenticated user if chats are private | ||
| // For now, assuming getChat can be called or it handles anon access for metadata appropriately | ||
| const userId = await getCurrentUserIdOnServer(); // Attempt to get user for metadata | ||
| const chat = await getChat(id, userId || 'anonymous'); // Pass userId or 'anonymous' if none | ||
| const { id } = await params; | ||
| const chat = await getChat(id); | ||
| return { | ||
|
Comment on lines
11
to
18
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix Next.js params typing; remove unnecessary awaits.
-export interface SearchPageProps {
- params: Promise<{ id: string }>;
-}
+export interface SearchPageProps {
+ params: { id: string };
+}
export async function generateMetadata({ params }: SearchPageProps) {
- const { id } = await params;
+ const { id } = params;-export default async function SearchPage({ params }: SearchPageProps) {
- const { id } = await params;
+export default async function SearchPage({ params }: SearchPageProps) {
+ const { id } = params;Also applies to: 23-25 🤖 Prompt for AI Agents |
||
| title: chat?.title?.toString().slice(0, 50) || 'Search', | ||
| }; | ||
| } | ||
|
|
||
| export default async function SearchPage({ params }: SearchPageProps) { | ||
| const { id } = await params; // Keep as is for now | ||
| const { id } = await params; | ||
| const userId = await getCurrentUserIdOnServer(); | ||
|
|
||
| if (!userId) { | ||
| // If no user, redirect to login or show appropriate page | ||
| // For now, redirecting to home, but a login page would be better. | ||
| redirect('/'); | ||
| } | ||
|
|
||
| const chat = await getChat(id, userId); | ||
| const chat = await getChat(id); | ||
|
|
||
| if (!chat) { | ||
| // If chat doesn't exist or user doesn't have access (handled by getChat) | ||
| notFound(); | ||
| } | ||
|
|
||
| // Fetch messages for the chat | ||
| const dbMessages: DrizzleMessage[] = await getChatMessages(chat.id); | ||
|
|
||
| // Transform DrizzleMessages to AIMessages | ||
| const initialMessages: AIMessage[] = dbMessages.map((dbMsg): AIMessage => { | ||
| return { | ||
| id: dbMsg.id, | ||
| role: dbMsg.role as AIMessage['role'], // Cast role, ensure AIMessage['role'] includes all dbMsg.role possibilities | ||
| content: dbMsg.content, | ||
| createdAt: dbMsg.createdAt ? new Date(dbMsg.createdAt) : undefined, | ||
| // 'type' and 'name' are not in the basic Drizzle 'messages' schema. | ||
| // These would be undefined unless specific logic is added to derive them. | ||
| // For instance, if a message with role 'tool' should have a 'name', | ||
| // or if some messages have a specific 'type' based on content or other flags. | ||
| // This mapping assumes standard user/assistant messages primarily. | ||
| }; | ||
| }); | ||
| const initialMessages = await getChatMessages(chat.id); | ||
|
|
||
| return ( | ||
| <AI | ||
| initialAIState={{ | ||
| chatId: chat.id, | ||
| messages: initialMessages, // Use the transformed messages from the database | ||
| // isSharePage: true, // This was in PR#533, but share functionality is removed. | ||
| // If needed for styling or other logic, it can be set. | ||
| messages: initialMessages as AIMessage[], | ||
| }} | ||
| > | ||
| <MapDataProvider> | ||
| <Chat id={id} /> | ||
| </MapDataProvider> | ||
| </AI> | ||
| ); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ | |
| import { useEffect, useState, useRef, ChangeEvent, forwardRef, useImperativeHandle } from 'react' | ||
| import type { AI, UIState } from '@/app/actions' | ||
| import { useUIState, useActions } from 'ai/rsc' | ||
| // Removed import of useGeospatialToolMcp as it's no longer used/available | ||
| import { cn } from '@/lib/utils' | ||
| import { UserMessage } from './user-message' | ||
| import { Button } from './ui/button' | ||
|
|
@@ -15,16 +14,17 @@ interface ChatPanelProps { | |
| messages: UIState | ||
| input: string | ||
| setInput: (value: string) => void | ||
| chatId: string | ||
| shareableLink: string | ||
| } | ||
|
Comment on lines
+17
to
19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Remove or use newly added props.
Also applies to: 25-25 🤖 Prompt for AI Agents |
||
|
|
||
| export interface ChatPanelRef { | ||
| handleAttachmentClick: () => void; | ||
| } | ||
|
|
||
| export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, input, setInput }, ref) => { | ||
| export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, input, setInput, chatId, shareableLink }, ref) => { | ||
| const [, setMessages] = useUIState<typeof AI>() | ||
| const { submit, clearChat } = useActions() | ||
| // Removed mcp instance as it's no longer passed to submit | ||
| const [isMobile, setIsMobile] = useState(false) | ||
| const [selectedFile, setSelectedFile] = useState<File | null>(null) | ||
| const inputRef = useRef<HTMLTextAreaElement>(null) | ||
|
|
@@ -37,7 +37,6 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i | |
| } | ||
| })); | ||
|
|
||
| // Detect mobile layout | ||
| useEffect(() => { | ||
| const checkMobile = () => { | ||
| setIsMobile(window.innerWidth <= 1024) | ||
|
|
@@ -116,7 +115,6 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i | |
| inputRef.current?.focus() | ||
| }, []) | ||
|
|
||
| // New chat button (appears when there are messages) | ||
| if (messages.length > 0 && !isMobile) { | ||
| return ( | ||
| <div | ||
|
|
@@ -172,7 +170,7 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i | |
| <div | ||
| className={cn( | ||
| 'relative flex items-start w-full', | ||
| isMobile && 'mobile-chat-input' // Apply mobile chat input styling | ||
| isMobile && 'mobile-chat-input' | ||
| )} | ||
| > | ||
| <input | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Guard
retrieveContextwhenuserInputis empty/undefined.userInputcan be falsy (e.g., file-only input or skip). CallingretrieveContextwithundefinedmay throw or degrade results.📝 Committable suggestion
🤖 Prompt for AI Agents