571 Commits

Author SHA1 Message Date
oudecheng
27160ef560 fix(web): 回到顶部改用 rAF 自驱动动画,修复消息多时平滑滚动被 virtualizer 纠正写入打断停在半路 2026-08-17 16:41:01 +08:00
oudecheng
af344b7087 perf(mcp): 增加 tool 调用全链路往返耗时 debug 日志
记录 roundtrip_ms(含 stdio 传输 + server 派发 + 工具执行 + 回传),
与 server 侧 duration_ms 对比可定位慢在哪一段。
2026-08-17 15:52:34 +08:00
oudecheng
8a4799656c chore: 升级版本号至 0.4.2 并更新 CHANGELOG 2026-08-17 09:59:56 +08:00
oudecheng
5e2bdaf757 perf(web): 子代理 stream_delta rAF 批处理 + 消息槽 memo 化 + base64 分块解码
- useSubAgentView 镜像主视图:delta 累加到 ref,rAF 批量一次 setState,避免逐 token 重渲染
- 所有非 delta 消息处理前同步落盘 pending delta,保证顺序与内容完整性
- MessageList 消息 ID 映射 useMemo,稳定回调引用减少重渲染
- MessageBubble base64 下载改分块解码(32K),大附件峰值内存从数百 MB 降为单块级
2026-08-17 09:55:11 +08:00
oudecheng
52f858bfb4 perf(tools): bash 输出增量匹配消除 O(n^2) + 缓冲上限,http_request 复用 Client + 流式限长
- bash 增量窗口扫描 pending 短语,不再全量重扫;输出缓冲设上限(头尾保留)
- 修复 wait 分支 stdout_buf 重复锁导致的 tokio Mutex 自死锁(此前正常命令挂到超时)
- shell_session 沿用 cap_output_buffer 上限并修复截断后偏移兜底
- http_request 复用长生命周期 Client;响应体改为流式限长读取,防超大响应耗尽内存
2026-08-17 09:55:03 +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
f2fc5e97ac feat(security): 部署安全加固(排除 token 项)
- 安全响应头中间件:nosniff / X-Frame-Options DENY / Referrer-Policy / CSP / Permissions-Policy,最外层覆盖所有响应
- loopback CORS 由 mirror_request 改为 loopback origin 白名单(原实现会回显任意 Origin,允许恶意网页跨域读取本地网关)
- 新增 gateway.allowed_origins 配置:非 loopback 部署可收紧 CORS,未配置时保持 permissive 并打 warn
- loopback 免认证模式强制 Host 头为 loopback,阻断 DNS rebinding
- loopback 免认证模式 WS Origin 必须为 loopback 来源,防跨站 WebSocket 劫持(CSWSH)
- WS 消息/帧大小显式上限 80MiB/16MiB(顺带修复 50MB 附件 base64 超 tungstenite 默认 64MB 上限的问题)
- HTTP 请求体显式限制 2MB(DefaultBodyLimit)
- 前端 HTTPS 页面自动使用 wss://,避免混合内容拦截 WebSocket
- 新增 10 个安全相关单元测试(host/origin loopback 判定、WS Origin 校验)
2026-08-17 06:47:35 +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
3faefc74b9 fix(web): npm audit fix 修复 4 个高危依赖漏洞(vite/postcss/undici/nanoid) 2026-08-16 19:43:27 +08:00
oudecheng
78e2ff7180 fix(deps): 升级 quinn-proto 0.11.14 -> 0.11.16 修复 RUSTSEC-2026-0185 远程内存耗尽漏洞 2026-08-16 19:43:25 +08:00
oudecheng
692cc93075 fix(ws): 历史加载时对账 task running 占位,修复刷新/切话题后子代理卡片永远显示运行中
DB messages 表的 task tool_result 固化在 spawn 时刻的 running 状态,完成信号只更新
pending_subagents 表;send_topic_history 原样发送导致刷新后卡片退回黄色运行中。
新增 reconcile_running_in_messages:发送前按 pending_subagents 实际状态替换发送副本,
复用 session.rs 提取/格式化函数(改为 pub(crate)),不落库且幂等,无占位时零查询。
2026-08-16 17:27:55 +08:00
oudecheng
867b7df409 chore: 升级版本号至 0.4.1 并更新 CHANGELOG 2026-08-16 14:04:52 +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
ca7dcabbde fix(protocol): TopicTokenStats 补齐 cached_tokens 字段,修复前端缓存占比恒为 0
根因:command 层与 protocol 层存在两个同名 TopicTokenStats 结构体,websocket 适配器做 JSON 往返时 protocol 版缺 cached_tokens 字段,serde 反序列化静默丢弃。后端解析/存库/聚合均正常(DB 实测 8832/13916 命中),仅传输层断链。补字段并加往返回归测试固化两结构体对齐不变量。
2026-08-15 21:02:29 +08:00
oudecheng
011b23b54e feat(provider): 缓存命中诊断日志与两种 usage 缓存格式解析测试
排查平台有缓存命中但前端占比为 0 的问题:set_usage/非流式/回退三处输出 cache diagnostics 日志;新增 DeepSeek 顶层与 OpenAI 嵌套缓存字段解析回归测试
2026-08-15 20:17:30 +08:00
oudecheng
b26a2c2512 feat(token): 新增缓存占比统计,聚合查询收敛到共享列清单
- 解析: OpenAIUsage 支持 DeepSeek prompt_cache_hit_tokens + OpenAI prompt_tokens_details.cached_tokens fallback;Anthropic 接入 cache_read_input_tokens

