Fix tools calls, reasoning and usage (#37)

Kujtim Hoxha created

Change summary

providers/google/google.go                                                                | 102 
providers/google/provider_options.go                                                      |   8 
providertests/google_test.go                                                              |  11 
providertests/testdata/TestGoogleCommon/gemini-2.5-flash/multi_tool.yaml                  |  21 
providertests/testdata/TestGoogleCommon/gemini-2.5-flash/multi_tool_streaming.yaml        |   8 
providertests/testdata/TestGoogleCommon/gemini-2.5-flash/simple.yaml                      |  14 
providertests/testdata/TestGoogleCommon/gemini-2.5-flash/simple_streaming.yaml            |   6 
providertests/testdata/TestGoogleCommon/gemini-2.5-flash/tool.yaml                        |  25 
providertests/testdata/TestGoogleCommon/gemini-2.5-flash/tool_streaming.yaml              |   2 
providertests/testdata/TestGoogleCommon/gemini-2.5-pro/multi_tool.yaml                    |   2 
providertests/testdata/TestGoogleCommon/gemini-2.5-pro/multi_tool_streaming.yaml          |   2 
providertests/testdata/TestGoogleCommon/gemini-2.5-pro/simple.yaml                        |  14 
providertests/testdata/TestGoogleCommon/gemini-2.5-pro/simple_streaming.yaml              |   2 
providertests/testdata/TestGoogleCommon/gemini-2.5-pro/tool.yaml                          |  35 
providertests/testdata/TestGoogleCommon/gemini-2.5-pro/tool_streaming.yaml                |   2 
providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/simple.yaml              |   6 
providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/simple_streaming.yaml    |  62 
providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/tool.yaml                |  14 
providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/tool_streaming.yaml      |  87 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/multi_tool.yaml           |  22 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/multi_tool_streaming.yaml |   2 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/simple.yaml               |  20 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/simple_streaming.yaml     |   6 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/tool.yaml                 |  28 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/tool_streaming.yaml       |   2 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/multi_tool.yaml             |   3 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/multi_tool_streaming.yaml   |   2 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/simple.yaml                 |  20 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/simple_streaming.yaml       |   2 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/tool.yaml                   |  38 
providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/tool_streaming.yaml         |   2 
providertests/testdata/TestGoogleThinking/gemini-2.5-flash/thinking-streaming.yaml        |   2 
providertests/testdata/TestGoogleThinking/gemini-2.5-flash/thinking.yaml                  |  27 
providertests/testdata/TestGoogleThinking/gemini-2.5-pro/thinking-streaming.yaml          |   2 
providertests/testdata/TestGoogleThinking/gemini-2.5-pro/thinking.yaml                    |  29 
35 files changed, 334 insertions(+), 296 deletions(-)

Detailed changes

providers/google/google.go πŸ”—

@@ -25,16 +25,20 @@ type provider struct {
 	options options
 }
 
+// ToolCallIDFunc defines a function that generates a tool call ID.
+type ToolCallIDFunc = func() string
+
 type options struct {
-	apiKey   string
-	name     string
-	baseURL  string
-	headers  map[string]string
-	client   *http.Client
-	backend  genai.Backend
-	project  string
-	location string
-	skipAuth bool
+	apiKey     string
+	name       string
+	baseURL    string
+	headers    map[string]string
+	client     *http.Client
+	backend    genai.Backend
+	project    string
+	location   string
+	skipAuth   bool
+	generateID ToolCallIDFunc
 }
 
 // Option defines a function that configures Google provider options.
@@ -44,6 +48,9 @@ type Option = func(*options)
 func New(opts ...Option) (fantasy.Provider, error) {
 	options := options{
 		headers: map[string]string{},
+		generateID: func() string {
+			return uuid.NewString()
+		},
 	}
 	for _, o := range opts {
 		o(&options)
@@ -114,6 +121,14 @@ func WithHTTPClient(client *http.Client) Option {
 	}
 }
 
+// WithToolCallIDFunc sets the function that generates a tool call ID.
+// WithToolCallIDFunc sets the function that generates a tool call ID.
+func WithToolCallIDFunc(f ToolCallIDFunc) Option {
+	return func(o *options) {
+		o.generateID = f
+	}
+}
+
 func (*provider) Name() string {
 	return Name
 }
@@ -350,6 +365,9 @@ func toGooglePrompt(prompt fantasy.Prompt) (*genai.Content, []*genai.Content, []
 			}
 		case fantasy.MessageRoleAssistant:
 			var parts []*genai.Part
+			// INFO: (kujtim) this is kind of a hacky way to include thinking for google
+			// weirdly thinking needs to be included in a function call
+			var signature []byte
 			for _, part := range msg.Content {
 				switch part.GetType() {
 				case fantasy.ContentTypeText:
@@ -377,7 +395,27 @@ func toGooglePrompt(prompt fantasy.Prompt) (*genai.Content, []*genai.Content, []
 							Name: toolCall.ToolName,
 							Args: result,
 						},
+						ThoughtSignature: signature,
 					})
+					// reset
+					signature = nil
+				case fantasy.ContentTypeReasoning:
+					reasoning, ok := fantasy.AsMessagePart[fantasy.ReasoningPart](part)
+					if !ok {
+						continue
+					}
+					metadata, ok := reasoning.ProviderOptions[Name]
+					if !ok {
+						continue
+					}
+					reasoningMetadata, ok := metadata.(*ReasoningMetadata)
+					if !ok {
+						continue
+					}
+					if !ok || reasoningMetadata.Signature == "" {
+						continue
+					}
+					signature = []byte(reasoningMetadata.Signature)
 				}
 			}
 			if len(parts) > 0 {
@@ -476,7 +514,7 @@ func (g *languageModel) Generate(ctx context.Context, call fantasy.Call) (*fanta
 		return nil, err
 	}
 
-	return mapResponse(response, warnings)
+	return g.mapResponse(response, warnings)
 }
 
 // Model implements fantasy.LanguageModel.
