fix: validate JSON before raw-embedding function call outputs in Responses API

gjson.Parse() marks any string starting with { or [ as gjson.JSON type,
even when the content is not valid JSON (e.g. macOS plist format, truncated
tool results). This caused sjson.SetRaw to embed non-JSON content directly
into the Gemini API request payload, producing 400 errors.

Add json.Valid() check before using SetRaw to ensure only actually valid
JSON is embedded raw. Non-JSON content now falls through to sjson.Set
which properly escapes it as a JSON string.

Fixes #2161
This commit is contained in:
enieuwy
2026-03-16 15:29:18 +08:00
parent 67669196ed
commit b24ae74216
@@ -1,6 +1,7 @@
package responses package responses
import ( import (
"encoding/json"
"strings" "strings"
"github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common" "github.com/router-for-me/CLIProxyAPI/v6/internal/translator/gemini/common"
@@ -340,7 +341,7 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
// Set the raw JSON output directly (preserves string encoding) // Set the raw JSON output directly (preserves string encoding)
if outputRaw != "" && outputRaw != "null" { if outputRaw != "" && outputRaw != "null" {
output := gjson.Parse(outputRaw) output := gjson.Parse(outputRaw)
if output.Type == gjson.JSON { if output.Type == gjson.JSON && json.Valid([]byte(output.Raw)) {
functionResponse, _ = sjson.SetRaw(functionResponse, "functionResponse.response.result", output.Raw) functionResponse, _ = sjson.SetRaw(functionResponse, "functionResponse.response.result", output.Raw)
} else { } else {
functionResponse, _ = sjson.Set(functionResponse, "functionResponse.response.result", outputRaw) functionResponse, _ = sjson.Set(functionResponse, "functionResponse.response.result", outputRaw)