- 存储: messages 表新增 cached_tokens 列(幂等迁移),贯穿 INSERT/SELECT/聚合

- 解耦加固: 抽取 MESSAGE_LOAD_COLUMNS 收敛 6 处消息加载 SELECT;抽取 USAGE_SUM_COLUMNS + read_usage_sum_row 收敛 topic/session 两份重复 SUM 聚合

- 协议: SessionTokenStats/TopicTokenStats 新增 cached_tokens 字段

- 前端: 面板新增缓存命中行 + 缓存命中率进度条(命中率越高越绿,与 ctx 占用方向相反)
2026-08-15 19:21:51 +08:00
oudecheng
82b6a882a2 test(scheduler): 调度器非阻塞派发与并发容量回归测试
- 慢执行器(400ms sleep)双任务:process_tick 必须立即返回且两任务并发完成(串行需 >=800ms,断言 <700ms)

- worker_queue_capacity=1:槽位耗尽时多余到期任务被推迟(保持 Scheduled),槽位释放后下个 tick 正常派发

- 执行完成后状态机验证:回到 Scheduled、status=ok、next_fire_at 推进
2026-08-15 19:04:54 +08:00
oudecheng
9b8c64bd21 refactor(scheduler): 任务执行移出 tick 循环,worker_queue_capacity 并发约束生效
原 process_tick 内联 await execute_job:长耗时 agent 任务(可达数分钟)会串行阻塞整个调度循环,拖后所有其他 job 的触发;worker_queue_capacity 配置项从未被使用。

- 到期 job 的执行与事后状态写入移入 tokio::spawn 后台任务,tick 循环只做派发

- 新增 worker_semaphore(容量=worker_queue_capacity):槽位耗尽时 job 保持 Scheduled 留待下个 tick,形成有界背压

- job 派发前置为 Running 状态,is_due 要求 Scheduled,天然防止重复派发

- after_execution 状态推进失败时回退为 Scheduled,避免 job 永久卡在 Running

- execute_job 拆分为 execute_job_inner(不依赖 &self,可移入后台任务)
2026-08-15 18:50:40 +08:00
oudecheng
4b93c84447 test(gateway): 定时任务 topic 补齐与消息送达回归测试
- 新增捕获请求的 mock OpenAI server,直接断言任务 prompt 进入 LLM 输入

- 静默任务按生产默认 fresh_session=true 连续执行两轮,验证清空-重建时序下 prompt 仍送达、topic 自动创建并持久化、系统提示词含送达提示

- ensure_topic_for_chat 幂等性与全新 chat 默认 topic 创建测试

- append_persisted_message 无 topic 回退 chat_id 键内存历史测试

- SessionManager/SessionLifecycleService 暴露 get_scheduler_session 供测试断言
2026-08-15 18:17:29 +08:00
oudecheng
cbe2ff1339 feat(gateway): 静默定时任务增加主动送达提示,避免结果静默丢失
silent_agent_task 的最终响应发往 scheduler/ 虚拟会话、被出站分发器跳过,成功时用户收不到任何消息,只能依赖 agent 主动调用 send_session_message。

- 定时任务系统提示词仅对 scheduler/ 虚拟会话追加送达提示(避免普通 agent_task 重复发送)

- scheduler_manage 工具描述新增 Silent Mode Delivery 指引:用户期望收到结果时,prompt 必须要求用 send_session_message 交付
2026-08-15 18:17:07 +08:00
oudecheng
508806a408 fix(gateway): 定时任务执行前自动补齐 topic,修复 agent 空历史执行
scheduler/ 虚拟会话从不经用户消息分配 topic,导致定时任务的系统提示词与任务 prompt 只落库、不进内存历史(append_persisted_message 在 topic=None 时跳过内存写入),agent 以空历史执行,任务实际未运行、消息无法送达会话。

