fix: Invalid type for 'input[x].summary': expected an array of objects, but got null instead
Some checks failed
Publish Docker image (Multi Registries) / Push Docker image to multiple registries (push) Has been cancelled

This commit is contained in:
CaIon 2025-08-26 13:17:31 +08:00
parent f249cf9acc
commit 3e5bc637de
5 changed files with 73 additions and 28 deletions

View File

@ -20,3 +20,25 @@ func DecodeJson(reader *bytes.Reader, v any) error {
func Marshal(v any) ([]byte, error) { func Marshal(v any) ([]byte, error) {
return json.Marshal(v) return json.Marshal(v)
} }
func GetJsonType(data json.RawMessage) string {
data = bytes.TrimSpace(data)
if len(data) == 0 {
return "unknown"
}
firstChar := bytes.TrimSpace(data)[0]
switch firstChar {
case '{':
return "object"
case '[':
return "array"
case '"':
return "string"
case 't', 'f':
return "boolean"
case 'n':
return "null"
default:
return "number"
}
}

View File

@ -760,27 +760,27 @@ type WebSearchOptions struct {
// https://platform.openai.com/docs/api-reference/responses/create // https://platform.openai.com/docs/api-reference/responses/create
type OpenAIResponsesRequest struct { type OpenAIResponsesRequest struct {
Model string `json:"model"` Model string `json:"model"`
Input any `json:"input,omitempty"` Input json.RawMessage `json:"input,omitempty"`
Include json.RawMessage `json:"include,omitempty"` Include json.RawMessage `json:"include,omitempty"`
Instructions json.RawMessage `json:"instructions,omitempty"` Instructions json.RawMessage `json:"instructions,omitempty"`
MaxOutputTokens uint `json:"max_output_tokens,omitempty"` MaxOutputTokens uint `json:"max_output_tokens,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"` Metadata json.RawMessage `json:"metadata,omitempty"`
ParallelToolCalls bool `json:"parallel_tool_calls,omitempty"` ParallelToolCalls bool `json:"parallel_tool_calls,omitempty"`
PreviousResponseID string `json:"previous_response_id,omitempty"` PreviousResponseID string `json:"previous_response_id,omitempty"`
Reasoning *Reasoning `json:"reasoning,omitempty"` Reasoning *Reasoning `json:"reasoning,omitempty"`
ServiceTier string `json:"service_tier,omitempty"` ServiceTier string `json:"service_tier,omitempty"`
Store bool `json:"store,omitempty"` Store bool `json:"store,omitempty"`
Stream bool `json:"stream,omitempty"` Stream bool `json:"stream,omitempty"`
Temperature float64 `json:"temperature,omitempty"` Temperature float64 `json:"temperature,omitempty"`
Text json.RawMessage `json:"text,omitempty"` Text json.RawMessage `json:"text,omitempty"`
ToolChoice json.RawMessage `json:"tool_choice,omitempty"` ToolChoice json.RawMessage `json:"tool_choice,omitempty"`
Tools []map[string]any `json:"tools,omitempty"` // 需要处理的参数很少MCP 参数太多不确定,所以用 map Tools json.RawMessage `json:"tools,omitempty"` // 需要处理的参数很少MCP 参数太多不确定,所以用 map
TopP float64 `json:"top_p,omitempty"` TopP float64 `json:"top_p,omitempty"`
Truncation string `json:"truncation,omitempty"` Truncation string `json:"truncation,omitempty"`
User string `json:"user,omitempty"` User string `json:"user,omitempty"`
MaxToolCalls uint `json:"max_tool_calls,omitempty"` MaxToolCalls uint `json:"max_tool_calls,omitempty"`
Prompt json.RawMessage `json:"prompt,omitempty"` Prompt json.RawMessage `json:"prompt,omitempty"`
} }
func (r *OpenAIResponsesRequest) GetTokenCountMeta() *types.TokenCountMeta { func (r *OpenAIResponsesRequest) GetTokenCountMeta() *types.TokenCountMeta {
@ -832,8 +832,7 @@ func (r *OpenAIResponsesRequest) GetTokenCountMeta() *types.TokenCountMeta {
} }
if len(r.Tools) > 0 { if len(r.Tools) > 0 {
toolStr, _ := common.Marshal(r.Tools) texts = append(texts, string(r.Tools))
texts = append(texts, string(toolStr))
} }
return &types.TokenCountMeta{ return &types.TokenCountMeta{
@ -853,6 +852,14 @@ func (r *OpenAIResponsesRequest) SetModelName(modelName string) {
} }
} }
func (r *OpenAIResponsesRequest) GetToolsMap() []map[string]any {
var toolsMap []map[string]any
if len(r.Tools) > 0 {
_ = common.Unmarshal(r.Tools, &toolsMap)
}
return toolsMap
}
type Reasoning struct { type Reasoning struct {
Effort string `json:"effort,omitempty"` Effort string `json:"effort,omitempty"`
Summary string `json:"summary,omitempty"` Summary string `json:"summary,omitempty"`
@ -879,13 +886,21 @@ func (r *OpenAIResponsesRequest) ParseInput() []MediaInput {
var inputs []MediaInput var inputs []MediaInput
// Try string first // Try string first
if str, ok := r.Input.(string); ok { // if str, ok := common.GetJsonType(r.Input); ok {
// inputs = append(inputs, MediaInput{Type: "input_text", Text: str})
// return inputs
// }
if common.GetJsonType(r.Input) == "string" {
var str string
_ = common.Unmarshal(r.Input, &str)
inputs = append(inputs, MediaInput{Type: "input_text", Text: str}) inputs = append(inputs, MediaInput{Type: "input_text", Text: str})
return inputs return inputs
} }
// Try array of parts // Try array of parts
if array, ok := r.Input.([]any); ok { if common.GetJsonType(r.Input) == "array" {
var array []any
_ = common.Unmarshal(r.Input, &array)
for _, itemAny := range array { for _, itemAny := range array {
// Already parsed MediaInput // Already parsed MediaInput
if media, ok := itemAny.(MediaInput); ok { if media, ok := itemAny.(MediaInput); ok {

View File

@ -537,8 +537,14 @@ func detectImageMimeType(filename string) string {
func (a *Adaptor) ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.OpenAIResponsesRequest) (any, error) { func (a *Adaptor) ConvertOpenAIResponsesRequest(c *gin.Context, info *relaycommon.RelayInfo, request dto.OpenAIResponsesRequest) (any, error) {
// 转换模型推理力度后缀 // 转换模型推理力度后缀
effort, originModel := parseReasoningEffortFromModelSuffix(request.Model) effort, originModel := parseReasoningEffortFromModelSuffix(request.Model)
if effort != "" && request.Reasoning != nil { if effort != "" {
request.Reasoning.Effort = effort if request.Reasoning == nil {
request.Reasoning = &dto.Reasoning{
Effort: effort,
}
} else {
request.Reasoning.Effort = effort
}
request.Model = originModel request.Model = originModel
} }
return request, nil return request, nil

View File

@ -92,6 +92,8 @@ func OaiResponsesStreamHandler(c *gin.Context, info *relaycommon.RelayInfo, resp
} }
} }
} }
} else {
logger.LogError(c, "failed to unmarshal stream response: "+err.Error())
} }
return true return true
}) })

View File

@ -313,7 +313,7 @@ func GenRelayInfoResponses(c *gin.Context, request *dto.OpenAIResponsesRequest)
BuiltInTools: make(map[string]*BuildInToolInfo), BuiltInTools: make(map[string]*BuildInToolInfo),
} }
if len(request.Tools) > 0 { if len(request.Tools) > 0 {
for _, tool := range request.Tools { for _, tool := range request.GetToolsMap() {
toolType := common.Interface2String(tool["type"]) toolType := common.Interface2String(tool["type"])
info.ResponsesUsageInfo.BuiltInTools[toolType] = &BuildInToolInfo{ info.ResponsesUsageInfo.BuiltInTools[toolType] = &BuildInToolInfo{
ToolName: toolType, ToolName: toolType,