📝 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:
commit
42513d13c6
37 files changed
+5795
No files matched your search
@@ -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)
|
||||
@@ -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、社区或市场引用。
|
||||
@@ -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 同源数据,是用户可见的透明视图而非诊断特权。
|
||||
|
||||
不变量:重新生成不覆盖旧候答;后代节点绑定用户实际依据的候答;已归真经历不因切换候答、删除旁枝或移动工作入口而回滚;未归真旁枝不自动入忆。
|
||||
@@ -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、密钥状态或其他租户信息暴露给兼容客户端。
|
||||
@@ -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、规范化参数和显式业务对象组成。
|
||||
- 不缓存认证失败、审批拒绝和未知执行结果。
|
||||
@@ -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` 当授权。
|
||||
@@ -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 猜测符号。
|
||||
- 不得将引擎错误消息原样透传给最终用户;错误本地化由宿主完成。
|
||||
@@ -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` 的版本/能力协商硬编码猜测方法行为。
|
||||
- 不得将引擎错误消息原样透传给最终用户;错误本地化由宿主完成。
|
||||
@@ -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 明细。
|
||||
@@ -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 直接覆盖。
|
||||
@@ -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 名、状态、耗时 | 否 | 是 | 是 | 是 |
|
||||
| 脱敏参数/结果 | 否 | 否 | 是 | 是 |
|
||||
| 受限敏感内容 | 否 | 否 | 否 | 额外确认 |
|
||||
| 隐藏推理 | 否 | 否 | 否 | 否 |
|
||||
Reference in new issue
Block a user