- Session 新增 ensure_topic_for_chat:内存无 topic 时从 DB 恢复最近活跃 topic,无则自动创建(先确保持久会话以规避外键约束)

- prepare_and_execute_scheduled_task 捕获 topic 前调用 ensure,保证 original_topic_id 恒为 Some

- append_persisted_message 无 topic 时回退到 chat_id 键内存历史,兜底所有无 topic 路径
2026-08-15 18:16:50 +08:00
oudecheng
73c25e5a20 feat(web): Task 卡片差异显示子代理模型名 + 子代理完成状态转发修复
- Task/tool 卡片头部在子代理模型与主代理不同(model 或 provider 任一不同)时显示模型徽章
- useChat 放行带 subagent_task_id 的 execution_completed 消息,更新卡片 running→completed 状态
2026-08-15 15:35:32 +08:00
oudecheng
53e2fb6dc6 feat(web): per-topic 输入草稿记忆(切换暂存/恢复 + localStorage 持久化 + 删除清理)
- 文本草稿 debounce 持久化到 localStorage(key 按 topicId),附件仅存内存
- 切换话题时暂存当前草稿并恢复目标话题草稿,组件卸载时补齐落盘
- 删除话题时同步清除其持久化草稿,避免孤儿 key
2026-08-15 15:35:07 +08:00
oudecheng
8f59b6b93a feat(web): 话题级模型选择前端(ModelSelector topicId 化 + 竞态防护)+ 专家系统开关隐藏
- ModelSelector 支持按 topicId 读写话题级选择(topic 优先,session 兜底)
- 快速切换话题时用递增令牌丢弃过期响应,防止乱序覆盖
- ChatContainer 透传 topicId,向后端双写新话题默认模型
- ExpertSelector 依据后端 experts_system_enabled 隐藏选择器并清除已选专家
2026-08-15 15:34:38 +08:00
oudecheng
dc693fa80b feat(model): 主代理/子代理模型解析链 topic>session>expert>config + TaskToolResult 附带实际模型
- 主代理解析链新增 topic 级选择(最高优先级),session 级首命中时物化固化为话题选择
- 子代理解析链共享 helper:def frontmatter > 话题级 > session 级 > 全局基础配置
- TaskToolResult 携带子代理实际使用的 provider/model,供前端差异展示
2026-08-15 15:34:18 +08:00
oudecheng
414105d419 feat(model): 话题级模型选择持久化与 API(topics 表加 provider/model 列 + 双写内存缓存)
- topics 表迁移新增 provider/model 列,记录话题级显式模型选择
- storage 层新增 update_topic_model / list_topic_model_selections
- 新增 POST /api/topic/select-model 与 GET /api/topic/selected-model
- 双写 key 取 topic 行自带 session_id(不信任请求体,防污染其他会话)
- 清除时同步清 session 级选择,避免'重置为默认'被物化逻辑重新覆盖
2026-08-15 15:33:58 +08:00
oudecheng
9e503f2672 feat(web): 工具卡片统一格式,子智能体显示 '工具名 · 任务描述' 并移除下方徽章与时间 2026-08-15 09:32:16 +08:00
oudecheng
f705536fb1 feat(web): 通道/会话切换移至设置页 ConnectionTab,修复通道失效回退;连接状态上移 Logo 行并支持窄侧栏 compact 降级 2026-08-15 08:38:12 +08:00
oudecheng
eaee29841d feat(web): 对齐 deepseek-harness 设计语言,重构前端视觉与三栏布局
- 设计 token 重映射为 DeepSeek 调色板(深浅双主题),正文改无衬线字体栈,全面去霓虹化
- 移除顶部 Header,控件迁入左栏(Logo/连接/通道/会话/tabs/底部操作区),左右栏支持拖拽调宽并持久化,折叠为图标 rail
- 对话区对齐 DeepSeek 聊天风:hero/docked 状态机、736px 居中列、用户右对齐柔和气泡、助手无气泡平铺、composer 卡片与反差发送键;子智能体点击导航完整保留
- 全功能区同步换肤:侧栏列表、右栏面板、ConfigPage、弹窗、选择器等
- fix: 修复 virtual-core 3.17.x 陈旧行高导致消息行重叠(宽度变化/滚动停止后强制 resizeItem 重测)
- fix: 修复 ConfigPage/Modal 引用不存在的 fadeIn/scaleIn keyframes 致入场动画失效
2026-08-14 19:15:45 +08:00
oudecheng
4c21add43b chore: 同步 Cargo.lock 版本号至 0.4.0 2026-08-14 16:39:11 +08:00
oudecheng
2dead61697 chore: 升级版本号至 0.4.0 并更新 CHANGELOG 2026-08-13 23:20:44 +08:00
oudecheng
f05f09b636 docs: 异步子代理设计文档
记录 v8 设计方案的三个核心不变量、wait 模式、取消机制与崩溃恢复策略
2026-08-13 22:13:00 +08:00
oudecheng
daf973a7dc fix(web): 子代理状态显示与渲染崩溃修复
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 字段
2026-08-13 22:12:43 +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
f65fb0167f chore: 忽略 artifacts 构建产物目录 2026-08-12 10:27:12 +08:00
oudecheng
a9ce308c05 fix(web): 移除 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 重置机制
2026-08-12 09:16:38 +08:00
oudecheng
3910bc324b chore: 升级版本号至 0.3.5 并更新 CHANGELOG 2026-08-12 08:39:40 +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
7cb170e0c2 fix(gateway): 压缩期间释放 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 完全并行不受影响。
2026-08-12 08:24:46 +08:00
oudecheng
77a0eac2c8 fix(mcp): 修复前端空输入重置为不超时,增加超时路径单元测试
P3: 清空输入框时回退到默认值 300 而非 0;新增两个 tokio 测试覆盖有超时和无超时(error pass-through)路径
2026-08-11 23:07:00 +08:00
oudecheng
3e97ed903c feat(mcp): 为 MCP 工具调用增加超时保护,默认 5 分钟
在 McpToolWrapper 适配层用 tokio::time::timeout 包裹 call_tool,防止外部 MCP server 挂起导致 agent loop 无限阻塞。超时时间通过 config.mcp_tool_timeout_secs 配置(默认 300 秒,0=不超时),前端 McpTab 设置页提供输入框。
2026-08-11 21:53:07 +08:00
oudecheng
7de9a8a054 feat(web): 顶栏显示后端版本号
复用现有 /health 端点返回的 CARGO_PKG_VERSION,避免在 package.json 重复维护版本号;挂载时拉取一次,失败则不显示徽标。
2026-08-07 14:52:11 +08:00
oudecheng
f26ec49182 chore: 修复 release 构建的编译器警告
- 为 regex::Captures 补全显式生命周期标注
- 将仅用于 debug 日志的局部变量 (media_count/len/total) 用 cfg(debug_assertions) 条件化
- 为仅 debug 读取的 AnthropicProvider::llm_timeout_secs 字段添加 cfg_attr allow(dead_code)
2026-08-07 14:36:27 +08:00
oudecheng
da62905505 chore: 升级版本号至 0.3.3 并更新 CHANGELOG 2026-08-07 11:55:59 +08:00
oudecheng
79d099a3bc chore(compaction): 调整压缩阈值默认值
工程化压缩阈值 threshold_ratio: 0.7 → 0.5(50%)
LLM 压缩阈值 llm_compaction_threshold_ratio: 0.5 → 0.3(30%)

