mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(gemini): honor pro-model thinking constraints
This commit is contained in:
@@ -347,12 +347,21 @@ func buildGeminiThinkingConfig(model string, options map[string]any) map[string]
|
|||||||
config["includeThoughts"] = includeThoughts
|
config["includeThoughts"] = includeThoughts
|
||||||
|
|
||||||
if isGemini25Model(model) {
|
if isGemini25Model(model) {
|
||||||
|
if isGemini25ProModel(model) && (rawLevel == "off" || rawLevel == "minimal") {
|
||||||
|
// Gemini 2.5 Pro cannot disable thinking; keep model-default thinking.
|
||||||
|
return config
|
||||||
|
}
|
||||||
if budget, ok := mapGeminiThinkingBudget(rawLevel); ok {
|
if budget, ok := mapGeminiThinkingBudget(rawLevel); ok {
|
||||||
config["thinkingBudget"] = budget
|
config["thinkingBudget"] = budget
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isGemini3ProModel(model) && (rawLevel == "off" || rawLevel == "minimal") {
|
||||||
|
// Gemini 3.x Pro does not support minimal thinking level.
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
if thinkingLevel := mapGeminiThinkingLevel(rawLevel); thinkingLevel != "" {
|
if thinkingLevel := mapGeminiThinkingLevel(rawLevel); thinkingLevel != "" {
|
||||||
config["thinkingLevel"] = thinkingLevel
|
config["thinkingLevel"] = thinkingLevel
|
||||||
}
|
}
|
||||||
@@ -369,6 +378,16 @@ func isGemini25Model(model string) bool {
|
|||||||
return strings.Contains(lowerModel, "gemini-2.5") || strings.Contains(lowerModel, "gemini-25")
|
return strings.Contains(lowerModel, "gemini-2.5") || strings.Contains(lowerModel, "gemini-25")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isGemini25ProModel(model string) bool {
|
||||||
|
lowerModel := strings.ToLower(strings.TrimSpace(model))
|
||||||
|
return isGemini25Model(lowerModel) && strings.Contains(lowerModel, "pro")
|
||||||
|
}
|
||||||
|
|
||||||
|
func isGemini3ProModel(model string) bool {
|
||||||
|
lowerModel := strings.ToLower(strings.TrimSpace(model))
|
||||||
|
return strings.Contains(lowerModel, "gemini-3") && strings.Contains(lowerModel, "pro")
|
||||||
|
}
|
||||||
|
|
||||||
func mapGeminiThinkingBudget(level string) (int, bool) {
|
func mapGeminiThinkingBudget(level string) (int, bool) {
|
||||||
level = strings.ToLower(strings.TrimSpace(level))
|
level = strings.ToLower(strings.TrimSpace(level))
|
||||||
if level == "" {
|
if level == "" {
|
||||||
|
|||||||
@@ -362,6 +362,56 @@ func TestGeminiProvider_BuildRequestBody_DefaultsThinkingOffForGemini3(t *testin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGeminiProvider_BuildRequestBody_DefaultsThinkingOffForGemini25Pro(t *testing.T) {
|
||||||
|
provider := NewGeminiProvider("test-key", "https://example.com/v1beta", "", "", 0, nil, nil)
|
||||||
|
body := provider.buildRequestBody(
|
||||||
|
[]Message{{Role: "user", Content: "hello"}},
|
||||||
|
nil,
|
||||||
|
"gemini-2.5-pro",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
generationConfig, ok := body["generationConfig"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("generationConfig = %#v, want map", body["generationConfig"])
|
||||||
|
}
|
||||||
|
thinkingConfig, ok := generationConfig["thinkingConfig"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("thinkingConfig = %#v, want map", generationConfig["thinkingConfig"])
|
||||||
|
}
|
||||||
|
if includeThoughts, ok := thinkingConfig["includeThoughts"].(bool); !ok || includeThoughts {
|
||||||
|
t.Fatalf("includeThoughts = %#v, want false for default/off", thinkingConfig["includeThoughts"])
|
||||||
|
}
|
||||||
|
if _, hasBudget := thinkingConfig["thinkingBudget"]; hasBudget {
|
||||||
|
t.Fatalf("thinkingBudget should be omitted for Gemini 2.5 Pro default/off: %#v", thinkingConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeminiProvider_BuildRequestBody_DefaultsThinkingOffForGemini31Pro(t *testing.T) {
|
||||||
|
provider := NewGeminiProvider("test-key", "https://example.com/v1beta", "", "", 0, nil, nil)
|
||||||
|
body := provider.buildRequestBody(
|
||||||
|
[]Message{{Role: "user", Content: "hello"}},
|
||||||
|
nil,
|
||||||
|
"gemini-3.1-pro",
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
generationConfig, ok := body["generationConfig"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("generationConfig = %#v, want map", body["generationConfig"])
|
||||||
|
}
|
||||||
|
thinkingConfig, ok := generationConfig["thinkingConfig"].(map[string]any)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("thinkingConfig = %#v, want map", generationConfig["thinkingConfig"])
|
||||||
|
}
|
||||||
|
if includeThoughts, ok := thinkingConfig["includeThoughts"].(bool); !ok || includeThoughts {
|
||||||
|
t.Fatalf("includeThoughts = %#v, want false for default/off", thinkingConfig["includeThoughts"])
|
||||||
|
}
|
||||||
|
if _, hasLevel := thinkingConfig["thinkingLevel"]; hasLevel {
|
||||||
|
t.Fatalf("thinkingLevel should be omitted for Gemini 3.1 Pro default/off: %#v", thinkingConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestGeminiProvider_BuildRequestBody_PreservesMultipleSystemMessages(t *testing.T) {
|
func TestGeminiProvider_BuildRequestBody_PreservesMultipleSystemMessages(t *testing.T) {
|
||||||
provider := NewGeminiProvider("test-key", "https://example.com/v1beta", "", "", 0, nil, nil)
|
provider := NewGeminiProvider("test-key", "https://example.com/v1beta", "", "", 0, nil, nil)
|
||||||
body := provider.buildRequestBody(
|
body := provider.buildRequestBody(
|
||||||
|
|||||||
Reference in New Issue
Block a user