fix fork bug

This commit is contained in:
phact 2025-08-22 03:11:16 -04:00
parent be61909bed
commit e11d631702

View file

@ -70,7 +70,7 @@ interface RequestBody {
function ChatPage() { function ChatPage() {
const isDebugMode = process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_OPENRAG_DEBUG === 'true' const isDebugMode = process.env.NODE_ENV === 'development' || process.env.NEXT_PUBLIC_OPENRAG_DEBUG === 'true'
const { user } = useAuth() const { user } = useAuth()
const { endpoint, setEndpoint, refreshConversations, currentConversationId, conversationData, setCurrentConversationId, addConversationDoc } = useChat() const { endpoint, setEndpoint, refreshConversations, currentConversationId, conversationData, setCurrentConversationId, addConversationDoc, startNewConversation } = useChat()
const [messages, setMessages] = useState<Message[]>([ const [messages, setMessages] = useState<Message[]>([
{ {
role: "assistant", role: "assistant",
@ -99,6 +99,9 @@ function ChatPage() {
const [selectedFilterIndex, setSelectedFilterIndex] = useState(0) const [selectedFilterIndex, setSelectedFilterIndex] = useState(0)
const [isFilterHighlighted, setIsFilterHighlighted] = useState(false) const [isFilterHighlighted, setIsFilterHighlighted] = useState(false)
const [dropdownDismissed, setDropdownDismissed] = useState(false) const [dropdownDismissed, setDropdownDismissed] = useState(false)
const [isUserInteracting, setIsUserInteracting] = useState(false)
const [isForkingInProgress, setIsForkingInProgress] = useState(false)
const [lastForkTimestamp, setLastForkTimestamp] = useState<number>(0)
const dragCounterRef = useRef(0) const dragCounterRef = useRef(0)
const messagesEndRef = useRef<HTMLDivElement>(null) const messagesEndRef = useRef<HTMLDivElement>(null)
const inputRef = useRef<HTMLTextAreaElement>(null) const inputRef = useRef<HTMLTextAreaElement>(null)
@ -328,8 +331,15 @@ function ChatPage() {
} }
useEffect(() => { useEffect(() => {
scrollToBottom() // Only auto-scroll if not in the middle of user interaction
}, [messages, streamingMessage]) if (!isUserInteracting) {
const timer = setTimeout(() => {
scrollToBottom()
}, 50) // Small delay to avoid conflicts with click events
return () => clearTimeout(timer)
}
}, [messages, streamingMessage, isUserInteracting])
// Reset selected index when search term changes // Reset selected index when search term changes
useEffect(() => { useEffect(() => {
@ -343,7 +353,22 @@ function ChatPage() {
// Load conversation when conversationData changes // Load conversation when conversationData changes
useEffect(() => { useEffect(() => {
const now = Date.now()
// Don't reset messages if user is in the middle of an interaction (like forking)
if (isUserInteracting || isForkingInProgress) {
console.log("Skipping conversation load due to user interaction or forking")
return
}
// Don't reload if we just forked recently (within 1 second)
if (now - lastForkTimestamp < 1000) {
console.log("Skipping conversation load - recent fork detected")
return
}
if (conversationData && conversationData.messages) { if (conversationData && conversationData.messages) {
console.log("Loading conversation with", conversationData.messages.length, "messages")
// Convert backend message format to frontend Message interface // Convert backend message format to frontend Message interface
const convertedMessages: Message[] = conversationData.messages.map((msg: any) => ({ const convertedMessages: Message[] = conversationData.messages.map((msg: any) => ({
role: msg.role, role: msg.role,
@ -360,8 +385,9 @@ function ChatPage() {
[conversationData.endpoint]: conversationData.response_id [conversationData.endpoint]: conversationData.response_id
})) }))
} }
// Reset messages when starting a new conversation // Reset messages when starting a new conversation (but not during forking)
else if (currentConversationId === null) { else if (currentConversationId === null && !isUserInteracting && !isForkingInProgress && now - lastForkTimestamp > 1000) {
console.log("Resetting to default message for new conversation")
setMessages([ setMessages([
{ {
role: "assistant", role: "assistant",
@ -370,7 +396,7 @@ function ChatPage() {
} }
]) ])
} }
}, [conversationData, currentConversationId]) }, [conversationData, currentConversationId, isUserInteracting, isForkingInProgress, lastForkTimestamp])
// Listen for file upload events from navigation // Listen for file upload events from navigation
useEffect(() => { useEffect(() => {
@ -1038,7 +1064,21 @@ function ChatPage() {
}) })
} }
const handleForkConversation = (messageIndex: number) => { const handleForkConversation = (messageIndex: number, event?: React.MouseEvent) => {
// Prevent any default behavior and stop event propagation
if (event) {
event.preventDefault()
event.stopPropagation()
}
// Set interaction state to prevent auto-scroll interference
const forkTimestamp = Date.now()
setIsUserInteracting(true)
setIsForkingInProgress(true)
setLastForkTimestamp(forkTimestamp)
console.log("Fork conversation called for message index:", messageIndex)
// Get messages up to and including the selected assistant message // Get messages up to and including the selected assistant message
const messagesToKeep = messages.slice(0, messageIndex + 1) const messagesToKeep = messages.slice(0, messageIndex + 1)
@ -1046,6 +1086,9 @@ function ChatPage() {
const forkedMessage = messages[messageIndex] const forkedMessage = messages[messageIndex]
if (forkedMessage.role !== 'assistant') { if (forkedMessage.role !== 'assistant') {
console.error('Fork button should only be on assistant messages') console.error('Fork button should only be on assistant messages')
setIsUserInteracting(false)
setIsForkingInProgress(false)
setLastForkTimestamp(0)
return return
} }
@ -1059,6 +1102,8 @@ function ChatPage() {
setMessages(messagesToKeep) setMessages(messagesToKeep)
setCurrentConversationId(null) // This creates a new conversation thread setCurrentConversationId(null) // This creates a new conversation thread
// We'll handle clearing conversation data differently
// Set the response_id we want to continue from as the previous response ID // Set the response_id we want to continue from as the previous response ID
// This tells the backend to continue the conversation from this point // This tells the backend to continue the conversation from this point
setPreviousResponseIds(prev => ({ setPreviousResponseIds(prev => ({
@ -1066,6 +1111,15 @@ function ChatPage() {
[endpoint]: responseIdToForkFrom [endpoint]: responseIdToForkFrom
})) }))
console.log("Forked conversation with", messagesToKeep.length, "messages")
// Reset interaction state after a longer delay to ensure all effects complete
setTimeout(() => {
setIsUserInteracting(false)
setIsForkingInProgress(false)
console.log("Fork interaction complete, re-enabling auto effects")
}, 500)
// The original conversation remains unchanged in the sidebar // The original conversation remains unchanged in the sidebar
// This new forked conversation will get its own response_id when the user sends the next message // This new forked conversation will get its own response_id when the user sends the next message
} }
@ -1402,7 +1456,7 @@ function ChatPage() {
</div> </div>
<div className="flex-shrink-0 ml-2"> <div className="flex-shrink-0 ml-2">
<button <button
onClick={() => handleForkConversation(index)} onClick={(e) => handleForkConversation(index, e)}
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground" className="opacity-0 group-hover:opacity-100 transition-opacity p-1 hover:bg-accent rounded text-muted-foreground hover:text-foreground"
title="Fork conversation from here" title="Fork conversation from here"
> >