feat(openai): 完善 Chat 与 Responses 参数转发
原生 Chat/Responses 改为透明转发,保留标准工具结构并保护调用方显式参数。补齐 Responses 到 Chat 的兼容转换、协议路由边界、完整响应和流式事件,并同步更新 Swagger、回归测试与真实验收脚本。 验证: - cd apps/api && env -u AI_GATEWAY_TEST_DATABASE_URL go test ./... -count=1 - pnpm openapi - pnpm lint - pnpm test - pnpm build - gofmt -l 无输出 - git diff --check 通过 风险: - Chat 回退无法等价表达的 Responses 原生能力现在会返回 unsupported_response_parameter - 真实供应商 E2E 因本地没有已启用的平台模型候选而未完成
This commit is contained in:
+74
-19
@@ -6450,7 +6450,7 @@
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "/api/v1/chat/completions 同步执行:stream=true 返回 text/event-stream SSE;stream=false 或未传返回兼容 JSON;该接口忽略 X-Async。",
|
||||
"description": "/api/v1/chat/completions 同步执行:除 Gateway 路由字段外透明转发当前及未来 OpenAI 字段与嵌套结构,完整保留 function/custom tools、tool_choice、tool_calls 和旧版 function_call;stream=true 返回 text/event-stream SSE,stream=false 或未传返回兼容 JSON;该接口忽略 X-Async。",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -8566,7 +8566,7 @@
|
||||
"BearerAuth": []
|
||||
}
|
||||
],
|
||||
"description": "公开 OpenAI-compatible Responses 入口。模型声明 openai_responses 时原生转发,否则使用 Chat Completions 转换;store 缺省为 true。previous_response_id 严格绑定首次成功的平台模型和上游协议,链路不可用时不跨平台续接。未提供 previous_response_id 时由调用方管理完整状态,Gateway 以本轮 input/messages 为准且不追加本地历史。",
|
||||
"description": "公开 OpenAI-compatible Responses 入口。模型声明 openai_responses 时除 Gateway 路由字段外透明转发当前及未来 OpenAI 字段;否则仅对具有等价 Chat Completions 语义的请求执行转换。background、conversation、prompt template、context management、max_tool_calls、自动 truncation、reasoning summary、内置工具、MCP 和 namespace 等原生专属能力不会静默丢弃:路由会排除 Chat 候选,固定 Chat 链路则返回带参数路径的 unsupported_response_parameter。store 缺省为 true。previous_response_id 严格绑定首次成功的平台模型和上游协议,链路不可用时不跨平台续接;未提供 previous_response_id 时调用方历史权威,Gateway 不追加本地历史。",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
@@ -8580,7 +8580,7 @@
|
||||
"summary": "创建 OpenAI Responses",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Responses 请求;Chat 回退只支持自定义 function tools",
|
||||
"description": "Responses 请求;Chat 回退支持 function/custom tools 及所有可等价能力",
|
||||
"name": "input",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
@@ -8597,7 +8597,7 @@
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "invalid_previous_response_id / unsupported_response_tool / unsupported_response_parameter",
|
||||
"description": "invalid_previous_response_id / unsupported_response_parameter",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/httpapi.OpenAIErrorEnvelope"
|
||||
}
|
||||
@@ -10810,6 +10810,7 @@
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"logprobs": {},
|
||||
"message": {
|
||||
"$ref": "#/definitions/httpapi.ChatCompletionChoiceMessage"
|
||||
}
|
||||
@@ -10818,14 +10819,18 @@
|
||||
"httpapi.ChatCompletionChoiceMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"example": "Hello"
|
||||
"annotations": {},
|
||||
"audio": {},
|
||||
"content": {},
|
||||
"function_call": {},
|
||||
"refusal": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"example": "assistant"
|
||||
}
|
||||
},
|
||||
"tool_calls": {}
|
||||
}
|
||||
},
|
||||
"httpapi.ChatCompletionCompatibleResponse": {
|
||||
@@ -10853,6 +10858,12 @@
|
||||
"type": "string",
|
||||
"example": "chat.completion"
|
||||
},
|
||||
"service_tier": {
|
||||
"type": "string"
|
||||
},
|
||||
"system_fingerprint": {
|
||||
"type": "string"
|
||||
},
|
||||
"usage": {
|
||||
"$ref": "#/definitions/httpapi.ChatCompletionUsage"
|
||||
}
|
||||
@@ -11045,11 +11056,15 @@
|
||||
"httpapi.ChatMessage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"audio": {},
|
||||
"content": {},
|
||||
"function_call": {},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"refusal": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string",
|
||||
"example": "user"
|
||||
@@ -12312,18 +12327,35 @@
|
||||
"httpapi.ResponsesCompatibleResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"background": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"completed_at": {
|
||||
"type": "integer"
|
||||
},
|
||||
"conversation": {},
|
||||
"created_at": {
|
||||
"type": "integer",
|
||||
"example": 1710000000
|
||||
},
|
||||
"error": {},
|
||||
"id": {
|
||||
"type": "string",
|
||||
"example": "resp_0123456789abcdef0123456789abcdef"
|
||||
},
|
||||
"incomplete_details": {},
|
||||
"instructions": {},
|
||||
"max_output_tokens": {},
|
||||
"max_tool_calls": {},
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"model": {
|
||||
"type": "string",
|
||||
"example": "Doubao Seed 2.0 Pro"
|
||||
},
|
||||
"moderation": {},
|
||||
"object": {
|
||||
"type": "string",
|
||||
"example": "response"
|
||||
@@ -12339,18 +12371,47 @@
|
||||
"type": "string",
|
||||
"example": "Hello"
|
||||
},
|
||||
"previous_response_id": {
|
||||
"type": "string",
|
||||
"example": "resp_abcdef0123456789abcdef0123456789"
|
||||
"parallel_tool_calls": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"previous_response_id": {},
|
||||
"prompt": {},
|
||||
"prompt_cache_key": {},
|
||||
"prompt_cache_options": {},
|
||||
"prompt_cache_retention": {},
|
||||
"reasoning": {},
|
||||
"safety_identifier": {},
|
||||
"service_tier": {},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"queued",
|
||||
"in_progress",
|
||||
"completed",
|
||||
"incomplete",
|
||||
"failed",
|
||||
"cancelled"
|
||||
],
|
||||
"example": "completed"
|
||||
},
|
||||
"temperature": {},
|
||||
"text": {},
|
||||
"tool_choice": {},
|
||||
"tools": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"top_logprobs": {},
|
||||
"top_p": {},
|
||||
"truncation": {},
|
||||
"usage": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"user": {}
|
||||
}
|
||||
},
|
||||
"httpapi.ResponsesRequest": {
|
||||
@@ -12359,13 +12420,7 @@
|
||||
"background": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"context_management": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"context_management": {},
|
||||
"conversation": {},
|
||||
"include": {
|
||||
"type": "array",
|
||||
|
||||
+69
-18
@@ -154,17 +154,22 @@ definitions:
|
||||
index:
|
||||
example: 0
|
||||
type: integer
|
||||
logprobs: {}
|
||||
message:
|
||||
$ref: '#/definitions/httpapi.ChatCompletionChoiceMessage'
|
||||
type: object
|
||||
httpapi.ChatCompletionChoiceMessage:
|
||||
properties:
|
||||
content:
|
||||
example: Hello
|
||||
annotations: {}
|
||||
audio: {}
|
||||
content: {}
|
||||
function_call: {}
|
||||
refusal:
|
||||
type: string
|
||||
role:
|
||||
example: assistant
|
||||
type: string
|
||||
tool_calls: {}
|
||||
type: object
|
||||
httpapi.ChatCompletionCompatibleResponse:
|
||||
properties:
|
||||
@@ -184,6 +189,10 @@ definitions:
|
||||
object:
|
||||
example: chat.completion
|
||||
type: string
|
||||
service_tier:
|
||||
type: string
|
||||
system_fingerprint:
|
||||
type: string
|
||||
usage:
|
||||
$ref: '#/definitions/httpapi.ChatCompletionUsage'
|
||||
type: object
|
||||
@@ -323,10 +332,13 @@ definitions:
|
||||
type: object
|
||||
httpapi.ChatMessage:
|
||||
properties:
|
||||
audio: {}
|
||||
content: {}
|
||||
function_call: {}
|
||||
name:
|
||||
type: string
|
||||
refusal:
|
||||
type: string
|
||||
role:
|
||||
example: user
|
||||
type: string
|
||||
@@ -1195,15 +1207,29 @@ definitions:
|
||||
type: object
|
||||
httpapi.ResponsesCompatibleResponse:
|
||||
properties:
|
||||
background:
|
||||
type: boolean
|
||||
completed_at:
|
||||
type: integer
|
||||
conversation: {}
|
||||
created_at:
|
||||
example: 1710000000
|
||||
type: integer
|
||||
error: {}
|
||||
id:
|
||||
example: resp_0123456789abcdef0123456789abcdef
|
||||
type: string
|
||||
incomplete_details: {}
|
||||
instructions: {}
|
||||
max_output_tokens: {}
|
||||
max_tool_calls: {}
|
||||
metadata:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
model:
|
||||
example: Doubao Seed 2.0 Pro
|
||||
type: string
|
||||
moderation: {}
|
||||
object:
|
||||
example: response
|
||||
type: string
|
||||
@@ -1215,25 +1241,47 @@ definitions:
|
||||
output_text:
|
||||
example: Hello
|
||||
type: string
|
||||
previous_response_id:
|
||||
example: resp_abcdef0123456789abcdef0123456789
|
||||
type: string
|
||||
parallel_tool_calls:
|
||||
type: boolean
|
||||
previous_response_id: {}
|
||||
prompt: {}
|
||||
prompt_cache_key: {}
|
||||
prompt_cache_options: {}
|
||||
prompt_cache_retention: {}
|
||||
reasoning: {}
|
||||
safety_identifier: {}
|
||||
service_tier: {}
|
||||
status:
|
||||
enum:
|
||||
- queued
|
||||
- in_progress
|
||||
- completed
|
||||
- incomplete
|
||||
- failed
|
||||
- cancelled
|
||||
example: completed
|
||||
type: string
|
||||
temperature: {}
|
||||
text: {}
|
||||
tool_choice: {}
|
||||
tools:
|
||||
items:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: array
|
||||
top_logprobs: {}
|
||||
top_p: {}
|
||||
truncation: {}
|
||||
usage:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
user: {}
|
||||
type: object
|
||||
httpapi.ResponsesRequest:
|
||||
properties:
|
||||
background:
|
||||
type: boolean
|
||||
context_management:
|
||||
items:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
type: array
|
||||
context_management: {}
|
||||
conversation: {}
|
||||
include:
|
||||
items:
|
||||
@@ -8559,8 +8607,9 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: /api/v1/chat/completions 同步执行:stream=true 返回 text/event-stream
|
||||
SSE;stream=false 或未传返回兼容 JSON;该接口忽略 X-Async。
|
||||
description: /api/v1/chat/completions 同步执行:除 Gateway 路由字段外透明转发当前及未来 OpenAI 字段与嵌套结构,完整保留
|
||||
function/custom tools、tool_choice、tool_calls 和旧版 function_call;stream=true
|
||||
返回 text/event-stream SSE,stream=false 或未传返回兼容 JSON;该接口忽略 X-Async。
|
||||
parameters:
|
||||
- description: 该接口忽略此参数
|
||||
in: header
|
||||
@@ -9926,11 +9975,14 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 公开 OpenAI-compatible Responses 入口。模型声明 openai_responses 时原生转发,否则使用
|
||||
Chat Completions 转换;store 缺省为 true。previous_response_id 严格绑定首次成功的平台模型和上游协议,链路不可用时不跨平台续接。未提供
|
||||
previous_response_id 时由调用方管理完整状态,Gateway 以本轮 input/messages 为准且不追加本地历史。
|
||||
description: 公开 OpenAI-compatible Responses 入口。模型声明 openai_responses 时除 Gateway
|
||||
路由字段外透明转发当前及未来 OpenAI 字段;否则仅对具有等价 Chat Completions 语义的请求执行转换。background、conversation、prompt
|
||||
template、context management、max_tool_calls、自动 truncation、reasoning summary、内置工具、MCP
|
||||
和 namespace 等原生专属能力不会静默丢弃:路由会排除 Chat 候选,固定 Chat 链路则返回带参数路径的 unsupported_response_parameter。store
|
||||
缺省为 true。previous_response_id 严格绑定首次成功的平台模型和上游协议,链路不可用时不跨平台续接;未提供 previous_response_id
|
||||
时调用方历史权威,Gateway 不追加本地历史。
|
||||
parameters:
|
||||
- description: Responses 请求;Chat 回退只支持自定义 function tools
|
||||
- description: Responses 请求;Chat 回退支持 function/custom tools 及所有可等价能力
|
||||
in: body
|
||||
name: input
|
||||
required: true
|
||||
@@ -9945,8 +9997,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/definitions/httpapi.ResponsesCompatibleResponse'
|
||||
"400":
|
||||
description: invalid_previous_response_id / unsupported_response_tool /
|
||||
unsupported_response_parameter
|
||||
description: invalid_previous_response_id / unsupported_response_parameter
|
||||
schema:
|
||||
$ref: '#/definitions/httpapi.OpenAIErrorEnvelope'
|
||||
"401":
|
||||
|
||||
Reference in New Issue
Block a user