Skip to content

feat(dashboard): 对话栏架构升级 —— streamdown + 七态状态机 + 组件拆分#127

Merged
mirror29 merged 8 commits into
mainfrom
feat/chat-streamdown-refactor
Jul 2, 2026
Merged

feat(dashboard): 对话栏架构升级 —— streamdown + 七态状态机 + 组件拆分#127
mirror29 merged 8 commits into
mainfrom
feat/chat-streamdown-refactor

Conversation

@mirror29

@mirror29 mirror29 commented Jul 1, 2026

Copy link
Copy Markdown
Owner

概述

基于 Omnigent 调研,提取可复用的流式架构改进,分三个 Phase 渐进式升级 Dashboard 对话栏。

改动

Phase 1:streamdown 替换 react-markdown(dae02d5

  • 新增 ChatStreamdown.tsx:封装 Streamdown,逐 token 渐进渲染 Markdown
  • 新增 chat-streamdown-security.ts:禁用远程图片加载
  • 流式 assistant 消息用 ChatStreamdown,历史消息保留 ChatMarkdown
  • 安装 streamdown ^2.5.0 + @streamdown/cjk + @streamdown/code

Phase 2:工具调用七态状态机(8a5d796

  • 新增 tool-states.ts:定义 Pending/Running/Completed/Error/Denied/Awaiting Approval/Responded 七种 ToolState
  • ToolChip 从 done 布尔值改为 state 驱动
  • 中间态有 pulse 动画,错误态红色高亮,审批态有 clock 图标

Phase 3:ChatThread 组件拆分(0d4c14c

  • ChatThread.tsx 941 行 → 373 行(-60%)
  • 拆分为 6 个独立组件:
    • ChatErrorBanner.tsx — 错误横幅
    • ChatHistoryPanel.tsx — 历史会话下拉面板
    • ChatToolChip.tsx — 工具调用 chip
    • ChatMessage.tsx — 单条消息渲染
    • ChatMessageList.tsx — 消息列表 + 自动滚动
    • ChatInput.tsx — 输入框 + 发送/停止 + 页面上下文胶囊

不做的事

  • 不替换 CopilotKit 传输层(/api/copilotkit AG-UI 桥保持不变)
  • 不引入 Vercel AI SDK / Zustand 等新大依赖
  • 不删除现有 tool-views(K线卡片、回测绩效表、因子热力图等量化视图全部保留)

验证

  • pnpm typecheck(orchestration + dashboard)零错误
  • 现有对话栏功能不受影响

🤖 Generated with Claude Code

mirror29 and others added 3 commits July 1, 2026 17:00
- 新增 ChatStreamdown.tsx:封装 Streamdown,保留印章终端主题样式
- 新增 chat-streamdown-security.ts:禁用远程图片加载
- ChatThread.tsx:流式 assistant 消息用 ChatStreamdown 逐 token 渲染,
  历史消息仍用 ChatMarkdown
- 安装 streamdown ^2.5.0 + @streamdown/cjk + @streamdown/code

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- 新增 tool-states.ts:定义七种 ToolState,含图标/颜色/展开态/pulse 动画
- ToolChip 从 done 布尔值改为 state 驱动,中间态有 pulse/spinner,
  完成态绿色可展开,错误态红色高亮,审批态有 clock 图标
- 基于 AG-UI 消息自动推断工具状态(tool call → Running,
  tool result → Completed/Error)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
将 ChatThread.tsx 拆分为 7 个独立组件:
- ChatErrorBanner.tsx  — 错误横幅
- ChatHistoryPanel.tsx — 历史会话下拉面板
- ChatToolChip.tsx    — 工具调用 chip(七态状态机)
- ChatMessage.tsx     — 单条消息渲染(user/assistant/tool)
- ChatMessageList.tsx — 消息列表 + 自动滚动 + 空态/思考中
- ChatInput.tsx       — 输入框 + 发送/停止 + 页面上下文胶囊
- ChatThread.tsx      — 精简为 373 行的纯容器/编排层

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 1, 2026

Copy link
Copy Markdown

Deploying inalpha-web with  Cloudflare Pages  Cloudflare Pages

Latest commit: bd5975b
Status: ✅  Deploy successful!
Preview URL: https://e0e284ef.inalpha-web.pages.dev
Branch Preview URL: https://feat-chat-streamdown-refacto.inalpha-web.pages.dev

View logs

@claude

claude Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor
commit: bd5975b

本轮复查基于上一条评论(commit d6eb69f)剩余的 1 项 medium 逐条核实:bd5975b 已解决,细节如下。

必修(critical / major)

无。

可选优化(medium)

无遗留。核实结果:

  • ChatMessage.tsx:114 完成态 / 历史消息已改为统一走 <ChatStreamdown streaming={isStreaming}>modestreaming prop 决定 static/streaming),不再有 isStreaming 翻转后切回 ChatMarkdown 纯等宽渲染的降级闪烁;ChatMarkdown.tsx 已整文件删除,ChatMessage.tsx 无残留 import,react-markdown 已从 package.json / pnpm-lock.yaml 移除且无其他消费方(lockfile 里剩的 react-markdown@8.0.7 是别的包的传递依赖,与本 PR 无关)——上一轮"高亮降级/闪烁"问题已修复,且顺带做到净减依赖。
  • 完成态与流式态现在共用同一条 createSecureRehypePlugins()allowedImagePrefixes: [])管线,不存在两套渲染管线各管一半安全策略的风险。
  • 上一轮"streamdown 传递依赖 mermaid/shiki 是否拖累首屏 bundle"一项,commit message 里给出了核实结论(import() 动态分包,不进首屏),本地未装 node_modules 无法独立复现该验证,但改动本身(顶层仍是 import { Streamdown } from "streamdown" 静态导入 streamdown 核心)与结论一致,不再视为阻塞项。

其余部分(组件拆分、七态状态机接线、i18n 文案、fetch abort patch、ChatInput 自动聚焦、ChatToolChip/ChatMessageList 数据流)本轮未发现新增问题。

LGTM。

mirror29 and others added 5 commits July 2, 2026 11:00
回应 PR #127 auto-review 的两个必修:

**[critical] abort signal 形同虚设**
- fetch 补丁里 stoppingRef 为真时 ctrl.abort() 后却用原始 init 发请求,
  signal 没挂上 → "点暂停后回复继续输出" bug 复发
- 修复:ctrl.abort() 后用 { ...init, signal: ctrl.signal } 发请求,
  浏览器立即以 AbortError 拒绝,真正掐断续段

**[major] 打开对话栏不再自动聚焦**
- Phase 3 拆分把 textarea 移进 ChatInput,但聚焦 effect 留在 ChatThread
  用已失效的 inputRef → 每次打开要手动点一下才能打字
- 修复:ChatInput 接受 open prop,按 open 变化驱动聚焦;
  ChatThread 删掉死的 inputRef

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
回应 PR #127 auto-review 的 medium:七态里只有 3 个(Running/Completed/Error)
有生产者,另外 4 个(Pending/Denied/审批态)是为 mastra 未来上报中间状态
预留的定义。加注释明确区分,避免后来者误以为审批态已可用而踩空。

样式表保留(定义先行合理),等 mastra 上报生命周期细分时扩 inferToolState 即可点亮。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- ChatHistoryPanel: t("historyLoading")(不存在的 key)→ t("loadingHistory")
- 工具七态文案从 TOOL_STATE_MAP 硬编码英文改走 next-intl:
  新增 TOOL_STATE_I18N_KEY 映射,ChatMessageList 经 t() 解析后
  注入 ChatMessage,中文 locale 不再显示裸 "Running"/"Completed"
- messages/{zh,en}.json 补 toolPending/toolError/toolDenied/
  toolAwaitingApproval/toolResponded(toolRunning/toolDone 复用)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
已完成 / 历史消息走 ChatMarkdown(react-markdown),此前无 img 覆盖,
markdown 里的 ![]() 会渲染成真实 <img src> 发起请求;注入的图片
beacon URL 会在重新渲染 / 重开历史会话时把 URL 参数渗出给第三方。
补 img 组件渲染 alt 占位而非 <img>,与 ChatStreamdown 的空白名单对齐。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
此前流式态走 ChatStreamdown(带 @streamdown/code 高亮 + cjk 排版),isStreaming
一翻转就切回 ChatMarkdown(纯等宽无高亮):agent 生成代码回复刚结束高亮即消失、
肉眼可见"闪一下",历史会话永远无高亮——Phase 1 引入高亮的卖点在实际停留时间
里基本不可见。

改为完成态 / 历史消息也走 ChatStreamdown(mode=static),与流式态共用同一条
渲染管线(高亮 + cjk + 空白名单图片拦截一致)。ChatMarkdown 随之成为死代码,
删除;react-markdown 已无任何消费方,从 package.json 移除(净减依赖)。

bundle 核实:streamdown 对 mermaid/shiki 走 import() 动态导入(dist chunk 实测),
二者按需 split 进异步 chunk,不进首屏 bundle;ChatStreamdown 顶层静态 import
只带入 streamdown 核心。上一轮 medium「bundle 体积」据此排除。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mirror29 mirror29 merged commit 7201038 into main Jul 2, 2026
10 checks passed
mirror29 added a commit that referenced this pull request Jul 2, 2026
回应 PR #127 auto-review 的两个必修:

**[critical] abort signal 形同虚设**
- fetch 补丁里 stoppingRef 为真时 ctrl.abort() 后却用原始 init 发请求,
  signal 没挂上 → "点暂停后回复继续输出" bug 复发
- 修复:ctrl.abort() 后用 { ...init, signal: ctrl.signal } 发请求,
  浏览器立即以 AbortError 拒绝,真正掐断续段

**[major] 打开对话栏不再自动聚焦**
- Phase 3 拆分把 textarea 移进 ChatInput,但聚焦 effect 留在 ChatThread
  用已失效的 inputRef → 每次打开要手动点一下才能打字
- 修复:ChatInput 接受 open prop,按 open 变化驱动聚焦;
  ChatThread 删掉死的 inputRef

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mirror29 added a commit that referenced this pull request Jul 2, 2026
回应 PR #127 auto-review 的 medium:七态里只有 3 个(Running/Completed/Error)
有生产者,另外 4 个(Pending/Denied/审批态)是为 mastra 未来上报中间状态
预留的定义。加注释明确区分,避免后来者误以为审批态已可用而踩空。

样式表保留(定义先行合理),等 mastra 上报生命周期细分时扩 inferToolState 即可点亮。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mirror29 mirror29 deleted the feat/chat-streamdown-refactor branch July 2, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant