feat(api): 统一官方兼容接口响应协议

兼容接口现在以入口协议作为最终响应协议,同协议保留官方 Wire 响应,跨协议统一转换成功、任务状态与错误结构。

同时修正异步提交状态边界,持久化兼容公开任务标识和官方提交响应,并新增迁移、流式响应及协议契约测试。

验证:go vet ./...;go test ./...;govulncheck ./...;pnpm lint;pnpm test;pnpm build;pnpm audit --audit-level high;pnpm openapi;全部 CI 脚本。
This commit is contained in:
2026-07-22 15:34:59 +08:00
parent 42e8b517fd
commit e07a997aa9
32 changed files with 2436 additions and 591 deletions
+327 -163
View File
@@ -5469,43 +5469,43 @@
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"402": {
"description": "Payment Required",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"429": {
"description": "Too Many Requests",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
}
}
@@ -5532,6 +5532,18 @@
"type": "object",
"additionalProperties": true
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
}
}
},
@@ -5556,8 +5568,31 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": true
"$ref": "#/definitions/httpapi.VolcesContentsGenerationTaskResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
},
"429": {
"description": "Too Many Requests",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
}
}
@@ -5590,8 +5625,13 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": true
"$ref": "#/definitions/httpapi.VolcesContentsGenerationTaskResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
}
}
@@ -5623,8 +5663,13 @@
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": true
"$ref": "#/definitions/httpapi.VolcesContentsGenerationTaskResponse"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/httpapi.VolcesErrorEnvelope"
}
}
}
@@ -5637,7 +5682,6 @@
"BearerAuth": []
}
],
"description": "统一公开入口按 model 选择平台模型并默认同步返回兼容响应;设置 X-Async=true 时异步创建任务并返回 202。",
"consumes": [
"application/json"
],
@@ -5645,24 +5689,12 @@
"application/json"
],
"tags": [
"tasks"
"embeddings"
],
"summary": "创建或执行 AI 任务",
"summary": "创建 OpenAI Embeddings",
"parameters": [
{
"type": "boolean",
"description": "true 时异步创建任务并返回 202",
"name": "X-Async",
"in": "header"
},
{
"type": "string",
"description": "可选请求幂等键;同一用户范围内唯一",
"name": "Idempotency-Key",
"in": "header"
},
{
"description": "AI 任务请求,字段随任务类型变化",
"description": "OpenAI Embeddings 请求",
"name": "input",
"in": "body",
"required": true,
@@ -5678,52 +5710,28 @@
"$ref": "#/definitions/httpapi.CompatibleResponse"
}
},
"202": {
"description": "Accepted",
"schema": {
"$ref": "#/definitions/httpapi.TaskAcceptedResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"402": {
"description": "Payment Required",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"429": {
"description": "Too Many Requests",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
}
}
@@ -5930,7 +5938,6 @@
"BearerAuth": []
}
],
"description": "统一公开入口按 model 选择平台模型并默认同步返回兼容响应;设置 X-Async=true 时异步创建任务并返回 202。",
"consumes": [
"application/json"
],
@@ -5938,24 +5945,12 @@
"application/json"
],
"tags": [
"tasks"
"images"
],
"summary": "创建或执行 AI 任务",
"summary": "创建或编辑 OpenAI Images",
"parameters": [
{
"type": "boolean",
"description": "true 时异步创建任务并返回 202",
"name": "X-Async",
"in": "header"
},
{
"type": "string",
"description": "可选请求幂等键;同一用户范围内唯一",
"name": "Idempotency-Key",
"in": "header"
},
{
"description": "AI 任务请求,字段随任务类型变化",
"description": "OpenAI Images 请求",
"name": "input",
"in": "body",
"required": true,
@@ -5971,52 +5966,28 @@
"$ref": "#/definitions/httpapi.CompatibleResponse"
}
},
"202": {
"description": "Accepted",
"schema": {
"$ref": "#/definitions/httpapi.TaskAcceptedResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"402": {
"description": "Payment Required",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"429": {
"description": "Too Many Requests",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
}
}
@@ -6029,7 +6000,6 @@
"BearerAuth": []
}
],
"description": "统一公开入口按 model 选择平台模型并默认同步返回兼容响应;设置 X-Async=true 时异步创建任务并返回 202。",
"consumes": [
"application/json"
],
@@ -6037,24 +6007,12 @@
"application/json"
],
"tags": [
"tasks"
"images"
],
"summary": "创建或执行 AI 任务",
"summary": "创建或编辑 OpenAI Images",
"parameters": [
{
"type": "boolean",
"description": "true 时异步创建任务并返回 202",
"name": "X-Async",
"in": "header"
},
{
"type": "string",
"description": "可选请求幂等键;同一用户范围内唯一",
"name": "Idempotency-Key",
"in": "header"
},
{
"description": "AI 任务请求,字段随任务类型变化",
"description": "OpenAI Images 请求",
"name": "input",
"in": "body",
"required": true,
@@ -6070,52 +6028,28 @@
"$ref": "#/definitions/httpapi.CompatibleResponse"
}
},
"202": {
"description": "Accepted",
"schema": {
"$ref": "#/definitions/httpapi.TaskAcceptedResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"402": {
"description": "Payment Required",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
}
},
"404": {
"description": "Not Found",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"429": {
"description": "Too Many Requests",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
}
}
@@ -6289,7 +6223,7 @@
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.KlingErrorEnvelope"
}
}
}
@@ -6391,7 +6325,7 @@
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.KlingErrorEnvelope"
}
}
}
@@ -6603,7 +6537,8 @@
"application/json"
],
"produces": [
"application/json"
"application/json",
"text/event-stream"
],
"tags": [
"gemini-compatible"
@@ -6639,25 +6574,98 @@
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
}
}
}
},
"/api/v1/models/{model}:streamGenerateContent": {
"post": {
"security": [
{
"BearerAuth": []
}
],
"description": "使用统一 /api/v1 前缀接收 Gemini generateContent 请求;旧 /v1 和 /v1beta 路径保留兼容。",
"consumes": [
"application/json"
],
"produces": [
"application/json",
"text/event-stream"
],
"tags": [
"gemini-compatible"
],
"summary": "Gemini generateContent 兼容接口",
"parameters": [
{
"type": "string",
"description": "模型名称",
"name": "model",
"in": "path",
"required": true
},
{
"description": "Gemini generateContent 请求",
"name": "input",
"in": "body",
"required": true,
"schema": {
"type": "object",
"additionalProperties": true
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "object",
"additionalProperties": true
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
},
"502": {
"description": "Bad Gateway",
"schema": {
"$ref": "#/definitions/httpapi.GeminiErrorEnvelope"
}
}
}
@@ -7392,42 +7400,36 @@
"description": "OK",
"schema": {
"$ref": "#/definitions/httpapi.ResponsesCompatibleResponse"
},
"headers": {
"X-Gateway-Task-Id": {
"type": "string",
"description": "网关审计任务 ID"
}
}
},
"400": {
"description": "invalid_previous_response_id / unsupported_response_tool / unsupported_response_parameter",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"402": {
"description": "Payment Required",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
},
"503": {
"description": "response_chain_unavailable",
"schema": {
"$ref": "#/definitions/httpapi.ErrorEnvelope"
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
}
}
}
@@ -9849,6 +9851,38 @@
}
}
},
"httpapi.GeminiErrorEnvelope": {
"type": "object",
"properties": {
"error": {
"$ref": "#/definitions/httpapi.GeminiErrorStatus"
}
}
},
"httpapi.GeminiErrorStatus": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"example": 400
},
"details": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {}
}
},
"message": {
"type": "string",
"example": "Invalid argument"
},
"status": {
"type": "string",
"example": "INVALID_ARGUMENT"
}
}
},
"httpapi.HealthResponse": {
"type": "object",
"properties": {
@@ -10097,6 +10131,26 @@
}
}
},
"httpapi.KlingErrorEnvelope": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"example": 1001
},
"error": {
"type": "string",
"example": "invalid_parameter"
},
"message": {
"type": "string",
"example": "invalid parameter"
},
"request_id": {
"type": "string"
}
}
},
"httpapi.ModelCatalogFilterOption": {
"type": "object",
"properties": {
@@ -10390,6 +10444,35 @@
}
}
},
"httpapi.OpenAIErrorEnvelope": {
"type": "object",
"properties": {
"error": {
"$ref": "#/definitions/httpapi.OpenAIErrorPayload"
}
}
},
"httpapi.OpenAIErrorPayload": {
"type": "object",
"properties": {
"code": {
"type": "string",
"example": "invalid_parameter"
},
"message": {
"type": "string",
"example": "Invalid parameter"
},
"param": {
"type": "string",
"example": "model"
},
"type": {
"type": "string",
"example": "invalid_request_error"
}
}
},
"httpapi.PlatformListResponse": {
"type": "object",
"properties": {
@@ -11117,6 +11200,67 @@
}
}
},
"httpapi.VolcesContentsGenerationTaskResponse": {
"type": "object",
"properties": {
"content": {
"type": "object",
"additionalProperties": {}
},
"created_at": {
"type": "integer"
},
"error": {
"type": "object",
"additionalProperties": {}
},
"id": {
"type": "string",
"example": "cgt-202607221234"
},
"model": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"queued",
"running",
"succeeded",
"failed",
"cancelled"
]
},
"updated_at": {
"type": "integer"
},
"usage": {
"type": "object",
"additionalProperties": {}
}
}
},
"httpapi.VolcesErrorEnvelope": {
"type": "object",
"properties": {
"error": {
"$ref": "#/definitions/httpapi.VolcesErrorPayload"
}
}
},
"httpapi.VolcesErrorPayload": {
"type": "object",
"properties": {
"code": {
"type": "string",
"example": "invalid_parameter"
},
"message": {
"type": "string",
"example": "model is required"
}
}
},
"httpapi.WalletAdjustmentResponse": {
"type": "object",
"properties": {
@@ -12629,6 +12773,26 @@
"cancellable": {
"type": "boolean"
},
"compatibilityProtocol": {
"type": "string"
},
"compatibilityPublicId": {
"type": "string"
},
"compatibilitySourceProtocol": {
"type": "string"
},
"compatibilitySubmitBody": {
"type": "object",
"additionalProperties": {}
},
"compatibilitySubmitHeaders": {
"type": "object",
"additionalProperties": {}
},
"compatibilitySubmitHttpStatus": {
"type": "integer"
},
"conversationId": {
"type": "string"
},