Skip to main content
xbot
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage
Edit page

Web Channel V2 — 圆桌会议纪要

日期:2026-03-27 分支:feat/web-fancy(基于 master aa7fa0c) 参会方:方案拥护者、魔鬼代言人、工程实践者、用户视角


一、共识结论

✅ 批准事项

功能决议备注
代码块语法高亮 + 复制按钮✅ P0highlight.js,纯前端,1-2天
停止生成按钮✅ P0后端 /cancel 已就绪,前端 1天
结构化进度展示✅ P1ProgressEventHandler 管道,3-4天
文件上传下载✅ P2HTTP 通道,10MB 限制,5-8天
增强输入区✅ P2Markdown 工具栏 + 预览,2-3天
Settings 页面✅ P2localStorage,主题+字号,2天
WS 断线重连✅ P1前端 exponential backoff,1天

❌ 否决事项

功能决议理由
Tiptap 富文本编辑器❌ 全员反对富文本→纯文本有损、LLM 侧无收益、竞品均用纯文本、维护成本高
framer-motion 动画库纯 CSS @keyframes 可替代
shadcn/ui / MUI过重,手写组件足够
文件走 WS 传输WS 64KB 限制(client→server),HTTP 更标准

⚠️ 延后事项

功能决议理由
真流式输出(打字机效果)⏸️ 延后engine.go CollectStream 贪心消费 + Run 循环多轮迭代架构约束,改 engine 核心循环风险大,ROI 不如进度展示
Sidebar 会话列表⏸️ 延后功能填充不足前不做布局重构

二、关键代码发现

发现 1:ProgressEventHandler 是空壳

// engine.go:91-92 — 字段定义
ProgressEventHandler func(event *ProgressEvent)

// engine.go:367-373 — engine 内部调用
if cfg.ProgressEventHandler != nil {
    cfg.ProgressEventHandler(&ProgressEvent{...})
}

// engine_wire.go:136-143 — 只注入了 ProgressNotifier
if autoNotify {
    cfg.ProgressNotifier = func(lines []string) { ... }
    // ← ProgressEventHandler 从未被注入!
}

影响StructuredProgress(Phase/ActiveTools/CompletedTools)已构建但被丢弃,需在 buildMainRunConfig 中补接。

发现 2:停止生成后端已就绪

// agent.go:960 — /cancel 命令拦截
if strings.TrimSpace(strings.ToLower(msg.Content)) == "/cancel" {
    cancelKey := msg.Channel + ":" + msg.ChatID + ":" + msg.SenderID
    ch.(chan struct{}) <- struct{}{}  // → reqCancel() → context cancellation
}

前端只需发送 {"type":"message","content":"/cancel"} 即可触发。

发现 3:进度消息堆积 Bug(P0)

当前前端把每条 type:"progress" WS 消息当作独立气泡追加,导致 5-20 条进度消息淹没聊天区。需改为"进度区域"概念,独立于消息列表。

发现 4:setLoading(false) 时机错误

当前收到任意 WS 消息就关闭 loading,应在收到最终回复(text/card)时才关闭。

发现 5:LLM 流式被 CollectStream 吞掉

// engine.go:245-254
func generateResponse(...) (*llm.LLMResponse, error) {
    eventCh, _ := streaming.GenerateStream(...)
    return llm.CollectStream(ctx, eventCh)  // ← 所有 StreamEvent 被聚合
}

真流式需要穿透此处,但 Run 循环的多轮迭代(tool_calls vs final text)使改造成本巨大。

发现 6:WS 64KB 限制方向

c.conn.SetReadLimit(65536) 只限 client→server 方向,server→client 无限制。文件传输走 HTTP 不受影响。


三、分阶段实施计划

Phase 1:基础体验补全(P0,预计 3-4 天)

#任务天数依赖
1代码块语法高亮 + 复制按钮前端1
2停止生成按钮前端+后端1
3修复进度消息堆积 Bug前端0.5
4修复 loading 状态时机前端0.25
5消息时间戳显示前端0.25
6智能滚动(上滚暂停自动滚动)前端0.5
7WS 断线自动重连前端0.5

Phase 2:差异化功能(P1,预计 4-5 天)

#任务天数依赖
8接通 ProgressEventHandler 管道后端1Phase 1
9WS 协议扩展(progress_structured 类型)后端0.5#8
10前端进度面板(折叠式工具列表)前端2#9
11进度区到最终回复的过渡动画前端0.5#10

Phase 3:能力扩展(P2,预计 7-10 天)

#任务天数依赖
12文件下载(GET /api/files/:id)后端1Phase 2
13文件上传(POST /api/files/upload + 拖拽+粘贴+按钮)后端+前端3#12
14增强输入区(Markdown 工具栏 + 预览切换)前端2
15Settings 页面(主题+字号,localStorage)前端2
16Todo checklist 渲染(前端解析 [x]/[ ])前端1
17消息历史分页/虚拟滚动前端+后端2

Phase 4:进阶体验(P3,按需)

#任务天数备注
18真流式输出(token 级打字机)全栈10-15需改造 engine.go 核心
19Sidebar 布局 + 会话列表全栈3-5需后端会话管理 API
20移动端适配前端2-3响应式布局

总工期估算:14-19 天(Phase 1-3),不含 Phase 4


四、后端改动汇总

WS 协议扩展

// 服务端 → 客户端(wsMessage 扩展)
type wsMessage struct {
    Type      string               `json:"type"`                         // "text","progress","progress_structured","card","file"
    ID        string               `json:"id,omitempty"`
    Content   string               `json:"content,omitempty"`
    TS        int64                `json:"ts,omitempty"`
    Progress  *progressPayload     `json:"progress,omitempty"`           // 新增:结构化进度
    File      *filePayload         `json:"file,omitempty"`               // 新增:文件元数据
}

type progressPayload struct {
    Phase          string           `json:"phase"`            // thinking|tool_exec|compressing|done
    Iteration      int              `json:"iteration"`
    ActiveTools    []toolProgress   `json:"active_tools"`
    CompletedTools []toolProgress   `json:"completed_tools"`
}

type toolProgress struct {
    Name    string `json:"name"`
    Label   string `json:"label"`
    Status  string `json:"status"`   // running|done|error
    Elapsed int    `json:"elapsed_ms"`
}

type filePayload struct {
    ID   string `json:"id"`
    Name string `json:"name"`
    Size int64  `json:"size"`
    Mime string `json:"mime"`
    URL  string `json:"url"`
}
// 客户端 → 服务端(wsClientMessage 扩展)
type wsClientMessage struct {
    Type    string   `json:"type"`                // "message","cancel"
    Content string   `json:"content,omitempty"`
    FileIDs []string `json:"file_ids,omitempty"`  // 新增:附件引用
}

新增 API 端点

端点方法说明
/api/files/uploadPOSTmultipart 文件上传,10MB 限制
/api/files/:idGET文件下载

五、风险与缓解

风险严重度缓解
停止按钮只断 WS 不发 /cancel🔴 高测试用例覆盖;前端走 WS 消息不 close
进度推送频率过高卡顿🟡 中后端节流 ≥500ms;前端 requestAnimationFrame 合并
ProgressEventHandler 影响飞书渠道🟡 中按 channel 条件注入,飞书不设置则不触发
打字机动画不完整 Markdown🟡 中最终回复直接显示,不做打字机(准流式方案已弃用打字机)
文件上传恶意文件🟡 中MIME 校验 + 大小硬限 + 存储隔离

六、WS 协议向后兼容

新增字段全部 omitempty,新增 type 值不影响旧客户端。旧客户端忽略未知 type 即可。WS 协议为真流式预留 stream_start/stream_delta/stream_end type(不实现,协议兼容)。


会议结束,待陛下批准后启动实施。