- 产品层:产品宪章与永久禁域、产品定义、完整 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
11 KiB
统一富内容与流式协议
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"
}
notation1.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:
- 保存用户原始 Markdown 的规范化副本及 hash;
- 使用确定性 parser 解析 AST;
- fenced
mermaid转为 Mermaid Block; - 闭合数学定界符转为 Math Block;
- fenced 其他语言转为 Code Block;
- Markdown 图片只允许已上传
file_id语法或经过 URL 安全代理的 HTTPS URL; - 输出 canonical ContentBlock 列表和 parser version;
- 编辑后重新规范化,创建 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/artifactBlock);经用户接纳并归真后才成为正式答复。 - 上下文镜(
context_mirror):发送或继续前向用户渐进展示实际采用的上下文范围、压缩与省略项;与 ContextSnapshot 同源数据,是用户可见的透明视图而非诊断特权。
不变量:重新生成不覆盖旧候答;后代节点绑定用户实际依据的候答;已归真经历不因切换候答、删除旁枝或移动工作入口而回滚;未归真旁枝不自动入忆。