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()
|
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 上游要求必须包含身份提示词,注入到请求中
|
// Antigravity 上游要求必须包含身份提示词,注入到请求中
|
||||||
injectedBody, err := injectIdentityPatchToGeminiRequest(body)
|
injectedBody, err := injectIdentityPatchToGeminiRequest(filteredBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -2778,3 +2785,55 @@ func cleanGeminiRequest(body []byte) ([]byte, error) {
|
|||||||
|
|
||||||
return json.Marshal(payload)
|
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")
|
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 {
|
switch action {
|
||||||
case "generateContent", "streamGenerateContent", "countTokens":
|
case "generateContent", "streamGenerateContent", "countTokens":
|
||||||
// ok
|
// ok
|
||||||
|
|||||||
Reference in New Issue
Block a user