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:
2026-08-04 19:26:48 +08:00
parent b2c9b4f6d9
commit fe8dcb40ca
22 changed files with 2098 additions and 309 deletions
+14 -1
View File
@@ -83,7 +83,8 @@ func (s *Service) prepareResponseExecution(ctx context.Context, task store.Gatew
return result, nil
}
func prepareResponseCandidates(candidates []store.RuntimeModelCandidate, execution responseExecutionContext) ([]store.RuntimeModelCandidate, error) {
func prepareResponseCandidates(candidates []store.RuntimeModelCandidate, execution responseExecutionContext, body map[string]any) ([]store.RuntimeModelCandidate, error) {
chatCompatibilityErr := clients.ValidateResponsesChatFallback(body)
if execution.PreviousChain != nil {
for _, candidate := range candidates {
if candidate.PlatformModelID != execution.PreviousChain.PlatformModelID {
@@ -92,6 +93,9 @@ func prepareResponseCandidates(candidates []store.RuntimeModelCandidate, executi
if !candidateSupportsProtocol(candidate, execution.PreviousChain.UpstreamProtocol) {
break
}
if execution.PreviousChain.UpstreamProtocol == clients.ProtocolOpenAIChatCompletions && chatCompatibilityErr != nil {
return nil, chatCompatibilityErr
}
candidate.ResponseProtocol = execution.PreviousChain.UpstreamProtocol
return []store.RuntimeModelCandidate{candidate}, nil
}
@@ -106,6 +110,7 @@ func prepareResponseCandidates(candidates []store.RuntimeModelCandidate, executi
items := make([]indexedCandidate, 0, len(candidates))
hasAnthropicOnly := false
hasDeclaredUnsupported := false
hasChatCandidate := false
for index, candidate := range candidates {
protocols := candidateSupportedProtocols(candidate)
group := 1
@@ -119,11 +124,19 @@ func prepareResponseCandidates(candidates []store.RuntimeModelCandidate, executi
hasAnthropicOnly = true
}
continue
} else {
hasChatCandidate = true
if chatCompatibilityErr != nil {
continue
}
}
candidate.ResponseProtocol = protocol
items = append(items, indexedCandidate{candidate: candidate, index: index, group: group})
}
if len(items) == 0 {
if hasChatCandidate && chatCompatibilityErr != nil {
return nil, chatCompatibilityErr
}
if hasAnthropicOnly {
return nil, &clients.ClientError{Code: "unsupported_model_protocol", Message: "the selected model only supports Anthropic Messages; the public Anthropic adapter is not available", StatusCode: http.StatusBadRequest}
}