Files
hunjing/docs/contracts/content-blocks-and-streaming.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

11 KiB
Raw Blame History

统一富内容与流式协议

1. 目标

同一套 ContentBlock 用于 Native Message、Agent 输出、社区内容、私信、协作评论和结构化产物。用户编辑可接受 Markdown 内嵌 Mermaid/数学语法;服务端在保存或发送前解析并规范化为类型化 Block。

原则:

  • 类型化 Block 是 API 和存储规范形态;
  • Markdown 是常用创作输入和可移植表示,不是所有媒体的唯一协议;
  • 每个 Block 有稳定 ID 和独立状态,可局部流式、报错、重试、替换和无障碍展示;
  • 不执行 HTML、JavaScript、Mermaid click callback 或不可信媒体脚本。

2. Content 容器

{
  "content": [
    {"id": "block_01...", "type": "markdown", "text": "## 结论\n..."},
    {"id": "block_02...", "type": "mermaid", "source": "flowchart LR\nA-->B"},
    {"id": "block_03...", "type": "math", "notation": "latex", "display": "block", "source": "E=mc^2"},
    {"id": "block_04...", "type": "image", "file_id": "file_01...", "alt": "架构图"}
  ]
}

所有 Block 通用字段:

字段 必需 说明
id 是 Message 内稳定 block_ ID
type 是 Block 类型
status 响应中 pending、streaming、completed、failed、cancelled
annotations 否 citation、来源、敏感度、语言等类型化标注
metadata 否 只允许 Schema 登记字段,不存任意秘密

id 在创建请求中可省略,由服务端生成;流事件必须携带服务端 Block ID。

3. Block 类型

3.1 文本与结构

type 关键字段 流式策略
text text, language? 字符增量
markdown text, flavor="hunjing-gfm-v1" 字符增量,安全增量解析
code source, language?, filename? 字符增量,Shiki 节流高亮
quote content[], source_ref? 子 Block 增量
table columns, rows, caption? 行级追加或完成后展示
callout kind, title?, content[] 子 Block 增量

Markdown 方言支持 CommonMark/GFM 的标题、段落、列表、引用、表格、任务列表、链接、图片引用、行内代码和 fenced code。原始 HTML 默认禁用。

3.2 数学公式

{
  "id": "block_math",
  "type": "math",
  "notation": "latex",
  "display": "block",
  "source": "\\int_0^1 x^2 dx = \\frac{1}{3}",
  "fallback_text": "从 0 到 1 的 x² 积分等于 1/3",
  "label": "公式 1"
}
  • notation 1.0 为 latex 或 asciimath;服务端规范化优先输出 LaTeX。
  • display 为 inline 或 block。
  • fallback_text 是可访问性与解析失败降级描述,不是隐藏推理。
  • Markdown 输入支持 $...$、$$...$$、\(...\)、\[...\];只有闭合定界符后才转换为 Math Block。
  • 常见公式描述应同时包含公式与自然语言说明,例如变量、单位、适用条件和来源,不能只输出不可读符号。

3.3 Mermaid

