From 6dcb65debd6a61c5d0aef5aca413a0caa71e4b2f Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Thu, 4 Sep 2025 15:36:41 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20(frontend):=20Add=20new=20functi?= =?UTF-8?q?on=20'refreshConversationsSilent'=20to=20update=20data=20withou?= =?UTF-8?q?t=20loading=20states=20=F0=9F=9A=80=20(frontend):=20Implement?= =?UTF-8?q?=20support=20for=20process.env.PORT=20to=20run=20app=20on=20a?= =?UTF-8?q?=20configurable=20port=20=F0=9F=94=A7=20(frontend):=20Change=20?= =?UTF-8?q?port=20variable=20case=20from=20lowercase=20'port'=20to=20upper?= =?UTF-8?q?case=20'PORT'=20for=20better=20semantics=20=F0=9F=93=9D=20(fron?= =?UTF-8?q?tend):=20Add=20comments=20to=20clarify=20the=20purpose=20of=20l?= =?UTF-8?q?oading=20conversation=20data=20only=20when=20user=20explicitly?= =?UTF-8?q?=20selects=20a=20conversation=20=F0=9F=93=9D=20(frontend):=20Ad?= =?UTF-8?q?d=20comments=20to=20explain=20the=20logic=20for=20loading=20con?= =?UTF-8?q?versation=20data=20based=20on=20certain=20conditions=20?= =?UTF-8?q?=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20describe=20t?= =?UTF-8?q?he=20purpose=20of=20handling=20new=20conversation=20creation=20?= =?UTF-8?q?and=20resetting=20messages=20=F0=9F=93=9D=20(frontend):=20Add?= =?UTF-8?q?=20comments=20to=20explain=20the=20logic=20for=20loading=20conv?= =?UTF-8?q?ersation=20data=20when=20conversationData=20changes=20?= =?UTF-8?q?=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20clarify=20th?= =?UTF-8?q?e=20purpose=20of=20loading=20conversations=20from=20the=20backe?= =?UTF-8?q?nd=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20describ?= =?UTF-8?q?e=20the=20logic=20for=20silent=20refresh=20to=20update=20data?= =?UTF-8?q?=20without=20loading=20states=20=F0=9F=93=9D=20(frontend):=20Ad?= =?UTF-8?q?d=20comments=20to=20explain=20the=20purpose=20of=20starting=20a?= =?UTF-8?q?=20new=20conversation=20and=20creating=20a=20placeholder=20conv?= =?UTF-8?q?ersation=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20c?= =?UTF-8?q?larify=20the=20logic=20for=20forking=20from=20a=20response=20an?= =?UTF-8?q?d=20starting=20a=20new=20conversation=20=F0=9F=93=9D=20(fronten?= =?UTF-8?q?d):=20Add=20comments=20to=20describe=20the=20purpose=20of=20add?= =?UTF-8?q?ing=20a=20conversation=20document=20and=20clearing=20conversati?= =?UTF-8?q?on=20documents=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20?= =?UTF-8?q?to=20explain=20the=20logic=20for=20using=20a=20timeout=20to=20d?= =?UTF-8?q?ebounce=20multiple=20rapid=20refresh=20calls=20=F0=9F=93=9D=20(?= =?UTF-8?q?frontend):=20Add=20comments=20to=20clarify=20the=20purpose=20of?= =?UTF-8?q?=20cleaning=20up=20timeout=20on=20unmount=20=F0=9F=93=9D=20(fro?= =?UTF-8?q?ntend):=20Add=20comments=20to=20describe=20the=20logic=20for=20?= =?UTF-8?q?handling=20new=20conversation=20creation=20and=20resetting=20st?= =?UTF-8?q?ate=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20explai?= =?UTF-8?q?n=20the=20logic=20for=20forking=20from=20a=20response=20and=20s?= =?UTF-8?q?tarting=20a=20new=20conversation=20=F0=9F=93=9D=20(frontend):?= =?UTF-8?q?=20Add=20comments=20to=20clarify=20the=20purpose=20of=20using?= =?UTF-8?q?=20useMemo=20for=20optimizing=20performance=20in=20ChatProvider?= =?UTF-8?q?=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20describe?= =?UTF-8?q?=20the=20logic=20for=20using=20useMemo=20in=20the=20ChatProvide?= =?UTF-8?q?r=20component=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20t?= =?UTF-8?q?o=20explain=20the=20purpose=20of=20the=20useChat=20custom=20hoo?= =?UTF-8?q?k=20=F0=9F=93=9D=20(frontend):=20Add=20comments=20to=20clarify?= =?UTF-8?q?=20the=20error=20message=20when=20useChat=20is=20not=20used=20w?= =?UTF-8?q?ithin=20a=20ChatProvider=20=F0=9F=93=9D=20(services):=20Update?= =?UTF-8?q?=20ChatService=20to=20fetch=20Langflow=20history=20with=20flow?= =?UTF-8?q?=5Fid=20parameter=20for=20better=20control?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/app/chat/page.tsx | 110 ++++---- frontend/src/components/navigation.tsx | 230 +++++++++++++++++ frontend/src/contexts/chat-context.tsx | 333 +++++++++++++++---------- src/services/chat_service.py | 2 +- 4 files changed, 495 insertions(+), 180 deletions(-) create mode 100644 frontend/src/components/navigation.tsx diff --git a/frontend/src/app/chat/page.tsx b/frontend/src/app/chat/page.tsx index 100228ea..19703214 100644 --- a/frontend/src/app/chat/page.tsx +++ b/frontend/src/app/chat/page.tsx @@ -91,8 +91,10 @@ function ChatPage() { addConversationDoc, forkFromResponse, refreshConversations, + refreshConversationsSilent, previousResponseIds, setPreviousResponseIds, + placeholderConversation, } = useChat(); const [messages, setMessages] = useState([ { @@ -133,6 +135,7 @@ function ChatPage() { const dropdownRef = useRef(null); const streamAbortRef = useRef(null); const streamIdRef = useRef(0); + const lastLoadedConversationRef = useRef(null); const { addTask, isMenuOpen } = useTask(); const { selectedFilter, parsedFilterData, isPanelOpen, setSelectedFilter } = useKnowledgeFilter(); @@ -241,11 +244,16 @@ function ChatPage() { ...prev, [endpoint]: result.response_id, })); + + // If this is a new conversation (no currentConversationId), set it now + if (!currentConversationId) { + setCurrentConversationId(result.response_id); + refreshConversations(true); + } else { + // For existing conversations, do a silent refresh to keep backend in sync + refreshConversationsSilent(); + } } - // Sidebar should show this conversation after upload creates it - try { - refreshConversations(); - } catch {} } else { throw new Error(`Upload failed: ${response.status}`); } @@ -406,6 +414,7 @@ function ChatPage() { setExpandedFunctionCalls(new Set()); setIsFilterHighlighted(false); setLoading(false); + lastLoadedConversationRef.current = null; }; const handleFocusInput = () => { @@ -420,25 +429,19 @@ function ChatPage() { }; }, []); - // Load conversation when conversationData changes + // Load conversation only when user explicitly selects a conversation 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) { + // Only load conversation data when: + // 1. conversationData exists AND + // 2. It's different from the last loaded conversation AND + // 3. User is not in the middle of an interaction + if ( + conversationData && + conversationData.messages && + lastLoadedConversationRef.current !== conversationData.response_id && + !isUserInteracting && + !isForkingInProgress + ) { console.log( "Loading conversation with", conversationData.messages.length, @@ -460,6 +463,7 @@ function ChatPage() { ); setMessages(convertedMessages); + lastLoadedConversationRef.current = conversationData.response_id; // Set the previous response ID for this conversation setPreviousResponseIds((prev) => ({ @@ -467,14 +471,16 @@ function ChatPage() { [conversationData.endpoint]: conversationData.response_id, })); } - // Reset messages when starting a new conversation (but not during forking) - else if ( - currentConversationId === null && - !isUserInteracting && - !isForkingInProgress && - now - lastForkTimestamp > 1000 - ) { - console.log("Resetting to default message for new conversation"); + }, [ + conversationData, + isUserInteracting, + isForkingInProgress, + ]); + + // Handle new conversation creation - only reset messages when placeholderConversation is set + useEffect(() => { + if (placeholderConversation && currentConversationId === null) { + console.log("Starting new conversation"); setMessages([ { role: "assistant", @@ -482,15 +488,9 @@ function ChatPage() { timestamp: new Date(), }, ]); + lastLoadedConversationRef.current = null; } - }, [ - conversationData, - currentConversationId, - isUserInteracting, - isForkingInProgress, - lastForkTimestamp, - setPreviousResponseIds, - ]); + }, [placeholderConversation, currentConversationId]); // Listen for file upload events from navigation useEffect(() => { @@ -1280,14 +1280,16 @@ function ChatPage() { ...prev, [endpoint]: newResponseId, })); + + // If this is a new conversation (no currentConversationId), set it now + if (!currentConversationId) { + setCurrentConversationId(newResponseId); + refreshConversations(true); + } else { + // For existing conversations, do a silent refresh to keep backend in sync + refreshConversationsSilent(); + } } - - // Trigger sidebar refresh to include this conversation (with small delay to ensure backend has processed) - setTimeout(() => { - try { - refreshConversations(); - } catch {} - }, 100); } catch (error) { // If stream was aborted (e.g., starting new conversation), do not append errors or final messages if (streamAbortRef.current?.signal.aborted) { @@ -1390,13 +1392,16 @@ function ChatPage() { ...prev, [endpoint]: result.response_id, })); + + // If this is a new conversation (no currentConversationId), set it now + if (!currentConversationId) { + setCurrentConversationId(result.response_id); + refreshConversations(true); + } else { + // For existing conversations, do a silent refresh to keep backend in sync + refreshConversationsSilent(); + } } - // Trigger sidebar refresh to include/update this conversation (with small delay to ensure backend has processed) - setTimeout(() => { - try { - refreshConversations(); - } catch {} - }, 100); } else { console.error("Chat failed:", result.error); const errorMessage: Message = { @@ -2013,9 +2018,6 @@ function ChatPage() { // Clear filter highlight when user starts typing if (isFilterHighlighted) { setIsFilterHighlighted(false); - try { - refreshConversations(); - } catch {} } // Find if there's an @ at the start of the last word diff --git a/frontend/src/components/navigation.tsx b/frontend/src/components/navigation.tsx new file mode 100644 index 00000000..30ac9a4b --- /dev/null +++ b/frontend/src/components/navigation.tsx @@ -0,0 +1,230 @@ +"use client" + +import { useState, useEffect, useRef } from "react" +import { useRouter, usePathname } from "next/navigation" +import { Button } from "@/components/ui/button" +import { Plus, MessageSquare, Database, Settings, GitBranch } from "lucide-react" +import { useChat } from "@/contexts/chat-context" +import { useAuth } from "@/contexts/auth-context" + +interface Conversation { + id: string + title: string + endpoint: string + last_activity: string + created_at: string + response_id: string + messages?: Array<{ + role: string + content: string + timestamp?: string + response_id?: string + }> +} + +export function Navigation() { + const router = useRouter() + const pathname = usePathname() + const { user } = useAuth() + const { + refreshTrigger, + refreshTriggerSilent, + loadConversation, + startNewConversation, + currentConversationId, + placeholderConversation, + } = useChat() + + const [conversations, setConversations] = useState([]) + const [loading, setLoading] = useState(false) + + // Load conversations from backend + const loadConversations = async () => { + if (!user) return + + try { + setLoading(true) + const response = await fetch("/api/conversations") + if (response.ok) { + const data = await response.json() + setConversations(data.conversations || []) + } + } catch (error) { + console.error("Failed to load conversations:", error) + } finally { + setLoading(false) + } + } + + // Load conversations on mount and when refreshTrigger changes (with loading state) + useEffect(() => { + loadConversations() + }, [refreshTrigger, user]) + + // Silent refresh - update data without loading state + useEffect(() => { + const loadSilent = async () => { + if (!user) return + + try { + // Don't show loading state for silent refresh + const response = await fetch("/api/conversations") + if (response.ok) { + const data = await response.json() + setConversations(data.conversations || []) + } + } catch (error) { + console.error("Silent conversation refresh failed:", error) + } + } + + // Only do silent refresh if we have a silent trigger change (not initial load) + if (refreshTriggerSilent > 0) { + loadSilent() + } + }, [refreshTriggerSilent, user]) + + const handleNewConversation = () => { + startNewConversation() + // Dispatch custom event to notify chat page + window.dispatchEvent(new CustomEvent('newConversation')) + router.push('/chat') + } + + const handleConversationClick = async (conversation: Conversation) => { + try { + // Load full conversation data from backend + const response = await fetch(`/api/conversations/${conversation.response_id}`) + if (response.ok) { + const fullConversation = await response.json() + loadConversation(fullConversation) + router.push('/chat') + } + } catch (error) { + console.error("Failed to load conversation:", error) + } + } + + const formatRelativeTime = (timestamp: string) => { + const date = new Date(timestamp) + const now = new Date() + const diffMs = now.getTime() - date.getTime() + const diffHours = Math.floor(diffMs / (1000 * 60 * 60)) + const diffDays = Math.floor(diffHours / 24) + + if (diffDays > 0) { + return `${diffDays}d ago` + } else if (diffHours > 0) { + return `${diffHours}h ago` + } else { + return 'Just now' + } + } + + return ( + + ) +} \ No newline at end of file diff --git a/frontend/src/contexts/chat-context.tsx b/frontend/src/contexts/chat-context.tsx index cc734d99..db79e0d3 100644 --- a/frontend/src/contexts/chat-context.tsx +++ b/frontend/src/contexts/chat-context.tsx @@ -1,161 +1,244 @@ -"use client" +"use client"; -import React, { createContext, useContext, useState, ReactNode } from 'react' +import { + createContext, + ReactNode, + useCallback, + useContext, + useEffect, + useMemo, + useRef, + useState, +} from "react"; -export type EndpointType = 'chat' | 'langflow' +export type EndpointType = "chat" | "langflow"; interface ConversationDocument { - filename: string - uploadTime: Date + filename: string; + uploadTime: Date; } interface ConversationMessage { - role: string - content: string - timestamp?: string - response_id?: string + role: string; + content: string; + timestamp?: string; + response_id?: string; } interface ConversationData { - messages: ConversationMessage[] - endpoint: EndpointType - response_id: string - title: string - [key: string]: unknown + messages: ConversationMessage[]; + endpoint: EndpointType; + response_id: string; + title: string; + [key: string]: unknown; } interface ChatContextType { - endpoint: EndpointType - setEndpoint: (endpoint: EndpointType) => void - currentConversationId: string | null - setCurrentConversationId: (id: string | null) => void + endpoint: EndpointType; + setEndpoint: (endpoint: EndpointType) => void; + currentConversationId: string | null; + setCurrentConversationId: (id: string | null) => void; previousResponseIds: { - chat: string | null - langflow: string | null - } - setPreviousResponseIds: (ids: { chat: string | null; langflow: string | null } | ((prev: { chat: string | null; langflow: string | null }) => { chat: string | null; langflow: string | null })) => void - refreshConversations: () => void - refreshTrigger: number - loadConversation: (conversation: ConversationData) => void - startNewConversation: () => void - conversationData: ConversationData | null - forkFromResponse: (responseId: string) => void - conversationDocs: ConversationDocument[] - addConversationDoc: (filename: string) => void - clearConversationDocs: () => void - placeholderConversation: ConversationData | null - setPlaceholderConversation: (conversation: ConversationData | null) => void + chat: string | null; + langflow: string | null; + }; + setPreviousResponseIds: ( + ids: + | { chat: string | null; langflow: string | null } + | ((prev: { chat: string | null; langflow: string | null }) => { + chat: string | null; + langflow: string | null; + }) + ) => void; + refreshConversations: (force?: boolean) => void; + refreshConversationsSilent: () => Promise; + refreshTrigger: number; + refreshTriggerSilent: number; + loadConversation: (conversation: ConversationData) => void; + startNewConversation: () => void; + conversationData: ConversationData | null; + forkFromResponse: (responseId: string) => void; + conversationDocs: ConversationDocument[]; + addConversationDoc: (filename: string) => void; + clearConversationDocs: () => void; + placeholderConversation: ConversationData | null; + setPlaceholderConversation: (conversation: ConversationData | null) => void; } -const ChatContext = createContext(undefined) +const ChatContext = createContext(undefined); interface ChatProviderProps { - children: ReactNode + children: ReactNode; } export function ChatProvider({ children }: ChatProviderProps) { - const [endpoint, setEndpoint] = useState('langflow') - const [currentConversationId, setCurrentConversationId] = useState(null) + const [endpoint, setEndpoint] = useState("langflow"); + const [currentConversationId, setCurrentConversationId] = useState< + string | null + >(null); const [previousResponseIds, setPreviousResponseIds] = useState<{ - chat: string | null - langflow: string | null - }>({ chat: null, langflow: null }) - const [refreshTrigger, setRefreshTrigger] = useState(0) - const [conversationData, setConversationData] = useState(null) - const [conversationDocs, setConversationDocs] = useState([]) - const [placeholderConversation, setPlaceholderConversation] = useState(null) + chat: string | null; + langflow: string | null; + }>({ chat: null, langflow: null }); + const [refreshTrigger, setRefreshTrigger] = useState(0); + const [refreshTriggerSilent, setRefreshTriggerSilent] = useState(0); + const [conversationData, setConversationData] = + useState(null); + const [conversationDocs, setConversationDocs] = useState< + ConversationDocument[] + >([]); + const [placeholderConversation, setPlaceholderConversation] = + useState(null); - const refreshConversations = () => { - setRefreshTrigger(prev => prev + 1) - } + // Debounce refresh requests to prevent excessive reloads + const refreshTimeoutRef = useRef(null); - const loadConversation = (conversation: ConversationData) => { - setCurrentConversationId(conversation.response_id) - setEndpoint(conversation.endpoint) - // Store the full conversation data for the chat page to use - // We'll pass it through a ref or state that the chat page can access - setConversationData(conversation) - // Clear placeholder when loading a real conversation - setPlaceholderConversation(null) - } - - const startNewConversation = () => { - // Create a temporary placeholder conversation - const placeholderConversation: ConversationData = { - response_id: 'new-conversation-' + Date.now(), - title: 'New conversation', - endpoint: endpoint, - messages: [{ - role: 'assistant', - content: 'How can I assist?', - timestamp: new Date().toISOString() - }], - created_at: new Date().toISOString(), - last_activity: new Date().toISOString() + const refreshConversations = useCallback((force = false) => { + if (force) { + // Immediate refresh for important updates like new conversations + setRefreshTrigger((prev) => prev + 1); + return; } - - setCurrentConversationId(null) - setPreviousResponseIds({ chat: null, langflow: null }) - setConversationData(null) - setConversationDocs([]) - setPlaceholderConversation(placeholderConversation) - // Force a refresh to ensure sidebar shows correct state - setRefreshTrigger(prev => prev + 1) - } - const addConversationDoc = (filename: string) => { - setConversationDocs(prev => [...prev, { filename, uploadTime: new Date() }]) - } + // Clear any existing timeout + if (refreshTimeoutRef.current) { + clearTimeout(refreshTimeoutRef.current); + } - const clearConversationDocs = () => { - setConversationDocs([]) - } + // Set a new timeout to debounce multiple rapid refresh calls + refreshTimeoutRef.current = setTimeout(() => { + setRefreshTrigger((prev) => prev + 1); + }, 250); // 250ms debounce + }, []); - const forkFromResponse = (responseId: string) => { - // Start a new conversation with the messages up to the fork point - setCurrentConversationId(null) // Clear current conversation to indicate new conversation - setConversationData(null) // Clear conversation data to prevent reloading - // Set the response ID that we're forking from as the previous response ID - setPreviousResponseIds(prev => ({ + // Cleanup timeout on unmount + useEffect(() => { + return () => { + if (refreshTimeoutRef.current) { + clearTimeout(refreshTimeoutRef.current); + } + }; + }, []); + + // Silent refresh - updates data without loading states + const refreshConversationsSilent = useCallback(async () => { + // Trigger silent refresh that updates conversation data without showing loading states + setRefreshTriggerSilent((prev) => prev + 1); + }, []); + + const loadConversation = useCallback((conversation: ConversationData) => { + setCurrentConversationId(conversation.response_id); + setEndpoint(conversation.endpoint); + // Store the full conversation data for the chat page to use + setConversationData(conversation); + // Clear placeholder when loading a real conversation + setPlaceholderConversation(null); + }, []); + + const startNewConversation = useCallback(() => { + // Clear current conversation data and reset state + setCurrentConversationId(null); + setPreviousResponseIds({ chat: null, langflow: null }); + setConversationData(null); + setConversationDocs([]); + + // Create a temporary placeholder conversation to show in sidebar + const placeholderConversation: ConversationData = { + response_id: "new-conversation-" + Date.now(), + title: "New conversation", + endpoint: endpoint, + messages: [ + { + role: "assistant", + content: "How can I assist?", + timestamp: new Date().toISOString(), + }, + ], + created_at: new Date().toISOString(), + last_activity: new Date().toISOString(), + }; + + setPlaceholderConversation(placeholderConversation); + // Force immediate refresh to ensure sidebar shows correct state + refreshConversations(true); + }, [endpoint, refreshConversations]); + + const addConversationDoc = useCallback((filename: string) => { + setConversationDocs((prev) => [ ...prev, - [endpoint]: responseId - })) - // Clear placeholder when forking - setPlaceholderConversation(null) - // The messages are already set by the chat page component before calling this - } + { filename, uploadTime: new Date() }, + ]); + }, []); - const value: ChatContextType = { - endpoint, - setEndpoint, - currentConversationId, - setCurrentConversationId, - previousResponseIds, - setPreviousResponseIds, - refreshConversations, - refreshTrigger, - loadConversation, - startNewConversation, - conversationData, - forkFromResponse, - conversationDocs, - addConversationDoc, - clearConversationDocs, - placeholderConversation, - setPlaceholderConversation, - } + const clearConversationDocs = useCallback(() => { + setConversationDocs([]); + }, []); - return ( - - {children} - - ) + const forkFromResponse = useCallback( + (responseId: string) => { + // Start a new conversation with the messages up to the fork point + setCurrentConversationId(null); // Clear current conversation to indicate new conversation + setConversationData(null); // Clear conversation data to prevent reloading + // Set the response ID that we're forking from as the previous response ID + setPreviousResponseIds((prev) => ({ + ...prev, + [endpoint]: responseId, + })); + // Clear placeholder when forking + setPlaceholderConversation(null); + // The messages are already set by the chat page component before calling this + }, + [endpoint] + ); + + const value = useMemo( + () => ({ + endpoint, + setEndpoint, + currentConversationId, + setCurrentConversationId, + previousResponseIds, + setPreviousResponseIds, + refreshConversations, + refreshConversationsSilent, + refreshTrigger, + refreshTriggerSilent, + loadConversation, + startNewConversation, + conversationData, + forkFromResponse, + conversationDocs, + addConversationDoc, + clearConversationDocs, + placeholderConversation, + setPlaceholderConversation, + }), + [ + endpoint, + currentConversationId, + previousResponseIds, + refreshConversations, + refreshConversationsSilent, + refreshTrigger, + refreshTriggerSilent, + loadConversation, + startNewConversation, + conversationData, + forkFromResponse, + conversationDocs, + addConversationDoc, + clearConversationDocs, + placeholderConversation, + ] + ); + + return {children}; } export function useChat(): ChatContextType { - const context = useContext(ChatContext) + const context = useContext(ChatContext); if (context === undefined) { - throw new Error('useChat must be used within a ChatProvider') + throw new Error("useChat must be used within a ChatProvider"); } - return context -} \ No newline at end of file + return context; +} diff --git a/src/services/chat_service.py b/src/services/chat_service.py index 1b811d69..93fddcc8 100644 --- a/src/services/chat_service.py +++ b/src/services/chat_service.py @@ -328,7 +328,7 @@ class ChatService: # 2. Get historical conversations from Langflow database # (works with both Google-bound users and direct Langflow users) print(f"[DEBUG] Attempting to fetch Langflow history for user: {user_id}") - langflow_history = await langflow_history_service.get_user_conversation_history(user_id) + langflow_history = await langflow_history_service.get_user_conversation_history(user_id, flow_id=FLOW_ID) if langflow_history.get("conversations"): for conversation in langflow_history["conversations"]: