Files
hunjing/docs/architecture/frontend-content-rendering.md
T
chenxin 42513d13c6 📝 docs: 建立魂镜完整 1.0 设计文档体系
- 产品层:产品宪章与永久禁域、产品定义、完整 1.0 范围与发布门、道家文化语言体系、指标与反指标
- 研究层:参考项目研究(deepseek-harness、pi、MemOS、模型网关)、灵台原生引擎研究(业界原生引擎架构理念与道家文化出处)
- 架构层:系统、Agent 运行时(周天体系)、插件系统、灵台引擎(C++ 双形态)、媒体与设备、社区协作市场、前端富内容渲染、数据、记忆与知识
- 契约层:协议与稳定标识、API 总体约定、Native API、兼容网关、实时与 Webhook、内部端口、统一 ContentBlock 与流式(含分支对话交互态)、灵台 C ABI 与 gRPC Service、API 表面、HTTP 与事件、运行观测
- 决策:ADR-001 至 ADR-023(模块化单体、每 attempt 持久化、候选记忆、OAuth 2.1、灵台引擎、双形态部署、大周天演化、宪章、三界作用域、私箧与保全态、叩心、周天统一等)
- 交付:WP-01 至 WP-15 实施 TODO 与设计阶段交接文档
- 工程:AGENTS.md 工程规则(含 C++/灵台规范)、CLAUDE.md 引用、.gitignore
2026-09-09 21:07:14 +08:00

8.6 KiB
Raw Blame History

前端富内容实时渲染

1. 适用客户端

同一渲染内核服务 Next.js Web、Tauri Desktop 和 Tauri Mobile。平台差异只位于资源加载、文件保存、设备能力和性能档位;ContentBlock 与流状态机保持一致。

推荐组件:

  • Markdown:react-markdown + remark-gfm + 受控 remark/rehype 插件;
  • Code:Shiki,高亮 Worker 与缓存;
  • Math:KaTeX 为默认,MathJax 只作为兼容回退;
  • Mermaid:Mermaid strict mode,在 Worker/隔离容器渲染 SVG;
  • 长列表:@tanstack/react-virtual;
  • 媒体:原生 image/video/audio,使用受控资源 URL;
  • 状态:TanStack Query 管服务端资源;轻量本地 store 管流 accumulator 和 UI 状态。

新增依赖前仍需按 AGENTS.md 查当前维护状态和已安装能力。

2. 渲染流水线

flowchart LR
  SSE[SSE Events] --> ACC[Event Accumulator]
  ACC --> STORE[Block Store]
  STORE --> PARSE[Incremental Parse]
  PARSE --> SAFE[Sanitize and Validate]
  SAFE --> RENDER[Typed Renderers]
  RENDER --> DOM[Accessible UI]
  FINAL[Completed Message] --> RECON[Reconcile]
  RECON --> STORE

各层职责:

  1. Event Accumulator:校验 run sequence 与 block delta index,去重和检测缺口。
  2. Block Store:以 message_id/block_id 保存原始 block、流状态和 renderer 状态。
  3. Parse:只对允许增量的类型做节流解析。
  4. Sanitize:URL、Markdown AST、SVG、公式和媒体元数据安全处理。
  5. Renderer:按 Block type 分派,未知类型显示兼容占位而不崩溃。
  6. Reconcile:content.block.completed 与 message.completed 到达后用权威快照替换临时状态。

3. 流状态机

stateDiagram-v2
  [*] --> pending
  pending --> streaming : block.started
  streaming --> streaming : ordered delta
  streaming --> awaiting_replay : delta gap
  awaiting_replay --> streaming : replay filled
  awaiting_replay --> completed : final snapshot
  streaming --> completed : block.completed
  streaming --> failed : block.failed
  streaming --> cancelled : block.cancelled
  failed --> completed : retry/resource ready
  completed --> [*]
  cancelled --> [*]
  • 乱序 delta 暂存在小窗口;超过窗口请求重放,不猜顺序。
  • 重复 delta 根据 (block_id, delta_index) 丢弃。
  • 连接断开保留乐观内容并标记“正在恢复”;最终 GET Run/Message 对账。
  • Final snapshot 与累积 hash 不一致时记录前端诊断并以服务端快照为准。

4. Markdown 增量渲染

4.1 策略

  • 原始增量文本始终保留;AST 是可丢弃派生状态。
  • 以 50–100 ms 或换行边界节流解析,不逐 token 全量重渲染。
  • 未闭合 fence、链接、表格、强调或数学定界符保持源码/纯文本展示,不自动补造语义。
  • Completed 后对完整 Markdown 再解析一次,替换临时 AST。
  • 大 Block 分段渲染,避免每次 delta 重建整个消息树。

4.2 安全

  • 禁用原始 HTML;若以后开放,仅对可信内部内容使用严格 allowlist。
  • 链接协议允许 https、mailto 和内部资源 scheme;拒绝 javascript、危险 data、file。
  • 外链打开使用 noopener noreferrer,并显示目标域。
  • Markdown 图片规范化为 Image Block;不直接加载任意第三方跟踪像素。

5. Code 与 Shiki

  • 流式时先用等宽纯文本展示;完整行或节流窗口后发送 Worker 高亮。
  • Shiki grammar 按需加载并缓存;未知语言回退 plain text。
  • 超大代码块关闭实时高亮,完成后按可见区域高亮。
  • 提供复制、换行、下载、语言、文件名和行号;复制取原始源码,不从高亮 DOM 提取。
  • 代码永不在渲染器执行;可执行动作是独立 Tool/Approval。