@@ -523,7 +561,7 @@ func (g *languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.
 		var blockCounter int
 		var currentTextBlockID string
 		var currentReasoningBlockID string
-		var usage fantasy.Usage
+		var usage *fantasy.Usage
 		var lastFinishReason fantasy.FinishReason
 
 		for resp, err := range chat.SendMessageStream(ctx, depointerSlice(lastMessage.Parts)...) {
@@ -579,9 +617,15 @@ func (g *languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.
 								// End any active reasoning block before starting text
 								if isActiveReasoning {
 									isActiveReasoning = false
+									metadata := &ReasoningMetadata{
+										Signature: string(part.ThoughtSignature),
+									}
 									if !yield(fantasy.StreamPart{
 										Type: fantasy.StreamPartTypeReasoningEnd,
 										ID:   currentReasoningBlockID,
+										ProviderMetadata: fantasy.ProviderMetadata{
+											Name: metadata,
+										},
 									}) {
 										return
 									}
@@ -623,15 +667,22 @@ func (g *languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.
 						}
 						if isActiveReasoning {
 							isActiveReasoning = false
+
+							metadata := &ReasoningMetadata{
+								Signature: string(part.ThoughtSignature),
+							}
 							if !yield(fantasy.StreamPart{
 								Type: fantasy.StreamPartTypeReasoningEnd,
 								ID:   currentReasoningBlockID,
+								ProviderMetadata: fantasy.ProviderMetadata{
+									Name: metadata,
+								},
 							}) {
 								return
 							}
 						}
 
-						toolCallID := cmp.Or(part.FunctionCall.ID, part.FunctionCall.Name, uuid.NewString())
+						toolCallID := cmp.Or(part.FunctionCall.ID, g.providerOptions.generateID())
 
 						args, err := json.Marshal(part.FunctionCall.Args)
 						if err != nil {
@@ -686,7 +737,15 @@ func (g *languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.
 			}
 
 			if resp.UsageMetadata != nil {
-				usage = mapUsage(resp.UsageMetadata)
+				currentUsage := mapUsage(resp.UsageMetadata)
+				// if first usage chunk
+				if usage == nil {
+					usage = &currentUsage
+				} else {
+					usage.OutputTokens += currentUsage.OutputTokens
+					usage.ReasoningTokens += currentUsage.ReasoningTokens
+					usage.CacheReadTokens += currentUsage.CacheReadTokens
+				}
 			}
 
 			if len(resp.Candidates) > 0 && resp.Candidates[0].FinishReason != "" {
@@ -721,7 +780,7 @@ func (g *languageModel) Stream(ctx context.Context, call fantasy.Call) (fantasy.
 
 		yield(fantasy.StreamPart{
 			Type:         fantasy.StreamPartTypeFinish,
-			Usage:        usage,
+			Usage:        *usage,
 			FinishReason: finishReason,
 		})
 	}, nil
@@ -873,7 +932,7 @@ func mapJSONTypeToGoogle(jsonType string) genai.Type {
 	}
 }
 
-func mapResponse(response *genai.GenerateContentResponse, warnings []fantasy.CallWarning) (*fantasy.Response, error) {
+func (g languageModel) mapResponse(response *genai.GenerateContentResponse, warnings []fantasy.CallWarning) (*fantasy.Response, error) {
 	if len(response.Candidates) == 0 || response.Candidates[0].Content == nil {
 		return nil, errors.New("no response from model")
 	}
@@ -889,7 +948,10 @@ func mapResponse(response *genai.GenerateContentResponse, warnings []fantasy.Cal
 		switch {
 		case part.Text != "":
 			if part.Thought {
-				content = append(content, fantasy.ReasoningContent{Text: part.Text})
+				metadata := &ReasoningMetadata{
+					Signature: string(part.ThoughtSignature),
+				}
+				content = append(content, fantasy.ReasoningContent{Text: part.Text, ProviderMetadata: fantasy.ProviderMetadata{Name: metadata}})
 			} else {
 				content = append(content, fantasy.TextContent{Text: part.Text})
 			}
@@ -898,7 +960,7 @@ func mapResponse(response *genai.GenerateContentResponse, warnings []fantasy.Cal
 			if err != nil {
 				return nil, err
 			}
-			toolCallID := cmp.Or(part.FunctionCall.ID, part.FunctionCall.Name, uuid.NewString())
+			toolCallID := cmp.Or(part.FunctionCall.ID, g.providerOptions.generateID())
 			content = append(content, fantasy.ToolCallContent{
 				ToolCallID:       toolCallID,
 				ToolName:         part.FunctionCall.Name,
@@ -951,11 +1013,11 @@ func mapFinishReason(reason genai.FinishReason) fantasy.FinishReason {
 
 func mapUsage(usage *genai.GenerateContentResponseUsageMetadata) fantasy.Usage {
 	return fantasy.Usage{
-		InputTokens:         int64(usage.ToolUsePromptTokenCount),
+		InputTokens:         int64(usage.PromptTokenCount),
 		OutputTokens:        int64(usage.CandidatesTokenCount),
 		TotalTokens:         int64(usage.TotalTokenCount),
 		ReasoningTokens:     int64(usage.ThoughtsTokenCount),
-		CacheCreationTokens: int64(usage.CachedContentTokenCount),
-		CacheReadTokens:     0,
+		CacheCreationTokens: 0,
+		CacheReadTokens:     int64(usage.CachedContentTokenCount),
 	}
 }

providers/google/provider_options.go πŸ”—

@@ -9,6 +9,14 @@ type ThinkingConfig struct {
 	IncludeThoughts *bool  `json:"include_thoughts"`
 }
 
+// ReasoningMetadata represents reasoning metadata for the Google provider.
+type ReasoningMetadata struct {
+	Signature string `json:"signature"`
+}
+
+// Options implements the ProviderOptionsData interface for ReasoningMetadata.
+func (m *ReasoningMetadata) Options() {}
+
 // SafetySetting represents safety settings for the Google provider.
 type SafetySetting struct {
 	// 'HARM_CATEGORY_UNSPECIFIED',

providertests/google_test.go πŸ”—

@@ -2,6 +2,7 @@ package providertests
 
 import (
 	"cmp"
+	"fmt"
 	"net/http"
 	"os"
 	"testing"
@@ -69,11 +70,20 @@ func testGoogleThinking(t *testing.T, result *fantasy.AgentResult) {
 	require.Greater(t, reasoningContentCount, 0)
 }
 
+func generateIDMock() google.ToolCallIDFunc {
+	id := 0
+	return func() string {
+		id++
+		return fmt.Sprintf("%d", id)
+	}
+}
+
 func geminiBuilder(model string) builderFunc {
 	return func(t *testing.T, r *recorder.Recorder) (fantasy.LanguageModel, error) {
 		provider, err := google.New(
 			google.WithGeminiAPIKey(cmp.Or(os.Getenv("FANTASY_GEMINI_API_KEY"), "(missing)")),
 			google.WithHTTPClient(&http.Client{Transport: r}),
+			google.WithToolCallIDFunc(generateIDMock()),
 		)
 		if err != nil {
 			return nil, err
@@ -88,6 +98,7 @@ func vertexBuilder(model string) builderFunc {
 			google.WithVertex(os.Getenv("FANTASY_VERTEX_PROJECT"), os.Getenv("FANTASY_VERTEX_LOCATION")),
 			google.WithHTTPClient(&http.Client{Transport: r}),
 			google.WithSkipAuth(!r.IsRecording()),
+			google.WithToolCallIDFunc(generateIDMock()),
 		)
 		if err != nil {
 			return nil, err

providertests/testdata/TestGoogleCommon/gemini-2.5-flash/multi_tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -37,14 +37,14 @@ interactions:
                       "b": 3
                     }
                   },
-                  "thoughtSignature": "Cr4BAdHtim9LvttVUIQ0QpEtexErSfMWokWFxdJCGfdh4M6N0YBwqI+kBhIbVJOwQonI1GmBaw8lfUzjvYYW2ScSRvYAUJoBWMRuLzcaafC/2FnOcLPR9hyaC9499fBWocLFbnCRO/0bzA+Z4uAS81EL/zTqCsZuO5OS5KwvLe9OIbPXrMc65pKhED6D80UaJe9+9OfeIKsTf53yxXUk7elFlA//EukpULLiadHrHKMVFu9FKnHwFBQ+BsY9lALcSg=="
+                  "thoughtSignature": "CrwBAdHtim/FP8KqTMIQ2DVD+5BAiIXjN0k+ERNVFbVGtenSKcR/G6MtoIcIE/2nxX2ysKRnwClCPnq5+/KJSzS8uFjvU0577RF+LrP7bRIXSNoufBoAJV0aKusqd1DtXQBZif76FBAMtgiG42NALcM0+Jxs2JaKOhFof+1GhNOi8Zbnj+S/YYkU34CvqANixzHQCFkLpFpHbOmsqfYaiMol4juPFMVOJg2w1WZMS/0mE36gP5C8i8p3B0njO9E="
                 },
                 {
                   "functionCall": {
                     "name": "multiply",
                     "args": {
-                      "a": 2,
-                      "b": 3
+                      "b": 3,
+                      "a": 2
                     }
                   }
                 }
@@ -52,44 +52,45 @@ interactions:
               "role": "model"
             },
             "finishReason": "STOP",
-            "index": 0
+            "index": 0,
+            "finishMessage": "Model generated function call(s)."
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 125,
           "candidatesTokenCount": 36,
-          "totalTokenCount": 200,
+          "totalTokenCount": 201,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 125
             }
           ],
-          "thoughtsTokenCount": 39
+          "thoughtsTokenCount": 40
         },
         "modelVersion": "gemini-2.5-flash",
-        "responseId": "53LWaN-ZF8_l7M8Pt4CxmQE"
+        "responseId": "WtH5aJy3I4K0nsEPiZnbmQs"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.153815667s
+    duration: 1.046624584s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 1173
+    content_length: 1155
     host: generativelanguage.googleapis.com
     body: |

providertests/testdata/TestGoogleCommon/gemini-2.5-flash/multi_tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
-    body: "data: {\"candidates\": [{\"content\": {\"parts\": [{\"functionCall\": {\"name\": \"add\",\"args\": {\"b\": 3,\"a\": 2}},\"thoughtSignature\": \"CikB0e2Kb3lvvSL0It28ryFF9z5njRrxz3nsWrllFnR383RdO+Nvx+O+jAptAdHtim90asVCH4fPJo0zzAM1LahZnmnG89/nkCa+cp1fnFR9gNoREBnHD+AeskNrSR799cQqjqA9e/fU82a1LDE59kURBuczfm0udTUlIHvry3e8sg4ST4P3T1HxxDl7fdjSs6U0OYGcu4J1TgpnAdHtim8/SPXWy3ZQd+BX+TdRCZ+dmdpkztv5mNK8x6m8pkAIeVPJOQq2xOq1R4kXryxbzcjeEgW60lBKOaHz8sVUMkuHC03Y0WnuNr29ObdqmLCQdSFRvpLljGIXoYQU4egHik5IiQ==\"},{\"functionCall\": {\"name\": \"multiply\",\"args\": {\"b\": 3,\"a\": 2}}}],\"role\": \"model\"},\"finishReason\": \"STOP\",\"index\": 0}],\"usageMetadata\": {\"promptTokenCount\": 121,\"candidatesTokenCount\": 36,\"totalTokenCount\": 195,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 121}],\"thoughtsTokenCount\": 38},\"modelVersion\": \"gemini-2.5-flash\",\"responseId\": \"6HLWaOOUB8W1nsEP0aLTmQs\"}\r\n\r\n"
+    body: "data: {\"candidates\": [{\"content\": {\"parts\": [{\"functionCall\": {\"name\": \"add\",\"args\": {\"a\": 2,\"b\": 3}},\"thoughtSignature\": \"CiQB0e2Kb02QlBJ2I5/zDqv1c0AUEV+Ct+vGYwdFdWC3cx3yIuUKXQHR7Ypv3ZUytEmQlCdJhzrfshB8YFIoW134jv3AuUL8L16mz3cXjEvhr8tAFeSEScUollNyBu/e3OFraKdblEfpDXY2UASkOMhrezbveAaD4bxTeBmXbcJNqLFeTwp/AdHtim8YarufF4O5TXWRjFYgnIppzlQcQfTEyqqmA8J3gLjGgyROG7/2MSw/0EakJKFOXuFth2Sdskl1sLjsD7lOvAxbmzDHITcg9l39JrSaXcHN405OLs1bfgIhKdi8m/wq+MXPL72IOuO6YjuBjud9qruxF3/THtP+netVeA==\"},{\"functionCall\": {\"name\": \"multiply\",\"args\": {\"b\": 3,\"a\": 2}}}],\"role\": \"model\"},\"finishReason\": \"STOP\",\"index\": 0,\"finishMessage\": \"Model generated function call(s).\"}],\"usageMetadata\": {\"promptTokenCount\": 121,\"candidatesTokenCount\": 36,\"totalTokenCount\": 196,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 121}],\"thoughtsTokenCount\": 39},\"modelVersion\": \"gemini-2.5-flash\",\"responseId\": \"XNH5aLSAF8GznsEP9sXIsAs\"}\r\n\r\n"
     headers:
       Content-Type:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 798.333667ms
+    duration: 1.227179416s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 1156
+    content_length: 1138
     host: generativelanguage.googleapis.com
     body: |

providertests/testdata/TestGoogleCommon/gemini-2.5-flash/simple.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -30,7 +30,7 @@ interactions:
             "content": {
               "parts": [
                 {
-                  "text": "OlΓ‘!\n\nIn Portuguese, \"hi\" or \"hello\" is **\"OlΓ‘\"**."
+                  "text": "OlΓ‘!"
                 }
               ],
               "role": "model"
@@ -41,22 +41,22 @@ interactions:
         ],
         "usageMetadata": {
           "promptTokenCount": 11,
-          "candidatesTokenCount": 19,
-          "totalTokenCount": 54,
+          "candidatesTokenCount": 2,
+          "totalTokenCount": 51,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 11
             }
           ],
-          "thoughtsTokenCount": 24
+          "thoughtsTokenCount": 38
         },
         "modelVersion": "gemini-2.5-flash",
-        "responseId": "4nLWaKeCGN-ynsEPsYS_iAs"
+        "responseId": "VNH5aLz3OsyinsEP1JWGwAY"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 831.958458ms
+    duration: 1.251824334s

providertests/testdata/TestGoogleCommon/gemini-2.5-flash/simple_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,10 +25,10 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
-    body: "data: {\"candidates\": [{\"content\": {\"parts\": [{\"text\": \"OlΓ‘!\"}],\"role\": \"model\"},\"finishReason\": \"STOP\",\"index\": 0}],\"usageMetadata\": {\"promptTokenCount\": 11,\"candidatesTokenCount\": 2,\"totalTokenCount\": 39,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 11}],\"thoughtsTokenCount\": 26},\"modelVersion\": \"gemini-2.5-flash\",\"responseId\": \"4nLWaP6OKvCDkdUP7Ze-gAc\"}\r\n\r\n"
+    body: "data: {\"candidates\": [{\"content\": {\"parts\": [{\"text\": \"OlΓ‘!\"}],\"role\": \"model\"},\"finishReason\": \"STOP\",\"index\": 0}],\"usageMetadata\": {\"promptTokenCount\": 11,\"candidatesTokenCount\": 2,\"totalTokenCount\": 36,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 11}],\"thoughtsTokenCount\": 23},\"modelVersion\": \"gemini-2.5-flash\",\"responseId\": \"VtH5aOrPCKXe7M8PyIqmyAQ\"}\r\n\r\n"
     headers:
       Content-Type:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 423.699166ms
+    duration: 1.273950833s

providertests/testdata/TestGoogleCommon/gemini-2.5-flash/tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -36,50 +36,51 @@ interactions:
                       "location": "Florence,Italy"
                     }
                   },
-                  "thoughtSignature": "CoQCAdHtim/RXh2BurmfhDAIWuDZaECZhw96eMGy0JrHOvouNR43xVQZdtrsPVDRc9XlaGzzZMpiBeJ90773lWhO96qMygspNDBUXQLCnl73AjXpkroRFxcupqHe0xjcZq1WwTLqmq+1JOcdZ4EY9MQl2LkBccWIM38fZFW0bV76uuGAikuhRw8huaD7EjP/8819+E7WVVGKjmaYr2lchfYv36/1OJU4Y2cqwgO6aNTEyVBYmbs61vN4SaNhj+ogcJ6orbgNLiq0Q2nfLL2LPLBxW3MfefywSvaq147G6NmA6HCfno10SEBA5tmrNfmFMvfdOcppyRB8rfDU0QXcyDnJEhUNfrQ="
+                  "thoughtSignature": "Cq4CAdHtim/sCKoBA0iloUCbLJWtYGJ3Erj6sIXdg1uSnBCPSFzy/3AeL+OpNUxx+N1pYyE7i0pmxs4o2aws3AdQiEN3ATSeiIVjI9BSNXo32VsDtcGmKtB1Gd+p/3MJSh9BCfA1ob6StFyP6Fn7aUoXpPEzV0JN54wDGaBskFWVwXY3sSx7vNU4akaRYYATrg49z66uUqPN+j95C2d8dRYBJe7bJqYbLi4w96Wzl5gLpAURmMv/XlJrK33cf/69yTrxVmQ2nxIeP7ok710y5FIz1n3x1GmQ6ZsQsoJ6QfDLr3lmTFH0DP91MUYB0w28nJ/dMz61MYzOWPNsL1GgHce13+sQTfxLGli+7Tw9/aNXJkxlU9mBpRCdHrLJXLvT9dctSeQ0BzOrrmmFckp3sRs="
                 }
               ],
               "role": "model"
             },
             "finishReason": "STOP",
-            "index": 0
+            "index": 0,
+            "finishMessage": "Model generated function call(s)."
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 54,
           "candidatesTokenCount": 15,
-          "totalTokenCount": 122,
+          "totalTokenCount": 134,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 54
             }
           ],
-          "thoughtsTokenCount": 53
+          "thoughtsTokenCount": 65
         },
         "modelVersion": "gemini-2.5-flash",
-        "responseId": "43LWaMOULuH6nsEP-JagUA"
+        "responseId": "V9H5aMaoC7b1kdUP5pDSgA0"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 926.95325ms
+    duration: 912.648167ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 734
+    content_length: 722
     host: generativelanguage.googleapis.com
     body: |
-      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence,Italy"},"id":"weather","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"weather","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
+      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence,Italy"},"id":"1","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"1","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
     headers:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -116,11 +117,11 @@ interactions:
           ]
         },
         "modelVersion": "gemini-2.5-flash",
