7 Commits

Author SHA1 Message Date
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
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
e3e32c725d style: 对存储模块应用 rustfmt 格式化 2026-08-07 08:34:30 +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
5eec77ae10 perf: 减少热路径无谓拷贝与重复正则编译,并跳过已完成迁移
- agent_loop::filter_images_by_age_and_count 改返回 Cow<[ChatMessage]>,
  无图片或无需过滤时零拷贝返回原切片引用,避免每次 LLM 调用都完整克隆消息列表
- anthropic::convert_image_url_to_anthropic 用 OnceLock 缓存 data URL 正则,
  避免每次图片转换都重新编译正则
- memory_scope_key 迁移用 PRAGMA user_version 记录已迁移版本,
  避免每次启动都执行全表 DELETE + UPDATE
2026-08-05 08:10:36 +08:00
oudecheng
2e4b1931a6 feat(tokens): 添加 topic 维度 token 消耗与上下文窗口占用统计
后端:
- openai provider 流式响应启用 stream_options.include_usage,从 SSE 末帧捕获 usage
- ChatMessage 新增 MessageUsage(prompt/completion/total/context_window_tokens)
- agent_loop 三处 LLM 调用点持久化 usage,含 context_window_tokens
- storage 新增 context_window_tokens 列及 migration,batch_session_token_stats 聚合查询
- last_prompt_tokens 查询过滤 prompt_tokens IS NOT NULL,跳过 error/cancel 消息
- build_topic_summaries 简化签名,context_window_tokens 从消息记录读取
- protocol 扩展 TopicTokenStats,按 session_id 聚合天然隔离子代理

前端:
- protocol.ts 新增 TopicTokenStats 类型
- useTopics 映射 token_stats 到 Topic
- TopicList 展示总 token 消耗与上下文占用百分比(绿/黄/红三色)

测试:outbound_dispatcher 4 个测试修复(drop(bus) 不关闭 bus,改用 abort)
2026-08-04 17:01:54 +08:00
oudecheng
c8660df14b refactor: 拆分 storage/mod.rs 与 ConfigPage.tsx (P2)
storage/mod.rs (2957 -> 1834 行):
- 抽出 tests.rs: 17 个测试函数
- 抽出 row_mapping.rs: 8 个 row<->record 映射与单记录查询函数
- 抽出 migrations.rs: 7 个 schema 迁移函数 (ensure_*_schema, has_column, add_column_if_missing)

ConfigPage.tsx (1568 -> 1235 行):
- 抽出 types.ts: 所有接口/类型定义
- 抽出 constants.ts: TABS, inputCls, selectCls, TIMEZONE_OPTIONS
- 抽出 ui.tsx: Field, Toggle, TagEditor, SectionCard, SourceEditor, MapEntryHeader
- 抽出 api/expert.ts: getSelectedExpert, selectExpert (经 ConfigPage 再导出保持兼容)

验证: cargo build, cargo test --lib storage:: 17/17, npm run build
对抗性检查: 8/8 通过 (无丢失/重复函数, 无循环依赖, 无未使用导入)
2026-07-07 18:36:23 +08:00