diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 13cf13605b..9f7cd98c82 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -1690,15 +1690,6 @@ async def fork_chat_by_id( history = (chat.chat or {}).get('history') or {} messages_map = await Chats.get_messages_map_by_chat_id(id) or history.get('messages') or {} - if any( - message.get('role') == 'assistant' and message.get('done') is False - for message in messages_map.values() - if isinstance(message, dict) - ): - raise HTTPException( - status_code=status.HTTP_409_CONFLICT, - detail='Wait for the current response to finish before forking.', - ) source_message_id = ( (form_data.message_id if form_data else None) or chat.current_message_id or history.get('currentId') @@ -1715,6 +1706,22 @@ async def fork_chat_by_id( detail=detail, ) from exc + # An unfinished message is stale unless it is awaiting tool approval + for message in fork_history['messages'].values(): + if message.get('role') != 'assistant' or message.get('done') is not False: + continue + + output = message.get('output') + if isinstance(output, list) and any( + isinstance(item, dict) + and item.get('type') == 'function_call' + and item.get('status') in {'pending', 'queued', 'requires_approval'} + for item in output + ): + continue + + message['done'] = True + updated_chat = {**(chat.chat or {})} updated_chat.pop('currentId', None) updated_chat.update( diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index fe577388ca..6b4f8e2e07 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -3035,11 +3035,11 @@ return; } - const currentMessage = history.messages?.[history.currentId]; + const forkedMessage = history.messages?.[messageId ?? history.currentId]; if ( generating || taskIds?.length || - (currentMessage?.role === 'assistant' && !currentMessage.done) + (forkedMessage?.role === 'assistant' && !forkedMessage.done) ) { toast.warning($i18n.t('Wait for the current response to finish before forking.')); return;