libre-webui 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +204 -0
- package/backend/dist/db.d.ts +19 -0
- package/backend/dist/db.d.ts.map +1 -0
- package/backend/dist/db.js +355 -0
- package/backend/dist/db.js.map +1 -0
- package/backend/dist/env.d.ts +2 -0
- package/backend/dist/env.d.ts.map +1 -0
- package/backend/dist/env.js +22 -0
- package/backend/dist/env.js.map +1 -0
- package/backend/dist/index.d.ts +4 -0
- package/backend/dist/index.d.ts.map +1 -0
- package/backend/dist/index.js +751 -0
- package/backend/dist/index.js.map +1 -0
- package/backend/dist/middleware/auth.d.ts +18 -0
- package/backend/dist/middleware/auth.d.ts.map +1 -0
- package/backend/dist/middleware/auth.js +98 -0
- package/backend/dist/middleware/auth.js.map +1 -0
- package/backend/dist/middleware/index.d.ts +5 -0
- package/backend/dist/middleware/index.d.ts.map +1 -0
- package/backend/dist/middleware/index.js +62 -0
- package/backend/dist/middleware/index.js.map +1 -0
- package/backend/dist/models/personaModel.d.ts +37 -0
- package/backend/dist/models/personaModel.d.ts.map +1 -0
- package/backend/dist/models/personaModel.js +269 -0
- package/backend/dist/models/personaModel.js.map +1 -0
- package/backend/dist/models/userModel.d.ts +86 -0
- package/backend/dist/models/userModel.d.ts.map +1 -0
- package/backend/dist/models/userModel.js +212 -0
- package/backend/dist/models/userModel.js.map +1 -0
- package/backend/dist/routes/auth.d.ts +3 -0
- package/backend/dist/routes/auth.d.ts.map +1 -0
- package/backend/dist/routes/auth.js +389 -0
- package/backend/dist/routes/auth.js.map +1 -0
- package/backend/dist/routes/chat.d.ts +3 -0
- package/backend/dist/routes/chat.d.ts.map +1 -0
- package/backend/dist/routes/chat.js +767 -0
- package/backend/dist/routes/chat.js.map +1 -0
- package/backend/dist/routes/documents.d.ts +3 -0
- package/backend/dist/routes/documents.d.ts.map +1 -0
- package/backend/dist/routes/documents.js +244 -0
- package/backend/dist/routes/documents.js.map +1 -0
- package/backend/dist/routes/ollama.d.ts +3 -0
- package/backend/dist/routes/ollama.d.ts.map +1 -0
- package/backend/dist/routes/ollama.js +549 -0
- package/backend/dist/routes/ollama.js.map +1 -0
- package/backend/dist/routes/personas.d.ts +3 -0
- package/backend/dist/routes/personas.d.ts.map +1 -0
- package/backend/dist/routes/personas.js +505 -0
- package/backend/dist/routes/personas.js.map +1 -0
- package/backend/dist/routes/plugins.d.ts +3 -0
- package/backend/dist/routes/plugins.d.ts.map +1 -0
- package/backend/dist/routes/plugins.js +417 -0
- package/backend/dist/routes/plugins.js.map +1 -0
- package/backend/dist/routes/preferences.d.ts +3 -0
- package/backend/dist/routes/preferences.d.ts.map +1 -0
- package/backend/dist/routes/preferences.js +303 -0
- package/backend/dist/routes/preferences.js.map +1 -0
- package/backend/dist/routes/tts.d.ts +3 -0
- package/backend/dist/routes/tts.d.ts.map +1 -0
- package/backend/dist/routes/tts.js +304 -0
- package/backend/dist/routes/tts.js.map +1 -0
- package/backend/dist/routes/users.d.ts +3 -0
- package/backend/dist/routes/users.d.ts.map +1 -0
- package/backend/dist/routes/users.js +246 -0
- package/backend/dist/routes/users.js.map +1 -0
- package/backend/dist/services/authService.d.ts +51 -0
- package/backend/dist/services/authService.d.ts.map +1 -0
- package/backend/dist/services/authService.js +153 -0
- package/backend/dist/services/authService.js.map +1 -0
- package/backend/dist/services/chatService.d.ts +52 -0
- package/backend/dist/services/chatService.d.ts.map +1 -0
- package/backend/dist/services/chatService.js +645 -0
- package/backend/dist/services/chatService.js.map +1 -0
- package/backend/dist/services/documentService.d.ts +34 -0
- package/backend/dist/services/documentService.d.ts.map +1 -0
- package/backend/dist/services/documentService.js +428 -0
- package/backend/dist/services/documentService.js.map +1 -0
- package/backend/dist/services/encryptionService.d.ts +62 -0
- package/backend/dist/services/encryptionService.d.ts.map +1 -0
- package/backend/dist/services/encryptionService.js +284 -0
- package/backend/dist/services/encryptionService.js.map +1 -0
- package/backend/dist/services/memoryService.d.ts +140 -0
- package/backend/dist/services/memoryService.d.ts.map +1 -0
- package/backend/dist/services/memoryService.js +867 -0
- package/backend/dist/services/memoryService.js.map +1 -0
- package/backend/dist/services/mutationEngineService.d.ts +49 -0
- package/backend/dist/services/mutationEngineService.d.ts.map +1 -0
- package/backend/dist/services/mutationEngineService.js +432 -0
- package/backend/dist/services/mutationEngineService.js.map +1 -0
- package/backend/dist/services/ollamaService.d.ts +55 -0
- package/backend/dist/services/ollamaService.d.ts.map +1 -0
- package/backend/dist/services/ollamaService.js +450 -0
- package/backend/dist/services/ollamaService.js.map +1 -0
- package/backend/dist/services/personaService.d.ts +67 -0
- package/backend/dist/services/personaService.d.ts.map +1 -0
- package/backend/dist/services/personaService.js +373 -0
- package/backend/dist/services/personaService.js.map +1 -0
- package/backend/dist/services/pluginService.d.ts +42 -0
- package/backend/dist/services/pluginService.d.ts.map +1 -0
- package/backend/dist/services/pluginService.js +961 -0
- package/backend/dist/services/pluginService.js.map +1 -0
- package/backend/dist/services/preferencesService.d.ts +35 -0
- package/backend/dist/services/preferencesService.d.ts.map +1 -0
- package/backend/dist/services/preferencesService.js +255 -0
- package/backend/dist/services/preferencesService.js.map +1 -0
- package/backend/dist/services/simpleGitHubOAuth.d.ts +48 -0
- package/backend/dist/services/simpleGitHubOAuth.d.ts.map +1 -0
- package/backend/dist/services/simpleGitHubOAuth.js +203 -0
- package/backend/dist/services/simpleGitHubOAuth.js.map +1 -0
- package/backend/dist/services/simpleHuggingFaceOAuth.d.ts +43 -0
- package/backend/dist/services/simpleHuggingFaceOAuth.d.ts.map +1 -0
- package/backend/dist/services/simpleHuggingFaceOAuth.js +159 -0
- package/backend/dist/services/simpleHuggingFaceOAuth.js.map +1 -0
- package/backend/dist/services/userService.d.ts +1 -0
- package/backend/dist/services/userService.d.ts.map +1 -0
- package/backend/dist/services/userService.js +18 -0
- package/backend/dist/services/userService.js.map +1 -0
- package/backend/dist/storage.d.ts +55 -0
- package/backend/dist/storage.d.ts.map +1 -0
- package/backend/dist/storage.js +741 -0
- package/backend/dist/storage.js.map +1 -0
- package/backend/dist/test-encryption.d.ts +2 -0
- package/backend/dist/test-encryption.d.ts.map +1 -0
- package/backend/dist/test-encryption.js +64 -0
- package/backend/dist/test-encryption.js.map +1 -0
- package/backend/dist/types/index.d.ts +523 -0
- package/backend/dist/types/index.d.ts.map +1 -0
- package/backend/dist/types/index.js +31 -0
- package/backend/dist/types/index.js.map +1 -0
- package/backend/dist/utils/generationUtils.d.ts +10 -0
- package/backend/dist/utils/generationUtils.d.ts.map +1 -0
- package/backend/dist/utils/generationUtils.js +49 -0
- package/backend/dist/utils/generationUtils.js.map +1 -0
- package/backend/dist/utils/hash.d.ts +29 -0
- package/backend/dist/utils/hash.d.ts.map +1 -0
- package/backend/dist/utils/hash.js +73 -0
- package/backend/dist/utils/hash.js.map +1 -0
- package/backend/dist/utils/jwt.d.ts +37 -0
- package/backend/dist/utils/jwt.d.ts.map +1 -0
- package/backend/dist/utils/jwt.js +86 -0
- package/backend/dist/utils/jwt.js.map +1 -0
- package/bin/cli.js +150 -0
- package/electron/main.js +322 -0
- package/frontend/dist/_redirects +1 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/frontend/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/frontend/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/frontend/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/frontend/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/frontend/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/frontend/dist/assets/index-CRQkB7Wz.js +3 -0
- package/frontend/dist/css/index-B1OjddR-.css +1 -0
- package/frontend/dist/favicon-dark.png +0 -0
- package/frontend/dist/favicon-light.png +0 -0
- package/frontend/dist/index.html +23 -0
- package/frontend/dist/js/ArtifactContainer-c_oi7XMs.js +23 -0
- package/frontend/dist/js/ArtifactDemoPage-CdfwJVXu.js +98 -0
- package/frontend/dist/js/ChatPage-CyotkmS0.js +281 -0
- package/frontend/dist/js/ModelsPage-DNaziPHc.js +2 -0
- package/frontend/dist/js/PersonasPage-DcnbJf8Q.js +13 -0
- package/frontend/dist/js/UserManagementPage-DtTf92dS.js +1 -0
- package/frontend/dist/js/markdown-vendor-D-79K2xZ.js +22 -0
- package/frontend/dist/js/react-vendor-N--QU9DW.js +8 -0
- package/frontend/dist/js/router-vendor-B-t91v39.js +3 -0
- package/frontend/dist/js/ui-vendor-VxSCY_bv.js +177 -0
- package/frontend/dist/js/utils-vendor-DNzxLBGx.js +6 -0
- package/frontend/dist/logo-dark.png +0 -0
- package/frontend/dist/logo-light.png +0 -0
- package/frontend/dist/logo.svg +14 -0
- package/package.json +128 -0
- package/plugins/anthropic.json +25 -0
- package/plugins/elevenlabs.json +58 -0
- package/plugins/gemini.json +57 -0
- package/plugins/github.json +23 -0
- package/plugins/groq.json +25 -0
- package/plugins/mistral.json +73 -0
- package/plugins/openai-tts.json +38 -0
- package/plugins/openai.json +132 -0
- package/plugins/openrouter.json +353 -0
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Libre WebUI
|
|
3
|
+
* Copyright (C) 2025 Kroonen AI, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at:
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
18
|
+
import storageService from '../storage.js';
|
|
19
|
+
import preferencesService from './preferencesService.js';
|
|
20
|
+
import { personaService } from './personaService.js';
|
|
21
|
+
import { memoryService } from './memoryService.js';
|
|
22
|
+
import { mutationEngineService } from './mutationEngineService.js';
|
|
23
|
+
class ChatService {
|
|
24
|
+
constructor() {
|
|
25
|
+
this.sessions = new Map();
|
|
26
|
+
this.loadSessions();
|
|
27
|
+
}
|
|
28
|
+
loadSessions() {
|
|
29
|
+
try {
|
|
30
|
+
const sessionsArray = storageService.getAllSessions();
|
|
31
|
+
this.sessions = new Map(sessionsArray.map(session => [session.id, session]));
|
|
32
|
+
console.log(`Loaded ${sessionsArray.length} sessions from storage`);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
console.error('Failed to load sessions:', error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
saveSessions() {
|
|
39
|
+
// This method is kept for compatibility but individual session saving is now handled by storage service
|
|
40
|
+
// The storage service handles both SQLite and JSON fallback
|
|
41
|
+
}
|
|
42
|
+
async createSession(model, title, userId = 'default', personaId) {
|
|
43
|
+
const sessionId = uuidv4();
|
|
44
|
+
const now = Date.now();
|
|
45
|
+
console.log(`🚀 ChatService.createSession: sessionId=%s, userId=%s, model=%s, personaId=%s`, sessionId, userId, model, personaId);
|
|
46
|
+
const session = {
|
|
47
|
+
id: sessionId,
|
|
48
|
+
title: title || 'New Chat',
|
|
49
|
+
messages: [],
|
|
50
|
+
model,
|
|
51
|
+
createdAt: now,
|
|
52
|
+
updatedAt: now,
|
|
53
|
+
personaId,
|
|
54
|
+
};
|
|
55
|
+
// Add system message - prioritize persona system prompt over global preferences
|
|
56
|
+
let systemMessage = '';
|
|
57
|
+
let systemMessageSource = 'none';
|
|
58
|
+
console.log(`[DEBUG] createSession model: "${model}", starts with persona: ${model.startsWith('persona:')}`);
|
|
59
|
+
// If model is a persona, try to get the persona's system prompt
|
|
60
|
+
if (model.startsWith('persona:')) {
|
|
61
|
+
try {
|
|
62
|
+
const personaIdFromModel = model.replace('persona:', '');
|
|
63
|
+
console.log(`[DEBUG] Extracting persona ID: "%s" for user: "%s"`, personaIdFromModel, userId);
|
|
64
|
+
const { personaService } = await import('./personaService.js');
|
|
65
|
+
// Get persona for the current user only (no fallback to maintain privacy)
|
|
66
|
+
const persona = await personaService.getPersonaById(personaIdFromModel, userId);
|
|
67
|
+
console.log(`[DEBUG] Persona lookup for user ${userId}:`, persona ? `Found: ${persona.name}` : 'Not found');
|
|
68
|
+
if (persona && persona.parameters?.system_prompt) {
|
|
69
|
+
systemMessage = persona.parameters.system_prompt.trim();
|
|
70
|
+
systemMessageSource = `persona:${persona.name}`;
|
|
71
|
+
console.log(`[DEBUG] Using persona system prompt from ${persona.name}: "${systemMessage.substring(0, 100)}..."`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
console.log(`[DEBUG] No system prompt found in persona or persona not found`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error(`❌ Error getting persona system prompt:`, error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// If no persona system prompt, fall back to global preferences
|
|
82
|
+
if (!systemMessage) {
|
|
83
|
+
const globalSystemMessage = preferencesService.getSystemMessage(userId);
|
|
84
|
+
if (globalSystemMessage && globalSystemMessage.trim()) {
|
|
85
|
+
systemMessage = globalSystemMessage.trim();
|
|
86
|
+
systemMessageSource = 'preferences';
|
|
87
|
+
console.log(`[DEBUG] Using global system message: "${systemMessage.substring(0, 100)}..."`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Add the system message if we have one
|
|
91
|
+
if (systemMessage) {
|
|
92
|
+
console.log(`✅ Adding system message to session: ${sessionId} (source: ${systemMessageSource})`);
|
|
93
|
+
const systemMsg = {
|
|
94
|
+
id: uuidv4(),
|
|
95
|
+
role: 'system',
|
|
96
|
+
content: systemMessage,
|
|
97
|
+
timestamp: now,
|
|
98
|
+
};
|
|
99
|
+
session.messages.push(systemMsg);
|
|
100
|
+
session.updatedAt = now;
|
|
101
|
+
}
|
|
102
|
+
this.sessions.set(sessionId, session);
|
|
103
|
+
console.log(`📝 Session stored in cache: ${sessionId}`);
|
|
104
|
+
// Save to storage with user ID
|
|
105
|
+
storageService.saveSession(session, userId);
|
|
106
|
+
console.log(`💾 Session saved to storage: ${sessionId} for user ${userId}`);
|
|
107
|
+
return session;
|
|
108
|
+
}
|
|
109
|
+
getSession(sessionId, userId = 'default') {
|
|
110
|
+
console.log(`🔍 ChatService.getSession: sessionId=${sessionId}, userId=${userId}`);
|
|
111
|
+
// First try to get from memory cache
|
|
112
|
+
let session = this.sessions.get(sessionId);
|
|
113
|
+
console.log(`📝 Session in cache: ${session ? 'YES' : 'NO'}`);
|
|
114
|
+
// If not in cache, try to load from storage (with user verification)
|
|
115
|
+
if (!session) {
|
|
116
|
+
session = storageService.getSession(sessionId, userId);
|
|
117
|
+
console.log(`💾 Session in storage: ${session ? 'YES' : 'NO'}`);
|
|
118
|
+
if (session) {
|
|
119
|
+
this.sessions.set(sessionId, session);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
// If found in cache, we should still verify it belongs to this user
|
|
124
|
+
// by checking the storage service (which has the user verification logic)
|
|
125
|
+
const verifiedSession = storageService.getSession(sessionId, userId);
|
|
126
|
+
console.log(`✅ Session verification: ${verifiedSession ? 'PASSED' : 'FAILED'}`);
|
|
127
|
+
if (!verifiedSession) {
|
|
128
|
+
// Session doesn't belong to this user, remove from cache and return undefined
|
|
129
|
+
console.log(`❌ Removing session ${sessionId} from cache - verification failed`);
|
|
130
|
+
this.sessions.delete(sessionId);
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
console.log(`🎯 Returning session: ${session ? session.id : 'undefined'}`);
|
|
135
|
+
return session;
|
|
136
|
+
}
|
|
137
|
+
getAllSessions(userId = 'default') {
|
|
138
|
+
// Load fresh data from storage to ensure we have the latest
|
|
139
|
+
const sessionsArray = storageService.getAllSessions(userId);
|
|
140
|
+
// Update memory cache with user-specific sessions
|
|
141
|
+
// Note: We don't clear the entire cache since other users might be using it
|
|
142
|
+
sessionsArray.forEach(session => {
|
|
143
|
+
this.sessions.set(session.id, session);
|
|
144
|
+
});
|
|
145
|
+
return sessionsArray;
|
|
146
|
+
}
|
|
147
|
+
async updateSession(sessionId, updates, userId = 'default') {
|
|
148
|
+
// First verify the session belongs to the user
|
|
149
|
+
const session = this.getSession(sessionId, userId);
|
|
150
|
+
if (!session)
|
|
151
|
+
return undefined;
|
|
152
|
+
const updatedSession = {
|
|
153
|
+
...session,
|
|
154
|
+
...updates,
|
|
155
|
+
updatedAt: Date.now(),
|
|
156
|
+
};
|
|
157
|
+
// If the model is being updated and it's a persona, update the system message and personaId
|
|
158
|
+
if (updates.model && updates.model !== session.model) {
|
|
159
|
+
console.log(`[DEBUG] updateSession: Model changed from "${session.model}" to "${updates.model}"`);
|
|
160
|
+
if (updates.model.startsWith('persona:')) {
|
|
161
|
+
const personaId = updates.model.replace('persona:', '');
|
|
162
|
+
console.log(`[DEBUG] updateSession: Extracting persona ID: %s`, personaId);
|
|
163
|
+
// Update personaId
|
|
164
|
+
updatedSession.personaId = personaId;
|
|
165
|
+
// Update system message with persona's system prompt
|
|
166
|
+
await this.updateSystemMessageForPersona(updatedSession, personaId, userId);
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// If switching away from a persona to a regular model, clear personaId and use default system message
|
|
170
|
+
updatedSession.personaId = undefined;
|
|
171
|
+
this.updateSystemMessageToDefault(updatedSession, userId);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
this.sessions.set(sessionId, updatedSession);
|
|
175
|
+
storageService.saveSession(updatedSession, userId);
|
|
176
|
+
return updatedSession;
|
|
177
|
+
}
|
|
178
|
+
addMessage(sessionId, message, userId = 'default') {
|
|
179
|
+
console.log(`[addMessage] Called with sessionId=${sessionId}, role=${message.role}, id=${message.id}, userId=${userId}`);
|
|
180
|
+
// First verify the session belongs to the user
|
|
181
|
+
const session = this.getSession(sessionId, userId);
|
|
182
|
+
if (!session) {
|
|
183
|
+
console.log(`[addMessage] Session not found: ${sessionId}`);
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
console.log(`[addMessage] Session found with ${session.messages.length} messages`);
|
|
187
|
+
const messageId = message.id || uuidv4();
|
|
188
|
+
// Check if message with this ID already exists to prevent duplicates
|
|
189
|
+
const existingMessage = session.messages.find(msg => msg.id === messageId);
|
|
190
|
+
if (existingMessage) {
|
|
191
|
+
console.log(`[addMessage] Message with ID already exists, skipping duplicate: ${messageId}, existing content length: ${existingMessage.content.length}`);
|
|
192
|
+
return existingMessage;
|
|
193
|
+
}
|
|
194
|
+
const newMessage = {
|
|
195
|
+
...message,
|
|
196
|
+
id: messageId,
|
|
197
|
+
timestamp: Date.now(),
|
|
198
|
+
};
|
|
199
|
+
// If this is a branch message (has parentId), update sibling messages
|
|
200
|
+
if (newMessage.parentId) {
|
|
201
|
+
const parentId = newMessage.parentId;
|
|
202
|
+
// Mark all sibling messages (including the parent) as inactive
|
|
203
|
+
for (const msg of session.messages) {
|
|
204
|
+
const isSibling = msg.id === parentId || msg.parentId === parentId;
|
|
205
|
+
if (isSibling) {
|
|
206
|
+
msg.isActive = false;
|
|
207
|
+
// Ensure the parent has branchIndex 0 if it doesn't have one
|
|
208
|
+
if (msg.branchIndex === undefined) {
|
|
209
|
+
msg.branchIndex = 0;
|
|
210
|
+
}
|
|
211
|
+
// Update siblingCount for all siblings
|
|
212
|
+
msg.siblingCount = (newMessage.branchIndex || 0) + 1;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
session.messages.push(newMessage);
|
|
217
|
+
session.updatedAt = Date.now();
|
|
218
|
+
// Process advanced persona features if applicable
|
|
219
|
+
console.log(`[DEBUG] addMessage: Checking advanced processing - personaId: ${session.personaId}, messageRole: ${message.role}, content length: ${message.content.length}`);
|
|
220
|
+
if (session.personaId) {
|
|
221
|
+
console.log(`[DEBUG] addMessage: PersonaId exists, processing message role: ${message.role}`);
|
|
222
|
+
if (message.role === 'user') {
|
|
223
|
+
console.log(`[DEBUG] addMessage: Starting advanced user interaction processing for persona ${session.personaId}`);
|
|
224
|
+
this.processAdvancedPersonaInteraction(session.personaId, userId, message.content, session).catch((error) => console.error('Advanced persona processing error:', error));
|
|
225
|
+
}
|
|
226
|
+
else if (message.role === 'assistant') {
|
|
227
|
+
console.log(`[DEBUG] addMessage: Starting advanced assistant response processing for persona ${session.personaId}`);
|
|
228
|
+
this.processAdvancedPersonaResponse(session.personaId, userId, message.content).catch((error) => console.error('Advanced persona response processing error:', error));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
console.log(`[DEBUG] addMessage: No personaId found, skipping advanced processing`);
|
|
233
|
+
}
|
|
234
|
+
// Auto-generate title from first user message
|
|
235
|
+
const userMessages = session.messages.filter(msg => msg.role === 'user');
|
|
236
|
+
if (userMessages.length === 1 &&
|
|
237
|
+
message.role === 'user' &&
|
|
238
|
+
session.title === 'New Chat') {
|
|
239
|
+
session.title = this.generateTitle(message.content);
|
|
240
|
+
}
|
|
241
|
+
this.sessions.set(sessionId, session);
|
|
242
|
+
storageService.saveSession(session, userId);
|
|
243
|
+
console.log(`[addMessage] Message saved successfully: ${newMessage.id}, session now has ${session.messages.length} messages`);
|
|
244
|
+
return newMessage;
|
|
245
|
+
}
|
|
246
|
+
updateMessage(sessionId, messageId, updates, userId = 'default') {
|
|
247
|
+
// First verify the session belongs to the user
|
|
248
|
+
const session = this.getSession(sessionId, userId);
|
|
249
|
+
if (!session) {
|
|
250
|
+
console.error('Session not found or access denied:', sessionId, userId);
|
|
251
|
+
return undefined;
|
|
252
|
+
}
|
|
253
|
+
// Find the message to update
|
|
254
|
+
const messageIndex = session.messages.findIndex(msg => msg.id === messageId);
|
|
255
|
+
if (messageIndex === -1) {
|
|
256
|
+
console.error('Message not found:', messageId);
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
// Update the message
|
|
260
|
+
const updatedMessage = {
|
|
261
|
+
...session.messages[messageIndex],
|
|
262
|
+
...updates,
|
|
263
|
+
timestamp: Date.now(), // Always update timestamp
|
|
264
|
+
};
|
|
265
|
+
session.messages[messageIndex] = updatedMessage;
|
|
266
|
+
session.updatedAt = Date.now();
|
|
267
|
+
// Save updated session
|
|
268
|
+
this.sessions.set(sessionId, session);
|
|
269
|
+
storageService.saveSession(session, userId);
|
|
270
|
+
console.log(`✅ Updated message ${messageId} in session ${sessionId}`);
|
|
271
|
+
return updatedMessage;
|
|
272
|
+
}
|
|
273
|
+
deleteSession(sessionId, userId = 'default') {
|
|
274
|
+
// First verify the session belongs to the user
|
|
275
|
+
const session = this.getSession(sessionId, userId);
|
|
276
|
+
if (!session)
|
|
277
|
+
return false;
|
|
278
|
+
const deleted = storageService.deleteSession(sessionId, userId);
|
|
279
|
+
if (deleted) {
|
|
280
|
+
this.sessions.delete(sessionId);
|
|
281
|
+
}
|
|
282
|
+
return deleted;
|
|
283
|
+
}
|
|
284
|
+
clearAllSessions(userId = 'default') {
|
|
285
|
+
// Get all sessions for the user first
|
|
286
|
+
const userSessions = this.getAllSessions(userId);
|
|
287
|
+
// Remove them from memory cache
|
|
288
|
+
userSessions.forEach(session => {
|
|
289
|
+
this.sessions.delete(session.id);
|
|
290
|
+
});
|
|
291
|
+
// Clear them from storage
|
|
292
|
+
userSessions.forEach(session => {
|
|
293
|
+
storageService.deleteSession(session.id, userId);
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
generateTitle(content) {
|
|
297
|
+
// Generate a concise title from the first message
|
|
298
|
+
const words = content.trim().split(/\s+/).slice(0, 6);
|
|
299
|
+
let title = words.join(' ');
|
|
300
|
+
if (title.length > 50) {
|
|
301
|
+
title = title.substring(0, 47) + '...';
|
|
302
|
+
}
|
|
303
|
+
return title || 'New Chat';
|
|
304
|
+
}
|
|
305
|
+
getMessagesForContext(sessionId, maxMessages = 10) {
|
|
306
|
+
const session = this.sessions.get(sessionId);
|
|
307
|
+
if (!session)
|
|
308
|
+
return [];
|
|
309
|
+
// Separate system messages from conversation messages
|
|
310
|
+
// Only include active messages (isActive !== false) to respect branch selection
|
|
311
|
+
const systemMessages = session.messages.filter(msg => msg.role === 'system');
|
|
312
|
+
const conversationMessages = session.messages.filter(msg => msg.role !== 'system' && msg.isActive !== false);
|
|
313
|
+
// Take the last N conversation messages, but always include all system messages first
|
|
314
|
+
const recentConversation = conversationMessages.slice(-maxMessages);
|
|
315
|
+
// Return system messages first, then conversation messages
|
|
316
|
+
const contextMessages = [...systemMessages, ...recentConversation];
|
|
317
|
+
// Debug: Log the system messages being sent
|
|
318
|
+
if (systemMessages.length > 0) {
|
|
319
|
+
console.log(`🎯 [DEBUG] Context for session ${sessionId}:`);
|
|
320
|
+
systemMessages.forEach((msg, index) => {
|
|
321
|
+
console.log(` System message ${index + 1}: "${msg.content.substring(0, 100)}${msg.content.length > 100 ? '...' : ''}"`);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return contextMessages;
|
|
325
|
+
}
|
|
326
|
+
async updateSystemMessageForPersona(session, personaId, userId) {
|
|
327
|
+
try {
|
|
328
|
+
console.log(`[DEBUG] updateSystemMessageForPersona: Starting for persona %s, user %s`, personaId, userId);
|
|
329
|
+
// Get persona for the current user only (no fallback to maintain privacy)
|
|
330
|
+
const persona = await personaService.getPersonaById(personaId, userId);
|
|
331
|
+
if (persona && persona.parameters?.system_prompt) {
|
|
332
|
+
const newSystemMessage = persona.parameters.system_prompt.trim();
|
|
333
|
+
console.log(`[DEBUG] updateSystemMessageForPersona: Found persona system prompt: "${newSystemMessage.substring(0, 100)}..."`);
|
|
334
|
+
// Update or replace the system message
|
|
335
|
+
this.replaceSystemMessage(session, newSystemMessage);
|
|
336
|
+
console.log(`[DEBUG] updateSystemMessageForPersona: Successfully updated system message for session ${session.id}`);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
console.log(`[DEBUG] updateSystemMessageForPersona: No system prompt found for persona %s, using default`, personaId);
|
|
340
|
+
// Fallback to default system message
|
|
341
|
+
this.updateSystemMessageToDefault(session, userId);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
console.error(`[ERROR] updateSystemMessageForPersona: Error getting persona %s:`, personaId, error);
|
|
346
|
+
// Fallback to default system message
|
|
347
|
+
this.updateSystemMessageToDefault(session, userId);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
updateSystemMessageToDefault(session, userId) {
|
|
351
|
+
const defaultSystemMessage = preferencesService.getSystemMessage(userId);
|
|
352
|
+
console.log(`[DEBUG] updateSystemMessageToDefault: Using default system message: "${defaultSystemMessage.substring(0, 100)}..."`);
|
|
353
|
+
this.replaceSystemMessage(session, defaultSystemMessage);
|
|
354
|
+
}
|
|
355
|
+
replaceSystemMessage(session, newSystemMessage) {
|
|
356
|
+
// Find existing system message
|
|
357
|
+
const systemMessageIndex = session.messages.findIndex(msg => msg.role === 'system');
|
|
358
|
+
if (systemMessageIndex !== -1) {
|
|
359
|
+
// Update existing system message
|
|
360
|
+
session.messages[systemMessageIndex] = {
|
|
361
|
+
...session.messages[systemMessageIndex],
|
|
362
|
+
content: newSystemMessage,
|
|
363
|
+
timestamp: Date.now(),
|
|
364
|
+
};
|
|
365
|
+
console.log(`[DEBUG] replaceSystemMessage: Updated existing system message`);
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
// Add new system message at the beginning
|
|
369
|
+
const systemMessage = {
|
|
370
|
+
id: uuidv4(),
|
|
371
|
+
role: 'system',
|
|
372
|
+
content: newSystemMessage,
|
|
373
|
+
timestamp: Date.now(),
|
|
374
|
+
};
|
|
375
|
+
session.messages.unshift(systemMessage);
|
|
376
|
+
console.log(`[DEBUG] replaceSystemMessage: Added new system message`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Process advanced persona interactions: memory storage, retrieval, and mutations
|
|
381
|
+
*/
|
|
382
|
+
async processAdvancedPersonaInteraction(personaId, userId, userMessage, session) {
|
|
383
|
+
try {
|
|
384
|
+
console.log(`[ADVANCED-DEBUG] processAdvancedPersonaInteraction called - personaId: ${personaId}, userId: ${userId}`);
|
|
385
|
+
// Check if persona has advanced features enabled for current user only (no fallback to maintain privacy)
|
|
386
|
+
const persona = await personaService.getPersonaById(personaId, userId);
|
|
387
|
+
console.log(`[ADVANCED-DEBUG] Persona lookup for user ${userId}:`, persona ? `Found: ${persona.name}` : 'Not found');
|
|
388
|
+
if (!persona) {
|
|
389
|
+
console.log(`[ADVANCED-DEBUG] No persona found for user, exiting`);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
// Check if this persona has advanced features (memory or adaptive learning)
|
|
393
|
+
const hasAdvancedFeatures = persona.embedding_model || persona.memory_settings;
|
|
394
|
+
console.log(`[ADVANCED-DEBUG] Advanced features check:`, {
|
|
395
|
+
embedding_model: persona.embedding_model,
|
|
396
|
+
memory_settings: persona.memory_settings,
|
|
397
|
+
hasAdvancedFeatures,
|
|
398
|
+
});
|
|
399
|
+
if (!hasAdvancedFeatures) {
|
|
400
|
+
console.log(`[ADVANCED-DEBUG] No advanced features, exiting`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
console.log(`[ADVANCED] Processing interaction for persona ${persona.name} (${personaId})`);
|
|
404
|
+
// Get advanced settings
|
|
405
|
+
const embeddingModel = persona.embedding_model || 'nomic-embed-text';
|
|
406
|
+
console.log(`[ADVANCED] Using embedding model: ${embeddingModel}`);
|
|
407
|
+
console.log(`[ADVANCED] Advanced features enabled`);
|
|
408
|
+
// 1. Store the user message as a memory
|
|
409
|
+
console.log(`[ADVANCED] Storing user message as memory...`);
|
|
410
|
+
await memoryService.storeMemory(userId, personaId, userMessage, embeddingModel, undefined, // context
|
|
411
|
+
0.7 // importance score
|
|
412
|
+
);
|
|
413
|
+
console.log(`[ADVANCED] ✅ User message stored successfully`);
|
|
414
|
+
// 2. Search for relevant memories
|
|
415
|
+
console.log(`[ADVANCED] Searching for relevant memories...`);
|
|
416
|
+
const relevantMemories = await memoryService.searchMemories(userId, personaId, userMessage, embeddingModel, 5, // topK
|
|
417
|
+
0.3 // similarity threshold
|
|
418
|
+
);
|
|
419
|
+
console.log(`[ADVANCED] Found ${relevantMemories.length} relevant memories`);
|
|
420
|
+
if (relevantMemories.length > 0) {
|
|
421
|
+
console.log(`[ADVANCED] Memory details:`, relevantMemories.map(m => ({
|
|
422
|
+
content: m.entry.content.substring(0, 100) + '...',
|
|
423
|
+
similarity: (m.similarity_score * 100).toFixed(1) + '%',
|
|
424
|
+
})));
|
|
425
|
+
}
|
|
426
|
+
// 3. Process potential mutations based on the interaction
|
|
427
|
+
if (relevantMemories.length > 0) {
|
|
428
|
+
await mutationEngineService.processMutation(userMessage, persona, // Cast to Persona for mutation engine
|
|
429
|
+
userId, relevantMemories);
|
|
430
|
+
}
|
|
431
|
+
// 4. Update system message with relevant memories if any found
|
|
432
|
+
if (relevantMemories.length > 0) {
|
|
433
|
+
await this.updateSystemMessageWithMemories(session, persona, relevantMemories, userId);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
catch (error) {
|
|
437
|
+
console.error(`[ADVANCED] Error processing persona interaction:`, error);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Update system message to include relevant memories
|
|
442
|
+
*/
|
|
443
|
+
async updateSystemMessageWithMemories(session, persona, memories, userId) {
|
|
444
|
+
try {
|
|
445
|
+
const baseSystemPrompt = persona.parameters?.system_prompt || '';
|
|
446
|
+
// Get core memories (always-include important facts, preferences, instructions)
|
|
447
|
+
const coreMemories = await memoryService.getCoreMemories(userId, persona.id, 3);
|
|
448
|
+
// Combine core memories with contextual memories, avoiding duplicates
|
|
449
|
+
const coreIds = new Set(coreMemories.map(m => m.id));
|
|
450
|
+
const contextualMemories = memories
|
|
451
|
+
.filter(m => !coreIds.has(m.entry.id))
|
|
452
|
+
.slice(0, 3);
|
|
453
|
+
if (coreMemories.length === 0 && contextualMemories.length === 0)
|
|
454
|
+
return;
|
|
455
|
+
// Build memory context sections
|
|
456
|
+
let memoryContext = '';
|
|
457
|
+
// Core memories section (always relevant)
|
|
458
|
+
if (coreMemories.length > 0) {
|
|
459
|
+
memoryContext += '=== Core Knowledge ===\n';
|
|
460
|
+
memoryContext += coreMemories
|
|
461
|
+
.map(memory => {
|
|
462
|
+
const type = memory.memory_type || 'general';
|
|
463
|
+
const typeLabel = type === 'fact'
|
|
464
|
+
? 'Fact'
|
|
465
|
+
: type === 'preference'
|
|
466
|
+
? 'Preference'
|
|
467
|
+
: type === 'instruction'
|
|
468
|
+
? 'Instruction'
|
|
469
|
+
: 'Info';
|
|
470
|
+
return `[${typeLabel}] ${memory.content}`;
|
|
471
|
+
})
|
|
472
|
+
.join('\n');
|
|
473
|
+
memoryContext += '\n\n';
|
|
474
|
+
}
|
|
475
|
+
// Contextual memories section (relevant to current query)
|
|
476
|
+
if (contextualMemories.length > 0) {
|
|
477
|
+
memoryContext += '=== Relevant Context ===\n';
|
|
478
|
+
memoryContext += contextualMemories
|
|
479
|
+
.map(memory => {
|
|
480
|
+
const relevance = (memory.similarity_score * 100).toFixed(0);
|
|
481
|
+
return `[${relevance}% match] ${memory.entry.content}`;
|
|
482
|
+
})
|
|
483
|
+
.join('\n');
|
|
484
|
+
}
|
|
485
|
+
const enhancedSystemPrompt = `${baseSystemPrompt}
|
|
486
|
+
|
|
487
|
+
[PERSONA MEMORY CONTEXT]
|
|
488
|
+
You have access to the following memories from past interactions with this user:
|
|
489
|
+
|
|
490
|
+
${memoryContext.trim()}
|
|
491
|
+
|
|
492
|
+
Guidelines:
|
|
493
|
+
- Use Core Knowledge naturally in your responses - these are established facts about the user
|
|
494
|
+
- Reference Relevant Context when it helps answer the current question
|
|
495
|
+
- Don't explicitly mention having "memories" - integrate knowledge seamlessly
|
|
496
|
+
- If memories conflict with current information, prioritize the most recent
|
|
497
|
+
[END MEMORY CONTEXT]`;
|
|
498
|
+
// Update the system message
|
|
499
|
+
const systemMessageIndex = session.messages.findIndex(msg => msg.role === 'system');
|
|
500
|
+
if (systemMessageIndex !== -1) {
|
|
501
|
+
session.messages[systemMessageIndex] = {
|
|
502
|
+
...session.messages[systemMessageIndex],
|
|
503
|
+
content: enhancedSystemPrompt,
|
|
504
|
+
timestamp: Date.now(),
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
// Add new system message
|
|
509
|
+
const systemMessage = {
|
|
510
|
+
id: uuidv4(),
|
|
511
|
+
role: 'system',
|
|
512
|
+
content: enhancedSystemPrompt,
|
|
513
|
+
timestamp: Date.now(),
|
|
514
|
+
};
|
|
515
|
+
session.messages.unshift(systemMessage);
|
|
516
|
+
}
|
|
517
|
+
// Save the updated session
|
|
518
|
+
this.sessions.set(session.id, session);
|
|
519
|
+
storageService.saveSession(session, userId);
|
|
520
|
+
console.log(`[ADVANCED] Updated system message with ${coreMemories.length} core + ${contextualMemories.length} contextual memories`);
|
|
521
|
+
}
|
|
522
|
+
catch (error) {
|
|
523
|
+
console.error(`[ADVANCED] Error updating system message with memories:`, error);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Process advanced persona response - store AI responses as memories for future reference
|
|
528
|
+
*/
|
|
529
|
+
async processAdvancedPersonaResponse(personaId, userId, assistantMessage) {
|
|
530
|
+
try {
|
|
531
|
+
console.log(`[ADVANCED-DEBUG] processAdvancedPersonaResponse called - personaId: ${personaId}, userId: ${userId}`);
|
|
532
|
+
// Check if persona has advanced features enabled for current user only (no fallback to maintain privacy)
|
|
533
|
+
const persona = await personaService.getPersonaById(personaId, userId);
|
|
534
|
+
console.log(`[ADVANCED-DEBUG] Persona lookup for user ${userId}:`, persona ? `Found: ${persona.name}` : 'Not found');
|
|
535
|
+
if (!persona) {
|
|
536
|
+
console.log(`[ADVANCED-DEBUG] No persona found for user, exiting`);
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
const hasAdvancedFeatures = persona.embedding_model || persona.memory_settings;
|
|
540
|
+
console.log(`[ADVANCED-DEBUG] Advanced detection check:`, {
|
|
541
|
+
embedding_model: persona.embedding_model,
|
|
542
|
+
memory_settings: persona.memory_settings,
|
|
543
|
+
hasAdvancedFeatures,
|
|
544
|
+
});
|
|
545
|
+
if (!hasAdvancedFeatures) {
|
|
546
|
+
console.log(`[ADVANCED-DEBUG] Not an advanced persona, exiting`);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
console.log(`[ADVANCED] Storing assistant response as memory for persona ${persona.name}`);
|
|
550
|
+
// Get advanced settings
|
|
551
|
+
const embeddingModel = persona.embedding_model || 'nomic-embed-text';
|
|
552
|
+
// Store the assistant response as a memory for future context
|
|
553
|
+
await memoryService.storeMemory(userId, personaId, `Assistant response: ${assistantMessage}`, embeddingModel, undefined, // context
|
|
554
|
+
0.6 // slightly lower importance than user messages
|
|
555
|
+
);
|
|
556
|
+
console.log(`[ADVANCED] ✅ Assistant response stored successfully`);
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
console.error(`[ADVANCED] Error processing persona response:`, error);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Create a new branch for a message (used for regeneration)
|
|
564
|
+
* This marks the original message as inactive and creates a new active variant
|
|
565
|
+
*/
|
|
566
|
+
createMessageBranch(sessionId, originalMessageId, newMessage, userId = 'default') {
|
|
567
|
+
const session = this.getSession(sessionId, userId);
|
|
568
|
+
if (!session)
|
|
569
|
+
return undefined;
|
|
570
|
+
const originalMessage = session.messages.find(msg => msg.id === originalMessageId);
|
|
571
|
+
if (!originalMessage)
|
|
572
|
+
return undefined;
|
|
573
|
+
// The parent is either the original's parent (if it's already a variant) or the original itself
|
|
574
|
+
const parentId = originalMessage.parentId || originalMessageId;
|
|
575
|
+
// Find all siblings to determine the new branch index
|
|
576
|
+
const siblings = session.messages.filter(msg => msg.id === parentId || msg.parentId === parentId);
|
|
577
|
+
const newBranchIndex = siblings.length;
|
|
578
|
+
// Mark all current siblings as inactive
|
|
579
|
+
for (const sibling of siblings) {
|
|
580
|
+
sibling.isActive = false;
|
|
581
|
+
}
|
|
582
|
+
const messageId = newMessage.id || uuidv4();
|
|
583
|
+
const newBranchMessage = {
|
|
584
|
+
...newMessage,
|
|
585
|
+
id: messageId,
|
|
586
|
+
timestamp: Date.now(),
|
|
587
|
+
parentId: parentId,
|
|
588
|
+
branchIndex: newBranchIndex,
|
|
589
|
+
isActive: true,
|
|
590
|
+
siblingCount: newBranchIndex + 1,
|
|
591
|
+
};
|
|
592
|
+
// Update sibling counts for all related messages
|
|
593
|
+
for (const sibling of siblings) {
|
|
594
|
+
sibling.siblingCount = newBranchIndex + 1;
|
|
595
|
+
}
|
|
596
|
+
session.messages.push(newBranchMessage);
|
|
597
|
+
session.updatedAt = Date.now();
|
|
598
|
+
this.sessions.set(sessionId, session);
|
|
599
|
+
storageService.saveSession(session, userId);
|
|
600
|
+
return newBranchMessage;
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Switch to a different branch of a message
|
|
604
|
+
*/
|
|
605
|
+
switchMessageBranch(sessionId, messageId, targetBranchIndex, userId = 'default') {
|
|
606
|
+
const session = this.getSession(sessionId, userId);
|
|
607
|
+
if (!session)
|
|
608
|
+
return undefined;
|
|
609
|
+
// Find the target message directly by ID
|
|
610
|
+
const targetMessage = session.messages.find(msg => msg.id === messageId);
|
|
611
|
+
if (!targetMessage)
|
|
612
|
+
return undefined;
|
|
613
|
+
// Find the parent ID (the original message that spawned branches)
|
|
614
|
+
const parentId = targetMessage.parentId || messageId;
|
|
615
|
+
// Find all siblings (including the original parent message)
|
|
616
|
+
const siblings = session.messages.filter(msg => msg.id === parentId || msg.parentId === parentId);
|
|
617
|
+
// Mark all siblings as inactive, then mark the target as active
|
|
618
|
+
for (const sibling of siblings) {
|
|
619
|
+
sibling.isActive = false;
|
|
620
|
+
}
|
|
621
|
+
targetMessage.isActive = true;
|
|
622
|
+
session.updatedAt = Date.now();
|
|
623
|
+
this.sessions.set(sessionId, session);
|
|
624
|
+
storageService.saveSession(session, userId);
|
|
625
|
+
return targetMessage;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* Get all branches for a message
|
|
629
|
+
*/
|
|
630
|
+
getMessageBranches(sessionId, messageId, userId = 'default') {
|
|
631
|
+
const session = this.getSession(sessionId, userId);
|
|
632
|
+
if (!session)
|
|
633
|
+
return [];
|
|
634
|
+
const message = session.messages.find(msg => msg.id === messageId);
|
|
635
|
+
if (!message)
|
|
636
|
+
return [];
|
|
637
|
+
const parentId = message.parentId || messageId;
|
|
638
|
+
// Find all siblings (including the original parent message)
|
|
639
|
+
return session.messages
|
|
640
|
+
.filter(msg => msg.id === parentId || msg.parentId === parentId)
|
|
641
|
+
.sort((a, b) => (a.branchIndex ?? 0) - (b.branchIndex ?? 0));
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
export default new ChatService();
|
|
645
|
+
//# sourceMappingURL=chatService.js.map
|