mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-29 02:52:27 +08:00
feat(llm): redo chat storage, part 1
This commit is contained in:
parent
206905b278
commit
35f78aede9
@ -6,8 +6,10 @@ import type { SessionResponse } from "./types.js";
|
||||
|
||||
/**
|
||||
* Create a new chat session
|
||||
* @param currentNoteId - Optional current note ID for context
|
||||
* @returns The noteId of the created chat note
|
||||
*/
|
||||
export async function createChatSession(currentNoteId?: string): Promise<{chatNoteId: string | null, noteId: string | null}> {
|
||||
export async function createChatSession(currentNoteId?: string): Promise<string | null> {
|
||||
try {
|
||||
const resp = await server.post<SessionResponse>('llm/chat', {
|
||||
title: 'Note Chat',
|
||||
@ -15,48 +17,42 @@ export async function createChatSession(currentNoteId?: string): Promise<{chatNo
|
||||
});
|
||||
|
||||
if (resp && resp.id) {
|
||||
// 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 {
|
||||
chatNoteId: resp.id,
|
||||
noteId: resp.noteId || null
|
||||
};
|
||||
// Backend returns the chat note ID as 'id'
|
||||
return resp.id;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to create chat session:', error);
|
||||
}
|
||||
|
||||
return {
|
||||
chatNoteId: null,
|
||||
noteId: null
|
||||
};
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a session exists
|
||||
* Check if a chat note exists
|
||||
* @param noteId - The ID of the chat note
|
||||
*/
|
||||
export async function checkSessionExists(chatNoteId: string): Promise<boolean> {
|
||||
export async function checkSessionExists(noteId: string): Promise<boolean> {
|
||||
try {
|
||||
// Validate that we have a proper note ID format, not a session ID
|
||||
// Note IDs in Trilium are typically longer or in a different format
|
||||
if (chatNoteId && chatNoteId.length === 16 && /^[A-Za-z0-9]+$/.test(chatNoteId)) {
|
||||
console.warn(`Invalid note ID format detected: ${chatNoteId} appears to be a legacy session ID`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const sessionCheck = await server.getWithSilentNotFound<any>(`llm/chat/${chatNoteId}`);
|
||||
const sessionCheck = await server.getWithSilentNotFound<any>(`llm/chat/${noteId}`);
|
||||
return !!(sessionCheck && sessionCheck.id);
|
||||
} catch (error: any) {
|
||||
console.log(`Error checking chat note ${chatNoteId}:`, error);
|
||||
console.log(`Error checking chat note ${noteId}:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up streaming response via WebSocket
|
||||
* @param noteId - The ID of the chat note
|
||||
* @param messageParams - Message parameters
|
||||
* @param onContentUpdate - Callback for content updates
|
||||
* @param onThinkingUpdate - Callback for thinking updates
|
||||
* @param onToolExecution - Callback for tool execution
|
||||
* @param onComplete - Callback for completion
|
||||
* @param onError - Callback for errors
|
||||
*/
|
||||
export async function setupStreamingResponse(
|
||||
chatNoteId: string,
|
||||
noteId: string,
|
||||
messageParams: any,
|
||||
onContentUpdate: (content: string, isDone?: boolean) => void,
|
||||
onThinkingUpdate: (thinking: string) => void,
|
||||
@ -64,13 +60,6 @@ export async function setupStreamingResponse(
|
||||
onComplete: () => void,
|
||||
onError: (error: Error) => void
|
||||
): Promise<void> {
|
||||
// Validate that we have a proper note ID format, not a session ID
|
||||
if (chatNoteId && chatNoteId.length === 16 && /^[A-Za-z0-9]+$/.test(chatNoteId)) {
|
||||
console.error(`Invalid note ID format: ${chatNoteId} appears to be a legacy session ID`);
|
||||
onError(new Error("Invalid note ID format - using a legacy session ID"));
|
||||
return;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
let assistantResponse = '';
|
||||
let postToolResponse = ''; // Separate accumulator for post-tool execution content
|
||||
@ -87,12 +76,12 @@ 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 chat note ${chatNoteId}`);
|
||||
console.log(`[${responseId}] Setting up WebSocket streaming for chat note ${noteId}`);
|
||||
|
||||
// Send the initial request to initiate streaming
|
||||
(async () => {
|
||||
try {
|
||||
const streamResponse = await server.post<any>(`llm/chat/${chatNoteId}/messages/stream`, {
|
||||
const streamResponse = await server.post<any>(`llm/chat/${noteId}/messages/stream`, {
|
||||
content: messageParams.content,
|
||||
useAdvancedContext: messageParams.useAdvancedContext,
|
||||
showThinking: messageParams.showThinking,
|
||||
@ -158,7 +147,7 @@ export async function setupStreamingResponse(
|
||||
const message = customEvent.detail;
|
||||
|
||||
// Only process messages for our chat note
|
||||
if (!message || message.chatNoteId !== chatNoteId) {
|
||||
if (!message || message.chatNoteId !== noteId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -172,12 +161,12 @@ export async function setupStreamingResponse(
|
||||
cleanupTimeoutId = null;
|
||||
}
|
||||
|
||||
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'}`);
|
||||
console.log(`[${responseId}] LLM Stream message received via CustomEvent: chatNoteId=${noteId}, 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 chat note ${chatNoteId}`);
|
||||
console.log(`[${responseId}] First message received for chat note ${noteId}`);
|
||||
|
||||
// Clear the initial timeout since we've received a message
|
||||
if (initialTimeoutId !== null) {
|
||||
@ -298,7 +287,7 @@ export async function setupStreamingResponse(
|
||||
|
||||
// Set new timeout
|
||||
timeoutId = window.setTimeout(() => {
|
||||
console.warn(`[${responseId}] Stream timeout for chat note ${chatNoteId}`);
|
||||
console.warn(`[${responseId}] Stream timeout for chat note ${noteId}`);
|
||||
|
||||
// Clean up
|
||||
performCleanup();
|
||||
@ -369,7 +358,7 @@ export async function setupStreamingResponse(
|
||||
|
||||
// Handle completion
|
||||
if (message.done) {
|
||||
console.log(`[${responseId}] Stream completed for chat note ${chatNoteId}, has content: ${!!message.content}, content length: ${message.content?.length || 0}, current response: ${assistantResponse.length} chars`);
|
||||
console.log(`[${responseId}] Stream completed for chat note ${noteId}, 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) {
|
||||
@ -428,9 +417,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 chat note ${chatNoteId}`);
|
||||
console.warn(`[${responseId}] No messages received for initial period in chat note ${noteId}`);
|
||||
if (!receivedAnyMessage) {
|
||||
console.error(`[${responseId}] WebSocket connection not established for chat note ${chatNoteId}`);
|
||||
console.error(`[${responseId}] WebSocket connection not established for chat note ${noteId}`);
|
||||
|
||||
if (timeoutId !== null) {
|
||||
window.clearTimeout(timeoutId);
|
||||
@ -463,15 +452,9 @@ function cleanupEventListener(listener: ((event: Event) => void) | null): void {
|
||||
/**
|
||||
* Get a direct response from the server without streaming
|
||||
*/
|
||||
export async function getDirectResponse(chatNoteId: string, messageParams: any): Promise<any> {
|
||||
export async function getDirectResponse(noteId: string, messageParams: any): Promise<any> {
|
||||
try {
|
||||
// Validate that we have a proper note ID format, not a session ID
|
||||
if (chatNoteId && chatNoteId.length === 16 && /^[A-Za-z0-9]+$/.test(chatNoteId)) {
|
||||
console.error(`Invalid note ID format: ${chatNoteId} appears to be a legacy session ID`);
|
||||
throw new Error("Invalid note ID format - using a legacy session ID");
|
||||
}
|
||||
|
||||
const postResponse = await server.post<any>(`llm/chat/${chatNoteId}/messages`, {
|
||||
const postResponse = await server.post<any>(`llm/chat/${noteId}/messages`, {
|
||||
message: messageParams.content,
|
||||
includeContext: messageParams.useAdvancedContext,
|
||||
options: {
|
||||
|
@ -37,9 +37,10 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
private thinkingBubble!: HTMLElement;
|
||||
private thinkingText!: HTMLElement;
|
||||
private thinkingToggle!: HTMLElement;
|
||||
private chatNoteId: string | null = null;
|
||||
private noteId: string | null = null; // The actual noteId for the Chat Note
|
||||
private currentNoteId: string | null = null;
|
||||
|
||||
// Simplified to just use noteId - this represents the AI Chat note we're working with
|
||||
private noteId: string | null = null;
|
||||
private currentNoteId: string | null = null; // The note providing context (for regular notes)
|
||||
private _messageHandlerId: number | null = null;
|
||||
private _messageHandler: any = null;
|
||||
|
||||
@ -90,12 +91,21 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
public getChatNoteId(): string | null {
|
||||
return this.chatNoteId;
|
||||
public getNoteId(): string | null {
|
||||
return this.noteId;
|
||||
}
|
||||
|
||||
public setChatNoteId(chatNoteId: string | null): void {
|
||||
this.chatNoteId = chatNoteId;
|
||||
public setNoteId(noteId: string | null): void {
|
||||
this.noteId = noteId;
|
||||
}
|
||||
|
||||
// Deprecated - keeping for backward compatibility but mapping to noteId
|
||||
public getChatNoteId(): string | null {
|
||||
return this.noteId;
|
||||
}
|
||||
|
||||
public setChatNoteId(noteId: string | null): void {
|
||||
this.noteId = noteId;
|
||||
}
|
||||
|
||||
public getNoteContextChatMessages(): HTMLElement {
|
||||
@ -307,10 +317,16 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
}
|
||||
}
|
||||
|
||||
const dataToSave: ChatData = {
|
||||
// Only save if we have a valid note ID
|
||||
if (!this.noteId) {
|
||||
console.warn('Cannot save chat data: no noteId available');
|
||||
return;
|
||||
}
|
||||
|
||||
const dataToSave = {
|
||||
messages: this.messages,
|
||||
chatNoteId: this.chatNoteId,
|
||||
noteId: this.noteId,
|
||||
chatNoteId: this.noteId, // For backward compatibility
|
||||
toolSteps: toolSteps,
|
||||
// Add sources if we have them
|
||||
sources: this.sources || [],
|
||||
@ -325,7 +341,7 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
}
|
||||
};
|
||||
|
||||
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`);
|
||||
console.log(`Saving chat data with 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
|
||||
@ -400,7 +416,6 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
// Load Chat Note ID if available
|
||||
if (savedData.noteId) {
|
||||
console.log(`Using noteId as Chat Note ID: ${savedData.noteId}`);
|
||||
this.chatNoteId = savedData.noteId;
|
||||
this.noteId = savedData.noteId;
|
||||
} else {
|
||||
console.log(`No noteId found in saved data, cannot load chat session`);
|
||||
@ -550,6 +565,15 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
// Get current note context if needed
|
||||
const currentActiveNoteId = appContext.tabManager.getActiveContext()?.note?.noteId || null;
|
||||
|
||||
// For AI Chat notes, the note itself IS the chat session
|
||||
// So currentNoteId and noteId should be the same
|
||||
if (this.noteId && currentActiveNoteId === this.noteId) {
|
||||
// We're in an AI Chat note - don't reset, just load saved data
|
||||
console.log(`Refreshing AI Chat note ${this.noteId} - loading saved data`);
|
||||
await this.loadSavedData();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're switching to a different note, we need to reset
|
||||
if (this.currentNoteId !== currentActiveNoteId) {
|
||||
console.log(`Note ID changed from ${this.currentNoteId} to ${currentActiveNoteId}, resetting chat panel`);
|
||||
@ -557,7 +581,6 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
// Reset the UI and data
|
||||
this.noteContextChatMessages.innerHTML = '';
|
||||
this.messages = [];
|
||||
this.chatNoteId = null;
|
||||
this.noteId = null; // Also reset the chat note ID
|
||||
this.hideSources(); // Hide any sources from previous note
|
||||
|
||||
@ -569,7 +592,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.chatNoteId || !this.noteId || !hasSavedData) {
|
||||
if (!this.noteId || !hasSavedData) {
|
||||
// Create a new chat session
|
||||
await this.createChatSession();
|
||||
}
|
||||
@ -580,19 +603,15 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
*/
|
||||
private async createChatSession() {
|
||||
try {
|
||||
// Create a new chat session, passing the current note ID if it exists
|
||||
const { chatNoteId, noteId } = await createChatSession(
|
||||
this.currentNoteId ? this.currentNoteId : undefined
|
||||
);
|
||||
// If we already have a noteId (for AI Chat notes), use it
|
||||
const contextNoteId = this.noteId || this.currentNoteId;
|
||||
|
||||
if (chatNoteId) {
|
||||
// If we got back an ID from the API, use it
|
||||
this.chatNoteId = chatNoteId;
|
||||
|
||||
// For new sessions, the noteId should equal the chatNoteId
|
||||
// This ensures we're using the note ID consistently
|
||||
this.noteId = noteId || chatNoteId;
|
||||
// Create a new chat session, passing the context note ID
|
||||
const noteId = await createChatSession(contextNoteId ? contextNoteId : undefined);
|
||||
|
||||
if (noteId) {
|
||||
// Set the note ID for this chat
|
||||
this.noteId = noteId;
|
||||
console.log(`Created new chat session with noteId: ${this.noteId}`);
|
||||
} else {
|
||||
throw new Error("Failed to create chat session - no ID returned");
|
||||
@ -645,7 +664,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.chatNoteId}`);
|
||||
console.log(`Sending message with: useAdvancedContext=${useAdvancedContext}, showThinking=${showThinking}, noteId=${this.currentNoteId}, sessionId=${this.noteId}`);
|
||||
|
||||
// Create the message parameters
|
||||
const messageParams = {
|
||||
@ -695,11 +714,11 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
await validateEmbeddingProviders(this.validationWarning);
|
||||
|
||||
// Make sure we have a valid session
|
||||
if (!this.chatNoteId) {
|
||||
if (!this.noteId) {
|
||||
// If no session ID, create a new session
|
||||
await this.createChatSession();
|
||||
|
||||
if (!this.chatNoteId) {
|
||||
if (!this.noteId) {
|
||||
// If still no session ID, show error and return
|
||||
console.error("Failed to create chat session");
|
||||
toastService.showError("Failed to create chat session");
|
||||
@ -730,7 +749,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.chatNoteId}`);
|
||||
console.log(`Sending message with: useAdvancedContext=${useAdvancedContext}, showThinking=${showThinking}, noteId=${this.currentNoteId}, sessionId=${this.noteId}`);
|
||||
|
||||
// Create the message parameters
|
||||
const messageParams = {
|
||||
@ -767,12 +786,12 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
*/
|
||||
private async handleDirectResponse(messageParams: any): Promise<boolean> {
|
||||
try {
|
||||
if (!this.chatNoteId) return false;
|
||||
if (!this.noteId) return false;
|
||||
|
||||
console.log(`Getting direct response using sessionId: ${this.chatNoteId} (noteId: ${this.noteId})`);
|
||||
console.log(`Getting direct response using sessionId: ${this.noteId} (noteId: ${this.noteId})`);
|
||||
|
||||
// Get a direct response from the server
|
||||
const postResponse = await getDirectResponse(this.chatNoteId, messageParams);
|
||||
const postResponse = await getDirectResponse(this.noteId, messageParams);
|
||||
|
||||
// If the POST request returned content directly, display it
|
||||
if (postResponse && postResponse.content) {
|
||||
@ -845,11 +864,11 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
* Set up streaming response via WebSocket
|
||||
*/
|
||||
private async setupStreamingResponse(messageParams: any): Promise<void> {
|
||||
if (!this.chatNoteId) {
|
||||
if (!this.noteId) {
|
||||
throw new Error("No session ID available");
|
||||
}
|
||||
|
||||
console.log(`Setting up streaming response using sessionId: ${this.chatNoteId} (noteId: ${this.noteId})`);
|
||||
console.log(`Setting up streaming response using sessionId: ${this.noteId} (noteId: ${this.noteId})`);
|
||||
|
||||
// Store tool executions captured during streaming
|
||||
const toolExecutionsCache: Array<{
|
||||
@ -862,7 +881,7 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
}> = [];
|
||||
|
||||
return setupStreamingResponse(
|
||||
this.chatNoteId,
|
||||
this.noteId,
|
||||
messageParams,
|
||||
// Content update handler
|
||||
(content: string, isDone: boolean = false) => {
|
||||
@ -898,7 +917,7 @@ export default class LlmChatPanel extends BasicWidget {
|
||||
similarity?: number;
|
||||
content?: string;
|
||||
}>;
|
||||
}>(`llm/chat/${this.chatNoteId}`)
|
||||
}>(`llm/chat/${this.noteId}`)
|
||||
.then((sessionData) => {
|
||||
console.log("Got updated session data:", sessionData);
|
||||
|
||||
|
@ -11,7 +11,7 @@ export interface ChatResponse {
|
||||
export interface SessionResponse {
|
||||
id: string;
|
||||
title: string;
|
||||
noteId?: string;
|
||||
noteId: string; // The ID of the chat note
|
||||
}
|
||||
|
||||
export interface ToolExecutionStep {
|
||||
@ -33,8 +33,8 @@ export interface MessageData {
|
||||
|
||||
export interface ChatData {
|
||||
messages: MessageData[];
|
||||
chatNoteId: string | null;
|
||||
noteId?: string | null;
|
||||
noteId: string; // The ID of the chat note
|
||||
chatNoteId?: string; // Deprecated - kept for backward compatibility, should equal noteId
|
||||
toolSteps: ToolExecutionStep[];
|
||||
sources?: Array<{
|
||||
noteId: string;
|
||||
|
@ -94,6 +94,11 @@ export default class AiChatTypeWidget extends TypeWidget {
|
||||
this.llmChatPanel.clearNoteContextChatMessages();
|
||||
this.llmChatPanel.setMessages([]);
|
||||
|
||||
// Set the note ID for the chat panel
|
||||
if (note) {
|
||||
this.llmChatPanel.setNoteId(note.noteId);
|
||||
}
|
||||
|
||||
// This will load saved data via the getData callback
|
||||
await this.llmChatPanel.refresh();
|
||||
this.isInitialized = true;
|
||||
@ -130,7 +135,7 @@ export default class AiChatTypeWidget extends TypeWidget {
|
||||
// Reset the chat panel UI
|
||||
this.llmChatPanel.clearNoteContextChatMessages();
|
||||
this.llmChatPanel.setMessages([]);
|
||||
this.llmChatPanel.setChatNoteId(null);
|
||||
this.llmChatPanel.setNoteId(this.note.noteId);
|
||||
}
|
||||
|
||||
// Call the parent method to refresh
|
||||
@ -152,6 +157,7 @@ export default class AiChatTypeWidget extends TypeWidget {
|
||||
// Make sure the chat panel has the current note ID
|
||||
if (this.note) {
|
||||
this.llmChatPanel.setCurrentNoteId(this.note.noteId);
|
||||
this.llmChatPanel.setNoteId(this.note.noteId);
|
||||
}
|
||||
|
||||
this.initPromise = (async () => {
|
||||
@ -186,7 +192,7 @@ export default class AiChatTypeWidget extends TypeWidget {
|
||||
// Format the data properly - this is the canonical format of the data
|
||||
const formattedData = {
|
||||
messages: data.messages || [],
|
||||
chatNoteId: data.chatNoteId || this.note.noteId,
|
||||
noteId: this.note.noteId, // Always use the note's own ID
|
||||
toolSteps: data.toolSteps || [],
|
||||
sources: data.sources || [],
|
||||
metadata: {
|
||||
|
@ -814,10 +814,11 @@ async function streamMessage(req: Request, res: Response) {
|
||||
throw new Error('Content cannot be empty');
|
||||
}
|
||||
|
||||
// Check if session exists
|
||||
const session = restChatService.getSessions().get(chatNoteId);
|
||||
// Get or create session from Chat Note
|
||||
// This will check the sessions store first, and if not found, create from the Chat Note
|
||||
const session = await restChatService.getOrCreateSessionFromChatNote(chatNoteId, true);
|
||||
if (!session) {
|
||||
throw new Error('Chat not found');
|
||||
throw new Error('Chat not found and could not be created from note');
|
||||
}
|
||||
|
||||
// Update last active timestamp
|
||||
|
@ -480,27 +480,56 @@ class RestChatService {
|
||||
const options: any = req.body || {};
|
||||
const title = options.title || 'Chat Session';
|
||||
|
||||
// Use the currentNoteId as the chatNoteId if provided
|
||||
let chatNoteId = options.chatNoteId;
|
||||
// Determine the note ID for the chat
|
||||
let noteId = options.noteId || options.chatNoteId; // Accept either name for backward compatibility
|
||||
|
||||
// If currentNoteId is provided but chatNoteId is not, use currentNoteId
|
||||
if (!chatNoteId && options.currentNoteId) {
|
||||
chatNoteId = options.currentNoteId;
|
||||
log.info(`Using provided currentNoteId ${chatNoteId} as chatNoteId`);
|
||||
// If currentNoteId is provided, check if it's already an AI Chat note
|
||||
if (!noteId && options.currentNoteId) {
|
||||
// Import becca to check note type
|
||||
const becca = (await import('../../../becca/becca.js')).default;
|
||||
const note = becca.notes[options.currentNoteId];
|
||||
|
||||
// Check if this is an AI Chat note by looking at its content structure
|
||||
if (note) {
|
||||
try {
|
||||
const content = note.getContent();
|
||||
if (content) {
|
||||
const contentStr = typeof content === 'string' ? content : content.toString();
|
||||
const parsedContent = JSON.parse(contentStr);
|
||||
// AI Chat notes have a messages array and noteId in their content
|
||||
if (parsedContent.messages && Array.isArray(parsedContent.messages) && parsedContent.noteId) {
|
||||
// This looks like an AI Chat note - use it directly
|
||||
noteId = options.currentNoteId;
|
||||
log.info(`Using existing AI Chat note ${noteId} as session`);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Not JSON content, so not an AI Chat note
|
||||
}
|
||||
}
|
||||
|
||||
if (!noteId) {
|
||||
log.info(`Creating new chat note from context of note ${options.currentNoteId}`);
|
||||
// Don't use the currentNoteId as the chat note ID - create a new one
|
||||
}
|
||||
}
|
||||
|
||||
// If we still don't have a chatNoteId, create a new Chat Note
|
||||
if (!chatNoteId) {
|
||||
// If we don't have a noteId, create a new Chat Note
|
||||
if (!noteId) {
|
||||
// Create a new Chat Note via the storage service
|
||||
const chatStorageService = (await import('../../llm/chat_storage_service.js')).default;
|
||||
const newChat = await chatStorageService.createChat(title);
|
||||
chatNoteId = newChat.id;
|
||||
log.info(`Created new Chat Note with ID: ${chatNoteId}`);
|
||||
noteId = newChat.id;
|
||||
log.info(`Created new Chat Note with ID: ${noteId}`);
|
||||
} else {
|
||||
// We have a noteId - this means we're working with an existing aiChat note
|
||||
// Don't create another note, just use the existing one
|
||||
log.info(`Using existing Chat Note with ID: ${noteId}`);
|
||||
}
|
||||
|
||||
// Create a new session through our session store
|
||||
// Create a new session through our session store using the note ID
|
||||
const session = SessionsStore.createSession({
|
||||
chatNoteId,
|
||||
chatNoteId: noteId, // This is really the noteId of the chat note
|
||||
title,
|
||||
systemPrompt: options.systemPrompt,
|
||||
contextNoteId: options.contextNoteId,
|
||||
@ -511,10 +540,10 @@ class RestChatService {
|
||||
});
|
||||
|
||||
return {
|
||||
id: session.id,
|
||||
id: session.id, // This will be the same as noteId
|
||||
title: session.title,
|
||||
createdAt: session.createdAt,
|
||||
noteId: chatNoteId // Return the note ID explicitly
|
||||
noteId: noteId // Return the note ID for clarity
|
||||
};
|
||||
} catch (error: any) {
|
||||
log.error(`Error creating LLM session: ${error.message || 'Unknown error'}`);
|
||||
|
Loading…
x
Reference in New Issue
Block a user