fix(gateway): 过滤 Gemini 请求中 parts 为空的消息
Gemini API 不接受 contents 数组中 parts 为空的消息,会返回 400 INVALID_ARGUMENT 错误。 添加 filterEmptyPartsFromGeminiRequest 函数在转发前过滤这类消息。 影响范围:ForwardGemini (antigravity) 和 ForwardNative (gemini)
This commit is contained in:
@@ -1412,8 +1412,15 @@ func (s *AntigravityGatewayService) ForwardGemini(ctx context.Context, c *gin.Co
|
||||
proxyURL = account.Proxy.URL()
|
||||
}
|
||||
|
||||
// 过滤掉 parts 为空的消息(Gemini API 不接受空 parts)
|
||||
filteredBody, err := filterEmptyPartsFromGeminiRequest(body)
|
||||
if err != nil {
|
||||
log.Printf("[Antigravity] Failed to filter empty parts: %v", err)
|
||||
filteredBody = body
|
||||
}
|
||||
|
||||
// Antigravity 上游要求必须包含身份提示词,注入到请求中
|
||||
injectedBody, err := injectIdentityPatchToGeminiRequest(body)
|
||||
injectedBody, err := injectIdentityPatchToGeminiRequest(filteredBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2778,3 +2785,55 @@ func cleanGeminiRequest(body []byte) ([]byte, error) {
|
||||
|
||||
return json.Marshal(payload)
|
||||
}
|
||||
|
||||
// filterEmptyPartsFromGeminiRequest 过滤 Gemini 请求中 parts 为空的消息
|
||||
// Gemini API 不接受 parts 为空数组的消息,会返回 400 错误
|
||||
func filterEmptyPartsFromGeminiRequest(body []byte) ([]byte, error) {
|
||||
var payload map[string]any
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
contents, ok := payload["contents"].([]any)
|
||||
if !ok || len(contents) == 0 {
|
||||
return body, nil
|
||||
}
|
||||
|
||||
filtered := make([]any, 0, len(contents))
|
||||
modified := false
|
||||
|
||||
for _, c := range contents {
|
||||
contentMap, ok := c.(map[string]any)
|
||||
if !ok {
|
||||
filtered = append(filtered, c)
|
||||
continue
|
||||
}
|
||||
|
||||
parts, hasParts := contentMap["parts"]
|
||||
if !hasParts {
|
||||
filtered = append(filtered, c)
|
||||
continue
|
||||
}
|
||||
|
||||
partsSlice, ok := parts.([]any)
|
||||
if !ok {
|
||||
filtered = append(filtered, c)
|
||||
continue
|
||||
}
|
||||
|
||||
// 跳过 parts 为空数组的消息
|
||||
if len(partsSlice) == 0 {
|
||||
modified = true
|
||||
continue
|
||||
}
|
||||
|
||||
filtered = append(filtered, c)
|
||||
}
|
||||
|
||||
if !modified {
|
||||
return body, nil
|
||||
}
|
||||
|
||||
payload["contents"] = filtered
|
||||
return json.Marshal(payload)
|
||||
}
|
||||
|
||||
@@ -840,6 +840,11 @@ func (s *GeminiMessagesCompatService) ForwardNative(ctx context.Context, c *gin.
|
||||
return nil, s.writeGoogleError(c, http.StatusBadRequest, "Request body is empty")
|
||||
}
|
||||
|
||||
// 过滤掉 parts 为空的消息(Gemini API 不接受空 parts)
|
||||
if filteredBody, err := filterEmptyPartsFromGeminiRequest(body); err == nil {
|
||||
body = filteredBody
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "generateContent", "streamGenerateContent", "countTokens":
|
||||
// ok
|
||||
|
||||
Reference in New Issue
Block a user