Files
HxClaw/changelog.md
titor 5494a296d9 docs: 更新文档记录 v0.2.7 升级和 /context 命令
- agents.md: 添加上下文监控功能说明和输出示例
- changelog.md: 新增 v0.3.1 版本记录
- 更新目前进度列表
2026-05-03 02:45:22 +08:00

432 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# hxclaw 更新日志
## 版本记录
### v0.3.1 (2026-05-03)
- **升级 picoclaw 至 v0.2.7**
- 配置版本从 v2 升级至 v3
- 适配配置结构变更Bindings → Dispatch, channels → channel_list
- 同步更新相关间接依赖
- **新增 `/context` 命令**
- 显示当前会话上下文窗口使用情况
- 包含消息数、token 使用量、压缩阈值和剩余空间
- 在 interactiveMode 和 simpleInteractiveMode 中均支持
---
### v0.3.0 (2026-04-27)
- **Session 创建逻辑优化**
- Session 只在用户输入聊天消息时创建
- /new 命令只重置 currentSession不立即创建
- 退出后重新进入算作新会话
- 配置项auto_session默认 true
- **LLM 生成摘要**
- Chat 摘要:调用 LLM 生成极简文言文概述
- Session 摘要:每次对话后用 LLM 精简整合
- 配置项summary_timeout默认 30 秒)
- 容错处理:超时失败回退到简单截断
- **双记忆系统合并**
- 读取 picoclaw 的 MEMORY.md 作为长期记忆
- 合并到 hxclaw 的会话摘要上下文
- AI 同时看到长期记忆和会话摘要
- **独立上下文系统**
- 创建 GetContextPrompt() 返回会话摘要
- 注入到 ProcessDirect() 调用前
- 不再依赖 picoclaw session 管理
- 修复 recall 结果污染 session summary 问题
- **数据库层完善**
- 集成 libSQL (TursoDB)
- 创建 sessions 和 chats 表
- 实现 CRUD 操作
- 数据库保存在 `~/.config/hxclaw/hxclaw.db`
- 向量存储使用 binary 编码float32
- **向量检索功能**
- 硅基流动 BGE-M3 API 集成
- 向量生成和存储
- Cosine Similarity 计算
- SearchSimilar() 函数实现
- 4 个查询场景RecallHistory, RecallTopic, RecallSession, RecallWithinSession
- **三重检测机制**
- 关键词匹配(之前、聊过、记得等)
- 向量相似度自动检测auto_recall + 阈值)
- /recall 命令强制触发
- 配置项keywords, auto_recall, similarity_threshold, max_results
- **MongoDB 风格导出**
- 固定路径:`~/.config/hxclaw/export-data.json`
- chats 嵌套在 sessions 下
- 增量导出,同 session 累加
- 版本控制version 字段)
- **UI 优化**
- 合并状态显示到单行(耗时 · 状态 · 消息数)
- 颜色设计:金色图标 + 灰色文字
- 暗绿色"会话已保存" / 暗红色"会话保存异常"
- **配置项更新**
- memory.recall 配置
- memory.vector.max_search_results
- memory.auto_export替换 export_on_exit
- 默认 max_search_results = 10
---
### v0.2.1
- 修复 TTS JSON 请求格式,兼容 Windows daemon
- 发送格式改为 `{"text": "内容"}`
---
### v0.2.0
- 新增 TTS 语音朗读功能
- 集成 mimo-tts client 功能,通过 TCP 连接本地 daemon
- 支持配置文件开关tts.enabled
- 支持命令行切换(/tts on/off/status
- 支持临时 TTS 前缀(`T 消息` 临时开启)
- 动态提示符显示 TTS 状态(👀 🔊)
- 静默失败处理(网络异常时警告日志)
---
### v0.1.0
- 创建 hxclaw 项目
- 实现流式输出功能
- Markdown 渲染glamour自动代码高亮
- 项目配置化project.config.yml
---
## 待实现功能
### v0.2.0 (当前)
- [x] TTS 语音朗读功能
- [x] 集成 mimo-tts client (TCP 连接)
- [x] 配置文件开关 (tts.enabled)
- [x] 命令行切换 (/tts on/off/status)
- [x] 临时 TTS 前缀 (T 消息)
- [x] 动态提示符显示状态
- [x] 静默失败处理
### v0.3.0 (当前)
- [x] 双记忆系统合并picoclaw MEMORY.md + hxclaw 会话摘要)
- [x] 数据库层集成libSQL
- [x] 独立上下文系统(不再依赖 picoclaw session
- [x] 会话摘要注入
- [x] UI 优化(合并显示、颜色设计)
- [x] 向量检索(硅基流动 API
- [x] 4 个查询场景RecallHistory, RecallTopic...
- [x] 三重检测机制
- [x] MongoDB 风格导出
- [x] Session 创建逻辑优化(输入消息时自动创建)
- [x] /new 命令(只重置 currentSession
- [x] LLM 生成摘要(文言文风格)
- [x] summary_timeout 配置
---
## 待实现功能
### v0.4.0 (计划)
- [ ] 命令行参数支持(--theme, --tts 等)
- [ ] 多语言支持
- [ ] 命令提示/补全功能(输入 / 显示内置命令列表)
---
## 目前进度
- [x] 创建项目目录结构
- [x] 编写讨论记录taolun.md
- [x] 编写更新日志changelog.md
- [x] 编写 AI 行为指南agents.md
- [x] 创建 go.mod
- [x] 实现 main.go 入口
- [x] 实现流式输出核心逻辑
- [x] 编译成功,生成 hxclaw 二进制
- [x] 添加 spinner 加载动画组件
- [x] 实现 Markdown 渲染glamour
- [x] 实现项目配置化project.config.yml
- [x] 实现 TTS 语音朗读功能
- [x] 集成 libSQL 数据库
- [x] 实现独立上下文系统
- [x] UI 状态合并显示
- [x] LLM 生成摘要(文言文风格)
- [x] Session 自动创建逻辑
- [x] 升级 picoclaw 至 v0.2.7
- [x] 实现 `/context` 命令
---
## 认知纠正(踩坑记录)
### Go replace 机制不需要发布到 registry
**问题**:最初担心需要像 npm 那样发布到 registry 才能被其他项目引用
**纠正**Go 的 replace 机制可以直接指向:
- 本地路径(如 `../picoclaw`
- GitHub 仓库 + tag`github.com/sipeed/picoclaw v0.2.4`
**知识点**Go 模块不需要发布到任何 registryGitHub 就是事实上的 registry
---
### hxclaw 不需要实现全部 picoclaw 功能
**问题**:最初担心需要自己实现 onboard、tools、mcp 等全部功能
**纠正**hxclaw 是 CLI 增强层只替换交互逻辑。picoclaw 的核心功能agent loop、tools、mcp、skills通过导入其 pkg 即可复用
**知识点**:采用组合优于继承的设计,需要什么功能就导入对应的包
---
### 流式输出需要判断 Provider 是否支持
**问题**:不是所有 Provider 都支持流式输出
**纠正**:需要使用类型断言判断 Provider 是否实现 `providers.StreamingProvider` 接口:
```go
if sp, ok := provider.(providers.StreamingProvider); ok {
// 使用 ChatStream
} else {
// 使用普通 Chat
}
```
**知识点**picoclaw 的 Provider 设计使用了接口分离原则,流式是可选能力
---
### 终端渲染使用 charmbracelet 库
**问题**:如何实现 Markdown 终端渲染
**纠正**:使用 charmbracelet 家族:
- lipgloss样式定义
- glow代码高亮
**知识点**charmbracelet 是 Go 终端UI 的事实标准API 设计优雅
---
### 独立二进制部署方式
**问题**hxclaw 和 picoclaw 的关系
**纠正**hxclaw 作为独立二进制,用户可以同时保留两个命令:
- `picoclaw agent` 使用原版
- `hxclaw` 使用增强版
**知识点**:通过 go.mod replace 实现依赖绑定,用户无需安装 picoclaw 源码
---
### AgentRegistry 没有 BuildMessages 方法
**问题**:最初尝试调用 agentLoop.GetRegistry().BuildMessages() 构建消息
**纠正**BuildMessages 属于 ContextBuilder不是 AgentRegistry
```go
// 正确方式
agentInstance.ContextBuilder.BuildMessages(history, summary, input, media, channel, chatID, senderID, senderDisplayName)
```
**知识点**picoclaw 代码结构中ContextBuilder 负责消息构建AgentRegistry 负责 agent 管理
---
### ToolDefinitions 获取方式
**问题**:如何获取可用的工具定义列表
**纠正**:通过 ToolRegistry 的 ToProviderDefs 方法:
```go
toolDefs := agentInstance.Tools.ToProviderDefs()
```
**知识点**ToolRegistry 维护工具注册ToProviderDefs 转换为 provider 可用的格式
---
### 流式输出实时刷新
**问题**:流式输出时字符不是实时显示,要等很久才一次性出现
**纠正**:在 onChunk 回调中添加 `os.Stdout.Sync()` 强制刷新 stdout
```go
func(token string) {
fmt.Print(token)
os.Stdout.Sync() // 强制刷新
}
```
**知识点**Go 的 `fmt.Print` 使用缓冲输出,需要手动刷新才能实时显示
---
### Session 历史消息获取
**问题**:如何获取会话历史用于流式调用
**纠正**:通过 `SessionStore` 接口:
```go
history := agentInstance.Sessions.GetHistory(sessionKey)
summary := agentInstance.Sessions.GetSummary(sessionKey)
```
**知识点**`AgentInstance.Sessions` 实现了 `SessionStore` 接口,支持 `GetHistory``GetSummary` 方法
---
### 流式调用后的消息保存
**问题**:流式调用绕过了 agent loop消息没有保存到 session
**纠正**:流式调用后手动保存消息:
```go
agentInstance.Sessions.AddMessage(sessionKey, "user", input)
agentInstance.Sessions.AddMessage(sessionKey, "assistant", result)
```
**知识点**`SessionStore` 接口提供 `AddMessage` 方法,支持 "user" 和 "assistant" 角色
---
### onChunk 回调接收累积文本导致重复输出
**问题**picoclaw 的 `StreamingProvider` 接口定义:
```go
onChunk func(accumulated string)
```
注释说明:"onChunk receives the accumulated text so far (not individual deltas)"。每次回调时参数是累积的完整文本(如 "你好" → "你好!再次" → "你好!再次见到"),而不是增量。
**纠正**:使用 `printedLen` 跟踪已打印位置,只打印新增部分:
```go
var printedLen int
func(accumulated string) {
if len(accumulated) > printedLen {
fmt.Print(accumulated[printedLen:])
printedLen = len(accumulated)
}
}
```
**知识点**picoclaw 故意设计为累积文本,这样可以在任意时刻获取完整内容用于调试
---
### 尝试 uilive 库但只显示最后一行
**问题**:为了实现同行流动效果,尝试使用 `github.com/gosuri/uilive`
**现象**:该库会覆盖每一行,只显示最后一行内容
**纠正**:移除 uilive直接使用 `fmt.Print` + `os.Stdout.Sync()`,让终端自然处理换行
**知识点**uilive 适用于进度条等场景,不适合长文本流式输出
---
### 流式输出期望同行流动但实际换行显示
**问题**:用户期望像 ollama 那样在同行逐字符流动
**最终方案**
```go
fmt.Print(accumulated[printedLen:])
os.Stdout.Sync()
```
效果:
- 字符串自然累积增长
- 终端自动处理换行(满一行自动 wrap
- 保留所有历史输出
- 每次刷新缓冲区确保立即显示
**知识点**:最简单的方案就是最有效的方案,不需要额外库
---
### spinner 组件的 model 更新必须使用返回值
**问题**spinner 动画不动
**现象**:调用 spinner.Update(msg) 后动画不更新
**纠正**spinner model 是值类型,需要使用返回值更新:
```go
// 错误写法
func (s *Spinner) tick() {
msg := s.spinner.Tick()
if msg, ok := msg.(spinner.TickMsg); ok {
s.spinner.Update(msg) // 动画不会动!
}
}
// 正确写法
func (s *Spinner) tick() {
msg := s.spinner.Tick()
if msg, ok := msg.(spinner.TickMsg); ok {
s.spinner, _ = s.spinner.Update(msg) // 必须使用返回值更新
}
}
```
**知识点**bubbletea v2 的组件遵循 TEA 架构模式Update 方法返回更新后的 model需要显式使用返回值。
---
### spinner 和流式输出在同一行的冲突问题
**问题**spinner 使用 `\r` 回到行首刷新,流式输出也在同一行打印,导致内容混在一起
**现象**
```
⠋ 回答中... 好
⠋ 回答中... 注于
```
**纠正**:在第一个 token 时停止 spinner让 spinner 输出 "思考完成." 并换行,然后再开始流式打印:
```go
if firstToken && len(accumulated) > 0 {
spinner.Stop() // 停止 spinner会打印 "思考完成."
firstToken = false
}
```
**知识点**spinner 和流式输出需要分时工作,不能同时占用同一行。
---
### spinner 动画位置和换行策略
**问题**:用户期望动画在前,文字在后,且需要正确的换行
**效果**
```
思考中... ⠋ -> 用户期望 ⠋ 思考中...
思考完成. -> 用户期望 ⠋ 思考完成.
```
**纠正**
- 动画在前,文字在后:`fmt.Printf("\r%s %s", s.spinner.View(), s.text)`
- 换行:"思考完成.\n" + 流式输出后 "fmt.Println()\n"
**知识点**:终端输出需要精确控制位置和换行,否则会导致格式错乱。