PicoBot/docs/CHANGELOG.md
oudecheng 14d903e067 fix: Agent 执行与显示层解耦,修复锁屏冻结根因
浏览器锁屏导致 WebSocket 半死,ws_sender.send().await 永久阻塞,
级联阻塞 dispatcher → MessageBus → Agent Loop,后端停止执行直到解锁。

基于第一性原理建立"执行-显示解耦"原则:agent 执行只依赖 SQLite
持久化,实时广播是可丢弃的最佳努力通道。

核心改动:
- MessageBus::publish_outbound 由 send().await 改为 try_send(),
  bus 满时丢弃消息并告警,agent 不再被显示层阻塞
- WebSocket writer task 包裹 30s 超时,使用每连接独立的
  CancellationToken(非共享 CliChannel 级 token),避免一个连接
  超时关闭所有连接;writer 退出时 cancel 通知主 loop 退出
- CliChannel::send 由 send().await 改为 try_send(),避免 dispatcher
  单线程被卡住的 writer 阻塞 37s
- 全仓 13 处 publish_outbound 调用统一区分 Dropped(warn)/Closed(error)
- scheduler 3 处 ? 改为 warn,避免 Dropped 触发 misfire 重试风暴
- 前端 WebSocket 添加 25s ping + 指数退避重连(3s→60s封顶)
- 前端 session_list 区分重连恢复/首次连接,重连时保留 messages
  并刷新 topic 列表

经五轮对抗性审查验证,修复了共享 cancel token、dispatcher 阻塞、
load_chat_messages 跨 topic 污染、原 session 删除后状态不一致等
回归问题。

同时升级版本号至 0.3.0 并更新 CHANGELOG。

验证:cargo clippy --all-targets --all-features ✓
      npm run build ✓ | useChat.test.ts 13 passed ✓
2026-08-04 10:55:52 +08:00

182 lines
12 KiB
Markdown
Raw 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.