-        "responseId": "5HLWaP7VKJS9kdUP1JnEcA"
+        "responseId": "V9H5aPKVNI_i7M8P5667uQs"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 906.09475ms
+    duration: 754.80525ms

providertests/testdata/TestGoogleCommon/gemini-2.5-flash/tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/gemini-2.5-pro/multi_tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -37,7 +37,7 @@ interactions:
                       "b": 3
                     }
                   },

providertests/testdata/TestGoogleCommon/gemini-2.5-pro/multi_tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/gemini-2.5-pro/simple.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -30,7 +30,7 @@ interactions:
             "content": {
               "parts": [
                 {
-                  "text": "Of course!\n\nThe most common ways to say \"hi\" in Portuguese are:\n\n*   **OlΓ‘** (A bit more formal, like \"hello\")\n*   **Oi** (Very common and casual, like \"hi\")"
+                  "text": "Of course!\n\nThe most common ways to say \"hi\" in Portuguese are:\n\n*   **OlΓ‘** (This is like \"hello\" and works in any situation, formal or informal.)\n*   **Oi** (This is more like \"hi\" and is very common and informal, especially in Brazil.)\n\nYou can also use a friendly greeting like:\n\n*   **Tudo bem?** (Literally \"All good?\" but used to mean \"How are you?\")"
                 }
               ],
               "role": "model"
@@ -41,22 +41,22 @@ interactions:
         ],
         "usageMetadata": {
           "promptTokenCount": 11,
-          "candidatesTokenCount": 49,
-          "totalTokenCount": 677,
+          "candidatesTokenCount": 100,
+          "totalTokenCount": 893,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 11
             }
           ],
-          "thoughtsTokenCount": 617
+          "thoughtsTokenCount": 782
         },
         "modelVersion": "gemini-2.5-pro",
-        "responseId": "8HLWaNeEFcqpkdUPnej7cA"
+        "responseId": "Z9H5aM_PPKKBkdUP-OO7oAM"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 7.315723791s
+    duration: 10.457368166s

providertests/testdata/TestGoogleCommon/gemini-2.5-pro/simple_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,10 +25,10 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/gemini-2.5-pro/tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -36,50 +36,51 @@ interactions:
                       "location": "Florence, Italy"
                     }
                   },
-                  "thoughtSignature": "CoIEADAxMjP/1r9Ehb1hMsCGxmRcIP+NfJYs5AhN1vOqcJSADnQNg0th80QbX5wKXuEj5Qf/EhEXvIKSHiTZTEIre13But3TzRwORDAJjrprSqG778poPprDsbFv+mUlydKMQ/2xv32LcNVeAAWf/b3fp9LX+02t2LWNh1Q07j50ok7vf5pTaH3MVY6xTKekx9mSen3IsKX1u95mu8EJKBCd7bUJri8WZDuuh7ujhWZxfcSe0uRtwQTPCxzY0ZPwOdKPh0Pi4qqwTIBUgczVJHdAzwZrJGLlf5X53i/tcV3N0x8/Evg5yMrqrTrmOKW6j7fcYpvnVi6qa+VTQsFLBgMmA3sB+KiHEepTUjqOzVsONvCPEUY401AmopBy/+0IZKXAoSFrfMDI5nYc+QtxBH2d0QIfk9ZAYY98B3vo1edYZt7Hzc8D/YkBHUcmMsIjVYyfTyuWGalq0vXYqj6jzjHKu1t+oIV6GhehVhCX6MFNu2ogIFPREusFNmqHQvRsIIaatOgddEEy+kath3csDKU41RKvD6XCtt0LkAwCVR/S+zJHdphGkgy3DxAENrmpOLkP/4DPMv/VvmtPcVo9pp2GGy515YnrPgPD9N++lPFXB+pY27tVhCpgRo/XDnM7cot64U3IURL35jgvYPytKsU7J9+G+KI/uUFKhDLKfpsFCJMVaw=="
+                  "thoughtSignature": "CoUDAdHtim/bgtT9Odj2/r1QcjzgE9Zr7qHxmcWWEWix5kqp2At0qQunrv0dH5Lpnh6leBLIjYTZh9Zws11pzYaMxpo8FuY9ajBeG2xcYNkBtmCpNTwXNMODKv90J0jq6PM3RsddM4a0yqfcr8ES2PEtD6XY5KJBdtmcdgIZI6T0S03ITXOXfcwtAoOP5Jm0cdl2YmnvafVbJYCnNlZjuOvpGCMaJIsW8fG9lJZRJKDeg7v80t5sN91085qOP1ZdfhiXxOB/GumlRYO/u35IK3Me35wJI+oFCb1tFxEK7w6HrCBBXduvZqneGgwZyMH+clrRZ6euFhy5uF5xUJPPfeXxLJIw40x6l1bWjAmOtTtiQXFmTSYLerz1iZeFPnZxzbRz0Vr9k4kUBjEEppCgKHm/VN0dfsG0bmrRBIgkJ166xlhwZBJu6cic2Iabw50Sow/VLhzYCXuLQ7lfcL2g5s6arkIAEY62N9gIYpGNRWWh9qghP47ouM5cKzCe1WVWAHIXcs1XBrU="
                 }
               ],
               "role": "model"
             },
             "finishReason": "STOP",
