mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-03 04:42:39 +02:00
Send edited user images and full message content in chat regenerate while leaving reload on server-resolved turns.
This commit is contained in:
parent
056870464a
commit
a07c44f496
1 changed files with 45 additions and 29 deletions
|
|
@ -77,7 +77,10 @@ import {
|
||||||
type ThreadListResponse,
|
type ThreadListResponse,
|
||||||
type ThreadRecord,
|
type ThreadRecord,
|
||||||
} from "@/lib/chat/thread-persistence";
|
} from "@/lib/chat/thread-persistence";
|
||||||
import { extractUserTurnForNewChatApi } from "@/lib/chat/user-turn-api-parts";
|
import {
|
||||||
|
extractUserTurnForNewChatApi,
|
||||||
|
type NewChatUserImagePayload,
|
||||||
|
} from "@/lib/chat/user-turn-api-parts";
|
||||||
import { NotFoundError } from "@/lib/error";
|
import { NotFoundError } from "@/lib/error";
|
||||||
import {
|
import {
|
||||||
trackChatCreated,
|
trackChatCreated,
|
||||||
|
|
@ -1337,15 +1340,24 @@ export default function NewChatPage() {
|
||||||
* Handle regeneration (edit or reload) by calling the regenerate endpoint
|
* Handle regeneration (edit or reload) by calling the regenerate endpoint
|
||||||
* and streaming the response. This rewinds the LangGraph checkpointer state.
|
* and streaming the response. This rewinds the LangGraph checkpointer state.
|
||||||
*
|
*
|
||||||
* @param newUserQuery - The new user query (for edit). Pass null/undefined for reload.
|
* @param newUserQuery - `null` = reload with same turn from the server. A string = edit
|
||||||
|
* (including an empty string when the edited turn is images-only); pass `editExtras` for images/content.
|
||||||
*/
|
*/
|
||||||
const handleRegenerate = useCallback(
|
const handleRegenerate = useCallback(
|
||||||
async (newUserQuery?: string | null) => {
|
async (
|
||||||
|
newUserQuery: string | null,
|
||||||
|
editExtras?: {
|
||||||
|
userMessageContent: ThreadMessageLike["content"];
|
||||||
|
userImages: NewChatUserImagePayload[];
|
||||||
|
}
|
||||||
|
) => {
|
||||||
if (!threadId) {
|
if (!threadId) {
|
||||||
toast.error("Cannot regenerate: no active chat thread");
|
toast.error("Cannot regenerate: no active chat thread");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isEdit = newUserQuery !== null;
|
||||||
|
|
||||||
// Abort any previous streaming request
|
// Abort any previous streaming request
|
||||||
if (abortControllerRef.current) {
|
if (abortControllerRef.current) {
|
||||||
abortControllerRef.current.abort();
|
abortControllerRef.current.abort();
|
||||||
|
|
@ -1359,11 +1371,11 @@ export default function NewChatPage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the original user query BEFORE removing messages (for reload mode)
|
// Extract the original user query BEFORE removing messages (for reload mode)
|
||||||
let userQueryToDisplay = newUserQuery;
|
let userQueryToDisplay: string | undefined;
|
||||||
let originalUserMessageContent: ThreadMessageLike["content"] | null = null;
|
let originalUserMessageContent: ThreadMessageLike["content"] | null = null;
|
||||||
let originalUserMessageMetadata: ThreadMessageLike["metadata"] | undefined;
|
let originalUserMessageMetadata: ThreadMessageLike["metadata"] | undefined;
|
||||||
|
|
||||||
if (!newUserQuery) {
|
if (!isEdit) {
|
||||||
// Reload mode - find and preserve the last user message content
|
// Reload mode - find and preserve the last user message content
|
||||||
const lastUserMessage = [...messages].reverse().find((m) => m.role === "user");
|
const lastUserMessage = [...messages].reverse().find((m) => m.role === "user");
|
||||||
if (lastUserMessage) {
|
if (lastUserMessage) {
|
||||||
|
|
@ -1377,6 +1389,8 @@ export default function NewChatPage() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
userQueryToDisplay = newUserQuery;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the last two messages (user + assistant) from the UI immediately
|
// Remove the last two messages (user + assistant) from the UI immediately
|
||||||
|
|
@ -1412,11 +1426,13 @@ export default function NewChatPage() {
|
||||||
const userMessage: ThreadMessageLike = {
|
const userMessage: ThreadMessageLike = {
|
||||||
id: userMsgId,
|
id: userMsgId,
|
||||||
role: "user",
|
role: "user",
|
||||||
content: newUserQuery
|
content: isEdit
|
||||||
? [{ type: "text", text: newUserQuery }]
|
? (editExtras?.userMessageContent ?? [
|
||||||
|
{ type: "text", text: newUserQuery ?? "" },
|
||||||
|
])
|
||||||
: originalUserMessageContent || [{ type: "text", text: userQueryToDisplay || "" }],
|
: originalUserMessageContent || [{ type: "text", text: userQueryToDisplay || "" }],
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
metadata: newUserQuery ? undefined : originalUserMessageMetadata,
|
metadata: isEdit ? undefined : originalUserMessageMetadata,
|
||||||
};
|
};
|
||||||
setMessages((prev) => [...prev, userMessage]);
|
setMessages((prev) => [...prev, userMessage]);
|
||||||
|
|
||||||
|
|
@ -1433,20 +1449,24 @@ export default function NewChatPage() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const selection = await getAgentFilesystemSelection();
|
const selection = await getAgentFilesystemSelection();
|
||||||
|
const requestBody: Record<string, unknown> = {
|
||||||
|
search_space_id: searchSpaceId,
|
||||||
|
user_query: newUserQuery,
|
||||||
|
disabled_tools: disabledTools.length > 0 ? disabledTools : undefined,
|
||||||
|
filesystem_mode: selection.filesystem_mode,
|
||||||
|
client_platform: selection.client_platform,
|
||||||
|
local_filesystem_mounts: selection.local_filesystem_mounts,
|
||||||
|
};
|
||||||
|
if (isEdit) {
|
||||||
|
requestBody.user_images = editExtras?.userImages ?? [];
|
||||||
|
}
|
||||||
const response = await fetch(getRegenerateUrl(threadId), {
|
const response = await fetch(getRegenerateUrl(threadId), {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(requestBody),
|
||||||
search_space_id: searchSpaceId,
|
|
||||||
user_query: newUserQuery || null,
|
|
||||||
disabled_tools: disabledTools.length > 0 ? disabledTools : undefined,
|
|
||||||
filesystem_mode: selection.filesystem_mode,
|
|
||||||
client_platform: selection.client_platform,
|
|
||||||
local_filesystem_mounts: selection.local_filesystem_mounts,
|
|
||||||
}),
|
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1536,8 +1556,10 @@ export default function NewChatPage() {
|
||||||
if (contentParts.length > 0) {
|
if (contentParts.length > 0) {
|
||||||
try {
|
try {
|
||||||
// Persist user message (for both edit and reload modes, since backend deleted it)
|
// Persist user message (for both edit and reload modes, since backend deleted it)
|
||||||
const userContentToPersist = newUserQuery
|
const userContentToPersist = isEdit
|
||||||
? [{ type: "text", text: newUserQuery }]
|
? (editExtras?.userMessageContent ?? [
|
||||||
|
{ type: "text", text: newUserQuery ?? "" },
|
||||||
|
])
|
||||||
: originalUserMessageContent || [{ type: "text", text: userQueryToDisplay || "" }];
|
: originalUserMessageContent || [{ type: "text", text: userQueryToDisplay || "" }];
|
||||||
|
|
||||||
const savedUserMessage = await appendMessage(threadId, {
|
const savedUserMessage = await appendMessage(threadId, {
|
||||||
|
|
@ -1602,21 +1624,15 @@ export default function NewChatPage() {
|
||||||
// Handle editing a message - truncates history and regenerates with new query
|
// Handle editing a message - truncates history and regenerates with new query
|
||||||
const onEdit = useCallback(
|
const onEdit = useCallback(
|
||||||
async (message: AppendMessage) => {
|
async (message: AppendMessage) => {
|
||||||
// Extract the new user query from the message content
|
const { userQuery, userImages } = extractUserTurnForNewChatApi(message, []);
|
||||||
let newUserQuery = "";
|
const queryForApi = userQuery.trim();
|
||||||
for (const part of message.content) {
|
if (!queryForApi && userImages.length === 0) {
|
||||||
if (part.type === "text") {
|
|
||||||
newUserQuery += part.text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!newUserQuery.trim()) {
|
|
||||||
toast.error("Cannot edit with empty message");
|
toast.error("Cannot edit with empty message");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call regenerate with the new query
|
const userMessageContent = message.content as unknown as ThreadMessageLike["content"];
|
||||||
await handleRegenerate(newUserQuery.trim());
|
await handleRegenerate(queryForApi, { userMessageContent, userImages });
|
||||||
},
|
},
|
||||||
[handleRegenerate]
|
[handleRegenerate]
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue