47 Commits

Author SHA1 Message Date
oudecheng
d3ee430aa9 test(web): MessageList 虚拟化的对抗性 smoke test
对抗性审查 commit 03d8840 的虚拟化实现,新增 5 个组件测试:

- 用例 1: 空消息渲染空状态
- 用例 2: 100 条消息不崩溃(虚拟化 smoke test)
- 用例 3: highlight 指向视口外消息不崩溃
- 用例 4: viewKey 切换不崩溃
- 用例 5: 流式 rerender 不崩溃

发现:jsdom 下 getBoundingClientRect 返回 0 + rAF 同步化,
virtualizer 测量后可见范围可能变空(textContent 不可靠)。
这是测试环境限制,不反映浏览器真实行为(浏览器 rAF 异步、
高度真实)。用例 5 聚焦不崩溃验证,内容正确性由真实布局保证。
2026-08-07 08:34:17 +08:00
oudecheng
2367d87db6 perf(web): 消息列表虚拟化,长对话不再卡顿
原实现 messages.map 渲染所有消息,500 条消息会产生 10000+ DOM
节点(每条 MessageBubble 含 ReactMarkdown 解析),导致首次渲染
卡顿、滚动掉帧、流式输出每 token 都全量 diff。

引入 @tanstack/react-virtual 实现虚拟化:
- 只渲染视口内 + overscan=6 条消息,DOM 节点数恒定
- measureElement 动态测量变高度消息(一行文本 vs 50 行代码块)
- estimateSize=120 提供初始估计,测量后自动校正
- Firefox 特殊处理 measureElement(getBoundingClientRect)

适配现有功能:
- 自动滚到底部:bottomRef.scrollIntoView 改为 virtualizer.scrollToIndex
- viewKey 滚动位置记忆:保留 scrollTop 保存/恢复逻辑
- highlightedMessageId:先 scrollToIndex 渲染目标项,rAF 后加 class
- newMessageCount:流式 delta 不计数(消息条数不变)
- space-y-6 改为每项 pb-6(虚拟化下相邻 margin 不生效)

性能对比(500 条消息):
- DOM 节点:10000+ → ~200(仅可见+overscan)
- 首次渲染:数百 ms → <16ms
- 流式 diff:全量列表 → 仅可见项
2026-08-07 08:34:07 +08:00
oudecheng
4e74d66a7c fix(web): 修复流式期间消息重渲染、WebSocket 无谓重连与新消息计数错误
- MessageBubble 用 React.memo 包裹,流式 delta 只追加到最后一条消息,
  其余消息引用不变可被 memo 跳过,避免 N-1 条历史消息无谓重渲染
- useWebSocket 用 useRef 存储回调最新引用,connect 不再依赖回调引用,
  避免调用方回调变化触发 disconnect+connect 重连
- MessageList 用 prevMessageCountRef 追踪消息条数变化,仅当真正新增
  消息条数时才累加 newMessageCount;流式 delta 不增加条数不再误计数,
  滑到底部按钮触发的清零路径与时序经审查覆盖各种边界场景
2026-08-05 08:10:44 +08:00
oudecheng
c724bbf864 chore(web): prettier 一次性格式化并在 CI 启用 format:check
对 47 个前端文件统一执行 npm run format,消除存量格式差异。
随后在 CI 与 Makefile check 中启用 format:check,确保后续提交强制遵守 prettier 风格。
2026-08-03 23:25:22 +08:00
oudecheng
649ea2998d feat(web): 集成 ModelSelector 实现主 agent 模型选择 UI
新建 ModelSelector 组件(参考 ExpertSelector 交互模式): 显示当前生效模型,下拉支持 provider/model 选择,草稿暂存+应用提交,重置为默认。

ChatContainer 用共享 flex 容器并排渲染 ExpertSelector 和 ModelSelector,ExpertSelector 简化外层 wrapper(去除冗余 padding/max-width)。

API 层: 新增 sessionSelectedModel 端点常量和 getSelectedModel 函数; types.ts 为 ModelOptionsResponse 添加 current 字段。

