openapi: 3.1.0 info: title: Hunjing API version: 0.1.0 summary: Hunjing 平台公共契约(OpenAPI 3.1 单一真源) license: name: Apache-2.0 identifier: Apache-2.0 description: | 本文件由 docs/contracts/ 机器化而来,是公共 HTTP 契约的单一真源; TypeScript/Rust 客户端由本文件生成,不手写重复 DTO。 当前版本覆盖阶段 0 所需基础:错误体、分页、Money、平台 ID、 统一 ContentBlock(21 类型)与流事件 envelope;资源端点随工作包增量登记。 jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema servers: - url: https://api.example.dev/v1 description: Native API(开发占位,正式域名见 docs/contracts/api-conventions.md) paths: /healthz: get: operationId: getHealth tags: [ops] summary: 服务健康探针 security: [] responses: "200": description: 服务正常 content: application/json: schema: type: object required: [status] properties: status: { type: string, enum: [ok] } env: { type: string } default: description: 错误 content: application/json: schema: { $ref: "#/components/schemas/ErrorEnvelope" } components: schemas: # ===== 通用:错误体(api-conventions 第 7 节) ===== Error: type: object required: [code, message] properties: code: type: string description: 稳定机器错误码 examples: [validation_failed] message: { type: string, description: 可本地化消息 } trace_id: { type: string, format: uuid } request_id: { type: string } details: type: object additionalProperties: true description: 不稳定细节,必须脱敏 ErrorEnvelope: type: object required: [error] properties: error: { $ref: "#/components/schemas/Error" } # ===== 通用:分页(opaque cursor) ===== CursorPage: type: object required: [data, next_cursor, has_more] properties: data: { type: array, items: {} } next_cursor: oneOf: [{ type: string }, { type: "null" }] description: opaque cursor;客户端不得解析 has_more: { type: boolean } # ===== 通用:金额(最小货币单位整数,禁止浮点) ===== Money: type: object required: [amount_minor, currency] properties: amount_minor: { type: integer, minimum: 0 } currency: { type: string, pattern: "^[A-Z]{3}$" } # ===== 平台 ID(ADR-015:;首批按垂直切片登记) ===== UserId: { type: string, pattern: "^user_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } PersonalDomainId: { type: string, pattern: "^domain_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } ConversationId: { type: string, pattern: "^conversation_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } BranchId: { type: string, pattern: "^branch_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } MessageId: { type: string, pattern: "^message_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } ContentBlockId: { type: string, pattern: "^block_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } RunId: { type: string, pattern: "^run_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } TurnId: { type: string, pattern: "^turn_[0-9a-f]{12}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" } RequestId: { type: string, pattern: "^request_[0-9a-f]{12}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", description: 服务端生成,UUIDv4 } # ===== 统一 ContentBlock(content-blocks-and-streaming 第 2-3 节) ===== BlockStatus: type: string enum: [pending, streaming, completed, failed, cancelled] BlockAnnotation: type: object description: 类型化标注(citation/来源/敏感度/语言) additionalProperties: true BlockBase: type: object required: [id] properties: id: { $ref: "#/components/schemas/ContentBlockId" } status: { $ref: "#/components/schemas/BlockStatus" } annotations: type: array items: { $ref: "#/components/schemas/BlockAnnotation" } metadata: type: object description: 只允许 Schema 登记字段,不存任意秘密 additionalProperties: true TextBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [text] properties: type: { type: string, enum: [text] } text: { type: string } language: { type: string } MarkdownBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [text] properties: type: { type: string, enum: [markdown] } text: { type: string } flavor: { type: string, enum: [hunjing-gfm-v1] } CodeBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [source] properties: type: { type: string, enum: [code] } source: { type: string } language: { type: string } filename: { type: string } QuoteBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [content] properties: type: { type: string, enum: [quote] } content: type: array items: { $ref: "#/components/schemas/ContentBlock" } source_ref: { type: string } TableBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [columns, rows] properties: type: { type: string, enum: [table] } columns: { type: array, items: { type: string } } rows: { type: array, items: { type: array, items: {} } } caption: { type: string } CalloutBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [kind, content] properties: type: { type: string, enum: [callout] } kind: { type: string, enum: [info, warning, danger, success] } title: { type: string } content: type: array items: { $ref: "#/components/schemas/ContentBlock" } MathBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [notation, display, source] properties: type: { type: string, enum: [math] } notation: { type: string, enum: [latex, asciimath] } display: { type: string, enum: [inline, block] } source: { type: string } fallback_text: { type: string, description: 可访问性与解析失败降级描述 } label: { type: string } MermaidBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [source] properties: type: { type: string, enum: [mermaid] } source: { type: string } title: { type: string } caption: { type: string } fallback_code_language: { type: string, default: mermaid } ImageBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [alt] properties: type: { type: string, enum: [image] } file_id: { type: string } url_ref: { type: string, description: "受控 URL;禁止 file://、javascript: 等协议" } alt: { type: string } width: { type: integer, minimum: 1 } height: { type: integer, minimum: 1 } caption: { type: string } VideoBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [file_id] properties: type: { type: string, enum: [video] } file_id: { type: string } poster_file_id: { type: string } caption: { type: string } transcript_file_id: { type: string } duration_ms: { type: integer, minimum: 0 } AudioBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [file_id] properties: type: { type: string, enum: [audio] } file_id: { type: string } transcript: { type: string } duration_ms: { type: integer, minimum: 0 } waveform: { type: string } FileBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [file_id, filename, media_type, size_bytes] properties: type: { type: string, enum: [file] } file_id: { type: string } filename: { type: string } media_type: { type: string } size_bytes: { type: integer, minimum: 0 } description: { type: string } GalleryBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [items] properties: type: { type: string, enum: [gallery] } items: type: array items: oneOf: - $ref: "#/components/schemas/ImageBlock" - $ref: "#/components/schemas/VideoBlock" layout: { type: string } AvatarBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [asset_id, format] properties: type: { type: string, enum: [avatar] } asset_id: { type: string } format: { type: string, enum: [live2d, vrm, gltf] } preview_file_id: { type: string } ToolCallBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [tool_name, call_id] properties: type: { type: string, enum: [tool_call] } tool_name: { type: string } call_id: { type: string } arguments_redacted: { type: object, description: 参数脱敏视图 } approval_id: { type: string } ToolResultBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [call_id] properties: type: { type: string, enum: [tool_result] } call_id: { type: string } summary: { type: object, additionalProperties: true } file_ids: { type: array, items: { type: string } } is_error: { type: boolean } AgentStatusBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [stage] properties: type: { type: string, enum: [agent_status] } agent_id: { type: string } child_run_id: { type: string } stage: { type: string } progress: { type: object, additionalProperties: true } waiting_reason: { type: string } ApprovalRequestBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [approval_id, action] properties: type: { type: string, enum: [approval_request] } approval_id: { type: string } action: { type: string } impact: { type: string } arguments_summary: { type: object, additionalProperties: true } expires_at: { type: string, format: date-time } ArtifactBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [artifact_id, artifact_type] properties: type: { type: string, enum: [artifact] } artifact_id: { type: string } artifact_type: { type: string } version: { type: integer } CitationBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [source_id, title, quoted_text] properties: type: { type: string, enum: [citation] } source_id: { type: string } title: { type: string } quoted_text: { type: string } locator: type: object description: 定位(文本区间、图像区域、PDF 页区、音视频时间码)与原文快照 additionalProperties: true ErrorBlock: allOf: - $ref: "#/components/schemas/BlockBase" - type: object required: [message] properties: type: { type: string, enum: [error] } message: { type: string } retryable: { type: boolean } fallback: { type: string } ContentBlock: oneOf: - $ref: "#/components/schemas/TextBlock" - $ref: "#/components/schemas/MarkdownBlock" - $ref: "#/components/schemas/CodeBlock" - $ref: "#/components/schemas/QuoteBlock" - $ref: "#/components/schemas/TableBlock" - $ref: "#/components/schemas/CalloutBlock" - $ref: "#/components/schemas/MathBlock" - $ref: "#/components/schemas/MermaidBlock" - $ref: "#/components/schemas/ImageBlock" - $ref: "#/components/schemas/VideoBlock" - $ref: "#/components/schemas/AudioBlock" - $ref: "#/components/schemas/FileBlock" - $ref: "#/components/schemas/GalleryBlock" - $ref: "#/components/schemas/AvatarBlock" - $ref: "#/components/schemas/ToolCallBlock" - $ref: "#/components/schemas/ToolResultBlock" - $ref: "#/components/schemas/AgentStatusBlock" - $ref: "#/components/schemas/ApprovalRequestBlock" - $ref: "#/components/schemas/ArtifactBlock" - $ref: "#/components/schemas/CitationBlock" - $ref: "#/components/schemas/ErrorBlock" discriminator: propertyName: type # ===== 流事件 envelope(content-blocks-and-streaming 第 5 节) ===== StreamEvent: type: object required: [type, data] properties: type: type: string enum: [ content.block.started, content.block.delta, content.block.progress, content.block.completed, content.block.failed, content.block.cancelled, message.completed, ] data: { type: object, additionalProperties: true } sequence: type: integer minimum: 0 description: Run 内单调递增