Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions pkg/model/provider/gemini/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ func extractMimeType(dataURLPrefix string) string {
return "image/jpeg" // Default fallback
}

// buildConfig creates GenerateContentConfig from model config
// BuildConfig creates GenerateContentConfig from model config.
func (c *Client) buildConfig() *genai.GenerateContentConfig {
config := &genai.GenerateContentConfig{}
if c.ModelConfig.MaxTokens != nil {
Expand Down Expand Up @@ -453,7 +453,11 @@ func (c *Client) buildConfig() *genai.GenerateContentConfig {
// Apply thinking configuration for Gemini models.
// See https://ai.google.dev/gemini-api/docs/thinking
if c.ModelOptions.NoThinking() {
// NoThinking requested (e.g. title generation). For Gemini 3+ models
if c.ModelOptions.GeneratingTitle() {
return config
}

// NoThinking requested (e.g. MCP sampling). For Gemini 3+ models
// that always think, use the lowest level and bump MaxOutputTokens so
// internal reasoning doesn't consume the entire budget. Gemini 2.5 and
// older can fully disable thinking with ThinkingBudget=0.
Expand Down
64 changes: 64 additions & 0 deletions pkg/model/provider/gemini/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,74 @@ import (
"github.com/docker/docker-agent/pkg/chat"
"github.com/docker/docker-agent/pkg/config/latest"
"github.com/docker/docker-agent/pkg/model/provider/base"
"github.com/docker/docker-agent/pkg/model/provider/options"
"github.com/docker/docker-agent/pkg/modelsdev"
"github.com/docker/docker-agent/pkg/tools"
)

func TestBuildConfig_NoThinking(t *testing.T) {
t.Parallel()

tests := []struct {
name string
model string
opts []options.Opt
wantThinking bool
wantMinTokens bool
}{
{
name: "title generation omits thinking config",
model: "gemini-3-flash",
opts: []options.Opt{options.WithGeneratingTitle(), options.WithNoThinking()},
wantThinking: false,
},
{
name: "MCP sampling disables Gemini 3 thinking",
model: "gemini-3-flash",
opts: []options.Opt{options.WithNoThinking()},
wantThinking: true,
wantMinTokens: true,
},
{
name: "MCP sampling disables Gemini 2.5 thinking",
model: "gemini-2.5-flash",
opts: []options.Opt{options.WithNoThinking()},
wantThinking: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

client := &Client{Config: base.Config{
ModelConfig: latest.ModelConfig{
Provider: "google",
Model: tt.model,
ThinkingBudget: &latest.ThinkingBudget{Effort: "high"},
},
ModelOptions: options.Apply(tt.opts...),
}}

config := client.buildConfig()
if !tt.wantThinking {
assert.Nil(t, config.ThinkingConfig)
return
}

require.NotNil(t, config.ThinkingConfig)
assert.False(t, config.ThinkingConfig.IncludeThoughts)
if tt.wantMinTokens {
assert.Equal(t, genai.ThinkingLevelLow, config.ThinkingConfig.ThinkingLevel)
assert.GreaterOrEqual(t, config.MaxOutputTokens, int32(200))
return
}
require.NotNil(t, config.ThinkingConfig.ThinkingBudget)
assert.Zero(t, *config.ThinkingConfig.ThinkingBudget)
})
}
}

func TestBuildConfig_Gemini25_ThinkingBudget(t *testing.T) {
t.Parallel()

Expand Down
Loading