按钮语义: 已覆盖时显示 provider/model,未覆盖时显示 '默认 provider/model'。
2026-07-30 23:25:14 +08:00
oudecheng
0a8d21fe40 fix: 修复专家发现与前端选择多项问题
后端:
- split_frontmatter 兼容 CRLF/LF 行尾符,修复 Windows 下 EXPERT.md 解析失败
- Config::load_from 移除 fallback 到 cwd/config.json 的逻辑,避免静默加载项目目录配置导致 experts 字段缺失
- ExpertRuntime 新增 update_config 方法,save_config 时同步更新 ExpertRuntime 内部 config,sources 变更即时生效
- source_order 空数组不再兜底返回 [User, Project],尊重用户关闭所有源的意图
- from_config_with_cwd 增加诊断日志,输出 enabled/sources/cwd/discovered

前端:
- ExpertSelector 弹窗改为按钮上方居中展开
- 专家卡片 name 完整显示(break-all),路径显示在卡片底部
- "管理专家"入口仅在无专家时显示
- 每次打开下拉都重新拉取列表和选中状态
- 监听设置弹窗关闭事件刷新已选专家(处理已选专家被禁用的情况)
2026-07-08 14:53:30 +08:00
oudecheng
ffc1f79de4 refactor: 建立前端 API 客户端层,消除硬编码路径与重复 fetch
- 新增 web/src/api/ 目录(6 个文件):client.ts 基础设施 + 5 个领域模块
- 封装 18 处 fetch 调用为强类型函数,消除 17 处硬编码 /api/ 路径
- 统一 13 处重复的 fetch+json+错误处理模式
- 删除旧 web/src/components/Settings/api/expert.ts,合并到新 api/experts.ts
- ConfigPage.tsx 替换 15 处 fetch 调用,ExpertSelector.tsx 改用新 API
- 保持现有组件行为不变(静默失败仍静默,错误处理等价)
2026-07-08 10:03:34 +08:00
oudecheng
f8d5f0253a refactor: 清理 P1 类型债与 React key 债
- 消除 useChat.ts 中 13 处 (message as any).timestamp,改用已收窄变量的 .timestamp
- 给 ExecutionCancelled 接口补 timestamp?: number 字段,与后端对齐
- 修复 MessageInput 附件列表 key={index}: 给 FileAttachment 加 id 字段(crypto.randomUUID())
- 修复 ConfigPage TagEditor key={i} → key={t}(tag 值唯一)
- 修复 ConfigPage SourceEditor customPaths key={i} → key={p}(路径值唯一)
2026-07-07 17:53:53 +08:00
oudecheng
61c2fca2a7 feat: 对话框上方集成专家选择器,支持实时选择与系统提示词注入
- 新建 ExpertSelector 组件,加载时查询 session 选中状态,失败降级显示无专家

- 下拉面板含无专家/专家列表/管理专家入口,乐观更新+失败回滚保证一致性

- ChatContainer 在 MessageList 与 MessageInput 之间渲染 ExpertSelector

- MessageInput 接收 selectedExpert,选中时 placeholder 显示以专家身份对话

- App.tsx 传递 sessionId/onOpenSettings 给 ChatContainer,支持从对话框直达专家设置