6. 数学公式

6.1 解析

  • Native Math Block 直接按 notation 处理。
  • Markdown 中只有闭合 $...$、$$...$$、\(...\)、\[...\] 才触发公式渲染。
  • 流式未闭合公式显示转义源码和稳定占位,避免页面反复跳动。
  • KaTeX 解析失败显示 fallback_text 或源码,并提供错误详情展开。

6.2 安全和可访问性

  • KaTeX trust=false,限制宏、展开深度和输入长度;禁用 URL/HTML 注入命令。
  • 生成 MathML/ARIA;Block 公式提供自然语言 fallback_text、变量和单位说明。
  • 用户可切换“渲染公式/显示源码”。
  • 常见公式描述采用“名称 → 公式 → 变量/单位 → 适用条件 → 示例”的结构,不把推导过程混入隐藏思维。

7. Mermaid

  • 流式期间不渲染图,仅展示代码骨架和进度。
  • block.completed 后把源码发送 Worker;验证节点数、边数、字符数和超时。
  • Mermaid 使用 securityLevel: strict,禁止 click、HTML label、外部资源和任意初始化指令。
  • 输出 SVG 再经 sanitizer;SVG 不允许 script、foreignObject、事件属性或外部 URL。
  • 渲染失败显示源码、错误摘要和“复制到 Mermaid 编辑器”的安全动作,不空白。
  • 提供缩放、平移、适配宽度、下载 SVG/PNG、文本替代和全屏。
  • 图表在移动端默认源码/缩略图折叠,按需展开,防止长宽溢出。

8. 图片、视频和音频

图片

  • 使用 file_id 换取短期授权 URL;响应式尺寸、懒加载、占位、失败重试和 alt。
  • 不信任服务端文件名/MIME;资源域返回正确 Content-Type、CSP、CORP 和 nosniff。
  • 大图支持查看器、缩放和下载;不默认将 EXIF 暴露给其他用户。

视频

  • 等待 resource_ready 后显示 poster;使用 HLS/DASH 或受控 MP4。
  • 提供字幕、转写、时长、加载/转码状态和失败说明。
  • 自动播放默认关闭;有声音播放必须由用户手势触发。

音频

  • 显示波形/时长/转写;流式 TTS 与固化 Audio Block 分离。
  • 实时语音使用 WebSocket 播放队列,不把每帧写入 React 树。
  • 支持打断、静音、速度和字幕;停止后清空未播放帧。

9. Agent、工具和审批展示

  • AgentStatus Block 显示当前阶段、ChildRun、预算、等待和取消操作,不展示隐藏推理。
  • ToolCall Block 默认显示工具名、用途、状态、耗时和脱敏参数摘要;敏感详情走诊断授权。
  • ApprovalRequest 必须显示动作、目标、影响、费用、数据范围、有效期、允许/拒绝按钮。
  • ToolResult 区分成功、错误、未知结果和产物,不把错误结果渲染成普通助手文本。
  • 并行 ChildRun 使用树/时间线,主消息流只展示汇总状态,避免刷屏。

10. 长列表与性能

  • Conversation/Community/Diagnostics 使用虚拟滚动,Block 高度由 ResizeObserver 缓存。
  • 流式中的当前 Message 可脱离虚拟列表单独渲染,完成后归档入列表。
  • Markdown AST、Shiki tokens、Mermaid SVG 和 Math 渲染按 content hash 缓存。
  • Worker 处理高亮、Mermaid 和重解析;主线程只提交最终安全树。
  • prefers-reduced-motion 关闭非必要动画;流式光标不引发布局抖动。
  • 建立不同设备性能档:关闭实时代码高亮、降低 Avatar 帧率、延迟复杂图渲染,而不丢失内容。

11. 可访问性

  • 每个 Block 使用正确语义元素和可聚焦操作。
  • 新 delta 不持续抢夺屏幕阅读器焦点;用节流 aria-live 汇报状态。
  • 图像必有 alt;图表有 title/caption/源码替代;音视频有字幕/转写。
  • 数学提供 MathML 和 fallback text;代码支持键盘复制和横向滚动。
  • 工具确认、错误和费用不能只靠颜色表达。
  • Avatar/动效不阻塞核心内容和操作。

12. 失败与降级

失败 展示
Markdown 解析失败 转义纯文本
Shiki 失败 plain code
Math 失败 fallback text + source
Mermaid 失败 source + error summary
媒体未就绪 progress placeholder
媒体失败 retry/download details
未知 Block type “当前客户端暂不支持” + JSON-safe summary
SSE 断线 recovering 状态 + replay/final fetch
hash 不一致 final snapshot + diagnostic marker

降级必须保留用户内容,不以空白、崩溃或静默删除处理。

13. 测试

  • 对每种 Block 建立 canonical fixture、流式分片、断线、重复、乱序、失败和未知类型测试。
  • Markdown/Math/Mermaid 做 XSS、URL、SVG、宏膨胀和资源耗尽测试。
  • 浏览器组件测试覆盖键盘、屏幕阅读器、reduced motion 和移动布局。
  • Playwright 覆盖从 SSE 到 Markdown/公式/Mermaid/媒体/Tool Approval 的端到端流程。
  • 对 1 MB Markdown、万行代码、复杂 Mermaid、长公式和大量消息做性能基线。