diff --git a/relay/channel/gemini/relay-gemini.go b/relay/channel/gemini/relay-gemini.go index f4b6bbf72..22ddfaeaa 100644 --- a/relay/channel/gemini/relay-gemini.go +++ b/relay/channel/gemini/relay-gemini.go @@ -1355,20 +1355,50 @@ func GeminiChatHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.R return nil, types.NewOpenAIError(err, types.ErrorCodeBadResponseBody, http.StatusInternalServerError) } if len(geminiResponse.Candidates) == 0 { - // [FIX] Return meaningful error when Candidates is empty + usage := dto.Usage{ + PromptTokens: geminiResponse.UsageMetadata.PromptTokenCount, + } + usage.CompletionTokenDetails.ReasoningTokens = geminiResponse.UsageMetadata.ThoughtsTokenCount + for _, detail := range geminiResponse.UsageMetadata.PromptTokensDetails { + if detail.Modality == "AUDIO" { + usage.PromptTokensDetails.AudioTokens = detail.TokenCount + } else if detail.Modality == "TEXT" { + usage.PromptTokensDetails.TextTokens = detail.TokenCount + } + } + if usage.PromptTokens <= 0 { + usage.PromptTokens = info.GetEstimatePromptTokens() + } + + var newAPIError *types.NewAPIError if geminiResponse.PromptFeedback != nil && geminiResponse.PromptFeedback.BlockReason != nil { - return nil, types.NewOpenAIError( + newAPIError = types.NewOpenAIError( errors.New("request blocked by Gemini API: "+*geminiResponse.PromptFeedback.BlockReason), types.ErrorCodePromptBlocked, http.StatusBadRequest, ) } else { - return nil, types.NewOpenAIError( + newAPIError = types.NewOpenAIError( errors.New("empty response from Gemini API"), types.ErrorCodeEmptyResponse, http.StatusInternalServerError, ) } + + service.ResetStatusCode(newAPIError, c.GetString("status_code_mapping")) + + switch info.RelayFormat { + case types.RelayFormatClaude: + c.JSON(newAPIError.StatusCode, gin.H{ + "type": "error", + "error": newAPIError.ToClaudeError(), + }) + default: + c.JSON(newAPIError.StatusCode, gin.H{ + "error": newAPIError.ToOpenAIError(), + }) + } + return &usage, nil } fullTextResponse := responseGeminiChat2OpenAI(c, &geminiResponse) fullTextResponse.Model = info.UpstreamModelName @@ -1643,4 +1673,3 @@ func convertToolChoiceToGeminiConfig(toolChoice any) *dto.ToolConfig { // Unsupported type, return nil return nil } -