53 Commits

Author SHA1 Message Date
oudecheng
452c5ad0ef fix(gateway): 修复长会话后新消息无响应——僵尸子代理清理、panic 兜底与运行预算
- 发送 ExecutionCompleted 前惰性清理僵尸 running 子代理(DB running 但执行任务已消失),解除 pending 阻塞
- processor panic 路径补发 error 通知 + ExecutionCompleted,防止前端永久 loading
- agent 单轮增加墙钟预算 max_run_secs,超时优雅退出释放 topic 串行锁
- topic 串行锁等待增加 info/warn 日志,长等待可观测
- sanitize 清理结果回写 DB(delete_messages_by_ids),消除每次加载的重复修复
- storage 新增 keyset 分页与按 ID 批量删除的单元测试
2026-08-18 09:33:07 +08:00
oudecheng
4517e4a724 perf(db): 热路径同步 SQLite 操作改 spawn_blocking 并定向查询
- processor/session 热点 DB 调用放到 blocking 线程池,避免阻塞 tokio worker
- 定向查询 topic 首条用户消息(DB 侧 LIMIT 1),不再全量加载历史
- 新增 first_user_message_content 访问方法
2026-08-17 09:54:54 +08:00
oudecheng
1019dbe8cc refactor(code-quality): 清理 clippy 存量告警(unwrap/clone/redundant 等)
- 移除无用克隆与冗余引用,减少不必要内存分配
- 规范 unwrap/expect 使用,修复可提前失败路径
- 修复 anthropic provider llm_timeout_secs 死代码并补全超时日志
- cargo fmt 统一格式
2026-08-16 23:22:22 +08:00
oudecheng
0f60b02ede chore(log): 缩减 INFO 日志量,高频诊断日志降级/删除
1. 删除缓存诊断日志 4 处(openai.rs):排查已完结,字段已补齐,每次 LLM 调用都刷屏。
2. 删除 AgentPromptProvider 模型配置日志(agent_prompt_provider.rs):排查遗留,每次请求刷。
3. AgentFactory 创建日志 info→debug(agent_factory.rs):每轮对话刷,降级保留供偶发排查。
4. Calling tool / Tool calls detected info→debug(agent_loop.rs):每次工具调用都刷,全量参数打印开销大,tracing 在未启用级别时不评估字段。
5. LoadTaskMessages 3 条日志 info→debug(load_task_messages.rs):每次前端 trigger 都刷,一次 3 条。
6. 旧结果诊断日志 info→debug(execution.rs):每条消息首次 agent 迭代都触发。
7. pending subagents 日志 info→debug(processor.rs):子代理运行期高频率重复触发。
8. Updating current_session_id 仅变化时打(ws.rs):old==new 时每条消息都刷,无信息量。
编译通过,测试全绿。
2026-08-15 23:10:39 +08:00
oudecheng
fc3a95b152 feat: 异步子代理 v8 实现与 /stop 取消流程修复
后端核心实现:
- 新增 wait_coordinator:释放/重获取 serial_lock 的 in-tool waiting 模式,替代旧的 break-exit 方案
- 新增 wait_for_subagents 工具:select! 等待子代理完成/用户消息/超时,支持 try_drain 批量消费
- task 工具异步 spawn 路径:CancellationToken 注册表 + RAII guard + Semaphore 并发限流
- process exit 安全检查:pending 子代理存在时抑制 ExecutionCompleted
- 崩溃恢复:启动时标记 running->interrupted,history 加载时对账占位

/stop 取消流程修复:
- wait_coordinator select! 添加 cancel 分支,完整清理状态
- ToolContext 注入 cancel_rx(watch::Receiver clone)
- agent_loop 工具执行 select! 对 wait 工具跳过竞速,防止 drop coordinator 清理逻辑
- 子代理完成状态通过 execution_completed metadata 传播

存储层:
- pending_subagents 表 + 条件 UPDATE
- mark_all_running_as_interrupted 崩溃恢复
2026-08-13 22:12:20 +08:00
oudecheng
e0313ab8f3 fix: 增强 panic 安全与计算器健壮性
- agent_loop/processor: catch_unwind 隔离 panic,防止消息静默丢失
- calculator: 拒绝 NaN/Infinity 输入,修复阶乘溢出(上限 34),拒绝非有限表达式结果
- message: 修复 sanitize 两阶段删除索引未排序导致的越界 panic
- utils: 新增 panic_payload_message 提取可读 panic 消息
- .gitignore: 忽略 artifacts/ 测试产物目录
2026-08-13 08:38:36 +08:00
oudecheng
29060315a3 feat(observability): 端到端可观测性整改,修复 trace_id 断链与指标配对
- 传播 trace_id:BusToolCallEmitter/SubAgentEmitter/processor 全链路设置

- AgentEnd 配对:补发 5 个 cancel/defensive 路径,闭合 AgentStart 指标

- LLM 计时修正:attempt_start 移入 retry 循环,排除退避等待时间

- /metrics auth:非 loopback 部署时纳入 Bearer token 校验

- recorder 复用:OnceLock 缓存 PrometheusHandle,热重启后不再返回 503

- 结构化日志:新增 tracing_ctx + JSON 日志格式支持
2026-08-12 08:26:42 +08:00
oudecheng
bf8c227634 refactor: 迁移 parking_lot 锁并优化阻塞 IO 与内存管理
## 锁迁移:std::sync → parking_lot
消除锁中毒(poison)导致的级联崩溃风险。parking_lot 锁不会中毒,
且性能更优。迁移覆盖全部生产代码:
- experts/mod.rs: 4 RwLock + 13 expect
- skills/mod.rs: 1 RwLock + 11 expect
- tools/registry.rs: 1 RwLock + 2 expect
- gateway/model_selection.rs: 1 RwLock + 2 expect
- tools/task/repository.rs: 1 RwLock + 4 unwrap
- tools/task/runtime.rs: 2 RwLock + 17 expect
- gateway/session.rs + task/runtime.rs: stream_message_id Mutex
- gateway/processor.rs: description_generation_in_flight Mutex
- command/handler.rs + help.rs: metadata Mutex(公开 API)
- mcp/client.rs: stderr_lines Mutex

测试代码中的 std::sync::Mutex(串行化锁 + TestObserver)有意保留,
已通过 unwrap_or_else(|err| err.into_inner()) 做中毒恢复。

## P1: 阻塞 IO 迁移到 spawn_blocking
将 3 处阻塞 async worker 的操作迁移到 blocking 线程池:
- file_read.rs: read_to_string + 行处理 + base64 编码整体包入 spawn_blocking
- agent_loop.rs: 新增 preencode_images_for_request 两阶段预编码
  (顺序分配预算 → 并行 spawn_blocking 编码),build_llm_request 改为 async
- wechat.rs: media_to_send_content 改为 async,std::fs::read 用 spawn_blocking 包裹

## P2: session_history topic_histories 内存上限
新增 MAX_CACHED_TOPICS=32 上限和 evict_inactive_if_needed 方法。
超限时驱逐非活跃 topic(不在 chat_topic_ids、不在 compression_in_flight、
serial_lock 未被持有)。活跃 topic 永不误驱逐。
remove_history 同步清理 topic_serial_locks,防止无限增长。

## P3: 减少 panic 面
agent_loop.rs retry 循环的 response.expect(...) 改为 ok_or_else(...)?
返回 AgentError::Other,逻辑 bug 不再导致整个 agent 崩溃。

## 对抗性审查修复
- preencode_images_for_request: 用 seen HashSet 去重,防止同 path 重复
  编码导致 HashMap entry 覆盖(NoBudget 覆盖 Encoded 等)
- evict_inactive_if_needed: 检查 topic_serial_lock.try_lock(),防止驱逐
  正在 agent 处理中的 topic(original_topic_id 不在 chat_topic_ids 但
  agent 仍持锁)
- remove_history: 清理 topic_serial_locks

## 验证
- cargo check: 通过(仅既有 lifetime 警告)
- cargo test: 559 passed / 3 failed(均为环境/sandbox 权限问题,与本次改动无关)
2026-08-06 08:18:04 +08:00
oudecheng
81fbee4878 feat(storage): 历史压缩保留原消息,前端展示完整对话、LLM 用压缩摘要
将压缩流程从物理删除原消息改为标记位 is_compacted 分离两个视图:
- LLM 视角(load_messages_for_topic):只看 is_compacted=0 的压缩摘要+新消息
- UI 视角(load_messages_for_topic_full):看原消息(含 is_compacted=1)+新消息,排除摘要

