diff --git a/src/public/app/widgets/llm_chat/communication.ts b/src/public/app/widgets/llm_chat/communication.ts index 69974baf7..bf39365fb 100644 --- a/src/public/app/widgets/llm_chat/communication.ts +++ b/src/public/app/widgets/llm_chat/communication.ts @@ -7,17 +7,17 @@ import type { SessionResponse } from "./types.js"; /** * Create a new chat session */ -export async function createChatSession(): Promise<{sessionId: string | null, noteId: string | null}> { +export async function createChatSession(): Promise<{chatNoteId: string | null, noteId: string | null}> { try { - const resp = await server.post('llm/sessions', { + const resp = await server.post('llm/chat', { title: 'Note Chat' }); if (resp && resp.id) { - // The backend might provide the noteId separately from the sessionId + // The backend might provide the noteId separately from the chatNoteId // If noteId is provided, use it; otherwise, we'll need to query for it separately return { - sessionId: resp.id, + chatNoteId: resp.id, noteId: resp.noteId || null }; } @@ -26,7 +26,7 @@ export async function createChatSession(): Promise<{sessionId: string | null, no } return { - sessionId: null, + chatNoteId: null, noteId: null }; } @@ -34,12 +34,12 @@ export async function createChatSession(): Promise<{sessionId: string | null, no /** * Check if a session exists */ -export async function checkSessionExists(sessionId: string): Promise { +export async function checkSessionExists(chatNoteId: string): Promise { try { - const sessionCheck = await server.getWithSilentNotFound(`llm/sessions/${sessionId}`); + const sessionCheck = await server.getWithSilentNotFound(`llm/chat/${chatNoteId}`); return !!(sessionCheck && sessionCheck.id); } catch (error: any) { - console.log(`Error checking session ${sessionId}:`, error); + console.log(`Error checking chat note ${chatNoteId}:`, error); return false; } } @@ -48,7 +48,7 @@ export async function checkSessionExists(sessionId: string): Promise { * Set up streaming response via WebSocket */ export async function setupStreamingResponse( - sessionId: string, + chatNoteId: string, messageParams: any, onContentUpdate: (content: string, isDone?: boolean) => void, onThinkingUpdate: (thinking: string) => void, @@ -72,7 +72,7 @@ export async function setupStreamingResponse( // Create a unique identifier for this response process const responseId = `llm-stream-${Date.now()}-${Math.floor(Math.random() * 1000)}`; - console.log(`[${responseId}] Setting up WebSocket streaming for session ${sessionId}`); + console.log(`[${responseId}] Setting up WebSocket streaming for chat note ${chatNoteId}`); // Function to safely perform cleanup const performCleanup = () => { @@ -115,8 +115,9 @@ export async function setupStreamingResponse( const customEvent = event as CustomEvent; const message = customEvent.detail; - // Only process messages for our session - if (!message || message.sessionId !== sessionId) { + // Only process messages for our chat note + // Note: The WebSocket messages still use sessionId property for backward compatibility + if (!message || message.sessionId !== chatNoteId) { return; } @@ -130,12 +131,12 @@ export async function setupStreamingResponse( cleanupTimeoutId = null; } - console.log(`[${responseId}] LLM Stream message received via CustomEvent: session=${sessionId}, content=${!!message.content}, contentLength=${message.content?.length || 0}, thinking=${!!message.thinking}, toolExecution=${!!message.toolExecution}, done=${!!message.done}, type=${message.type || 'llm-stream'}`); + console.log(`[${responseId}] LLM Stream message received via CustomEvent: chatNoteId=${chatNoteId}, content=${!!message.content}, contentLength=${message.content?.length || 0}, thinking=${!!message.thinking}, toolExecution=${!!message.toolExecution}, done=${!!message.done}, type=${message.type || 'llm-stream'}`); // Mark first message received if (!receivedAnyMessage) { receivedAnyMessage = true; - console.log(`[${responseId}] First message received for session ${sessionId}`); + console.log(`[${responseId}] First message received for chat note ${chatNoteId}`); // Clear the initial timeout since we've received a message if (initialTimeoutId !== null) { @@ -256,7 +257,7 @@ export async function setupStreamingResponse( // Set new timeout timeoutId = window.setTimeout(() => { - console.warn(`[${responseId}] Stream timeout for session ${sessionId}`); + console.warn(`[${responseId}] Stream timeout for chat note ${chatNoteId}`); // Clean up performCleanup(); @@ -327,7 +328,7 @@ export async function setupStreamingResponse( // Handle completion if (message.done) { - console.log(`[${responseId}] Stream completed for session ${sessionId}, has content: ${!!message.content}, content length: ${message.content?.length || 0}, current response: ${assistantResponse.length} chars`); + console.log(`[${responseId}] Stream completed for chat note ${chatNoteId}, has content: ${!!message.content}, content length: ${message.content?.length || 0}, current response: ${assistantResponse.length} chars`); // Dump message content to console for debugging if (message.content) { @@ -386,9 +387,9 @@ export async function setupStreamingResponse( // Set initial timeout for receiving any message initialTimeoutId = window.setTimeout(() => { - console.warn(`[${responseId}] No messages received for initial period in session ${sessionId}`); + console.warn(`[${responseId}] No messages received for initial period in chat note ${chatNoteId}`); if (!receivedAnyMessage) { - console.error(`[${responseId}] WebSocket connection not established for session ${sessionId}`); + console.error(`[${responseId}] WebSocket connection not established for chat note ${chatNoteId}`); if (timeoutId !== null) { window.clearTimeout(timeoutId); @@ -403,12 +404,12 @@ export async function setupStreamingResponse( }, 10000); // Send the streaming request to start the process - console.log(`[${responseId}] Sending HTTP POST request to initiate streaming: /llm/sessions/${sessionId}/messages/stream`); - server.post(`llm/sessions/${sessionId}/messages/stream`, { + console.log(`[${responseId}] Sending HTTP POST request to initiate streaming: /llm/chat/${chatNoteId}/messages/stream`); + server.post(`llm/chat/${chatNoteId}/messages/stream`, { ...messageParams, stream: true // Explicitly indicate this is a streaming request }).catch(err => { - console.error(`[${responseId}] HTTP error sending streaming request for session ${sessionId}:`, err); + console.error(`[${responseId}] HTTP error sending streaming request for chat note ${chatNoteId}:`, err); // Clean up timeouts if (initialTimeoutId !== null) { @@ -444,19 +445,24 @@ function cleanupEventListener(listener: ((event: Event) => void) | null): void { } /** - * Get a direct response from the server + * Get a direct response from the server without streaming */ -export async function getDirectResponse(sessionId: string, messageParams: any): Promise { - // Create a copy of the params without any streaming flags - const postParams = { - ...messageParams, - stream: false // Explicitly set to false to ensure we get a direct response - }; +export async function getDirectResponse(chatNoteId: string, messageParams: any): Promise { + try { + const postResponse = await server.post(`llm/chat/${chatNoteId}/messages`, { + message: messageParams.content, + includeContext: messageParams.useAdvancedContext, + options: { + temperature: 0.7, + maxTokens: 2000 + } + }); - console.log(`Sending direct POST request for session ${sessionId}`); - - // Send the message via POST request with the updated params - return server.post(`llm/sessions/${sessionId}/messages`, postParams); + return postResponse; + } catch (error) { + console.error('Error getting direct response:', error); + throw error; + } } /** diff --git a/src/public/app/widgets/llm_chat/llm_chat_panel.ts b/src/public/app/widgets/llm_chat/llm_chat_panel.ts index ed4415df6..18d0eaa65 100644 --- a/src/public/app/widgets/llm_chat/llm_chat_panel.ts +++ b/src/public/app/widgets/llm_chat/llm_chat_panel.ts @@ -33,7 +33,7 @@ export default class LlmChatPanel extends BasicWidget { private useAdvancedContextCheckbox!: HTMLInputElement; private showThinkingCheckbox!: HTMLInputElement; private validationWarning!: HTMLElement; - private sessionId: string | null = null; + private chatNoteId: string | null = null; private noteId: string | null = null; // The actual noteId for the Chat Note private currentNoteId: string | null = null; private _messageHandlerId: number | null = null; @@ -86,12 +86,12 @@ export default class LlmChatPanel extends BasicWidget { this.messages = messages; } - public getSessionId(): string | null { - return this.sessionId; + public getChatNoteId(): string | null { + return this.chatNoteId; } - public setSessionId(sessionId: string | null): void { - this.sessionId = sessionId; + public setChatNoteId(chatNoteId: string | null): void { + this.chatNoteId = chatNoteId; } public getNoteContextChatMessages(): HTMLElement { @@ -232,7 +232,7 @@ export default class LlmChatPanel extends BasicWidget { const dataToSave: ChatData = { messages: this.messages, - sessionId: this.sessionId, + chatNoteId: this.chatNoteId, noteId: this.noteId, toolSteps: toolSteps, // Add sources if we have them @@ -248,7 +248,7 @@ export default class LlmChatPanel extends BasicWidget { } }; - console.log(`Saving chat data with sessionId: ${this.sessionId}, noteId: ${this.noteId}, ${toolSteps.length} tool steps, ${this.sources?.length || 0} sources, ${toolExecutions.length} tool executions`); + console.log(`Saving chat data with chatNoteId: ${this.chatNoteId}, noteId: ${this.noteId}, ${toolSteps.length} tool steps, ${this.sources?.length || 0} sources, ${toolExecutions.length} tool executions`); // Save the data to the note attribute via the callback // This is the ONLY place we should save data, letting the container widget handle persistence @@ -320,29 +320,36 @@ export default class LlmChatPanel extends BasicWidget { console.log(`Loaded metadata from saved data:`, this.metadata); } - // Load session ID if available - if (savedData.sessionId) { - console.log(`Setting session ID from saved data: ${savedData.sessionId}`); - this.sessionId = savedData.sessionId; + // Load Chat Note ID if available + if (savedData.chatNoteId) { + console.log(`Setting Chat Note ID from saved data: ${savedData.chatNoteId}`); + this.chatNoteId = savedData.chatNoteId; - // Set the noteId as well - this could be different from the sessionId - // If we have a separate noteId stored, use it, otherwise default to the sessionId + // Set the noteId as well - this could be different from the chatNoteId + // If we have a separate noteId stored, use it, otherwise default to the chatNoteId if (savedData.noteId) { this.noteId = savedData.noteId; console.log(`Using stored Chat Note ID: ${this.noteId}`); } else { - // For compatibility with older data, use the sessionId as the noteId - this.noteId = savedData.sessionId; - console.log(`No Chat Note ID found, using session ID: ${this.sessionId}`); + // For compatibility with older data, use the chatNoteId as the noteId + this.noteId = savedData.chatNoteId; + console.log(`No Chat Note ID found, using Chat Note ID: ${this.chatNoteId}`); } // No need to check if session exists on server since the Chat Note // is now the source of truth - if we have the Note, we have the session } else { - // No saved session ID, create a new one - this.sessionId = null; - this.noteId = null; - await this.createChatSession(); + // For backward compatibility, try to get sessionId + if ((savedData as any).sessionId) { + console.log(`Using legacy sessionId as Chat Note ID: ${(savedData as any).sessionId}`); + this.chatNoteId = (savedData as any).sessionId; + this.noteId = savedData.noteId || (savedData as any).sessionId; + } else { + // No saved Chat Note ID, create a new one + this.chatNoteId = null; + this.noteId = null; + await this.createChatSession(); + } } return true; @@ -466,7 +473,7 @@ export default class LlmChatPanel extends BasicWidget { // Reset the UI and data this.noteContextChatMessages.innerHTML = ''; this.messages = []; - this.sessionId = null; + this.chatNoteId = null; this.noteId = null; // Also reset the chat note ID this.hideSources(); // Hide any sources from previous note @@ -478,7 +485,7 @@ export default class LlmChatPanel extends BasicWidget { const hasSavedData = await this.loadSavedData(); // Only create a new session if we don't have a session or saved data - if (!this.sessionId || !this.noteId || !hasSavedData) { + if (!this.chatNoteId || !this.noteId || !hasSavedData) { // Create a new chat session await this.createChatSession(); } @@ -487,16 +494,16 @@ export default class LlmChatPanel extends BasicWidget { private async createChatSession() { try { // Create a new Chat Note to represent this chat session - // The function now returns both sessionId and noteId + // The function now returns both chatNoteId and noteId const result = await createChatSession(); - if (!result.sessionId) { + if (!result.chatNoteId) { toastService.showError('Failed to create chat session'); return; } - console.log(`Created new chat session with ID: ${result.sessionId}`); - this.sessionId = result.sessionId; + console.log(`Created new chat session with ID: ${result.chatNoteId}`); + this.chatNoteId = result.chatNoteId; // If the API returned a noteId directly, use it if (result.noteId) { @@ -505,13 +512,12 @@ export default class LlmChatPanel extends BasicWidget { } else { // Otherwise, try to get session details to find the noteId try { - const sessionDetails = await server.get(`llm/sessions/${this.sessionId}`); + const sessionDetails = await server.get(`llm/chat/${this.chatNoteId}`); if (sessionDetails && sessionDetails.noteId) { this.noteId = sessionDetails.noteId; console.log(`Using noteId from session details: ${this.noteId}`); } else { - // As a last resort, use DyFEvvxsMylI as the noteId since logs show this is the correct one - // This is a temporary fix until the backend consistently returns noteId + // As a last resort, use the current note ID console.warn(`No noteId found in session details, using parent note ID: ${this.currentNoteId}`); this.noteId = this.currentNoteId; } @@ -562,7 +568,7 @@ export default class LlmChatPanel extends BasicWidget { const showThinking = this.showThinkingCheckbox.checked; // Add logging to verify parameters - console.log(`Sending message with: useAdvancedContext=${useAdvancedContext}, showThinking=${showThinking}, noteId=${this.currentNoteId}, sessionId=${this.sessionId}`); + console.log(`Sending message with: useAdvancedContext=${useAdvancedContext}, showThinking=${showThinking}, noteId=${this.currentNoteId}, sessionId=${this.chatNoteId}`); // Create the message parameters const messageParams = { @@ -611,11 +617,11 @@ export default class LlmChatPanel extends BasicWidget { await validateEmbeddingProviders(this.validationWarning); // Make sure we have a valid session - if (!this.sessionId) { + if (!this.chatNoteId) { // If no session ID, create a new session await this.createChatSession(); - if (!this.sessionId) { + if (!this.chatNoteId) { // If still no session ID, show error and return console.error("Failed to create chat session"); toastService.showError("Failed to create chat session"); @@ -644,7 +650,7 @@ export default class LlmChatPanel extends BasicWidget { await this.saveCurrentData(); // Add logging to verify parameters - console.log(`Sending message with: useAdvancedContext=${useAdvancedContext}, showThinking=${showThinking}, noteId=${this.currentNoteId}, sessionId=${this.sessionId}`); + console.log(`Sending message with: useAdvancedContext=${useAdvancedContext}, showThinking=${showThinking}, noteId=${this.currentNoteId}, sessionId=${this.chatNoteId}`); // Create the message parameters const messageParams = { @@ -681,12 +687,12 @@ export default class LlmChatPanel extends BasicWidget { */ private async handleDirectResponse(messageParams: any): Promise { try { - if (!this.sessionId) return false; + if (!this.chatNoteId) return false; - console.log(`Getting direct response using sessionId: ${this.sessionId} (noteId: ${this.noteId})`); + console.log(`Getting direct response using sessionId: ${this.chatNoteId} (noteId: ${this.noteId})`); // Get a direct response from the server - const postResponse = await getDirectResponse(this.sessionId, messageParams); + const postResponse = await getDirectResponse(this.chatNoteId, messageParams); // If the POST request returned content directly, display it if (postResponse && postResponse.content) { @@ -759,11 +765,11 @@ export default class LlmChatPanel extends BasicWidget { * Set up streaming response via WebSocket */ private async setupStreamingResponse(messageParams: any): Promise { - if (!this.sessionId) { + if (!this.chatNoteId) { throw new Error("No session ID available"); } - console.log(`Setting up streaming response using sessionId: ${this.sessionId} (noteId: ${this.noteId})`); + console.log(`Setting up streaming response using sessionId: ${this.chatNoteId} (noteId: ${this.noteId})`); // Store tool executions captured during streaming const toolExecutionsCache: Array<{ @@ -776,7 +782,7 @@ export default class LlmChatPanel extends BasicWidget { }> = []; return setupStreamingResponse( - this.sessionId, + this.chatNoteId, messageParams, // Content update handler (content: string, isDone: boolean = false) => { @@ -812,7 +818,7 @@ export default class LlmChatPanel extends BasicWidget { similarity?: number; content?: string; }>; - }>(`llm/sessions/${this.sessionId}`) + }>(`llm/sessions/${this.chatNoteId}`) .then((sessionData) => { console.log("Got updated session data:", sessionData); diff --git a/src/public/app/widgets/llm_chat/types.ts b/src/public/app/widgets/llm_chat/types.ts index e4fad8d1c..dc19f38d3 100644 --- a/src/public/app/widgets/llm_chat/types.ts +++ b/src/public/app/widgets/llm_chat/types.ts @@ -28,7 +28,7 @@ export interface MessageData { export interface ChatData { messages: MessageData[]; - sessionId: string | null; + chatNoteId: string | null; noteId?: string | null; toolSteps: ToolExecutionStep[]; sources?: Array<{ diff --git a/src/public/app/widgets/type_widgets/ai_chat.ts b/src/public/app/widgets/type_widgets/ai_chat.ts index c4d758a7d..e96cf5f20 100644 --- a/src/public/app/widgets/type_widgets/ai_chat.ts +++ b/src/public/app/widgets/type_widgets/ai_chat.ts @@ -130,7 +130,7 @@ export default class AiChatTypeWidget extends TypeWidget { // Reset the chat panel UI this.llmChatPanel.clearNoteContextChatMessages(); this.llmChatPanel.setMessages([]); - this.llmChatPanel.setSessionId(null); + this.llmChatPanel.setChatNoteId(null); } // Call the parent method to refresh @@ -186,8 +186,7 @@ export default class AiChatTypeWidget extends TypeWidget { // Format the data properly - this is the canonical format of the data const formattedData = { messages: data.messages || [], - sessionId: data.sessionId, - noteId: data.noteId || this.note.noteId, + chatNoteId: data.chatNoteId || this.note.noteId, toolSteps: data.toolSteps || [], sources: data.sources || [], metadata: {