update frontend

This commit is contained in:
perf3ct 2025-04-16 21:43:19 +00:00
parent cdc84f1cef
commit 2b14f73ad4
No known key found for this signature in database
GPG Key ID: 569C4EEC436F5232
4 changed files with 87 additions and 76 deletions

View File

@ -7,17 +7,17 @@ import type { SessionResponse } from "./types.js";
/** /**
* Create a new chat session * 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 { try {
const resp = await server.post<SessionResponse>('llm/sessions', { const resp = await server.post<SessionResponse>('llm/chat', {
title: 'Note Chat' title: 'Note Chat'
}); });
if (resp && resp.id) { 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 // If noteId is provided, use it; otherwise, we'll need to query for it separately
return { return {
sessionId: resp.id, chatNoteId: resp.id,
noteId: resp.noteId || null noteId: resp.noteId || null
}; };
} }
@ -26,7 +26,7 @@ export async function createChatSession(): Promise<{sessionId: string | null, no
} }
return { return {
sessionId: null, chatNoteId: null,
noteId: null noteId: null
}; };
} }
@ -34,12 +34,12 @@ export async function createChatSession(): Promise<{sessionId: string | null, no
/** /**
* Check if a session exists * Check if a session exists
*/ */
export async function checkSessionExists(sessionId: string): Promise<boolean> { export async function checkSessionExists(chatNoteId: string): Promise<boolean> {
try { try {
const sessionCheck = await server.getWithSilentNotFound<any>(`llm/sessions/${sessionId}`); const sessionCheck = await server.getWithSilentNotFound<any>(`llm/chat/${chatNoteId}`);
return !!(sessionCheck && sessionCheck.id); return !!(sessionCheck && sessionCheck.id);
} catch (error: any) { } catch (error: any) {
console.log(`Error checking session ${sessionId}:`, error); console.log(`Error checking chat note ${chatNoteId}:`, error);
return false; return false;
} }
} }
@ -48,7 +48,7 @@ export async function checkSessionExists(sessionId: string): Promise<boolean> {
* Set up streaming response via WebSocket * Set up streaming response via WebSocket
*/ */
export async function setupStreamingResponse( export async function setupStreamingResponse(
sessionId: string, chatNoteId: string,
messageParams: any, messageParams: any,
onContentUpdate: (content: string, isDone?: boolean) => void, onContentUpdate: (content: string, isDone?: boolean) => void,
onThinkingUpdate: (thinking: string) => void, onThinkingUpdate: (thinking: string) => void,
@ -72,7 +72,7 @@ export async function setupStreamingResponse(
// Create a unique identifier for this response process // Create a unique identifier for this response process
const responseId = `llm-stream-${Date.now()}-${Math.floor(Math.random() * 1000)}`; 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 // Function to safely perform cleanup
const performCleanup = () => { const performCleanup = () => {
@ -115,8 +115,9 @@ export async function setupStreamingResponse(
const customEvent = event as CustomEvent; const customEvent = event as CustomEvent;
const message = customEvent.detail; const message = customEvent.detail;
// Only process messages for our session // Only process messages for our chat note
if (!message || message.sessionId !== sessionId) { // Note: The WebSocket messages still use sessionId property for backward compatibility
if (!message || message.sessionId !== chatNoteId) {
return; return;
} }
@ -130,12 +131,12 @@ export async function setupStreamingResponse(
cleanupTimeoutId = null; 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 // Mark first message received
if (!receivedAnyMessage) { if (!receivedAnyMessage) {
receivedAnyMessage = true; 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 // Clear the initial timeout since we've received a message
if (initialTimeoutId !== null) { if (initialTimeoutId !== null) {
@ -256,7 +257,7 @@ export async function setupStreamingResponse(
// Set new timeout // Set new timeout
timeoutId = window.setTimeout(() => { timeoutId = window.setTimeout(() => {
console.warn(`[${responseId}] Stream timeout for session ${sessionId}`); console.warn(`[${responseId}] Stream timeout for chat note ${chatNoteId}`);
// Clean up // Clean up
performCleanup(); performCleanup();
@ -327,7 +328,7 @@ export async function setupStreamingResponse(
// Handle completion // Handle completion
if (message.done) { 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 // Dump message content to console for debugging
if (message.content) { if (message.content) {
@ -386,9 +387,9 @@ export async function setupStreamingResponse(
// Set initial timeout for receiving any message // Set initial timeout for receiving any message
initialTimeoutId = window.setTimeout(() => { 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) { 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) { if (timeoutId !== null) {
window.clearTimeout(timeoutId); window.clearTimeout(timeoutId);
@ -403,12 +404,12 @@ export async function setupStreamingResponse(
}, 10000); }, 10000);
// Send the streaming request to start the process // Send the streaming request to start the process
console.log(`[${responseId}] Sending HTTP POST request to initiate streaming: /llm/sessions/${sessionId}/messages/stream`); console.log(`[${responseId}] Sending HTTP POST request to initiate streaming: /llm/chat/${chatNoteId}/messages/stream`);
server.post(`llm/sessions/${sessionId}/messages/stream`, { server.post(`llm/chat/${chatNoteId}/messages/stream`, {
...messageParams, ...messageParams,
stream: true // Explicitly indicate this is a streaming request stream: true // Explicitly indicate this is a streaming request
}).catch(err => { }).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 // Clean up timeouts
if (initialTimeoutId !== null) { 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<any> { export async function getDirectResponse(chatNoteId: string, messageParams: any): Promise<any> {
// Create a copy of the params without any streaming flags try {
const postParams = { const postResponse = await server.post<any>(`llm/chat/${chatNoteId}/messages`, {
...messageParams, message: messageParams.content,
stream: false // Explicitly set to false to ensure we get a direct response includeContext: messageParams.useAdvancedContext,
}; options: {
temperature: 0.7,
maxTokens: 2000
}
});
console.log(`Sending direct POST request for session ${sessionId}`); return postResponse;
} catch (error) {
// Send the message via POST request with the updated params console.error('Error getting direct response:', error);
return server.post<any>(`llm/sessions/${sessionId}/messages`, postParams); throw error;
}
} }
/** /**

View File

@ -33,7 +33,7 @@ export default class LlmChatPanel extends BasicWidget {
private useAdvancedContextCheckbox!: HTMLInputElement; private useAdvancedContextCheckbox!: HTMLInputElement;
private showThinkingCheckbox!: HTMLInputElement; private showThinkingCheckbox!: HTMLInputElement;
private validationWarning!: HTMLElement; 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 noteId: string | null = null; // The actual noteId for the Chat Note
private currentNoteId: string | null = null; private currentNoteId: string | null = null;
private _messageHandlerId: number | null = null; private _messageHandlerId: number | null = null;
@ -86,12 +86,12 @@ export default class LlmChatPanel extends BasicWidget {
this.messages = messages; this.messages = messages;
} }
public getSessionId(): string | null { public getChatNoteId(): string | null {
return this.sessionId; return this.chatNoteId;
} }
public setSessionId(sessionId: string | null): void { public setChatNoteId(chatNoteId: string | null): void {
this.sessionId = sessionId; this.chatNoteId = chatNoteId;
} }
public getNoteContextChatMessages(): HTMLElement { public getNoteContextChatMessages(): HTMLElement {
@ -232,7 +232,7 @@ export default class LlmChatPanel extends BasicWidget {
const dataToSave: ChatData = { const dataToSave: ChatData = {
messages: this.messages, messages: this.messages,
sessionId: this.sessionId, chatNoteId: this.chatNoteId,
noteId: this.noteId, noteId: this.noteId,
toolSteps: toolSteps, toolSteps: toolSteps,
// Add sources if we have them // 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 // 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 // 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); console.log(`Loaded metadata from saved data:`, this.metadata);
} }
// Load session ID if available // Load Chat Note ID if available
if (savedData.sessionId) { if (savedData.chatNoteId) {
console.log(`Setting session ID from saved data: ${savedData.sessionId}`); console.log(`Setting Chat Note ID from saved data: ${savedData.chatNoteId}`);
this.sessionId = savedData.sessionId; this.chatNoteId = savedData.chatNoteId;
// Set the noteId as well - this could be different from 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 sessionId // If we have a separate noteId stored, use it, otherwise default to the chatNoteId
if (savedData.noteId) { if (savedData.noteId) {
this.noteId = savedData.noteId; this.noteId = savedData.noteId;
console.log(`Using stored Chat Note ID: ${this.noteId}`); console.log(`Using stored Chat Note ID: ${this.noteId}`);
} else { } else {
// For compatibility with older data, use the sessionId as the noteId // For compatibility with older data, use the chatNoteId as the noteId
this.noteId = savedData.sessionId; this.noteId = savedData.chatNoteId;
console.log(`No Chat Note ID found, using session ID: ${this.sessionId}`); 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 // 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 // is now the source of truth - if we have the Note, we have the session
} else { } else {
// No saved session ID, create a new one // For backward compatibility, try to get sessionId
this.sessionId = null; if ((savedData as any).sessionId) {
this.noteId = null; console.log(`Using legacy sessionId as Chat Note ID: ${(savedData as any).sessionId}`);
await this.createChatSession(); 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; return true;
@ -466,7 +473,7 @@ export default class LlmChatPanel extends BasicWidget {
// Reset the UI and data // Reset the UI and data
this.noteContextChatMessages.innerHTML = ''; this.noteContextChatMessages.innerHTML = '';
this.messages = []; this.messages = [];
this.sessionId = null; this.chatNoteId = null;
this.noteId = null; // Also reset the chat note ID this.noteId = null; // Also reset the chat note ID
this.hideSources(); // Hide any sources from previous note this.hideSources(); // Hide any sources from previous note
@ -478,7 +485,7 @@ export default class LlmChatPanel extends BasicWidget {
const hasSavedData = await this.loadSavedData(); const hasSavedData = await this.loadSavedData();
// Only create a new session if we don't have a session or saved data // 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 // Create a new chat session
await this.createChatSession(); await this.createChatSession();
} }
@ -487,16 +494,16 @@ export default class LlmChatPanel extends BasicWidget {
private async createChatSession() { private async createChatSession() {
try { try {
// Create a new Chat Note to represent this chat session // 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(); const result = await createChatSession();
if (!result.sessionId) { if (!result.chatNoteId) {
toastService.showError('Failed to create chat session'); toastService.showError('Failed to create chat session');
return; return;
} }
console.log(`Created new chat session with ID: ${result.sessionId}`); console.log(`Created new chat session with ID: ${result.chatNoteId}`);
this.sessionId = result.sessionId; this.chatNoteId = result.chatNoteId;
// If the API returned a noteId directly, use it // If the API returned a noteId directly, use it
if (result.noteId) { if (result.noteId) {
@ -505,13 +512,12 @@ export default class LlmChatPanel extends BasicWidget {
} else { } else {
// Otherwise, try to get session details to find the noteId // Otherwise, try to get session details to find the noteId
try { try {
const sessionDetails = await server.get<any>(`llm/sessions/${this.sessionId}`); const sessionDetails = await server.get<any>(`llm/chat/${this.chatNoteId}`);
if (sessionDetails && sessionDetails.noteId) { if (sessionDetails && sessionDetails.noteId) {
this.noteId = sessionDetails.noteId; this.noteId = sessionDetails.noteId;
console.log(`Using noteId from session details: ${this.noteId}`); console.log(`Using noteId from session details: ${this.noteId}`);
} else { } else {
// As a last resort, use DyFEvvxsMylI as the noteId since logs show this is the correct one // As a last resort, use the current note ID
// This is a temporary fix until the backend consistently returns noteId
console.warn(`No noteId found in session details, using parent note ID: ${this.currentNoteId}`); console.warn(`No noteId found in session details, using parent note ID: ${this.currentNoteId}`);
this.noteId = this.currentNoteId; this.noteId = this.currentNoteId;
} }
@ -562,7 +568,7 @@ export default class LlmChatPanel extends BasicWidget {
const showThinking = this.showThinkingCheckbox.checked; const showThinking = this.showThinkingCheckbox.checked;
// Add logging to verify parameters // 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 // Create the message parameters
const messageParams = { const messageParams = {
@ -611,11 +617,11 @@ export default class LlmChatPanel extends BasicWidget {
await validateEmbeddingProviders(this.validationWarning); await validateEmbeddingProviders(this.validationWarning);
// Make sure we have a valid session // Make sure we have a valid session
if (!this.sessionId) { if (!this.chatNoteId) {
// If no session ID, create a new session // If no session ID, create a new session
await this.createChatSession(); await this.createChatSession();
if (!this.sessionId) { if (!this.chatNoteId) {
// If still no session ID, show error and return // If still no session ID, show error and return
console.error("Failed to create chat session"); console.error("Failed to create chat session");
toastService.showError("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(); await this.saveCurrentData();
// Add logging to verify parameters // 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 // Create the message parameters
const messageParams = { const messageParams = {
@ -681,12 +687,12 @@ export default class LlmChatPanel extends BasicWidget {
*/ */
private async handleDirectResponse(messageParams: any): Promise<boolean> { private async handleDirectResponse(messageParams: any): Promise<boolean> {
try { 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 // 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 the POST request returned content directly, display it
if (postResponse && postResponse.content) { if (postResponse && postResponse.content) {
@ -759,11 +765,11 @@ export default class LlmChatPanel extends BasicWidget {
* Set up streaming response via WebSocket * Set up streaming response via WebSocket
*/ */
private async setupStreamingResponse(messageParams: any): Promise<void> { private async setupStreamingResponse(messageParams: any): Promise<void> {
if (!this.sessionId) { if (!this.chatNoteId) {
throw new Error("No session ID available"); 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 // Store tool executions captured during streaming
const toolExecutionsCache: Array<{ const toolExecutionsCache: Array<{
@ -776,7 +782,7 @@ export default class LlmChatPanel extends BasicWidget {
}> = []; }> = [];
return setupStreamingResponse( return setupStreamingResponse(
this.sessionId, this.chatNoteId,
messageParams, messageParams,
// Content update handler // Content update handler
(content: string, isDone: boolean = false) => { (content: string, isDone: boolean = false) => {
@ -812,7 +818,7 @@ export default class LlmChatPanel extends BasicWidget {
similarity?: number; similarity?: number;
content?: string; content?: string;
}>; }>;
}>(`llm/sessions/${this.sessionId}`) }>(`llm/sessions/${this.chatNoteId}`)
.then((sessionData) => { .then((sessionData) => {
console.log("Got updated session data:", sessionData); console.log("Got updated session data:", sessionData);

View File

@ -28,7 +28,7 @@ export interface MessageData {
export interface ChatData { export interface ChatData {
messages: MessageData[]; messages: MessageData[];
sessionId: string | null; chatNoteId: string | null;
noteId?: string | null; noteId?: string | null;
toolSteps: ToolExecutionStep[]; toolSteps: ToolExecutionStep[];
sources?: Array<{ sources?: Array<{

View File

@ -130,7 +130,7 @@ export default class AiChatTypeWidget extends TypeWidget {
// Reset the chat panel UI // Reset the chat panel UI
this.llmChatPanel.clearNoteContextChatMessages(); this.llmChatPanel.clearNoteContextChatMessages();
this.llmChatPanel.setMessages([]); this.llmChatPanel.setMessages([]);
this.llmChatPanel.setSessionId(null); this.llmChatPanel.setChatNoteId(null);
} }
// Call the parent method to refresh // 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 // Format the data properly - this is the canonical format of the data
const formattedData = { const formattedData = {
messages: data.messages || [], messages: data.messages || [],
sessionId: data.sessionId, chatNoteId: data.chatNoteId || this.note.noteId,
noteId: data.noteId || this.note.noteId,
toolSteps: data.toolSteps || [], toolSteps: data.toolSteps || [],
sources: data.sources || [], sources: data.sources || [],
metadata: { metadata: {