新增 compact_topic_history:不删除原消息,仅打标记+插入摘要,
同事务内删除旧摘要避免累积。修复 token 统计因压缩丢失 usage 的问题。
2026-08-05 12:46:43 +08:00
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
oudecheng
cda14360af chore: 建立工程化基线(rustfmt + clippy + CI + eslint + prettier)
配置:
- rustfmt.toml: 固化 max_width=100 / 4 空格缩进,cargo fmt 全量格式化
- Cargo.toml: 配置 [lints.rust] 与 [lints.clippy] 渐进式规则
- .github/workflows/ci.yml: Rust(fmt+clippy+test) + 前端(eslint+tsc+test) 双平台 CI
- Makefile: 新增 check/fmt/fix 目标,clippy 对齐 --all-targets --all-features
- web: eslint flat config + prettier 配置 + package.json 脚本与依赖
- src/main.rs: loop→while 修复 clippy::never_loop

对抗性审查发现并修复:
- eslint 缺 caughtErrorsIgnorePattern 导致 catch(_) 误报为 error
- 前端 lint 未接入 CI,现已补上 Lint 步骤
- Makefile 与 CI 的 clippy flags 不一致,已对齐
2026-08-03 23:24:02 +08:00
oudecheng
2a5a0277c0 feat(web): 添加话题重命名功能
新增 RenameTopic 命令与 TopicRenamed 协议消息,复用存储层已有的
update_topic_title 方法。后端响应携带刷新后的完整 topic 列表,
前端零额外往返即可同步侧边栏。

前端 TopicList 侧边栏增加内联编辑入口:悬停显示铅笔图标,点击进入
编辑模式,Enter 提交 / Esc 取消 / blur 取消;通过 onMouseDown
preventDefault 防止按钮点击时 input 提前失焦。

包含 5 个单元测试覆盖成功、空标题、不存在、标题未变跳过写入、
can_handle 等场景。
2026-08-03 22:10:25 +08:00
oudecheng
b042b45ac7 fix: 话题隔离 - topic_id 全程显式传递,修复消息错投与并发阻塞
问题:WS 端一个话题执行中时新建另一话题发消息,新会话无响应
(串行锁按 chat_id 阻塞),且首个话题完成后用户消息错误出现在
旧话题而非新话题(执行路径多次从共享 UI 状态读取 topic_id 产生竞态)。

核心修复(第一性原则):
执行上下文应在消息接收时一次性捕获,全程显式传递,不从共享可变
状态重复读取。

1. processor.rs: process_one 入口捕获 current_topic,传入 handle_message
   和 set_agent_cancel_token
2. session_message_service.rs: handle_message 签名加 topic_id 参数,
   透传给 MessageExecutionRequest
3. execution.rs: MessageExecutionRequest 加 topic_id 字段;
   - 串行锁键改用 topic_id(不同 topic 并发,同 topic 串行)
   - original_topic_id 优先用传入值,消除锁等待期间 topic 切换竞态
   - append_persisted_message 调用传入 original_topic_id
   - create_agent 调用传入 original_topic_id
4. session.rs: append_persisted_message 加 explicit_topic_id 参数;
   create_agent/create_agent_with_provider_config 加 explicit_topic_id;
   set_cancel_receiver/set_agent_cancel_token 加 topic_id 参数;
   pending_cancel_tokens 查找改为优先 topic_id(避免并发 topic 执行时
   cancel token 互相覆盖)

对抗性审查补丁:
- append_persisted_message: 仅当写入 topic 匹配当前活跃 topic 时才更新
  内存历史,避免旧 topic 的排队消息污染已切换到的新 topic 内存历史
- prepare_and_execute_scheduled_task: 锁前一次性捕获 topic_id,锁后
  复用同一值作为 original_topic_id,保证锁键与写入目标一致

已验证:cargo check 通过,gateway 模块 48 个测试通过(1 个预存在的
prompt 模板测试失败,与本次修改无关)。
2026-07-28 14:19:20 +08:00
oudecheng
7652bb16e2 refactor: get_current/save_topic 直读 DB 加载消息,移除 SessionManager 依赖
get_current.rs 和 save_topic.rs 改为直读 DB(load_messages_for_topic),不依赖 SessionManager 内存,重启后也能正确获取历史。

mod.rs: 删除 get_messages_from_session 辅助函数。

