fix(gemini): resolve latency and error issues with model normalization and v1beta tool routing
This commit is contained in:
+2
-2
@@ -209,9 +209,9 @@ func (db *DB) RunMigrations() error {
|
||||
}{
|
||||
{"deepseek-auto", "heuristic", `["deepseek-chat","deepseek-reasoner"]`, "", nil, nil, nil},
|
||||
{"openai-auto", "heuristic", `["gpt-4o-mini","gpt-4o"]`, "", nil, nil, nil},
|
||||
{"gemini-auto", "heuristic", `["gemini-2.5-flash","gemini-2.5-pro"]`, "", nil, nil, nil},
|
||||
{"gemini-auto", "heuristic", `["gemini-3.5-flash-lite","gemini-3.1-flash-lite","gemini-2.5-flash"]`, "", nil, nil, nil},
|
||||
{"heavy-logic", "heuristic", `["grok-4.3","kimi-k2.6","deepseek-v4-pro"]`, "", nil, intPtr(9), strPtr("Complex Coding, Logic, Agents.")},
|
||||
{"standard-pro", "heuristic", `["gpt-5.4-mini","gemini-3-flash-preview"]`, "", nil, intPtr(5), strPtr("General Assistant, Long Docs.")},
|
||||
{"standard-pro", "heuristic", `["gpt-5.4-mini","gemini-3.5-flash-lite"]`, "", nil, intPtr(5), strPtr("General Assistant, Long Docs.")},
|
||||
{"fast-flow", "heuristic", `["deepseek-v4-flash","gpt-5.4-nano"]`, "", nil, intPtr(2), strPtr("Classification, JSON, Basic Q&A.")},
|
||||
{"dispatcher", "classifier", `["fast-flow","standard-pro","heavy-logic"]`, "gpt-5.4-nano", intPtr(10), nil, strPtr("Auto-dispatches to tier groups by complexity.")},
|
||||
}
|
||||
|
||||
@@ -202,15 +202,7 @@ func (p *GeminiProvider) ResponsesStream(ctx context.Context, req *models.Respon
|
||||
}
|
||||
|
||||
func (p *GeminiProvider) ChatCompletion(ctx context.Context, req *models.UnifiedRequest) (*models.ChatCompletionResponse, error) {
|
||||
// Map deprecated or preview model names to active equivalents
|
||||
switch req.Model {
|
||||
case "gemini-2.0-flash":
|
||||
req.Model = "gemini-2.5-flash"
|
||||
case "gemini-3-flash":
|
||||
req.Model = "gemini-3-flash-preview"
|
||||
case "gemini-3-pro":
|
||||
req.Model = "gemini-3-pro-preview"
|
||||
}
|
||||
req.Model = normalizeGeminiModel(req.Model)
|
||||
|
||||
// Gemini mapping
|
||||
var contents []GeminiContent
|
||||
@@ -273,7 +265,7 @@ func (p *GeminiProvider) ChatCompletion(ctx context.Context, req *models.Unified
|
||||
}
|
||||
|
||||
if foundAny {
|
||||
contents = append(contents, GeminiContent{Role: "function", Parts: functionParts})
|
||||
contents = append(contents, GeminiContent{Role: "user", Parts: functionParts})
|
||||
i = j - 1 // Advance outer loop past the tool messages we consumed
|
||||
} else {
|
||||
// If no tool results found but assistant made calls, Gemini WILL error.
|
||||
@@ -364,8 +356,9 @@ func (p *GeminiProvider) ChatCompletion(ctx context.Context, req *models.Unified
|
||||
if strings.Contains(lowerModel, "preview") ||
|
||||
strings.Contains(lowerModel, "thinking") ||
|
||||
strings.Contains(lowerModel, "gemini-") ||
|
||||
hasMappedTools {
|
||||
// Use v1beta for preview, newer models, or when using tools
|
||||
hasMappedTools ||
|
||||
hasHistoryToolCalls(contents) {
|
||||
// Use v1beta for preview, newer models, tool use, or historical tool calls
|
||||
if !strings.Contains(baseURL, "v1beta") {
|
||||
baseURL = strings.Replace(baseURL, "/v1", "/v1beta", 1)
|
||||
}
|
||||
@@ -478,15 +471,7 @@ func (p *GeminiProvider) ChatCompletion(ctx context.Context, req *models.Unified
|
||||
}
|
||||
|
||||
func (p *GeminiProvider) ChatCompletionStream(ctx context.Context, req *models.UnifiedRequest) (<-chan *models.ChatCompletionStreamResponse, error) {
|
||||
// Map deprecated or preview model names to active equivalents
|
||||
switch req.Model {
|
||||
case "gemini-2.0-flash":
|
||||
req.Model = "gemini-2.5-flash"
|
||||
case "gemini-3-flash":
|
||||
req.Model = "gemini-3-flash-preview"
|
||||
case "gemini-3-pro":
|
||||
req.Model = "gemini-3-pro-preview"
|
||||
}
|
||||
req.Model = normalizeGeminiModel(req.Model)
|
||||
|
||||
// Simplified Gemini mapping
|
||||
var contents []GeminiContent
|
||||
@@ -535,7 +520,7 @@ func (p *GeminiProvider) ChatCompletionStream(ctx context.Context, req *models.U
|
||||
}
|
||||
|
||||
if foundAny {
|
||||
contents = append(contents, GeminiContent{Role: "function", Parts: functionParts})
|
||||
contents = append(contents, GeminiContent{Role: "user", Parts: functionParts})
|
||||
i = j - 1
|
||||
}
|
||||
continue
|
||||
@@ -617,8 +602,9 @@ func (p *GeminiProvider) ChatCompletionStream(ctx context.Context, req *models.U
|
||||
if strings.Contains(lowerModel, "preview") ||
|
||||
strings.Contains(lowerModel, "thinking") ||
|
||||
strings.Contains(lowerModel, "gemini-") ||
|
||||
hasMappedTools {
|
||||
// Use v1beta for preview, newer models, or when using tools
|
||||
hasMappedTools ||
|
||||
hasHistoryToolCalls(contents) {
|
||||
// Use v1beta for preview, newer models, tool use, or historical tool calls
|
||||
if !strings.Contains(baseURL, "v1beta") {
|
||||
baseURL = strings.Replace(baseURL, "/v1", "/v1beta", 1)
|
||||
}
|
||||
@@ -748,3 +734,30 @@ func resolveToolName(toolMsg models.UnifiedMessage, toolCalls []models.ToolCall,
|
||||
return "unknown_function"
|
||||
}
|
||||
|
||||
func normalizeGeminiModel(model string) string {
|
||||
switch model {
|
||||
case "gemini-2.0-flash", "gemini-1.5-flash":
|
||||
return "gemini-3.5-flash-lite"
|
||||
case "gemini-3-flash", "gemini-3-flash-preview":
|
||||
return "gemini-3.5-flash-lite"
|
||||
case "gemini-3-pro", "gemini-3-pro-preview", "gemini-1.5-pro":
|
||||
return "gemini-2.5-pro"
|
||||
default:
|
||||
return model
|
||||
}
|
||||
}
|
||||
|
||||
func hasHistoryToolCalls(contents []GeminiContent) bool {
|
||||
for _, c := range contents {
|
||||
if c.Role == "function" {
|
||||
return true
|
||||
}
|
||||
for _, p := range c.Parts {
|
||||
if p.FunctionCall != nil || p.FunctionResponse != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user