- App.tsx 同时包含 subagent 导航 command 发送的连带修改
2026-07-06 18:08:19 +08:00
oudecheng
cb0d3d932d feat: TodoPanel 改为常驻右边栏并支持点击跳转
- TodoPanel 移除浮动定位与拖动逻辑,改为常驻右边栏
- 右边栏与左边栏对称的折叠/展开逻辑,localStorage 持久化
- 待办/记忆/技能三 Tab 切换
- 点击已完成 todo 滚动并高亮对应 tool 消息
- 修复 MessageBubble isMergedTool 分支缺失 data-message-id 导致跳转失效
- ChatContainer 移除 todoPanel prop
2026-07-03 19:32:46 +08:00
oudecheng
a40f57fb22 feat: 注册 save_topic 处理器并优化助手消息渲染逻辑 2026-06-25 14:10:04 +08:00
oudecheng
4efc8b51e7 feat(todo): 添加待办项关联的创建消息ID并支持消息高亮
- 在待办相关数据结构和存储中新增 created_by_message_id 字段
- 记录待办项创建时对应的消息ID,支持追溯来源
- 在前端待办列表项增加点击事件,点击后滚动并高亮对应消息
- 在消息列表组件中实现高亮动画及自动滚动功能
- 更新相关工具、协议和数据库查询,确保新字段正确传递和存储
- 增加 CSS 动画实现待办对应消息的高亮闪烁效果
- 优化前端状态管理,支持设置与获取高亮消息ID
2026-06-22 14:50:37 +08:00
oudecheng
9ea5849f22 refactor(task): 子智能体相关字段重命名及导航逻辑调整
- 将 runtime 中的 sub_session_id 字段重命名为 task_id,作为持久化的 scope_key
- 调整持久化 todo_write 结果使用 task_id 代替 session_id 作为 scope_key
- 重命名前端消息中的 subagentTaskId 为 navigateToTaskId,增强导航表达
- 修改 MessageBubble 组件中子智能体任务导航相关的字段名和条件判断
- 优化 useChat 中 task tool_call 消息的 navigateToTaskId 设置逻辑,确保正确导航孙智能体任务
- 移除无用的 getTopicId 辅助方法,简化消息处理逻辑
- 在协议类型定义中新增 navigateToTaskId 字段,明确导航用途与关系
2026-06-18 17:09:42 +08:00
oudecheng
e585ec71b1 refactor(todo): 统一子代理 scope_key 为全局唯一的 task_id
- 修改 list_todos 处理器,子代理使用 task_id 作为 scope_key,替代原先的 sub:{parent_session_id}:{task_id}
- 调整 todo_write 的 scope_key_from_context 函数,子/孙代理使用 task_id 隔离,避免与父代理污染
- 修正子任务消息的 task_id 传递逻辑,在 useChat hook 中为子代理视图的孙子任务回填正确的 task_id
- 清理 MessageBubble 组件中多余的 isSubAgent 变量声明
2026-06-18 16:44:54 +08:00
oudecheng
421714dfa3 style(TodoPanel): 优化待办面板动画和样式细节
- 新增待办卡片及条目动画效果,提升界面动感
- 添加待办分组折叠内容展开/收起过渡样式
- 优化按钮尺寸及颜色悬浮效果,提升交互体验
- 自动展开新待办项,空列表时自动收起
- 调整待办面板大小、圆角及阴影效果,增强视觉层次
- 改进待办标题栏排版及交互样式,支持拖动操作手感
- 为无待办状态提供占位展示及提示文字
- 优化待办分组标题样式及折叠箭头动画
- 改进待办条目列表项样式,支持悬浮高亮显示
- 移除消息气泡中的冗余子智能体标签显示内容
2026-06-18 16:15:08 +08:00
oudecheng
301506a3b1 feat(chat): 支持子智能体导航添加子智能体类型参数
- 扩展 enterSubAgentView 方法,新增 subagentType 可选参数
- 更新相关回调 onNavigateToSubAgent,添加 subagentType 参数支持
- 调整 MessageBubble 组件触发子智能体导航时传递 subagentType
- 优化 MessageList 组件显示新消息计数及底部导航按钮交互
- 美化底部浮动导航按钮样式,增加新消息数字提示和动画
- TodoPanel 添加状态点样式,消息内容排版更紧凑
- 维护滚动位置状态,改进滚动时新消息计数逻辑
2026-06-18 15:34:27 +08:00
oudecheng
8684ff9549 feat(chat): 实现多视图滚动位置保存与恢复功能
- 在 App 组件中新增 viewKey,用于标识当前视图
- 通过属性链传递 viewKey 至 MessageList 以区分不同滚动上下文
- MessageList 中新增滚动位置缓存机制,使用 Map 保存各视图的滚动状态
- 在视图切换时自动恢复对应滚动位置,提升用户体验
- 保持消息新增时的自动滚动行为,兼顾视图切换与消息更新场景
2026-06-18 15:02:25 +08:00
oudecheng
6962ea2eb1 feat(todo): 优化悬浮待办面板功能
- 将悬浮待办面板集成到聊天组件上方,避免重复渲染
- 调整状态样式配置,简化颜色和样式管理
- 实现待办面板位置拖拽功能,支持位置持久化保存
- 优化折叠与展开交互,改进分组标题和列表项显示样式
- 设计迷你和完整两种面板展现形态,提升界面灵活性
- 添加刷新按钮及自动展开待办新条目功能
- 精简和改进待办项展示,提高内容可读性和界面美观度
2026-06-18 14:25:41 +08:00
3630e62e18 style(chat): 优化消息气泡组件样式间距
- 移除消息气泡底部多余外边距,调整整体布局美观
- 为模型思考内容容器增加底部外边距,改善内容分隔
- 统一模型思考区域的外边距,提升视觉一致性
- 根据内容情况动态添加外边距,增强排版灵活性
2026-06-14 12:55:49 +08:00
b67848180b feat(stream): 添加子代理消息流增量处理功能
- 在 runtime 模块中新增 handle_stream_delta 方法,支持子代理消息流的增量和结束事件处理
- 为流消息新增 stream_message_id,用于标识和管理消息流状态
- 修改 ConversationContext 初始化,加入 stream_message_id 互斥锁字段
- 更新 web 端 Chat 组件,添加对流增量内容的条件渲染,避免空字符串渲染
- 在 useChat 钩子内增加对 stream_delta 和 stream_end 类型消息的识别和处理逻辑
- 实现流增量消息的累积更新,合并多次流增量内容和推理文本
- 处理流结束消息时的无操作逻辑,确保消息流完整性
- 对 assistant_response 消息进行替换更新,修正流消息的最终呈现内容
2026-06-14 12:51:26 +08:00
oudecheng
50d0b92336 feat: 添加详细工具视图和状态图标,支持放大查看功能 2026-06-12 16:49:20 +08:00
oudecheng
3c889caacf feat: 添加日志记录以持久化待办事项时的调试信息 2026-06-12 16:22:43 +08:00
oudecheng
f808bd09ea feat: 隐藏无实质内容的助手消息气泡以优化界面显示 2026-06-12 08:44:14 +08:00
oudecheng
4487f1a490 feat: 添加思考过程显示功能,允许用户选择是否展示助手的思考内容 2026-06-11 17:15:03 +08:00
oudecheng
6ff5907616 feat: 添加 reasoning_content 字段到多个消息结构,支持思考过程展示 2026-06-11 14:33:29 +08:00
oudecheng
0ce89a0e4e feat: 添加 reasoning_content 字段到多个消息结构,支持思考过程展示 2026-06-11 12:04:52 +08:00
oudecheng
d0741ef4fc feat: 优化话题选择逻辑,避免用户手动选择后自动切换;重构消息列表滚动逻辑,提升用户体验 2026-06-08 18:01:32 +08:00
oudecheng
3f9bb22097 feat: 添加 favicon.svg 文件并在 index.html 中引用 2026-06-08 14:43:47 +08:00
c0d4f65de4 feat: 更新数据库连接管理,使用连接池优化会话存储,添加新的错误处理 2026-06-07 21:35:47 +08:00
1f04c62d0d feat: 添加图片轻箱功能,支持点击图片预览和下载,优化附件展示逻辑 2026-06-07 18:47:17 +08:00
62ea6de3a7 feat: 更新时间戳处理逻辑,支持从消息中提取并格式化时间,同时为话题列表添加分页功能 2026-06-07 18:17:13 +08:00
bd13cffe14 feat: 添加亮色/暗色主题切换功能
- 在 index.css 中新增 html.light 亮色主题 CSS 变量和过渡动画
- 在 App.tsx Header 添加 Sun/Moon 主题切换按钮
- 主题偏好通过 localStorage 持久化,默认暗色主题
- 将所有组件中的硬编码 Tailwind 颜色值转换为 CSS 变量引用
- 状态色(emerald/amber/red/violet)保持不变,两种主题均适用
2026-06-04 21:52:45 +08:00
oudecheng
2f529e96d0 feat: 添加滚动控制功能,支持回到顶部和回到底部的按钮 2026-06-04 16:00:43 +08:00
e8a3a47ac7 feat: 添加 TaskStarted 事件,支持任务开始通知功能 2026-06-03 21:53:37 +08:00
oudecheng
1b571e943f feat: 添加停止当前执行的 Agent 功能,支持通过 /stop 命令取消执行 2026-06-03 16:49:29 +08:00
oudecheng
0d6880f6a3 fix: 修复任务工具结果解析逻辑,确保正确处理显示内容 2026-06-03 14:08:23 +08:00
oudecheng
f8fc0f7d0f feat: 添加工具结果处理功能,支持执行时长记录和显示 2026-06-02 16:15:05 +08:00
7d9355fd78 feat: WebSocket 媒体文件处理优化
- 后端 ws.rs: 处理前端上传的 base64 内容,保存到本地文件并更新路径
- 后端 ws.rs: 历史消息加载时从文件读取内容填充 base64,过滤 media_refs_json
- 前端 App.tsx: 传递 attachments 给 handleMessage 实现实时显示
- 前端 useChat.ts: handleMessage 支持 attachments 参数
- 前端 MessageInput.tsx: 支持剪贴板粘贴文件/图片
- 前端 MessageInput.tsx: 修复拖拽文件时闪烁问题
- 测试 test_request_format.rs: 补充缺失的 attachments 字段
2026-05-30 10:22:30 +08:00
c2293238fc feat: 前端支持文件附件输入
- 后端 WsInbound::Message 添加 attachments 字段
- ws.rs 将 attachments 转换为 MediaItem
- 前端 MessageInput 支持点击选择和拖拽文件
- 附件预览列表,支持删除
- 文件大小限制 50MB
- 支持所有文件类型
2026-05-30 08:07:02 +08:00
3d9c981c2a feat: 前端输入框体验优化
- AI 响应完成后自动聚焦输入框
- 输入框和发送按钮居中对齐
- 隐藏输入框滚动条
- 新建话题无需输入名称,自动生成默认标题
2026-05-29 23:12:53 +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
4cb26b5b67 feat: 子智能体任务消息查看,实时广播工具调用事件
- 新增 LoadTaskMessages 命令,加载子智能体任务的历史消息
- SubAgentEmitter 通过 MessageBus 实时广播子智能体工具调用
- 前端新增子智能体视图,支持导航进入/退出子智能体会话
- 外部渠道过滤子智能体事件,避免推送到飞书/微信
- ToolCall/ToolResult 新增 subagent_task_id 字段

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 11:15:38 +08:00
oudecheng
182bebdaef feat: 工具消息合并为可展开卡片,添加复制按钮
- 新增 merged_tool 消息类型,将 tool_call 和 tool_result 合并展示
- 卡片支持展开/折叠,显示参数和结果,带状态动画
- 添加复制按钮(hover 显示),支持消息文本和工具结果复制
- 过滤结果中冗余的"工具结果"前缀

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 09:10:34 +08:00
oudecheng
44e82e8473 feat: 附件通过 base64 内容实现前端直接下载
- MediaItem/MediaSummary 新增 content_base64 和 file_name 字段
- 解析附件时读取文件内容并 base64 编码(限 50MB),前端 Blob 下载
- 创建 Session 后返回完整 topics 列表,前端侧边栏实时同步
- 简化话题历史加载逻辑,不再回退到 session 消息

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 14:01:37 +08:00
oudecheng
7898ca69e4 feat: 添加附件支持、自动选择话题及消息展示优化
- 消息协议新增 attachments 字段,支持图片/音频/视频/文件附件
- 文本和附件合并在一条消息中发送,不再拆分为多条
- Topics 加载后自动选中第一个话题并加载历史消息
- 用户消息现在通过 WebSocket 发送,可在前端展示
- 前端过滤 tool_result 消息,添加附件卡片展示组件

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 11:51:48 +08:00
oudecheng
e9e1439428 feat: 添加通道和话题管理功能
后端:
- 新增 ListChannels 命令,列出所有可用通道 (WebSocket/CLI)
- 新增 ListSessionsByChannel 命令,支持按通道筛选会话
- 新增 ListTopics 命令,列出 Session 的所有 Topics
- 添加 Channel 和 TopicSummary 数据结构
- 更新 WebSocket 协议,支持 channel_list 和 topic_list 消息

前端:
- 新增 ChannelSelector 组件用于通道选择
- 新增 SessionSelector 组件用于会话选择
- 更新 TopicList 组件支持话题展示
- 更新 useChat hook 和协议类型定义

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:55:09 +08:00
oudecheng
624d8e8943 feat: 添加 React Web UI 前端界面
- 使用 React 18 + TypeScript + Vite + Tailwind CSS 构建前端
- 实现 WebSocket 实时通信(useWebSocket hook)
- 添加聊天界面组件(MessageList, MessageBubble, MessageInput)
- 集成 Topic 管理(新建、列出、切换)
- 支持 Markdown 渲染(react-markdown + remark-gfm)
- 添加工具调用展示面板
- 实现深色科技主题(Tech Dark)
- 后端集成静态文件服务(tower-http)
- 添加 Makefile 和 build.sh 构建脚本
- 更新 .gitignore 忽略前端构建产物

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-26 17:43:15 +08:00