Skip to content

feat(home-chat): 新增 stream 级 typing indicator 覆盖请求真空期 - #481

Merged
ThreeFish-AI merged 1 commit into
feature/1.x.xfrom
ThreeFish-AI/agent-typing-indicator
May 9, 2026
Merged

feat(home-chat): 新增 stream 级 typing indicator 覆盖请求真空期#481
ThreeFish-AI merged 1 commit into
feature/1.x.xfrom
ThreeFish-AI/agent-typing-indicator

Conversation

@ThreeFish-AI

Copy link
Copy Markdown
Owner

背景

用户在首页 Home Chat 发送消息后,前端在「请求已发出 → Agent 流式内容首次显示」之间存在 100–500ms(慢网或冷启动可达数秒)的等待真空期:

  • 用户消息气泡已渲染、输入框切换为 Stop;
  • 但 Assistant 气泡尚未挂载(要等 RUN_STARTED / 首个 TEXT_MESSAGE_CONTENT 入会话树);
  • 整个对话区视觉死寂,用户难以判断是否提交成功 / 是否已开始处理。

AssistantReplyBubble.tsx:118-128 早期已有三点 bounce 占位,但只覆盖「气泡已挂载但 segments 仍为空」的窗口;本 PR 在更上游的 ChatStream 层补一段 stream 级 indicator,与 bubble 级 placeholder 形成无缝接力。

改动总览

  • 抽取共享组件 ChatTypingIndicator(inline / standalone 两种 variant),把 AssistantReplyBubbleMessageBubble 内既有的三点 bounce 占位收敛为单一事实源;保留 data-testid=\"agent-waiting-placeholder\" 兼容既有测试。
  • ChatStream 新增 pending prop:在 displayBlocks.map 之外追加 standalone 三点动画,覆盖 Assistant 气泡尚未挂载的真空期;末尾 displayBlock 已是 assistant-reply 时让位给 bubble 级 placeholder,避免双 indicator。
  • home-body 直接以既有 effectiveConnection ∈ {connecting, streaming} 派生 pending不引入新 state、不动 activeRunIdRef(PR fix(home-chat): 根治重复渲染/乱序/双气泡 — Phase 3 折叠闸门 + invocationId 映射 + sort tiebreaker #479 故意以 ref 形式保留以规避并发 race)。
  • 含 a11y:role=\"status\" + aria-live=\"polite\" + sr-only 文本;动效降级:motion-reduce:animate-none 响应 prefers-reduced-motion

风险评估(对 PR #479

路径 是否触碰
buildChatDisplayBlocks 去重/排序/Phase 3 折叠闸门 ❌ indicator 在 displayBlocks.map 之外渲染
invocationId 映射 ❌ 无关联
Sort tiebreaker ❌ indicator 无 timestamp
activeRunIdRef 并发隔离 ❌ 不读不写
conversation-tree / session-hydration / useAgentSubscription ❌ 完全不动

回归风险:低

业界最佳实践对照

  • iMessage typing dots:三点 bounce + 紧贴气泡上方 — 与本方案最接近;本方案多一层 stream 级覆盖「block 尚未挂载」窗口;
  • Anthropic Claude.ai / ChatGPT:在 Assistant 气泡内显示等待 caret/spinner — 对应现有 bubble 级 placeholder;
  • Vercel AI SDK useChat:暴露 isLoading 由调用方决定 UI — 与本方案 effectiveConnection 派生 pending 概念一致。

自证材料

测试

  • 新增 12 个单元测试(ChatTypingIndicator.test.tsx 6 条 + ChatStream.pending.test.tsx 6 条),覆盖 inline/standalone 两个 variant、a11y、reduced-motion、向后兼容、stream→bubble 接力路径。
  • 全量 vitest:85 文件 / 625 测试全绿;MessageBubble 与 ChatStream 既有测试套零回归。
  • pnpm typecheckpnpm lint --max-warnings=0:均通过。

浏览器实机验证(chrome_devtools 接入用户主 Chrome 真实登录态)

  • React Fiber 反查确认 <ChatStream> 收到 pending prop(key 列表含 pending);
  • Timeline 完整捕获:发送后 standalone indicator 出现 → Assistant 气泡挂载时 indicator 消失,bubble 级 placeholder 接力;
  • 暗色色彩对比正常,无 console 错误。

实机截图归档于 .context/typing-indicator-*.png

Test plan

🤖 Generated with Claude Code, CodeX, Gemini

- 抽取 ChatTypingIndicator 共享组件(inline / standalone 两种 variant),把
  AssistantReplyBubble 与 MessageBubble 内既有的三点 bounce 占位收敛为单一
  事实源;保留 data-testid="agent-waiting-placeholder" 兼容既有测试。
- ChatStream 新增 pending prop:在 displayBlocks 之外渲染 standalone 三点
  动画,覆盖「用户已发送但 Assistant 气泡尚未挂载」的网络真空期;末尾
  block 已是 assistant-reply 时让位给 bubble 级 placeholder,形成无缝接力。
- home-body 用既有 effectiveConnection ∈ {connecting, streaming} 直接驱动
  pending,不引入新 state,不动 activeRunIdRef(PR #479 故意保持 ref 以
  规避并发 race),完全外置于 buildChatDisplayBlocks / 折叠闸门 / invocationId
  映射等高风险路径,零回归风险。
- 组件含 role="status" + aria-live="polite" + sr-only 文本,并对
  prefers-reduced-motion 启用 motion-reduce:animate-none 静态降级。
- 新增 12 个单元测试覆盖 indicator 与 ChatStream pending 接力路径,整套
  625 个测试全绿,typecheck / lint 干净。
- 通过 chrome_devtools 接入用户主 Chrome 实机验证:fiber 反查确认 pending
  prop 正确绑定;timeline 完整捕获 mount → unmount 生命周期;暗色色彩对比
  通过;无 console 错误。

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
@ThreeFish-AI
ThreeFish-AI merged commit 4e2db23 into feature/1.x.x May 9, 2026
11 checks passed
@ThreeFish-AI
ThreeFish-AI deleted the ThreeFish-AI/agent-typing-indicator branch May 10, 2026 04:18
ThreeFish-AI added a commit that referenced this pull request Jul 5, 2026
…-2026-4372 处置) (#1057)

* fix(deps): ts-deepmerge 补丁地板至 8.0.0 修复 GHSA-87mf-gv2c-c62c (#481);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(negentropy): pydantic-settings 升 2.14.2 + joserfc>=1.6.7 补丁地板修复 #482/#488;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* fix(cognizes): joserfc/msgpack/python-socketio/python-engineio 补丁地板修复 #483/#486/#487/#490/#491;

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>

* docs(perceives): ISSUE-092 增补 CVE-2026-4372 威胁模型;transformers 钉 4.x + dismiss #492(marker 5.x 不兼容实测);

🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
Co-Authored-By: Aurelius Huang<threefish.ai@gmail.com>
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