# 变更日志 本文件记录 Picobot 各版本的显著变更,遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 风格。 ## [0.3.0] - 2026-08-04 较 [0.2.0] 的 15 个已提交 commit + 本次版本一并提交的锁屏冻结架构修复(12 文件),聚焦 **Agent 执行与显示层解耦**、**工程化基线**、**并发持久化稳定性**、**安全加固** 与 **MCP 兼容性** 五大方向。架构修复经五轮对抗性审查验证。 ### 新增功能 #### 话题重命名 - 新增 `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`:Rust(fmt + 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 段。 #### MCP 工具名清洗 - OpenAI 要求 function name 匹配 `^[a-zA-Z0-9_-]+$`,否则整个请求 400。MCP 工具名由 `mcp_{server_key}_{tool_name}` 拼成,两个输入源分别处理: - 后端:`sanitize_tool_name` 替换 `tool_name` 中的非法字符(`.`, `:`, `/` 等)为 `_`,保留 `server_key` 和 `tool_name` 原值用于路由,仅清洗 LLM 可见的 `full_name`,发生清洗时打 warn 日志便于定位。 - 前端:MCP 卡片头部改用 `MapEntryHeader` 支持点击重命名,`addMcp` / `renameMcp` 正则校验 server 名称 + toast 提示。顺手修了 `MapEntryHeader` 进入编辑时 `val` 未同步当前 `name` 的 bug。 ## [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` 不变,专家切换只影响下一次 `create_agent`。 - **轻量 token 估算**:新增 `estimate_text_tokens_from_chat_messages`,直接基于 `ChatMessage` 累加字段长度,消除中间 `text_only_messages: Vec` 构造(原方案每条消息 × 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