-            "index": 0
+            "index": 0,
+            "finishMessage": "Model generated function call(s)."
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 54,
           "candidatesTokenCount": 15,
-          "totalTokenCount": 188,
+          "totalTokenCount": 162,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 54
             }
           ],
-          "thoughtsTokenCount": 119
+          "thoughtsTokenCount": 93
         },
         "modelVersion": "gemini-2.5-pro",
-        "responseId": "_HLWaOTEEaaE7M8P2v-q6AY"
+        "responseId": "dNH5aK6UFNX1kdUPluXGkAs"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 2.570022292s
+    duration: 3.179773083s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 735
+    content_length: 723
     host: generativelanguage.googleapis.com
     body: |
-      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"weather","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"weather","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
+      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"1","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"1","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
     headers:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -95,8 +96,7 @@ interactions:
             "content": {
               "parts": [
                 {
-                  "text": "It is 40 C in Florence, Italy.",
-                  "thoughtSignature": "CrEFADAxMjOTETaUeVTeEBfr/K5W2YcCHTKu2k2V7oGdytdZWBmRyAWtt6l1BEuP1CaoRb5xKDNZiZAPbwfsZjb4xW7nV34Va6I7Q7XtewDymKsCwTGoO6pbJJ02jm/LgjSsv6LsHxu37DlTo2IQzaM9OgEGRqRksE4FcGNJA06RBbm3KZLUJLue19ZW9E1ucict1u+jc7W/Hk+JqYdd3nlZPEVsbAdAVhxV3gsh6ElJuK47hAzj1sEbzt2pxEMx7abDMxAxPsm+i059DM3URTOcsHGHApsr3fvjdFReFGA+HyPm37wTysqoOsP6pjUzAN6IKP+OFYP1fZcWUsR4rI6pn1KSPGcl37pT3vGbkLTjxHahTMdcnipUTOTQRP/FkG99SeYcqXGWDTeXjbOR4GnrFIFGVHog7VUmMN7bx9UUpnOQ6chGzT7ZoayyhcQTCi5yYCzNAT4rXgg0eCwpMu13OTaeI+KVIbuCqgKLswrQ+9nllsRgpngmoE2p3U+Y1FFz0intoU2tBDI6AVf134xvnBWHVsbWry05QJPP5RQQYJ3EHEvYaHdWkHiWuO8i9aZ99YQ0U6O92Sy0i31qY8eXLH1JzZ/KESHra7pDOPUPNAgnZLxm3gnbfUafehEEes0NG4DJ8YIh4Lqy25g+Uk6IXl6WzCiHiveji5towENouDnmAc9ONCXX5rf2a+Gv392bdO9bIXzaWdRTVBWdfgq0NcqX+o2uqZL9+oK5tgho5YodFN4Y9yA1cR+zJV+cEJ80s1Td8kEF4oFpQgleLmid+sXtWS7zRd0CoTM0MuKXrfFzmZVAYSWrOnI06Bfjp2yuVt0EfwmZnTb2iaL/WcFoErPtu4cotTnl+zcZe53hEytICMm2JdpVjia5SoVttqe0Vuusk5cD86WPQ8Bu2JSfP8s="
+                  "text": "The weather in Florence, Italy is 40 C. \n"
                 }
               ],
               "role": "model"
@@ -107,22 +107,21 @@ interactions:
         ],
         "usageMetadata": {
           "promptTokenCount": 84,
-          "candidatesTokenCount": 11,
-          "totalTokenCount": 261,
+          "candidatesTokenCount": 12,
+          "totalTokenCount": 96,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 84
             }
-          ],
-          "thoughtsTokenCount": 166
+          ]
         },
         "modelVersion": "gemini-2.5-pro",
-        "responseId": "_3LWaM30LrSC7M8PlbSegA4"
+        "responseId": "d9H5aJKyGI3rnsEP9MvF6Qs"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 3.478226625s
+    duration: 3.521672167s

providertests/testdata/TestGoogleCommon/gemini-2.5-pro/tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/simple.yaml πŸ”—

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.13.0
+      - Anthropic/Go 1.14.0
     url: https://us-east5-aiplatform.googleapis.com/v1/projects/fantasy-playground-472418/locations/us-east5/publishers/anthropic/models/claude-3-7-sonnet@20250219:rawPredict
     method: POST
   response:
@@ -24,10 +24,10 @@ interactions:
     proto_minor: 0
     content_length: -1
     uncompressed: true
-    body: '{"id":"msg_vrtx_01JoBtryoxdRxCJ4GfXam6Yu","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[{"type":"text","text":"OlΓ‘! That''s \"hi\" in Portuguese. I can also say \"Oi\" which is a more casual greeting in Portuguese."}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":16,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":33}}'
+    body: '{"model":"claude-3-7-sonnet-20250219","id":"msg_vrtx_01RTPizSndQfkUH6eWrcFtk8","type":"message","role":"assistant","content":[{"type":"text","text":"OlΓ‘! Como vocΓͺ estΓ‘? (This means \"Hi! How are you?\" in Portuguese.)"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":16,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":24}}'
     headers:
       Content-Type:
       - application/json
     status: 200 OK
     code: 200
-    duration: 1.987505375s
+    duration: 2.138460417s

providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/simple_streaming.yaml πŸ”—

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.13.0
+      - Anthropic/Go 1.14.0
     url: https://us-east5-aiplatform.googleapis.com/v1/projects/fantasy-playground-472418/locations/us-east5/publishers/anthropic/models/claude-3-7-sonnet@20250219:streamRawPredict
     method: POST
   response:
@@ -26,7 +26,7 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_vrtx_01551jxgCbyerbL44qCuV9kn","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":16,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":5}}            }
+      data: {"type":"message_start","message":{"model":"claude-3-7-sonnet-20250219","id":"msg_vrtx_01UZhFsyrYaUuvRKEzxJ7FkK","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":16,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":5}}  }
 
       event: ping
       data: {"type": "ping"}
@@ -35,68 +35,20 @@ interactions:
       data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""} }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"OlΓ‘!"}            }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"\n\n\""}               }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"OlΓ‘\" is"} }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the"} }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Portuguese way"}           }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" to say"}   }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" \"hi"}         }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"\" or \"hello.\""}        }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" It's a friendly"}      }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" greeting"}               }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" use"}        }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d in both"}             }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Portugal"}   }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" and Brazil,"}}
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" as"}               }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" well as other"}              }
-
-      event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Portuguese-speaking countries."}   }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"OlΓ‘!"}      }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0}
+      data: {"type":"content_block_stop","index":0        }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":47}               }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":7} }
 
       event: message_stop
-      data: {"type":"message_stop"        }
+      data: {"type":"message_stop"          }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.902656792s
+    duration: 1.311998834s

providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/tool.yaml πŸ”—

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.13.0
+      - Anthropic/Go 1.14.0
     url: https://us-east5-aiplatform.googleapis.com/v1/projects/fantasy-playground-472418/locations/us-east5/publishers/anthropic/models/claude-3-7-sonnet@20250219:rawPredict
     method: POST
   response:
@@ -24,13 +24,13 @@ interactions:
     proto_minor: 0
     content_length: -1
     uncompressed: true
-    body: '{"id":"msg_vrtx_012JnDNruXUPVCywN7jYpwZ8","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[{"type":"text","text":"I''ll check the current weather in Florence, Italy for you."},{"type":"tool_use","id":"toolu_vrtx_0129YeW9ohuKMKgnDRAStbvo","name":"weather","input":{"location":"Florence,Italy"}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":394,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":67}}'
+    body: '{"model":"claude-3-7-sonnet-20250219","id":"msg_vrtx_01HMPWEJiA8uwFGoNxfXG78Z","type":"message","role":"assistant","content":[{"type":"text","text":"I''ll check the current weather in Florence, Italy for you."},{"type":"tool_use","id":"toolu_vrtx_017DkoRKzJJVLa8p4HV1RdJp","name":"weather","input":{"location":"Florence,Italy"}}],"stop_reason":"tool_use","stop_sequence":null,"usage":{"input_tokens":394,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":67}}'
     headers:
       Content-Type:
       - application/json
     status: 200 OK
     code: 200
-    duration: 1.557585167s
+    duration: 1.494068458s
 - id: 1
   request:
     proto: HTTP/1.1
@@ -38,14 +38,14 @@ interactions:
     proto_minor: 1
     content_length: 881
     host: ""
