feat: conversation long-term memory + fix source ENUM bug
- New: conversationSummarizer.js (LLM summary every 3 turns, loadBestSummary, persistFinalSummary) - db/index.js: conversation_summaries table, upsertConversationSummary, getSessionSummary - redisClient.js: setSummary/getSummary (TTL 2h) - nativeVoiceGateway.js: _turnCount tracking, trigger summarize, persist on close - realtimeDialogRouting.js: inject summary context, reduce history 5->3 rounds - Fix: messages source ENUM missing 'search_knowledge' causing chat DB writes to fail
This commit is contained in:
@@ -26,8 +26,8 @@ async function migrateSchema() {
|
||||
if (!(await columnMatchesType('messages', 'role', "'system'"))) {
|
||||
await pool.execute("ALTER TABLE `messages` MODIFY COLUMN `role` ENUM('user', 'assistant', 'tool', 'system') NOT NULL");
|
||||
}
|
||||
if (!(await columnMatchesType('messages', 'source', "'chat_bot'"))) {
|
||||
await pool.execute("ALTER TABLE `messages` MODIFY COLUMN `source` ENUM('voice_asr', 'voice_bot', 'voice_tool', 'chat_user', 'chat_bot') NOT NULL");
|
||||
if (!(await columnMatchesType('messages', 'source', "'search_knowledge'"))) {
|
||||
await pool.execute("ALTER TABLE `messages` MODIFY COLUMN `source` ENUM('voice_asr', 'voice_bot', 'voice_tool', 'chat_user', 'chat_bot', 'search_knowledge') NOT NULL");
|
||||
}
|
||||
await ensureColumnExists('messages', 'tool_name', '`tool_name` VARCHAR(64) NULL AFTER `source`');
|
||||
await ensureColumnExists('messages', 'meta_json', '`meta_json` JSON NULL AFTER `tool_name`');
|
||||
@@ -81,7 +81,7 @@ async function initialize() {
|
||||
session_id VARCHAR(128) NOT NULL,
|
||||
role ENUM('user', 'assistant', 'tool', 'system') NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
source ENUM('voice_asr', 'voice_bot', 'voice_tool', 'chat_user', 'chat_bot') NOT NULL,
|
||||
source ENUM('voice_asr', 'voice_bot', 'voice_tool', 'chat_user', 'chat_bot', 'search_knowledge') NOT NULL,
|
||||
tool_name VARCHAR(64),
|
||||
meta_json JSON,
|
||||
created_at BIGINT,
|
||||
@@ -90,6 +90,21 @@ async function initialize() {
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`);
|
||||
|
||||
await pool.execute(`
|
||||
CREATE TABLE IF NOT EXISTS conversation_summaries (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
session_id VARCHAR(128) NOT NULL,
|
||||
user_id VARCHAR(128),
|
||||
summary TEXT NOT NULL,
|
||||
turn_count INT DEFAULT 0,
|
||||
topics JSON,
|
||||
created_at BIGINT,
|
||||
updated_at BIGINT,
|
||||
UNIQUE INDEX idx_session (session_id),
|
||||
INDEX idx_user_time (user_id, updated_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`);
|
||||
|
||||
await migrateSchema();
|
||||
|
||||
console.log(`[DB] MySQL connected: ${dbName}, tables ready`);
|
||||
@@ -202,9 +217,31 @@ async function getSessionList(userId, limit = 50) {
|
||||
*/
|
||||
async function deleteSession(sessionId) {
|
||||
await pool.execute('DELETE FROM messages WHERE session_id = ?', [sessionId]);
|
||||
await pool.execute('DELETE FROM conversation_summaries WHERE session_id = ?', [sessionId]);
|
||||
await pool.execute('DELETE FROM sessions WHERE id = ?', [sessionId]);
|
||||
}
|
||||
|
||||
// ==================== Conversation Summaries ====================
|
||||
|
||||
async function upsertConversationSummary(sessionId, userId, summary, { turnCount = 0, topics = null } = {}) {
|
||||
const now = Date.now();
|
||||
const topicsJson = topics ? JSON.stringify(topics) : null;
|
||||
await pool.execute(
|
||||
`INSERT INTO conversation_summaries (session_id, user_id, summary, turn_count, topics, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE summary=VALUES(summary), turn_count=VALUES(turn_count), topics=VALUES(topics), updated_at=VALUES(updated_at)`,
|
||||
[sessionId, userId || null, summary, turnCount, topicsJson, now, now]
|
||||
);
|
||||
}
|
||||
|
||||
async function getSessionSummary(sessionId) {
|
||||
const [rows] = await pool.execute(
|
||||
'SELECT summary, turn_count, topics, updated_at FROM conversation_summaries WHERE session_id = ? LIMIT 1',
|
||||
[sessionId]
|
||||
);
|
||||
return rows[0] || null;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
initialize,
|
||||
getPool,
|
||||
@@ -217,4 +254,6 @@ module.exports = {
|
||||
getHistoryForLLM,
|
||||
getSessionList,
|
||||
deleteSession,
|
||||
upsertConversationSummary,
|
||||
getSessionSummary,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user