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
@@ -454,6 +454,30 @@ func (h *ChatHandler) handleHistoryRequest(client *ws.Client, msg ws.ClientMessa
}
messages := h.hub.GetConversation(client.UserID, sessionID)
// 如果内存缓存为空,尝试从数据库恢复(网关重启后缓存丢失的情况)
if len(messages) == 0 && h.sessionStore != nil && h.sessionStore.IsAvailable() {
dbMessages, err := h.sessionStore.GetMessages(sessionID, 50, 0)
if err == nil && len(dbMessages) > 0 {
log.Printf("[history] 从数据库恢复会话历史: session=%s, %d 条消息", sessionID, len(dbMessages))
// 恢复到内存缓存
for _, dbMsg := range dbMessages {
messages = append(messages, ws.Message{
ID: fmt.Sprintf("db_%d", dbMsg.ID),
Role: dbMsg.Role,
Content: dbMsg.Content,
Timestamp: dbMsg.CreatedAt.UnixMilli(),
})
h.hub.CacheMessage(client.UserID, sessionID, ws.Message{
ID: fmt.Sprintf("db_%d", dbMsg.ID),
Role: dbMsg.Role,
Content: dbMsg.Content,
Timestamp: dbMsg.CreatedAt.UnixMilli(),
})
}
}
}
if messages == nil {
messages = []ws.Message{}
}
@@ -488,6 +512,73 @@ func (h *ChatHandler) SendSystemMessage(userID, sessionID, text string) error {
return nil
}
// HandleProactiveMessage 处理来自 AI-Core 后台思考的主动消息
// POST /api/v1/internal/proactive-message
func (h *ChatHandler) HandleProactiveMessage(c *gin.Context) {
var req struct {
UserID string `json:"user_id" binding:"required"`
Content string `json:"content" binding:"required"`
SessionID string `json:"session_id"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效: " + err.Error()})
return
}
// 检查用户是否在线
onlineCount := h.hub.UserClientCount(req.UserID)
if onlineCount == 0 {
c.JSON(http.StatusOK, gin.H{
"success": false,
"reason": "user_offline",
"message": "用户不在线,消息未发送",
})
return
}
// 构建主动消息
msgID := "proactive_" + generateID()
msg := ws.ServerMessage{
Type: "response",
MessageID: msgID,
Content: req.Content,
Role: "assistant",
MsgType: "proactive",
SessionID: req.SessionID,
Timestamp: time.Now().UnixMilli(),
}
data, err := json.Marshal(msg)
if err != nil {
log.Printf("[proactive] 序列化消息失败: %v", err)
c.JSON(http.StatusInternalServerError, gin.H{"error": "内部错误"})
return
}
h.hub.SendToUser(req.UserID, data)
// 同时缓存到对话历史(使用 admin 的主 session
sessionID := req.SessionID
if sessionID == "" {
sessionID = "session_admin_main"
}
h.hub.CacheMessage(req.UserID, sessionID, ws.Message{
ID: msgID,
Role: "assistant",
Content: req.Content,
Timestamp: time.Now().UnixMilli(),
})
h.hub.RecordMessage(sessionID, "assistant", req.Content)
log.Printf("[proactive] 主动消息已推送: user=%s, online=%d, content_len=%d", req.UserID, onlineCount, len(req.Content))
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "消息已推送",
"delivered": onlineCount,
})
}
func generateID() string {
return time.Now().Format("20060102150405") + randomStr(6)
}