- {imagePart && (
-
-
-
- )}
- {textPart &&
{textPart}
}
+
+
+
+ {imagePart && (
+
+
+
+ )}
+ {isEditing ? (
+
+ ) : (
+ textPart && (
+
+ {textPart}
+
+ )
+ )}
+
+ {enableShare && showShare && chatId &&
}
- {enableShare && showShare && chatId &&
}
+
+ {!isEditing && id && (
+
+
+
+
+
+
+
+
+
+
+
+ Delete message?
+
+ This will delete this message and all subsequent messages in this chat.
+
+
+
+ Cancel
+
+ Delete
+
+
+
+
+
+ )}
)
}
diff --git a/lib/actions/chat-db.ts b/lib/actions/chat-db.ts
index 4f0559ec..f25972b0 100644
--- a/lib/actions/chat-db.ts
+++ b/lib/actions/chat-db.ts
@@ -1,6 +1,6 @@
import { db } from '@/lib/db';
import { chats, messages, users } from '@/lib/db/schema';
-import { eq, desc, and, sql, asc } from 'drizzle-orm'; // Added asc
+import { eq, desc, and, sql, asc, gt } from 'drizzle-orm'; // Added asc, gt
import { alias } from 'drizzle-orm/pg-core';
import { getCurrentUserIdOnServer } from '@/lib/auth/get-current-user'; // We'll use this to ensure user-specific actions
@@ -119,7 +119,17 @@ export async function saveChat(chatData: NewChat, messagesData: Omit
{
}
}
-// More granular functions might be needed based on PR #533 specifics:
-// - updateMessage(messageId: string, updates: Partial): Promise
-// - deleteMessage(messageId: string, userId: string): Promise
-// - deleteTrailingMessages(chatId: string, lastKeptMessageId: string): Promise
-// These are placeholders for now and can be implemented if subsequent steps show they are directly part of PR #533's changes.
-// The PR mentions "feat: Add message update and trailing deletion logic" and "refactor(chat): Adjust message edit logic".
+/**
+ * Updates an existing message.
+ * @param messageId - The ID of the message to update.
+ * @param updates - The updates to apply.
+ * @returns The updated message object or null if error.
+ */
+export async function updateMessage(
+ messageId: string,
+ updates: Partial
+): Promise {
+ try {
+ const result = await db
+ .update(messages)
+ .set(updates)
+ .where(eq(messages.id, messageId))
+ .returning();
+ return result[0] || null;
+ } catch (error) {
+ console.error('Error updating message:', error);
+ return null;
+ }
+}
+
+/**
+ * Deletes a specific message.
+ * @param messageId - The ID of the message to delete.
+ * @returns True if deletion was successful, false otherwise.
+ */
+export async function deleteMessage(messageId: string): Promise {
+ try {
+ const result = await db
+ .delete(messages)
+ .where(eq(messages.id, messageId))
+ .returning({ id: messages.id });
+ return result.length > 0;
+ } catch (error) {
+ console.error('Error deleting message:', error);
+ return false;
+ }
+}
+
+/**
+ * Deletes all messages in a chat created after a certain message.
+ * @param chatId - The ID of the chat.
+ * @param createdAt - The timestamp after which messages should be deleted.
+ */
+export async function deleteTrailingMessages(
+ chatId: string,
+ createdAt: Date
+): Promise {
+ try {
+ await db
+ .delete(messages)
+ .where(and(eq(messages.chatId, chatId), gt(messages.createdAt, createdAt)));
+ } catch (error) {
+ console.error('Error deleting trailing messages:', error);
+ }
+}
console.log('Chat DB actions loaded. Ensure getCurrentUserId() is correctly implemented for server-side usage if applicable.');
diff --git a/lib/actions/chat.ts b/lib/actions/chat.ts
index c257d6e8..3d4f6df9 100644
--- a/lib/actions/chat.ts
+++ b/lib/actions/chat.ts
@@ -10,6 +10,9 @@ import {
saveChat as dbSaveChat,
createMessage as dbCreateMessage,
getMessagesByChatId as dbGetMessagesByChatId, // Added
+ updateMessage as dbUpdateMessage,
+ deleteMessage as dbDeleteMessage,
+ deleteTrailingMessages as dbDeleteTrailingMessages,
type Chat as DrizzleChat,
type Message as DrizzleMessage, // Added
type NewChat as DbNewChat,
@@ -162,6 +165,32 @@ export async function saveChat(chat: OldChatType, userId: string): Promise {
+ try {
+ return await dbUpdateMessage(messageId, { content });
+ } catch (error) {
+ console.error(`Error updating message ${messageId}:`, error);
+ return null;
+ }
+}
+
+export async function deleteMessage(messageId: string): Promise {
+ try {
+ return await dbDeleteMessage(messageId);
+ } catch (error) {
+ console.error(`Error deleting message ${messageId}:`, error);
+ return false;
+ }
+}
+
+export async function deleteTrailingMessages(chatId: string, createdAt: Date): Promise {
+ try {
+ await dbDeleteTrailingMessages(chatId, createdAt);
+ } catch (error) {
+ console.error(`Error deleting trailing messages for chat ${chatId}:`, error);
+ }
+}
+
export async function updateDrawingContext(chatId: string, contextData: { drawnFeatures: any[], cameraState: any }) {
'use server';
console.log('[Action] updateDrawingContext called for chatId:', chatId);
diff --git a/lib/agents/researcher.tsx b/lib/agents/researcher.tsx
index 72a5d737..3a49472c 100644
--- a/lib/agents/researcher.tsx
+++ b/lib/agents/researcher.tsx
@@ -105,15 +105,13 @@ export async function researcher(
)
const result = await nonexperimental_streamText({
- model: (await getModel(hasImage)) as LanguageModel,
+ model: (await getModel(useSpecificModel, hasImage)) as LanguageModel,
maxTokens: 4096,
system: systemPromptToUse,
messages,
tools: getTools({ uiStream, fullResponse, mapProvider }),
})
- uiStream.update(null) // remove spinner
-
const toolCalls: ToolCallPart[] = []
const toolResponses: ToolResultPart[] = []
diff --git a/lib/agents/resolution-search.tsx b/lib/agents/resolution-search.tsx
index 1acd0e01..65bf07c9 100644
--- a/lib/agents/resolution-search.tsx
+++ b/lib/agents/resolution-search.tsx
@@ -71,7 +71,7 @@ Analyze the user's prompt and the image to provide a holistic understanding of t
// Use streamObject to get partial results.
return streamObject({
- model: await getModel(hasImage),
+ model: await getModel(false, hasImage),
system: systemPrompt,
messages: filteredMessages,
schema: resolutionSearchSchema,
diff --git a/lib/utils/index.ts b/lib/utils/index.ts
index 64e8a305..cbc405d5 100644
--- a/lib/utils/index.ts
+++ b/lib/utils/index.ts
@@ -17,8 +17,8 @@ export function generateUUID(): string {
return uuidv4();
}
-export async function getModel(requireVision: boolean = false) {
- const selectedModel = await getSelectedModel();
+export async function getModel(useSpecificAPI: boolean = false, requireVision: boolean = false) {
+ const selectedModel = useSpecificAPI ? (process.env.SPECIFIC_API_MODEL || 'Gemini 3') : await getSelectedModel();
const xaiApiKey = process.env.XAI_API_KEY;
const gemini3ProApiKey = process.env.GEMINI_3_PRO_API_KEY;
@@ -37,7 +37,7 @@ export async function getModel(requireVision: boolean = false) {
baseURL: 'https://api.x.ai/v1',
});
try {
- return xai('grok-4-fast-non-reasoning');
+ return xai(requireVision ? 'grok-vision-beta' : 'grok-beta');
} catch (error) {
console.error('Selected model "Grok 4.2" is configured but failed to initialize.', error);
throw new Error('Failed to initialize selected model.');
@@ -52,7 +52,7 @@ export async function getModel(requireVision: boolean = false) {
apiKey: gemini3ProApiKey,
});
try {
- return google('gemini-3-pro-preview');
+ return google(requireVision ? 'gemini-1.5-pro' : 'gemini-1.5-pro');
} catch (error) {
console.error('Selected model "Gemini 3" is configured but failed to initialize.', error);
throw new Error('Failed to initialize selected model.');
@@ -81,7 +81,7 @@ export async function getModel(requireVision: boolean = false) {
baseURL: 'https://api.x.ai/v1',
});
try {
- return xai('grok-4-fast-non-reasoning');
+ return xai(requireVision ? 'grok-vision-beta' : 'grok-beta');
} catch (error) {
console.warn('xAI API unavailable, falling back to next provider:');
}
@@ -92,7 +92,7 @@ export async function getModel(requireVision: boolean = false) {
apiKey: gemini3ProApiKey,
});
try {
- return google('gemini-3-pro-preview');
+ return google(requireVision ? 'gemini-1.5-pro' : 'gemini-1.5-pro');
} catch (error) {
console.warn('Gemini 3 Pro API unavailable, falling back to next provider:', error);
}
diff --git a/server.log b/server.log
deleted file mode 100644
index 45044476..00000000
--- a/server.log
+++ /dev/null
@@ -1,11 +0,0 @@
-$ next dev --turbo
- ⚠ Port 3000 is in use, using available port 3003 instead.
- ▲ Next.js 15.3.6 (Turbopack)
- - Local: http://localhost:3003
- - Network: http://192.168.0.2:3003
- - Environments: .env.local, .env
-
- ✓ Starting...
- ○ Compiling middleware ...
- ✓ Compiled middleware in 648ms
- ✓ Ready in 2.5s