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
+25 -2
View File
@@ -49,7 +49,7 @@ func (s *compatibleStreamWriter) writeDelta(w http.ResponseWriter, event clients
if sequence := intFromStreamValue(event.Event["sequence_number"]); sequence >= s.responseSequence {
s.responseSequence = sequence + 1
}
if eventType == "response.completed" {
if isResponsesTerminalEvent(eventType) {
s.sentResponseDone = true
}
sendSSE(w, eventType, event.Event)
@@ -84,7 +84,8 @@ func (s *compatibleStreamWriter) writeDone(w http.ResponseWriter, output map[str
if s.sentResponseDone {
return
}
sendSSE(w, "response.completed", map[string]any{"type": "response.completed", "sequence_number": s.responseSequence, "response": output})
eventType := responsesTerminalEvent(output)
sendSSE(w, eventType, map[string]any{"type": eventType, "sequence_number": s.responseSequence, "response": output})
s.sentResponseDone = true
return
}
@@ -106,6 +107,28 @@ func (s *compatibleStreamWriter) writeDone(w http.ResponseWriter, output map[str
s.writeDoneMarker(w)
}
func isResponsesTerminalEvent(eventType string) bool {
switch eventType {
case "response.completed", "response.incomplete", "response.failed", "response.cancelled":
return true
default:
return false
}
}
func responsesTerminalEvent(output map[string]any) string {
switch status, _ := output["status"].(string); status {
case "incomplete":
return "response.incomplete"
case "failed":
return "response.failed"
case "cancelled":
return "response.cancelled"
default:
return "response.completed"
}
}
func intFromStreamValue(value any) int {
switch typed := value.(type) {
case int: