diff --git a/dto/openai_response.go b/dto/openai_response.go index 37ea17b..7bd38bb 100644 --- a/dto/openai_response.go +++ b/dto/openai_response.go @@ -343,7 +343,24 @@ type ResponsesOutput struct { Size string `json:"size"` CallId string `json:"call_id,omitempty"` Name string `json:"name,omitempty"` - Arguments string `json:"arguments,omitempty"` + // Arguments can be a JSON string or a JSON object (e.g. gpt-5.4 returns objects for some tools) + Arguments json.RawMessage `json:"arguments,omitempty"` +} + +// GetArguments returns the arguments as a plain string. +// If the upstream sent a JSON string value, the inner string is returned (unescaped). +// If the upstream sent a JSON object, the raw JSON bytes are returned as a string. +func (r *ResponsesOutput) GetArguments() string { + if len(r.Arguments) == 0 { + return "" + } + if r.Arguments[0] == '"' { + var s string + if err := json.Unmarshal(r.Arguments, &s); err == nil { + return s + } + } + return string(r.Arguments) } type ResponsesOutputContent struct { diff --git a/relay/channel/openai/chat_via_responses.go b/relay/channel/openai/chat_via_responses.go index 8c4be24..c084e13 100644 --- a/relay/channel/openai/chat_via_responses.go +++ b/relay/channel/openai/chat_via_responses.go @@ -409,7 +409,7 @@ func OaiResponsesToChatStreamHandler(c *gin.Context, info *relaycommon.RelayInfo toolCallNameByID[callID] = name } - newArgs := streamResp.Item.Arguments + newArgs := streamResp.Item.GetArguments() prevArgs := toolCallArgsByID[callID] argsDelta := "" if newArgs != "" { diff --git a/service/openaicompat/responses_to_chat.go b/service/openaicompat/responses_to_chat.go index abd0359..5ce894c 100644 --- a/service/openaicompat/responses_to_chat.go +++ b/service/openaicompat/responses_to_chat.go @@ -60,7 +60,7 @@ func ResponsesResponseToChatCompletionsResponse(resp *dto.OpenAIResponsesRespons Type: "function", Function: dto.FunctionResponse{ Name: name, - Arguments: out.Arguments, + Arguments: out.GetArguments(), }, }) }