processor.rs/ws.rs: 移除 with_session_manager 调用。
2026-07-07 14:13:31 +08:00
oudecheng
4329cfbbe9 feat: 统一路径显示格式,确保跨平台兼容性;重构系统提示词提供者构建逻辑 2026-07-07 09:19:58 +08:00
oudecheng
994db87f11 feat: 新增 ExecutionCompleted 信号修复发送按钮状态
- 后端 OutboundEventKind/WsOutbound 新增 ExecutionCompleted 变体
- processor 在 handle_message 完成后发送该信号
- 飞书/微信通道过滤该信号(不发送)
- 前端 useChat 移除 stream_delta/assistant_response 的 isLoading=false
- 改由 execution_completed 事件统一设置 isLoading=false,确保智能体迭代期间按钮保持停止态
2026-07-03 19:32:14 +08:00
oudecheng
edc975e6d0 feat(command): 优化 StopExecution 命令按话题取消逻辑
- StopExecutionCommandHandler 新增 SessionManager 依赖
- 优先使用 ctx.topic_id,若无则从 SessionManager 获取当前话题
- 增加获取话题过程中错误处理和日志打印
- 更新命令处理器构造参数,传入 SessionManager
- 在命令路由和 WebSocket 注册时同步修改 StopExecutionCommandHandler 创建方式
2026-06-18 17:17:26 +08:00
oudecheng
6f8c4a7ce8 feat: 更新 load_messages_for_topic 方法,支持按 session_id 过滤消息 2026-06-12 19:05:06 +08:00
oudecheng
4866ea9538 fix: todo_write 持久化从 finalize_result 移到 BusToolCallEmitter,即时触发
之前持久化挂在 agent 全部完成后,长任务永远等不到。
现在每个 todo_write 工具调用完成时立即持久化到 SQLite。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 16:58:05 +08:00
eeea7d44d0 feat: 添加 topic_id 支持,确保消息按话题隔离 2026-06-07 17:49:22 +08:00
3a623cc8a3 fix: 修复话题描述更新逻辑的竞态条件和语义错误,前端自动刷新描述
- topic_description.rs: LLM 返回空字符串时返回 Err 而非 Ok(""),防止空值写回 DB 触发循环生成
- processor.rs: 添加 Arc<Mutex<HashSet>> 生成中守卫防止重复触发,改用 DB 中真正第一条用户消息生成描述
- useChat.ts: assistant_response 时检测当前话题描述为空则递增刷新信号
- App.tsx: 监听刷新信号,500ms 防抖后自动发送 list_topics 获取新描述
2026-06-07 16:52:44 +08:00
b5e2886068 feat: 添加删除话题功能,包括命令处理器和前端交互 2026-06-07 14:09:14 +08:00
oudecheng
1d4ebb27a7 feat: 更新 StopExecution 命令和 CancelManager,支持按话题取消 Agent 执行 2026-06-03 18:13:15 +08:00
oudecheng
1b571e943f feat: 添加停止当前执行的 Agent 功能,支持通过 /stop 命令取消执行 2026-06-03 16:49:29 +08:00
oudecheng
eebfe0faa5 feat: 增强错误处理和日志记录,优雅处理通道关闭情况 2026-06-02 15:23:50 +08:00
oudecheng
06756a4816 fix: 修复消息持久化缺失 topic 关联和 assistant 文本丢失
- PersistingEmittedMessageHandler 新增 topic_id 参数,使用 append_message_with_topic 替代 append_message
- agent_loop 的所有退出路径中为最终 assistant 文本添加 emit_live_tool_call_message
- 更新 finalize_result filter,live_emitter 存在时抑制所有消息的 post-loop 广播

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 18:09:00 +08:00
oudecheng
d0051baa07 refactor: 消息持久化从批量改为实时逐条,通过装饰器模式实现
- 新增 PersistingEmittedMessageHandler 装饰器,在 emitter 广播前逐条落库
- processor 和 task/runtime 使用装饰器包裹 emitter,替代 post-loop 批量写入
- 移除 session_history 中的批量 DB 写入,仅保留内存历史更新
- execution 中跳过已由 live emitter 实时广播的工具消息,避免重复
- 前端支持运行中 task 工具卡片"查看实时进度"跳转子智能体视图

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 16:47:57 +08:00
oudecheng
5e5de7ce9f refactor: 移除 show_tool_results 开关,始终实时推送工具调用消息
简化工具消息推送逻辑,去掉条件判断,让所有工具消息(含结果)
直接通过 emit_live_tool_call_message 实时发送给用户。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 18:52:40 +08:00
oudecheng
542e11d0b3 refactor: 将 Session 命令重构为 Topic 命令
- 新增 LoadTopic 命令处理器,替代 LoadSession
- 新增 SwitchTopic 命令处理器,替代 SwitchSession
- 删除 LoadSession 和 SwitchSession 处理器
- 更新 Command 枚举:LoadSession -> LoadTopic, SwitchSession -> SwitchTopic
- 同步更新前端协议类型定义
- 调整适配器和网关代码以适应新命令

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 16:01:07 +08:00
0732b31e6b feat: 添加主题描述生成和更新功能,优化会话信息展示 2026-05-24 08:32:34 +08:00
oudecheng
49475783a2 feat: 添加子智能体支持到保存话题和会话功能,优化数据持久化 2026-05-20 17:52:46 +08:00
oudecheng
90228a4d49 feat: 更新 GetCurrentSessionCommandHandler,添加系统提示词提供者支持并优化令牌估算逻辑 2026-05-19 18:29:32 +08:00
oudecheng
2d5b6168cc feat: 添加会话管理器支持到 GetCurrentSessionCommandHandler,并重构从会话获取消息的逻辑 2026-05-19 17:42:47 +08:00
oudecheng
cd97ac0f57 feat: 更新 save_topic 处理器以支持从会话获取历史消息,并在命令处理器中配置会话管理器 2026-05-19 17:11:23 +08:00
831832664d feat: 重构会话管理逻辑,添加获取当前话题的方法,简化命令处理中的会话获取逻辑 2026-05-16 20:19:49 +08:00
3591822145 feat: add /help command to display all supported commands
- Implemented HelpCommandHandler to handle the /help command.
- Added CommandMetadata struct to store command metadata.
- Registered new command handlers for GetCurrentSession, ListSessions, LoadSession, and SwitchSession.
- Updated existing command handlers to provide metadata for help command.
- Removed deprecated SessionQueryCommandHandler.
- Added new command handlers for listing sessions and loading sessions.
2026-05-16 19:48:39 +08:00
20f32a3f96 feat: 添加保存话题功能,支持将当前话题内容保存为 Markdown 文件 2026-05-16 19:33:42 +08:00
oudecheng
8edc7ef905 feat: 添加当前话题获取功能,优化命令上下文处理 2026-05-15 18:42:26 +08:00
oudecheng
34938f57b8 feat: 添加 SessionManager 支持到 SessionCommandHandler,优化会话管理 2026-05-15 16:51:06 +08:00
oudecheng
2e13f6932c feat: Enhance session management with topic support
- Added topic management capabilities, allowing users to create, switch, and query topics within sessions.
- Updated command structure to include new commands: SwitchSession and GetCurrentSession.
- Introduced TopicRecord for managing topic data in the storage layer.
- Modified session handlers to accommodate topic operations, including listing and loading topics.
- Enhanced database schema to support topics, including new tables and relationships.
- Updated input adapters to recognize new commands and handle topic-related actions.
- Improved logging for session and topic operations to aid in debugging and monitoring.
2026-05-15 15:01:58 +08:00
oudecheng
025c0b5d7f feat: 添加 session_id 支持到 OutboundMessage,优化会话管理 2026-05-15 10:00:17 +08:00
530bea518d feat: 优化会话列表消息格式,添加会话切换提示 2026-05-14 23:45:52 +08:00
e005d06a9b feat: 添加会话管理命令,支持列出和加载会话功能 2026-05-14 23:35:34 +08:00
5eb9a26843 feat: 添加会话查询命令处理器,支持列出和加载会话功能 2026-05-14 23:27:23 +08:00
b77fc93d71 Refactor command handling and input adapters
- Removed the `format_session_list` function and related session handling from the client module.
- Simplified command output in the client by removing session-related commands.
- Introduced `ChannelInputAdapter` for parsing channel commands like `/new` and `/save`.
- Updated WebSocket handling to process commands via the new command system.
- Removed deprecated in-chat command handling from the gateway.
- Adjusted tests to reflect changes in command serialization and session handling.
- Enhanced session cleanup and job scheduling in the configuration module.
2026-05-14 22:23:02 +08:00
oudecheng
23b7497b12 feat: 更新 save_session 处理器,使用组合系统提示词提供者;移除 LLMProviderConfig 依赖 2026-05-14 16:07:49 +08:00
oudecheng
4181253b17 feat: 更新文件路径解析逻辑,自动保存会话到用户主目录下的 .picobot/sessions/ 目录;修改 InboundProcessor 结构体字段命名 2026-05-14 10:42:35 +08:00
oudecheng
102a4a63c5 feat: 更新 /save 命令,支持保存全部消息到指定路径;修改命令处理逻辑以包含新参数 2026-05-14 10:07:58 +08:00
b17ddd7556 feat: 更新 InChatCommandHandler 接口,添加会话管理器参数;修改命令路由和保存会话逻辑以支持会话管理 2026-05-13 23:11:02 +08:00
08172dcf9c feat: 实现 InChat 命令处理器和路由器,支持聊天中直接输入的命令;添加保存会话功能 2026-05-13 22:40:41 +08:00