-    body: '{"max_tokens":4000,"messages":[{"content":[{"text":"What''s the weather in Florence,Italy?","type":"text"}],"role":"user"},{"content":[{"text":"I''ll check the current weather in Florence, Italy for you.","type":"text"},{"id":"toolu_vrtx_0129YeW9ohuKMKgnDRAStbvo","input":{"location":"Florence,Italy"},"name":"weather","type":"tool_use"}],"role":"assistant"},{"content":[{"tool_use_id":"toolu_vrtx_0129YeW9ohuKMKgnDRAStbvo","content":[{"text":"40 C","type":"text"}],"type":"tool_result"}],"role":"user"}],"system":[{"text":"You are a helpful assistant","type":"text"}],"tool_choice":{"disable_parallel_tool_use":false,"type":"auto"},"tools":[{"input_schema":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"},"name":"weather","description":"Get weather information for a location"}],"anthropic_version":"vertex-2023-10-16"}'
+    body: '{"max_tokens":4000,"messages":[{"content":[{"text":"What''s the weather in Florence,Italy?","type":"text"}],"role":"user"},{"content":[{"text":"I''ll check the current weather in Florence, Italy for you.","type":"text"},{"id":"toolu_vrtx_017DkoRKzJJVLa8p4HV1RdJp","input":{"location":"Florence,Italy"},"name":"weather","type":"tool_use"}],"role":"assistant"},{"content":[{"tool_use_id":"toolu_vrtx_017DkoRKzJJVLa8p4HV1RdJp","content":[{"text":"40 C","type":"text"}],"type":"tool_result"}],"role":"user"}],"system":[{"text":"You are a helpful assistant","type":"text"}],"tool_choice":{"disable_parallel_tool_use":false,"type":"auto"},"tools":[{"input_schema":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"},"name":"weather","description":"Get weather information for a location"}],"anthropic_version":"vertex-2023-10-16"}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.13.0
+      - Anthropic/Go 1.14.0
     url: https://us-east5-aiplatform.googleapis.com/v1/projects/fantasy-playground-472418/locations/us-east5/publishers/anthropic/models/claude-3-7-sonnet@20250219:rawPredict
     method: POST
   response:
@@ -54,10 +54,10 @@ interactions:
     proto_minor: 0
     content_length: -1
     uncompressed: true
-    body: '{"id":"msg_vrtx_015jg26txA4Uuayzue6Q8PP4","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[{"type":"text","text":"The current temperature in Florence, Italy is 40Β°C (104Β°F), which is extremely hot. If you''re in Florence or planning to visit soon, I''d recommend staying hydrated, seeking shade when possible, and perhaps planning indoor activities during the hottest parts of the day."}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":475,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":63}}'
+    body: '{"model":"claude-3-7-sonnet-20250219","id":"msg_vrtx_01BJEBEdTy82Hb4nNAn5b1GE","type":"message","role":"assistant","content":[{"type":"text","text":"It''s currently 40Β°C (104Β°F) in Florence, Italy. That''s very hot! Make sure to stay hydrated and try to avoid being outside during the hottest parts of the day if possible."}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":475,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":49}}'
     headers:
       Content-Type:
       - application/json
     status: 200 OK
     code: 200
-    duration: 1.644774333s
+    duration: 1.508433666s

providertests/testdata/TestGoogleCommon/vertex-claude-3-7-sonnet/tool_streaming.yaml πŸ”—

@@ -15,7 +15,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.13.0
+      - Anthropic/Go 1.14.0
     url: https://us-east5-aiplatform.googleapis.com/v1/projects/fantasy-playground-472418/locations/us-east5/publishers/anthropic/models/claude-3-7-sonnet@20250219:streamRawPredict
     method: POST
   response:
@@ -26,52 +26,52 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_vrtx_01MtpPXF7gH6SFEyKNTJLWEw","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":394,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":3}}      }
+      data: {"type":"message_start","message":{"model":"claude-3-7-sonnet-20250219","id":"msg_vrtx_018pH9zeQy8MYJ3gttq4JD8x","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":394,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":5}}            }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_start
-      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}   }
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}             }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"I'll check"}       }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"I'll check the current"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the current weather in"}          }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" weather in"}            }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Florence, Italy for you"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Florence, Italy for you"}         }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."}       }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"."}         }
 
       event: content_block_stop
       data: {"type":"content_block_stop","index":0              }
 
       event: content_block_start
-      data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_vrtx_01Tj3azsUbpPDwNvW3itTJ3L","name":"weather","input":{}}          }
+      data: {"type":"content_block_start","index":1,"content_block":{"type":"tool_use","id":"toolu_vrtx_01QqhPGFZ4wcxFxZLX6rF6ht","name":"weather","input":{}}  }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}   }
+      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":""}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"locatio"}   }
+      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"{\"loca"}         }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"n\": \"Fl"}             }
+      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"tion\": \"Fl"}           }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"ore"}}
+      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"orence,I"}          }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"nce,Italy\"}"}             }
+      data: {"type":"content_block_delta","index":1,"delta":{"type":"input_json_delta","partial_json":"taly\"}"}             }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":1  }
+      data: {"type":"content_block_stop","index":1      }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":67}            }
+      data: {"type":"message_delta","delta":{"stop_reason":"tool_use","stop_sequence":null},"usage":{"output_tokens":67}    }
 
       event: message_stop
       data: {"type":"message_stop"  }
@@ -81,7 +81,7 @@ interactions:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 790.875833ms
+    duration: 1.365237292s
 - id: 1
   request:
     proto: HTTP/1.1
@@ -89,14 +89,14 @@ interactions:
     proto_minor: 1
     content_length: 895
     host: ""
-    body: '{"max_tokens":4000,"messages":[{"content":[{"text":"What''s the weather in Florence,Italy?","type":"text"}],"role":"user"},{"content":[{"text":"I''ll check the current weather in Florence, Italy for you.","type":"text"},{"id":"toolu_vrtx_01Tj3azsUbpPDwNvW3itTJ3L","input":{"location":"Florence,Italy"},"name":"weather","type":"tool_use"}],"role":"assistant"},{"content":[{"tool_use_id":"toolu_vrtx_01Tj3azsUbpPDwNvW3itTJ3L","content":[{"text":"40 C","type":"text"}],"type":"tool_result"}],"role":"user"}],"system":[{"text":"You are a helpful assistant","type":"text"}],"tool_choice":{"disable_parallel_tool_use":false,"type":"auto"},"tools":[{"input_schema":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"},"name":"weather","description":"Get weather information for a location"}],"stream":true,"anthropic_version":"vertex-2023-10-16"}'
+    body: '{"max_tokens":4000,"messages":[{"content":[{"text":"What''s the weather in Florence,Italy?","type":"text"}],"role":"user"},{"content":[{"text":"I''ll check the current weather in Florence, Italy for you.","type":"text"},{"id":"toolu_vrtx_01QqhPGFZ4wcxFxZLX6rF6ht","input":{"location":"Florence,Italy"},"name":"weather","type":"tool_use"}],"role":"assistant"},{"content":[{"tool_use_id":"toolu_vrtx_01QqhPGFZ4wcxFxZLX6rF6ht","content":[{"text":"40 C","type":"text"}],"type":"tool_result"}],"role":"user"}],"system":[{"text":"You are a helpful assistant","type":"text"}],"tool_choice":{"disable_parallel_tool_use":false,"type":"auto"},"tools":[{"input_schema":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"},"name":"weather","description":"Get weather information for a location"}],"stream":true,"anthropic_version":"vertex-2023-10-16"}'
     headers:
       Accept:
       - application/json
       Content-Type:
       - application/json
       User-Agent:
-      - Anthropic/Go 1.13.0
+      - Anthropic/Go 1.14.0
     url: https://us-east5-aiplatform.googleapis.com/v1/projects/fantasy-playground-472418/locations/us-east5/publishers/anthropic/models/claude-3-7-sonnet@20250219:streamRawPredict
     method: POST
   response:
@@ -107,80 +107,83 @@ interactions:
     uncompressed: true
     body: |+
       event: message_start
-      data: {"type":"message_start","message":{"id":"msg_vrtx_0164AzFzxtcpgGX36csNs7ch","type":"message","role":"assistant","model":"claude-3-7-sonnet-20250219","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":475,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":2}}         }
+      data: {"type":"message_start","message":{"model":"claude-3-7-sonnet-20250219","id":"msg_vrtx_01EsEHsrt9QdPFuhVgtfjum1","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":475,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":2}}   }
 
       event: ping
       data: {"type": "ping"}
 
       event: content_block_start
-      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}  }
+      data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}       }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"The"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"It"}}
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" current temperature in Florence,"} }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'s"}  }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" Italy is 40Β°"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" currently 40Β°C"}      }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"C (104Β°F"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" (104Β°F)"} }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"),"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" in Florence, Italy."}              }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" which is very hot."}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" That"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" If"}    }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"'s very"} }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" you're there"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" hot! If"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" or"}}
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" you're there"}            }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" planning to"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" or"}   }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" visit, make"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" planning to"}           }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" sure to stay hydrate"}      }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" visit, I'd recommen"}         }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d and try"}            }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d staying hydrated and trying"}           }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" to avoi"}             }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" to avoi"}               }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d extende"}              }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d being"} }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"d exposure to the sun during"}           }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" out"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the hottest parts of"}         }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"doors during the hottest"}    }
 
       event: content_block_delta
-      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" the day."}       }
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" parts"}             }
+
+      event: content_block_delta
+      data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":" of the day."}       }
 
       event: content_block_stop
-      data: {"type":"content_block_stop","index":0   }
+      data: {"type":"content_block_stop","index":0           }
 
       event: message_delta
-      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":59}    }
+      data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":57}             }
 
       event: message_stop
-      data: {"type":"message_stop"           }
+      data: {"type":"message_stop"             }
 
     headers:
       Content-Type:
       - text/event-stream; charset=utf-8
     status: 200 OK
     code: 200
-    duration: 1.460643125s
+    duration: 772.506333ms

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/multi_tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -38,27 +38,27 @@ interactions:
                       "a": 2
                     }
                   },
