feat: 全链路优化 — 死锁修复、MD3主题、上下文持久化、群聊自然化、打字状态、知识库
**死锁根因修复** - periodicThinkLoop:1015 orphaned lock → 删除(字段已原子化) - RecordUserMessage 隔离为 recordMu - atomic.Int64 替换 lastUserMessage/lastThinkTime 等 **MD3 / Android 17 主题** - 毛玻璃卡片 (backdrop-filter) - MD3 色彩令牌 (pink primary #f472b6) - icons.js 独立矢量图标库 + 运行时 emoji 替换 - 无边框卡片、圆角按钮、阴影层次 **上下文持久化** - AddMessage → saveToDB 异步写 PostgreSQL - LoadFromDB 恢复 (admin-session-main + 懒加载) - LLMMessage.Timestamp 字段 **群聊与适配器** - group_ambient 模式: 非@消息让 LLM 自己判断是否插话 - 戳一戳动作消息总是回复 - NapCat 打字状态 (set_input_status, 最小3秒显示) - HTTP API 配置 (http_url/http_token) **知识库 & 防编造** - knowledge.CanHandle 对 chat 意图也触发 - 关键词预筛选避免无关 embedding 调用 - persona + synthesizer 三重诚实规则 - 工具结果持久化到会话历史 **平台桥接器** - detached:true Go进程独立存活 - ethend 重启自动接管已运行服务 - stop() 接管模式 taskkill/F/ PID - Windows netstat 替代 fuser 获取 PID - 重复适配器种子逻辑修复 - 失败转发日志 Direction: error **崩溃诊断** - crashlog 包 (Recover + WrapHTTP + LLMCall) - /api/v1/debug/goroutines 端点 - thinker 操作日志 + 30s stats - 日志写入 logs/ 目录持久化 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
@@ -65,6 +66,33 @@ func (cs *ConversationStore) AddMessage(sessionID string, msg model.LLMMessage)
|
||||
}
|
||||
}
|
||||
cs.messages[sessionID] = msgs
|
||||
|
||||
// 异步写 DB 确保重启后上下文不丢失
|
||||
if cs.databaseURL != "" {
|
||||
go cs.saveToDB(sessionID, msg)
|
||||
}
|
||||
}
|
||||
|
||||
// saveToDB persists a message to the database.
|
||||
func (cs *ConversationStore) saveToDB(sessionID string, msg model.LLMMessage) {
|
||||
db, err := sql.Open("postgres", cs.databaseURL)
|
||||
if err != nil {
|
||||
logger.Printf("[context] saveToDB open error: %v", err)
|
||||
return
|
||||
}
|
||||
defer db.Close()
|
||||
// 确保 session 存在
|
||||
_, _ = db.Exec(
|
||||
`INSERT INTO sessions (id, user_id, created_at, updated_at) VALUES ($1, $2, $3, $3) ON CONFLICT (id) DO NOTHING`,
|
||||
sessionID, "admin", msg.Timestamp,
|
||||
)
|
||||
_, err = db.Exec(
|
||||
`INSERT INTO messages (session_id, role, content, created_at) VALUES ($1, $2, $3, $4)`,
|
||||
sessionID, string(msg.Role), msg.Content, msg.Timestamp,
|
||||
)
|
||||
if err != nil {
|
||||
logger.Printf("[context] saveToDB insert error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// GetHistory 获取会话历史。
|
||||
@@ -107,7 +135,7 @@ func (cs *ConversationStore) LoadFromDB(databaseURL, sessionID string, limit int
|
||||
defer db.Close()
|
||||
|
||||
rows, err := db.Query(
|
||||
`SELECT role, content FROM messages
|
||||
`SELECT role, content, created_at FROM messages
|
||||
WHERE session_id = $1
|
||||
ORDER BY created_at ASC
|
||||
LIMIT $2`,
|
||||
@@ -124,7 +152,8 @@ func (cs *ConversationStore) LoadFromDB(databaseURL, sessionID string, limit int
|
||||
var loaded int
|
||||
for rows.Next() {
|
||||
var roleStr, content string
|
||||
if err := rows.Scan(&roleStr, &content); err != nil {
|
||||
var createdAt time.Time
|
||||
if err := rows.Scan(&roleStr, &content, &createdAt); err != nil {
|
||||
return fmt.Errorf("扫描消息行失败: %w", err)
|
||||
}
|
||||
// 将旧数据中的 "action" 角色映射为 "assistant"(LLM 模型不支持自定义角色)
|
||||
|
||||
Reference in New Issue
Block a user