feat: 记忆体系统 v0.3.0 完成
Some checks failed
Release / build (push) Failing after 4m28s

## 核心功能
- 双记忆系统合并:picoclaw MEMORY.md + hxclaw 会话摘要
- 独立上下文系统:不依赖 picoclaw session
- 向量检索:硅基流动 BGE-M3 API
- 三重检测:关键词/向量相似度/命令

## 数据库
- libSQL (TursoDB) 存储
- sessions + chats 表设计
- 向量存储使用 binary 编码

## 查询场景
- RecallHistory: 查询所有会话摘要
- RecallTopic: 按话题向量检索
- RecallSession: 指定会话详情
- RecallWithinSession: 会话内检索

## 导出
- MongoDB 风格:~/.config/hxclaw/export-data.json
- chats 嵌套在 sessions 下
- 增量导出,同 session 累加

## UI 优化
- 合并状态显示(耗时 · 状态 · 消息数)
- 颜色设计:金色图标 + 暗绿色/暗红色状态

## 配置项
- memory.recall: keywords, auto_recall, similarity_threshold
- memory.vector: max_search_results
- memory.auto_export
This commit is contained in:
2026-04-27 06:16:19 +08:00
parent 88a110e87e
commit 5d9498f687
12 changed files with 1583 additions and 52 deletions

103
taolun.md
View File

@@ -455,4 +455,105 @@ func (r *Readline) SetPrompt(prompt string) error {
func (r *Readline) SetPrompt(prompt string) {
r.rl.SetPrompt(prompt) // void 类型
}
```
```
---
### 20. 禁用 picoclaw session 历史,实现独立上下文系统
#### 问题背景
- picoclaw 的 session 历史会被自动清空
- 不利于 hxclaw 的会话连续性
- 需要实现自我控制的上下文系统
#### 解决方案
- 禁用 picoclaw 的 session 历史读取
- 使用 hxclaw 自己的 libSQL 数据库存储会话摘要
- 在 ProcessDirect() 调用前注入上下文摘要到用户输入
#### 实现步骤
1. **创建 GetContextPrompt()** - `cmd/hxclaw/internal/memory/save.go`
```go
func GetContextPrompt() string {
// 从 hxclaw 自己的数据库获取会话摘要
return "=== 当前会话摘要 ===
" + session.Summary + "
============
"
}
```
2. **注入上下文** - `cmd/hxclaw/main.go`
```go
if memoryCfg.Enabled {
contextPrompt := memory.GetContextPrompt()
if contextPrompt != "" {
input = contextPrompt + "
用户新问题: " + input
}
}
resp, err := agentLoop.ProcessDirect(context.Background(), input, sessionKey)
```
#### 效果
- hxclaw 完全独立于 picoclaw session 管理
- 会话摘要通过数据库持久化
- 上下文通过摘要注入传递
---
### 21. UI 合并显示与颜色设计
#### 需求
将原来分两行显示的信息合并为一行:
- 之前:`[memory] 已保存,当前会话 8 条消息` + `▣ 耗时: 20.3s`
- 之后:`▣ 耗时: 20.3s · 会话已保存 · 当前会话 8 条消息`
#### 颜色设计
| 文字 | 颜色 | 十六进制 |
|------|------|---------|
| ▣ (图标) | 金色 | #f0c75e |
| 灰色文字 | 灰色 | #2b2e32 |
| 会话已保存 | 暗绿色 | #4a9e6b |
| 会话保存异常 | 暗红色 | #c75050 |
#### 代码实现
```go
var (
iconStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#f0c75e"))
textStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#2b2e32"))
memoryOkStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#4a9e6b"))
memoryErrStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#c75050"))
)
func printElapsed(elapsed time.Duration, chatCount int, saveErr error) {
icon := iconStyle.Render("▣ ")
timeText := textStyle.Render(fmt.Sprintf("耗时: %s", elapsedStr))
var statusText string
if saveErr != nil {
statusText = memoryErrStyle.Render("会话保存异常")
} else if chatCount > 0 {
statusText = memoryOkStyle.Render("会话已保存")
}
memCountText := textStyle.Render(fmt.Sprintf("当前会话 %d 条消息", chatCount))
fmt.Printf(" %s%s · %s · %s
", icon, timeText, statusText, memCountText)
}
```
#### 关键点
- `SaveChat()` 改为返回 `(chatCount int, err error)`,便于错误处理
- 状态文字单独使用颜色样式
- 失败时显示"会话保存异常"(暗红色)