fix: 前端消息拆分+动作消息样式+DevTools自主思考状态保持+记忆表名修复

- 侧边栏底部 "昔涟 AI" 改为 "昔涟"
- 暂时禁用消息朗读按钮
- 修复前端 response 处理器:支持 gateway 发送的 content+role+msg_type 字段,
  使动作消息(括号内容)正确拆分为独立的 ActionMessageBubble 显示
- 修复 DevTools 自主思考面板:5秒自动刷新后展开的思考日志不再自动折叠
- 修复 memory-service 表名不一致:memory_entries → memories,
  解决 DevTools 记忆管理页面查不到 admin 用户记忆的问题
- 修复 sessionStore 解析历史消息时 msgType 未定义引用

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 10:50:42 +08:00
parent 26a5c69aba
commit 31be1b71eb
14 changed files with 442 additions and 154 deletions
+29 -8
View File
@@ -713,7 +713,7 @@ const STATE = {
resourceHistory: {},
// 记忆面板状态
memoryCache: [],
memoryUserId: 'admin_admin',
memoryUserId: 'admin',
memoryFilterCategory: 'all',
memorySortBy: 'importance',
memorySortDir: 'desc',
@@ -726,10 +726,12 @@ const STATE = {
sttAutoRefreshInterval: null,
// 时间线面板状态
timelineData: [],
timelineUserId: 'admin_admin',
timelineUserId: 'admin',
timelineFilterType: 'all',
timelineAutoRefresh: null,
timelineLimit: 100,
// 自主思考面板:记录展开的日志 ID
expandedThinkingLogs: {},
};
// ========== WebSocket ==========
@@ -1346,7 +1348,7 @@ function renderMemoryPanel() {
<div class="form-row">
<div class="form-group" style="flex:1">
<label>用户ID</label>
<input type="text" id="mem-user-id" placeholder="admin_admin" value="${escHtml(STATE.memoryUserId)}">
<input type="text" id="mem-user-id" placeholder="admin" value="${escHtml(STATE.memoryUserId)}">
</div>
<div class="form-group" style="flex:2">
<label>全文搜索</label>
@@ -1368,7 +1370,7 @@ function renderMemoryPanel() {
<div class="card" style="margin:0">
<div class="card-header"><span class="card-title"> 添加记忆</span></div>
<div class="form-group"><label>用户ID</label><input type="text" id="mem-add-user-id" placeholder="admin_admin" value="admin_admin"></div>
<div class="form-group"><label>用户ID</label><input type="text" id="mem-add-user-id" placeholder="admin" value="admin"></div>
<div class="form-group"><label>内容</label><textarea id="mem-add-content" placeholder="输入记忆内容..." rows="2"></textarea></div>
<div class="form-row">
<div class="form-group">
@@ -2940,7 +2942,7 @@ async function renderThinkingPanel() {
if (!STATE.thinkingPage) STATE.thinkingPage = 1;
if (!STATE.thinkingAutoRefresh) STATE.thinkingAutoRefresh = null;
if (!STATE.thinkingLimit) STATE.thinkingLimit = 20;
if (!STATE.thinkingUserId) STATE.thinkingUserId = 'admin_admin';
if (!STATE.thinkingUserId) STATE.thinkingUserId = 'admin';
var actionsEl = document.getElementById('panel-actions');
var autoRefreshOn = STATE.thinkingAutoRefresh !== null;
@@ -2951,7 +2953,11 @@ async function renderThinkingPanel() {
var statsData = null;
try {
var statsResp = await fetch('/api/v1/thinking/stats?user_id=' + encodeURIComponent(STATE.thinkingUserId));
if (statsResp.ok) statsData = await statsResp.json();
if (statsResp.ok) {
statsData = await statsResp.json();
// 兼容旧格式 {stats: {...}} 和新格式 {total_logs: ..., ...}
if (statsData && statsData.stats) statsData = statsData.stats;
}
} catch(e) {}
var logsData = null;
@@ -3053,12 +3059,27 @@ async function renderThinkingPanel() {
}
container.innerHTML = statsCardsHtml + filterHtml + tableHtml + paginationHtml;
// 恢复之前展开的思考日志
Object.keys(STATE.expandedThinkingLogs).forEach(function(logId) {
if (STATE.expandedThinkingLogs[logId]) {
var expandRow = document.getElementById(logId + '-expand');
if (expandRow) expandRow.style.display = '';
}
});
}
function toggleThinkingExpand(logId) {
var expandRow = document.getElementById(logId + '-expand');
if (expandRow) {
expandRow.style.display = expandRow.style.display === 'none' ? '' : 'none';
var isExpanded = expandRow.style.display !== 'none';
if (isExpanded) {
expandRow.style.display = 'none';
STATE.expandedThinkingLogs[logId] = false;
} else {
expandRow.style.display = '';
STATE.expandedThinkingLogs[logId] = true;
}
}
}
@@ -3114,7 +3135,7 @@ async function renderTimelinePanel() {
'<button class="btn btn-sm" onclick="renderTimelinePanel()" style="margin-left:8px">🔄 刷新</button>';
// 加载数据
var userId = STATE.timelineUserId || 'admin_admin';
var userId = STATE.timelineUserId || 'admin';
var data = await api('/api/memory-timeline?user_id=' + encodeURIComponent(userId) + '&limit=' + STATE.timelineLimit);
if (data.error) {