-                  "thoughtSignature": "CtYBAR/MhbZp5ZDuhyHbftCznQzuyaI5rPK4iL6DCOZOAmHm2hvqsydZ6Zw+07tzqcdyvt0Xj3Jnh9XktQUlSX7lLhgt9ChPZYfBbTUMPnBujEDNLtWhe8/7rZrBKchffl35uHsDpucQ+I+KC9Wj6NzQyaUr/TlGlyGsEXG6RotaEkVFjgxkbwLI7Ibh7CKjSQfqRd5cRz3ANCA9Td7OGCMRGXFGVwm8iC9lmhRtIOFUGxP2WyU/Nnsr3wGO9i4q+3gK17X2+rNbqMKHgb0W0anxkm4kfn8EDw=="
+                  "thoughtSignature": "CuACAePx/153kf8ikIzjnbSUf9jLxFZAf53a2GQYy4mUIqUl077OLhKwcyMd2YnG1/umJQZK8aqE6kdtgJG7sqpuDFZuFmEOqjgc1O3MxE4S+TaBZSa5wS/KAA05t4aGvS8TpkEttdy3u6wfIv6y8LM8A7LHn04qC9gswllmAiZ9iQn72RDWDgS7o2/ciprExjiDQMkU+m5yk3eRkXm1ovs9oNDNoDqlTTJnN0jtu2YgYtsxB/mwKBdA3MjSKwsiuIVc5fJj8970xQrfEmsA94QSGUQ9MNCUkB6kAUsFt3wQQ07X/Q3bYmfyud0OP/dB9HIM4xyVkayDrrVkbAOKD/1u8nKMGkPA5G/0+DaDVU4ZAqhCRGQAtHYRWYhwUZ4DICXJAqhBk9iTLIHvglDMaw4sKDZHqIlVRNnjvsx4nOoirR2S2Wpm3mKoEmCPnFGcQwRV9yJNY5/JwDquRAcwU9q1ug=="
                 },
                 {
                   "functionCall": {
                     "name": "multiply",
                     "args": {
-                      "b": 3,
-                      "a": 2
+                      "a": 2,
+                      "b": 3
                     }
                   }
                 }
               ]
             },
             "finishReason": "STOP",
-            "avgLogprobs": -0.949029541015625
+            "avgLogprobs": -1.9749752044677735
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 60,
           "candidatesTokenCount": 10,
-          "totalTokenCount": 129,
+          "totalTokenCount": 146,
           "trafficType": "ON_DEMAND",
           "promptTokensDetails": [
             {
@@ -72,32 +72,32 @@ interactions:
               "tokenCount": 10
             }
           ],
-          "thoughtsTokenCount": 59
+          "thoughtsTokenCount": 76
         },
         "modelVersion": "gemini-2.5-flash",
-        "createTime": "2025-10-10T17:53:33.301138Z",
-        "responseId": "HUjpaNKwEoav1tEPtZXfiQc"
+        "createTime": "2025-10-23T06:56:24.603477Z",
+        "responseId": "mNH5aNXqJMHDptQPtJigwQc"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.033450667s
+    duration: 1.215592042s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 1173
+    content_length: 1155
     host: us-east5-aiplatform.googleapis.com
     body: |

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/multi_tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/simple.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -31,18 +31,18 @@ interactions:
               "role": "model",
               "parts": [
                 {
-                  "text": "OlΓ‘!"
+                  "text": "OlΓ‘! (Oh-lah!)"
                 }
               ]
             },
             "finishReason": "STOP",
-            "avgLogprobs": -2.0520646572113037
+            "avgLogprobs": -1.2647225516183036
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 9,
-          "candidatesTokenCount": 2,
-          "totalTokenCount": 37,
+          "candidatesTokenCount": 7,
+          "totalTokenCount": 43,
           "trafficType": "ON_DEMAND",
           "promptTokensDetails": [
             {
@@ -53,18 +53,18 @@ interactions:
           "candidatesTokensDetails": [
             {
               "modality": "TEXT",
-              "tokenCount": 2
+              "tokenCount": 7
             }
           ],
-          "thoughtsTokenCount": 26
+          "thoughtsTokenCount": 27
         },
         "modelVersion": "gemini-2.5-flash",
-        "createTime": "2025-10-10T17:53:28.119129Z",
-        "responseId": "GEjpaNmiB8Kh18kP2devgQ4"
+        "createTime": "2025-10-23T06:56:18.469078Z",
+        "responseId": "ktH5aNbQHOn1ptQPkf36wAU"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.410897667s
+    duration: 1.883201042s

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/simple_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,10 +25,10 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1
-    body: "data: {\"candidates\": [{\"content\": {\"role\": \"model\",\"parts\": [{\"text\": \"OlΓ‘! (pronounced \\\"oh-LAH\\\")\"}]},\"finishReason\": \"STOP\"}],\"usageMetadata\": {\"promptTokenCount\": 9,\"candidatesTokenCount\": 9,\"totalTokenCount\": 45,\"trafficType\": \"ON_DEMAND\",\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 9}],\"candidatesTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 9}],\"thoughtsTokenCount\": 27},\"modelVersion\": \"gemini-2.5-flash\",\"createTime\": \"2025-10-10T17:53:29.051002Z\",\"responseId\": \"GUjpaLqOA4av1tEPtZXfiQc\"}\r\n\r\n"
+    body: "data: {\"candidates\": [{\"content\": {\"role\": \"model\",\"parts\": [{\"text\": \"OlΓ‘!\"}]},\"finishReason\": \"STOP\"}],\"usageMetadata\": {\"promptTokenCount\": 9,\"candidatesTokenCount\": 2,\"totalTokenCount\": 37,\"trafficType\": \"ON_DEMAND\",\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 9}],\"candidatesTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 2}],\"thoughtsTokenCount\": 26},\"modelVersion\": \"gemini-2.5-flash\",\"createTime\": \"2025-10-23T06:56:19.541931Z\",\"responseId\": \"k9H5aOuJIcqZptQPrcWIuQM\"}\r\n\r\n"
     headers:
       Content-Type:
       - text/event-stream
     status: 200 OK
     code: 200
-    duration: 780.130208ms
+    duration: 838.164042ms

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -37,18 +37,18 @@ interactions:
                       "location": "Florence,Italy"
                     }
                   },
-                  "thoughtSignature": "CvoBAR/MhbYk0qvoO1yRgdHDwwyxH/IbvJEJWkExyjhCp5q/0S0Zf9zBcxa2OWwWdQJR8+Z0JMwJ0PLQnf58ln2HT24wU1p3Nr2gMxAVoZUaB4Uxo/g5rq5C5sFVqfrdzeMXIDxhtrC0Q8OzSEcQy2XIjrrmu0XZLF3BVU58ewt4Ok4/HRGzoworbz23/JLZxUEmB4Jz3TmQD3+tCNhENGIko9zcXctE/R06mFmVF/WaihIM1ibpNichDjYZqmHq5NGSE36wpBaxwJgfxxNwspek3hjVT4EsDn97FJsMeL5I3W1j0Tu8XjF7BX92tWcmP9jZO4iF5O2nda6bbQ=="
+                  "thoughtSignature": "CsICAePx/14z2/Y1LwOZuOEfW+8h7yERSI5lsHY/AqynX6oLR1OiF3GZPJApHAIv7Z1RJZJszK371HXJVUnVWQIM3RW5uHNhwqD5iiMhJKgEkC5R5b4LC4EzCzHSQKGXEuFEJKUhIjy36IZKGS8aChOGVs4Cx1g+wgYICstMVtF2Ny86IuYHKfE+KL9BAc6TYN8d5yQySsuPRmPKCHTMC5q/ZaL5muk+Y+2KBMNOb2pI0tM3JiJyl3m/iYn9ENTMOCtPW8WVnR/43SCjF8ECpJH4Ot19VC0DQarwkgj6G1Hb/kw+kypGLm+SXsjWB/nnfOrvjbysSPNKPWL2GJtjTI1aMt6VOE4m8FPTlOQXze4jr3XeiHcylNOoRvWF9t8hesLdmy8xnyKrwSKCH+nAn21yTHPhoYgc69k5gquSB7jztgU/mQ=="
                 }
               ]
             },
             "finishReason": "STOP",
-            "avgLogprobs": -1.0515016555786132
+            "avgLogprobs": -2.8889617919921875
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 28,
           "candidatesTokenCount": 5,
-          "totalTokenCount": 84,
+          "totalTokenCount": 101,
           "trafficType": "ON_DEMAND",
           "promptTokensDetails": [
             {
@@ -62,32 +62,32 @@ interactions:
               "tokenCount": 5
             }
           ],
-          "thoughtsTokenCount": 51
+          "thoughtsTokenCount": 68
         },
         "modelVersion": "gemini-2.5-flash",
-        "createTime": "2025-10-10T17:53:30.097682Z",
-        "responseId": "GkjpaJL7BYXg1tEPj-il0Ak"
+        "createTime": "2025-10-23T06:56:20.673204Z",
+        "responseId": "lNH5aLSLKbHEptQP-Ob28Ak"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 765.1515ms
+    duration: 835.350042ms
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 734
+    content_length: 722
     host: us-east5-aiplatform.googleapis.com
     body: |
-      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence,Italy"},"id":"weather","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"weather","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
+      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence,Italy"},"id":"1","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"1","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
     headers:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -131,12 +131,12 @@ interactions:
           ]
         },
         "modelVersion": "gemini-2.5-flash",
-        "createTime": "2025-10-10T17:53:30.858865Z",
-        "responseId": "GkjpaPG1NOnqr9wPkPmEqQc"
+        "createTime": "2025-10-23T06:56:21.509020Z",
+        "responseId": "ldH5aNyIH6D5ptQPsI7YiQ0"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 613.84925ms
+    duration: 1.159554792s

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-flash/tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/multi_tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -38,27 +38,27 @@ interactions:
                       "b": 3
                     }
                   },