降低触发门槛使压缩更积极介入,减少上下文溢出风险。
同步更新相关注释、日志信息和前端 hint 文案。
2026-08-07 11:53:54 +08:00
oudecheng
a9429a5657 fix(web): 输入框/发送按钮状态按话题隔离,避免处理中仍可发送
将单一全局 isLoading 布尔值重构为按 topic_id 跟踪的 processingTopicIds
集合,isLoading 派生自当前选中话题是否在集合中。导航响应不再清空处理
状态,切换话题后切回原话题仍能正确禁用输入。重连时通过新增的
/api/executions 端点对账后端权威执行状态,修正断连期间丢失的
execution_completed 信号导致的状态漂移。
2026-08-07 11:45:47 +08:00
oudecheng
feeb9d9c18 chore: 降低 list_todos 日志级别为 debug
前端每次 todo_write 后自动刷新会触发 list_todos 命令,子代理多次更新待办时产生大量 INFO 日志噪音。将 handler 与 gateway 转发两处日志降级为 debug,默认不输出,需要排查时通过 RUST_LOG=debug 开启。
2026-08-07 09:01:33 +08:00
oudecheng
03be2ef5bc chore: remove optimization plan doc from repo 2026-08-07 08:34:39 +08:00
oudecheng
e3e32c725d style: 对存储模块应用 rustfmt 格式化 2026-08-07 08:34:30 +08:00