{
  "id": "block_mermaid",
  "type": "mermaid",
  "source": "sequenceDiagram\nA->>B: request",
  "title": "请求时序",
  "caption": "客户端到网关的调用",
  "fallback_code_language": "mermaid"
}
  • 只在 Block completed 后渲染;流式期间展示代码/骨架和“图表生成中”。
  • 禁止 click、外部脚本、HTML label、任意 URL callback 和危险初始化配置。
  • 渲染使用 strict security level、隔离 worker/iframe 和超时/节点数/源码长度限制。
  • 解析失败展示转义后的 Mermaid 源码与错误摘要,不丢失内容。
  • Markdown fenced ```mermaid 在规范化时转换为 Mermaid Block。

3.4 媒体与文件

type 关键字段
image file_id 或受控 url_ref, alt, width?, height?, caption?
video file_id, poster_file_id?, caption?, transcript_file_id?, duration_ms?
audio file_id, transcript?, duration_ms?, waveform?
file file_id, filename, media_type, size_bytes, description?
gallery items[](image/video refs), layout?
avatar asset_id, format(live2d/vrm/gltf), preview_file_id?
  • API 不接受 file://、javascript:、data:text/html 等 URL。
  • 内部资源使用 file_id,下载通过授权 API 或短期签名 URL。
  • 图片 alt 必需;视频应提供字幕/转写状态;音频应提供转写或文本摘要。
  • 媒体生成流只发送 asset.progress 与最终 File/Media Block,不把未完成二进制塞进 SSE JSON。

3.5 Agent 与工具

type 说明
tool_call 工具名、调用 ID、参数脱敏视图、状态和审批引用
tool_result 调用 ID、结构化摘要、文件引用、错误状态
agent_status Agent/ChildRun、阶段、进度和等待原因
approval_request 动作、影响、参数摘要、有效期和 Approval ID
artifact Run 产物 ID、类型、版本和下载/打开动作
citation 来源 ID、标题、引用文本与定位(文本区间、图像区域、PDF 页区、音视频时间码);保存原文快照,来源正影后提示后继版本
error 局部 Block 错误、可否重试和 fallback

普通 Message API 不允许客户端伪造系统产生的 tool_call、tool_result、agent_status 和 approval_request;这些 Block 只由 Runtime 写入。

4. Markdown 输入规范化

当客户端提交 markdown Block:

  1. 保存用户原始 Markdown 的规范化副本及 hash;
  2. 使用确定性 parser 解析 AST;
  3. fenced mermaid 转为 Mermaid Block;
  4. 闭合数学定界符转为 Math Block;
  5. fenced 其他语言转为 Code Block;
  6. Markdown 图片只允许已上传 file_id 语法或经过 URL 安全代理的 HTTPS URL;
  7. 输出 canonical ContentBlock 列表和 parser version;
  8. 编辑后重新规范化,创建 Message Revision,不静默改旧 Block。

导出可选择 canonical JSON 或重建的 Hunjing Markdown;重建时复杂 Block 使用稳定 fenced/directive 语法。

5. 流式事件

Run SSE 使用统一 envelope;Block 事件如下:

content.block.started
content.block.delta
content.block.progress
content.block.completed
content.block.failed
content.block.cancelled
message.completed

5.1 Started

{
  "type": "content.block.started",
  "data": {
    "message_id": "message_01...",
    "block": {"id": "block_01...", "type": "markdown", "status": "streaming"},
    "index": 0
  }
}

5.2 Delta

{
  "type": "content.block.delta",
  "data": {
    "message_id": "message_01...",
    "block_id": "block_01...",
    "delta_index": 7,
    "delta": {"type": "text_append", "text": "新增文本"}
  }
}

Delta 类型:

  • text_append:text/markdown/code/math/mermaid source 追加;
  • json_patch:只用于 Schema 明确允许的结构化 Block,采用受限 RFC 6902 子集;
  • row_append:table 追加完整行;
  • annotation_add:追加 citation/来源;
  • resource_ready:绑定已完成 file/media/artifact;
  • status_replace:Agent/tool/approval 状态转换。

每个 Block 的 delta_index 从 0 单调递增;同一 delta 可重放,客户端按 (block_id, delta_index) 去重。缺口出现时暂停该 Block 增量展示,并通过 Run 重放或最终 Message 对账。

5.3 Completed

{
  "type": "content.block.completed",
  "data": {
    "message_id": "message_01...",
    "block": {
      "id": "block_01...",
      "type": "markdown",
      "status": "completed",
      "text": "完整权威内容"
    },
    "content_hash": "sha256:..."
  }
}

Completed Block 是该 Block 的权威快照。客户端丢弃临时解析状态,以完整 Block 重建并校验 hash。message.completed 携带最终 Message ID、Block 顺序和版本,最终 GET Message 可恢复所有内容。

6. 分级实时策略

内容 流式展示
Plain text / Markdown 增量显示;解析节流;未闭合结构以文本态保留
Code 增量显示;按行/时间片重新高亮,不逐 token 运行 Shiki
Inline/Block Math 累积到完整定界符或 Block 完成后渲染;此前显示源码占位
Mermaid 只在 Block completed 后渲染;此前显示源码/骨架
Image/Video/Audio/File progress 占位;resource_ready 后加载;失败可重试
Table 完整行追加,避免半行抖动
Tool/Agent/Approval 状态替换,不拼接自由文本

7. 限制与安全

  • 单 Message、Block、源码、节点、表格、媒体和嵌套深度的限额由配置发布,但 Schema 必须有硬上限。
  • Markdown URL 经 scheme/host 校验,外链加 noopener noreferrer,可选经安全跳转页。
  • HTML 默认不解析;需要 HTML 的可信内部 Block 也必须经 allowlist sanitizer。
  • KaTeX/MathJax 禁用信任命令、宏注入和外部资源;限制宏展开和源码长度。
  • Shiki 只高亮不执行代码;复制/下载保留原源码。
  • Mermaid 渲染隔离且不允许交互脚本。
  • 媒体采用 CSP、正确 Content-Type、nosniff 和独立对象域。

8. 兼容 API 映射

OpenAI/Anthropic Content Block 在 Gateway Adapter 转为内部 Block,但兼容响应仍保持目标协议。无法映射的 Native 类型:

  • 优先转换为目标协议支持的 text/image/document/tool block;
  • Mermaid/math/code 可降级为 Markdown/fenced source;
  • video/audio/avatar/artifact 使用文本说明 + 受控文件引用;
  • 不能无损、安全表达时返回明确 unsupported,不伪造协议字段。

9. 分支对话交互态

分支对话(镜树)在流式协议之上的交互态语义(承接旧版镜树专题 PRD,字段与枚举进入 OpenAPI 前以本节为基线):

  • 临时芽体(Block status: streaming 的未完成答复):完成后才固化为权威快照;流式期间展示为进行态,不进入归真候选。
  • 残答(interrupted):被停止或中断的不完整答复封存可查,不作为完成答复;默认上下文不自动包含。
  • 续生(generation_resume):从残答继续生成时创建新 Message 并引用残答来源;残答本身不被修改或"补全"。
  • 引用合流(citation_intake):树间内容经显式引用带入另一棵树,以 citation/引文锚表达;不物理合并两树,被引内容保留原树的界域与归真作用域。
  • 结题(topic_conclusion):标记主题阶段完成并生成可审阅总结(总结内容走候选确认);结题后仍可复照继续,不删除历史。
  • 回响(task_echo):后台受托任务完成后,结果以回响形态回到原分支,作为带来源的观察呈现(agent_status/artifact Block);经用户接纳并归真后才成为正式答复。
  • 上下文镜(context_mirror):发送或继续前向用户渐进展示实际采用的上下文范围、压缩与省略项;与 ContextSnapshot 同源数据,是用户可见的透明视图而非诊断特权。

不变量:重新生成不覆盖旧候答;后代节点绑定用户实际依据的候答;已归真经历不因切换候答、删除旁枝或移动工作入口而回滚;未归真旁枝不自动入忆。