UNPKG

langflow-chatbot

Version:

Add a Langflow-powered chatbot to your website.

179 lines (178 loc) 9.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChatSessionManager = void 0; const datetimeUtils_1 = require("../utils/datetimeUtils"); /** * Manages chat sessions, including session ID state and chat history loading/display. */ class ChatSessionManager { /** * Constructs a ChatSessionManager instance. * @param client The LangflowChatClient for API interactions. * @param config Configuration for sender names. * @param displayCallbacks Callbacks for UI display operations. * @param logger Logger instance. * @param initialSessionId Optional initial session ID to load history for. * @param welcomeMessage Optional message to display if chat history is empty. */ constructor(client, config, displayCallbacks, logger, initialSessionId, welcomeMessage) { this._currentSessionId = null; this._isHistoryLoaded = false; this.client = client; this.config = config; this.displayCallbacks = displayCallbacks; this.logger = logger; this.welcomeMessage = welcomeMessage; if (initialSessionId) { this.logger.info(`ChatSessionManager: Initializing with session ID: ${initialSessionId}`); this.updateCurrentSessionId(initialSessionId); // Sets _currentSessionId and resets _isHistoryLoaded // Auto-load history if an initial session ID is provided. // The check for _isHistoryLoaded is implicitly false here due to updateCurrentSessionId. this.setSessionIdAndLoadHistory(initialSessionId); } else { this.logger.info("ChatSessionManager: Initialized without a session ID."); // If no initial session ID, and there's a welcome message, display it. // Ensure messages are cleared first, as there's no history to load that would do it. this.displayCallbacks.clearMessages(); if (this.welcomeMessage) { this.displayCallbacks.addMessage(this.config.botSender, this.welcomeMessage, false); this.displayCallbacks.scrollChatToBottom(); } this._isHistoryLoaded = true; // Mark as "loaded" as we've handled the initial state. } } /** Gets the current session ID. */ get currentSessionId() { return this._currentSessionId; } /** Indicates if the history for the current session has been loaded. */ get isHistoryLoaded() { return this._isHistoryLoaded; } /** * Updates the current session ID and resets the history loaded flag. * @param newSessionId The new session ID, or null to clear the session. */ updateCurrentSessionId(newSessionId) { const oldSessionId = this._currentSessionId; if (newSessionId && oldSessionId !== newSessionId) { this._currentSessionId = newSessionId; this._isHistoryLoaded = false; // Reset flag when session ID changes this.logger.info(`Session ID updated to: ${this._currentSessionId}`); } else if (newSessionId === null && oldSessionId !== null) { this._currentSessionId = null; this._isHistoryLoaded = false; // Reset flag when session is cleared this.logger.info("Session ID cleared."); } } /** * Processes a session ID update that originated from a flow response. * This typically updates the internal session ID but does not automatically trigger history loading, * as the flow itself might manage message display or further interactions. * @param newSessionId The new session ID from the flow. */ processSessionIdUpdateFromFlow(newSessionId) { this.logger.info(`ChatSessionManager: Session ID update from flow: ${newSessionId}`); if (this._currentSessionId !== newSessionId) { this.updateCurrentSessionId(newSessionId); } } /** * Loads and displays chat history messages. * This method clears existing messages before displaying the new history. * It determines sender types based on configuration and message data. * @param history An array of ChatMessageData objects representing the history. */ async loadAndDisplayHistory(history) { if (this._isHistoryLoaded && history.length === 0 && !this.currentSessionId) { // This case is less common if setSessionIdAndLoadHistory is the main entry point. // Allows re-check if history was empty & no session, then session appears. } else if (this._isHistoryLoaded) { this.logger.info("History already loaded or loading process was completed for the current session."); return; } this.logger.info("Loading and displaying history..."); this.displayCallbacks.clearMessages(); for (const rawMessage of history) { const messageText = rawMessage.text || ""; let senderType; const rawSenderLower = rawMessage.sender?.toLowerCase(); // Determine sender type, prioritizing configured names, then common keywords, then fallbacks. if (rawMessage.sender_name === this.config.userSender) { senderType = this.config.userSender; } else if (rawMessage.sender_name === this.config.botSender) { senderType = this.config.botSender; } else if (rawSenderLower === 'user') { senderType = this.config.userSender; } else if (rawSenderLower === 'bot' || rawSenderLower === 'machine') { // 'machine' is another common term for bot senderType = this.config.botSender; } else if (rawMessage.sender_name) { senderType = rawMessage.sender_name; // Use sender_name if available but didn't match known config } else { senderType = this.config.systemSender; // Ultimate fallback this.logger.warn(`Unidentified sender in history: rawMessage.sender='${rawMessage.sender}', rawMessage.sender_name='${rawMessage.sender_name}'. Defaulting to systemSender.`); } const normalizedTimestamp = (0, datetimeUtils_1.normalizeLangflowTimestamp)(rawMessage.timestamp); this.displayCallbacks.addMessage(senderType, messageText, false, // History messages are not "thinking" indicators normalizedTimestamp); } this._isHistoryLoaded = true; this.displayCallbacks.scrollChatToBottom(); this.logger.info("History loaded and displayed."); } /** * Sets the session ID and loads/displays its history. * If no session ID is provided (or it's empty), the current session is cleared. * @param sessionId The session ID to set. If undefined or empty, clears the session. */ async setSessionIdAndLoadHistory(sessionId) { if (sessionId && sessionId.trim() !== "") { if (this._currentSessionId !== sessionId || !this._isHistoryLoaded) { this.logger.info(`Setting session ID to: ${sessionId} and loading history.`); this.updateCurrentSessionId(sessionId); // Updates ID and resets history loaded flag try { const historyData = await this.client.getMessageHistory(sessionId); if (historyData && historyData.length > 0) { await this.loadAndDisplayHistory(historyData); } else { this.logger.info("No history data found for the session, or history is empty."); this.displayCallbacks.clearMessages(); // Clear display if history is empty if (this.welcomeMessage) { this.displayCallbacks.addMessage(this.config.botSender, this.welcomeMessage, false); this.displayCallbacks.scrollChatToBottom(); } this._isHistoryLoaded = true; // Mark as loaded even if history was empty } } catch (error) { this.logger.error("Error loading chat history:", error); this.displayCallbacks.addMessage(this.config.errorSender, "Error loading chat history."); this._isHistoryLoaded = true; // Mark as loaded to prevent retry loops on error } } else { this.logger.info(`Session ID is already ${sessionId} and history is loaded.`); } } else { this.logger.info("No session ID provided, or session ID is empty. Clearing session and messages."); this.updateCurrentSessionId(null); this.displayCallbacks.clearMessages(); if (this.welcomeMessage) { this.displayCallbacks.addMessage(this.config.botSender, this.welcomeMessage, false); this.displayCallbacks.scrollChatToBottom(); } this._isHistoryLoaded = true; // Mark as "loaded" (i.e., processed empty/cleared state) } } } exports.ChatSessionManager = ChatSessionManager;