Skip to content

Commit d81d691

Browse files
committed
Fix gemini tool calls
There is no function or tool call id, so we make a unique one ourselves Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
1 parent d96d88c commit d81d691

2 files changed

Lines changed: 5 additions & 77 deletions

File tree

pkg/model/provider/gemini/adapter.go

Lines changed: 5 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package gemini
22

33
import (
44
"encoding/json"
5-
"fmt"
65
"io"
76
"log/slog"
87
"regexp"
@@ -11,6 +10,7 @@ import (
1110

1211
"github.com/docker/cagent/pkg/chat"
1312
"github.com/docker/cagent/pkg/tools"
13+
"github.com/google/uuid"
1414
"google.golang.org/genai"
1515
)
1616

@@ -140,52 +140,6 @@ func NewStreamAdapter(iter func(func(*genai.GenerateContentResponse, error) bool
140140
return adapter
141141
}
142142

143-
// NewNonStreamingAdapter creates a streaming adapter from a non-streaming response
144-
func NewNonStreamingAdapter(response *genai.GenerateContentResponse, model string) *StreamAdapter {
145-
adapter := &StreamAdapter{
146-
ch: make(chan result),
147-
model: model,
148-
}
149-
150-
go func() {
151-
defer close(adapter.ch)
152-
153-
// Send the complete response as a single chunk
154-
if response != nil {
155-
// Check if we should send the response (has content, function calls, or usage)
156-
hasContent := false
157-
158-
// Check for text content
159-
for _, candidate := range response.Candidates {
160-
if candidate.Content != nil {
161-
for _, part := range candidate.Content.Parts {
162-
if part.Text != "" {
163-
hasContent = true
164-
break
165-
}
166-
}
167-
}
168-
if hasContent {
169-
break
170-
}
171-
}
172-
173-
// Check for function calls
174-
hasFunctionCalls := len(response.FunctionCalls()) > 0
175-
176-
// Send response once if it has any relevant content
177-
if hasContent || hasFunctionCalls || response.UsageMetadata != nil {
178-
adapter.ch <- result{resp: response}
179-
}
180-
}
181-
182-
// Send final message
183-
adapter.ch <- result{done: true, resp: response}
184-
}()
185-
186-
return adapter
187-
}
188-
189143
// Recv gets the next Gemini content chunk
190144
func (g *StreamAdapter) Recv() (chat.MessageStreamResponse, error) {
191145
res, ok := <-g.ch
@@ -249,22 +203,19 @@ func (g *StreamAdapter) Recv() (chat.MessageStreamResponse, error) {
249203
for i, fc := range funcs {
250204
// Convert args to JSON string
251205
argsJSON, _ := json.Marshal(fc.Args)
206+
id := "call_" + uuid.New().String()
207+
slog.Debug("Gemini: Function call", "name", fc.Name, "args", string(argsJSON), "id", id)
252208
idx := i
253-
// Generate ID if not provided
254-
toolID := fc.ID
255-
if toolID == "" {
256-
toolID = fmt.Sprintf("call_%d", i)
257-
}
258209
resp.Choices[0].Delta.ToolCalls[i] = tools.ToolCall{
259210
Index: &idx,
260-
ID: toolID,
211+
ID: id,
261212
Type: "function",
262213
Function: tools.FunctionCall{
263214
Name: fc.Name,
264215
Arguments: string(argsJSON),
265216
},
266217
}
267-
slog.Debug("Gemini: Sending tool call", "name", fc.Name, "args", string(argsJSON), "id", toolID)
218+
slog.Debug("Gemini: Sending tool call", "name", fc.Name, "args", string(argsJSON), "id", fc.ID)
268219
}
269220
}
270221
}

pkg/model/provider/gemini/client.go

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -365,29 +365,6 @@ func (c *Client) CreateChatCompletionStream(
365365
slog.Debug("Message", "index", i, "role", content.Role)
366366
}
367367

368-
// For Gemini 2.5 models with thoughtSignature streaming issues,
369-
// try non-streaming first to avoid parsing problems
370-
if strings.Contains(c.config.Model, "2.5") {
371-
slog.Debug("Using non-streaming mode for Gemini 2.5 to avoid thoughtSignature parsing issues")
372-
var client *genai.Client
373-
if c.useGateway {
374-
if gwClient, err := c.newGatewayClient(ctx); err == nil {
375-
client = gwClient
376-
} else {
377-
client = c.client
378-
}
379-
} else {
380-
client = c.client
381-
}
382-
response, err := client.Models.GenerateContent(ctx, c.config.Model, contents, config)
383-
if err != nil {
384-
slog.Debug("Non-streaming failed, falling back to streaming", "error", err)
385-
} else {
386-
// Convert non-streaming response to streaming format
387-
return NewNonStreamingAdapter(response, c.config.Model), nil
388-
}
389-
}
390-
391368
// Build a fresh client per request when using the gateway
392369
var iter func(func(*genai.GenerateContentResponse, error) bool)
393370
if c.useGateway {

0 commit comments

Comments
 (0)