-                  "thoughtSignature": "CqQCAR/MhbZLwIC6tafwHAkCxScqjr2T0r1NLWoahLzRTjgt+N9/7szY8vWOM7QZWZZ88VI9n2FshjX2uMxOuA17pXgQkyvSD3RFCTbzN46tFVYUY+ZyOLMM5YXSyHV40LjXUjbuzMAl/zy+m3ePoYHjQa6xnYhjBPSb/By2HvrCQeDkvRJlvh0uG6xxUr2+0mH0T6ml3Dz6M1LIBHIQiQb20vaPtYn2AyboMVIZA2wFPr14kQhVrOec6fwLc9EtVhoEQO+l+/wPIKfbSdxoX1iA9WqgcdarYtREK7FMcM7afsFKpxziZzPw8BEOAmR2piTTSLPpRckvvB0AkRs25Cnq8IYd2A6D543MpTWrZVcvMcLxL9SJ1DGitNCwc3T7NrPRxR6M+w=="

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/multi_tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/simple.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -31,18 +31,18 @@ interactions:
               "role": "model",
               "parts": [
                 {
-                  "text": "Of course!\n\nThe most common ways to say \"hi\" in Portuguese are:\n\n*   **OlΓ‘!** (This is the direct translation of \"hello\" and can be used in any situation, formal or informal.)\n*   **Oi!** (This is more informal, like \"hi,\" and is extremely common, especially in Brazil.)\n\nYou can also use greetings that change with the time of day:\n\n*   **Bom dia** (Good morning)\n*   **Boa tarde** (Good afternoon)\n*   **Boa noite** (Good evening / Good night)"
+                  "text": "Of course!\n\nThe most common way to say \"hi\" in Portuguese is:\n\n**Oi**\n\nYou can also use:\n\n**OlΓ‘** (which is like \"hello\")"
                 }
               ]
             },
             "finishReason": "STOP",
-            "avgLogprobs": -1.9789696365106302
+            "avgLogprobs": -2.3780706305252877
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 9,
-          "candidatesTokenCount": 122,
-          "totalTokenCount": 1356,
+          "candidatesTokenCount": 38,
+          "totalTokenCount": 720,
           "trafficType": "ON_DEMAND",
           "promptTokensDetails": [
             {
@@ -53,18 +53,18 @@ interactions:
           "candidatesTokensDetails": [
             {
               "modality": "TEXT",
-              "tokenCount": 122
+              "tokenCount": 38
             }
           ],
-          "thoughtsTokenCount": 1225
+          "thoughtsTokenCount": 673
         },
         "modelVersion": "gemini-2.5-pro",
-        "createTime": "2025-10-10T17:53:37.635488Z",
-        "responseId": "IUjpaODkJunqr9wPkPmEqQc"
+        "createTime": "2025-10-23T06:56:29.134156Z",
+        "responseId": "ndH5aIyYCLHEptQP-Ob28Ak"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 14.255680041s
+    duration: 7.471405083s

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/simple_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,10 +25,10 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/tool.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -37,18 +37,18 @@ interactions:
                       "location": "Florence, Italy"
                     }
                   },
-                  "thoughtSignature": "Cv4DAR/MhbZ2LpWbGDKTyyTnSEI5Mbxsa8KH+9LlZ7C1whClIZwMMYizqs+M3qhEkbCwG4lqJXruVsWCWHhA8Mth+s3XzLc4cq3DChXa/vjuNuTGi7NWDzjAOA5ZY+BnK658YQvva+1dFinvrKu1H928HLMQkthqikGFX/oEJw+VJo0tKTWAEKU00oL5D3BL10AWE+D7xcuc/sxoEsJXq+cJaZf4TqNuQ2WvsPi0bx+CIqDmCVJ8Zr7S94jYj0CiAX+taFLoPyvpjG79R5kcnqI6euqhckUnsSbG3nXOeHBiNvsaTD3eHjl+lIs6rWOCVu7sQDOQhO2IkZlrVl+/uYzWFLz/4JJYODYtECgJCz7VK5OSeqIx/YOxADIMpCCgF5S74pGz+9o33foKqukPtPHiJ22YMOs37RYFZDR8f5cnvkomHwIChRQ1T723wsGHLK/KD2c6mb2I8eeVtYQwODyP11ryI5r7G7aMUKM6NKu9K/FzlSkURUlJ18hZ1tPaIyFYGys3+WI0Q7CbxP9Yc7M6luXxy8UdiMqZkk7fegM4EO3IVHp4yYB9exU9Y1QjhY1jTsZcgYZd8QMLpI6mRtwnqtsPF6ymqvo9jfxi1FXCAjhyiNjmP1IPjt1hPoYXbOb+Ntbb9XvGxWtGv1ZhVSveggLzbI53wZFTGd6IuhWd"
+                  "thoughtSignature": "CsQDAePx/16BSTox7w915NWGeZDiCcadqyQOruFo69gjDNj2kp4g8LWDvvqodBi8WkgyhBQCwvQFUOs/UuJDUgabzKp22DWPBpri/c9PH56m7Ss1siHb9d0ETRVWu5d4+Z3cU1iu1/OJy8a4zskJICrRSg8WU8euc2C1qPSHsM0KoFDMPNCluTO4+/BKef19qKEByzGP126OHQPcL498iUIB3dq9suqF4inMw0wQ81J5Cn4+68ckU2fMbvPQpKqmZfzF0y68MwvPH0RWhl1CWiOeIC0tzI/flCWNQJKAB2q+RoK5D3zr1gFQ8QP/cfwet6VW16ajcnmYH7F9Df4/H01iV/aQ5A9M5IRBcwed97whvZraqQFefMQNSru4PeiXygp0cYYbrMQ3+5fntpqhIviNg7oxexnd5jcZhaNZOYD4OIJt6+CPkZXzBtzc9BE9UwCcnJzWRyvHSgDH7zl/xudo8/p4KleUVaD+rzO3f54UtOAV/zd+Fd8qyoqAb2BpLS8czoKP9KVCnFbNizZgno7oTgi8dUkgAtPNUzL4SbDrgNQTKkNDzpfKd8OOmvxo3YVgrXGSeI1fonHIOGf0eMmmzvd+AUY="
                 }
               ]
             },
             "finishReason": "STOP",
-            "avgLogprobs": -0.83615646362304685
+            "avgLogprobs": -1.9075927734375
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 28,
           "candidatesTokenCount": 5,
-          "totalTokenCount": 150,
+          "totalTokenCount": 128,
           "trafficType": "ON_DEMAND",
           "promptTokensDetails": [
             {
@@ -62,32 +62,32 @@ interactions:
               "tokenCount": 5
             }
           ],
-          "thoughtsTokenCount": 117
+          "thoughtsTokenCount": 95
         },
         "modelVersion": "gemini-2.5-pro",
-        "createTime": "2025-10-10T17:54:02.708890Z",
-        "responseId": "OkjpaJqiK6GI0ekPqveHmA4"
+        "createTime": "2025-10-23T06:56:46.277788Z",
+        "responseId": "rtH5aJz6EOn1ptQPkf36wAU"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 2.841282292s
+    duration: 1.957397917s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 735
+    content_length: 723
     host: us-east5-aiplatform.googleapis.com
     body: |
-      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"weather","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"weather","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
+      {"contents":[{"parts":[{"text":"What's the weather in Florence,Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"1","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"1","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"maxOutputTokens":4000},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
     headers:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -104,18 +104,18 @@ interactions:
               "role": "model",
               "parts": [
                 {
-                  "text": "The weather in Florence, Italy is 40 degrees Celsius.\n"
+                  "text": "The weather in Florence, Italy is 40 C.\n"
                 }
               ]
             },
             "finishReason": "STOP",
-            "avgLogprobs": -0.07556527001517159
+            "avgLogprobs": -0.1211475684092595
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 38,
-          "candidatesTokenCount": 14,
-          "totalTokenCount": 52,
+          "candidatesTokenCount": 13,
+          "totalTokenCount": 51,
           "trafficType": "ON_DEMAND",
           "promptTokensDetails": [
             {
@@ -126,17 +126,17 @@ interactions:
           "candidatesTokensDetails": [
             {
               "modality": "TEXT",
-              "tokenCount": 14
+              "tokenCount": 13
             }
           ]
         },
         "modelVersion": "gemini-2.5-pro",
-        "createTime": "2025-10-10T17:54:05.547479Z",
-        "responseId": "PUjpaJe1IbqD0ekPpPnL0A0"
+        "createTime": "2025-10-23T06:56:48.759113Z",
+        "responseId": "sNH5aMmqLsHDptQPtJigwQc"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.102223375s
+    duration: 1.759973041s

providertests/testdata/TestGoogleCommon/vertex-gemini-2-5-pro/tool_streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.29.0 gl-go/go1.25.0
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://us-east5-aiplatform.googleapis.com/v1beta1/projects/fantasy-playground-472418/locations/us-east5/publishers/google/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleThinking/gemini-2.5-flash/thinking-streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleThinking/gemini-2.5-flash/thinking.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -30,7 +30,7 @@ interactions:
             "content": {
               "parts": [
                 {
-                  "text": "**Alright, here's what I'm thinking.**\n\nThe user wants the weather, simple enough. They've specified \"Florence, Italy\".  My internal processing is telling me I have a `weather` tool that's specifically designed for this sort of query.  It needs a `location` argument, and \"Florence, Italy\" is *perfect* for that. So, I should just feed \"Florence, Italy\" directly into the `weather` tool's `location` parameter. That's it, should be a quick and easy retrieval.\n",
+                  "text": "**Analyzing the Request: Weather in Florence**\n\nOkay, so the user wants the weather forecast for Florence, Italy. That's straightforward enough. The \"weather\" tool is the obvious choice here – it's designed specifically for this kind of query. Now, I just need to figure out the right way to use the tool. It looks like it needs a \"location\" argument, which makes perfect sense. And since the user explicitly mentioned \"Florence, Italy,\" that's the location I should provide. So, to get the information, I'll call the \"weather\" tool and pass in `location='Florence, Italy'`. Should be a quick and easy retrieval!\n",
                   "thought": true
                 },
                 {
@@ -40,50 +40,51 @@ interactions:
                       "location": "Florence, Italy"
                     }
                   },
-                  "thoughtSignature": "Cv0BAdHtim/faT2T5UU6b+75rrcyw9ZzINxOjX23TIc40xJ+vXIv0bdgEIs1AckES34/063nRHBt7/gjtCTI+I/EQvdFAeW8wmtXO0Bp7Vqyineg3rw9u9W4E//mEjfLqcP9EiYi4HER9Pwj+iASiRpZQ0l/hJ32cSCzFVLVgVPQFRlWOrl7AbqZKRZDx1u72L6+3VBhXTGAB+i8m4CK0s1HY4/apyoOcfHVKJyNviC9kXRUhGstF6LO1Gwhz4ckVPHrVOMUCbEDkdcqR4zkCm1R/x6r+9nXwJKoKli5BDcQ7LssCBal009/HaRMJxVnFOLKi5NgSUFqf5SBmZ006g=="
+                  "thoughtSignature": "CqcCAdHtim+w7Zjxo3b6l9LJXbVvkFXVwAc85VHZldttwHx3G4FKSfN61k8WbpQjZArax2N/4C5HtNmYKM7mkzpmqxmR8wiJ9+o5QuG+L6EB6/gs3p0cnJR0tYrt0e/N6uvVasA8wF0DK1GehZ4WPRR6XbQ1fx66s1t2Pi4y0ri70XEa6QgE+TxaGDVg6KOm73GCVVp2IifpSorSF0hmgLboLqPHL5IVgWXbGnr9+0t25KqY04v01BAK04QY3Lmdr4Xr+jxjoCBeCSL7xS/K8zPTl94QtwdWiNqsqK/X5IcGDcz7rlLOLkv76IurHs9+JfPtAcGjZgWO5ZyW5Mf31O8cW4O/9QDYwRTSuBfmY3/dPjUj0Ijk2tHVJkqmmCZ5xe2M7UOWxdV2Kg=="
                 }
               ],
               "role": "model"
             },
             "finishReason": "STOP",
-            "index": 0
+            "index": 0,
+            "finishMessage": "Model generated function call(s)."
           }
         ],
         "usageMetadata": {
           "promptTokenCount": 54,
           "candidatesTokenCount": 15,
-          "totalTokenCount": 120,
+          "totalTokenCount": 131,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
               "tokenCount": 54
             }
           ],
