diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts
index b4bc2e002c..64d2960dbf 100644
--- a/src/lib/apis/chats/index.ts
+++ b/src/lib/apis/chats/index.ts
@@ -920,6 +920,47 @@ export const cloneChatById = async (token: string, id: string, title?: string) =
return res;
};
+export const forkChatById = async (token: string, id: string, messageId?: string | null) => {
+ let error = null;
+
+ const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}/fork`, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json',
+ ...(token && { authorization: `Bearer ${token}` })
+ },
+ body: JSON.stringify({
+ message_id: messageId ?? null
+ })
+ })
+ .then(async (res) => {
+ if (!res.ok) throw await res.json();
+ return res.json();
+ })
+ .then((json) => {
+ return json;
+ })
+ .catch((err) => {
+ error = err;
+
+ if ('detail' in err) {
+ error = err.detail;
+ } else {
+ error = err;
+ }
+
+ console.error(err);
+ return null;
+ });
+
+ if (error) {
+ throw error;
+ }
+
+ return res;
+};
+
export const cloneSharedChatById = async (token: string, id: string) => {
let error = null;
diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte
index 08bde0bc9f..d059846625 100644
--- a/src/lib/components/chat/Chat.svelte
+++ b/src/lib/components/chat/Chat.svelte
@@ -70,10 +70,10 @@
import {
archiveChatById,
- cloneChatById,
compactChatById,
createNewChat,
deleteChatById,
+ forkChatById,
getAllTags,
getChatById,
getTagsById,
@@ -1884,6 +1884,9 @@
(chatContent?.history ?? undefined) !== undefined
? chatContent.history
: convertMessagesToHistory(chatContent.messages);
+ if (chat?.current_message_id && history?.messages?.[chat.current_message_id]) {
+ history.currentId = chat.current_message_id;
+ }
// Sanitize history: repair orphaned references and structurally-malformed
// nodes from failed regenerations (#24424, #24157, #20474)
@@ -2466,7 +2469,7 @@
document.getElementById('chat-input')?.focus();
};
- const handleForkChat = async () => {
+ const handleForkChat = async (messageId: string | null = null) => {
if (!$chatId || !history?.currentId) {
toast.message($i18n.t('No chat to fork'));
return;
@@ -2489,13 +2492,7 @@
const toastId = toast.loading($i18n.t('Forking chat...'));
try {
- const result = await cloneChatById(
- localStorage.token,
- $chatId,
- $i18n.t('Clone of {{TITLE}}', {
- TITLE: $chatTitle || 'Chat'
- })
- );
+ const result = await forkChatById(localStorage.token, $chatId, messageId ?? history.currentId);
if (result?.id) {
if (!embedded) {
@@ -3725,6 +3722,7 @@
{mergeResponses}
{chatActionHandler}
{addMessages}
+ forkHandler={generating || taskIds?.length ? null : handleForkChat}
topPadding={!embedded}
bottomPadding={files.length > 0}
{onSelect}
diff --git a/src/lib/components/chat/MessageInput/Commands/SlashCommands.svelte b/src/lib/components/chat/MessageInput/Commands/SlashCommands.svelte
index 084379ac90..75ec04ee1a 100644
--- a/src/lib/components/chat/MessageInput/Commands/SlashCommands.svelte
+++ b/src/lib/components/chat/MessageInput/Commands/SlashCommands.svelte
@@ -183,10 +183,10 @@
{:else if item.data.id === 'fork'}
-
+
diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte
index 9322175b7c..0adb4a027a 100644
--- a/src/lib/components/chat/Messages.svelte
+++ b/src/lib/components/chat/Messages.svelte
@@ -40,6 +40,7 @@
export let showMessage: Function = () => {};
export let submitMessage: Function = () => {};
export let addMessages: Function = () => {};
+ export let forkHandler: Function | null = null;
export let readOnly = false;
export let editCodeBlock = true;
@@ -539,6 +540,7 @@
{continueResponse}
{mergeResponses}
{addMessages}
+ {forkHandler}
{triggerScroll}
{readOnly}
{editCodeBlock}
diff --git a/src/lib/components/chat/Messages/Message.svelte b/src/lib/components/chat/Messages/Message.svelte
index 5fb9a399da..0b18ca2d9f 100644
--- a/src/lib/components/chat/Messages/Message.svelte
+++ b/src/lib/components/chat/Messages/Message.svelte
@@ -39,6 +39,7 @@
export let mergeResponses;
export let addMessages;
+ export let forkHandler: Function | null = null;
export let triggerScroll;
export let readOnly = false;
export let editCodeBlock = true;
@@ -97,6 +98,7 @@
{continueResponse}
{regenerateResponse}
{addMessages}
+ {forkHandler}
{readOnly}
{editCodeBlock}
{topPadding}
@@ -122,6 +124,7 @@
{mergeResponses}
{triggerScroll}
{addMessages}
+ {forkHandler}
{readOnly}
{editCodeBlock}
{topPadding}
diff --git a/src/lib/components/chat/Messages/MultiResponseMessages.svelte b/src/lib/components/chat/Messages/MultiResponseMessages.svelte
index a58f6bd9a9..6223cf8338 100644
--- a/src/lib/components/chat/Messages/MultiResponseMessages.svelte
+++ b/src/lib/components/chat/Messages/MultiResponseMessages.svelte
@@ -45,6 +45,7 @@
export let mergeResponses: Function;
export let addMessages: Function;
+ export let forkHandler: Function | null = null;
export let triggerScroll: Function;
@@ -319,6 +320,7 @@
groupedMessageIds[selectedModelIdx].messageIds.length - 1;
}}
{addMessages}
+ {forkHandler}
{readOnly}
{topPadding}
{onInsertToNote}
@@ -376,6 +378,7 @@
groupedMessageIds[modelIdx].messageIds.length - 1;
}}
{addMessages}
+ {forkHandler}
{readOnly}
{editCodeBlock}
{topPadding}
diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte
index 11b71eaae0..36d05bc37b 100644
--- a/src/lib/components/chat/Messages/ResponseMessage.svelte
+++ b/src/lib/components/chat/Messages/ResponseMessage.svelte
@@ -159,6 +159,7 @@
export let submitMessage: Function;
export let continueResponse: Function;
export let regenerateResponse: Function;
+ export let forkHandler: Function | null = null;
export let addMessages: Function;
@@ -1054,6 +1055,37 @@
+ {#if message.done && !readOnly && forkHandler}
+
+
+
+ {/if}
+
{#if onInsertToNote && visibleResponseContent}