diff --git a/server/routes/agent-chat.js b/server/routes/agent-chat.js index 5e44023..9b24480 100644 --- a/server/routes/agent-chat.js +++ b/server/routes/agent-chat.js @@ -493,28 +493,10 @@ function saveMeta(agentId, convId, meta) { function loadHistory(agentId, convId) { try { const historyPath = path.join(getAgentDir(agentId), 'conversations', convId, 'history.json'); - const logPath = path.join(getAgentDir(agentId), 'conversations', convId, 'messages.log'); - - let history = []; if (fs.existsSync(historyPath)) { - history = JSON.parse(fs.readFileSync(historyPath, 'utf-8')); - } - - // 如果 messages.log 存在且比 history.json 更丰富, 从 log 里解析完整消息 - if (fs.existsSync(logPath)) { - const logContent = fs.readFileSync(logPath, 'utf-8'); - const parsed = parseMessagesLog(logContent); - // 只有当 log 解析出的消息更丰富时才使用 (例如包含更多内容) - if (parsed.length > 0) { - const historyTotalLen = history.reduce((sum, m) => sum + (m.content || '').length, 0); - const logTotalLen = parsed.reduce((sum, m) => sum + (m.content || '').length, 0); - if (logTotalLen > historyTotalLen * 1.5) { - return parsed; - } - } + return JSON.parse(fs.readFileSync(historyPath, 'utf-8')); } - - return history; + return []; } catch { return []; } } @@ -552,10 +534,43 @@ function appendHistory(agentId, convId, msg) { fs.writeFileSync(path.join(dir, 'history.json'), JSON.stringify(history, null, 2)); } -/** 写日志(流式或单次) */ +/** 写日志(流式,带缓冲) */ +const _logBuffers = new Map(); +const LOG_BUFFER_SIZE = 4096; // 4KB +const LOG_FLUSH_INTERVAL = 1000; // 1s + function logMessageChunk(agentId, convId, content) { - const dir = getConvDir(agentId, convId); - fs.appendFileSync(path.join(dir, 'messages.log'), content, 'utf-8'); + const key = `${agentId}::${convId}`; + if (!_logBuffers.has(key)) { + _logBuffers.set(key, { buf: '', timer: null, agentId, convId }); + } + const entry = _logBuffers.get(key); + entry.buf += content; + if (entry.buf.length >= LOG_BUFFER_SIZE) { + _flushLogBuffer(key); + } else if (!entry.timer) { + entry.timer = setTimeout(() => _flushLogBuffer(key), LOG_FLUSH_INTERVAL); + } +} + +function _flushLogBuffer(key) { + const entry = _logBuffers.get(key); + if (!entry || !entry.buf) return; + try { + const dir = getConvDir(entry.agentId, entry.convId); + fs.appendFileSync(path.join(dir, 'messages.log'), entry.buf, 'utf-8'); + } catch (err) { + console.error(`[LogBuffer] ⚠️ flush 失败: ${key}`, err.message); + } + entry.buf = ''; + if (entry.timer) { clearTimeout(entry.timer); entry.timer = null; } +} + +/** 强制刷出指定对话的日志缓冲 */ +function flushLogBufferForConv(agentId, convId) { + const key = `${agentId}::${convId}`; + _flushLogBuffer(key); + _logBuffers.delete(key); } /** 传统单次写日志 (为了兼容) */ @@ -818,8 +833,18 @@ router.get('/quota', (req, res) => { } }); +// ── Agent List 缓存 (5秒 TTL,避免每次请求全量扫描磁盘) ── +let _agentListCache = null; +let _agentListCacheTime = 0; +const AGENT_LIST_CACHE_TTL = 5000; // 5 秒 + router.get('/list', (req, res) => { try { + // 缓存命中:5秒内直接返回 + if (_agentListCache && Date.now() - _agentListCacheTime < AGENT_LIST_CACHE_TTL) { + return res.json(_agentListCache); + } + const allAgents = [] const DATA_ROOT = path.resolve(__dirname, '../../data') @@ -927,6 +952,10 @@ router.get('/list', (req, res) => { return tb - ta }) + // 更新缓存 + _agentListCache = allAgents; + _agentListCacheTime = Date.now(); + res.json(allAgents) } catch (err) { res.status(500).json({ error: err.message }) } }); @@ -2361,6 +2390,7 @@ ${resultsText.join('\n\n')} } meta.status = 'completed'; + flushLogBufferForConv(agentId, convId); // 刷出日志缓冲 saveMeta(agentId, convId, meta); // ── Phase 1 MVP: 自动保存 Session 摘要到记忆 ── @@ -2382,6 +2412,7 @@ ${resultsText.join('\n\n')} } catch (err) { console.error('[AgentChat] Error:', err.message); logMessageChunk(agentId, convId, `\n\n[ERROR]\n${err.message}\n\n`); + flushLogBufferForConv(agentId, convId); // 刷出日志缓冲 meta.status = 'failed'; meta.error = err.message; saveMeta(agentId, convId, meta);