-          "thoughtsTokenCount": 51
+          "thoughtsTokenCount": 62
         },
         "modelVersion": "gemini-2.5-flash",
-        "responseId": "FHPWaKjHEu-C7M8P4Yuh8QY"
+        "responseId": "jtn5aJa6OuayvdIPornA0Q4"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 2.220739041s
+    duration: 2.3995905s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 776
+    content_length: 764
     host: generativelanguage.googleapis.com
     body: |
-      {"contents":[{"parts":[{"text":"What's the weather in Florence, Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"weather","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"weather","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"thinkingConfig":{"includeThoughts":true,"thinkingBudget":128}},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
+      {"contents":[{"parts":[{"text":"What's the weather in Florence, Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"1","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"1","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"thinkingConfig":{"includeThoughts":true,"thinkingBudget":128}},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
     headers:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent
     method: POST
   response:
@@ -120,11 +121,11 @@ interactions:
           ]
         },
         "modelVersion": "gemini-2.5-flash",
-        "responseId": "FHPWaL-mJ4X9nsEP8NW9qQc"
+        "responseId": "j9n5aPLXJ5uP28oPi-aP0QE"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 338.789083ms
+    duration: 506.190917ms

providertests/testdata/TestGoogleThinking/gemini-2.5-pro/thinking-streaming.yaml πŸ”—

@@ -17,7 +17,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:streamGenerateContent?alt=sse
     method: POST
   response:
@@ -25,22 +25,22 @@ interactions:
     proto_major: 2
     proto_minor: 0
     content_length: -1

providertests/testdata/TestGoogleThinking/gemini-2.5-pro/thinking.yaml πŸ”—

@@ -14,7 +14,7 @@ interactions:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -30,7 +30,7 @@ interactions:
             "content": {
               "parts": [
                 {
-                  "text": "**Getting the Weather in Florence**\n\nOkay, so I'm trying to figure out the weather in Florence, Italy. That's straightforward, really. My immediate thought is, \"I need to use that `weather.get_weather` function.\" It's designed for this kind of query. All I have to do is plug in \"Florence, Italy\" as the `location` parameter, and I should have the information I need. Easy peasy.\n",
+                  "text": "**Getting the Weather in Florence**\n\nOkay, so I'm thinking about the weather, specifically in Florence, Italy. That immediately clicks - I know I've got a function, `weather.get_weather`, that's designed for exactly this kind of query. It takes a `location` parameter, which is perfect.  Therefore, I'll set that `location` parameter to \"Florence, Italy\", and that should be all I need to get the forecast.\n",
                   "thought": true
                 },
                 {
@@ -40,13 +40,14 @@ interactions:
                       "location": "Florence, Italy"
                     }
                   },
-                  "thoughtSignature": "CpwCADAxMjOrBS23pWMtbykG2/HxS9zDAprusCU0aR/qeI4cMnnfJCAl4n2UOC6oNCFeNyL3anLH6D2mEwiah92877DeEAig/Rm9u98ApqtJ6mu9vaKXr92/xyQ3EOwYzdXtPEb8LS4qK0SQGWG4zB4KUTVliondCRp6EgYlmlArjj0zbbvNYE1YHtQ6jzR6FpLphhFY8jDP73M0JkwANtjZf+dv9aFNX9pNAK5XYfZCIPEzzWoJpV6zQ5v8dwdj7nSXUqWsd06MR5sRwrfVmtpGrKaDzdDwVcxg2GiWWfYggDbC9EpUidRpCcZt2rKOM486MLgrK1/yIRUCC4jdueC3rkzgihndxJqFNKZw4I1+0Ob+XCw8wanXc9lb314="
+                  "thoughtSignature": "Cp4CAdHtim8JgCsNhv84SCzZ8bo/kRaAn5bY0cEQ0mfo7nl3GCS7sRlN2T7G4P/Epnwc7/9wbdFzcvcdaqNgWk1flXACXm4QluykEizpys7U+TyP8I2vaUUDIl4Tii0yBZNwjaJxmYp0yb5E9LjpsuEFolG0Ao2vqoJar/0XgY5bzViogURnnUHqVzP2euy5PJEdAd+rOqz1hnK4lCumsNfF5vrkx8aeyGL99C1Eu1/ZETTU7TSnVht+z+4qlysMOlhx4ko0anJ5MWzjewwrZBFkMPgzzw0zVmsHZg9d4t0Hnhmk6Ft7Ge6JOhvI54NgL8MkiviZNvIYT6iHNRqSd71uYeCdCdiw9UJCwASXvbRIv/ktz6OZKrlGld61RP1BXw=="
                 }
               ],
               "role": "model"
             },
             "finishReason": "STOP",
-            "index": 0
+            "index": 0,
+            "finishMessage": "Model generated function call(s)."
           }
         ],
         "usageMetadata": {
@@ -62,28 +63,28 @@ interactions:
           "thoughtsTokenCount": 66
         },
         "modelVersion": "gemini-2.5-pro",
-        "responseId": "vHXWaNC4EY7ivdIPg5bG-QM"
+        "responseId": "29n5aPKhFJrivdIPhYnAuQE"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 4.127855167s
+    duration: 3.824523542s
 - id: 1
   request:
     proto: HTTP/1.1
     proto_major: 1
     proto_minor: 1
-    content_length: 776
+    content_length: 764
     host: generativelanguage.googleapis.com
     body: |
-      {"contents":[{"parts":[{"text":"What's the weather in Florence, Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"weather","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"weather","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"thinkingConfig":{"includeThoughts":true,"thinkingBudget":128}},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
+      {"contents":[{"parts":[{"text":"What's the weather in Florence, Italy?"}],"role":"user"},{"parts":[{"functionCall":{"args":{"location":"Florence, Italy"},"id":"1","name":"weather"}}],"role":"model"},{"parts":[{"functionResponse":{"id":"1","name":"weather","response":{"result":"40 C"}}}],"role":"user"}],"generationConfig":{"thinkingConfig":{"includeThoughts":true,"thinkingBudget":128}},"systemInstruction":{"parts":[{"text":"You are a helpful assistant"}],"role":"user"},"toolConfig":{"functionCallingConfig":{"mode":"AUTO"}},"tools":[{"functionDeclarations":[{"description":"Get weather information for a location","name":"weather","parameters":{"properties":{"location":{"description":"the city","type":"STRING"}},"required":["location"],"type":"OBJECT"}}]}]}
     headers:
       Content-Type:
       - application/json
       User-Agent:
-      - google-genai-sdk/1.23.0 gl-go/go1.25.1
+      - google-genai-sdk/1.29.0 gl-go/go1.25.1
     url: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent
     method: POST
   response:
@@ -99,7 +100,7 @@ interactions:
             "content": {
               "parts": [
                 {
-                  "text": "The weather in Florence, Italy is 40 degrees Celsius. \n"
+                  "text": "The weather in Florence, Italy is 40 C. \n"
                 }
               ],
               "role": "model"
@@ -110,8 +111,8 @@ interactions:
         ],
         "usageMetadata": {
           "promptTokenCount": 84,
-          "candidatesTokenCount": 13,
-          "totalTokenCount": 97,
+          "candidatesTokenCount": 12,
+          "totalTokenCount": 96,
           "promptTokensDetails": [
             {
               "modality": "TEXT",
@@ -120,11 +121,11 @@ interactions:
           ]
         },
         "modelVersion": "gemini-2.5-pro",
-        "responseId": "vXXWaNC2HOqLxN8P_pmomQM"
+        "responseId": "3Nn5aMLPIMahxN8P5c69gQc"
       }
     headers:
       Content-Type:
       - application/json; charset=UTF-8
     status: 200 OK
     code: 200
-    duration: 1.178061334s
+    duration: 1.228113333s