# 变更日志 本文件记录 Picobot 各版本的显著变更,遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 风格。 ## [0.4.2] - 2026-08-17 较 [0.4.1] 的 8 个 commit 迭代,聚焦 **安全漏洞修复**、**全链路性能优化** 与 **前端健壮性** 三大方向。 ### 新增功能 #### 部署安全加固 - 前端生产构建产物与配置文件中,输出/展示时排除所有 token 相关敏感字段(`api_key`/`auth_token`/`access_token` 等),防止误写入日志或静态文件泄露凭据。 ### 性能优化 #### 前端流式渲染性能(子代理场景 P0) - 子代理 `stream_delta` 用 `requestAnimationFrame` 批处理 delta 合并,避免每 token 一次 setState 触发子树重渲染。 - 消息槽(MessageBubble / SubagentCard)用 `React.memo` 包裹,流式期间跳过未变更项的 diff。 - base64 附件解码改为分块处理,大文件解码时不阻塞主线程。 #### Bash 输出增量匹配与 HTTP 工具性能 - Bash 增量匹配:每一次增量输出原先用 O(n²) 算法寻找已有匹配段,改为基于游标增量扫描,长 stdout 场景 CPU 占用显著下降。 - Bash 缓冲上限:新增流式缓冲大小限制(默认 2MB),超出时按行截断,防止异常大输出撑爆内存。 - `http_request` 复用 `reqwest::Client`(之前每次调用新建),建立连接池;响应体保持流式分块读取并累加限长。 #### 数据库热路径优化 - 热路径同步 SQLite 操作(`get_topic_message_count`、`load_messages_for_topic_full` 等)改 `tokio::task::spawn_blocking`,解除 tokio worker 线程阻塞,多 topic 并行场景吞吐提升。 - 定向查询优化:只查询需要的列(不加载 tool_calls_json / content 等大字段),减少 DB → 内存拷贝。 ### 修复 #### 安全漏洞 - 升级 `quinn-proto` 0.11.14 → 0.11.16,修复 **RUSTSEC-2026-0185** 远程内存耗尽漏洞(QUIC 握手畸形数据包导致的无界内存分配)。 - `npm audit fix` 修复前端 4 个高危依赖漏洞:`vite` / `postcss` / `undici` / `nanoid`。 #### 子代理运行中状态丢失 - 历史加载时对账 task running 占位:刷新页面或切换话题后,子代理卡片不再因 running 占位缺失而永远显示「运行中」。 ### 重构 - 清理 clippy 存量告警:替换不必要的 `unwrap()` 为 match/`?`,去除多余 `.clone()`,删除冗余分支与死代码。 --- ## [0.4.1] - 2026-08-14 较 [0.4.0] 的 17 个 commit 迭代,聚焦 **前端视觉重构**、**话题级模型选择**、**定时任务可靠性**、**缓存占比统计** 与 **调度器并发** 五大方向。 ### 新增功能 #### 前端视觉重构(对齐 deepseek-harness 设计语言) - 重构前端视觉与三栏布局,对齐 deepseek-harness 设计语言。 - 通道/会话切换移至设置页新增 `ConnectionTab`,连接状态上移 Logo 行,窄侧栏支持 compact 降级。 - 工具卡片统一格式:子智能体显示「工具名 · 任务描述」,移除下方徽章与时间。 #### 话题级模型选择 - 后端持久化与 API:`topics` 表新增 `provider` / `model` 列 + 双写内存缓存。 - 模型解析链:`topic > session > expert > config` 逐级覆盖;`TaskToolResult` 附带实际使用的模型。 - 前端:`ModelSelector` 话题级化(`topicId` 透传 + 竞态防护),隐藏专家系统开关。 - Task 卡片差异显示子代理模型名。 #### per-topic 输入草稿记忆 - 切换话题时暂存当前草稿、切回时恢复,`localStorage` 持久化,删除话题时清理。 #### 缓存占比统计 - 新增缓存占比统计(`cached_tokens`),聚合查询收敛到共享列清单。 - Provider 缓存命中诊断日志,兼容两种 usage 缓存格式解析。 #### 定时任务可靠性 - 静默定时任务执行后增加主动送达提示,避免结果静默丢失。 - 调度器重构:任务执行移出 tick 循环,`worker_queue_capacity` 并发约束生效,实现非阻塞派发。 ### 修复 - **定时任务空历史执行**:执行前自动补齐 topic,修复 agent 空历史执行问题。 - **前端缓存占比恒为 0**:`TopicTokenStats` 补齐 `cached_tokens` 字段(协议字段缺失)。 - **通道失效回退**:通道/会话切换迁移时修复通道失效后的自动回退。 - **子代理完成状态转发**:修复子代理完成状态在前端转发链路丢失。 ### 内部改进 - 缩减 INFO 日志量,高频诊断日志降级或删除。 ### 测试 - 定时任务 topic 补齐与消息送达回归测试。 - 调度器非阻塞派发与并发容量回归测试。 --- ## [0.4.0] - 2026-08-13 较 [0.3.5] 的 3 个 commit 迭代,聚焦 **异步子代理 v8 架构**、**/stop 取消流程** 与 **前端子代理状态展示** 三大方向。异步子代理 v8 为里程碑式架构升级:子代理执行从「父子同步串行」改为「后台异步 + 显式等待」,显著提升多子代理并行吞吐与父代理可控性。 ### 新增功能 #### 异步子代理 v8 架构(父代理不再阻塞) - **双通道异步通信**:子代理结果走独立队列 `sub_done_q`(直达 wait,不绕 SQLite → bus → reload);用户消息复用现有 bus,channel 适配器零改动。 - **`wait_for_subagents` 工具**(新增 `src/tools/wait_tool.rs`):`select!` 等待子代理完成 / 用户消息 / 超时,支持 `try_drain` 批量消费;task tool_result 返回 `running` + 引导提示,引导 LLM 调用 wait。 - **`wait_coordinator`**(新增 `src/gateway/wait_coordinator.rs`):释放/重获取 `serial_lock` 的 in-tool waiting 模式,替代旧的 break-exit 方案;`is_waiting` 持锁后判断,无 TOCTOU。 - **task 工具异步 spawn 路径**(`src/tools/task/runtime.rs` +488):`CancellationToken` 注册表 + RAII guard + `Semaphore` 并发限流。 - **子代理完成回调**携带 `pending_task_ids` 列表,LLM 据此判断全局进度并决策下一步。 - **崩溃恢复**:启动时标记 `running -> interrupted`,history 加载时对账占位;新增 `pending_subagents` 表 + 条件 UPDATE + `mark_all_running_as_interrupted`。 - **嵌套层级**:仅顶层异步,避免复杂度爆炸。 - 新增 `docs/ASYNC_SUBAGENT_DESIGN.md` 设计文档,记录 v8 三个核心不变量、wait 模式、取消机制与崩溃恢复策略。 ### 修复 #### /stop 取消流程 - `wait_coordinator` `select!` 添加 cancel 分支,完整清理状态。 - `ToolContext` 注入 `cancel_rx`(watch::Receiver clone)。 - `agent_loop` 工具执行 `select!` 对 wait 工具跳过竞速,防止 drop coordinator 清理逻辑。 - 子代理完成状态通过 `execution_completed` metadata 传播。 #### 前端子代理状态显示与渲染崩溃 - `MessageBubble`:`taskStatusConfig` 补全 running/completed/cancelled/interrupted 状态配色,修复未知状态访问 `undefined.borderColor` 导致的白屏崩溃;添加安全回退到 failed 状态。 - `main.tsx`:新增 `ErrorBoundary` 捕获 React 渲染错误,防止白屏并提供错误详情与恢复入口。 - `useMessages`:收到子代理 `execution_completed` 事件后,更新主视图中 task tool result 占位消息的 status 字段(running → completed/failed/cancelled),消除永久黄色转圈。 - `protocol.ts`:`ExecutionCompleted` 接口新增 `subagent_status` 和 `subagent_summary` 字段。 ### 测试 - `src/tools/task/runtime.rs` 测试模块持续扩充,覆盖异步 spawn / 取消 / 并发限流等核心路径。 --- ## [0.3.5] - 2026-08-12 较 [0.3.4] 的 7 个 commit 迭代,聚焦 **可观测性**、**并发性能** 与 **外部集成健壮性** 三大方向。 ### 新增功能 #### MCP 工具调用超时保护 - 在 `McpToolWrapper` 适配层用 `tokio::time::timeout` 包裹 `call_tool`,防止外部 MCP server 挂起导致 agent loop 无限阻塞。 - 超时时间通过 `config.mcp_tool_timeout_secs` 配置(默认 300 秒,0=不超时)。 - 前端 McpTab 设置页提供输入框。 #### 端到端可观测性整改 - **trace_id 全链路传播**:`BusToolCallEmitter` / `SubAgentEmitter` / `processor` 全链路设置 trace_id。 - **AgentEnd 指标配对**:补发 5 个 cancel/defensive 路径的 AgentEnd 事件,闭合 AgentStart 指标。 - **LLM 计时修正**:`attempt_start` 移入 retry 循环,排除退避等待时间。 - **`/metrics` auth**:非 loopback 部署时纳入 Bearer token 校验。 - **recorder 复用**:`OnceLock` 缓存 `PrometheusHandle`,热重启后不再返回 503。 - **结构化日志**:新增 `tracing_ctx` + JSON 日志格式支持。 ### 修复 #### 压缩期间 session 锁阻塞新建话题 - 压缩任务在 LLM 调用(2-5s)期间持有 session 锁,阻塞 `create_session` 命令获取锁执行 `switch_topic`,导致新建话题后列表刷新延迟。 - 将压缩重构为 4 阶段: 1. 短暂持锁:读取 history/compressor/store/session_id/provider_config 2. 释放锁:LLM 压缩调用(2-5s) 3. 释放锁:DB 写入(store 为 Arc,DB 层自带事务保护) 4. 短暂持锁:reload 内存历史 - 并发安全:同 topic 由调用方的 per-topic serial lock 保证串行;不同 topic 完全并行不受影响。 #### MCP 前端空输入重置为不超时 - 清空输入框时回退到默认值 300 而非 0(0 表示不超时,与用户预期不符)。 - 新增两个 tokio 测试覆盖有超时和无超时(error pass-through)路径。 #### 移除 ChatContainer key remount 修复新建话题列表刷新延迟 - 话题切换时 `key={selectedTopic}` 导致整个 `ChatContainer` 子树卸载重建,触发 `ExpertSelector` / `ModelSelector` 重新挂载并发起 3 次冗余 HTTP 请求(`getSelectedExpert` / `listModelOptions` / 模型选择刷新),引入 200-500ms 延迟。 - 改用 `topicId` prop 透传话题 ID: - `App.tsx`:移除 key,`viewKey` 纳入 `selectedTopic` 保持各话题独立滚动位置。 - `ChatContainer`:新增 `topicId` prop 透传给 `MessageInput`。 - `MessageInput`:监听 `topicId` 变化清空草稿,替代原 key remount 重置机制。 #### Panic 安全增强 - `agent_loop.rs` / `processor.rs`:用 `catch_unwind` 隔离工具执行和消息处理的 panic,归一化为错误返回,LLM 可见错误并自我纠正,防止用户消息被静默丢弃。 - `utils.rs`:新增 `panic_payload_message()` 从 panic payload 中提取可读消息,支持 `&str` / `String` / 其他类型降级。 - `bus/message.rs`:修复 `sanitize_incomplete_tool_call_sequences` 两阶段删除索引未全局排序导致的越界 panic(Phase 1 降序 + Phase 1.5 升序 → 合并后必须重新排序)。 #### 计算器健壮性 - 拒绝 `"NaN"` / `"inf"` 等非有限输入,防止 `sort_by` 中 `partial_cmp().unwrap()` panic。 - 修复阶乘溢出:上限从 170 降至 34(35! 超出 `u128::MAX`),改用 `checked_mul` 替代 unchecked 乘法。 - `evaluate` 表达式拒绝非有限结果(如 `1/0` → inf、`0/0` → NaN)。 - 新增 7 个 tokio 测试覆盖所有边界场景。 ### 测试 - MCP 超时路径新增 2 个 tokio 单元测试。 --- ## [0.3.4] - 2026-08-10 较 [0.3.3] 的 9 个 commit 迭代,聚焦 **安全加固**、**健壮性防御** 与 **代码质量优化** 三大方向。 ### 新增功能 #### 顶栏显示后端版本号 - 复用现有 `/health` 端点返回的 `CARGO_PKG_VERSION`,避免在 `package.json` 重复维护版本号。 - 前端挂载时拉取一次,失败则不显示徽标。 #### 文件工具路径限制(最小权限原则) - 默认行为:文件读写编辑限制在当前工作目录内。 - 新增配置项:`tools.allowed_dirs`(白名单目录列表)+ `tools.file_access_unrestricted`(opt-in 全局放开)。 - 共享 `resolve_file_path()` 函数,使用 `canonicalize()` 防御符号链接与 `..` 路径遍历。 - 前端:设置页 > 工具标签新增"文件访问"卡片,含开关与目录标签编辑器。 - 向后兼容:旧配置默认 cwd 限制(`serde(default)`)。 ### 安全修复 #### Shell 会话生命周期管理 - `GatewayState` 持有 `Arc` 引用,网关关闭时(`ctrl_c` 和重启两条路径)调用 `shutdown()`。 - 新增防御性 `Drop` impl,泄露会话时打 warn 日志。 - 子进程 kill 添加 5s 超时,防止无限阻塞。 #### HTTP 工具 OOM 防护 - `WebFetchTool` / `HttpRequestTool` 实现流式读取响应体(`futures_util::StreamExt`),防止大响应撑爆内存。 - 检查 `Content-Length` 头,分块读取并累计校验大小。 - 默认限制:`WebFetch` 200KB,`HttpRequest` 4MB。 #### TimeTool 重复类型转换修复 - 移除 `time.rs` 中重复的 `u32::try_from` 调用(复制粘贴错误)。 #### 消除 16 处 unreachable! panic 风险 - 15 个 command handler 文件中 `_ => unreachable!()` 替换为 `_ => Err(CommandError::new(...))`,防止 `Command` 枚举新增变体时运行时 panic。 #### 配置占位符校验 - 新增 `validate_no_unresolved_placeholders()`,拒绝包含未解析 `` 或 `\` 占位符的配置。 - 防止字面占位符字符串被当作真实 API key 发送到 LLM provider(难以诊断的 401 根因)。 - 首次运行跳过校验(`create_default_config` 模板场景)。 ### 修复 #### 切换话题后滚动到最新消息 - 修复切换话题后不滚动到最新消息的问题。 - 跟随意图仅由用户输入(wheel/touch/key)推翻,程序触发的滚动不会打断用户浏览。 - 将虚拟化 `totalSize` 纳入滚动依赖,使测量收敛到真实底部。 #### WebSocket 重连竞态修复 - 修复 URL 切换时的 WebSocket 重连竞态问题。 - 事件处理引入代际同一性守卫,孤儿 socket 事件整体忽略。 - disconnect 恰好触发一次 `onDisconnect`,避免重复清理。 #### 删除话题竞态修复 - 修复删除选中话题时的竞态问题。 - 乐观移除本地话题并以 `null` 作为唯一无选择哨兵。 - 杜绝基于过期列表重选已删除话题。 ### 重构 #### 8 处 quick wins - `shared.rs` 提取 channel/cli 适配器公共逻辑,消除 124 行重复代码。 - `http_utils.rs` 提取 HTTP 响应读取公共逻辑,`http_request.rs` 与 `web_fetch.rs` 共享实现。 - `bash.rs` / `shell_session.rs` 简化冗余逻辑。 - `gateway/mod.rs` 优化路由分支。 - `storage/mod.rs` 精简查询逻辑。 - `mcp/client.rs` 增强错误处理。 ### 内部改进 - 修复 release 构建编译器警告:补全 `regex::Captures` 显式生命周期标注,`cfg(debug_assertions)` 条件化仅 debug 使用的变量,`AnthropicProvider::llm_timeout_secs` 添加 `cfg_attr allow(dead_code)`。 - 飞书 channel 时间戳去重改用 `crate::utils::current_timestamp()`,消除 `unwrap()` panic 点并统一日志格式。 - 批量更新依赖 patch 版本(chrono, clap, anyhow, bytes 等),无 breaking change。 ### 测试 - `cancel_manager.rs` 新增 8 个单元测试,覆盖 register/cancel/remove/overwrite/list/cancel_all/drop-safety 核心路径。 - `session_pool.rs` 新增 3 个单元测试,覆盖 `is_scheduler_chat_id` 路由逻辑。 - 配置占位符校验新增 11 个单元测试,覆盖空值、小写、数字、去重、多占位符、首次运行、加载集成等边缘场景。 --- ## [0.3.3] - 2026-08-07 较 [0.3.2] 的 12 个 commit 迭代,聚焦 **前端渲染性能飞跃**、**流式通信健壮性** 与 **代码质量治理** 三大方向。 ### 新增功能 #### 执行状态对账端点 - 新增 `GET /api/executions` HTTP 端点,返回后端权威的执行中话题集合。前端 WebSocket 重连时调用此端点对账,修正断连期间丢失的 `execution_completed` 信号导致的状态漂移。 ### 性能优化 #### 消息列表虚拟化(长对话不再卡顿) - 引入 `@tanstack/react-virtual` 替换原 `messages.map` 全量渲染,只渲染视口内 + overscan=6 条消息,DOM 节点数恒定。 - `measureElement` 动态测量变高度消息(一行文本 vs 50 行代码块),`estimateSize=120` 提供初始估计,测量后自动校正。 - Firefox 特殊处理 `measureElement`(`getBoundingClientRect`)。 - 适配现有功能:自动滚到底部改用 `virtualizer.scrollToIndex`;`viewKey` 滚动位置记忆保留;`highlightedMessageId` 先渲染目标项再 rAF 加 class;流式 delta 不计数(消息条数不变)。 - 性能对比(500 条消息):DOM 节点 10000+ → ~200;首次渲染数百 ms → <16ms;流式 diff 从全量列表降至仅可见项。 #### 流式 delta 批处理(避免每 token 全数组拷贝) - 用 `streamingRef` 累加 delta chunks + `requestAnimationFrame` 批量 flush,将每秒数十次 O(n) 数组拷贝合并为一帧一次状态更新。 - `useMessages.ts` 新增 `streamingRef` 累加器 + rAF 调度,所有 delta 只 push 到 ref,由 `flushStreaming` 批量落盘。 - `useChat.ts` 5 处 `setMessages([])` 改为 `clearMessages()`,切话题/会话/通道时重置流式 ref,避免脏状态残留。 - 复杂度:O(n²·L) → O(n) 每帧。 ### 改进 #### 压缩阈值默认值下调 - 工程化压缩阈值 `threshold_ratio` 从 0.7 下调至 0.5(50%),LLM 压缩阈值 `llm_compaction_threshold_ratio` 从 0.5 下调至 0.3(30%)。 - 降低触发门槛使压缩更积极介入,减少上下文溢出风险。同步更新相关注释、日志信息和前端 hint 文案。 ### 修复 #### 输入框/发送按钮状态按话题隔离 - 将单一全局 `isLoading` 布尔值重构为按 `topic_id` 跟踪的 `processingTopicIds` 集合,`isLoading` 派生自当前选中话题是否在集合中。 - 导航响应不再清空处理状态,切换话题后切回原话题仍能正确禁用输入。 - 重连时通过 `/api/executions` 端点对账后端权威执行状态,修正断连期间丢失的 `execution_completed` 信号。 #### WebSocket 断连时清理流式状态 - 修复 WebSocket 在流式输出中途断连时 `streamingRef`(contentChunks/index)不重置,导致重连后新消息 delta 追加到旧消息错误位置。 - 修复链路:`useWebSocket` 的 `onDisconnect` 回调 → `useChat` 的 `finishStreaming` → `useMessages` 的 `finishStreaming`(重置 ref + flush pending chunks)。 #### 会话消息泄露到定时任务视图 - `handleSchedulerMessage`(Tier 1 路由)原先无条件吞掉所有可转换的 chat 消息,导致正在执行的实时消息被错误追加到调度器视图。 - 修复:调度器视图只接收不带 `topic_id` 的历史加载消息;实时流式消息和带 `topic_id` 的实时消息 fall through 到主视图。 ### 重构 #### 公共工具函数提取与 DRY - 提取 `src/utils.rs` 公共工具函数模块,消除跨模块重复逻辑。 - 修复飞书 channel 正则表达式重复编译问题,改为 `Lazy` 一次编译。 - 网关路由逻辑 DRY 化,减少 `gateway/mod.rs` 重复代码。 - `agent_loop` / `providers` / `config` / `storage` 等多模块统一引用公共函数,20 个文件受影响。 - CI 新增安全审计步骤(`cargo audit`)。 ### 内部改进 - 存储模块应用 `rustfmt` 格式化(`migrations.rs` / `row_mapping.rs` / `tests.rs`)。 - 降低 `list_todos` handler 与 gateway 转发日志级别为 debug,减少子代理多次更新待办时的 INFO 日志噪音。 - 删除临时优化计划文件 `OPTIMIZATION_PLAN.md`。 ### 测试 - 新增 MessageList 虚拟化对抗性 smoke test(5 个用例):空消息渲染、100 条消息不崩溃、highlight 视口外不崩溃、viewKey 切换不崩溃、流式 rerender 不崩溃。 - 新增流式断连对抗性测试(2 个用例):`stream_end` 幂等性验证、多周期断连-重连循环下 `finishStreaming` 幂等验证。 - 新增断连后新 delta 不污染旧消息测试(用例 17)。 - 新增定时任务视图消息隔离测试(用例 16)。 - 新增批量 delta 累加与 `stream_end` 后 `assistant_response` 替换对抗性测试。 --- ## [0.3.2] - 2026-08-06 较 [0.3.1] 的 7 个 commit 迭代,聚焦 **上下文压缩可配置化**、**网关安全加固**、**并发模型优化** 与 **错误防御性提升** 四大方向。 ### 新增功能 #### 压缩算法关键参数暴露到设置页面 - 将 4 个上下文压缩参数从硬编码提取到 `config.json` 顶层 `compaction` 节: - `threshold_ratio`(0.7):工程化压缩触发阈值,占 `context_window` 的比例 - `llm_compaction_threshold_ratio`(0.5):LLM 压缩触发阈值 - `truncate_max_tokens`(100):工程化压缩时 tool 结果截断到的 token 数 - `preserve_count`(5):LLM 三段压缩保留最旧/最新的 unit 数 - 前端新增"上下文压缩"设置标签页(Archive 图标),4 个 number input 分两组展示。 - `ContextCompressor` 内聚所有压缩参数,新增 `with_compaction_config()` 构造函数和 `truncate_tool_results()` 方法。 - `AgentLoop` 通过调用 `compressor.truncate_tool_results()` 实现零参数耦合,压缩参数变更仅影响 `ContextCompressor`。 #### HTTP API 认证与 CORS 防护 - 新增 HTTP API 认证机制,未授权请求直接返回 401。 - CORS 防护:明确指定允许的 origin,阻止跨域未授权访问。 - 修复密钥泄露风险:敏感信息不再出现在错误响应中。 ### 改进 #### 上下文压缩重构为两阶段+双阈值+三段保留 - **两阶段压缩**:工具调用完成后触发压缩流程,先用 `prompt_tokens` 判断 70% 阈值。 - **阶段 1(工程化压缩)**:截断非子代理 tool 结果到约 100 token,仅改内存数据。 - **阶段 2(LLM 压缩)**:工程化压缩后若估算 token 仍超 50% 阈值,才调用 LLM 压缩。 - **三段保留**:保留最旧 5 个 unit + 中间段 LLM 摘要 + 最新 5 个 unit,通过 `HistoryUnit` 原子单元保证 `ToolRound` 不被拆分。 - LLM 压缩失败时降级为仅工程化压缩,不中断 agent loop。 #### 迁移 parking_lot 锁并优化阻塞 IO 与内存管理 - 将 `std::sync` 锁替换为 `parking_lot` 实现,减少锁竞争开销。 - 优化阻塞 IO 路径,避免热路径无谓阻塞。 - 内存管理改进:减少不必要的克隆与分配。 ### 修复 #### 子智能体任务状态卡死 - 修复已完成子智能体任务卡在"子智能体正在执行..."状态,前端无法正确展示结果。 #### 飞书 channel 消息丢失 - 修正飞书 reaction 语义,与飞书 API 规范对齐。 - 增容 message bus 队列,避免高频消息场景下队列满导致最后一条消息丢失。 #### 防御性错误处理 - 替换 `unreachable!()` 宏调用为防御性错误返回,避免运行时 panic。 - agent/gateway 关键路径改用 `Result` 传播错误,提升系统鲁棒性。 --- ## [0.3.1] - 2026-08-05 较 [0.3.0] 的 19 个 commit 迭代,聚焦 **历史压缩可追溯性**、**token 统计准确性**、**前端渲染稳定性**、**工具执行可靠性** 与 **网关吞吐优化** 五大方向。 ### 新增功能 #### 历史压缩保留原消息(双视图分离) - 压缩流程从物理删除原消息改为标记位 `is_compacted` 分离两个视图: - **LLM 视角**(`load_messages_for_topic`):只看 `is_compacted=0` 的压缩摘要 + 新消息,context 仍精简。 - **UI 视角**(`load_messages_for_topic_full`):看原消息(含 `is_compacted=1`)+ 新消息,排除压缩摘要,前端切回老话题仍能展示完整原始对话。 - 新增 `compact_topic_history`:不删除原消息,仅打标记 + 插入摘要,同事务内删除旧摘要避免累积。修复 token 统计因压缩丢失 `usage` 的问题。 - `messages` 表新增 `is_compacted INTEGER NOT NULL DEFAULT 0` 列,migration 幂等。 #### Topic 维度 token 统计 - 新增 `batch_topic_token_stats`,按 `topic_id` 聚合 token 消耗,替代原按 `session_id` 聚合导致的同 session 多 topic 共享总和问题。 - 前端侧边栏每个 topic 显示独立 token 消耗与 context 占用百分比(Coins 图标 + 数值,绿/黄/红三色指示)。 - 主代理执行结束时触发 `list_topics` 刷新(500ms 防抖),实时更新侧边栏 token 统计;子代理每轮执行也支持刷新。 #### 设置页重启按钮 - 设置页 Footer 区新增重启按钮,样式为 `bg-tertiary` + 边框,与主保存按钮区分。 - 确认对话框区分触发来源:保存后触发显示"配置已保存 / 稍后",手动触发显示"重启服务 / 取消"并警告未保存改动。 - 状态管理改用 `restartDialogMode: 'saved' | 'manual' | null`,按钮在重启期间显示 loading 并禁用。 #### 设置页懒加载标签页与子代理管理 - 拆分设置页为懒加载标签页,减少首屏渲染负担。 - 前端支持子代理创建与删除,配合 `PUT /api/subagents/update` 端点。 #### LLM 主调用可配置重试机制(0.3.0 收尾补充) - `ProviderConfig` 增加 `max_retries` 字段(serde default=3,向后兼容)。 - `agent_loop` 流式 + summary 两个调用点实现重试循环:指数退避 1s/2s/4s,仅对 429/502/503/504/timeout/connection reset 重试;流式仅在未 emit delta 时重试,避免重复输出。 ### 修复 #### 前端渲染稳定性 - `MessageBubble` 使用 `React.memo` 避免流式期间不必要重渲染。 - `useWebSocket` 回调 ref-化,避免父组件重渲染触发 WebSocket 无谓重连。 - 修复触发滚动到底部按钮时新消息计数错误。 - 修复话题重命名预填字段与写入字段不一致。 - 修复流式期间消息重渲染、WebSocket 无谓重连与新消息计数错误。 #### 子智能体结果展示 - 失败/超时子智能体返回结构化结果,前端可点击查看详情,而非静默丢失。 #### Token 统计准确性 - 修复 token 统计按 `session_id` 聚合导致同 session 多 topic 共享总和:改为按 `topic_id` 聚合,子代理消息通过 `session_id NOT LIKE 'sub:%'` 排除。 - 修复主代理执行结束后 token 统计不刷新:`useMessages` 在 `execution_completed` 事件时触发 `bumpTopicRefreshTrigger()`。 #### 工具执行可靠性 - 修复 shell 工具超时未生效:`adb start-server` 守护进程继承 stdout 管道导致 EOF 阻塞,`adb devices` 误判 socket 等待为 stdin 等待绕过 deadline。新增 `STREAM_DRAIN_MS` 常量、改进 `kill_and_reap`、移除 `should_return_pending` 中的错误检查,确保 timeout 参数完全覆盖默认值。 #### 安全加固 - `web_fetch` 加固 SSRF 防护,禁用 HTTP 重定向,与 `http_request` 实现对齐。 #### MCP 兼容性 - 限制 MCP server 名称字符并兜底 `tool_name` 清洗,避免非法字符导致 OpenAI API 400。 ### 性能优化 #### 网关吞吐 - `send_with_retry` 对 `ChannelFull` 错误短路(不重试、不退避),加速队列消费,避免 dispatcher 在满队列时 7s 退避阻塞。 - 新增 `ChannelError::ChannelFull` 变体,`CliChannel` 在 `try_send` 返回 `Full` 时映射为 `ChannelFull`。 #### 存储查询 - `get_topic_message_count` 改用 `SELECT COUNT(*)` 在数据库侧计数,避免将所有消息(含 `content`、`tool_calls_json` 等大字段)加载到内存。 #### 热路径优化 - 减少热路径无谓拷贝与重复正则编译,跳过已完成 migration。 ### 内部改进 - 删除临时计划文件 `PLAN.md`。 - CHANGELOG 补充 LLM 重试机制条目并修正 commit 计数。 --- ## [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.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,匹配长任务子代理的实际需求。 #### 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_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.4.2]: https://github.com/picobot/picobot/compare/v0.4.1...v0.4.2 [0.4.1]: https://github.com/picobot/picobot/compare/v0.4.0...v0.4.1 [0.4.0]: https://github.com/picobot/picobot/compare/v0.3.5...v0.4.0 [0.3.5]: https://github.com/picobot/picobot/compare/v0.3.4...v0.3.5 [0.3.4]: https://github.com/picobot/picobot/compare/v0.3.3...v0.3.4 [0.3.3]: https://github.com/picobot/picobot/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/picobot/picobot/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/picobot/picobot/compare/v0.3.0...v0.3.1 [0.3.0]: https://github.com/picobot/picobot/compare/v0.2.0...v0.3.0 [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