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

254 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 统一富内容与流式协议
## 1. 目标
同一套 `ContentBlock` 用于 Native Message、Agent 输出、社区内容、私信、协作评论和结构化产物。用户编辑可接受 Markdown 内嵌 Mermaid/数学语法;服务端在保存或发送前解析并规范化为类型化 Block。
原则:
- 类型化 Block 是 API 和存储规范形态;
- Markdown 是常用创作输入和可移植表示,不是所有媒体的唯一协议;
- 每个 Block 有稳定 ID 和独立状态,可局部流式、报错、重试、替换和无障碍展示;
- 不执行 HTML、JavaScript、Mermaid click callback 或不可信媒体脚本。
## 2. Content 容器
```json
{
"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 数学公式
```json
{
"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
```json
{
"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 事件如下:
```text
content.block.started
content.block.delta
content.block.progress
content.block.completed
content.block.failed
content.block.cancelled
message.completed
```
### 5.1 Started
```json
{
"type": "content.block.started",
"data": {
"message_id": "message_01...",
"block": {"id": "block_01...", "type": "markdown", "status": "streaming"},
"index": 0
}
}
```
### 5.2 Delta
```json
{
"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
```json
{
"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 同源数据,是用户可见的透明视图而非诊断特权。
不变量:重新生成不覆盖旧候答;后代节点绑定用户实际依据的候答;已归真经历不因切换候答、删除旁枝或移动工作入口而回滚;未归真旁枝不自动入忆。