# 变更日志
本文件记录 Picobot 各版本的显著变更,遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 风格。
## [0.3.0] - 2026-08-04
较 [0.2.0] 的 14 个已提交 commit + 本次版本一并提交的锁屏冻结架构修复12 文件),聚焦 **Agent 执行与显示层解耦**、**工程化基线**、**并发持久化稳定性** 与 **安全加固** 四大方向。架构修复经五轮对抗性审查验证。
### 新增功能
#### 话题重命名
- 新增 `RenameTopic` 命令与 `TopicRenamed` 协议消息,复用存储层已有的 `update_topic_title` 方法。后端响应携带刷新后的完整 topic 列表,前端零额外往返同步侧边栏。
- 前端 `TopicList` 侧边栏增加内联编辑入口悬停显示铅笔图标Enter 提交 / Esc 取消 / blur 取消,通过 `onMouseDown preventDefault` 防止按钮点击时 input 提前失焦。
#### 前端自动构建集成
- 新增 `build.rs``cargo build` 时自动执行 `npm install + npm run build`,消除前后端构建割裂。支持 `SKIP_FRONTEND_BUILD` 环境变量跳过。
#### 工程化基线
- `rustfmt.toml` 固化 `max_width=100` / 4 空格缩进;`Cargo.toml` 配置 `[lints.rust]``[lints.clippy]` 渐进式规则。
- `.github/workflows/ci.yml`Rustfmt + clippy + test+ 前端eslint + tsc + test + prettier format:check双平台 CI。
- `Makefile` 新增 `check` / `fmt` / `fix` 目标clippy 对齐 `--all-targets --all-features`
- 前端 eslint flat config + prettier 配置,对 47 个前端文件统一格式化并在 CI 强制 `format:check`
#### 默认迭代上限调整
- `max_tool_iterations` 默认值调整为 1000匹配长任务子代理的实际需求。
### 架构修复
#### Agent 执行与显示层解耦(锁屏冻结根因修复)
根因:浏览器锁屏导致 WebSocket 半死,`ws_sender.send().await` 永久阻塞,级联阻塞 dispatcher → MessageBus → Agent Loop后端停止执行直到解锁。
基于第一性原理建立"执行-显示解耦"原则agent 执行只依赖 SQLite 持久化,实时广播是可丢弃的最佳努力通道。
- `MessageBus::publish_outbound``send().await` 改为 `try_send()`bus 满时丢弃消息并告警agent 不再被显示层阻塞。新增 `BusError::Dropped` 变体。
- WebSocket writer task 包裹 `tokio::time::timeout(30s)`:半死连接超时即关闭。使用每连接独立的 `CancellationToken`(非共享的 CliChannel 级 token避免一个连接超时关闭所有连接。writer 退出时 cancel 通知主 loop 退出,确保 `unregister_connection` 执行。
- `CliChannel::send``send().await` 改为 `try_send()`dispatcher 单线程顺序处理,原阻塞式发送在 writer 卡住时会阻塞所有连接 37s改后立即返回。
- 全仓 13 处 `publish_outbound` 调用统一区分 `Dropped`warn预期背压/ `Closed`error异常日志级别消除监控噪音。scheduler 的 3 处 `?` 改为 warn避免 `Dropped` 触发 misfire 重试风暴。
- 前端 WebSocket 添加 25s 客户端 ping + 指数退避重连3s→6s→12s→24s→60s 封顶,上限 999 次)。重连后区分"重连恢复"与"首次/切换通道":前者保留断连前 messages 并刷新 topic 列表,后者清空数据避免污染。
### 安全加固
#### SSRF 重定向绕过修复
- `web_fetch` 工具禁用 HTTP 重定向(`redirect::Policy::none()`):原 `validate_url` 只校验初始 URL 的 host跟随 302 跳转可重定向到 `169.254.169.254`(云元数据)或 `127.0.0.1` 等内网地址,绕过 `is_private_host` 的 SSRF 防护。与 `http_request` 工具保持一致。
#### Safety Guard 正则收紧
- `format` 正则收紧为 `\bformat\s+.*[a-z]:`,要求出现盘符才拦截,避免误伤 `dart format``buf format``pytest --format` 等合法命令。
- 按平台分组注入规则Unix 不再注入 Windows 专用规则;`Remove-Item` 正则改为小写,与 `guard_command` 的大小写处理一致。
### 稳定性修复
#### SQLite 并发写入死锁
- 7 个写事务从 `BEGIN DEFERRED` 改为 `BEGIN IMMEDIATE`:在事务开始即获取写锁,消除多 sub-agent 并发写入时的死锁路径。`busy_timeout` 从 5s 提升至 30s。
- 根因:`BEGIN DEFERRED` 下多个事务可同时读 `MAX(seq)` 不持写锁提交时互相阻塞5s timeout 耗尽后返回 `SQLITE_BUSY``BEGIN IMMEDIATE` 强制写者串行排队,顺带消除 `MAX(seq)+1` 竞态导致的 UNIQUE 约束冲突。
#### 测试与代码质量
- 修复 `anthropic` 错误链嵌套测试为真正的 `#[source]`原测试是无效的inner 变量被 `let _` 抑制)。
- 补充 `anthropic` provider 15 个纯函数单测(原 396 行零测试),覆盖 data URL 解析、图片过滤、字段过滤、响应反序列化、错误链格式化。
- 修复 3 个失败测试:`agent_md_template` 写入模板内容 / `StreamingAccumulator` BTreeMap 保序 / `source_order` 断言补全。
- 清理未使用的 dead code 函数与方法。
- 新增 `ARCHITECTURE.md` 架构文档,聚焦数据流与 7 个关键设计决策。
#### CI 覆盖范围扩大
- `cargo build --lib` 改为 `cargo build`,确保 `main.rs` 二进制入口被编译验证。
- `cargo test --lib` 改为 `cargo test`,纳入 `tests/` 目录集成测试。`test_request_format.rs` 的 8 个序列化测试此前从未在 CI 中运行。
#### 跨平台构建修复
- 修正依赖分类错误:`rmcp` / `schemars` / `http` / `tower-http` / `rust-embed` 均为跨平台 crate错放在 `[target.'cfg(windows)'.dependencies]` 下导致 Linux 构建失败,移出 target 段。
## [0.2.0] - 2026-07-31
较 [0.1.2] 的 47 个 commit 迭代,聚焦 **能力策略**、**模型独立配置**、**话题级并发隔离** 与 **Agent Loop 性能优化** 四大方向。
### 新增功能
#### 能力策略CapabilityPolicy统一模型
- 新增 `CapabilityPolicy` 领域模型,统一管理专家/子代理/技能的 `allowed_skills` / `denied_skills` / `allowed_tools` / `denied_tools` 四类白/黑名单。
- 专家和子代理的 Markdown frontmatter 支持上述四类字段,在 `create_agent` 时按策略过滤 `ToolRegistry`(快照语义)。
- 子代理支持数据驱动的工具过滤,删除旧版内置 `explore` 白名单。
- 新增 HTTP 端点 `GET /api/tools``PUT /api/subagents/update`,供前端动态加载工具清单与更新子代理配置。
- 前端引入通用 `CheckboxList` 勾选组件,将 capability 字段从自由文本 textarea 改为按来源分组的勾选式编辑,避免手输工具名。
#### 模型独立配置
- 专家和子代理的 Markdown frontmatter 新增 `provider``model` 可选字段,引用 `config.json` 中的 `providers` / `models` 表,可独立指定模型而不再继承主 agent。
- 主 agent 支持会话级模型覆盖(`provider` / `model` 在配置层覆盖)。
- 前端编辑模态框新增"模型配置"卡片,含 provider/model 下拉选择,选项由 `GET /api/model-options` 提供。
- 专家引用不存在的 provider/model 时阻断会话并报错;子代理引用失败时将错误回传给 LLM。
#### 话题级并发隔离
- 实现聊天消息串行锁,确保同一聊天的消息处理串行执行。
- 串行锁按 `topic_id` 键化,支持多话题并发执行,互不阻塞。
- `topic_id` 全程显式传递(从消息接收到历史加载),修复消息错投与并发阻塞。
- 内存历史缓存按 `topic_id` 键化(原按 `chat_id`),修复 DB 压缩时的 TOCTOU 覆盖问题。
#### 子代理嵌套深度配置
- 暴露 `tools.task.max_nesting_depth` 为可配置项(默认 2前端"Task 子代理"卡片新增输入框。
- 保留双重防护:工具调用前校验 + 工具集构造时按深度移除 `task` 工具。
#### 专家配置热更新
- 专家配置保存后即时生效,无需重启网关。
#### 工具调用序列前向检查
- 添加工具调用序列的前向校验,确保 tool 消息紧随 assistant 的 tool_calls 消息,避免 OpenAI/DeepSeek API 400 错误。
#### 前端测试基础设施
- 引入 vitest 测试基础设施,添加 `useChat handleServerMessage` 特征测试。
### 性能优化
#### Agent Loop 性能P0
- **工具定义缓存**`get_definitions()` 从每轮迭代调用一次改为 `process()` 循环外构建一次。基于快照语义——单次 `process()``Arc<ToolRegistry>` 不变,专家切换只影响下一次 `create_agent`
- **轻量 token 估算**:新增 `estimate_text_tokens_from_chat_messages`,直接基于 `ChatMessage` 累加字段长度,消除中间 `text_only_messages: Vec<Message>` 构造(原方案每条消息 × 5 字段双克隆)。
- **工具 token 估算循环外预算**`serde_json::to_string` 全量序列化工具定义从每轮一次降为 `process()` 内一次。
- **DB 写 offload**`PersistingEmittedMessageHandler``tokio::task::spawn_blocking` 包装 SQLite 同步写,解除 tokio worker 线程阻塞,不改变失败语义(仅记日志不阻断主流程)。
#### SessionPool 锁范围收敛
- `ensure_session_internal` 改为 double-checked locking先短暂持锁检查存在性释放锁后执行耗时的 session 创建含配置加载、agent 工厂构造),再次持锁插入并处理竞态。避免跨 `session_factory.create().await` 持有全局锁导致所有 channel 的 session 访问串行化。
### 修复
#### 安全修复
- 修复 SSRF 重定向绕过漏洞。
- 修复符号链接路径遍历漏洞。
- 修复 `TodoItemSummary` 字段缺失。
#### 并发与稳定性
- `replace_todos``transaction()` 包裹 DELETE + INSERT保证原子性——中途失败自动回滚避免 todos 列表丢失。事务内复用同一连接查询返回值,消除 `drop(conn)` 后重新 `pool.get()` 的冗余。
- 修复话题隔离下 `topic_id` 全程显式传递,解决消息错投与并发阻塞。
- 修复内存历史按 `topic_id` 键化,新增 `replace_topic_history` 修复 DB 压缩覆盖。
- 修复 `http.rs` 重启信号吞错P1
- 修复 prompt 注入吞错P0
#### 前端修复
- 修复点击设置后白屏React hooks 顺序违规(`useEffect` 放在条件 return 之后导致 #310 错误)。
- 修复 `useEffect` 依赖项缺失P0
- 修复子智能体视图间歇性丢消息:同步前置 `subAgentViewRef` / `subAgentStackRef`
- 修复子智能体工具消息去重:改为按 `id + type` 去重,修复工具状态卡在执行中。
- 修复高亮消息时退出子智能体视图的问题。
- 修复专家发现与前端选择多项问题。
- 兼容 `base_url` 末尾斜杠,避免拼接产生双斜杠导致 404。
- `TodoWriteTool` merge 模式内存为空时从 DB 回填,防止丢失旧项。
#### 依赖与构建
- 升级 wechatbot 的 `reqwest` 至 0.13,消除版本冲突。
-`rmcp` 依赖从 git branch 迁移到 crates.io 版本。
- 提交 `Cargo.lock` 以保证二进制构建可复现binary 项目约定)。
### 重构
#### 前端架构
- 重写 `useChat` 为组合根,消除上帝 Hook。
- 抽取 `useChat` 的领域子 hook 与 `messageMappers`
- 建立前端 API 客户端层,消除硬编码路径与重复 `fetch`
- 拆分 `ConfigPage.tsx``storage/mod.rs`P2
- 清理 P0/P1 技术债(`any` 类型、React key、dead_code、硬编码 URL
#### 后端架构
- 重构 `AgentLoop` 中的消息处理逻辑,简化工具结果处理和 LLM 请求构建。
- 重构工具提示提供者,整合工具使用说明;删除冗余的 `TodoPromptProvider`
- `get_current` / `save_topic` 直读 DB 加载消息,移除 `SessionManager` 依赖。
- 改用 `gray_matter` 解析 Markdown frontmatter增加相应日志。
- 优化工具使用说明,简化记忆检索和写入规则。
- 移除未使用的 `cli_sessions` 变量,优化 `ws.rs` 中的代码。
### 内部改进
- 增加整理意识,确保同类工作输出到同一文件夹。
- 修复 MCP 日志输出。
---
## [0.1.2] - 2026-07-28
### 新增
- WebSocket 连接泄漏修复,使用 `CancellationToken` 实现优雅重启。
- 交互式 Shell 会话管理。
- 数据库连接池优化会话存储,新增错误处理。
- 平台特定的进程输入等待检查,增强 Bash 工具的用户授权检测。
- 前端静态文件嵌入二进制。
- React Web UI 前端界面。
[0.2.0]: https://github.com/picobot/picobot/compare/v0.1.2...v0.2.0
[0.1.2]: https://github.com/picobot/picobot/releases/tag/v0.1.2