📝 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
This commit is contained in:
chenxin committed 2026-09-09 21:07:14 +08:00
commit 42513d13c6
37 files changed
+5795

No files matched your search

+187
View File
@@ -0,0 +1,187 @@
# 协议与稳定标识
本目录是稳定工程契约的单一事实源。代码实现前应生成 OpenAPI 3.1 / JSON Schema;本文件定义尚未机器化前的命名基线。
## 命名
| 对象 | 规则 | 示例 |
| --- | --- | --- |
| JSON / SQL | `snake_case` | `personal_domain_id` |
| HTTP path 参数 | `snake_case` | `{run_id}` |
| 事件 | `domain.action` | `model.request.completed` |
| 插件稳定名 | reverse-domain 或点分稳定名 | `example.web-fetch` |
| 逻辑模型 | `kebab-case` | `default-chat` |
| 时间 | UTC RFC 3339 | `2026-09-02T08:00:00Z` |
## ID 前缀
| 对象 | 前缀 | 生成版本 |
| --- | --- | --- |
| User | `user_` | UUIDv7 |
| PersonalDomain | `domain_` | UUIDv7 |
| Character | `character_` | UUIDv7 |
| CharacterVersion | `character_version_` | UUIDv7 |
| CharacterAsset | `character_asset_` | UUIDv7 |
| CharacterImport | `import_` | UUIDv7 |
| Export | `export_` | UUIDv7 |
| Agent | `agent_` | UUIDv7 |
| Conversation | `conversation_` | UUIDv7 |
| Branch | `branch_` | UUIDv7 |
| Message | `message_` | UUIDv7 |
| ContentBlock | `block_` | UUIDv7 |
| File | `file_` | UUIDv7 |
| Upload | `upload_` | UUIDv7 |
| Run | `run_` | UUIDv7 |
| BigCycle | `cycle_` | UUIDv7 |
| Turn | `turn_` | UUIDv7 |
| ModelCall | `model_call_` | UUIDv7 |
| ToolCall | `tool_call_` | UUIDv7 |
| Approval | `approval_` | UUIDv7 |
| Job | `job_` | UUIDv7 |
| MemoryCandidate | `memory_candidate_` | UUIDv7 |
| Memory | `memory_` | UUIDv7 |
| MemoryVersion | `memory_version_` | UUIDv7 |
| KnowledgeDocument | `knowledge_document_` | UUIDv7 |
| KnowledgeChunk | `knowledge_chunk_` | UUIDv7 |
| ContextSnapshot | `context_snapshot_` | UUIDv7 |
| PluginSnapshot | `plugin_snapshot_` | UUIDv7 |
| DiagnosticGrant | `diagnostic_grant_` | UUIDv7 |
| Workspace | `workspace_` | UUIDv7 |
| WorkspaceInvitation | `invitation_` | UUIDv7 |
| Project | `project_` | UUIDv7 |
| Review | `review_` | UUIDv7 |
| CollaborationSession | `collab_session_` | UUIDv7 |
| CommunityContent | `content_` | UUIDv7 |
| InboxThread | `inbox_thread_` | UUIDv7 |
| Report | `report_` | UUIDv7 |
| ModerationCase | `moderation_` | UUIDv7 |
| Plugin | `plugin_` | UUIDv7 |
| PluginVersion | `plugin_version_` | UUIDv7 |
| PluginInstallation | `plugin_installation_` | UUIDv7 |
| MCPServer | `mcp_` | UUIDv7 |
| Skill | `skill_` | UUIDv7 |
| ReleaseVersion | `release_` | UUIDv7 |
| MarketplaceListing | `listing_` | UUIDv7 |
| Order | `order_` | UUIDv7 |
| PaymentAttempt | `payment_` | UUIDv7 |
| Refund | `refund_` | UUIDv7 |
| Entitlement | `entitlement_` | UUIDv7 |
| LedgerEntry | `ledger_` | UUIDv7 |
| SettlementBatch | `settlement_` | UUIDv7 |
| Device | `device_` | UUIDv7 |
| DeviceGrant | `device_grant_` | UUIDv7 |
| DeviceSession | `device_session_` | UUIDv7 |
| MediaAsset | `media_` | UUIDv7 |
| MediaJob | `media_job_` | UUIDv7 |
| Voice | `voice_` | UUIDv7 |
| AvatarModel | `avatar_` | UUIDv7 |
| RealtimeVoiceSession | `voice_session_` | UUIDv7 |
| ServiceAccount | `service_account_` | UUIDv7 |
| APIKey record | `key_` | UUIDv7 |
| WebhookEndpoint | `webhook_endpoint_` | UUIDv7 |
| WebhookEvent | `webhook_event_` | UUIDv7 |
| AuditEvent | `audit_` | UUIDv7 |
| Event | `event_` | UUIDv7 |
| Request | `request_` | UUIDv4(仅服务端生成) |
| Trace record | `trace_` | UUIDv4 |
### 生成规则
- UUIDv4/UUIDv7 的位布局、variant 和文本格式遵循 RFC 9562;各语言使用经过测试的标准库或成熟实现,不自行拼位。
- 持久化业务资源、版本、事件、账务、审计和异步任务统一使用 UUIDv7,获得数据库索引局部性和大致创建顺序。
- 请求关联与 Trace record 不需要按创建时间排序,使用 UUIDv4。调用方提供的合法 `Hunjing-Request-ID` 原样保留;只有服务端补发时使用 `request_<uuidv4>`。
- 格式固定为 `<prefix><lowercase-canonical-uuid>`,例如 `memory_01941f29-7c00-7cc8-9c2a-6f4f0f2de512`;解析时必须校验前缀和 UUID version,不能只校验 UUID 文本。
- UUIDv7 内含近似生成时间,但 `created_at`、`occurred_at` 和数据库提交顺序才是权威时间;不得从 ID 推导业务时间、权限、分页结果或事件顺序。
- W3C `traceparent` 中的 `trace-id` 仍按 W3C Trace Context 生成 16 字节非零随机值并编码为 32 位小写十六进制,不添加 `trace_` 前缀,也不与 Trace record ID 混用。
- API key 明文、Diagnostic Token、CSRF token、OAuth token、Webhook secret、实时恢复 token、ExecutionTicket 和预签名 URL capability 使用 CSPRNG/对应标准生成的 opaque value,不使用 UUIDv4 或 UUIDv7。
- `Idempotency-Key`、`client_message_id`、Provider request ID 和 Provider event ID 属外部或调用方标识,按各自契约验证并原样保存,不改写成平台 UUID。
- 前缀属于公开字符串的一部分;未经本文件登记,不新增公开前缀。
## 通用枚举
### `run_status`
`queued`、`running`、`waiting_approval`、`completed`、`failed`、`cancelled`
### `memory_candidate_status`
`pending_review`、`approved`、`rejected`、`expired`
### `memory_status`
`active`、`superseded`、`archived`、`deleted`
### `memory_kind`
`fact`、`preference`、`event`、`relationship`
### `sensitivity`
`none`、`low`、`medium`、`high`
### `permission_decision`
`allow`、`ask`、`deny`
### `usage_source`
`provider`、`gateway_estimate`、`unavailable`
### `diagnostic_level`
`summary`、`detailed`、`sensitive`
### `publication_status`
`draft`、`submitted`、`published`、`limited`、`suspended`、`removed`
### `order_status`
`pending_payment`、`paid`、`partially_refunded`、`refunded`、`disputed`、`cancelled`
### `ledger_entry_type`
`charge`、`refund`、`platform_fee`、`creator_payable`、`tax`、`reserve`、`payout`、`reversal`
### `device_capability`
`file`、`camera`、`microphone`、`screen`、`location`、`notification`
### `plugin_runtime`
`bundled`、`declarative`、`remote`、`isolated_process`、`container`
### `canonical_scope`
`reality`、`world`、`simulation`
### `big_cycle_status`
`pending`、`running`、`completed`、`failed`
### `autonomy_level`
`introspective`、`rule_bound`、`approval_required`、`forbidden`
## 约束
- 未知值用 `null`,真实零值用 `0`;不能混淆。
- 金额为 `cost_minor: integer` + `currency: string`。
- 时长统一 `_ms` 非负整数。
- 哈希字段必须在 Schema 说明算法和编码。
- API 不暴露数据库实现后缀,如 `_json`。
- 客户端对新增枚举值必须走 unknown 分支,不能崩溃。
## 子文档
1. [API 总体约定](api-conventions.md)
2. [Hunjing Native API](native-api.md)
3. [模型网关兼容 API](gateway-compatible-api.md)
4. [实时 API 与 Webhook](realtime-and-webhooks.md)
5. [内部端口、事件与插件协议](internal-api.md)
6. [统一富内容与流式协议](content-blocks-and-streaming.md)
7. [1.0 API 表面总表](api-surface.md)
8. [HTTP 与事件契约](http-and-events.md)
9. [运行观测契约](run-observability.md)
10. [Lingtai C ABI](lingtai-ffi.md)
11. [Lingtai Service](lingtai-service.md)
+159
View File
@@ -0,0 +1,159 @@
# API 总体约定
## 1. API 分面
| 分面 | 基地址 | 使用者 | 稳定性 |
| --- | --- | --- | --- |
| Native API | `https://api.<deployment-domain>/v1` | Web、Tauri、第三方应用 | 公开稳定 |
| OpenAI-compatible | `https://gateway.<deployment-domain>/openai/v1` | OpenAI SDK/兼容客户端 | 对齐所声明子集 |
| Anthropic-compatible | `https://gateway.<deployment-domain>/anthropic/v1` | Anthropic SDK/兼容客户端 | 对齐所声明子集 |
| Provider Webhook | `https://api.<deployment-domain>/webhooks/v1` | 支付、媒体等 Provider | Provider 签名契约 |
| Internal Port | 进程内接口或私有网络 | Core、Worker、Sandbox、Plugin Runtime | 不公开 |
Native、兼容和内部接口不能共享权限推断。兼容入口只提供模型推理,不直接读写角色、记忆、社区、设备和交易资源。
## 2. 认证
### 2.1 1.0 认证组合
| 客户端 | 凭据 | 传输位置 |
| --- | --- | --- |
| Web | OAuth 2.1 登录后的 `__Host-hunjing_session` | `Cookie` 请求头 |
| Tauri Desktop/Mobile | Authorization Code + PKCE 获得的短期 access token | `Authorization: Bearer` |
| 第三方用户应用 | OAuth 2.1 access token | `Authorization: Bearer` |
| Service Account | 可轮换、限 scope 的 opaque API key | `Authorization: Bearer` |
| OpenAI-compatible | Service account/API key | `Authorization: Bearer` |
| Anthropic-compatible | Service account/API key | `x-api-key`;OAuth 客户端可用 `Authorization: Bearer` |
所有凭据只能通过 Header 传递,不得进入 URL、query、业务 JSON、SSE data 或 WebSocket URL。Cookie 本身是 HTTP Header;Web 的状态变更请求还必须通过 `Origin` 校验和 `Hunjing-CSRF-Token` 双提交校验。
2.0 才设计自研加密登录、刷新和设备令牌协议。1.0 不自创密码学认证协议。
### 2.2 OAuth 端点
OAuth/OIDC 元数据不放在 `/v1`:
```text
GET /.well-known/oauth-authorization-server
GET /.well-known/openid-configuration
GET /.well-known/jwks.json
GET /oauth2/authorize
POST /oauth2/token
POST /oauth2/revoke
GET /oauth2/userinfo
```
- Web 使用 Authorization Code;服务端建立 HttpOnly、Secure、`SameSite=Lax` Session Cookie。
- Tauri 使用 Authorization Code + PKCE,回调采用已登记的 loopback/deep link。
- Refresh token 只发送到 `/oauth2/token`,支持轮换和重用检测。
- Service Account API key 只显示一次,数据库只保存哈希、前缀、scope、过期和撤销状态。
## 3. 通用请求头
| Header | 必需 | 语义 |
| --- | --- | --- |
| `Authorization` 或 Web Cookie | 是 | 调用主体认证;公开匿名读取除外 |
| `Content-Type` | 有 body 时 | JSON 为 `application/json` |
| `Accept` | 推荐 | JSON、SSE 或具体媒体类型 |
| `traceparent` | 推荐 | W3C Trace Context |
| `tracestate` | 否 | 供应商追踪状态,不含敏感数据 |
| `baggage` | 否 | 登记的低敏、低基数键;不参与授权 |
| `Hunjing-Request-ID` | 推荐 | 业务请求关联;缺失时服务端生成 |
| `Idempotency-Key` | 条件必需 | 创建 Run、支付、退款、结算和副作用命令 |
| `If-Match` | 更新时推荐 | ETag 乐观并发 |
| `Hunjing-CSRF-Token` | Cookie 状态变更 | 与受保护 Cookie 值匹配 |
服务端响应回显 `Hunjing-Request-ID`、`traceparent`,资源响应提供 `ETag`。敏感 Header 必须在反向代理、APM 和应用日志完全脱敏。
## 4. 资源与 JSON
- 字段统一 `snake_case`;ID 使用契约前缀,并按[协议与稳定标识](README.md#id-前缀)校验 UUID version。
- 时间是 UTC RFC 3339;时长是非负 `_ms` 整数。
- 金额是 `{amount_minor: integer, currency: "USD"}` 或明确 Decimal string,不使用浮点。
- 不适用字段省略;已知未知值用 `null`;真实零值用 `0`。
- 创建成功返回 `201` + `Location`;同步读取/修改返回 `200`;无 body 删除返回 `204`;异步操作返回 `202` + Job/Run。
- 资源直接作为成功 body 返回,不套无意义的 `{data: ...}`;列表除外。
### 4.1 列表
```json
{
"data": [],
"next_cursor": "opaque-or-null",
"has_more": false
}
```
查询统一使用 `limit`(默认 50,最大 200)、`cursor`、`order=asc|desc`。Cursor 是 opaque,并绑定排序和稳定过滤条件;客户端不得解析。
### 4.2 乐观并发
可变资源响应提供 `ETag: "<resource-version>"`。`PATCH`、发布、合并、权限变更和关键状态动作带 `If-Match`;版本过期返回 `412 precondition_failed`,不做静默覆盖。
## 5. 命令与状态动作
- CRUD 使用 `POST/GET/PATCH/DELETE`。
- 非 CRUD、具有领域语义且需审计的动作使用子资源:
```text
POST /v1/runs/{run_id}/cancellations
POST /v1/approvals/{approval_id}/decisions
POST /v1/releases/{release_id}/publications
POST /v1/orders/{order_id}/refunds
```
不使用含糊的 `/action` 或把命令塞进 `PATCH status`。命令响应包含其创建的资源或 `202` Job。
## 6. 幂等
`Idempotency-Key` 是调用方生成的 opaque string,最长 128 字符。服务端按“认证主体 + HTTP 方法 + 路径模板 + Key”隔离,并保存规范化请求哈希:
- 相同 Key、相同请求:返回原响应和原资源 ID;
- 相同 Key、不同请求:`409 idempotency_conflict`;
- 未知副作用结果:返回原操作状态,不自动重复执行;
- Webhook 使用 Provider event ID 独立去重。
聊天消息与 Run 原子创建时,一个 Key 覆盖消息和 Run 两个资源。
## 7. 错误
```json
{
"error": {
"code": "validation_failed",
"message": "请求字段不合法。",
"trace_id": "trace_01...",
"request_id": "request_01...",
"details": {
"field_errors": [
{"path": "content.0.text", "reason": "required"}
]
}
}
}
```
- `code` 是稳定机器值;`message` 可本地化;`details` 不稳定但必须脱敏。
- 401 不泄露凭据是否存在;跨租户/跨域对象按场景返回 404。
- 429 返回 `Retry-After`;SDK 只自动重试网络、408、409(安全时)、429 和 5xx。
- 流式 HTTP 200 后错误通过事件发送,最终资源状态仍可通过 GET 查询。
## 8. API 版本
- 公共路径使用 major `/v1`;兼容入口保留其协议 `/v1`。
- 向后兼容增加字段不升 major;客户端必须忽略未知字段和枚举。
- 破坏性变更进入 `/v2`,不在同一字段上改变语义。
- Preview 能力通过明确 `Hunjing-Preview` Header 和独立 Schema,不用 `X-` 前缀。
- 1.0 实现阶段不为未发布旧契约保留兼容层;正式发布后按公开弃用策略处理。
## 9. 文件上传
大文件不经过 JSON base64:
1. `POST /v1/uploads` 创建 Upload;
2. 服务端返回单次或 multipart 预签名 URL、允许 MIME、大小和过期;
3. 客户端直传对象存储;
4. `POST /v1/uploads/{upload_id}/completions` 完成并触发校验/扫描;
5. 成功后产生 `file_` 或 `media_` 资源。
预签名 URL 属短期对象访问 capability,不是用户登录或 API 凭据,因此是“凭据不得进入 URL”的唯一受控例外。它必须短期、绑定对象路径/方法/大小/MIME,优先单次使用;不得进入 Referer、业务日志、社区内容、Message、Audit、SSE 或诊断响应。未经完成和扫描的 Upload 不能被 Agent、社区或市场引用。
+47
View File
@@ -0,0 +1,47 @@
# 1.0 API 表面总表
本表用于检查 API 是否覆盖完整 1.0;详细字段以 OpenAPI 3.1 和对应契约文档为准。
| 域 | Native REST | SSE/WS | Internal/Plugin | Webhook |
| --- | --- | --- | --- | --- |
| Identity | `/me`、domains、service accounts、devices | — | Auth/Scope Ports | Identity Provider inbound |
| Character | characters、versions、imports、exports、forks、assets | — | Importer/Exporter | release events outbound |
| Conversation | conversations、branches、messages、revisions、统一 ContentBlock | Block/Run SSE | Context/Normalization Port | message/run outbound |
| Agent | agents、runs、approvals、children | Run SSE | Model/Tool/Sandbox Ports | run outbound |
| Memory | candidates、memories、searches、knowledge | — | Memory Policy Plugin | memory outbound |
| Media | uploads、files、media jobs、voices、avatars | Voice WS | Media Plugin/Worker | media Provider inbound |
| Device | devices、grants、sessions | Device WS | Tauri Capability Port | device outbound |
| Plugin | plugins、versions、installations、MCP、skills | status events | Plugin JSON-RPC/MCP | plugin outbound |
| Community | profiles、content、comments、reactions、feeds、reports | Notification SSE | Search/Moderation Ports | content/moderation outbound |
| Inbox | threads、members、messages | notification/presence | Moderation Port | message outbound |
| Collaboration | workspaces、projects、revisions、reviews | Collaboration WS | Document/CRDT Port | workspace outbound |
| Marketplace | listings、releases、entitlements | notification | Catalog/License Ports | listing/order outbound |
| Finance | orders、payment sessions、refunds、balances、settlements | notification | Payment/Ledger Ports | payment Provider inbound |
| Diagnostics | grants、run diagnostics | optional diagnostic SSE | Observability Ports | no sensitive outbound |
| Model Gateway | no Native inference endpoint | protocol SSE | Normalized Model Port | — |
## 兼容入口
```text
OpenAI: /openai/v1/models
/openai/v1/responses
/openai/v1/chat/completions
/openai/v1/embeddings
/openai/v1/images/generations
/openai/v1/audio/transcriptions
/openai/v1/audio/speech
Anthropic: /anthropic/v1/models
/anthropic/v1/messages
/anthropic/v1/messages/count_tokens
```
## 尚待发布配置,而非 API 结构不确定项
以下在实现期以配置/TODO 落实,不改变上述资源模型:
- 首发支付、KYC、税务、对象存储、ASR/TTS、图像与模型 Provider;
- 默认分页上限、媒体大小、Run/Agent 并发和各类 Rate Limit 数值;
- 首发地区、币种、税类、内容年龄分级和保留期限;
- 结算周期、退款窗口、平台费、准备金和争议时限;
- 兼容 API 支持的具体 Provider beta 功能清单。
@@ -0,0 +1,253 @@
# 统一富内容与流式协议
## 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 同源数据,是用户可见的透明视图而非诊断特权。
不变量:重新生成不覆盖旧候答;后代节点绑定用户实际依据的候答;已归真经历不因切换候答、删除旁枝或移动工作入口而回滚;未归真旁枝不自动入忆。
+137
View File
@@ -0,0 +1,137 @@
# 模型网关兼容 API
## 1. 边界
兼容网关提供模型推理协议,不是 Hunjing 角色或 Agent Runtime 的替代入口:
```text
https://gateway.<deployment-domain>/openai/v1
https://gateway.<deployment-domain>/anthropic/v1
```
- 它可以接受工具定义并返回 tool call,但不会自动执行客户端工具。
- 它不读写 Character、Memory、Conversation、Community、DeviceGrant、Order 或 PluginInstallation。
- 需要 Hunjing 自动工具循环、多 Agent、审批和持久化时,调用 Native `/v1/runs`。
## 2. OpenAI-compatible 子集
1.0 支持:
```text
GET /openai/v1/models
POST /openai/v1/responses
POST /openai/v1/chat/completions
POST /openai/v1/embeddings
POST /openai/v1/images/generations
POST /openai/v1/audio/transcriptions
POST /openai/v1/audio/speech
```
认证:
```http
Authorization: Bearer hjk_...
```
流式响应遵循对应 OpenAI SSE 子集;响应返回 `x-request-id` 和 `Hunjing-Request-ID`。未支持的请求字段返回明确 `unsupported_parameter`,不静默忽略会改变语义的字段。
## 3. Anthropic Messages-compatible 子集
1.0 支持:
```text
GET /anthropic/v1/models
POST /anthropic/v1/messages
POST /anthropic/v1/messages/count_tokens
```
认证和版本:
```http
x-api-key: hjk_...
anthropic-version: <supported-version>
```
OAuth 客户端也可用 `Authorization: Bearer`。网关返回 `request-id` 和 `Hunjing-Request-ID`。`anthropic-beta` 只允许 Adapter 明确支持的值;未知 beta 返回 400,不透传到任意上游。
Messages Tool Use 保留 `tool_use.id` / `tool_result.tool_use_id` 关联;Thinking、cache、usage、stop reason 和 SSE block 必须按所声明兼容版本转换,无法无损映射时拒绝而非伪造。
## 4. 模型名与路由
请求 `model` 优先解析 Hunjing 逻辑模型,例如:
```text
default-chat
fast-chat
reasoning-chat
vision-chat
embedding-default
image-default
speech-default
```
管理员可允许部分上游模型别名,但业务客户端不应依赖 Provider 密钥或 Endpoint。模型配置按固定顺序继承:平台硬边界 → 平台目录 → 用户偏好/BYOK → 角色覆写 → 会话临时选择;上层约束不可被下层覆盖,会话临时选择不持久化,切换模型不得改变角色身份。能力槽(chat、vision、ASR、TTS、image generation、embedding、rerank、safety 等)由逻辑模型声明。`GET models` 只返回当前调用主体获准、在其地区可用的模型和能力。
路由依次考虑:scope、地区、隐私级别、能力、上下文、工具/结构化输出支持、预算、健康、配额和优先级。
## 5. Header 策略
客户端 Header 默认不转发。Adapter 逐 Provider 声明 allowlist,例如:协议版本、项目/组织选择和特性开关。以下字段永不直接转发:
- Hunjing 用户 `Authorization`/Cookie;
- `Hunjing-Diagnostic-Token`;
- 客户端提交的上游 API key;
- 未登记 Provider beta;
- `baggage` 中未批准的键;
- Hop-by-hop Header。
上游凭据由 Secret Store 按 Endpoint 注入。常规日志只记录允许的 Header 名和不可逆摘要,不记录值。
## 6. 重试、故障转移和流提交
```mermaid
stateDiagram-v2
[*] --> routing
routing --> requesting
requesting --> retrying : retryable before visible output
retrying --> requesting
requesting --> streaming : first visible event
requesting --> completed : non-stream success
streaming --> completed
streaming --> failed : stream error
requesting --> failed
```
- 只在首个用户可见事件前对安全的错误重试/故障转移。
- 首个可见事件后禁止切换 Provider 重新生成;当前流继续或明确失败。
- 每个 attempt 单独创建 ModelCall;SDK 自身重试也必须可观测。
- 429 遵循 `Retry-After`;上下文错误、认证、权限和内容拒绝不做同请求盲重试。
## 7. Usage 标准化
标准字段见 `run-observability.md`。关键差异:
- Anthropic `usage.input_tokens` 表示未缓存输入,缓存创建/读取单列;
- OpenAI `usage.input_tokens` 通常含 cached tokens,Adapter 计算未缓存差值;
- Provider 未返回字段存 `null`,`usage_source=unavailable`;
- 平台估算必须标记 `gateway_estimate`,不能冒充 Provider usage;
- 成本由 Hunjing 价格版本计算,不信任上游返回成本;
- 流式 usage 可能只在末尾出现,流异常时允许部分 usage 或 unavailable。
## 8. BYOK 与 Service Account
- 兼容 API 只接受 Hunjing 凭据,不接受用户把 Provider Key 当认证凭据。
- BYOK 通过 Native Secret/Endpoint 配置写入,常规读取只返回掩码和状态。
- Service Account scope 可限制模型、能力、日/月预算、RPM/TPM、IP/来源和有效期。
- 同一个 API key 不跨 PersonalDomain/Workspace 自动访问。
## 9. 错误转换
兼容入口按目标协议返回错误 envelope,同时附:
```http
Hunjing-Request-ID: request_01...
traceparent: 00-...
```
内部保留标准错误和 Provider 原错误类别。不得把 Provider 私密正文、Endpoint、密钥状态或其他租户信息暴露给兼容客户端。
+170
View File
@@ -0,0 +1,170 @@
# HTTP 与事件契约
## 1. 通用请求头
| 字段 | 方向 | 规则 |
| --- | --- | --- |
| `Authorization` | request | `Bearer <access-token>`;只经 TLS |
| `traceparent` | both | W3C Trace Context;服务边界传播并生成新 span |
| `tracestate` | both | 可选;不得包含 PII、密钥或业务正文 |
| `baggage` | both | 可选;仅传播登记的低敏、低基数键,不参与授权 |
| `Hunjing-Request-ID` | both | 调用方可提供;服务端缺失时生成;最多 64 个 `[A-Za-z0-9_-]` |
| `Idempotency-Key` | request | 创建 Run 和副作用操作使用;opaque,作用域和 TTL 由端点定义 |
| `request-id` / `x-request-id` | upstream response | 保存供应商原始 request ID,不用本地值覆盖 |
`Hunjing-Request-ID` 用于业务请求关联,不能替代 `traceparent` 的父子调用链。字段名大小写不敏感;文档使用固定大小写。新私有字段不使用 `X-` 前缀。
所有自定义字段为单值字段。重复字段、逗号列表、控制字符、空值或超长值返回 `400 invalid_request`,防止代理合并改变语义。
## 2. Header 转发
### Client → API
只读取本契约列出的字段。未知 `Hunjing-*` 字段忽略或拒绝,不自动进入插件上下文。
### API → Provider
仅允许 Adapter 白名单:供应商鉴权、版本、beta、content type、trace 和明确业务所需字段。禁止转发:
- 用户 `Authorization`;
- `Cookie`;
- `Hunjing-Diagnostic-Token`;
- 任意用户提交的供应商 API Key Header;
- Hop-by-hop fields;
- 未登记实验字段。
BYOK 密钥由服务端 Secret Store 注入。
## 3. 错误响应
```json
{
"error": {
"code": "permission_denied",
"message": "无权执行该操作。",
"trace_id": "trace_01...",
"details": {}
}
}
```
稳定 `code`:
| Code | HTTP |
| --- | ---: |
| `invalid_request` | 400 |
| `authentication_required` | 401 |
| `permission_denied` | 403 |
| `not_found` | 404 |
| `conflict` | 409 |
| `payload_too_large` | 413 |
| `validation_failed` | 422 |
| `rate_limited` | 429 |
| `provider_error` | 502 |
| `provider_unavailable` | 503 |
| `provider_timeout` | 504 |
| `internal_error` | 500 |
错误消息不得含密钥、完整 Prompt、工具敏感参数或 Provider 原始正文。
## 4. SSE
事件 envelope:
```json
{
"id": "event_01...",
"type": "content.block.delta",
"run_id": "run_01...",
"turn_id": "turn_01...",
"sequence": 12,
"created_at": "2026-09-02T08:00:00Z",
"data": {}
}
```
- `sequence` 在 Run 内单调递增。
- Block delta 为临时传输;`content.block.completed` 提供 Block 权威快照,`message.completed` 指向持久化 Message。
- HTTP 200 后仍可能发送 `error` 事件。
- 在首个用户可见 delta 发出前,Runtime 可按路由策略重试或故障转移;发出后不得切换上游重新生成另一条内容,只能继续当前流或明确失败。
- 重连使用 `Last-Event-ID`;若服务端无法重放,则客户端先拉取 Run 当前状态再继续流。
- 心跳不写业务数据库。
## 5. 稳定事件名
```text
run.queued
run.started
run.waiting_approval
run.completed
run.failed
run.cancelled
turn.started
turn.completed
model.request.started
model.request.completed
model.request.failed
model.cache.observed
message.started
content.block.started
content.block.delta
content.block.progress
content.block.completed
content.block.failed
content.block.cancelled
message.completed
tool.call.requested
tool.call.approval_required
tool.call.started
tool.call.completed
tool.call.failed
memory.candidate.created
memory.candidate.approved
memory.candidate.rejected
memory.created
memory.updated
memory.archived
memory.deleted
plugin.submitted
plugin.published
plugin.installed
plugin.activated
plugin.suspended
plugin.deactivated
plugin.removed
media.job.started
media.job.completed
media.job.failed
device.grant.created
device.grant.revoked
community.content.published
community.content.limited
community.content.removed
moderation.case.created
moderation.case.decided
workspace.member.added
workspace.member.removed
release.published
listing.published
order.created
order.paid
order.cancelled
payment.succeeded
payment.failed
refund.succeeded
dispute.opened
entitlement.granted
entitlement.revoked
ledger.entry.posted
settlement.created
settlement.paid
settlement.failed
```
事件 payload 只引用敏感对象 ID 和脱敏摘要;原文通过受保护资源 API 读取。支付和 Ledger 事件只能由交易内核产生,插件不能伪造或覆盖。
## 6. 幂等
- `POST /runs` 接受 `Idempotency-Key`,相同用户、端点和规范化请求体重复提交返回同一 Run。
- ToolCall 的幂等键由 Run、Tool definition、规范化参数和显式业务对象组成。
- 不缓存认证失败、审批拒绝和未知执行结果。
+202
View File
@@ -0,0 +1,202 @@
# 内部端口、事件与插件协议
## 1. 原则
模块化单体内部不为每个模块创建 HTTP。领域模块通过类型化 Port、Command、Query 和 Domain Event 交互;只有独立扩缩容或安全边界才使用私有网络协议。
```mermaid
flowchart LR
API[Native API] --> CMD[Application Commands]
CMD --> DOMAIN[Domain Modules]
DOMAIN --> OUTBOX[(Transactional Outbox)]
OUTBOX --> WORKER[Workers]
DOMAIN --> PORTS[Provider and Tool Ports]
PORTS --> MODEL[Model Adapters]
PORTS --> PLUGIN[Plugin RPC]
PORTS --> SANDBOX[Sandbox RPC]
```
## 2. 应用 Command
核心 Command 示例:
```text
CreateCharacter
CreateConversation
AppendConversationMessageAndStartRun
StartTaskRun
SteerRun
CancelRun
ResumeRun
DecideApproval
CreateMemoryCandidate
DecideMemoryCandidate
PublishRelease
InstallPlugin
GrantDeviceCapability
CreateOrder
ApplyPaymentEvent
CreateRefund
CreateSettlement
DecideModerationCase
```
每个 Command 包含 `command_id`、actor、scope、trace context、idempotency key、occurred_at 和类型化 payload。Handler 在一个事务中写权威状态、AuditEvent 和 OutboxEvent。
## 3. Query Port
Query 返回授权后的 DTO,不返回 ORM Entity 或裸数据库连接。调用方必须提供 actor/scope;Repository 自身再次施加数据域条件,避免只在 API 层授权。
高成本检索使用显式 Query:`SearchMemories`、`SearchCommunity`、`BuildContextSnapshot`、`CalculateOrderQuote`。交易报价必须返回 price version 和 expires_at。
## 4. Domain Event 与 Outbox
Domain Event/Outbox 记录已提交领域事实,使用 `payload` 和聚合版本;公共 SSE 使用 [HTTP 与事件契约](http-and-events.md#4-sse) 的 `data`、Run `sequence` 和公开事件名;Normalized Model Event 只存在于 Model Adapter→Runtime 流中。Runtime 必须显式完成三层映射,不把 Provider/Normalized 事件原样作为公共事件或领域事实持久化。
Event envelope:
```json
{
"id": "event_01...",
"type": "run.queued",
"aggregate_type": "run",
"aggregate_id": "run_01...",
"aggregate_version": 1,
"personal_domain_id": "domain_01...",
"trace_id": "trace_01...",
"occurred_at": "2026-09-03T08:00:00Z",
"payload": {}
}
```
消费者按 event ID 幂等。事件只陈述已提交事实,不使用 `*.requested` 假装命令。命令需要结果时调用 Application Port;异步请求创建 Job/Run 资源。
## 5. Normalized Model Port
```text
ModelGateway.invoke(NormalizedRequest) -> AsyncIterator<NormalizedEvent>
ModelGateway.count_tokens(NormalizedRequest) -> TokenCount
ModelGateway.list_models(scope) -> ModelCapabilities[]
```
`NormalizedRequest` 包含逻辑模型、标准 content blocks、tools、tool choice、output contract、thinking/effort hint、cache plan、预算、地区、隐私级别和 trace。它不包含 Provider SDK 类型。
`NormalizedEvent`:
```text
response.started
content.block.started
text.delta
thinking.summary.delta
tool.call.delta
tool.call.completed
usage.updated
response.completed
response.failed
```
Adapter 负责协议转换、Provider Header allowlist、错误分类、上游 request ID、usage 标准化和能力校验;Gateway Kernel 负责路由、重试边界、预算、ModelCall 持久化和首个可见事件提交。Runtime 将 `text.delta`、`tool.call.*` 等 Normalized Event 映射为统一 ContentBlock 与 `content.block.*` 公共 SSE;`response.*` 只控制内部调用生命周期,不直接进入公共事件表。
## 6. Tool Runtime Port
```text
ToolRegistry.snapshot(scope) -> ToolSnapshot
Policy.evaluate(ToolInvocation, ActorContext) -> PolicyDecision
ToolExecutor.execute(ExecutionTicket) -> ToolResult
```
ExecutionTicket 是短期、单 ToolCall、不可扩大权限的凭证,包含 tool/plugin version、参数 hash、文件/网络/设备范围、超时、资源限制、approval 和 idempotency key。Executor 不接受模型直接构造的票据。
ToolResult 包含 status、typed content、is_error、result size、evidence refs 和 redaction metadata。大结果落 File/Object,模型只收到摘要和引用。
## 7. Worker 与 Lease
异步 Job 具有 `queued/running/succeeded/failed/cancelled` 状态。Worker 通过私有 Queue Port:
```text
claim(queue, worker_id, lease_ms) -> JobLease | null
heartbeat(job_id, lease_token)
complete(job_id, lease_token, result_ref)
fail(job_id, lease_token, retry_class, error)
```
Lease token 只在 Header/消息元数据传递,不能成为业务 API 凭据。过期 Lease 可重新领取;副作用步骤仍依赖业务幂等键,不能仅靠 Lease 防重复。
## 8. Hunjing Plugin Protocol
通用插件协议采用 JSON-RPC 2.0:
- 本地隔离插件:stdio;
- 远程插件:HTTPS;
- Tool-only 插件优先使用 MCP;
- UI 扩展使用声明式 manifest + 隔离消息协议。
握手方法:
```text
plugin.initialize
plugin.get_manifest
plugin.list_contributions
plugin.activate
plugin.deactivate
plugin.health
```
调用方法:
```text
tool.invoke
hook.observe
hook.transform
context.provide
memory.extract_candidates
media.process
importer.inspect
importer.apply
```
每次请求带 `plugin_run_id`、PluginVersion、deadline、trace context 和短期 capability token。Host 验证响应 Schema、大小、时限和调用顺序。插件不能返回新权限,也不能调用未在 Manifest 声明的 Host service。
### 8.1 Host 回调
插件需要访问 Host 时,只能调用受限反向 RPC:
```text
host.files.read
host.objects.create
host.http.fetch
host.secrets.use_reference
host.events.publish_observation
```
Host 根据 capability token 决定范围。`secrets.use_reference` 只让代理侧在允许 host/位置注入秘密,不向插件返回明文。
## 9. Sandbox RPC
Sandbox Worker 处于独立安全边界,私有协议至少支持:
```text
sandbox.start
sandbox.execute
sandbox.read_output
sandbox.cancel
sandbox.stop
```
请求包含镜像摘要、只读/可写挂载、网络 allowlist、环境变量引用、CPU/内存/进程/时间限制和 ExecutionTicket。没有满足策略的后端时返回 `sandbox_unavailable`,禁止未隔离执行。
## 10. 支付内部端口
```text
PaymentProvider.create_session(OrderSnapshot)
PaymentProvider.verify_webhook(raw_body, headers)
PaymentProvider.refund(PaymentReference, Amount)
PayoutProvider.create_payout(SettlementSnapshot)
ReconciliationProvider.list_transactions(period)
```
Provider Adapter 不写 Ledger。交易 Application Service 在验签和幂等后写 PaymentAttempt、LedgerEntry、Entitlement、Refund 或 PayoutAttempt。所有金额与货币由权威 Order/Settlement Snapshot 提供。
## 11. 内部认证
独立服务使用 workload identity/mTLS 或短期服务令牌;不复用用户 Cookie、Service Account API key 或 DiagnosticToken。每个服务身份只获所需方法与数据域。内部 Header 同样传播 `traceparent` 和 `Hunjing-Request-ID`,但不把 `baggage` 当授权。
+114
View File
@@ -0,0 +1,114 @@
# Lingtai C ABI
灵台引擎进程内形态的公共契约。本文件是 `hj_*` 稳定符号、类型与错误码的单一登记处;机器化前以本文件为命名基线,机器化后以 `include/hunjing/lingtai.h` 与生成 Schema 为准。独立服务形态(gRPC)契约见 [Lingtai Service](lingtai-service.md),两种形态共用同一核心与语义;架构语义见[灵台引擎架构](../architecture/lingtai-engine.md)。
## 1. 适用范围与稳定性
- 消费方:官方 Python/Go/Rust 绑定与经部署者授权的第三方宿主。这是公开稳定契约,适用与 Native API 相同的演进纪律:向后兼容的新增函数不升 major;修改既有签名或语义必须升 major。
- `HjStatus` 错误码同时是服务形态错误映射的源枚举(映射表见 [Lingtai Service](lingtai-service.md));新增错误码须同步评估两种形态。
- 凭据、用户内容与密钥不经 ABI 传递;引擎无网络与持久化能力(只读索引除外),不存在凭据通道。
- 本 ABI 不是 HTTP 分面,不与 `api.<domain>/v1` 的资源契约混用;引擎产物的字段与枚举复用本目录既有契约。
## 2. 命名与符号
| 对象 | 规则 | 示例 |
| --- | --- | --- |
| 函数 | `hj_` 前缀 + `snake_case` | `hj_engine_new` |
| 不透明句柄类型 | `Hj` 前缀 | `HjEngine`、`HjStream` |
| 状态码枚举 | `HJ_OK` / `HJ_ERR_*` | `HJ_ERR_PARSE_FAILED` |
| 宏 | `HJ_` 前缀大写 | `HJ_ABI_VERSION` |
| 库文件 | `libhunjing` | `libhunjing.so` / `.dylib` / `.dll` |
| 公共头 | 单一头文件 | `include/hunjing/lingtai.h` |
- 所有导出函数为 `extern "C"`;结构体不透明(仅前向声明),字段布局不进入契约。
- 除 `hj_*` 外不导出任何符号;C++ 类、STL 类型、异常与 RTTI 不得跨越边界。
### 2.1 模块标识
六个子系统的稳定模块名(职责详见[灵台引擎架构](../architecture/lingtai-engine.md),文化名见[文化语言体系](../product/cultural-language.md)):
| 模块 | 职责摘要 |
| --- | --- |
| `hj_core` | 版本协商、句柄生命周期、状态转换校验、事件序 |
| `hj_stream` | 流事件编码、增量去重、节流与重放缓冲 |
| `hj_plan` | 计划 DAG 校验、预算核算、上下文装配计算 |
| `hj_recall` | 只读离线混合索引、重排打分、多路合并 |
| `hj_transform` | Markdown 规范化为 canonical ContentBlock |
| `hj_policy` | Schema/路径/URL 校验、验签、幂等键、决策评估 |
## 3. 版本协商
```c
#define HJ_ABI_VERSION 1
uint32_t hj_abi_version(void);
```
- `HJ_ABI_VERSION` 为当前 major;`hj_abi_version()` 返回引擎构建时的 major。
- 宿主在 `hj_engine_new` 传入所需 major;不一致时返回 `HJ_ERR_UNSUPPORTED_ABI` 且不产生句柄,禁止静默降级运行。
- 引擎实现与 parser 版本可经 `hj_engine_build_info` 查询,供宿主写入 PluginSnapshot、诊断与审计。
## 4. 生命周期与内存
- 引擎句柄:`hj_engine_new` / `hj_engine_free`;`HjEngine` 线程安全。
- 会话句柄(`HjStream`、`HjTransform`、`HjRecallSession`、`HjPolicyEval`):从 `HjEngine` 派生,单线程亲和;每个句柄有对应 `hj_*_free`。
- 缓冲区:引擎分配的输出缓冲由 `hj_buffer_free` 释放;`hj_buffer_data`/`hj_buffer_len` 读取内容。宿主不得 `free` 引擎指针,引擎不得持有返回后的宿主指针。
- 字符串:UTF-8;输入 NUL 结尾或指针加长度,输出指针加长度。
- 二次释放、句柄复用与跨线程使用会话句柄返回 `HJ_ERR_HANDLE_INVALID`,不得崩溃。
## 5. `HjStatus` 错误码
| 枚举值 | 语义 | 典型映射 |
| --- | --- | --- |
| `HJ_OK` | 成功 | — |
| `HJ_ERR_INVALID_ARGUMENT` | 参数为空、编码非法或超长 | `validation_failed` |
| `HJ_ERR_OUT_OF_MEMORY` | 引擎分配失败 | `internal` + 告警 |
| `HJ_ERR_UNSUPPORTED_ABI` | major 版本不匹配 | 启动失败 |
| `HJ_ERR_HANDLE_INVALID` | 句柄非法、已释放或跨线程 | `internal` |
| `HJ_ERR_REENTRANCY` | 回调内再入引擎 | `internal` |
| `HJ_ERR_PARSE_FAILED` | 输入无法规范解析 | `validation_failed` |
| `HJ_ERR_LIMIT_EXCEEDED` | 长度/深度/节点/预算超限 | `payload_too_large` / `limit_exceeded` |
| `HJ_ERR_POLICY_DENIED` | 策略判定拒绝 | `permission_denied` / `forbidden` |
| `HJ_ERR_SIGNATURE_INVALID` | 验签失败或时间窗外的重放 | `invalid_signature` |
| `HJ_ERR_INDEX_CORRUPT` | 只读索引校验失败 | 启动失败,要求重建索引 |
| `HJ_ERR_BUFFER_TOO_SMALL` | 输出缓冲不足(可重试扩容) | — |
| `HJ_ERR_INTERNAL` | 引擎内部错误 | `internal` |
- 新增错误码不破坏兼容;绑定层必须对未知码走失败分支,不得当作成功。
- `hj_last_error` 返回线程局部的最近错误消息(UTF-8、脱敏、不含正文与密钥);下一次引擎调用覆盖。
## 6. 数据边界
- ContentBlock、流事件与策略判定输入输出使用本目录既有 JSON Schema([统一富内容与流式协议](content-blocks-and-streaming.md));引擎输出 canonical JSON:键序确定、无空白、UTF-8,保证 content hash 可跨端复现。
- 媒体字节(图片摘要、向量、波形)经 `hj_buffer` 二进制传递,不进入 JSON。
- 限额(单消息 Block 数、源码长度、节点数、嵌套深度)由宿主配置传入并在 Schema 中保留硬上限;超限返回 `HJ_ERR_LIMIT_EXCEEDED`,引擎不得为完成解析而放宽限额。
## 7. 回调约定
```c
typedef void (*HjStreamCallback)(void *user_data,
const char *event_json,
size_t event_len);
```
- 回调在触发调用的同一线程同步执行;回调内禁止调用任何 `hj_*` 函数(`HJ_ERR_REENTRANCY`)。
- `event_json` 仅在回调期间有效;宿主需要保留必须复制。
- 回调抛出的宿主异常不得穿透引擎:绑定层捕获后中止本次调用并返回错误。
## 8. 官方绑定矩阵
| 语言 | 包名(建议) | 实现 | 错误映射 |
| --- | --- | --- | --- |
| Python | `hunjing-lingtai` | nanobind 薄封装,no-gil 标记长计算 | `HunjingEngineError` 层级 |
| Rust | `hunjing-lingtai-sys` + `hunjing-lingtai` | bindgen 生成 + 安全包装(RAII、`Result`) | `LingtaiError` enum |
| Go | `hunjing/lingtai` | cgo,绑定集中在单一包 | `errors` 哨兵值 |
- 绑定层不缓存权威状态、不补写业务语义;三端输出必须字节一致(golden 测试)。
- 绑定的内存错误(泄漏/双重释放)由各端测试矩阵覆盖,属于发布门。
## 9. 禁令清单
- 不得以宿主语言重新实现已登记的引擎能力作为回退路径。
- 不得在 ABI 边界传递凭据、Cookie、诊断令牌或用户正文以外的敏感负载。
- 不得链接未登记的引擎内部符号或依赖头文件未声明的行为。
- 不得绕过 `hj_engine_new` 的版本协商直接 dlsym 猜测符号。
- 不得将引擎错误消息原样透传给最终用户;错误本地化由宿主完成。
+77
View File
@@ -0,0 +1,77 @@
# Lingtai Service
灵台引擎独立服务形态的 gRPC 契约。本文件是服务方法、错误映射与形态边界的登记处;机器化前以本文件为命名基线,机器化后以 `proto/lingtai/v1/lingtai.proto` 为真源。进程内形态契约见 [Lingtai C ABI](lingtai-ffi.md);架构语义见[灵台引擎架构](../architecture/lingtai-engine.md)。
## 1. 适用范围与稳定性
- 消费方:同一部署内的 FastAPI 宿主、Worker、Go 网关与经部署者授权的内部系统。这是**部署内部契约**,不进入 `api.<domain>`/`gateway.<domain>` 公共分面,不经公共网关暴露,不向最终用户承诺稳定性。
- proto 按 protobuf 官方演进纪律:不修改既有字段编号与类型,新增字段由消费方忽略;破坏性变更升 `v2` 包,并行维护一个旧包的最短过渡期。
- 服务无权威状态:任何方法被路由到任一实例结果一致;实例可水平扩缩,无会话粘滞(流式方法除外,见第 5 节)。
## 2. 命名
| 对象 | 规则 | 示例 |
| --- | --- | --- |
| proto 包 | `lingtai.v<major>` | `lingtai.v1` |
| 服务 | `LingtaiEngine` | `lingtai.v1.LingtaiEngine` |
| 方法 | 模块职责 + 动词 | `TransformMarkdown`、`EvaluatePolicy` |
| 消息 | 请求/响应后缀 | `TransformMarkdownRequest` |
| 二进制 | `hunjing-lingtai-server` | 监听部署内部地址 |
字段命名使用 `snake_case`,与 [协议与稳定标识](README.md) 一致;消息字段语义与 C ABI 的 JSON 边界([统一富内容与流式协议](content-blocks-and-streaming.md))同源,不另造字段语义。
## 3. 能力与方法
| 方法 | 对应子系统 | 语义 |
| --- | --- | --- |
| `GetEngineInfo` | `hj_core` | 版本、ABI major、parser version、能力位 |
| `TransformMarkdown` | `hj_transform` | Markdown → canonical ContentBlock 列表(含 parser version) |
| `RebuildExport` | `hj_transform` | canonical Block → 可移植 Markdown 重建 |
| `OpenStream` | `hj_stream` | 双向流:宿主喂增量,服务回 `content.block.*` 事件 envelope |
| `ValidatePlan` | `hj_plan` | 计划 DAG 校验、拓扑排序与预算核算 |
| `AssembleContext` | `hj_plan` | Context Manifest 裁剪与优先级排序计算 |
| `RerankRecall` | `hj_recall` | 多路检索结果重排与合并(服务形态能力) |
| `EvaluatePolicy` | `hj_policy` | Schema/路径/URL 校验、验签、幂等键规范化、决策表评估 |
| `CheckStateTransition` | `hj_core` | Run/Turn 状态转换合法性校验 |
- 形态边界登记:`hj_recall` 的离线索引文件 mmap 仅进程内形态可用;服务形态只提供 `RerankRecall` 等 CPU 计算部分。新增单形态能力必须在本表登记。
- 所有请求携带调用方声明的限额(长度/深度/预算);服务端按部署配置二次钳制,取两者较小值。
## 4. 传输与认证
- 仅监听部署内部网络;TLS 必启,客户端与服务端双向 mTLS,证书由部署内部 CA 签发。
- 认证是工作负载身份(客户端证书/SPIFFE 类标识),不是用户凭据;用户级授权判定在宿主完成后才调用引擎,引擎不重复也不绕过用户授权。
- 不存在匿名访问;未经认证连接在握手阶段断开并记审计。
- 部署元数据(trace 上下文)经 gRPC metadata 传播,与 `traceparent` 语义一致;业务请求 ID 由宿主透传,服务不生成权威 ID。
## 5. 流式语义
- `OpenStream` 为双向流:客户端按序发送增量帧,服务端按序返回事件 envelope;事件带 `sequence` 与 `delta_index`,语义与 C ABI 回调一致。
- 一条流绑定一个服务端会话句柄;流中断(网络/超时)后会话丢弃,客户端以最终权威数据重放重建,不依赖半程状态。
- 背压:服务端按配置的内存水位暂停读取;客户端必须在水位恢复前停止发送,不得假设无限缓冲。
## 6. 错误映射
`HjStatus`([Lingtai C ABI](lingtai-ffi.md))到 gRPC status 的映射:
| `HjStatus` | gRPC code |
| --- | --- |
| `HJ_OK` | `OK` |
| `HJ_ERR_INVALID_ARGUMENT` / `HJ_ERR_PARSE_FAILED` | `INVALID_ARGUMENT` |
| `HJ_ERR_LIMIT_EXCEEDED` | `OUT_OF_RANGE` 或 `RESOURCE_EXHAUSTED`(按限额类型) |
| `HJ_ERR_POLICY_DENIED` / `HJ_ERR_SIGNATURE_INVALID` | `FAILED_PRECONDITION` 或 `PERMISSION_DENIED`(按调用语义) |
| `HJ_ERR_INDEX_CORRUPT` | `DATA_LOSS`(要求重建索引) |
| `HJ_ERR_UNSUPPORTED_ABI` | `UNIMPLEMENTED` |
| `HJ_ERR_OUT_OF_MEMORY` / `HJ_ERR_INTERNAL` | `INTERNAL` |
| `HJ_ERR_HANDLE_INVALID` / `HJ_ERR_REENTRANCY` | `INTERNAL`(进程内契约,服务面不应出现) |
- 服务自身的基础设施错误(不可达、超时、认证失败、过载)使用标准 gRPC code:`UNAVAILABLE`、`DEADLINE_EXCEEDED`、`UNAUTHENTICATED`、`UNAVAILABLE`(过载)。
- 错误 detail 不包含请求正文、密钥或凭据;宿主对 `UNAVAILABLE`/`DEADLINE_EXCEEDED` 的重试由 gRPC 重试策略统一配置,计算方法无副作用、可安全重试。
## 7. 禁令清单
- 不得把本服务经公共网关或 `api.<domain>` 暴露给外部调用方。
- 不得在服务面引入用户身份认证或授权判定(那是宿主与 Policy Core 的职责)。
- 不得让任何方法在服务形态与进程内形态产生不同语义;发现分歧按缺陷处理并以 golden 测试复现。
- 不得绕过 `GetEngineInfo` 的版本/能力协商硬编码猜测方法行为。
- 不得将引擎错误消息原样透传给最终用户;错误本地化由宿主完成。
+378
View File
@@ -0,0 +1,378 @@
# Hunjing Native API
## 1. 设计总览
Native API 是角色、对话、Agent、媒体、插件、社区、协作和交易的唯一公共业务 API。模型直接调用使用独立 Gateway 兼容入口。
聊天采用**消息与 Run 原子创建**;任务工作台采用**显式 Run 创建**:
```mermaid
sequenceDiagram
participant C as Client
participant A as Native API
participant D as Database
participant R as Agent Runtime
C->>A: POST conversation message, start_run=true
A->>D: transaction create Message and Run
D-->>A: committed resources
A-->>C: 201 message and run
A->>R: outbox run.queued
C->>A: GET run event stream
R-->>C: SSE events
```
## 2. 身份、数据域和服务账号
```text
GET /v1/me
GET /v1/personal-domains
GET /v1/personal-domains/{domain_id}
PATCH /v1/personal-domains/{domain_id}
GET /v1/service-accounts
POST /v1/service-accounts
GET /v1/service-accounts/{service_account_id}
PATCH /v1/service-accounts/{service_account_id}
DELETE /v1/service-accounts/{service_account_id}
POST /v1/service-accounts/{service_account_id}/keys
GET /v1/service-accounts/{service_account_id}/keys
DELETE /v1/service-accounts/{service_account_id}/keys/{key_id}
```
Service Account scope 显式列出资源和动作,不允许隐式继承用户全部权限。API key 明文只在创建响应出现一次。
## 3. 角色与发布版本
```text
GET /v1/characters
POST /v1/characters
GET /v1/characters/{character_id}
PATCH /v1/characters/{character_id}
DELETE /v1/characters/{character_id}
GET /v1/characters/{character_id}/versions
POST /v1/characters/{character_id}/versions
GET /v1/characters/{character_id}/versions/{version_id}
POST /v1/character-imports
GET /v1/character-imports/{import_id}
POST /v1/characters/{character_id}/exports
GET /v1/exports/{export_id}
POST /v1/character-forks
GET /v1/characters/{character_id}/assets
POST /v1/characters/{character_id}/assets
```
创建 CharacterVersion 必须带 `If-Match` 当前 Character ETag。Import 只创建待审查候选,不执行脚本、插件或宏。
## 4. 对话、消息与分支
```text
GET /v1/conversations
POST /v1/conversations
GET /v1/conversations/{conversation_id}
PATCH /v1/conversations/{conversation_id}
DELETE /v1/conversations/{conversation_id}
GET /v1/conversations/{conversation_id}/branches
POST /v1/conversations/{conversation_id}/branches
GET /v1/conversations/{conversation_id}/messages
POST /v1/conversations/{conversation_id}/messages
GET /v1/messages/{message_id}
POST /v1/messages/{message_id}/revisions
POST /v1/messages/{message_id}/regenerations
POST /v1/branches/{branch_id}/selections
POST /v1/branches/{branch_id}/transplants
```
### 4.1 原子发送消息
```http
POST /v1/conversations/{conversation_id}/messages
Idempotency-Key: msg-...
```
```json
{
"branch_id": "branch_01...",
"content": [
{"type": "text", "text": "分析这张图"},
{"type": "file", "file_id": "file_01..."}
],
"client_message_id": "client-local-id",
"start_run": true,
"run": {
"agent_id": "agent_01...",
"budget": {"max_cost_minor": 100, "currency": "USD"},
"response_mode": "stream"
}
}
```
```json
{
"message": {"id": "message_01...", "status": "accepted"},
"run": {"id": "run_01...", "status": "queued"}
}
```
`start_run=false` 只保存消息草稿/人工消息。事务失败时两个资源都不创建。`client_message_id` 用于乐观 UI 对账,不承担服务端幂等。
## 5. Agent 定义、Run 与审批
```text
GET /v1/agents
POST /v1/agents
GET /v1/agents/{agent_id}
PATCH /v1/agents/{agent_id}
GET /v1/agents/{agent_id}/versions
POST /v1/agents/{agent_id}/versions
GET /v1/runs
POST /v1/runs
GET /v1/runs/{run_id}
GET /v1/runs/{run_id}/turns
GET /v1/runs/{run_id}/children
GET /v1/runs/{run_id}/events
POST /v1/runs/{run_id}/steering-messages
POST /v1/runs/{run_id}/cancellations
POST /v1/runs/{run_id}/resumptions
GET /v1/approvals/{approval_id}
POST /v1/approvals/{approval_id}/decisions
```
### 5.1 显式任务 Run
```json
{
"agent_id": "agent_01...",
"input": [{"type": "text", "text": "整理这些资料并生成报告"}],
"resources": [
{"type": "file", "file_id": "file_01...", "access": "read_only"}
],
"budget": {
"max_cost_minor": 500,
"currency": "USD",
"max_children": 3,
"max_duration_ms": 1800000
},
"output_contract": {
"type": "artifact",
"accepted_media_types": ["text/markdown", "application/pdf"]
}
}
```
Run 创建、取消、恢复和 ApprovalDecision 都要求 `Idempotency-Key`。ApprovalDecision 值为 `allow` 或 `deny`,拒绝可带用户可见原因;审批过期后不能复用。
## 6. 记忆与知识
```text
GET /v1/characters/{character_id}/memory-candidates
POST /v1/characters/{character_id}/memory-candidates
GET /v1/memory-candidates/{candidate_id}
POST /v1/memory-candidates/{candidate_id}/decisions
GET /v1/memories
POST /v1/memories
GET /v1/memories/{memory_id}
PATCH /v1/memories/{memory_id}
DELETE /v1/memories/{memory_id}
GET /v1/memories/{memory_id}/versions
POST /v1/memory-searches
GET /v1/knowledge-documents
POST /v1/knowledge-documents
GET /v1/knowledge-documents/{document_id}
PATCH /v1/knowledge-documents/{document_id}
DELETE /v1/knowledge-documents/{document_id}
```
Memory Search 使用 POST,因为过滤、scope、rerank 和预算是结构化请求;它只读,不要求幂等键。响应必须包含命中版本、来源、各检索通道分数、重排结果、召回原因和是否进入上下文。`POST /v1/memories` 与 Candidate decision 是幂等命令;`PATCH /v1/memories/{memory_id}` 必须带 `If-Match`,纠正创建新 MemoryVersion,不原地覆盖。所有权、状态过滤、删除和 ContextSnapshot 语义见[记忆与知识架构](../architecture/memory-and-knowledge.md)。
## 7. 文件、媒体、语音、Live2D 与 3D
```text
POST /v1/uploads
GET /v1/uploads/{upload_id}
POST /v1/uploads/{upload_id}/completions
GET /v1/files/{file_id}
DELETE /v1/files/{file_id}
GET /v1/files/{file_id}/content
GET /v1/media-assets
POST /v1/media-assets
GET /v1/media-assets/{media_id}
DELETE /v1/media-assets/{media_id}
POST /v1/media-jobs
GET /v1/media-jobs/{job_id}
POST /v1/media-jobs/{job_id}/cancellations
GET /v1/voices
POST /v1/voices
POST /v1/voice-consents
DELETE /v1/voice-consents/{consent_id}
POST /v1/realtime-voice-sessions
GET /v1/avatar-models/{avatar_id}
POST /v1/avatar-models
POST /v1/avatar-models/{avatar_id}/revisions
POST /v1/avatar-models/{avatar_id}/exports
```
`media_jobs` 的 `operation` 覆盖 ASR、TTS、image generation/edit、Live2D layer/validation、VRM/glTF validation/normalization 等;参数由 operation-specific JSON Schema 校验。
## 8. 设备与权限
```text
GET /v1/devices
POST /v1/devices/registrations
GET /v1/devices/{device_id}
PATCH /v1/devices/{device_id}
DELETE /v1/devices/{device_id}
GET /v1/device-grants
POST /v1/device-grants
GET /v1/device-grants/{grant_id}
DELETE /v1/device-grants/{grant_id}
POST /v1/device-sessions
GET /v1/device-sessions/{session_id}
POST /v1/device-sessions/{session_id}/terminations
```
DeviceGrant 创建 body 显式给出 capability、character、purpose、scope、precision、foreground/background、expiry 和 retention。OS 拒绝权限时不能在服务端伪装已授权。
## 9. 插件、MCP 与 Skill
```text
GET /v1/plugins
POST /v1/plugins
GET /v1/plugins/{plugin_id}
GET /v1/plugins/{plugin_id}/versions
POST /v1/plugins/{plugin_id}/versions
GET /v1/plugin-versions/{version_id}
POST /v1/plugin-versions/{version_id}/submissions
GET /v1/plugin-installations
POST /v1/plugin-installations
GET /v1/plugin-installations/{installation_id}
PATCH /v1/plugin-installations/{installation_id}
DELETE /v1/plugin-installations/{installation_id}
POST /v1/plugin-installations/{installation_id}/permission-decisions
GET /v1/mcp-servers
POST /v1/mcp-servers
PATCH /v1/mcp-servers/{server_id}
DELETE /v1/mcp-servers/{server_id}
GET /v1/skills
POST /v1/skills
```
上传 PluginVersion 不等于发布;购买不等于安装;安装不等于启用;升级新增权限必须重新创建 PermissionDecision。
## 10. Workspace 与协作
```text
GET /v1/workspaces
POST /v1/workspaces
GET /v1/workspaces/{workspace_id}
PATCH /v1/workspaces/{workspace_id}
GET /v1/workspaces/{workspace_id}/members
POST /v1/workspaces/{workspace_id}/invitations
DELETE /v1/workspaces/{workspace_id}/members/{user_id}
PATCH /v1/workspaces/{workspace_id}/members/{user_id}
GET /v1/projects
POST /v1/projects
GET /v1/projects/{project_id}
PATCH /v1/projects/{project_id}
GET /v1/projects/{project_id}/revisions
POST /v1/projects/{project_id}/revisions
POST /v1/projects/{project_id}/reviews
POST /v1/reviews/{review_id}/decisions
POST /v1/collaboration-sessions
```
成员编辑、评审、发布、市场上架和财务权限分离。权限变更、合并和发布要求 ETag/If-Match。
## 11. 社区与服务端治理私信
```text
GET /v1/profiles/{user_id}
PUT /v1/me/following/{user_id}
DELETE /v1/me/following/{user_id}
PUT /v1/me/blocks/{user_id}
DELETE /v1/me/blocks/{user_id}
GET /v1/community-content
POST /v1/community-content
GET /v1/community-content/{content_id}
PATCH /v1/community-content/{content_id}
DELETE /v1/community-content/{content_id}
GET /v1/community-content/{content_id}/comments
POST /v1/community-content/{content_id}/comments
PUT /v1/community-content/{content_id}/reactions/{reaction}
DELETE /v1/community-content/{content_id}/reactions/{reaction}
GET /v1/feeds/home
POST /v1/community-searches
POST /v1/reports
GET /v1/moderation-cases/{case_id}
POST /v1/moderation-cases/{case_id}/appeals
GET /v1/inbox/threads
POST /v1/inbox/threads
GET /v1/inbox/threads/{thread_id}/messages
POST /v1/inbox/threads/{thread_id}/messages
PATCH /v1/inbox/threads/{thread_id}/members/{user_id}
DELETE /v1/inbox/threads/{thread_id}/members/{user_id}
```
私信和小群聊使用服务端加密存储、多端同步、举报、屏蔽和审核,不承诺端到端加密。私信与角色 Conversation 使用不同资源类型和权限,避免混淆。
## 12. 市场、订单、支付与结算
```text
GET /v1/marketplace-listings
POST /v1/marketplace-listings
GET /v1/marketplace-listings/{listing_id}
PATCH /v1/marketplace-listings/{listing_id}
POST /v1/marketplace-listings/{listing_id}/publications
GET /v1/orders
POST /v1/orders
GET /v1/orders/{order_id}
POST /v1/orders/{order_id}/payment-sessions
POST /v1/orders/{order_id}/refunds
GET /v1/refunds/{refund_id}
GET /v1/entitlements
GET /v1/entitlements/{entitlement_id}
GET /v1/creator-accounts/{creator_id}
PATCH /v1/creator-accounts/{creator_id}
GET /v1/creator-accounts/{creator_id}/balances
GET /v1/creator-accounts/{creator_id}/settlements
GET /v1/settlements/{settlement_id}
GET /v1/creator-accounts/{creator_id}/statements
```
客户端不能提交权威金额。创建 Order 只接受 listing/version/quantity/coupon 等业务输入,服务端计算价格、税、许可和卖家快照。Payment/Refund/Payout 结果以验签 Webhook 和 Ledger 为准。
## 13. 通知、Webhook 和导出删除
```text
GET /v1/notifications
POST /v1/notifications/{notification_id}/reads
GET /v1/webhook-endpoints
POST /v1/webhook-endpoints
PATCH /v1/webhook-endpoints/{endpoint_id}
DELETE /v1/webhook-endpoints/{endpoint_id}
POST /v1/webhook-endpoints/{endpoint_id}/secret-rotations
POST /v1/data-exports
GET /v1/data-exports/{export_id}
POST /v1/deletion-requests
GET /v1/deletion-requests/{deletion_id}
```
Webhook secret 明文只在创建/轮换响应出现一次。导出和删除是异步资源,具有 scope、状态、进度、失败和审计,不使用一个全能同步端点。
## 14. 受保护诊断
```text
POST /v1/diagnostic-grants
GET /v1/diagnostic-grants/{grant_id}
DELETE /v1/diagnostic-grants/{grant_id}
GET /v1/runs/{run_id}/diagnostics
GET /v1/runs/{run_id}/diagnostics/turns/{turn_id}
```
诊断查询同时要求普通认证和:
```http
Hunjing-Diagnostic-Token: hjd_...
Hunjing-Diagnostic-Purpose: user_inspection
```
Grant 绑定 subject、domain、run/turn、scope、level、purpose、expiry 和 uses。普通 Run API 不返回模型 attempt、脱敏工具参数或 Context Manifest 明细。
+168
View File
@@ -0,0 +1,168 @@
# 实时 API 与 Webhook
## 1. 传输选择
| 场景 | 传输 | 原因 |
| --- | --- | --- |
| Run 文本/工具/状态输出 | SSE | 单向、可重连、HTTP 友好 |
| 实时语音 | WebSocket | 双向音频和控制 |
| 协同编辑/presence | WebSocket | 双向低延迟 |
| 设备会话 | WebSocket | 双向命令、状态和取消 |
| 普通通知 | SSE 或分页 GET | 无需双向连接 |
| 外部系统通知 | HTTPS Webhook | 异步推送 |
WebSocket 认证也只通过 Header:Web 使用 Cookie handshake;Tauri 使用 `Authorization: Bearer`。禁止 query token。
## 2. Run SSE
```http
GET /v1/runs/{run_id}/events
Accept: text/event-stream
Last-Event-ID: event_01...
```
事件格式沿用 `http-and-events.md`:`id`、`type`、`run_id`、`turn_id`、`sequence`、`created_at`、`data`。
规则:
- 连接先发送当前 `run.snapshot`,再发送新事件;
- `Last-Event-ID` 在保留窗口内重放;超出窗口返回 `409 event_cursor_expired`,客户端 GET Run/Message 后重连;
- `content.block.delta` 是预览,`content.block.completed` 提供 Block 权威快照,`message.completed` 指向权威 Message;
- `heartbeat` 不写业务表;
- `run.completed|failed|cancelled` 是终止事件;
- 客户端对 event ID 去重,不仅依赖 TCP 恰好一次。
## 3. WebSocket 通用握手
```http
GET /v1/realtime/voice/{session_id}
Upgrade: websocket
Sec-WebSocket-Protocol: hunjing.realtime.v1
Authorization: Bearer ...
```
Web 使用 Cookie 替代 Authorization。连接成功后第一帧:
```json
{
"type": "session.ready",
"session_id": "...",
"resume_token": "short-lived-opaque",
"capabilities": [],
"heartbeat_interval_ms": 15000
}
```
`resume_token` 只在后续同认证主体的 Header `Hunjing-Realtime-Resume` 使用,不放 URL;短期、单会话、可撤销。
JSON 控制帧统一包含 `type`、`event_id`、`sequence`、`sent_at`。二进制帧只承载协商后的音频/媒体块,元数据由前置 JSON frame 描述。
## 4. 实时语音
```text
POST /v1/realtime-voice-sessions
WS /v1/realtime/voice/{session_id}
POST /v1/realtime-voice-sessions/{session_id}/terminations
```
主要帧:
```text
input_audio.start
input_audio.chunk
input_audio.commit
transcript.delta
transcript.completed
agent.text.delta
output_audio.start
output_audio.chunk
output_audio.completed
response.interrupt
session.error
session.completed
```
- 音频 codec、采样率、语言和端点检测在 Session 创建时协商。
- `response.interrupt` 取消当前模型和 TTS,不删除已固化用户段。
- 服务端施加最大帧、带宽、静音、会话时长和费用预算。
- 原始音频保留策略在 Session 创建响应明确返回。
## 5. 协同编辑
```text
POST /v1/collaboration-sessions
WS /v1/realtime/collaboration/{session_id}
```
帧:`presence.joined/left`、`document.operation`、`document.ack`、`cursor.updated`、`review.updated`、`session.error`。每个 operation 带 client operation ID、base version 和资源 ID;服务端按 ACL 校验。不能通过协同通道编辑支付账、审批记录或已发布不可变版本。
## 6. 设备会话
```text
POST /v1/device-sessions
WS /v1/realtime/devices/{session_id}
```
帧:`capability.state`、`capture.started/chunk/completed`、`permission.changed`、`session.pause/resume/terminate`、`device.error`。每帧校验 DeviceGrant;撤权后连接立即停止相关 capability。Tauri 不暴露通用 Shell frame。
## 7. 社区通知
```http
GET /v1/notifications/events
Accept: text/event-stream
```
只发送薄事件:notification ID、type、resource ID、created_at;正文通过 Native API 按当前权限读取。屏蔽或权限变化后旧通知不能成为资源读取旁路。
## 8. Hunjing Outbound Webhook
```text
GET /v1/webhook-endpoints
POST /v1/webhook-endpoints
PATCH /v1/webhook-endpoints/{endpoint_id}
DELETE /v1/webhook-endpoints/{endpoint_id}
POST /v1/webhook-endpoints/{endpoint_id}/secret-rotations
```
投递 Header:
```http
Hunjing-Webhook-ID: webhook_event_01...
Hunjing-Webhook-Timestamp: 178...
Hunjing-Webhook-Signature: v1=<base64url-hmac>
```
签名输入是:`id + "." + timestamp + "." + raw_body`。接收方验证原始字节、时间窗和 event ID 去重。Secret 明文只显示一次,支持新旧 Secret 短期重叠轮换。
Envelope:
```json
{
"id": "webhook_event_01...",
"type": "run.completed",
"created_at": "2026-09-03T08:00:00Z",
"data": {
"resource_id": "run_01...",
"personal_domain_id": "domain_01..."
}
}
```
Webhook 是薄通知,不包含消息正文、工具参数、支付敏感数据或诊断内容。接收方用自己的凭据读取资源。
投递至少一次、不保证顺序;2xx 确认,3xx 不跟随,失败指数退避并有死信/管理重放。删除事件可能无法再次读取资源,Envelope 保留最小墓碑信息。
## 9. Provider Inbound Webhook
```text
POST /webhooks/v1/payments/{provider}
POST /webhooks/v1/media/{provider}
POST /webhooks/v1/identity/{provider}
```
- 先读取 raw body,再按 Provider 官方 SDK/算法验签;
- 验签前不解析为业务命令;
- 按 Provider event ID 幂等,保存接收、验证、处理状态和不可逆 body hash;
- 不依赖事件顺序,必要时向 Provider 主动查询当前状态;
- 快速返回 Provider 要求的 2xx,重处理进入内部 Job;
- 业务结果由 Ledger/权威资源决定,不由单个 Webhook body 直接覆盖。
+132
View File
@@ -0,0 +1,132 @@
# 运行观测契约
## 1. 聚合层次
```text
Run
└─ Turn
├─ ModelCall attempt
└─ ToolCall
```
普通 Run API 返回状态、可见消息和聚合 usage;详细对象只通过诊断 API 返回。
## 2. `turn`
必需字段:
- `id`、`run_id`、可选 `parent_turn_id`;
- `turn_index`、`status`、`started_at`、`ended_at`;
- `input_message_ids`、`output_message_ids`;
- `context_snapshot_id`、`plugin_snapshot_id`;
- `finish_reason`、`error_code`、`trace_id`。
## 3. `model_call`
每次上游 attempt 单独记录:
| 字段 | 说明 |
| --- | --- |
| `id`、`turn_id`、`attempt_index` | 关联和重试顺序 |
| `provider`、`endpoint_id` | 实际上游 |
| `logical_model`、`upstream_model` | 业务模型与实际模型 |
| `request_started_at`、`first_token_at`、`completed_at` | 时间点 |
| `latency_ms`、`time_to_first_token_ms` | 延迟 |
| `input_tokens` | 未缓存输入 |
| `cache_creation_input_tokens` | Provider 缓存写入 |
| `cache_read_input_tokens` | Provider 缓存读取 |
| `output_tokens` | Provider 输出 |
| `reasoning_tokens` | 供应商明确返回时记录数量 |
| `audio_*`、`image_*` | 适用且供应商返回时记录 |
| `cache_hit` | `true` / `false` / `null` |
| `cost_minor`、`currency`、`price_version` | 可重算成本 |
| `request_id`、`upstream_request_id` | 本地与供应商请求关联 |
| `finish_reason`、`error_type`、`error_code` | 结果 |
| `usage_source` | provider / estimate / unavailable |
总输入:
```text
total_input_tokens =
input_tokens +
cache_creation_input_tokens +
cache_read_input_tokens
```
`cache_hit=true` 仅当 `cache_read_input_tokens > 0`;供应商明确返回 0 时为 false;未提供相关字段时为 null。
上述公式定义的是 **Hunjing 标准化语义**。Adapter 必须先处理供应商差异:Anthropic 的 `input_tokens` 是未缓存部分,可直接映射;OpenAI 的 `input_tokens` 通常包含 `input_tokens_details.cached_tokens`,因此标准化时将后者映射到 `cache_read_input_tokens`,并将两者之差映射到本字段的 `input_tokens`。原始 usage 经脱敏后另存 `usage_raw_redacted`,便于核对,不能直接混加造成重复计数。
| 标准字段 | Anthropic | OpenAI |
| --- | --- | --- |
| `upstream_request_id` | `request-id` / error `request_id` | `x-request-id` |
| `input_tokens` | `usage.input_tokens` | `usage.input_tokens - usage.input_tokens_details.cached_tokens` |
| `cache_read_input_tokens` | `usage.cache_read_input_tokens` | `usage.input_tokens_details.cached_tokens` |
| `cache_creation_input_tokens` | `usage.cache_creation_input_tokens` | 无对应字段时为 `null` |
| `output_tokens` | `usage.output_tokens` | `usage.output_tokens` |
字段路径按具体 API 端点和 SDK 版本适配;表中缺失表示“该端点未返回”,不是数值 0。
## 4. 字段来源
### 供应商原生
供应商返回且 Adapter 原样标准化:
- 上游模型 ID;
- request ID;
- stop/finish reason;
- input/output/cache/reasoning token(若存在);
- server tool usage(若存在);
- 供应商错误类型。
### 平台计算
- `latency_ms`、`time_to_first_token_ms`;
- logical model、endpoint、attempt index;
- 成本与价格版本;
- cache hit 三态;
- retry/fallback 关联;
- Context 和 Plugin snapshot;
- 业务 trace。
平台计算字段不能标记 `usage_source=provider`。
## 5. `tool_call`
字段:
- `id`、`turn_id`、`step_index`、`call_index`;
- `tool_id`、`plugin_id`、`plugin_version`、`execution_backend`;
- `arguments_redacted`、`arguments_hash`、`redaction_status`;
- `result_redacted`、`result_size_bytes`、`is_error`;
- `status`、`error_code`、`started_at`、`ended_at`、`latency_ms`;
- `confirmation_id`、`policy_decision_id`;
- `trace_id`、`idempotency_key`、`evidence_ids`。
常规表禁止保存 Authorization、密钥、签名 URL、文件原文和第三方高敏正文。
## 6. Context Manifest
ContextSnapshot 保存:
- 来源对象 ID 与版本;
- 来源类型:system、character、message、memory、knowledge、tool result;
- 每项估算或真实 token;
- 采用、裁剪、压缩或拒绝原因;
- 最终顺序和不可逆内容摘要;
- cache breakpoint 位置与 Provider cache usage。
不保存隐藏 chain-of-thought。完整 Prompt 仅在用户明确生成敏感支持包时限期保存。
## 7. 普通与诊断响应
| 数据 | 普通 Run API | Summary | Detailed | Sensitive |
| --- | ---: | ---: | ---: | ---: |
| 状态、可见消息 | 是 | 是 | 是 | 是 |
| 聚合 token/cost | 是 | 是 | 是 | 是 |
| Model attempt | 否 | 摘要 | 是 | 是 |
| Tool 名、状态、耗时 | 否 | 是 | 是 | 是 |
| 脱敏参数/结果 | 否 | 否 | 是 | 是 |
| 受限敏感内容 | 否 | 否 | 否 | 额外确认 |
| 隐藏推理 | 否 | 否 | 否 | 否 |