PicoBot/docs/CHANGELOG.md

14 KiB
Raw Blame History

变更日志

本文件记录 Picobot 各版本的显著变更,遵循 Keep a Changelog 风格。

[0.3.0] - 2026-08-04

0.2.0 的 18 个 commit 迭代,聚焦 Agent 执行与显示层解耦LLM 调用稳定性工程化基线并发持久化稳定性安全加固MCP 兼容性 六大方向。锁屏冻结架构修复经五轮对抗性审查验证。

新增功能

话题重命名

  • 新增 RenameTopic 命令与 TopicRenamed 协议消息,复用存储层已有的 update_topic_title 方法。后端响应携带刷新后的完整 topic 列表,前端零额外往返同步侧边栏。
  • 前端 TopicList 侧边栏增加内联编辑入口悬停显示铅笔图标Enter 提交 / Esc 取消 / blur 取消,通过 onMouseDown preventDefault 防止按钮点击时 input 提前失焦。

前端自动构建集成

  • 新增 build.rscargo build 时自动执行 npm install + npm run build,消除前后端构建割裂。支持 SKIP_FRONTEND_BUILD 环境变量跳过。

工程化基线

  • rustfmt.toml 固化 max_width=100 / 4 空格缩进;Cargo.toml 配置 [lints.rust][lints.clippy] 渐进式规则。
  • .github/workflows/ci.ymlRustfmt + 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匹配长任务子代理的实际需求。

LLM 主调用可配置重试机制

  • ProviderConfig 增加 max_retries 字段serde default=3向后兼容透传至 AgentRuntimeConfig 归属 agent 行为层,不进 ProviderRuntimeConfig 以保持 provider 构造包纯净。
  • agent_loop 流式 + summary 两个调用点实现重试循环:指数退避 1s/2s/4s仅对 429/502/503/504/timeout/connection reset 重试;流式仅在未 emit delta 时重试(AtomicBool 跟踪),避免重复输出;退避 sleep 期间响应 cancel_signal,取消优先。
  • 前端 ProviderConfig 类型和表单增加 max_retries 字段。
  • 7 个单元测试3 判定 + 4 行为540 个 lib 测试全绿。

架构修复

Agent 执行与显示层解耦(锁屏冻结根因修复)

根因:浏览器锁屏导致 WebSocket 半死,ws_sender.send().await 永久阻塞,级联阻塞 dispatcher → MessageBus → Agent Loop后端停止执行直到解锁。

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

  • MessageBus::publish_outboundsend().await 改为 try_send()bus 满时丢弃消息并告警agent 不再被显示层阻塞。新增 BusError::Dropped 变体。
  • WebSocket writer task 包裹 tokio::time::timeout(30s):半死连接超时即关闭。使用每连接独立的 CancellationToken(非共享的 CliChannel 级 token避免一个连接超时关闭所有连接。writer 退出时 cancel 通知主 loop 退出,确保 unregister_connection 执行。
  • CliChannel::sendsend().await 改为 try_send()dispatcher 单线程顺序处理,原阻塞式发送在 writer 卡住时会阻塞所有连接 37s改后立即返回。
  • 全仓 13 处 publish_outbound 调用统一区分 Droppedwarn预期背压/ Closederror异常日志级别消除监控噪音。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 formatbuf formatpytest --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_BUSYBEGIN 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_keytool_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/toolsPUT /api/subagents/update,供前端动态加载工具清单与更新子代理配置。
  • 前端引入通用 CheckboxList 勾选组件,将 capability 字段从自由文本 textarea 改为按来源分组的勾选式编辑,避免手输工具名。

模型独立配置

  • 专家和子代理的 Markdown frontmatter 新增 providermodel 可选字段,引用 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 写 offloadPersistingEmittedMessageHandlertokio::task::spawn_blocking 包装 SQLite 同步写,解除 tokio worker 线程阻塞,不改变失败语义(仅记日志不阻断主流程)。

SessionPool 锁范围收敛

  • ensure_session_internal 改为 double-checked locking先短暂持锁检查存在性释放锁后执行耗时的 session 创建含配置加载、agent 工厂构造),再次持锁插入并处理竞态。避免跨 session_factory.create().await 持有全局锁导致所有 channel 的 session 访问串行化。

修复

安全修复

  • 修复 SSRF 重定向绕过漏洞。
  • 修复符号链接路径遍历漏洞。
  • 修复 TodoItemSummary 字段缺失。

并发与稳定性

  • replace_todostransaction() 包裹 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.tsxstorage/mod.rsP2
  • 清理 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 前端界面。