package gemini import ( "strings" "github.com/QuantumNous/new-api/common" "github.com/QuantumNous/new-api/dto" ) const ( geminiResponsesInputTypeCustomToolCall = "custom_tool_call" geminiResponsesInputTypeCustomToolCallOutput = "custom_tool_call_output" geminiResponsesInputTypeFunctionCallOutput = "function_call_output" ) func preprocessGeminiOpenAIResponsesRequest(request dto.OpenAIResponsesRequest) (dto.OpenAIResponsesRequest, error) { tools, err := filterGeminiResponsesTools(request.Tools) if err != nil { return request, err } request.Tools = tools input, err := filterGeminiResponsesInput(request.Input) if err != nil { return request, err } request.Input = input return request, nil } func filterGeminiResponsesTools(raw []byte) ([]byte, error) { if !geminiRawJSONPresent(raw) || common.GetJsonType(raw) != "array" { return raw, nil } var tools []map[string]any if err := common.Unmarshal(raw, &tools); err != nil { return nil, err } filtered := make([]map[string]any, 0, len(tools)) for _, tool := range tools { if strings.TrimSpace(common.Interface2String(tool["type"])) != "function" { // TODO: Support Responses custom/freeform tools when Gemini has a safe equivalent representation. continue } filtered = append(filtered, tool) } if len(filtered) == 0 { return nil, nil } return common.Marshal(filtered) } func filterGeminiResponsesInput(raw []byte) ([]byte, error) { if !geminiRawJSONPresent(raw) || common.GetJsonType(raw) != "array" { return raw, nil } var items []map[string]any if err := common.Unmarshal(raw, &items); err != nil { return nil, err } skippedCustomCallIDs := make(map[string]struct{}) for _, item := range items { if strings.TrimSpace(common.Interface2String(item["type"])) != geminiResponsesInputTypeCustomToolCall { continue } if callID := strings.TrimSpace(common.Interface2String(item["call_id"])); callID != "" { skippedCustomCallIDs[callID] = struct{}{} } } filtered := make([]map[string]any, 0, len(items)) for _, item := range items { itemType := strings.TrimSpace(common.Interface2String(item["type"])) switch itemType { case geminiResponsesInputTypeCustomToolCall, geminiResponsesInputTypeCustomToolCallOutput: // TODO: Support Responses custom/freeform tool calls once Gemini can preserve their semantics. continue case geminiResponsesInputTypeFunctionCallOutput: if _, ok := skippedCustomCallIDs[strings.TrimSpace(common.Interface2String(item["call_id"]))]; ok { continue } } filtered = append(filtered, item) } return common.Marshal(filtered) } func geminiRawJSONPresent(raw []byte) bool { if len(raw) == 0 { return false } return common.GetJsonType(raw) != "null" }