# 前端富内容实时渲染 ## 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. 渲染流水线 ```mermaid 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. 流状态机 ```mermaid 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、长公式和大量消息做性能基线。