diff --git a/providers/vercel/language_model_hooks.go b/providers/vercel/language_model_hooks.go
new file mode 100644
index 0000000000000000000000000000000000000000..d243e57f65d982b9d7739aeda1f1a6addbe4f868
--- /dev/null
+++ b/providers/vercel/language_model_hooks.go
@@ -0,0 +1,1052 @@
+package vercel
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "maps"
+ "strings"
+
+ "charm.land/fantasy"
+ "charm.land/fantasy/providers/anthropic"
+ "charm.land/fantasy/providers/google"
+ openaipkg "charm.land/fantasy/providers/openai"
+ openaisdk "github.com/openai/openai-go/v2"
+ "github.com/openai/openai-go/v2/packages/param"
+)
+
+const reasoningStartedCtx = "reasoning_started"
+
+type currentReasoningState struct {
+ metadata *openaipkg.ResponsesReasoningMetadata
+ googleMetadata *google.ReasoningMetadata
+ googleText string
+ anthropicSig string
+}
+
+func languagePrepareModelCall(_ fantasy.LanguageModel, params *openaisdk.ChatCompletionNewParams, call fantasy.Call) ([]fantasy.CallWarning, error) {
+ providerOptions := &ProviderOptions{}
+ if v, ok := call.ProviderOptions[Name]; ok {
+ providerOptions, ok = v.(*ProviderOptions)
+ if !ok {
+ return nil, &fantasy.Error{Title: "invalid argument", Message: "vercel provider options should be *vercel.ProviderOptions"}
+ }
+ }
+
+ extraFields := make(map[string]any)
+
+ // Handle reasoning options
+ if providerOptions.Reasoning != nil {
+ data, err := structToMapJSON(providerOptions.Reasoning)
+ if err != nil {
+ return nil, err
+ }
+ extraFields["reasoning"] = data
+ }
+
+ // Handle provider options for gateway routing
+ if providerOptions.ProviderOptions != nil {
+ data, err := structToMapJSON(providerOptions.ProviderOptions)
+ if err != nil {
+ return nil, err
+ }
+ extraFields["providerOptions"] = map[string]any{
+ "gateway": data,
+ }
+ }
+
+ // Handle BYOK (Bring Your Own Key)
+ if providerOptions.BYOK != nil {
+ data, err := structToMapJSON(providerOptions.BYOK)
+ if err != nil {
+ return nil, err
+ }
+ if gatewayOpts, ok := extraFields["providerOptions"].(map[string]any); ok {
+ gatewayOpts["byok"] = data
+ } else {
+ extraFields["providerOptions"] = map[string]any{
+ "gateway": map[string]any{
+ "byok": data,
+ },
+ }
+ }
+ }
+
+ // Handle standard OpenAI options
+ if providerOptions.LogitBias != nil {
+ params.LogitBias = providerOptions.LogitBias
+ }
+ if providerOptions.LogProbs != nil {
+ params.Logprobs = param.NewOpt(*providerOptions.LogProbs)
+ }
+ if providerOptions.TopLogProbs != nil {
+ params.TopLogprobs = param.NewOpt(*providerOptions.TopLogProbs)
+ }
+ if providerOptions.User != nil {
+ params.User = param.NewOpt(*providerOptions.User)
+ }
+ if providerOptions.ParallelToolCalls != nil {
+ params.ParallelToolCalls = param.NewOpt(*providerOptions.ParallelToolCalls)
+ }
+
+ // Handle model fallbacks - direct models field
+ if providerOptions.ProviderOptions != nil && len(providerOptions.ProviderOptions.Models) > 0 {
+ extraFields["models"] = providerOptions.ProviderOptions.Models
+ }
+
+ maps.Copy(extraFields, providerOptions.ExtraBody)
+ params.SetExtraFields(extraFields)
+ return nil, nil
+}
+
+func languageModelExtraContent(choice openaisdk.ChatCompletionChoice) []fantasy.Content {
+ content := make([]fantasy.Content, 0)
+ reasoningData := ReasoningData{}
+ err := json.Unmarshal([]byte(choice.Message.RawJSON()), &reasoningData)
+ if err != nil {
+ return content
+ }
+
+ responsesReasoningBlocks := make([]openaipkg.ResponsesReasoningMetadata, 0)
+ anthropicReasoningBlocks := make([]struct {
+ text string
+ metadata *anthropic.ReasoningOptionMetadata
+ }, 0)
+ googleReasoningBlocks := make([]struct {
+ text string
+ metadata *google.ReasoningMetadata
+ }, 0)
+ otherReasoning := make([]string, 0)
+
+ for _, detail := range reasoningData.ReasoningDetails {
+ if strings.HasPrefix(detail.Format, "openai-responses") || strings.HasPrefix(detail.Format, "xai-responses") {
+ var thinkingBlock openaipkg.ResponsesReasoningMetadata
+ if len(responsesReasoningBlocks)-1 >= detail.Index {
+ thinkingBlock = responsesReasoningBlocks[detail.Index]
+ } else {
+ thinkingBlock = openaipkg.ResponsesReasoningMetadata{}
+ responsesReasoningBlocks = append(responsesReasoningBlocks, thinkingBlock)
+ }
+
+ switch detail.Type {
+ case "reasoning.summary":
+ thinkingBlock.Summary = append(thinkingBlock.Summary, detail.Summary)
+ case "reasoning.encrypted":
+ thinkingBlock.EncryptedContent = &detail.Data
+ }
+ if detail.ID != "" {
+ thinkingBlock.ItemID = detail.ID
+ }
+ responsesReasoningBlocks[detail.Index] = thinkingBlock
+ continue
+ }
+
+ if strings.HasPrefix(detail.Format, "google-gemini") {
+ var thinkingBlock struct {
+ text string
+ metadata *google.ReasoningMetadata
+ }
+ if len(googleReasoningBlocks)-1 >= detail.Index {
+ thinkingBlock = googleReasoningBlocks[detail.Index]
+ } else {
+ thinkingBlock = struct {
+ text string
+ metadata *google.ReasoningMetadata
+ }{metadata: &google.ReasoningMetadata{}}
+ googleReasoningBlocks = append(googleReasoningBlocks, thinkingBlock)
+ }
+
+ switch detail.Type {
+ case "reasoning.text":
+ thinkingBlock.text = detail.Text
+ case "reasoning.encrypted":
+ thinkingBlock.metadata.Signature = detail.Data
+ thinkingBlock.metadata.ToolID = detail.ID
+ }
+ googleReasoningBlocks[detail.Index] = thinkingBlock
+ continue
+ }
+
+ if strings.HasPrefix(detail.Format, "anthropic-claude") {
+ anthropicReasoningBlocks = append(anthropicReasoningBlocks, struct {
+ text string
+ metadata *anthropic.ReasoningOptionMetadata
+ }{
+ text: detail.Text,
+ metadata: &anthropic.ReasoningOptionMetadata{
+ Signature: detail.Signature,
+ },
+ })
+ continue
+ }
+
+ otherReasoning = append(otherReasoning, detail.Text)
+ }
+
+ // Fallback to simple reasoning field if no details
+ if reasoningData.Reasoning != "" && len(reasoningData.ReasoningDetails) == 0 {
+ otherReasoning = append(otherReasoning, reasoningData.Reasoning)
+ }
+
+ for _, block := range responsesReasoningBlocks {
+ if len(block.Summary) == 0 {
+ block.Summary = []string{""}
+ }
+ content = append(content, fantasy.ReasoningContent{
+ Text: strings.Join(block.Summary, "\n"),
+ ProviderMetadata: fantasy.ProviderMetadata{
+ openaipkg.Name: &block,
+ },
+ })
+ }
+
+ for _, block := range anthropicReasoningBlocks {
+ content = append(content, fantasy.ReasoningContent{
+ Text: block.text,
+ ProviderMetadata: fantasy.ProviderMetadata{
+ anthropic.Name: block.metadata,
+ },
+ })
+ }
+
+ for _, block := range googleReasoningBlocks {
+ content = append(content, fantasy.ReasoningContent{
+ Text: block.text,
+ ProviderMetadata: fantasy.ProviderMetadata{
+ google.Name: block.metadata,
+ },
+ })
+ }
+
+ for _, reasoning := range otherReasoning {
+ if reasoning != "" {
+ content = append(content, fantasy.ReasoningContent{
+ Text: reasoning,
+ })
+ }
+ }
+
+ return content
+}
+
+func extractReasoningContext(ctx map[string]any) *currentReasoningState {
+ reasoningStarted, ok := ctx[reasoningStartedCtx]
+ if !ok {
+ return nil
+ }
+ state, ok := reasoningStarted.(*currentReasoningState)
+ if !ok {
+ return nil
+ }
+ return state
+}
+
+func languageModelStreamExtra(chunk openaisdk.ChatCompletionChunk, yield func(fantasy.StreamPart) bool, ctx map[string]any) (map[string]any, bool) {
+ if len(chunk.Choices) == 0 {
+ return ctx, true
+ }
+
+ currentState := extractReasoningContext(ctx)
+
+ inx := 0
+ choice := chunk.Choices[inx]
+ reasoningData := ReasoningData{}
+ err := json.Unmarshal([]byte(choice.Delta.RawJSON()), &reasoningData)
+ if err != nil {
+ yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeError,
+ Error: &fantasy.Error{Title: "stream error", Message: "error unmarshalling delta", Cause: err},
+ })
+ return ctx, false
+ }
+
+ // Reasoning Start
+ if currentState == nil {
+ if len(reasoningData.ReasoningDetails) == 0 && reasoningData.Reasoning == "" {
+ return ctx, true
+ }
+
+ var metadata fantasy.ProviderMetadata
+ currentState = ¤tReasoningState{}
+
+ if len(reasoningData.ReasoningDetails) > 0 {
+ detail := reasoningData.ReasoningDetails[0]
+
+ if strings.HasPrefix(detail.Format, "openai-responses") || strings.HasPrefix(detail.Format, "xai-responses") {
+ currentState.metadata = &openaipkg.ResponsesReasoningMetadata{
+ Summary: []string{detail.Summary},
+ }
+ metadata = fantasy.ProviderMetadata{
+ openaipkg.Name: currentState.metadata,
+ }
+ if detail.Data != "" {
+ shouldContinue := yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningStart,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: detail.Summary,
+ ProviderMetadata: metadata,
+ })
+ if !shouldContinue {
+ return ctx, false
+ }
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningEnd,
+ ID: fmt.Sprintf("%d", inx),
+ ProviderMetadata: fantasy.ProviderMetadata{
+ openaipkg.Name: &openaipkg.ResponsesReasoningMetadata{
+ Summary: []string{detail.Summary},
+ EncryptedContent: &detail.Data,
+ ItemID: detail.ID,
+ },
+ },
+ })
+ }
+ }
+
+ if strings.HasPrefix(detail.Format, "google-gemini") {
+ if detail.Type == "reasoning.encrypted" {
+ ctx[reasoningStartedCtx] = nil
+ if !yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningStart,
+ ID: fmt.Sprintf("%d", inx),
+ }) {
+ return ctx, false
+ }
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningEnd,
+ ID: fmt.Sprintf("%d", inx),
+ ProviderMetadata: fantasy.ProviderMetadata{
+ google.Name: &google.ReasoningMetadata{
+ Signature: detail.Data,
+ ToolID: detail.ID,
+ },
+ },
+ })
+ }
+ currentState.googleMetadata = &google.ReasoningMetadata{}
+ currentState.googleText = detail.Text
+ metadata = fantasy.ProviderMetadata{
+ google.Name: currentState.googleMetadata,
+ }
+ }
+
+ if strings.HasPrefix(detail.Format, "anthropic-claude") {
+ currentState.anthropicSig = detail.Signature
+ }
+ }
+
+ ctx[reasoningStartedCtx] = currentState
+ delta := reasoningData.Reasoning
+ if len(reasoningData.ReasoningDetails) > 0 {
+ delta = reasoningData.ReasoningDetails[0].Summary
+ if strings.HasPrefix(reasoningData.ReasoningDetails[0].Format, "google-gemini") {
+ delta = reasoningData.ReasoningDetails[0].Text
+ }
+ if strings.HasPrefix(reasoningData.ReasoningDetails[0].Format, "anthropic-claude") {
+ delta = reasoningData.ReasoningDetails[0].Text
+ }
+ }
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningStart,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: delta,
+ ProviderMetadata: metadata,
+ })
+ }
+
+ if len(reasoningData.ReasoningDetails) == 0 && reasoningData.Reasoning == "" {
+ if choice.Delta.Content != "" || len(choice.Delta.ToolCalls) > 0 {
+ ctx[reasoningStartedCtx] = nil
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningEnd,
+ ID: fmt.Sprintf("%d", inx),
+ })
+ }
+ return ctx, true
+ }
+
+ if len(reasoningData.ReasoningDetails) > 0 {
+ detail := reasoningData.ReasoningDetails[0]
+
+ if strings.HasPrefix(detail.Format, "openai-responses") || strings.HasPrefix(detail.Format, "xai-responses") {
+ if detail.Data != "" {
+ currentState.metadata.EncryptedContent = &detail.Data
+ currentState.metadata.ItemID = detail.ID
+ ctx[reasoningStartedCtx] = nil
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningEnd,
+ ID: fmt.Sprintf("%d", inx),
+ ProviderMetadata: fantasy.ProviderMetadata{
+ openaipkg.Name: currentState.metadata,
+ },
+ })
+ }
+ var textDelta string
+ if len(currentState.metadata.Summary)-1 >= detail.Index {
+ currentState.metadata.Summary[detail.Index] += detail.Summary
+ textDelta = detail.Summary
+ } else {
+ currentState.metadata.Summary = append(currentState.metadata.Summary, detail.Summary)
+ textDelta = "\n" + detail.Summary
+ }
+ ctx[reasoningStartedCtx] = currentState
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningDelta,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: textDelta,
+ ProviderMetadata: fantasy.ProviderMetadata{
+ openaipkg.Name: currentState.metadata,
+ },
+ })
+ }
+
+ if strings.HasPrefix(detail.Format, "anthropic-claude") {
+ if detail.Signature != "" {
+ metadata := fantasy.ProviderMetadata{
+ anthropic.Name: &anthropic.ReasoningOptionMetadata{
+ Signature: detail.Signature,
+ },
+ }
+ shouldContinue := yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningDelta,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: detail.Text,
+ ProviderMetadata: metadata,
+ })
+ if !shouldContinue {
+ return ctx, false
+ }
+ ctx[reasoningStartedCtx] = nil
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningEnd,
+ ID: fmt.Sprintf("%d", inx),
+ })
+ }
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningDelta,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: detail.Text,
+ })
+ }
+
+ if strings.HasPrefix(detail.Format, "google-gemini") {
+ if detail.Type == "reasoning.text" {
+ currentState.googleText += detail.Text
+ ctx[reasoningStartedCtx] = currentState
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningDelta,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: detail.Text,
+ })
+ }
+ if detail.Type == "reasoning.encrypted" {
+ currentState.googleMetadata.Signature = detail.Data
+ currentState.googleMetadata.ToolID = detail.ID
+ metadata := fantasy.ProviderMetadata{
+ google.Name: currentState.googleMetadata,
+ }
+ ctx[reasoningStartedCtx] = nil
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningEnd,
+ ID: fmt.Sprintf("%d", inx),
+ ProviderMetadata: metadata,
+ })
+ }
+ }
+
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningDelta,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: detail.Text,
+ })
+ }
+
+ if reasoningData.Reasoning != "" {
+ return ctx, yield(fantasy.StreamPart{
+ Type: fantasy.StreamPartTypeReasoningDelta,
+ ID: fmt.Sprintf("%d", inx),
+ Delta: reasoningData.Reasoning,
+ })
+ }
+
+ return ctx, true
+}
+
+func languageModelUsage(response openaisdk.ChatCompletion) (fantasy.Usage, fantasy.ProviderOptionsData) {
+ if len(response.Choices) == 0 {
+ return fantasy.Usage{}, nil
+ }
+
+ usage := response.Usage
+ completionTokenDetails := usage.CompletionTokensDetails
+ promptTokenDetails := usage.PromptTokensDetails
+
+ var provider string
+ if p, ok := response.JSON.ExtraFields["provider"]; ok {
+ provider = p.Raw()
+ }
+
+ providerMetadata := &ProviderMetadata{
+ Provider: provider,
+ }
+
+ return fantasy.Usage{
+ InputTokens: usage.PromptTokens,
+ OutputTokens: usage.CompletionTokens,
+ TotalTokens: usage.TotalTokens,
+ ReasoningTokens: completionTokenDetails.ReasoningTokens,
+ CacheReadTokens: promptTokenDetails.CachedTokens,
+ }, providerMetadata
+}
+
+func languageModelStreamUsage(chunk openaisdk.ChatCompletionChunk, _ map[string]any, metadata fantasy.ProviderMetadata) (fantasy.Usage, fantasy.ProviderMetadata) {
+ usage := chunk.Usage
+ if usage.TotalTokens == 0 {
+ return fantasy.Usage{}, nil
+ }
+
+ streamProviderMetadata := &ProviderMetadata{}
+ if metadata != nil {
+ if providerMetadata, ok := metadata[Name]; ok {
+ converted, ok := providerMetadata.(*ProviderMetadata)
+ if ok {
+ streamProviderMetadata = converted
+ }
+ }
+ }
+
+ if p, ok := chunk.JSON.ExtraFields["provider"]; ok {
+ streamProviderMetadata.Provider = p.Raw()
+ }
+
+ completionTokenDetails := usage.CompletionTokensDetails
+ promptTokenDetails := usage.PromptTokensDetails
+ aiUsage := fantasy.Usage{
+ InputTokens: usage.PromptTokens,
+ OutputTokens: usage.CompletionTokens,
+ TotalTokens: usage.TotalTokens,
+ ReasoningTokens: completionTokenDetails.ReasoningTokens,
+ CacheReadTokens: promptTokenDetails.CachedTokens,
+ }
+
+ return aiUsage, fantasy.ProviderMetadata{
+ Name: streamProviderMetadata,
+ }
+}
+
+func languageModelToPrompt(prompt fantasy.Prompt, _, model string) ([]openaisdk.ChatCompletionMessageParamUnion, []fantasy.CallWarning) {
+ var messages []openaisdk.ChatCompletionMessageParamUnion
+ var warnings []fantasy.CallWarning
+
+ for _, msg := range prompt {
+ switch msg.Role {
+ case fantasy.MessageRoleSystem:
+ var systemPromptParts []string
+ for _, c := range msg.Content {
+ if c.GetType() != fantasy.ContentTypeText {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "system prompt can only have text content",
+ })
+ continue
+ }
+ textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "system prompt text part does not have the right type",
+ })
+ continue
+ }
+ text := textPart.Text
+ if strings.TrimSpace(text) != "" {
+ systemPromptParts = append(systemPromptParts, textPart.Text)
+ }
+ }
+ if len(systemPromptParts) == 0 {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "system prompt has no text parts",
+ })
+ continue
+ }
+ systemMsg := openaisdk.SystemMessage(strings.Join(systemPromptParts, "\n"))
+ anthropicCache := anthropic.GetCacheControl(msg.ProviderOptions)
+ if anthropicCache != nil {
+ systemMsg.OfSystem.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": anthropicCache.Type,
+ },
+ })
+ }
+ messages = append(messages, systemMsg)
+
+ case fantasy.MessageRoleUser:
+ if len(msg.Content) == 1 && msg.Content[0].GetType() == fantasy.ContentTypeText {
+ textPart, ok := fantasy.AsContentType[fantasy.TextPart](msg.Content[0])
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "user message text part does not have the right type",
+ })
+ continue
+ }
+ userMsg := openaisdk.UserMessage(textPart.Text)
+ anthropicCache := anthropic.GetCacheControl(msg.ProviderOptions)
+ if anthropicCache != nil {
+ userMsg.OfUser.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": anthropicCache.Type,
+ },
+ })
+ }
+ messages = append(messages, userMsg)
+ continue
+ }
+
+ var content []openaisdk.ChatCompletionContentPartUnionParam
+ for i, c := range msg.Content {
+ isLastPart := i == len(msg.Content)-1
+ cacheControl := anthropic.GetCacheControl(c.Options())
+ if cacheControl == nil && isLastPart {
+ cacheControl = anthropic.GetCacheControl(msg.ProviderOptions)
+ }
+ switch c.GetType() {
+ case fantasy.ContentTypeText:
+ textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "user message text part does not have the right type",
+ })
+ continue
+ }
+ part := openaisdk.ChatCompletionContentPartUnionParam{
+ OfText: &openaisdk.ChatCompletionContentPartTextParam{
+ Text: textPart.Text,
+ },
+ }
+ if cacheControl != nil {
+ part.OfText.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ content = append(content, part)
+ case fantasy.ContentTypeFile:
+ filePart, ok := fantasy.AsContentType[fantasy.FilePart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "user message file part does not have the right type",
+ })
+ continue
+ }
+ switch {
+ case strings.HasPrefix(filePart.MediaType, "image/"):
+ base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
+ data := "data:" + filePart.MediaType + ";base64," + base64Encoded
+ imageURL := openaisdk.ChatCompletionContentPartImageImageURLParam{URL: data}
+ if providerOptions, ok := filePart.ProviderOptions[openaipkg.Name]; ok {
+ if detail, ok := providerOptions.(*openaipkg.ProviderFileOptions); ok {
+ imageURL.Detail = detail.ImageDetail
+ }
+ }
+ imageBlock := openaisdk.ChatCompletionContentPartImageParam{ImageURL: imageURL}
+ if cacheControl != nil {
+ imageBlock.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfImageURL: &imageBlock})
+
+ case filePart.MediaType == "audio/wav":
+ base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
+ audioBlock := openaisdk.ChatCompletionContentPartInputAudioParam{
+ InputAudio: openaisdk.ChatCompletionContentPartInputAudioInputAudioParam{
+ Data: base64Encoded,
+ Format: "wav",
+ },
+ }
+ if cacheControl != nil {
+ audioBlock.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfInputAudio: &audioBlock})
+
+ case filePart.MediaType == "audio/mpeg" || filePart.MediaType == "audio/mp3":
+ base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
+ audioBlock := openaisdk.ChatCompletionContentPartInputAudioParam{
+ InputAudio: openaisdk.ChatCompletionContentPartInputAudioInputAudioParam{
+ Data: base64Encoded,
+ Format: "mp3",
+ },
+ }
+ if cacheControl != nil {
+ audioBlock.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfInputAudio: &audioBlock})
+
+ case filePart.MediaType == "application/pdf":
+ dataStr := string(filePart.Data)
+ if strings.HasPrefix(dataStr, "file-") {
+ fileBlock := openaisdk.ChatCompletionContentPartFileParam{
+ File: openaisdk.ChatCompletionContentPartFileFileParam{
+ FileID: param.NewOpt(dataStr),
+ },
+ }
+ if cacheControl != nil {
+ fileBlock.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfFile: &fileBlock})
+ } else {
+ base64Encoded := base64.StdEncoding.EncodeToString(filePart.Data)
+ data := "data:application/pdf;base64," + base64Encoded
+ filename := filePart.Filename
+ if filename == "" {
+ filename = fmt.Sprintf("part-%d.pdf", len(content))
+ }
+ fileBlock := openaisdk.ChatCompletionContentPartFileParam{
+ File: openaisdk.ChatCompletionContentPartFileFileParam{
+ Filename: param.NewOpt(filename),
+ FileData: param.NewOpt(data),
+ },
+ }
+ if cacheControl != nil {
+ fileBlock.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ content = append(content, openaisdk.ChatCompletionContentPartUnionParam{OfFile: &fileBlock})
+ }
+
+ default:
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: fmt.Sprintf("file part media type %s not supported", filePart.MediaType),
+ })
+ }
+ }
+ }
+ if !hasVisibleUserContent(content) {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "dropping empty user message (contains neither user-facing content nor tool results)",
+ })
+ continue
+ }
+ messages = append(messages, openaisdk.UserMessage(content))
+
+ case fantasy.MessageRoleAssistant:
+ if len(msg.Content) == 1 && msg.Content[0].GetType() == fantasy.ContentTypeText {
+ textPart, ok := fantasy.AsContentType[fantasy.TextPart](msg.Content[0])
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "assistant message text part does not have the right type",
+ })
+ continue
+ }
+ assistantMsg := openaisdk.AssistantMessage(textPart.Text)
+ anthropicCache := anthropic.GetCacheControl(msg.ProviderOptions)
+ if anthropicCache != nil {
+ assistantMsg.OfAssistant.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": anthropicCache.Type,
+ },
+ })
+ }
+ messages = append(messages, assistantMsg)
+ continue
+ }
+
+ assistantMsg := openaisdk.ChatCompletionAssistantMessageParam{
+ Role: "assistant",
+ }
+ for i, c := range msg.Content {
+ isLastPart := i == len(msg.Content)-1
+ cacheControl := anthropic.GetCacheControl(c.Options())
+ if cacheControl == nil && isLastPart {
+ cacheControl = anthropic.GetCacheControl(msg.ProviderOptions)
+ }
+ switch c.GetType() {
+ case fantasy.ContentTypeText:
+ textPart, ok := fantasy.AsContentType[fantasy.TextPart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "assistant message text part does not have the right type",
+ })
+ continue
+ }
+ if assistantMsg.Content.OfString.Valid() {
+ textPart.Text = assistantMsg.Content.OfString.Value + "\n" + textPart.Text
+ }
+ assistantMsg.Content = openaisdk.ChatCompletionAssistantMessageParamContentUnion{
+ OfString: param.NewOpt(textPart.Text),
+ }
+ if cacheControl != nil {
+ assistantMsg.Content.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ case fantasy.ContentTypeReasoning:
+ reasoningPart, ok := fantasy.AsContentType[fantasy.ReasoningPart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "assistant message reasoning part does not have the right type",
+ })
+ continue
+ }
+ var reasoningDetails []ReasoningDetail
+ switch {
+ case strings.HasPrefix(model, "anthropic/") && reasoningPart.Text != "":
+ metadata := anthropic.GetReasoningMetadata(reasoningPart.Options())
+ if metadata == nil {
+ text := fmt.Sprintf("%s", reasoningPart.Text)
+ if assistantMsg.Content.OfString.Valid() {
+ text = assistantMsg.Content.OfString.Value + "\n" + text
+ }
+ assistantMsg.Content = openaisdk.ChatCompletionAssistantMessageParamContentUnion{
+ OfString: param.NewOpt(text),
+ }
+ if cacheControl != nil {
+ assistantMsg.Content.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ continue
+ }
+ reasoningDetails = append(reasoningDetails, ReasoningDetail{
+ Format: "anthropic-claude-v1",
+ Type: "reasoning.text",
+ Text: reasoningPart.Text,
+ Signature: metadata.Signature,
+ })
+ data, _ := json.Marshal(reasoningDetails)
+ reasoningDetailsMap := []map[string]any{}
+ _ = json.Unmarshal(data, &reasoningDetailsMap)
+ assistantMsg.SetExtraFields(map[string]any{
+ "reasoning_details": reasoningDetailsMap,
+ "reasoning": reasoningPart.Text,
+ })
+ case strings.HasPrefix(model, "openai/"):
+ metadata := openaipkg.GetReasoningMetadata(reasoningPart.Options())
+ if metadata == nil {
+ text := fmt.Sprintf("%s", reasoningPart.Text)
+ if assistantMsg.Content.OfString.Valid() {
+ text = assistantMsg.Content.OfString.Value + "\n" + text
+ }
+ assistantMsg.Content = openaisdk.ChatCompletionAssistantMessageParamContentUnion{
+ OfString: param.NewOpt(text),
+ }
+ continue
+ }
+ for inx, summary := range metadata.Summary {
+ if summary == "" {
+ continue
+ }
+ reasoningDetails = append(reasoningDetails, ReasoningDetail{
+ Type: "reasoning.summary",
+ Format: "openai-responses-v1",
+ Summary: summary,
+ Index: inx,
+ })
+ }
+ reasoningDetails = append(reasoningDetails, ReasoningDetail{
+ Type: "reasoning.encrypted",
+ Format: "openai-responses-v1",
+ Data: *metadata.EncryptedContent,
+ ID: metadata.ItemID,
+ })
+ data, _ := json.Marshal(reasoningDetails)
+ reasoningDetailsMap := []map[string]any{}
+ _ = json.Unmarshal(data, &reasoningDetailsMap)
+ assistantMsg.SetExtraFields(map[string]any{
+ "reasoning_details": reasoningDetailsMap,
+ })
+ case strings.HasPrefix(model, "google/"):
+ metadata := google.GetReasoningMetadata(reasoningPart.Options())
+ if metadata == nil {
+ text := fmt.Sprintf("%s", reasoningPart.Text)
+ if assistantMsg.Content.OfString.Valid() {
+ text = assistantMsg.Content.OfString.Value + "\n" + text
+ }
+ assistantMsg.Content = openaisdk.ChatCompletionAssistantMessageParamContentUnion{
+ OfString: param.NewOpt(text),
+ }
+ continue
+ }
+ if reasoningPart.Text != "" {
+ reasoningDetails = append(reasoningDetails, ReasoningDetail{
+ Type: "reasoning.text",
+ Format: "google-gemini-v1",
+ Text: reasoningPart.Text,
+ })
+ }
+ reasoningDetails = append(reasoningDetails, ReasoningDetail{
+ Type: "reasoning.encrypted",
+ Format: "google-gemini-v1",
+ Data: metadata.Signature,
+ ID: metadata.ToolID,
+ })
+ data, _ := json.Marshal(reasoningDetails)
+ reasoningDetailsMap := []map[string]any{}
+ _ = json.Unmarshal(data, &reasoningDetailsMap)
+ assistantMsg.SetExtraFields(map[string]any{
+ "reasoning_details": reasoningDetailsMap,
+ })
+ default:
+ reasoningDetails = append(reasoningDetails, ReasoningDetail{
+ Type: "reasoning.text",
+ Text: reasoningPart.Text,
+ Format: "unknown",
+ })
+ data, _ := json.Marshal(reasoningDetails)
+ reasoningDetailsMap := []map[string]any{}
+ _ = json.Unmarshal(data, &reasoningDetailsMap)
+ assistantMsg.SetExtraFields(map[string]any{
+ "reasoning_details": reasoningDetailsMap,
+ })
+ }
+ case fantasy.ContentTypeToolCall:
+ toolCallPart, ok := fantasy.AsContentType[fantasy.ToolCallPart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "assistant message tool part does not have the right type",
+ })
+ continue
+ }
+ tc := openaisdk.ChatCompletionMessageToolCallUnionParam{
+ OfFunction: &openaisdk.ChatCompletionMessageFunctionToolCallParam{
+ ID: toolCallPart.ToolCallID,
+ Type: "function",
+ Function: openaisdk.ChatCompletionMessageFunctionToolCallFunctionParam{
+ Name: toolCallPart.ToolName,
+ Arguments: toolCallPart.Input,
+ },
+ },
+ }
+ if cacheControl != nil {
+ tc.OfFunction.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ assistantMsg.ToolCalls = append(assistantMsg.ToolCalls, tc)
+ }
+ }
+ messages = append(messages, openaisdk.ChatCompletionMessageParamUnion{
+ OfAssistant: &assistantMsg,
+ })
+
+ case fantasy.MessageRoleTool:
+ for i, c := range msg.Content {
+ isLastPart := i == len(msg.Content)-1
+ cacheControl := anthropic.GetCacheControl(c.Options())
+ if cacheControl == nil && isLastPart {
+ cacheControl = anthropic.GetCacheControl(msg.ProviderOptions)
+ }
+ if c.GetType() != fantasy.ContentTypeToolResult {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "tool message can only have tool result content",
+ })
+ continue
+ }
+ toolResultPart, ok := fantasy.AsContentType[fantasy.ToolResultPart](c)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "tool message result part does not have the right type",
+ })
+ continue
+ }
+ switch toolResultPart.Output.GetType() {
+ case fantasy.ToolResultContentTypeText:
+ output, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentText](toolResultPart.Output)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "tool result output does not have the right type",
+ })
+ continue
+ }
+ tr := openaisdk.ToolMessage(output.Text, toolResultPart.ToolCallID)
+ if cacheControl != nil {
+ tr.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ messages = append(messages, tr)
+ case fantasy.ToolResultContentTypeError:
+ output, ok := fantasy.AsToolResultOutputType[fantasy.ToolResultOutputContentError](toolResultPart.Output)
+ if !ok {
+ warnings = append(warnings, fantasy.CallWarning{
+ Type: fantasy.CallWarningTypeOther,
+ Message: "tool result output does not have the right type",
+ })
+ continue
+ }
+ tr := openaisdk.ToolMessage(output.Error.Error(), toolResultPart.ToolCallID)
+ if cacheControl != nil {
+ tr.SetExtraFields(map[string]any{
+ "cache_control": map[string]string{
+ "type": cacheControl.Type,
+ },
+ })
+ }
+ messages = append(messages, tr)
+ }
+ }
+ }
+ }
+ return messages, warnings
+}
+
+func hasVisibleUserContent(content []openaisdk.ChatCompletionContentPartUnionParam) bool {
+ for _, part := range content {
+ if part.OfText != nil || part.OfImageURL != nil || part.OfInputAudio != nil || part.OfFile != nil {
+ return true
+ }
+ }
+ return false
+}
+
+func structToMapJSON(s any) (map[string]any, error) {
+ var result map[string]any
+ jsonBytes, err := json.Marshal(s)
+ if err != nil {
+ return nil, err
+ }
+ err = json.Unmarshal(jsonBytes, &result)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
diff --git a/providers/vercel/provider_options.go b/providers/vercel/provider_options.go
new file mode 100644
index 0000000000000000000000000000000000000000..046ba940d981117234d72a10747708f699bd4c70
--- /dev/null
+++ b/providers/vercel/provider_options.go
@@ -0,0 +1,191 @@
+// Package vercel provides an implementation of the fantasy AI SDK for Vercel AI Gateway.
+package vercel
+
+import (
+ "encoding/json"
+
+ "charm.land/fantasy"
+)
+
+// Global type identifiers for Vercel-specific provider data.
+const (
+ TypeProviderOptions = Name + ".options"
+ TypeProviderMetadata = Name + ".metadata"
+)
+
+// Register Vercel provider-specific types with the global registry.
+func init() {
+ fantasy.RegisterProviderType(TypeProviderOptions, func(data []byte) (fantasy.ProviderOptionsData, error) {
+ var v ProviderOptions
+ if err := json.Unmarshal(data, &v); err != nil {
+ return nil, err
+ }
+ return &v, nil
+ })
+ fantasy.RegisterProviderType(TypeProviderMetadata, func(data []byte) (fantasy.ProviderOptionsData, error) {
+ var v ProviderMetadata
+ if err := json.Unmarshal(data, &v); err != nil {
+ return nil, err
+ }
+ return &v, nil
+ })
+}
+
+// ReasoningEffort represents the reasoning effort level for Vercel AI Gateway.
+type ReasoningEffort string
+
+const (
+ // ReasoningEffortNone disables reasoning.
+ ReasoningEffortNone ReasoningEffort = "none"
+ // ReasoningEffortMinimal represents minimal reasoning effort (~10% of max_tokens).
+ ReasoningEffortMinimal ReasoningEffort = "minimal"
+ // ReasoningEffortLow represents low reasoning effort (~20% of max_tokens).
+ ReasoningEffortLow ReasoningEffort = "low"
+ // ReasoningEffortMedium represents medium reasoning effort (~50% of max_tokens).
+ ReasoningEffortMedium ReasoningEffort = "medium"
+ // ReasoningEffortHigh represents high reasoning effort (~80% of max_tokens).
+ ReasoningEffortHigh ReasoningEffort = "high"
+ // ReasoningEffortXHigh represents extra high reasoning effort (~95% of max_tokens).
+ ReasoningEffortXHigh ReasoningEffort = "xhigh"
+)
+
+// ReasoningOptions represents reasoning configuration for Vercel AI Gateway.
+type ReasoningOptions struct {
+ // Enabled enables reasoning output. When true, the model will provide its reasoning process.
+ Enabled *bool `json:"enabled,omitempty"`
+ // MaxTokens is the maximum number of tokens to allocate for reasoning.
+ // Cannot be used with Effort.
+ MaxTokens *int64 `json:"max_tokens,omitempty"`
+ // Effort controls reasoning effort level.
+ // Mutually exclusive with MaxTokens.
+ Effort *ReasoningEffort `json:"effort,omitempty"`
+ // Exclude excludes reasoning content from the response but still generates it internally.
+ Exclude *bool `json:"exclude,omitempty"`
+}
+
+// GatewayProviderOptions represents provider routing preferences for Vercel AI Gateway.
+type GatewayProviderOptions struct {
+ // Order is the list of provider slugs to try in order (e.g. ["vertex", "anthropic"]).
+ Order []string `json:"order,omitempty"`
+ // Models is the list of fallback models to try if the primary model fails.
+ Models []string `json:"models,omitempty"`
+}
+
+// BYOKCredential represents a single provider credential for BYOK.
+type BYOKCredential struct {
+ APIKey string `json:"apiKey,omitempty"`
+}
+
+// BYOKOptions represents Bring Your Own Key options for Vercel AI Gateway.
+type BYOKOptions struct {
+ Anthropic map[string][]BYOKCredential `json:"anthropic,omitempty"`
+ OpenAI map[string][]BYOKCredential `json:"openai,omitempty"`
+ Vertex map[string][]BYOKCredential `json:"vertex,omitempty"`
+ Bedrock map[string][]BYOKCredential `json:"bedrock,omitempty"`
+}
+
+// ProviderOptions represents additional options for Vercel AI Gateway provider.
+type ProviderOptions struct {
+ // Reasoning configuration for models that support extended thinking.
+ Reasoning *ReasoningOptions `json:"reasoning,omitempty"`
+ // ProviderOptions for gateway routing preferences.
+ ProviderOptions *GatewayProviderOptions `json:"providerOptions,omitempty"`
+ // BYOK for request-scoped provider credentials.
+ BYOK *BYOKOptions `json:"byok,omitempty"`
+ // User is a unique identifier representing your end-user.
+ User *string `json:"user,omitempty"`
+ // LogitBias modifies the likelihood of specified tokens appearing in the completion.
+ LogitBias map[string]int64 `json:"logit_bias,omitempty"`
+ // LogProbs returns the log probabilities of the tokens.
+ LogProbs *bool `json:"logprobs,omitempty"`
+ // TopLogProbs is the number of top log probabilities to return.
+ TopLogProbs *int64 `json:"top_logprobs,omitempty"`
+ // ParallelToolCalls enables parallel function calling during tool use.
+ ParallelToolCalls *bool `json:"parallel_tool_calls,omitempty"`
+ // ExtraBody for additional request body fields.
+ ExtraBody map[string]any `json:"extra_body,omitempty"`
+}
+
+// Options implements the ProviderOptionsData interface for ProviderOptions.
+func (*ProviderOptions) Options() {}
+
+// MarshalJSON implements custom JSON marshaling with type info for ProviderOptions.
+func (o ProviderOptions) MarshalJSON() ([]byte, error) {
+ type plain ProviderOptions
+ return fantasy.MarshalProviderType(TypeProviderOptions, plain(o))
+}
+
+// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderOptions.
+func (o *ProviderOptions) UnmarshalJSON(data []byte) error {
+ type plain ProviderOptions
+ var p plain
+ if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
+ return err
+ }
+ *o = ProviderOptions(p)
+ return nil
+}
+
+// ProviderMetadata represents metadata from Vercel AI Gateway provider.
+type ProviderMetadata struct {
+ Provider string `json:"provider,omitempty"`
+}
+
+// Options implements the ProviderOptionsData interface for ProviderMetadata.
+func (*ProviderMetadata) Options() {}
+
+// MarshalJSON implements custom JSON marshaling with type info for ProviderMetadata.
+func (m ProviderMetadata) MarshalJSON() ([]byte, error) {
+ type plain ProviderMetadata
+ return fantasy.MarshalProviderType(TypeProviderMetadata, plain(m))
+}
+
+// UnmarshalJSON implements custom JSON unmarshaling with type info for ProviderMetadata.
+func (m *ProviderMetadata) UnmarshalJSON(data []byte) error {
+ type plain ProviderMetadata
+ var p plain
+ if err := fantasy.UnmarshalProviderType(data, &p); err != nil {
+ return err
+ }
+ *m = ProviderMetadata(p)
+ return nil
+}
+
+// ReasoningDetail represents a reasoning detail from Vercel AI Gateway.
+type ReasoningDetail struct {
+ ID string `json:"id,omitempty"`
+ Type string `json:"type,omitempty"`
+ Text string `json:"text,omitempty"`
+ Data string `json:"data,omitempty"`
+ Format string `json:"format,omitempty"`
+ Summary string `json:"summary,omitempty"`
+ Signature string `json:"signature,omitempty"`
+ Index int `json:"index"`
+}
+
+// ReasoningData represents reasoning data from Vercel AI Gateway response.
+type ReasoningData struct {
+ Reasoning string `json:"reasoning,omitempty"`
+ ReasoningDetails []ReasoningDetail `json:"reasoning_details,omitempty"`
+}
+
+// ReasoningEffortOption creates a pointer to a ReasoningEffort value.
+func ReasoningEffortOption(e ReasoningEffort) *ReasoningEffort {
+ return &e
+}
+
+// NewProviderOptions creates new provider options for Vercel.
+func NewProviderOptions(opts *ProviderOptions) fantasy.ProviderOptions {
+ return fantasy.ProviderOptions{
+ Name: opts,
+ }
+}
+
+// ParseOptions parses provider options from a map for Vercel.
+func ParseOptions(data map[string]any) (*ProviderOptions, error) {
+ var options ProviderOptions
+ if err := fantasy.ParseOptions(data, &options); err != nil {
+ return nil, err
+ }
+ return &options, nil
+}
diff --git a/providers/vercel/vercel.go b/providers/vercel/vercel.go
new file mode 100644
index 0000000000000000000000000000000000000000..af87db5eba02a3f7ebea4935cb40ceb1d25d9f78
--- /dev/null
+++ b/providers/vercel/vercel.go
@@ -0,0 +1,114 @@
+// Package vercel provides an implementation of the fantasy AI SDK for Vercel AI Gateway.
+package vercel
+
+import (
+ "charm.land/fantasy"
+ "charm.land/fantasy/providers/openai"
+ "github.com/openai/openai-go/v2/option"
+)
+
+type options struct {
+ openaiOptions []openai.Option
+ languageModelOptions []openai.LanguageModelOption
+ sdkOptions []option.RequestOption
+ objectMode fantasy.ObjectMode
+}
+
+const (
+ // DefaultURL is the default URL for the Vercel AI Gateway API.
+ DefaultURL = "https://ai-gateway.vercel.sh/v1"
+ // Name is the name of the Vercel provider.
+ Name = "vercel"
+)
+
+// Option defines a function that configures Vercel provider options.
+type Option = func(*options)
+
+// New creates a new Vercel AI Gateway provider with the given options.
+func New(opts ...Option) (fantasy.Provider, error) {
+ providerOptions := options{
+ openaiOptions: []openai.Option{
+ openai.WithName(Name),
+ openai.WithBaseURL(DefaultURL),
+ },
+ languageModelOptions: []openai.LanguageModelOption{
+ openai.WithLanguageModelPrepareCallFunc(languagePrepareModelCall),
+ openai.WithLanguageModelUsageFunc(languageModelUsage),
+ openai.WithLanguageModelStreamUsageFunc(languageModelStreamUsage),
+ openai.WithLanguageModelStreamExtraFunc(languageModelStreamExtra),
+ openai.WithLanguageModelExtraContentFunc(languageModelExtraContent),
+ openai.WithLanguageModelToPromptFunc(languageModelToPrompt),
+ },
+ objectMode: fantasy.ObjectModeTool, // Default to tool mode for vercel
+ }
+ for _, o := range opts {
+ o(&providerOptions)
+ }
+
+ // Handle object mode: convert unsupported modes to tool
+ // Vercel AI Gateway doesn't support native JSON mode, so we use tool or text
+ objectMode := providerOptions.objectMode
+ if objectMode == fantasy.ObjectModeAuto || objectMode == fantasy.ObjectModeJSON {
+ objectMode = fantasy.ObjectModeTool
+ }
+
+ providerOptions.openaiOptions = append(
+ providerOptions.openaiOptions,
+ openai.WithSDKOptions(providerOptions.sdkOptions...),
+ openai.WithLanguageModelOptions(providerOptions.languageModelOptions...),
+ openai.WithObjectMode(objectMode),
+ )
+ return openai.New(providerOptions.openaiOptions...)
+}
+
+// WithAPIKey sets the API key for the Vercel provider.
+func WithAPIKey(apiKey string) Option {
+ return func(o *options) {
+ o.openaiOptions = append(o.openaiOptions, openai.WithAPIKey(apiKey))
+ }
+}
+
+// WithBaseURL sets the base URL for the Vercel provider.
+func WithBaseURL(url string) Option {
+ return func(o *options) {
+ o.openaiOptions = append(o.openaiOptions, openai.WithBaseURL(url))
+ }
+}
+
+// WithName sets the name for the Vercel provider.
+func WithName(name string) Option {
+ return func(o *options) {
+ o.openaiOptions = append(o.openaiOptions, openai.WithName(name))
+ }
+}
+
+// WithHeaders sets the headers for the Vercel provider.
+func WithHeaders(headers map[string]string) Option {
+ return func(o *options) {
+ o.openaiOptions = append(o.openaiOptions, openai.WithHeaders(headers))
+ }
+}
+
+// WithHTTPClient sets the HTTP client for the Vercel provider.
+func WithHTTPClient(client option.HTTPClient) Option {
+ return func(o *options) {
+ o.openaiOptions = append(o.openaiOptions, openai.WithHTTPClient(client))
+ }
+}
+
+// WithSDKOptions sets the SDK options for the Vercel provider.
+func WithSDKOptions(opts ...option.RequestOption) Option {
+ return func(o *options) {
+ o.sdkOptions = append(o.sdkOptions, opts...)
+ }
+}
+
+// WithObjectMode sets the object generation mode for the Vercel provider.
+// Supported modes: ObjectModeTool, ObjectModeText.
+// ObjectModeAuto and ObjectModeJSON are automatically converted to ObjectModeTool
+// since Vercel AI Gateway doesn't support native JSON mode.
+func WithObjectMode(om fantasy.ObjectMode) Option {
+ return func(o *options) {
+ o.objectMode = om
+ }
+}
diff --git a/providertests/testdata/TestVercelCommon/claude-sonnet-4/multi_tool.yaml b/providertests/testdata/TestVercelCommon/claude-sonnet-4/multi_tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7ab9ef881a8e7732bfcfc6e37cbb0d5e13d5ef33
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/claude-sonnet-4/multi_tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 830
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37K2HQCCQMFG024V4NNE3","object":"chat.completion","created":1770033239,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"toolu_01Pp7heoom1NFVC9pZAq7RVP","type":"function","function":{"name":"add","arguments":"{\"a\":2,\"b\":3}"}},{"id":"toolu_01CyT9hTRh1yDg65BtKKoQoJ","type":"function","function":{"name":"multiply","arguments":"{\"a\":2,\"b\":3}"}}],"provider_metadata":{"anthropic":{"usage":{"input_tokens":507,"output_tokens":135,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":335024.437964,"endTime":337607.847298,"statusCode":200,"providerResponseId":"msg_01K9VNT3Y7C6bhS39BSLDfma"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.003546","marketCost":"0.003546","generationId":"gen_01KGF37K2HQCCQMFG024V4NNE3","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":507,"completion_tokens":135,"total_tokens":642,"cost":0.003546,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003546},"system_fingerprint":"fp_lt5c47efr0","generationId":"gen_01KGF37K2HQCCQMFG024V4NNE3"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.695440458s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1259
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"toolu_01Pp7heoom1NFVC9pZAq7RVP","function":{"arguments":"{\"a\":2,\"b\":3}","name":"add"},"type":"function"},{"id":"toolu_01CyT9hTRh1yDg65BtKKoQoJ","function":{"arguments":"{\"a\":2,\"b\":3}","name":"multiply"},"type":"function"}],"role":"assistant"},{"content":"5","tool_call_id":"toolu_01Pp7heoom1NFVC9pZAq7RVP","role":"tool"},{"content":"6","tool_call_id":"toolu_01CyT9hTRh1yDg65BtKKoQoJ","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37NPK9H15VB93JDFXHTFA","object":"chat.completion","created":1770033242,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"I''ve performed both operations with the numbers 2 and 3:\n- Addition: 2 + 3 = 5\n- Multiplication: 2 × 3 = 6","provider_metadata":{"anthropic":{"usage":{"input_tokens":688,"output_tokens":47,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":4529729.487684,"endTime":4532485.133344,"statusCode":200,"providerResponseId":"msg_01NmyxoER7vKZW5SBBtUa98q"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002769","marketCost":"0.002769","generationId":"gen_01KGF37NPK9H15VB93JDFXHTFA","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":688,"completion_tokens":47,"total_tokens":735,"cost":0.002769,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002769},"system_fingerprint":"fp_iwzjnx4gms","generationId":"gen_01KGF37NPK9H15VB93JDFXHTFA"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.965395875s
diff --git a/providertests/testdata/TestVercelCommon/claude-sonnet-4/multi_tool_streaming.yaml b/providertests/testdata/TestVercelCommon/claude-sonnet-4/multi_tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ba630b779a4f7c1b28d213e806e15987189d9f98
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/claude-sonnet-4/multi_tool_streaming.yaml
@@ -0,0 +1,113 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 867
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"I"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'ll add an"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"d multiply the"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" numbers 2 and 3 "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"for you."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"toolu_0135npjMLttuPFBue5jmkrQ7","type":"function","function":{"name":"add","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"a\": 2"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":", \""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"b\": 3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"toolu_0158fwcmJxxApeN8LydKZFKq","type":"function","function":{"name":"multiply","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"a\": 2"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":", \"b"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"\": 3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_hia2ehn86q"}
+
+ data: {"id":"gen_01KGF37RMDX4SKJG4WVQMM9169","object":"chat.completion.chunk","created":1770033244,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":502,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":137,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1348791.685811,"endTime":1350481.290097,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1348791.685811,"endTime":1350481.290097,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.003561","marketCost":"0.003561","generationId":"gen_01KGF37RMDX4SKJG4WVQMM9169","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":502,"completion_tokens":137,"total_tokens":639,"cost":0.003561,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003561},"system_fingerprint":"fp_hia2ehn86q","generationId":"gen_01KGF37RMDX4SKJG4WVQMM9169"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.838556459s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1365
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"content":"I''ll add and multiply the numbers 2 and 3 for you.","tool_calls":[{"id":"toolu_0135npjMLttuPFBue5jmkrQ7","function":{"arguments":"{\"a\": 2, \"b\": 3}","name":"add"},"type":"function"},{"id":"toolu_0158fwcmJxxApeN8LydKZFKq","function":{"arguments":"{\"a\": 2, \"b\": 3}","name":"multiply"},"type":"function"}],"role":"assistant"},{"content":"5","tool_call_id":"toolu_0135npjMLttuPFBue5jmkrQ7","role":"tool"},{"content":"6","tool_call_id":"toolu_0158fwcmJxxApeN8LydKZFKq","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" results"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" are"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":":\n- "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"2 + 3 = "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"5\n- 2 × "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"3 = 6"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_sdbcn0gb5k"}
+
+ data: {"id":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","object":"chat.completion.chunk","created":1770033246,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":700,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":31,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7614629.293412,"endTime":7615648.604763,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7614629.293412,"endTime":7615648.604763,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002565","marketCost":"0.002565","generationId":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":700,"completion_tokens":31,"total_tokens":731,"cost":0.002565,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002565},"system_fingerprint":"fp_sdbcn0gb5k","generationId":"gen_01KGF37VJZFMN3ZHEKK9EGN5P1"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.108064583s
diff --git a/providertests/testdata/TestVercelCommon/claude-sonnet-4/simple.yaml b/providertests/testdata/TestVercelCommon/claude-sonnet-4/simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c62fe28e87ccb13f94e2c4e92411edb4210629f4
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/claude-sonnet-4/simple.yaml
@@ -0,0 +1,33 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 175
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF377728Q76J66SN7WNPNNP","object":"chat.completion","created":1770033226,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"Olá! \n\nThat''s \"hi\" in Portuguese. You could also say \"Oi!\" which is a bit more casual and friendly.","provider_metadata":{"anthropic":{"usage":{"input_tokens":16,"output_tokens":35,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1330927.642499,"endTime":1332861.743603,"statusCode":200,"providerResponseId":"msg_01KTuWnKf9GVVspdbvDRUbTo"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.000573","marketCost":"0.000573","generationId":"gen_01KGF377728Q76J66SN7WNPNNP","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"completion_tokens":35,"total_tokens":51,"cost":0.000573,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000573},"system_fingerprint":"fp_t6mx2uhujo","generationId":"gen_01KGF377728Q76J66SN7WNPNNP"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.374222792s
diff --git a/providertests/testdata/TestVercelCommon/claude-sonnet-4/simple_streaming.yaml b/providertests/testdata/TestVercelCommon/claude-sonnet-4/simple_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cf48e674de900fe50e962f0e0f165a5869f11975
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/claude-sonnet-4/simple_streaming.yaml
@@ -0,0 +1,62 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 229
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"Oi!"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"\n\n("},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"You"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" can"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" also say \"Olá!\" which"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" another"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" common way"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" to say hi"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" Portuguese)"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5a0fyewqxl"}
+
+ data: {"id":"gen_01KGF379703450NEHTHYWRXNWC","object":"chat.completion.chunk","created":1770033227,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":16,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":30,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1333898.356903,"endTime":1334761.868909,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1333898.356903,"endTime":1334761.868909,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000498","marketCost":"0.000498","generationId":"gen_01KGF379703450NEHTHYWRXNWC","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"completion_tokens":30,"total_tokens":46,"cost":0.000498,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000498},"system_fingerprint":"fp_5a0fyewqxl","generationId":"gen_01KGF379703450NEHTHYWRXNWC"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 993.576166ms
diff --git a/providertests/testdata/TestVercelCommon/claude-sonnet-4/tool.yaml b/providertests/testdata/TestVercelCommon/claude-sonnet-4/tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..ca3bb5c2b87e764921bb0effa4d9abfaf9843801
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/claude-sonnet-4/tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 467
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37B48YTSG8HPMC0Z9AVAR","object":"chat.completion","created":1770033230,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"toolu_01NSrymFZiohT2iy9U5LE9rA","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence,Italy\"}"}}],"provider_metadata":{"anthropic":{"usage":{"input_tokens":394,"output_tokens":67,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":2429109.035804,"endTime":2430987.56251,"statusCode":200,"providerResponseId":"msg_01Ak5uPKnJHaza1hFgS4fMoY"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002187","marketCost":"0.002187","generationId":"gen_01KGF37B48YTSG8HPMC0Z9AVAR","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":394,"completion_tokens":67,"total_tokens":461,"cost":0.002187,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002187},"system_fingerprint":"fp_u1vgvb877f","generationId":"gen_01KGF37B48YTSG8HPMC0Z9AVAR"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 1.999195125s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 720
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"toolu_01NSrymFZiohT2iy9U5LE9rA","function":{"arguments":"{\"location\":\"Florence,Italy\"}","name":"weather"},"type":"function"}],"role":"assistant"},{"content":"40 C","tool_call_id":"toolu_01NSrymFZiohT2iy9U5LE9rA","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37D4BQSXP782PJN0Q3KYT","object":"chat.completion","created":1770033233,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"The current weather in Florence, Italy is 40°C (104°F). That''s quite hot! It''s a very warm day there.","provider_metadata":{"anthropic":{"usage":{"input_tokens":463,"output_tokens":33,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":410587.245308,"endTime":412600.850201,"statusCode":200,"providerResponseId":"msg_01ReE5KwsYimH5AMRwEuLit9"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.001884","marketCost":"0.001884","generationId":"gen_01KGF37D4BQSXP782PJN0Q3KYT","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":463,"completion_tokens":33,"total_tokens":496,"cost":0.001884,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.001884},"system_fingerprint":"fp_dwzayvqyi3","generationId":"gen_01KGF37D4BQSXP782PJN0Q3KYT"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.1313565s
diff --git a/providertests/testdata/TestVercelCommon/claude-sonnet-4/tool_streaming.yaml b/providertests/testdata/TestVercelCommon/claude-sonnet-4/tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0039e197a1ec049f3910e564a992dd923f9ce0ce
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/claude-sonnet-4/tool_streaming.yaml
@@ -0,0 +1,121 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 521
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"I'll get the weather information for Florence"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":", Italy for you."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"toolu_01P61EhnucuCA3gRE8rXpYrt","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"location\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":": \""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Florence,"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Ita"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ly\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_22ov8ctw6a"}
+
+ data: {"id":"gen_01KGF37F6TEH1JWRE2BABW1XV7","object":"chat.completion.chunk","created":1770033234,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":394,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":67,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1339997.935348,"endTime":1341183.011845,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1339997.935348,"endTime":1341183.011845,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002187","marketCost":"0.002187","generationId":"gen_01KGF37F6TEH1JWRE2BABW1XV7","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":394,"completion_tokens":67,"total_tokens":461,"cost":0.002187,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002187},"system_fingerprint":"fp_22ov8ctw6a","generationId":"gen_01KGF37F6TEH1JWRE2BABW1XV7"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.273492958s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 850
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"content":"I''ll get the weather information for Florence, Italy for you.","tool_calls":[{"id":"toolu_01P61EhnucuCA3gRE8rXpYrt","function":{"arguments":"{\"location\": \"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant"},{"content":"40 C","tool_call_id":"toolu_01P61EhnucuCA3gRE8rXpYrt","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"The current"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" weather in Florence, Italy shows"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" temperature of 40°C (104"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"°F)."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" That"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'s quite hot"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" It woul"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"d be a good idea to stay"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" hydrated and seek"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" shade or"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" air conditioning if you're planning"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" to be"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" out"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"doors."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_xnw4h12lhy"}
+
+ data: {"id":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","object":"chat.completion.chunk","created":1770033235,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":476,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":53,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":3034449.959696,"endTime":3035377.30027,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":3034449.959696,"endTime":3035377.30027,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002223","marketCost":"0.002223","generationId":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":476,"completion_tokens":53,"total_tokens":529,"cost":0.002223,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002223},"system_fingerprint":"fp_xnw4h12lhy","generationId":"gen_01KGF37H1H6MYNJHYZ2N1SWF5H"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.122953792s
diff --git a/providertests/testdata/TestVercelCommon/gemini-2.5-flash/multi_tool.yaml b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/multi_tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5f1fc92ac8e1d7a7c225028464974c449c6bb5fb
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/multi_tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 828
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF381BH2CF0J56H612T8RC3","object":"chat.completion","created":1770033252,"model":"google/gemini-2.5-flash","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"s3q46gVXfhyIqY2s","type":"function","function":{"name":"add","arguments":"{\"a\":2,\"b\":3}"}},{"id":"vomF7JlLjIRlW7U8","type":"function","function":{"name":"multiply","arguments":"{\"a\":2,\"b\":3}"}}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":111,"promptTokenCount":61,"candidatesTokenCount":10,"totalTokenCount":182,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":4669622.140163,"endTime":4670671.510973,"statusCode":200,"providerResponseId":"Y5CAadiYMJCgmPUPj9uV-AI"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.0003208","marketCost":"0.0003208","generationId":"gen_01KGF381BH2CF0J56H612T8RC3","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":61,"completion_tokens":10,"total_tokens":71,"cost":0.0003208,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":111,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0003208},"system_fingerprint":"fp_q0dgwe4fbo","generationId":"gen_01KGF381BH2CF0J56H612T8RC3"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 1.184203208s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1201
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"s3q46gVXfhyIqY2s","function":{"arguments":"{\"a\":2,\"b\":3}","name":"add"},"type":"function"},{"id":"vomF7JlLjIRlW7U8","function":{"arguments":"{\"a\":2,\"b\":3}","name":"multiply"},"type":"function"}],"role":"assistant"},{"content":"5","tool_call_id":"s3q46gVXfhyIqY2s","role":"tool"},{"content":"6","tool_call_id":"vomF7JlLjIRlW7U8","role":"tool"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF382G93A1FEHZRVZDSTMQE","object":"chat.completion","created":1770033253,"model":"google/gemini-2.5-flash","choices":[{"index":0,"message":{"role":"assistant","content":"The sum of 2 and 3 is 5, and the product of 2 and 3 is 6.","provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":197,"candidatesTokenCount":25,"totalTokenCount":222}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"google","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":false,"error":"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn.","startTime":1956234.837355,"endTime":1956397.272511,"statusCode":400},{"provider":"google","internalModelId":"google:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":1956497.822129,"endTime":1956985.150646,"statusCode":200,"providerResponseId":"ZZCAady9I-KF7M8PkM3b4AE"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.0001216","marketCost":"0.0001216","generationId":"gen_01KGF382G93A1FEHZRVZDSTMQE","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":197,"completion_tokens":25,"total_tokens":222,"cost":0.0001216,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0001216},"system_fingerprint":"fp_sxou9xxzzl","generationId":"gen_01KGF382G93A1FEHZRVZDSTMQE"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 921.5745ms
diff --git a/providertests/testdata/TestVercelCommon/gemini-2.5-flash/multi_tool_streaming.yaml b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/multi_tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..25610637b38ad6a0e89aaca399ed38995ba06654
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/multi_tool_streaming.yaml
@@ -0,0 +1,87 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 865
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF383DF2E9FSJX95AA3ZED7","object":"chat.completion.chunk","created":1770033254,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_nkvitg7moc"}
+
+ data: {"id":"gen_01KGF383DF2E9FSJX95AA3ZED7","object":"chat.completion.chunk","created":1770033254,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"S66o9rnUIliVpcHx","type":"function","function":{"name":"add","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_nkvitg7moc"}
+
+ data: {"id":"gen_01KGF383DF2E9FSJX95AA3ZED7","object":"chat.completion.chunk","created":1770033254,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"b\":3,\"a\":2}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_nkvitg7moc"}
+
+ data: {"id":"gen_01KGF383DF2E9FSJX95AA3ZED7","object":"chat.completion.chunk","created":1770033254,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"6e0NXuEtzAHkTRep","type":"function","function":{"name":"multiply","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_nkvitg7moc"}
+
+ data: {"id":"gen_01KGF383DF2E9FSJX95AA3ZED7","object":"chat.completion.chunk","created":1770033254,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"a\":2,\"b\":3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_nkvitg7moc"}
+
+ data: {"id":"gen_01KGF383DF2E9FSJX95AA3ZED7","object":"chat.completion.chunk","created":1770033254,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":37,"promptTokenCount":57,"candidatesTokenCount":10,"totalTokenCount":104,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":3167743.289212,"endTime":3168716.703261,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":3167743.289212,"endTime":3168716.703261,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.0001346","marketCost":"0.0001346","generationId":"gen_01KGF383DF2E9FSJX95AA3ZED7","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":57,"completion_tokens":10,"total_tokens":67,"cost":0.0001346,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":37,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0001346},"system_fingerprint":"fp_nkvitg7moc","generationId":"gen_01KGF383DF2E9FSJX95AA3ZED7"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.071326459s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1238
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"S66o9rnUIliVpcHx","function":{"arguments":"{\"b\":3,\"a\":2}","name":"add"},"type":"function"},{"id":"6e0NXuEtzAHkTRep","function":{"arguments":"{\"a\":2,\"b\":3}","name":"multiply"},"type":"function"}],"role":"assistant"},{"content":"5","tool_call_id":"S66o9rnUIliVpcHx","role":"tool"},{"content":"6","tool_call_id":"6e0NXuEtzAHkTRep","role":"tool"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF384F3XAWSR4PC2A0QPAGW","object":"chat.completion.chunk","created":1770033255,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_r6gptvhx1g"}
+
+ data: {"id":"gen_01KGF384F3XAWSR4PC2A0QPAGW","object":"chat.completion.chunk","created":1770033255,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"content":"The sum of"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_r6gptvhx1g"}
+
+ data: {"id":"gen_01KGF384F3XAWSR4PC2A0QPAGW","object":"chat.completion.chunk","created":1770033255,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"content":" 2 and 3 is 5, and the product of 2 and"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_r6gptvhx1g"}
+
+ data: {"id":"gen_01KGF384F3XAWSR4PC2A0QPAGW","object":"chat.completion.chunk","created":1770033255,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"content":" 3 is 6."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_r6gptvhx1g"}
+
+ data: {"id":"gen_01KGF384F3XAWSR4PC2A0QPAGW","object":"chat.completion.chunk","created":1770033255,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":193,"candidatesTokenCount":23,"totalTokenCount":216}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"google","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":false,"error":"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn.","startTime":3168815.590185,"endTime":3168973.53366,"statusCode":400},{"provider":"google","internalModelId":"google:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":3169095.201105,"endTime":3169473.585021,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":true,"providerAttemptCount":2,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":false,"error":"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn.","startTime":3168815.590185,"endTime":3168973.53366,"statusCode":400},{"provider":"google","internalModelId":"google:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":3169095.201105,"endTime":3169473.585021,"statusCode":200}]}],"totalProviderAttemptCount":2},"cost":"0.0001154","marketCost":"0.0001154","generationId":"gen_01KGF384F3XAWSR4PC2A0QPAGW","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":193,"completion_tokens":23,"total_tokens":216,"cost":0.0001154,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0001154},"system_fingerprint":"fp_r6gptvhx1g","generationId":"gen_01KGF384F3XAWSR4PC2A0QPAGW"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 752.724625ms
diff --git a/providertests/testdata/TestVercelCommon/gemini-2.5-flash/simple.yaml b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..9676008c622dcbc9d8d14dbc35a811f1b24f41e4
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/simple.yaml
@@ -0,0 +1,33 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 173
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"google/gemini-2.5-flash","max_tokens":4000}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37X8BY3AB4X8CN72NQHAV","object":"chat.completion","created":1770033248,"model":"google/gemini-2.5-flash","choices":[{"index":0,"message":{"role":"assistant","content":"Olá!","provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":23,"promptTokenCount":9,"candidatesTokenCount":2,"totalTokenCount":34,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":427093.03273,"endTime":427617.793917,"statusCode":200,"providerResponseId":"X5CAaaH-Ipyy2fMP5ezVKA"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.0000652","marketCost":"0.0000652","generationId":"gen_01KGF37X8BY3AB4X8CN72NQHAV","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":2,"total_tokens":11,"cost":0.0000652,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":23,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0000652},"system_fingerprint":"fp_oj9j2v6wic","generationId":"gen_01KGF37X8BY3AB4X8CN72NQHAV"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 605.216666ms
diff --git a/providertests/testdata/TestVercelCommon/gemini-2.5-flash/simple_streaming.yaml b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/simple_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..70274c47b015261547a2fd3c0988df0f448876b4
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/simple_streaming.yaml
@@ -0,0 +1,40 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 227
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"stream_options":{"include_usage":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF37XVPQFTEF88B3MN5VGHK","object":"chat.completion.chunk","created":1770033248,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_1hjld5wcik"}
+
+ data: {"id":"gen_01KGF37XVPQFTEF88B3MN5VGHK","object":"chat.completion.chunk","created":1770033248,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"content":"Olá!"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_1hjld5wcik"}
+
+ data: {"id":"gen_01KGF37XVPQFTEF88B3MN5VGHK","object":"chat.completion.chunk","created":1770033248,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":25,"promptTokenCount":9,"candidatesTokenCount":2,"totalTokenCount":36,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":7617027.32849,"endTime":7617674.256609,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":7617027.32849,"endTime":7617674.256609,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.0000702","marketCost":"0.0000702","generationId":"gen_01KGF37XVPQFTEF88B3MN5VGHK","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":2,"total_tokens":11,"cost":0.0000702,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":25,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0000702},"system_fingerprint":"fp_1hjld5wcik","generationId":"gen_01KGF37XVPQFTEF88B3MN5VGHK"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 875.25225ms
diff --git a/providertests/testdata/TestVercelCommon/gemini-2.5-flash/tool.yaml b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0c738571b4444c507aed3d049733fe833eaadb73
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 465
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37YQYT0615AXEWGQMX7A4","object":"chat.completion","created":1770033249,"model":"google/gemini-2.5-flash","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"2UEinTAmGM13bjwN","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence,Italy\"}"}}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":57,"promptTokenCount":28,"candidatesTokenCount":5,"totalTokenCount":90,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":1355937.787241,"endTime":1356631.240553,"statusCode":200,"providerResponseId":"YZCAafTaCP-xhcIP6Zz3mAQ"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.0001634","marketCost":"0.0001634","generationId":"gen_01KGF37YQYT0615AXEWGQMX7A4","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":28,"completion_tokens":5,"total_tokens":33,"cost":0.0001634,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":57,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0001634},"system_fingerprint":"fp_q7zc9ylbsc","generationId":"gen_01KGF37YQYT0615AXEWGQMX7A4"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 851.617709ms
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 690
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"2UEinTAmGM13bjwN","function":{"arguments":"{\"location\":\"Florence,Italy\"}","name":"weather"},"type":"function"}],"role":"assistant"},{"content":"40 C","tool_call_id":"2UEinTAmGM13bjwN","role":"tool"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF37ZH945B4T7Q2YDF1YW7K","object":"chat.completion","created":1770033250,"model":"google/gemini-2.5-flash","choices":[{"index":0,"message":{"role":"assistant","content":"The weather in Florence, Italy is 40 C.","provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":40,"candidatesTokenCount":12,"totalTokenCount":52,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":347802.523594,"endTime":348287.615775,"statusCode":200,"providerResponseId":"YZCAaYSqO9X8tfAPg7j5QA"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.000042","marketCost":"0.000042","generationId":"gen_01KGF37ZH945B4T7Q2YDF1YW7K","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":40,"completion_tokens":12,"total_tokens":52,"cost":0.000042,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000042},"system_fingerprint":"fp_oqc02i8x0x","generationId":"gen_01KGF37ZH945B4T7Q2YDF1YW7K"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 587.012542ms
diff --git a/providertests/testdata/TestVercelCommon/gemini-2.5-flash/tool_streaming.yaml b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d5d4aca623dde1d7666af829ecfc2e167b41bfa2
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-2.5-flash/tool_streaming.yaml
@@ -0,0 +1,81 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 519
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3803YBNDA2M8B7319DJ82","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_7in70gabwf"}
+
+ data: {"id":"gen_01KGF3803YBNDA2M8B7319DJ82","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"g8BRNPzm2XAHjElR","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_7in70gabwf"}
+
+ data: {"id":"gen_01KGF3803YBNDA2M8B7319DJ82","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"location\":\"Florence,Italy\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_7in70gabwf"}
+
+ data: {"id":"gen_01KGF3803YBNDA2M8B7319DJ82","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":51,"promptTokenCount":28,"candidatesTokenCount":5,"totalTokenCount":84,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":430027.607924,"endTime":430701.108841,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":430027.607924,"endTime":430701.108841,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.0001484","marketCost":"0.0001484","generationId":"gen_01KGF3803YBNDA2M8B7319DJ82","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":28,"completion_tokens":5,"total_tokens":33,"cost":0.0001484,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":51,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0001484},"system_fingerprint":"fp_7in70gabwf","generationId":"gen_01KGF3803YBNDA2M8B7319DJ82"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 758.2815ms
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 744
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"g8BRNPzm2XAHjElR","function":{"arguments":"{\"location\":\"Florence,Italy\"}","name":"weather"},"type":"function"}],"role":"assistant"},{"content":"40 C","tool_call_id":"g8BRNPzm2XAHjElR","role":"tool"}],"model":"google/gemini-2.5-flash","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF380V9QM93HK4DBFD3050C","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_edgl953q80"}
+
+ data: {"id":"gen_01KGF380V9QM93HK4DBFD3050C","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_edgl953q80"}
+
+ data: {"id":"gen_01KGF380V9QM93HK4DBFD3050C","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"content":" weather in Florence, Italy is 40 C."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_edgl953q80"}
+
+ data: {"id":"gen_01KGF380V9QM93HK4DBFD3050C","object":"chat.completion.chunk","created":1770033251,"model":"google/gemini-2.5-flash","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":40,"candidatesTokenCount":12,"totalTokenCount":52,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-2.5-flash","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-2.5-flash","internalResolvedModelId":"vertex:gemini-2.5-flash","fallbacksAvailable":["google","deepinfra"],"internalReasoning":"Selected vertex as preferred provider for gemini-2.5-flash. 2 fallback(s) available: google, deepinfra","planningReasoning":"System credentials planned for: vertex, google, deepinfra. Total execution order: vertex(system) → google(system) → deepinfra(system)","canonicalSlug":"google/gemini-2.5-flash","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":4541137.912067,"endTime":4541464.788969,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-2.5-flash","canonicalSlug":"google/gemini-2.5-flash","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-2.5-flash","providerApiModelId":"gemini-2.5-flash","credentialType":"system","success":true,"startTime":4541137.912067,"endTime":4541464.788969,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000042","marketCost":"0.000042","generationId":"gen_01KGF380V9QM93HK4DBFD3050C","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":40,"completion_tokens":12,"total_tokens":52,"cost":0.000042,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000042},"system_fingerprint":"fp_edgl953q80","generationId":"gen_01KGF380V9QM93HK4DBFD3050C"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 425.562958ms
diff --git a/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/multi_tool.yaml b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/multi_tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0e3d6bb09244641ea72a2f200b92a312c848a2fb
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/multi_tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 832
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF39J2GMGMAPH0F955QXJN5","object":"chat.completion","created":1770033304,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"yr8vjBiBxciYk81p","type":"function","function":{"name":"add","arguments":"{\"b\":3,\"a\":2}"}},{"id":"AmDRMtn5jFH1FM4J","type":"function","function":{"name":"multiply","arguments":"{\"b\":3,\"a\":2}"}}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":119,"promptTokenCount":61,"candidatesTokenCount":18,"totalTokenCount":198,"trafficType":"PROVISIONED_THROUGHPUT"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7050722.565232,"endTime":7053930.218976,"statusCode":200,"providerResponseId":"lZCAaejDKf6BmLAPjqmi-Qo"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.001766","marketCost":"0.001766","generationId":"gen_01KGF39J2GMGMAPH0F955QXJN5","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":61,"completion_tokens":18,"total_tokens":79,"cost":0.001766,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":119,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.001766},"system_fingerprint":"fp_sbwyjrbwm9","generationId":"gen_01KGF39J2GMGMAPH0F955QXJN5"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 3.301019917s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1205
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"yr8vjBiBxciYk81p","function":{"arguments":"{\"b\":3,\"a\":2}","name":"add"},"type":"function"},{"id":"AmDRMtn5jFH1FM4J","function":{"arguments":"{\"b\":3,\"a\":2}","name":"multiply"},"type":"function"}],"role":"assistant"},{"content":"5","tool_call_id":"yr8vjBiBxciYk81p","role":"tool"},{"content":"6","tool_call_id":"AmDRMtn5jFH1FM4J","role":"tool"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF39N3ZQQNAHVCNDKGKFDXH","object":"chat.completion","created":1770033309,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":"The sum of 2 and 3 is 5, and the product of 2 and 3 is 6.","reasoning_details":[{"type":"reasoning.encrypted","data":"EowECokEAXLI2nxcmOHKFmCie8wZQj4/lvp5r14Pp4tqdLOscZ0XBOKdSP60HUPURffivhxpaKDjwvyYIf43reXC7PyAzrNjw/g82cNAjfDK7wpy9ytBDKW8Jmn0KghvDqliK1EHUa5r5phWGwyclW3coT/6X1mtcQd89uAjf3qg3HyAvSNRrpjY+5E8i1CWh9Klnz+4AJ6cAHyahhkqS6Kc/0fZWFwggkOYPetH/bLrdipfcjBOIyRsWg8YeR9iRiv2cBbHruJeops0JKxCVhr750bJiYYehM3eOgvfD6rXA9TJnv6+sjoGXK/kWkrFW84i7lJvbDZaonJwVbDe3B1qpm+cmiGRHDHBQDam9dfLnRoeuk8lvEHtJctSIGRKSG+qavsxhHsr+IyWolld74TkIc7/dFHqJvCUkp8UtIg7KFMIHsQmi0FGn2IpUK/pW47Q8wT9eUdbxr8FFkmcsTMziI1QexEK1bosMZYDYc6AnQ3HXQzGuCq/Alx8jaku4xeyl1xplmMCKPui0AvK05/uKD08xSmWouSi3iMsIxj/1QRvrejj22oT7DiHZuL/DKp8tnCR2f3M/U8OmxMr665dpyWMfrBLAFL0KL7AQGoRqpxoLEbTmISk5wDaxYdXqnLhgPw9qF4TCRYnUQNfSbzIfKmCk/ekKwX0NBROCJu5yhVEBsMEevDTC/sg8q0=","format":"google-gemini-v1","index":0}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":119,"promptTokenCount":223,"candidatesTokenCount":25,"totalTokenCount":367}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"google","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":false,"error":"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn.","startTime":7674067.523962,"endTime":7674739.16189,"statusCode":400},{"provider":"google","internalModelId":"google:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7674863.56271,"endTime":7678582.662173,"statusCode":200,"providerResponseId":"nZCAaaflFeKF7M8Pis3b4AE"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002174","marketCost":"0.002174","generationId":"gen_01KGF39N3ZQQNAHVCNDKGKFDXH","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":223,"completion_tokens":25,"total_tokens":248,"cost":0.002174,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":119,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002174},"system_fingerprint":"fp_q0jgoj8amw","generationId":"gen_01KGF39N3ZQQNAHVCNDKGKFDXH"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 4.618416166s
diff --git a/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/multi_tool_streaming.yaml b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/multi_tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..20871ca79f06f0cdeba0284c17a943d420bc7c71
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/multi_tool_streaming.yaml
@@ -0,0 +1,85 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 869
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF39SRSQ5CWVF17GR4P29CK","object":"chat.completion.chunk","created":1770033312,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_4r8izhsq38"}
+
+ data: {"id":"gen_01KGF39SRSQ5CWVF17GR4P29CK","object":"chat.completion.chunk","created":1770033312,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"Oxu2MENhE0ZsrlGm","type":"function","function":{"name":"add","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_4r8izhsq38"}
+
+ data: {"id":"gen_01KGF39SRSQ5CWVF17GR4P29CK","object":"chat.completion.chunk","created":1770033312,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"b\":3,\"a\":2}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_4r8izhsq38"}
+
+ data: {"id":"gen_01KGF39SRSQ5CWVF17GR4P29CK","object":"chat.completion.chunk","created":1770033312,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"jHpVWOzg44py3a4h","type":"function","function":{"name":"multiply","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_4r8izhsq38"}
+
+ data: {"id":"gen_01KGF39SRSQ5CWVF17GR4P29CK","object":"chat.completion.chunk","created":1770033312,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"b\":3,\"a\":2}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_4r8izhsq38"}
+
+ data: {"id":"gen_01KGF39SRSQ5CWVF17GR4P29CK","object":"chat.completion.chunk","created":1770033312,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":76,"promptTokenCount":57,"candidatesTokenCount":18,"totalTokenCount":151,"trafficType":"PROVISIONED_THROUGHPUT"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7678877.96491,"endTime":7682011.782537,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7678877.96491,"endTime":7682011.782537,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.001242","marketCost":"0.001242","generationId":"gen_01KGF39SRSQ5CWVF17GR4P29CK","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":57,"completion_tokens":18,"total_tokens":75,"cost":0.001242,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":76,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.001242},"system_fingerprint":"fp_4r8izhsq38","generationId":"gen_01KGF39SRSQ5CWVF17GR4P29CK"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 3.240620375s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1242
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"Oxu2MENhE0ZsrlGm","function":{"arguments":"{\"b\":3,\"a\":2}","name":"add"},"type":"function"},{"id":"jHpVWOzg44py3a4h","function":{"arguments":"{\"b\":3,\"a\":2}","name":"multiply"},"type":"function"}],"role":"assistant"},{"content":"5","tool_call_id":"Oxu2MENhE0ZsrlGm","role":"tool"},{"content":"6","tool_call_id":"jHpVWOzg44py3a4h","role":"tool"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF39X286MHE27SNFKH25NC4","object":"chat.completion.chunk","created":1770033316,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_77ne7mn4wm"}
+
+ data: {"id":"gen_01KGF39X286MHE27SNFKH25NC4","object":"chat.completion.chunk","created":1770033316,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":"The sum of 2 and 3 is"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_77ne7mn4wm"}
+
+ data: {"id":"gen_01KGF39X286MHE27SNFKH25NC4","object":"chat.completion.chunk","created":1770033316,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":" 5, and the product of 2 and 3 is 6."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_77ne7mn4wm"}
+
+ data: {"id":"gen_01KGF39X286MHE27SNFKH25NC4","object":"chat.completion.chunk","created":1770033316,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":107,"promptTokenCount":219,"candidatesTokenCount":25,"totalTokenCount":351}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"google","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":false,"error":"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn.","startTime":7682389.843352,"endTime":7682560.855095,"statusCode":400},{"provider":"google","internalModelId":"google:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7682658.945631,"endTime":7685688.640771,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":2,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":false,"error":"Please ensure that the number of function response parts is equal to the number of function call parts of the function call turn.","startTime":7682389.843352,"endTime":7682560.855095,"statusCode":400},{"provider":"google","internalModelId":"google:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7682658.945631,"endTime":7685688.640771,"statusCode":200}]}],"totalProviderAttemptCount":2},"cost":"0.002022","marketCost":"0.002022","generationId":"gen_01KGF39X286MHE27SNFKH25NC4","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":219,"completion_tokens":25,"total_tokens":244,"cost":0.002022,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":107,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002022},"system_fingerprint":"fp_77ne7mn4wm","generationId":"gen_01KGF39X286MHE27SNFKH25NC4"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 3.595823375s
diff --git a/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/simple.yaml b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..821feca092f740dc6112183046c15f4708c3dde0
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/simple.yaml
@@ -0,0 +1,33 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 177
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"google/gemini-3-pro-preview","max_tokens":4000}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF38WR2DQ7XVWAQPMSQN05J","object":"chat.completion","created":1770033284,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":"The most common way to say \"hi\" in Portuguese is:\n\n**Oi**\n\nYou can also say **Olá** (which is closer to \"hello\").","reasoning_details":[{"type":"reasoning.encrypted","data":"CtcGAY89a1/Vs+RSuBVpzJ1TJvRE/FtqFQVib99RvrHh+gb2EIdzDDZ/SY3ZVeQvQRZIOtEXdxlbjsymY95+YrKyX3B3sDmt7Y0hdpvDVQSQo7BymSD0/qtaPPexP57xCSzdyLZo08AKW5LCUmrBI15/XipH592d0XzRuidBu+EeAlTHMv3bwpwJaJ8DB4RoHhLpG8ueW73DsRnioUPYyQKnUK/8uov5qicTsNIiT67adu/wUBytqrDgRGmtiqw3MyQBaOG7xIEg8VUy8gTAVBKc3HFUh0m8d9+GbHshh2RgKyhA47cBxgef9hHH9fcM71mDXqgNJrZhv7vxgt4GOmVIF7e9iIx4lnYxi46WRlAchSO/rym7grFHNBAZ3D/uQoIp1VyoCyySIcLRVhLyNrU4c3IHWdOs6JuE+xbZiB3Flyccvg4oqiiaN4SOJXlP5+iAo9ASQmwHVy5e4j+/7Uo5G4D+pfxAdYwTT7cbGxLwHDZC13kcFfoi7YHawIghOLdcbQ4Y1wjkHbkP3vgp6zcTsQRw8PGZ8mPaHgMeZ3BGQn+q3jheqs3vcY0zazH9j2b1Yp4R2rcqyHqTpj1pV9BScW1g9dYuTRDjkzJbQxERZ2OrDTomVD6wPV76lldVGVeOOIRY/sNwl/VyXfyp4uJvqHTd6lz1A7JvUQDblT9GMvKmZKXlXW3uCqFroJpUGZVyFBxoNg4vo2vNZdpkCKikbX+irD58WxT8//oU9utaT5TmU7iVcGez3xeED8Pcfe8b4cDBnIBdNPDYJOjLXh5PFFJHJ7ad6Qzb+4FLdXnWl132D+uhuC3nQf7fPsrr8gf4yNzefuX8OjPgCGvobT56LusnH26ef8Vq7yYppYm8oz+JEVqXz2yydWWMwfJoCBESk96rNtdQ1fThaLrwGiz30NvOFZhBQ64f9MmTzt5/Ch97xfNBQNj4nCOzwOgsijXxOV0WG0W9zOjLVaL2StHURwyRNrCjDThoenOcOzRQiHIO+Y3ugEyp2k1dLIU93pILCZKmGmErUXVJxNOdPD/JNkfUDkioIvUDX9+To+cfmsx32Ynrm6auYsZzHI6ntFbu2Yw2S7iozfOVBER1ohInrt3djXS3gZn7NlaTlg71BQ3Lhr23As0Y","format":"google-gemini-v1","index":0}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":221,"promptTokenCount":9,"candidatesTokenCount":33,"totalTokenCount":263,"trafficType":"PROVISIONED_THROUGHPUT"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7028889.551463,"endTime":7033870.641762,"statusCode":200,"providerResponseId":"f5CAaZznMrj2mLAP-aa82AU"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.003066","marketCost":"0.003066","generationId":"gen_01KGF38WR2DQ7XVWAQPMSQN05J","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":33,"total_tokens":42,"cost":0.003066,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":221,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003066},"system_fingerprint":"fp_kece7x1dv2","generationId":"gen_01KGF38WR2DQ7XVWAQPMSQN05J"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 5.077063708s
diff --git a/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/simple_streaming.yaml b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/simple_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a775f281b5752a2448a09ec9aaa243c49a395e1a
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/simple_streaming.yaml
@@ -0,0 +1,42 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 231
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"stream_options":{"include_usage":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF391Q1MADSMMMS7RN0MPJX","object":"chat.completion.chunk","created":1770033289,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_s005gr6r3v"}
+
+ data: {"id":"gen_01KGF391Q1MADSMMMS7RN0MPJX","object":"chat.completion.chunk","created":1770033289,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":"The most common way to say \"hi\" in Portuguese is **\"Oi\"**.\n\nYou can also say **\"Olá\"** (which is more like \"hello\")."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_s005gr6r3v"}
+
+ data: {"id":"gen_01KGF391Q1MADSMMMS7RN0MPJX","object":"chat.completion.chunk","created":1770033289,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"reasoning_details":[{"type":"reasoning.encrypted","data":"CikBjz1rX1dPuLSzjatsf+kEp2Ri1nfHbqwWCwH07OuC1ZuewqSVGPoPzgpfAY89a18bv4mLFvt3bZAdiEoaZ+mjKsSaNKkndIQFXlBX/7hCWWnr1+bAbThHMnH0oIh/4vTXgk8DVKR87b2jqz0KuQG/kFftlB+5jAH9Jiq5/n2JIbFm06nvcF0dlyoKZgGPPWtfUh80MPPeLg0AMzKvrsGiCeKISEhrD6sg11jcaV4dgc/eBV9iwvHXn1LQU3GtPAsNZ4H1ZJM2+49hgdR6sN4vu81IqEdPsBItnGmr4TBm4Gm90LBPvCkcoSb3bh3q41kuaAqSAQGPPWtfYRILvpzZWl2d/sialYcYOf3UGDEFKBuz8HHUo40bCo+HQuJTal05BxWjIEzS4+wNKYrEsmo65fYSq/W1VBPGJVWbySFHDILvcVbMLJriGdWQbpAtXRAi/EoxQYjctaLyV1H77smAtachR9b7fKBfAlccpyd6QqLRi55uBIIczarwv97rFs+ylW/T/2m8CpQBAY89a198U9DZKPUsXuUCZvugyKq7U4JFHcDNk8+2W9F22IOz/lRPP4mRMj2DnaeMEZvj8NlAgN+uPpIS7pBPMWCiTsNUdTp0ZXfGZid8B/M6DFVv/DiS62f+C9LyW93Y+YLltHz0HsYgqFAhNW/TbxLFwshqad8KSAwEUJspHG5VheRkyflEReRxpNFm9MX7FTIsAQrhAQGPPWtf1NKdz86iQg+9J+FwwgJmOemZh5b7nk1s4iVyI4+SRdy5n6lGIwM/RS4brolzexTvzZU4yJHDd3kPm4eEOrATOu7g6wW4Vsdw6+LA6RkX/+TTPZbt7JmWYVbws5YUJGdKD3ddEG9faoV+kxGun8mJDEOdCKVZUDRQtU07nKEa/R9/8xkJaNBv8GBs4TuOHB56wH9rIp4I1qvaW9DU6TlcxKhw8BdtpYbD6Gg3e6asqePEUEIAXeQ5eQUfgC5lDSXRD99j4j42y3tNiKNXY+h2TZc3SIc40ohsM5XzTwqzAQGPPWtfzWc0ZYfA/k2tbqLr/45Vpgn/1yfSC1kXi+ABfbLhzZR4oNnbBlBHcmEbBF3DokgxaI7WEbopj4zbm0ZsYNJVLxD0cGd/kV+CBKbCf4j7L1fCJKlI8Mnorq5Bgp8i28XWjCydjvRAoTT49cJp0LKnKHw2Hr95yMnKPIwlOiAtQ0IFOjNXbfWQSCp42fSXDofsoufZor01El8xVfsaIQTkJtCbyE/AjOwz25v4xsp/CnkBjz1rXw6jbdgKOjllJsnqicBq0+EJ8nM5HbD25Dj1klrIvslkr8/5YyV6Fk43IYUfpLJW63qj9/4/cuRTDWBmbwOYMbf0JJCC0vGZvlz0UbLH3gEFfElZ7D8KAjc6iQ71etnHkYAHfUHlMdJ/B7qJLvQGpN8w4H/A","format":"google-gemini-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_s005gr6r3v"}
+
+ data: {"id":"gen_01KGF391Q1MADSMMMS7RN0MPJX","object":"chat.completion.chunk","created":1770033289,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":223,"promptTokenCount":9,"candidatesTokenCount":35,"totalTokenCount":267,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":1391831.603433,"endTime":1396730.275173,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":1391831.603433,"endTime":1396730.275173,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.003114","marketCost":"0.003114","generationId":"gen_01KGF391Q1MADSMMMS7RN0MPJX","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":9,"completion_tokens":35,"total_tokens":44,"cost":0.003114,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":223,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003114},"system_fingerprint":"fp_s005gr6r3v","generationId":"gen_01KGF391Q1MADSMMMS7RN0MPJX"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 5.130387417s
diff --git a/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/tool.yaml b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0b8ff03b8a0033f4253e8c7af414b65472164781
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 469
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF396RM9XH4DT3BKG6XYYC0","object":"chat.completion","created":1770033293,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"ixKHls2RfUCWLY8v","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence, Italy\"}"}}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":78,"promptTokenCount":28,"candidatesTokenCount":9,"totalTokenCount":115,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7659506.082926,"endTime":7662838.172979,"statusCode":200,"providerResponseId":"ipCAaZa6CeXDtfAPz8i1yAs"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.0011","marketCost":"0.0011","generationId":"gen_01KGF396RM9XH4DT3BKG6XYYC0","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":28,"completion_tokens":9,"total_tokens":37,"cost":0.0011,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":78,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0011},"system_fingerprint":"fp_oka8v3chzr","generationId":"gen_01KGF396RM9XH4DT3BKG6XYYC0"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 3.581068834s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 695
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"ixKHls2RfUCWLY8v","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant"},{"content":"40 C","tool_call_id":"ixKHls2RfUCWLY8v","role":"tool"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF39A6QVKDAEJE16471HJ6N","object":"chat.completion","created":1770033295,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":"The weather in Florence, Italy is currently 40°C.","provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":40,"candidatesTokenCount":14,"totalTokenCount":54,"trafficType":"PROVISIONED_THROUGHPUT"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":1411069.913659,"endTime":1413447.981679,"statusCode":200,"providerResponseId":"jZCAaczqJ6HZmLAP9c_xgAs"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.000248","marketCost":"0.000248","generationId":"gen_01KGF39A6QVKDAEJE16471HJ6N","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":40,"completion_tokens":14,"total_tokens":54,"cost":0.000248,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000248},"system_fingerprint":"fp_qhfqfihebr","generationId":"gen_01KGF39A6QVKDAEJE16471HJ6N"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.530493166s
diff --git a/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/tool_streaming.yaml b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a8ce080bf5d25b3dfec10aee4f155a34aeba9684
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gemini-3-pro-preview/tool_streaming.yaml
@@ -0,0 +1,81 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 523
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF39CMWTBAYWG62BTDA8EX5","object":"chat.completion.chunk","created":1770033298,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_n9t24sd6so"}
+
+ data: {"id":"gen_01KGF39CMWTBAYWG62BTDA8EX5","object":"chat.completion.chunk","created":1770033298,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"mbK8hEFBfrxbyEg3","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_n9t24sd6so"}
+
+ data: {"id":"gen_01KGF39CMWTBAYWG62BTDA8EX5","object":"chat.completion.chunk","created":1770033298,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"location\":\"Florence, Italy\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_n9t24sd6so"}
+
+ data: {"id":"gen_01KGF39CMWTBAYWG62BTDA8EX5","object":"chat.completion.chunk","created":1770033298,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":72,"promptTokenCount":28,"candidatesTokenCount":9,"totalTokenCount":109,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7665475.024571,"endTime":7668255.526409,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7665475.024571,"endTime":7668255.526409,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.001028","marketCost":"0.001028","generationId":"gen_01KGF39CMWTBAYWG62BTDA8EX5","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":28,"completion_tokens":9,"total_tokens":37,"cost":0.001028,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":72,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.001028},"system_fingerprint":"fp_n9t24sd6so","generationId":"gen_01KGF39CMWTBAYWG62BTDA8EX5"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 2.918596875s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 749
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"mbK8hEFBfrxbyEg3","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant"},{"content":"40 C","tool_call_id":"mbK8hEFBfrxbyEg3","role":"tool"}],"model":"google/gemini-3-pro-preview","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF39FC3KGNF4QFQ4V4694KD","object":"chat.completion.chunk","created":1770033301,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_et7g7hmqn5"}
+
+ data: {"id":"gen_01KGF39FC3KGNF4QFQ4V4694KD","object":"chat.completion.chunk","created":1770033301,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":"The current temperature in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_et7g7hmqn5"}
+
+ data: {"id":"gen_01KGF39FC3KGNF4QFQ4V4694KD","object":"chat.completion.chunk","created":1770033301,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":" Florence, Italy is 40°C."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_et7g7hmqn5"}
+
+ data: {"id":"gen_01KGF39FC3KGNF4QFQ4V4694KD","object":"chat.completion.chunk","created":1770033301,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":40,"candidatesTokenCount":14,"totalTokenCount":54,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7668162.82122,"endTime":7670529.245941,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7668162.82122,"endTime":7670529.245941,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000248","marketCost":"0.000248","generationId":"gen_01KGF39FC3KGNF4QFQ4V4694KD","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":40,"completion_tokens":14,"total_tokens":54,"cost":0.000248,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000248},"system_fingerprint":"fp_et7g7hmqn5","generationId":"gen_01KGF39FC3KGNF4QFQ4V4694KD"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 2.526340125s
diff --git a/providertests/testdata/TestVercelCommon/gpt-5/multi_tool.yaml b/providertests/testdata/TestVercelCommon/gpt-5/multi_tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..8d713a40d158a782b27e143dd4e182ae36095188
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gpt-5/multi_tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 828
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"openai/gpt-5","max_completion_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF38JKSTNNP061DTA2R1QR6","object":"chat.completion","created":1770033273,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJB5sMVU3E5XyBIYkGVYX_idbwIgEl6hyzl37P25LBkPxPxtSA-z_vG-ub3Ht2lLorQuxuYXJw5TvvQljT1wPC9GtS-3qVZwt_QhReZWbhESWHryCcV1WyEPUZj8oG3nUVCuV917iOoZgfkRgLG8X9Oi5ezb_M42WqRmF1XWXL302fu3bJRy_jT8mmoiLnCmS1wXX_78058GTTjjJLGqTBPni0y7sZDDHpFgUsgpoWv3gF9X9OClhk3JOfuqgNYIVTS90C6pQ-JUHWX-9q-v34qMHs-E_QnaCYQLShf4Fa04N_DY0SphPoP1UaJMp6A1spu8WjCNLr4KjkFsq3QirbYcp9pwZj_N_XmbDRSTE4DXcqLKUafsUjpQC9bNiEvZ2oh95CRmMwHznVetnUTXsmxPj3p7x8MRer9NM1LMetWxMLz28oAnDq6T1xHu1nhSdHVBG7DpVIDeXN6PYA6BLrCiVuB3K3_pooysaNVwv05EPDrCrvYotlHdbDPiU_OsF9uClsKkTguYjfCqihV48xgYqAQJqU_guhAe3NSacal5sjGMG8OBp_QrcTsRmCG-pUJ0_YkU3BKxN-h3FBBjBfnZrmJIHkV17oIvqyfd4mr_apHg_tNQJlyNr14usvYzzp65IK1jJ4UXepLHyBJfuBh6U1j9EQmRd2gS9gwwT_pvN0TVZaZZs32Pxakgq0wBNkRrto41JRHbpdYOuL_pWpcJ8fceSVv4rYxn7qewym_XxX1hFRz3on638qI70UUmPc64m3DzB60l0O83FLqHvlNEGOR6SSogOZc3M0oX9Zll-kgi02fb9deA6_HrhrGjYzAUDFQEuyFwML4u2mquXz7e1hmyKede1kBPnnZxhNODgFbRZrW_qZPf6D8fcLLR5KZHdhO4NjSGigxt3vbdBqRRPVJw5Ci9v2kXJLAczXB8Ifv5Vz9BUdQgAh_QWHmrirtcjU4Y84m1wCskcIpf_F5pduuGedRj6pnmEyYATiNxl0XCy6RmPGKjwgAz5qcQzOyHz013e4QzzB5Etmm6B01_oYpHXgmsi84z_LrSCtGSQI8S8l4RpESzGqaqQ84apbFvw4xJuA3fJPekyN6HkhK0cnD_NVxrUiEsmnhnLNSpUkwjzFGFWbasYYQj6Rik2WNOhoHpmPXzVgJsdrp94MrUGXWEgdUDcIWnH8LFizamKnBNox1e1i_phBxrQLLzqfgN2HABOE9WyDEIfpOgJOX2RfDn6q_RQ9WM79hDZJD7RUap1bC0dlxqomi0fYVqyOoW0RQyQ-_mrBK4nYFVwfDaZwrWXNzTsFvtlJzN8O8-L5J6UTx-AhSNcnI35O3AuxbNyRC72HhVzN-A0Ae4SouL25ouc582Oy8M1xzs9RjlkoSIHZYAe2wzfvD9B7N0F2tbahD-MOHCbLctCFRb_S4gO29xZgeGgdXxyykq5il4vya6f1GmTfCC9Ktg4dsdmmqbSAXV9Ck0iUhg4cZVSNliyxxUMjJfDLt8ZO0f_UxrD2RCoZL7zwRgCAldl4ndkmotvTH_0HSRxmob1Q6AwgItkWU7GcGdk_7PLUho5332sVdKbQcpLVZQNyKOVtreej8EkH47b8wEvVJ6lz2lKNKEz9tyHRUlEPBjW3yb3YvO3wyfRkkqMMXFO_PEuhQ66ceSOHJJW2zmJuZepwBMUiez3sZph3o1zjvB7tHAY7YCaTjbh8urPaYjGUrLyVmvAkwEbQQwE1-vpyhoztrqOinvOm6fUyU0HsQuQIEqCUtFqO8G755g3I_cFrgfjmgRXMMvhKk4iQ61rOL2YAPNozSdCGNtplTJIhnb2xZC-gbtK8YwcbWz7B1k2bICxfgAhX7W9cOsnGnJwB-wS_vAkmjSZrHmrkAAAEjPLaemIGxhPzZ9sU6R2TLKHL6wOA0LthE5ltRY5PGnsCK7NFcsHDcyFWCGLH10UYfV1n5_uOvUMqsHlT8iHMA2y-W0DtdzDNeEUOZj5mDAwfdTAIoXJc5-wieyLp27uLJqmJ0ZvchRT2CcM0SC_mDNaYXlJyn5uavmUkp4Ykh2LGN54lFFzbcOsVcVLzpdQJ0u2QF4QXIbzHMnw8ipejfMaN2zkXRGsex9BXcf9fIOxwPH8LTsLRArUz--pl8wq8x2_ZyRNC5ZPtZrWr3lTokTqXrb8gASoIchRTZDV8fQdPIPXIJE4A-Dn-8Hfrxnf63IKRoFv4ENTzOoycoNH4kyCh4LQSInGFeE5vAa3Iq_ctdHf6LlVnoURnZdrmC_c03UMJjv671ZYbzuS76jKRTAJF7PnJhDdAhV-xvZmRKzJpJ4k_ZmN9O19iXZVVv4ofjn3m0iOWY8N61suLBb9wErE0PJxzNQnLBFSXuC3qrd9IrVzEMUOsMloPH6bB-zGlRQP_gY3LzZ4tEF70ZuqIdwAYgjKGc9LqXfz0d5hXLLPE0MeJxiCJFuHyUCgPphf8gfCw6lw0gz7KiH87aXBbOTwcUl2bT6pDDmKSkZQPUv67c0JoB0j5IsH67XBFhYZHiyenTddXJHSKHXnLlhdZCifIDaYXElPZLdWT5SZ3Y_i1AAaLOk-h2esjagpMOWRZMzY97KHDINIMiUcW_aE5IrsGWkP8jnHu-rDHXU2L9VOzErnTMz8b-DXg==","id":"rs_09ce24a3ef4ef4c30169809075d9c881909a0602f2f9b94079","format":"openai-responses-v1","index":0}],"tool_calls":[{"id":"call_hw6yjnBO12c7jlYo4Ug0REvD","type":"function","function":{"name":"add","arguments":"{\"a\":2,\"b\":3}"}},{"id":"call_1DofUzAYzaNZecbxfrt2sRSv","type":"function","function":{"name":"multiply","arguments":"{\"a\":2,\"b\":3}"}}],"provider_metadata":{"openai":{"responseId":"resp_09ce24a3ef4ef4c30169809075837481908f0f2e352bb0536c","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1376272.617242,"endTime":1380180.418282,"statusCode":200,"providerResponseId":"resp_09ce24a3ef4ef4c30169809075837481908f0f2e352bb0536c"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.00609","marketCost":"0.00609","generationId":"gen_01KGF38JKSTNNP061DTA2R1QR6","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":56,"completion_tokens":346,"total_tokens":402,"cost":0.00609,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":256,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00609},"system_fingerprint":"fp_z6pyhzzwli","generationId":"gen_01KGF38JKSTNNP061DTA2R1QR6"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 3.998469542s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 4078
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"call_hw6yjnBO12c7jlYo4Ug0REvD","function":{"arguments":"{\"a\":2,\"b\":3}","name":"add"},"type":"function"},{"id":"call_1DofUzAYzaNZecbxfrt2sRSv","function":{"arguments":"{\"a\":2,\"b\":3}","name":"multiply"},"type":"function"}],"role":"assistant","reasoning_details":[{"data":"gAAAAABpgJB5sMVU3E5XyBIYkGVYX_idbwIgEl6hyzl37P25LBkPxPxtSA-z_vG-ub3Ht2lLorQuxuYXJw5TvvQljT1wPC9GtS-3qVZwt_QhReZWbhESWHryCcV1WyEPUZj8oG3nUVCuV917iOoZgfkRgLG8X9Oi5ezb_M42WqRmF1XWXL302fu3bJRy_jT8mmoiLnCmS1wXX_78058GTTjjJLGqTBPni0y7sZDDHpFgUsgpoWv3gF9X9OClhk3JOfuqgNYIVTS90C6pQ-JUHWX-9q-v34qMHs-E_QnaCYQLShf4Fa04N_DY0SphPoP1UaJMp6A1spu8WjCNLr4KjkFsq3QirbYcp9pwZj_N_XmbDRSTE4DXcqLKUafsUjpQC9bNiEvZ2oh95CRmMwHznVetnUTXsmxPj3p7x8MRer9NM1LMetWxMLz28oAnDq6T1xHu1nhSdHVBG7DpVIDeXN6PYA6BLrCiVuB3K3_pooysaNVwv05EPDrCrvYotlHdbDPiU_OsF9uClsKkTguYjfCqihV48xgYqAQJqU_guhAe3NSacal5sjGMG8OBp_QrcTsRmCG-pUJ0_YkU3BKxN-h3FBBjBfnZrmJIHkV17oIvqyfd4mr_apHg_tNQJlyNr14usvYzzp65IK1jJ4UXepLHyBJfuBh6U1j9EQmRd2gS9gwwT_pvN0TVZaZZs32Pxakgq0wBNkRrto41JRHbpdYOuL_pWpcJ8fceSVv4rYxn7qewym_XxX1hFRz3on638qI70UUmPc64m3DzB60l0O83FLqHvlNEGOR6SSogOZc3M0oX9Zll-kgi02fb9deA6_HrhrGjYzAUDFQEuyFwML4u2mquXz7e1hmyKede1kBPnnZxhNODgFbRZrW_qZPf6D8fcLLR5KZHdhO4NjSGigxt3vbdBqRRPVJw5Ci9v2kXJLAczXB8Ifv5Vz9BUdQgAh_QWHmrirtcjU4Y84m1wCskcIpf_F5pduuGedRj6pnmEyYATiNxl0XCy6RmPGKjwgAz5qcQzOyHz013e4QzzB5Etmm6B01_oYpHXgmsi84z_LrSCtGSQI8S8l4RpESzGqaqQ84apbFvw4xJuA3fJPekyN6HkhK0cnD_NVxrUiEsmnhnLNSpUkwjzFGFWbasYYQj6Rik2WNOhoHpmPXzVgJsdrp94MrUGXWEgdUDcIWnH8LFizamKnBNox1e1i_phBxrQLLzqfgN2HABOE9WyDEIfpOgJOX2RfDn6q_RQ9WM79hDZJD7RUap1bC0dlxqomi0fYVqyOoW0RQyQ-_mrBK4nYFVwfDaZwrWXNzTsFvtlJzN8O8-L5J6UTx-AhSNcnI35O3AuxbNyRC72HhVzN-A0Ae4SouL25ouc582Oy8M1xzs9RjlkoSIHZYAe2wzfvD9B7N0F2tbahD-MOHCbLctCFRb_S4gO29xZgeGgdXxyykq5il4vya6f1GmTfCC9Ktg4dsdmmqbSAXV9Ck0iUhg4cZVSNliyxxUMjJfDLt8ZO0f_UxrD2RCoZL7zwRgCAldl4ndkmotvTH_0HSRxmob1Q6AwgItkWU7GcGdk_7PLUho5332sVdKbQcpLVZQNyKOVtreej8EkH47b8wEvVJ6lz2lKNKEz9tyHRUlEPBjW3yb3YvO3wyfRkkqMMXFO_PEuhQ66ceSOHJJW2zmJuZepwBMUiez3sZph3o1zjvB7tHAY7YCaTjbh8urPaYjGUrLyVmvAkwEbQQwE1-vpyhoztrqOinvOm6fUyU0HsQuQIEqCUtFqO8G755g3I_cFrgfjmgRXMMvhKk4iQ61rOL2YAPNozSdCGNtplTJIhnb2xZC-gbtK8YwcbWz7B1k2bICxfgAhX7W9cOsnGnJwB-wS_vAkmjSZrHmrkAAAEjPLaemIGxhPzZ9sU6R2TLKHL6wOA0LthE5ltRY5PGnsCK7NFcsHDcyFWCGLH10UYfV1n5_uOvUMqsHlT8iHMA2y-W0DtdzDNeEUOZj5mDAwfdTAIoXJc5-wieyLp27uLJqmJ0ZvchRT2CcM0SC_mDNaYXlJyn5uavmUkp4Ykh2LGN54lFFzbcOsVcVLzpdQJ0u2QF4QXIbzHMnw8ipejfMaN2zkXRGsex9BXcf9fIOxwPH8LTsLRArUz--pl8wq8x2_ZyRNC5ZPtZrWr3lTokTqXrb8gASoIchRTZDV8fQdPIPXIJE4A-Dn-8Hfrxnf63IKRoFv4ENTzOoycoNH4kyCh4LQSInGFeE5vAa3Iq_ctdHf6LlVnoURnZdrmC_c03UMJjv671ZYbzuS76jKRTAJF7PnJhDdAhV-xvZmRKzJpJ4k_ZmN9O19iXZVVv4ofjn3m0iOWY8N61suLBb9wErE0PJxzNQnLBFSXuC3qrd9IrVzEMUOsMloPH6bB-zGlRQP_gY3LzZ4tEF70ZuqIdwAYgjKGc9LqXfz0d5hXLLPE0MeJxiCJFuHyUCgPphf8gfCw6lw0gz7KiH87aXBbOTwcUl2bT6pDDmKSkZQPUv67c0JoB0j5IsH67XBFhYZHiyenTddXJHSKHXnLlhdZCifIDaYXElPZLdWT5SZ3Y_i1AAaLOk-h2esjagpMOWRZMzY97KHDINIMiUcW_aE5IrsGWkP8jnHu-rDHXU2L9VOzErnTMz8b-DXg==","format":"openai-responses-v1","id":"rs_09ce24a3ef4ef4c30169809075d9c881909a0602f2f9b94079","index":0,"type":"reasoning.encrypted"}]},{"content":"5","tool_call_id":"call_hw6yjnBO12c7jlYo4Ug0REvD","role":"tool"},{"content":"6","tool_call_id":"call_1DofUzAYzaNZecbxfrt2sRSv","role":"tool"}],"model":"openai/gpt-5","max_completion_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF38PH89YBGB4JEVM3QY13Q","object":"chat.completion","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":"Sum: 5\nProduct: 6","provider_metadata":{"openai":{"responseId":"resp_09ce24a3ef4ef4c3016980907989e48190add2b3ea521eefd8","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":262916.844804,"endTime":263772.252753,"statusCode":200,"providerResponseId":"resp_09ce24a3ef4ef4c3016980907989e48190add2b3ea521eefd8"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.00070875","marketCost":"0.00070875","generationId":"gen_01KGF38PH89YBGB4JEVM3QY13Q","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":463,"completion_tokens":13,"total_tokens":476,"cost":0.00070875,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00070875},"system_fingerprint":"fp_md8g0mkmrp","generationId":"gen_01KGF38PH89YBGB4JEVM3QY13Q"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 961.776042ms
diff --git a/providertests/testdata/TestVercelCommon/gpt-5/multi_tool_streaming.yaml b/providertests/testdata/TestVercelCommon/gpt-5/multi_tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f2251f0326ff81db7a266e8ef7dc338f3d2ebeca
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gpt-5/multi_tool_streaming.yaml
@@ -0,0 +1,101 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 865
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"}],"model":"openai/gpt-5","max_completion_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_lwams5xjm0"}
+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJB6xgaIX4YGTj3EZimfLMfl7lZ7SJq0aBMWfGDeorXxt6sRPjllCKcFat69Q1kpuEDG1tvuIG_6OxUZHOP_noSA63nkkhTluixdSHPde3XgwYgrm01hBIphFo1ztgQMsVXZaqNGBJKfB35qJ7zSKEFXWcB6olUNA4UUXTup_nH8KrNf0_JcRd4JmIXeaQTTaNLYxeUNljoVsLun6RwBzKf2sDmMFqa8wdE5v159EsaN20EgWQnJGlWdyWEZBixffGM4cXbWIpmZRCv8TCy4dYMh3Nz8FQt7JbWJvCWQskP_b3AFm3TV-h8yUBFhdXRYAeZxtIZsBmjCZZtwDPGnKJ3tLtSnQ3PtlYFn1l0vvPgHh7mdmnhdbWtkUh3hQozmpwGYE5G0LE1XlEQ9KqdR6_ERfztdnbWnxJqAly_m5uXFu6ymcMDmZhkdFvRM1M8923TpttfrkNlzsQM2pzRyZYhATSrBz8eMgJY7me3UHXo3FlGnf0Capm2MNNLVytVv0mgqa8WEMhPzpuga1kbqKt884QqnjHgozx0DYM68uOwTOlMBdRSf6MCE5aqn4fYK7sp3_ZclUNtDr7cM8Pz5GJX3dh_py69qCStpAhptt0smksFcHGezX9zrDehJ9bPvW6gTK4aBKUAndr6SXQ22Boa0kRTo2YWU6mNMr0yNQomEoupdUvc5FtsJ6PiaOz7rTHDS10SCZAvSv0cE2rdVAmh_j-2uDfYkKBs_wPDiNSXCdmIBtO8w4QFABeZQut22nlPTA7a6zV2-GV5m_7FumT6mn92tVW39uuZaWLgJWqa_KADeWM35JQTHrzOOLz54vm4M","id":"rs_0023798544b250b9016980907aebec81948e9042e8de044015","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_lwams5xjm0"}
+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_tHpxKCS6xnVW3HBEkBww7S9T","type":"function","function":{"name":"add","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_lwams5xjm0"}
+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"a\":2,\"b\":3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_lwams5xjm0"}
+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"call_qj0i1JW7dlNDPv5uNW5Tq6lO","type":"function","function":{"name":"multiply","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_lwams5xjm0"}
+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"a\":2,\"b\":3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_lwams5xjm0"}
+
+ data: {"id":"gen_01KGF38QHY01RX510GTJVENPPB","object":"chat.completion.chunk","created":1770033274,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_0023798544b250b9016980907a944c8194aa354cf54822893e","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":7023589.520205,"endTime":7023819.54204,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":7023589.520205,"endTime":7023819.54204,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.0049675","marketCost":"0.0049675","generationId":"gen_01KGF38QHY01RX510GTJVENPPB","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":54,"completion_tokens":298,"total_tokens":352,"cost":0.0049675,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":192,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0049675},"system_fingerprint":"fp_lwams5xjm0","generationId":"gen_01KGF38QHY01RX510GTJVENPPB"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 408.927458ms
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 2299
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system"},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"call_tHpxKCS6xnVW3HBEkBww7S9T","function":{"arguments":"{\"a\":2,\"b\":3}","name":"add"},"type":"function"},{"id":"call_qj0i1JW7dlNDPv5uNW5Tq6lO","function":{"arguments":"{\"a\":2,\"b\":3}","name":"multiply"},"type":"function"}],"role":"assistant","reasoning_details":[{"data":"gAAAAABpgJB6xgaIX4YGTj3EZimfLMfl7lZ7SJq0aBMWfGDeorXxt6sRPjllCKcFat69Q1kpuEDG1tvuIG_6OxUZHOP_noSA63nkkhTluixdSHPde3XgwYgrm01hBIphFo1ztgQMsVXZaqNGBJKfB35qJ7zSKEFXWcB6olUNA4UUXTup_nH8KrNf0_JcRd4JmIXeaQTTaNLYxeUNljoVsLun6RwBzKf2sDmMFqa8wdE5v159EsaN20EgWQnJGlWdyWEZBixffGM4cXbWIpmZRCv8TCy4dYMh3Nz8FQt7JbWJvCWQskP_b3AFm3TV-h8yUBFhdXRYAeZxtIZsBmjCZZtwDPGnKJ3tLtSnQ3PtlYFn1l0vvPgHh7mdmnhdbWtkUh3hQozmpwGYE5G0LE1XlEQ9KqdR6_ERfztdnbWnxJqAly_m5uXFu6ymcMDmZhkdFvRM1M8923TpttfrkNlzsQM2pzRyZYhATSrBz8eMgJY7me3UHXo3FlGnf0Capm2MNNLVytVv0mgqa8WEMhPzpuga1kbqKt884QqnjHgozx0DYM68uOwTOlMBdRSf6MCE5aqn4fYK7sp3_ZclUNtDr7cM8Pz5GJX3dh_py69qCStpAhptt0smksFcHGezX9zrDehJ9bPvW6gTK4aBKUAndr6SXQ22Boa0kRTo2YWU6mNMr0yNQomEoupdUvc5FtsJ6PiaOz7rTHDS10SCZAvSv0cE2rdVAmh_j-2uDfYkKBs_wPDiNSXCdmIBtO8w4QFABeZQut22nlPTA7a6zV2-GV5m_7FumT6mn92tVW39uuZaWLgJWqa_KADeWM35JQTHrzOOLz54vm4M","format":"openai-responses-v1","id":"rs_0023798544b250b9016980907aebec81948e9042e8de044015","index":0,"type":"reasoning.encrypted"}]},{"content":"5","tool_call_id":"call_tHpxKCS6xnVW3HBEkBww7S9T","role":"tool"},{"content":"6","tool_call_id":"call_qj0i1JW7dlNDPv5uNW5Tq6lO","role":"tool"}],"model":"openai/gpt-5","max_completion_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"Add"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"5"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"\n"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"Multiply"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":":"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"6"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_rb8lymwxwp"}
+
+ data: {"id":"gen_01KGF38VW9EJPCTC0TED93SGM2","object":"chat.completion.chunk","created":1770033279,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_0023798544b250b9016980907efc7c81948203b5d78adfea6b","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":3192786.860293,"endTime":3193009.179478,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":3192786.860293,"endTime":3193009.179478,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000345","marketCost":"0.000345","generationId":"gen_01KGF38VW9EJPCTC0TED93SGM2","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":172,"completion_tokens":13,"total_tokens":185,"cost":0.000345,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000345},"system_fingerprint":"fp_rb8lymwxwp","generationId":"gen_01KGF38VW9EJPCTC0TED93SGM2"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 315.780916ms
diff --git a/providertests/testdata/TestVercelCommon/gpt-5/simple.yaml b/providertests/testdata/TestVercelCommon/gpt-5/simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1fec0eebb331f02f3e7e2d1900755a0b200041dc
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gpt-5/simple.yaml
@@ -0,0 +1,33 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 173
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"openai/gpt-5","max_completion_tokens":4000}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3857W5E69F2H2ANCE2CYB","object":"chat.completion","created":1770033258,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":"Olá!","reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJBqe4UanBDshmkUO5UeBgKTle4JTA6JRhnoTGSFte1-ryTvUUbT5rmqGZ7FNrxFvny6dsrNnl1pd4YxeeFus-r67hkBoXsTVYnvct-B0l_CJHcuIZGAD0KSmHfXF0VozKzfZ8Lir1W5zaRJjS_o06nJ-YlqE-V__aYAPeSAhqdscK2B0AJZH4auLrNQolMQq-9d-A7SMnqComX-a1dpu8dZug7-EN9DrypPQqfrBg311Wf4Od2HNwmZS_SqAvOofhi6gkcN2p8MqSiWZNKJRDAJjC_cJsGJ-LQ3tmyPJEzclcMbjehRvjT_IDk0qKqEJqWLSLiDbTH6QaXvSTBQAaSUT8QB6_p42tstR_Jhelyhy1GSfYyny__5FrEmoqLE4sxu16Z1nEdE8MYvcJaUl0KT5Q32GziBMefLQQq9wwhcx6rXJUc29dt6xvntz__4w_kmJismJ8Etb1eVlSLtZwNGF0OyO6K7jar7EL93mbxjmpzu4olDI93EnyxiEDmpz6UOSjFbq-Ey5Kw8AL_L9TwgIMXgLrG-UYYXyzXRhyIL_hWAzMHhcyQs1cvm_RaDmCRC_zFGyKE3cd4QDxC4mnzru7vhWSykmT4A8VyBm57hhxk7wEFxz0_KDfnmrSCUxZiMwGVujBWY6BeqzNd-fF1OvLrYiTmyLzRql_mQ4ED6WeFtq3bFGfp4VdLqJ7Huzg7r0_7o5mQwQ3JpjWE_iay8JtHQfsFXuFCmH_VRdA604UOsuYLdnoGej4hES3jqECSwvJQQXNASQyJbQ2_uGsG1C56IlCzE-vDhqp2PShFoYvEDJ3_gb6TdgiF0ASS3NyFq5PIa1J2zTk3gRJnXkYGgO4kD_iHpkTKhn75LEFLOCuWb4DBpB8qHIUDPHU8odqcGLPjng7NKat7wp5PQGQRVJ_8ulRxyLf5_rP85jB5n_eNDg1MXIO7KALnJE0X9303JThanVo9c7hgvmgE_dbwNbmdzYasxIqYpTH524aoW4Pv3Py7C13Y4PH8WeWY5PeKoEEcyeleiBC1YO1G25JG1e91p-HcOcGWxGHzmln74j9H_LO16zqJias3tT4gRLAphcrHe-a6Ao7pFxwdut9Dw2Lg_79zGR5h5gjN8LBaCJSwMg-pcZ-V1_TAbFCjbeCYfze7ndt9OWOXjS2T05xKAal_21dveRfiuK7-6phUWQ7TgruezFhpPQXoOp8sXHpieyRR8K3_DYGm4qCFbtqUM_SReW2m7qr805a-C5OaDurcQmq--ex8ORV4y6YxD2pA0uriVy60L8vTwX3o82fIhjxvkBNsR1wwjb0puBzUfxX_hvLbbZ8SV1UeNwe0tsnCD0TOtTLczGreq3HkSy25_JQ==","id":"rs_0195d9d352e85fe40169809068318c8190b2bbf966d0dcd881","format":"openai-responses-v1","index":0}],"provider_metadata":{"openai":{"responseId":"resp_0195d9d352e85fe40169809067d3bc8190a9e940c7bf350bb4","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":435303.593243,"endTime":437939.710829,"statusCode":200,"providerResponseId":"resp_0195d9d352e85fe40169809067d3bc8190a9e940c7bf350bb4"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.00168375","marketCost":"0.00168375","generationId":"gen_01KGF3857W5E69F2H2ANCE2CYB","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":19,"completion_tokens":102,"total_tokens":121,"cost":0.00168375,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":64,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00168375},"system_fingerprint":"fp_7r70i7ytcp","generationId":"gen_01KGF3857W5E69F2H2ANCE2CYB"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.791494792s
diff --git a/providertests/testdata/TestVercelCommon/gpt-5/simple_streaming.yaml b/providertests/testdata/TestVercelCommon/gpt-5/simple_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..620cf9ab29f545a6f6d683df496db838c7a639aa
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gpt-5/simple_streaming.yaml
@@ -0,0 +1,44 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 227
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"Say hi in Portuguese","role":"user"}],"model":"openai/gpt-5","max_completion_tokens":4000,"stream_options":{"include_usage":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF387XY51D0GDDRCM6KB8NB","object":"chat.completion.chunk","created":1770033258,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_tmpp8eb0yq"}
+
+ data: {"id":"gen_01KGF387XY51D0GDDRCM6KB8NB","object":"chat.completion.chunk","created":1770033258,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJBr1JtCCwq4H63wpwrzBisIFa5cozvaVKPCSa_QKdqiKVGM1bH7JXlt53SbT0JsAPDQ_zh4dp6N57-9-WHBZGeFpXVhBWOVjECwI-Sx19ug89zVfZf0Xc7GmgO2C6uR35S0kkVN76bxn8_4ofEGjaGB_P-yjp6oLE4wLzAkH082bkzjww6Yv-2Hqw1FSJsdzCEIuf_FwQkoFPnRdBb5PPPGfyRnIAiS9lFGsMLEA1k8VpOfAWsM5q_UR_pJ8YAFK9MG8gPH8qsaG9rMZSLq5kPoz6lkbX3ZEsBcnpIzJLoYGIKRHPQFXehUxj1ml0hy38aNBv22zgZc0bvQUcM7dsnX-4iaNrUa2YskUJ7TPPuaHGR79KBIwfv0qqFiFDdaa38pJEM_-gAKIv2JcBoNZnui6bCEFNIcyTn-sDU9lhqfbXvFt7jnu7ZNV4kCqe8mhrC3x4V_n7ip2Gd_nA849tPiQmeGlMAgGUiBR3-dGOo-quuJp1nBWSiUvj5DisGkI8NlG_-lAPaVQQfjCc32bn3KY2Ch5a5RltI-DJuCzvpcrDkl4RZIeMoJfaQHUImhpmpZn3Y05ckwCdy1n0difkQIXPgNGcbVXLW5RD7xYDC375nYL4qHfbIWxjPjVv7Jsc8jMWjMhHWC_XCDdon4BhZ9LSj70ppMxkaxl3wgZW8o-s1xeSOM-AbviX_ZBjj63WfeTsUS24-tRDRmfbVSApDHbt7GVJMRr-7AsNZkvuDKMC-URk5Omp8eXJVzhaPnaQVhYPyh3jYmPHWbldKPiu6HZ2QZksn-tIM4M3rse2wJXf4ffk8rbBCcsJPIgT-R9cfq","id":"rs_04b3b5ea2112e2f2016980906b0aa4819087bc5b624622f5c1","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_tmpp8eb0yq"}
+
+ data: {"id":"gen_01KGF387XY51D0GDDRCM6KB8NB","object":"chat.completion.chunk","created":1770033258,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"Olá"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_tmpp8eb0yq"}
+
+ data: {"id":"gen_01KGF387XY51D0GDDRCM6KB8NB","object":"chat.completion.chunk","created":1770033258,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_tmpp8eb0yq"}
+
+ data: {"id":"gen_01KGF387XY51D0GDDRCM6KB8NB","object":"chat.completion.chunk","created":1770033258,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_04b3b5ea2112e2f2016980906a921c81908b97d5d38611d5a6","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":356384.393513,"endTime":356580.787605,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":356384.393513,"endTime":356580.787605,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.00148375","marketCost":"0.00148375","generationId":"gen_01KGF387XY51D0GDDRCM6KB8NB","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":19,"completion_tokens":82,"total_tokens":101,"cost":0.00148375,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":64,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00148375},"system_fingerprint":"fp_tmpp8eb0yq","generationId":"gen_01KGF387XY51D0GDDRCM6KB8NB"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 284.897458ms
diff --git a/providertests/testdata/TestVercelCommon/gpt-5/tool.yaml b/providertests/testdata/TestVercelCommon/gpt-5/tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b1ffe90a9d3154d2930e3a94b01f303ed67b8c4d
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gpt-5/tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 465
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"openai/gpt-5","max_completion_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF389FA00FX9W76TJBD2FY0","object":"chat.completion","created":1770033261,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJBt9rDWBVUu57Qp4eDPgvhNl_yejTP7GQIvS9aR9c0rc2udBHMKWf6Lov1QwiEeQbCc8LROQ_SbUEvfyEl-9PofdGalnrJON5sqNjhFmugyAnTzQwIbCLzHhViPQYcKTeDxYUNkLO-WUzh9UcgCE3H9-JaGFMFgvpEtK2izjoSXQAfcM4N4TpIjSZVLKCARs9L3jzHHdIMx1God2c7H0MErV3MDZ_7J_xlIDaVOQPKOOMzVO6EjBEWH9TQn_C3f2h5bm6YphGwIfcI7TxOmQVmf7NV0r9e5Tl0v2NQ6L5alFvBllJiKLOsmO6jShYoPT_i119sexG8bSw0w8qqlOvJJxA3nSmKgimH9TJXIynwqntgKw2sf3TUov2ZcXBXuuWEvwwuzvJZ-IblbQ4tp3voRndpGGLL5RaUAnVJxsawXAC7ghykRDhuqBywJVrc0HuNZKsl0qLjEi22IYXAhdbVerM84pD1IMgA-9XbzPryB6R6vvwk6UBQH7H35sSIywXRK0pWMJftKwUIfh87K8iPyt2sdvdxFgeCv1zygTwsvRNIyxrdLznmOlPPEmgeapkBzXMnpnhkIDRkm0q1owi849hYpArAr5dP9KonpVSkJEx_hO4Nu125WOtKG6kt59lWzVy5ntGaQbQx0Y9Ekg-YrVAt0MRBDTHbyYFvg01tRDT5qX7RTjVrxcnBJaS4jiHsE3ThGQCvlyUKDLrBD891lSuLZHJ-b_WDXiAZW63-INaU6dm7rkw0-kCCg6f02WEiTbwrUI3la4iJ_OHvO5dX8HMzO566TT_VPay9vmSAzBcO9vYyJHqAahlce6fc8HSC6yM4FmArFa7fAI24qzACBtcwPZGufHi6SvIarOzZ_Hqhs0K1707Jlm8Nad1QR-mSS4dhXCAWyFuF7uyAA9TrsmKQHIUPXQH3ohsYNkJ-MJwm168NoHL0_Bj2j00JLENHX1oK0iUQLFy2RasyOO6-ChpeYo4GCPxbXkXRNMst9RdOwswtqZKS9lKa4mSrV8_-rlb4exerAjDg2YPPoMSsXEZEZt1BmtnA_xEk2Ba9FhOw6p8n2zakljygABYj__RQ7pwvQZL9AQdpzrDu4eiYkl538d02K0It_d39qaUF-MQVNIqUv40OTI17kDAUhq9MFcYquHywFRcBzS2h0L5siHwieTqTaCPk9LEJwen2JlDWeXovmqX-bxuByh1TNemfkHKSG4lDhIW8Jg2wcilnNEuvvMRmVEAPDen8IaOiP3-S3gjXPv2wqrpG_HD4-XxjugEB0lTmtEn-tA-8jBTTG__H4kUjAv8gX94FW4QYmA9x-xKJwb8mVI_f9xTUMgmx7OsBXoGY1ddAmKfNA5dN4wtTYwKUIoj_VQ9LpXK86DNVlIuT-OaRE_wjLPxnUc0aTXGUUUQJNhmzLRa6xLeyw1A==","id":"rs_0c750dfa299f673c016980906c83288193a268c0d2c594d1ed","format":"openai-responses-v1","index":0}],"tool_calls":[{"id":"call_Rpqo15PMdWRph6Je9FbyRkrP","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence, Italy\"}"}}],"provider_metadata":{"openai":{"responseId":"resp_0c750dfa299f673c016980906c2e748193aacbf2a1a14f5495","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":4677952.648505,"endTime":4679832.007624,"statusCode":200,"providerResponseId":"resp_0c750dfa299f673c016980906c2e748193aacbf2a1a14f5495"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.00185875","marketCost":"0.00185875","generationId":"gen_01KGF389FA00FX9W76TJBD2FY0","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":63,"completion_tokens":114,"total_tokens":177,"cost":0.00185875,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":64,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00185875},"system_fingerprint":"fp_4kn76nn85u","generationId":"gen_01KGF389FA00FX9W76TJBD2FY0"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.189340917s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 2326
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"call_Rpqo15PMdWRph6Je9FbyRkrP","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"data":"gAAAAABpgJBt9rDWBVUu57Qp4eDPgvhNl_yejTP7GQIvS9aR9c0rc2udBHMKWf6Lov1QwiEeQbCc8LROQ_SbUEvfyEl-9PofdGalnrJON5sqNjhFmugyAnTzQwIbCLzHhViPQYcKTeDxYUNkLO-WUzh9UcgCE3H9-JaGFMFgvpEtK2izjoSXQAfcM4N4TpIjSZVLKCARs9L3jzHHdIMx1God2c7H0MErV3MDZ_7J_xlIDaVOQPKOOMzVO6EjBEWH9TQn_C3f2h5bm6YphGwIfcI7TxOmQVmf7NV0r9e5Tl0v2NQ6L5alFvBllJiKLOsmO6jShYoPT_i119sexG8bSw0w8qqlOvJJxA3nSmKgimH9TJXIynwqntgKw2sf3TUov2ZcXBXuuWEvwwuzvJZ-IblbQ4tp3voRndpGGLL5RaUAnVJxsawXAC7ghykRDhuqBywJVrc0HuNZKsl0qLjEi22IYXAhdbVerM84pD1IMgA-9XbzPryB6R6vvwk6UBQH7H35sSIywXRK0pWMJftKwUIfh87K8iPyt2sdvdxFgeCv1zygTwsvRNIyxrdLznmOlPPEmgeapkBzXMnpnhkIDRkm0q1owi849hYpArAr5dP9KonpVSkJEx_hO4Nu125WOtKG6kt59lWzVy5ntGaQbQx0Y9Ekg-YrVAt0MRBDTHbyYFvg01tRDT5qX7RTjVrxcnBJaS4jiHsE3ThGQCvlyUKDLrBD891lSuLZHJ-b_WDXiAZW63-INaU6dm7rkw0-kCCg6f02WEiTbwrUI3la4iJ_OHvO5dX8HMzO566TT_VPay9vmSAzBcO9vYyJHqAahlce6fc8HSC6yM4FmArFa7fAI24qzACBtcwPZGufHi6SvIarOzZ_Hqhs0K1707Jlm8Nad1QR-mSS4dhXCAWyFuF7uyAA9TrsmKQHIUPXQH3ohsYNkJ-MJwm168NoHL0_Bj2j00JLENHX1oK0iUQLFy2RasyOO6-ChpeYo4GCPxbXkXRNMst9RdOwswtqZKS9lKa4mSrV8_-rlb4exerAjDg2YPPoMSsXEZEZt1BmtnA_xEk2Ba9FhOw6p8n2zakljygABYj__RQ7pwvQZL9AQdpzrDu4eiYkl538d02K0It_d39qaUF-MQVNIqUv40OTI17kDAUhq9MFcYquHywFRcBzS2h0L5siHwieTqTaCPk9LEJwen2JlDWeXovmqX-bxuByh1TNemfkHKSG4lDhIW8Jg2wcilnNEuvvMRmVEAPDen8IaOiP3-S3gjXPv2wqrpG_HD4-XxjugEB0lTmtEn-tA-8jBTTG__H4kUjAv8gX94FW4QYmA9x-xKJwb8mVI_f9xTUMgmx7OsBXoGY1ddAmKfNA5dN4wtTYwKUIoj_VQ9LpXK86DNVlIuT-OaRE_wjLPxnUc0aTXGUUUQJNhmzLRa6xLeyw1A==","format":"openai-responses-v1","id":"rs_0c750dfa299f673c016980906c83288193a268c0d2c594d1ed","index":0,"type":"reasoning.encrypted"}]},{"content":"40 C","tool_call_id":"call_Rpqo15PMdWRph6Je9FbyRkrP","role":"tool"}],"model":"openai/gpt-5","max_completion_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF38BGEDFPFYA0YSVGK53PZ","object":"chat.completion","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":"The current temperature in Florence, Italy is 40°C (104°F). Would you like a forecast or more details?","reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJBy04wiPgHZlcnRtMeJdCXiXkMzEOjA4bYMCrCHqVuCdI7vEDq8PlukdtI96JyxomTXvXxRPCIzKJdzHSXR3OLLYvNzwfNDgNQ1dW4bvh69vQpp54zP4Dhs57GgfsfZAB7q9RB0Kg-6eJD86w2NsGfTIO2ITYeN-_Y5Bqeg8rOb4V9XK1pf-bLaeZsL4uBfvriH8M_uL5nEyaaZupiXTiZfv0A6Lb-lMWH9SS0PPy5LsSx0H_w-4OR8G6J2isU7-bG12BGklNspMvMmtj5JWmZbgbb-JHvR_NO7p--3Q6QCQzg088E_Uh1lQTqvnX3AffKuPJNgxVaiivOQwZXXLEG0NYULjeB20PNsMBVTi_OF4frTljlCvvTzecAd9iaeIECwDBEJDEgqTQefE0linoyLBeey8kD6DIweziBNn8ezoWU7ACiWCqz8FtB0smGue1W949AEmHfRizTjaqEbVpUiW3CA4aVp3eNZiu1XbE3b514H7XMG-6SBBohs0YfPdlTIez7To3Ptzv2x0t7KPiPZi7uDYTscYS1AWdTeB7LJRoLy3mO74Jmq0w0ZnSF3U2zu7-cHkyk6_x1R66bH8uLTtuQRzmyZtef-7T8QGt8k_belGqnRr9o9rdvLp80rwEjjwwPK9lIcR_mA1XDZZHEqoNWOQKINWxwwrjypgRDwSxs_FI3zi-OviKBsFe8YJTn3sJx1ppVkoBU-czhIfpfeF1wqjgGxIIcGGXm8wVXGqWG1Nm-AZwNLxnf34CfhcBddIL4lbPwMa39aaGYGU2qc9Qj8egNg7Bzk0wysMxC4ttsQSpcGM1CXVuyYY9nKiNybsbFQGSB6S32blf05IVD6J1WRqRWlQjJ-doPxmRMqKkXVWOuLN6jHpjAVhtQt2a2jMOvzkuj1bkmrxwLZ6HVKdFEgTN1tVRZ8URSvN3KAQxkOmLr0qPFjqEocjCM8CCTvWSZPbEGTKmHGZBqWFRkOTTC9r0XL_NmeDPZ8x9IfRRTjHg4lJpMixQyrTpgqUHJ_YWgo_jQGFWGntrj8YVfTaOjJmDXigBb2eUr22Tu72U8sBFURrBFDvXQvrL_gbgP4KifJ9ablHQ5M7k2W-I1wD9SgW77LZYYtsDdr_bv1tLIv9zn7tien8eAv1RQN4cICC8yJSnd_8RpzVnpVg6ZyDHOMRL9fU5URSQvtl0ld8c-Hu46NRTR_Ua6b1bIrCVswrbFF0j1tvEA3UBKnuN92LNavwOlu_N7AAPy0tmSvTk0bxfuus3AHDMAEzeHbQBH2OclogxZcfnrm1dXk3ee24hksoxJjfMVTzRBaVPssUCN_ZLzu1T6GwQ4YCdMl2QKX1KWz9ONt6zDNjvkhbZKGYod9E0anXx91NMzhIwou15N1USmduEuklufFN6adsQDWyJ_dK-mS1tlVI9GcDVNnbRUbHvtNui2qwtCzLGxyY82blpFO6dZRjpzY1YRtqo9QA-3MXT1J1mwPmnP2nQh8x5DQPZ-wxs3TcC0DuPVhu-pWmc1RyUtrri3vUy6evRKkezMqybI2zSibyq96ORSAQfB6jZmkyGCNj_w3oCEgYpFJRpPdK42z7SydPItcHGyTbFIE72QqD5lbMA37vCx6iCN38tTUNRYhmeXcKAot9wN5TZ_zNs8TY6BbW1PaIGnPumEudzJCFZhlwPkN6_93U57l23S0chlyA34JN7JMrjI3gVyI0WYFY6IrgQzknsiwpmMAqi9_RQaY6wgVBHadORhAufCHOvq-Qgrcbzpgppuc6zWp7qpc-PACaXLdG2HBvD_whxNmKjaW8b4sUu0IEhHv4esQ4Cxdurb6PAsPPRyUqAyfYX3uYKePFCSGe_Gv6Zss6Lbd5hp0GBvLoVdCxa_81e0EH62Oi5OzbiUpWGY1717a9l6SepkbpbyYnllAMuNGI8whTOBJrDXNR85-lNMSEfVIg6Pjw7Imle0jFkZX1ASfHLXCta9elSYiw7pYIzW67aO3DUacyqKYUxEqO2kVWtcllcO1-_s3rJzKAM4_Qp7A80_0B9X1CfkEKWKLpdJTjfeAiMKtqOTEs0IXngkbaxppW6KdxBsj5bhGCTAXhq_yXeCkBei_aVteFzK2BO1vvLlUhMysIzxs8CLs1YLdAA6vO2dEznTujNxz9Rc=","id":"rs_0c750dfa299f673c016980906e9f1c8193a6477099ec37fe1e","format":"openai-responses-v1","index":0}],"provider_metadata":{"openai":{"responseId":"resp_0c750dfa299f673c016980906e3c00819389d21d48153004b1","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1368084.873343,"endTime":1372326.249053,"statusCode":200,"providerResponseId":"resp_0c750dfa299f673c016980906e3c00819389d21d48153004b1"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.0045725","marketCost":"0.0045725","generationId":"gen_01KGF38BGEDFPFYA0YSVGK53PZ","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":186,"completion_tokens":242,"total_tokens":428,"cost":0.0045725,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":192,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.0045725},"system_fingerprint":"fp_4lohj8xzuj","generationId":"gen_01KGF38BGEDFPFYA0YSVGK53PZ"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 4.324064375s
diff --git a/providertests/testdata/TestVercelCommon/gpt-5/tool_streaming.yaml b/providertests/testdata/TestVercelCommon/gpt-5/tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..1b7e34bb5dc1ff97e3bc648d4b1a893862bb0aa7
--- /dev/null
+++ b/providertests/testdata/TestVercelCommon/gpt-5/tool_streaming.yaml
@@ -0,0 +1,119 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 519
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"}],"model":"openai/gpt-5","max_completion_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJByBdy9g4TuHPa7DgknLNhMVPGBacw6RSFlD86GixiOuj40lDELdX_Q4KpFNDGcs2gWwNHn1H7rIRCRF7wxROP_609IYjQjHTHB5_0by_qtfPjubqMYZbBfLC9pD5LMt3wpLFWxvAkk-PckiEuLpg1NcdorEuBFlJgwEOKUgO51ZGJbVvpwBsqrcv2xrMSS1jp8NIwy70pS8GS8Chq74_U4FIB26Mpvi_67J_zuXCqiIL9YklAwao0gdOCNGRyKoioVhcOMpS85FvFB8Sg5HstfrBPyKxqNx65gAT9PkL-YS4Fnu403tFbWXIQEZK-oC4oMqpjZKSllX6lYRQdEMZ8TdGLX1FuzXT8apGuqpEcKKeSlUaF_4T5UzLszir9DvQRwapFdiyBrZaR1lWGvkfB6695EQLjgF0cM0qiyBmQ2QHcfEPWIvB4s_kvbE7VxZbZwzAQJwtevqnU1V4ZbG8uh60jClbHOLOiK-Ty5xntV9Pai9ISDeUpmVlfv60cvjRGyxYOIR6fu3uwZSZrje-OfnYUmC9_s6aDhbrNe-IEvhnlhBSbemJwolxE6buieN4kdjZ2xlqDFY2mk8nLx8tF6ZiP4IROD0_ZRz-k7k9cGEncfvTFtkITcfum_0_M-v94SuvRSGMjW6QjMun8UgSiMxBoAlftJWtZxlVBLiCao2fNlbaXdKEUuFS7CG8lfRUybrwSZiOgIPp7mLx05blU6MApN1vE6iSEHuNncRTKryb58XchOLOJRld1OH1NjFsE5_cczhvguSKkJb8uqdl_kOgtQea4XNRWlirogKKKiKdbpOH2F2wVwrYGXCdqGQBE5","id":"rs_02e57b3492270d950169809072df2c81958978be9de09c65c6","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_kjY7wC8Gbmob78vc6x7vvFRl","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"location"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Flor"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ence"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":","}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Italy"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_147br1mgel"}
+
+ data: {"id":"gen_01KGF38FRCNWV564Q8599HRRAW","object":"chat.completion.chunk","created":1770033266,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_02e57b3492270d9501698090728f488195b501a282cdac33a5","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":3180361.719299,"endTime":3180600.837456,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":3180361.719299,"endTime":3180600.837456,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.00191875","marketCost":"0.00191875","generationId":"gen_01KGF38FRCNWV564Q8599HRRAW","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":63,"completion_tokens":120,"total_tokens":183,"cost":0.00191875,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":64,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00191875},"system_fingerprint":"fp_147br1mgel","generationId":"gen_01KGF38FRCNWV564Q8599HRRAW"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 376.16525ms
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1780
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"call_kjY7wC8Gbmob78vc6x7vvFRl","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"data":"gAAAAABpgJByBdy9g4TuHPa7DgknLNhMVPGBacw6RSFlD86GixiOuj40lDELdX_Q4KpFNDGcs2gWwNHn1H7rIRCRF7wxROP_609IYjQjHTHB5_0by_qtfPjubqMYZbBfLC9pD5LMt3wpLFWxvAkk-PckiEuLpg1NcdorEuBFlJgwEOKUgO51ZGJbVvpwBsqrcv2xrMSS1jp8NIwy70pS8GS8Chq74_U4FIB26Mpvi_67J_zuXCqiIL9YklAwao0gdOCNGRyKoioVhcOMpS85FvFB8Sg5HstfrBPyKxqNx65gAT9PkL-YS4Fnu403tFbWXIQEZK-oC4oMqpjZKSllX6lYRQdEMZ8TdGLX1FuzXT8apGuqpEcKKeSlUaF_4T5UzLszir9DvQRwapFdiyBrZaR1lWGvkfB6695EQLjgF0cM0qiyBmQ2QHcfEPWIvB4s_kvbE7VxZbZwzAQJwtevqnU1V4ZbG8uh60jClbHOLOiK-Ty5xntV9Pai9ISDeUpmVlfv60cvjRGyxYOIR6fu3uwZSZrje-OfnYUmC9_s6aDhbrNe-IEvhnlhBSbemJwolxE6buieN4kdjZ2xlqDFY2mk8nLx8tF6ZiP4IROD0_ZRz-k7k9cGEncfvTFtkITcfum_0_M-v94SuvRSGMjW6QjMun8UgSiMxBoAlftJWtZxlVBLiCao2fNlbaXdKEUuFS7CG8lfRUybrwSZiOgIPp7mLx05blU6MApN1vE6iSEHuNncRTKryb58XchOLOJRld1OH1NjFsE5_cczhvguSKkJb8uqdl_kOgtQea4XNRWlirogKKKiKdbpOH2F2wVwrYGXCdqGQBE5","format":"openai-responses-v1","id":"rs_02e57b3492270d950169809072df2c81958978be9de09c65c6","index":0,"type":"reasoning.encrypted"}]},{"content":"40 C","tool_call_id":"call_kjY7wC8Gbmob78vc6x7vvFRl","role":"tool"}],"model":"openai/gpt-5","max_completion_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" current"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" weather"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" Florence"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" Italy"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" is"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" about"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"40"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_9trj17vyed"}
+
+ data: {"id":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","object":"chat.completion.chunk","created":1770033268,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_02e57b3492270d950169809074a41c8195b28990630eb61d38","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":3182379.990316,"endTime":3182610.529457,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":3182379.990316,"endTime":3182610.529457,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.00029125","marketCost":"0.00029125","generationId":"gen_01KGF38HQ7R9XH4N23YXVZ2V51","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":97,"completion_tokens":17,"total_tokens":114,"cost":0.00029125,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00029125},"system_fingerprint":"fp_9trj17vyed","generationId":"gen_01KGF38HQ7R9XH4N23YXVZ2V51"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 378.669292ms
diff --git a/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/multi_tool.yaml b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/multi_tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..fa6b1b6d6a431fd7d75d5f8074b75582d0103a85
--- /dev/null
+++ b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/multi_tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 904
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system","cache_control":{"type":"ephemeral"}},{"content":"Add and multiply the number 2 and 3","role":"user","cache_control":{"type":"ephemeral"}}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3AEN63MVZD10V5VWY1NFK","object":"chat.completion","created":1770033333,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"toolu_018Bqrp5E4LTkWWKFAWjJcPw","type":"function","function":{"name":"add","arguments":"{\"a\":2,\"b\":3}"}},{"id":"toolu_01ModQEwNzE9utyENTnUKDzE","type":"function","function":{"name":"multiply","arguments":"{\"a\":2,\"b\":3}"}}],"provider_metadata":{"anthropic":{"usage":{"input_tokens":507,"output_tokens":137,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7080018.781706,"endTime":7082515.69486,"statusCode":200,"providerResponseId":"msg_0198xyvGQtALbxVJ6en1oy92"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.003576","marketCost":"0.003576","generationId":"gen_01KGF3AEN63MVZD10V5VWY1NFK","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":507,"completion_tokens":137,"total_tokens":644,"cost":0.003576,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003576},"system_fingerprint":"fp_hbuq90twge","generationId":"gen_01KGF3AEN63MVZD10V5VWY1NFK"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.724311375s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1333
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. CRITICAL: Always use both add and multiply at the same time ALWAYS.","role":"system","cache_control":{"type":"ephemeral"}},{"content":"Add and multiply the number 2 and 3","role":"user"},{"tool_calls":[{"id":"toolu_018Bqrp5E4LTkWWKFAWjJcPw","function":{"arguments":"{\"a\":2,\"b\":3}","name":"add"},"type":"function"},{"id":"toolu_01ModQEwNzE9utyENTnUKDzE","function":{"arguments":"{\"a\":2,\"b\":3}","name":"multiply"},"type":"function","cache_control":{"type":"ephemeral"}}],"role":"assistant"},{"content":"5","tool_call_id":"toolu_018Bqrp5E4LTkWWKFAWjJcPw","role":"tool"},{"content":"6","tool_call_id":"toolu_01ModQEwNzE9utyENTnUKDzE","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3AH9QQJ48CR5J8VYYZN30","object":"chat.completion","created":1770033335,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"I''ve performed both operations with the numbers 2 and 3:\n- Addition: 2 + 3 = 5\n- Multiplication: 2 × 3 = 6","provider_metadata":{"anthropic":{"usage":{"input_tokens":688,"output_tokens":47,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1440501.815188,"endTime":1442379.185058,"statusCode":200,"providerResponseId":"msg_01HoW3wJwr4Hqen1m7PJHcEL"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002769","marketCost":"0.002769","generationId":"gen_01KGF3AH9QQJ48CR5J8VYYZN30","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":688,"completion_tokens":47,"total_tokens":735,"cost":0.002769,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002769},"system_fingerprint":"fp_yb4k07q27e","generationId":"gen_01KGF3AH9QQJ48CR5J8VYYZN30"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.006164709s
diff --git a/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/multi_tool_streaming.yaml b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/multi_tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..53b09c8f2c1751498f998fe8c5027aaf5713b905
--- /dev/null
+++ b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/multi_tool_streaming.yaml
@@ -0,0 +1,119 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 941
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system","cache_control":{"type":"ephemeral"}},{"content":"Add and multiply the number 2 and 3","role":"user","cache_control":{"type":"ephemeral"}}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"I"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'ll"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" ad"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"d an"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"d multiply the"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" numbers 2 and 3 "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"for you."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"toolu_01EbUPM9AHLKandFdpD3hR2d","type":"function","function":{"name":"add","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"a\": 2"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":", \"b\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":": 3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"id":"toolu_01WJxb3WgmL33DJCq2hw4DFL","type":"function","function":{"name":"multiply","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"{\"a\": "}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"2"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":", "}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":"\"b\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":1,"function":{"arguments":": 3}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kk4h3svyf"}
+
+ data: {"id":"gen_01KGF3AK848QW52MG188A9XZRA","object":"chat.completion.chunk","created":1770033336,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":502,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":137,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":4753514.35299,"endTime":4754858.992657,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":4753514.35299,"endTime":4754858.992657,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.003561","marketCost":"0.003561","generationId":"gen_01KGF3AK848QW52MG188A9XZRA","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":502,"completion_tokens":137,"total_tokens":639,"cost":0.003561,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003561},"system_fingerprint":"fp_kk4h3svyf","generationId":"gen_01KGF3AK848QW52MG188A9XZRA"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.471487583s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1439
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant. Always use both add and multiply at the same time.","role":"system","cache_control":{"type":"ephemeral"}},{"content":"Add and multiply the number 2 and 3","role":"user"},{"content":"I''ll add and multiply the numbers 2 and 3 for you.","tool_calls":[{"id":"toolu_01EbUPM9AHLKandFdpD3hR2d","function":{"arguments":"{\"a\": 2, \"b\": 3}","name":"add"},"type":"function"},{"id":"toolu_01WJxb3WgmL33DJCq2hw4DFL","function":{"arguments":"{\"a\": 2, \"b\": 3}","name":"multiply"},"type":"function","cache_control":{"type":"ephemeral"}}],"role":"assistant"},{"content":"5","tool_call_id":"toolu_01EbUPM9AHLKandFdpD3hR2d","role":"tool"},{"content":"6","tool_call_id":"toolu_01WJxb3WgmL33DJCq2hw4DFL","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"add","strict":false,"description":"Add two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"},{"function":{"name":"multiply","strict":false,"description":"Multiply two numbers","parameters":{"properties":{"a":{"description":"first number","type":"integer"},"b":{"description":"second number","type":"integer"}},"required":["a","b"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"The"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" results"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" are:\n- "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"2 + 3 = "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"5\n- 2 × "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"3 = 6"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_jv4rc3pqm1"}
+
+ data: {"id":"gen_01KGF3ANVSZB8AH86G2J0K92JN","object":"chat.completion.chunk","created":1770033339,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":700,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":31,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1445140.487939,"endTime":1446016.149192,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1445140.487939,"endTime":1446016.149192,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002565","marketCost":"0.002565","generationId":"gen_01KGF3ANVSZB8AH86G2J0K92JN","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":700,"completion_tokens":31,"total_tokens":731,"cost":0.002565,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002565},"system_fingerprint":"fp_jv4rc3pqm1","generationId":"gen_01KGF3ANVSZB8AH86G2J0K92JN"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.063098791s
diff --git a/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/simple.yaml b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/simple.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..664b864eb776e6c23f8416d682b0e473ba7527c4
--- /dev/null
+++ b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/simple.yaml
@@ -0,0 +1,33 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 249
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system","cache_control":{"type":"ephemeral"}},{"content":"Say hi in Portuguese","role":"user","cache_control":{"type":"ephemeral"}}],"model":"anthropic/claude-sonnet-4","max_tokens":4000}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3A0GNP7F130T7D4SZFNFG","object":"chat.completion","created":1770033318,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"Olá! (Oh-LAH)\n\nThis is the most common way to say \"hi\" in Portuguese. You can also use \"Oi!\" (OH-ee) for a more casual greeting.","provider_metadata":{"anthropic":{"usage":{"input_tokens":16,"output_tokens":48,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":305884.462307,"endTime":307858.655195,"statusCode":200,"providerResponseId":"msg_01NUekGRWWJS2rvj8HY222rZ"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.000768","marketCost":"0.000768","generationId":"gen_01KGF3A0GNP7F130T7D4SZFNFG","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"completion_tokens":48,"total_tokens":64,"cost":0.000768,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000768},"system_fingerprint":"fp_qvkh98zees","generationId":"gen_01KGF3A0GNP7F130T7D4SZFNFG"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.145596209s
diff --git a/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/simple_streaming.yaml b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/simple_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..219e897efea9268d5d8aef772f0001f3a4605260
--- /dev/null
+++ b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/simple_streaming.yaml
@@ -0,0 +1,60 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 303
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system","cache_control":{"type":"ephemeral"}},{"content":"Say hi in Portuguese","role":"user","cache_control":{"type":"ephemeral"}}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"Olá! "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"\n\n("},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"That"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'s \""},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"hello"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"\" in Portuguese -"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" friendly"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" way"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" to say hi"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"!)"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_c0bnftwhqr"}
+
+ data: {"id":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","object":"chat.completion.chunk","created":1770033319,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":16,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":25,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1425425.670751,"endTime":1426422.314773,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1425425.670751,"endTime":1426422.314773,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000423","marketCost":"0.000423","generationId":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":16,"completion_tokens":25,"total_tokens":41,"cost":0.000423,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000423},"system_fingerprint":"fp_c0bnftwhqr","generationId":"gen_01KGF3A2KGQFE5BW4K7TRSZ9DF"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.097552958s
diff --git a/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/tool.yaml b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/tool.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cfd728d52da0845fa653c2c2478a210cb50eee5d
--- /dev/null
+++ b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/tool.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 541
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system","cache_control":{"type":"ephemeral"}},{"content":"What''s the weather in Florence,Italy?","role":"user","cache_control":{"type":"ephemeral"}}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3A4CMTZP7AVTFGEHA9VZ3","object":"chat.completion","created":1770033322,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":null,"tool_calls":[{"id":"toolu_0199hSTV5K6aGu7K5MRpvNEk","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence,Italy\"}"}}],"provider_metadata":{"anthropic":{"usage":{"input_tokens":394,"output_tokens":68,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7069466.244378,"endTime":7071689.075105,"statusCode":200,"providerResponseId":"msg_01CtwtuZqqwryJAuJDdMoG65"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002202","marketCost":"0.002202","generationId":"gen_01KGF3A4CMTZP7AVTFGEHA9VZ3","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":394,"completion_tokens":68,"total_tokens":462,"cost":0.002202,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002202},"system_fingerprint":"fp_nd3kr99iaq","generationId":"gen_01KGF3A4CMTZP7AVTFGEHA9VZ3"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.395244583s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 794
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system","cache_control":{"type":"ephemeral"}},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"tool_calls":[{"id":"toolu_0199hSTV5K6aGu7K5MRpvNEk","function":{"arguments":"{\"location\":\"Florence,Italy\"}","name":"weather"},"type":"function","cache_control":{"type":"ephemeral"}}],"role":"assistant"},{"content":"40 C","tool_call_id":"toolu_0199hSTV5K6aGu7K5MRpvNEk","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}]}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3A6QKNJNQRZ2JER4MQD46","object":"chat.completion","created":1770033325,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"The weather in Florence, Italy is currently 40°C (104°F). That''s quite hot! It''s a very warm day in Florence.","provider_metadata":{"anthropic":{"usage":{"input_tokens":463,"output_tokens":34,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7072056.878135,"endTime":7074733.980106,"statusCode":200,"providerResponseId":"msg_01EYzxaa6Ayp7ACF78uvBrqV"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.001899","marketCost":"0.001899","generationId":"gen_01KGF3A6QKNJNQRZ2JER4MQD46","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":463,"completion_tokens":34,"total_tokens":497,"cost":0.001899,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.001899},"system_fingerprint":"fp_4i6565f6ii","generationId":"gen_01KGF3A6QKNJNQRZ2JER4MQD46"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.949003792s
diff --git a/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/tool_streaming.yaml b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/tool_streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..104f05bd52a1620fe503a32655af025c6725394e
--- /dev/null
+++ b/providertests/testdata/TestVercelCommonWithAnthropicCache/claude-sonnet-4/tool_streaming.yaml
@@ -0,0 +1,117 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 595
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system","cache_control":{"type":"ephemeral"}},{"content":"What''s the weather in Florence,Italy?","role":"user","cache_control":{"type":"ephemeral"}}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"I'll get"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" the weather information"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" for Florence, Italy for you."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"toolu_01NEeARJCxoJWc8F8yKkyTK2","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"l"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ocati"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"on\": \"Flore"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"nce,Italy\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_afeigrmiv8"}
+
+ data: {"id":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","object":"chat.completion.chunk","created":1770033327,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":394,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":67,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7695608.34416,"endTime":7697403.6705,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7695608.34416,"endTime":7697403.6705,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002187","marketCost":"0.002187","generationId":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":394,"completion_tokens":67,"total_tokens":461,"cost":0.002187,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002187},"system_fingerprint":"fp_afeigrmiv8","generationId":"gen_01KGF3A9P5RW4MNWQD4RZQY7FA"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 2.320939125s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 923
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system","cache_control":{"type":"ephemeral"}},{"content":"What''s the weather in Florence,Italy?","role":"user"},{"content":"I''ll get the weather information for Florence, Italy for you.","tool_calls":[{"id":"toolu_01NEeARJCxoJWc8F8yKkyTK2","function":{"arguments":"{\"location\": \"Florence,Italy\"}","name":"weather"},"type":"function","cache_control":{"type":"ephemeral"}}],"role":"assistant"},{"content":"40 C","tool_call_id":"toolu_01NEeARJCxoJWc8F8yKkyTK2","role":"tool"}],"model":"anthropic/claude-sonnet-4","max_tokens":4000,"stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"The current"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" weather in Florence, Italy is 40"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"°C (104°F). That"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'s quite"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" hot"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"! If"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" you're planning to visit or"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" are currently"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" there, make"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" sure to"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" stay"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" hydrated and seek"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" shade during the hottest parts of the"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" day."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_273kaqn10v"}
+
+ data: {"id":"gen_01KGF3ACA8VVD000VSTT20BPP5","object":"chat.completion.chunk","created":1770033330,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":476,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":54,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7697797.908831,"endTime":7699158.038376,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7697797.908831,"endTime":7699158.038376,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002238","marketCost":"0.002238","generationId":"gen_01KGF3ACA8VVD000VSTT20BPP5","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":476,"completion_tokens":54,"total_tokens":530,"cost":0.002238,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002238},"system_fingerprint":"fp_273kaqn10v","generationId":"gen_01KGF3ACA8VVD000VSTT20BPP5"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.463354875s
diff --git a/providertests/testdata/TestVercelThinking/claude-sonnet-4-sig/thinking-streaming.yaml b/providertests/testdata/TestVercelThinking/claude-sonnet-4-sig/thinking-streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..cb7d1b4b15c269eb9d4b8a6c4ce2b23afec9fa75
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/claude-sonnet-4-sig/thinking-streaming.yaml
@@ -0,0 +1,137 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 533
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"anthropic/claude-sonnet-4","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":"The user is asking for","reasoning_details":[{"type":"reasoning.text","text":"The user is asking for","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" weather","reasoning_details":[{"type":"reasoning.text","text":" weather","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" information for Florence, Italy. I have","reasoning_details":[{"type":"reasoning.text","text":" information for Florence, Italy. I have","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" a","reasoning_details":[{"type":"reasoning.text","text":" a","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" weather","reasoning_details":[{"type":"reasoning.text","text":" weather","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" function","reasoning_details":[{"type":"reasoning.text","text":" function","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" available that takes","reasoning_details":[{"type":"reasoning.text","text":" available that takes","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" a location parameter.","reasoning_details":[{"type":"reasoning.text","text":" a location parameter.","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" The","reasoning_details":[{"type":"reasoning.text","text":" The","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" location","reasoning_details":[{"type":"reasoning.text","text":" location","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" is","reasoning_details":[{"type":"reasoning.text","text":" is","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" clearly","reasoning_details":[{"type":"reasoning.text","text":" clearly","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" specified as \"Florence, Italy\" so","reasoning_details":[{"type":"reasoning.text","text":" specified as \"Florence, Italy\" so","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" I have","reasoning_details":[{"type":"reasoning.text","text":" I have","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" all the required parameters to","reasoning_details":[{"type":"reasoning.text","text":" all the required parameters to","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" make the function call.","reasoning_details":[{"type":"reasoning.text","text":" make the function call.","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":"","reasoning_details":[{"type":"reasoning.text","text":"","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":"","reasoning_details":[{"type":"reasoning.text","text":"","signature":"EqUDCkYICxgCKkB94vhGG6xKjNnGimHMfRxMKRoDnfxu8X0ubqexC/CZ0gU1q1TlbdRN/J4R0tWVpSFl6fFlfjxBILkP/+4vk0rsEgwiokH4mommeOQbO0kaDDeTcsDepWKtbzn7RCIwM9YXOvgQOWNhGfjjNVXcLf20mCH4hUPTSpIp3F2WEOxI0CLOTKxuwGTgRB4axXhdKowCQwf95zMeALPR1ZZHRXqVm3Dm8Lf9W0kR2/G/irnQLoTR/lxZ5gB6FqUdPqNJHXmn3r6KxrQlxTM97UEZ0hEZHhBvwLk24e4KQitX5oHkNp+XMFCzjaym/Pryfjo4qxde8drr9TmHH1ajVYHkXue2L/RWEDrbUWITgtUP0CgkbAGijhpdJm4xVIMLHOD2cJS2+gChTu85uzdvdowlgHwMB7G5rHR+c1NB/2BV9iwhgVMgVjZlGB0SZmUoPEvPr2ZW2Y56tpnQ5d5zl4GdxImJBTSzoQzEKoGxt94MsXE207I0sp5L0Zzm+p4bDGTU6V0SI+eumemcejIt9O/jlGFFLf539LcU1+qeMWFdpBgB","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"toolu_01YVA3v6AcXDxaGjsKS8DiUq","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"locati"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"on\": \"Flore"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"nce, Ital"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"y\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_iqjm7xgvli"}
+
+ data: {"id":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","object":"chat.completion.chunk","created":1770033404,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":424,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":109,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":162863.303643,"endTime":164602.735825,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":162863.303643,"endTime":164602.735825,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002907","marketCost":"0.002907","generationId":"gen_01KGF3CMBNWVQFHD13H2B0XSBK","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":424,"completion_tokens":109,"total_tokens":533,"cost":0.002907,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002907},"system_fingerprint":"fp_iqjm7xgvli","generationId":"gen_01KGF3CMBNWVQFHD13H2B0XSBK"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.897754625s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1993
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"toolu_01YVA3v6AcXDxaGjsKS8DiUq","function":{"arguments":"{\"location\": \"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"format":"anthropic-claude-v1","index":0,"signature":"EqUDCkYICxgCKkB94vhGG6xKjNnGimHMfRxMKRoDnfxu8X0ubqexC/CZ0gU1q1TlbdRN/J4R0tWVpSFl6fFlfjxBILkP/+4vk0rsEgwiokH4mommeOQbO0kaDDeTcsDepWKtbzn7RCIwM9YXOvgQOWNhGfjjNVXcLf20mCH4hUPTSpIp3F2WEOxI0CLOTKxuwGTgRB4axXhdKowCQwf95zMeALPR1ZZHRXqVm3Dm8Lf9W0kR2/G/irnQLoTR/lxZ5gB6FqUdPqNJHXmn3r6KxrQlxTM97UEZ0hEZHhBvwLk24e4KQitX5oHkNp+XMFCzjaym/Pryfjo4qxde8drr9TmHH1ajVYHkXue2L/RWEDrbUWITgtUP0CgkbAGijhpdJm4xVIMLHOD2cJS2+gChTu85uzdvdowlgHwMB7G5rHR+c1NB/2BV9iwhgVMgVjZlGB0SZmUoPEvPr2ZW2Y56tpnQ5d5zl4GdxImJBTSzoQzEKoGxt94MsXE207I0sp5L0Zzm+p4bDGTU6V0SI+eumemcejIt9O/jlGFFLf539LcU1+qeMWFdpBgB","text":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The location is clearly specified as \"Florence, Italy\" so I have all the required parameters to make the function call.","type":"reasoning.text"}],"reasoning":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The location is clearly specified as \"Florence, Italy\" so I have all the required parameters to make the function call."},{"content":"40 C","tool_call_id":"toolu_01YVA3v6AcXDxaGjsKS8DiUq","role":"tool"}],"model":"anthropic/claude-sonnet-4","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"The current"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" weather in Florence, Italy is 40"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"°C (104°F). That"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'s quite"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" hot!"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" It"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'s a very"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" warm day in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" Florence."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_95h77ud38a"}
+
+ data: {"id":"gen_01KGF3CQFX23W6JXADQ1QTEY98","object":"chat.completion.chunk","created":1770033406,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":548,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":34,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":4956.113352,"endTime":6171.847632,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":4956.113352,"endTime":6171.847632,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002154","marketCost":"0.002154","generationId":"gen_01KGF3CQFX23W6JXADQ1QTEY98","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":548,"completion_tokens":34,"total_tokens":582,"cost":0.002154,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002154},"system_fingerprint":"fp_95h77ud38a","generationId":"gen_01KGF3CQFX23W6JXADQ1QTEY98"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.345717s
diff --git a/providertests/testdata/TestVercelThinking/claude-sonnet-4-sig/thinking.yaml b/providertests/testdata/TestVercelThinking/claude-sonnet-4-sig/thinking.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..574caa7ed5b7490adf1f1d1848c51ae2849e13a1
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/claude-sonnet-4-sig/thinking.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 479
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"anthropic/claude-sonnet-4","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3CESJKXWS3VT4KZ7Z4H0S","object":"chat.completion","created":1770033398,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The location is clearly specified as \"Florence, Italy\" so I have all the required parameters to make the function call.","reasoning_details":[{"type":"reasoning.text","text":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The location is clearly specified as \"Florence, Italy\" so I have all the required parameters to make the function call.","signature":"EqUDCkYICxgCKkB94vhGG6xKjNnGimHMfRxMKRoDnfxu8X0ubqexC/CZ0gU1q1TlbdRN/J4R0tWVpSFl6fFlfjxBILkP/+4vk0rsEgxEmjcKGGfHXogpkvoaDIJiOn8VbzE+KqPLBCIwyk+17OatdTJTKgOrfaX2tZL5Qmx9Mm1mCs2Djj2mmm5pnDwGymarqbOQn4al+112KowCfd3UWJ1pnfvuMtHp4LCLBjiLWnPPq+gZnlgsNecPBSBXKDt73jMGOd0NQBN7lOOZBy2AR9oQzKpCbyH5CY475OUYjbr8Rz+Xi3JIBit+AL96bsHSares7CpY1y2KVT0d8EPZZMmRr2SEK0AYtccALMpN3n/+QTu0eOlC1Jsv1ygyiRhoPszCqW98h/OdlMzWQyLu60Hir9D91svBFCQ1umLHR3wiJQ/fN025OVtiffGmkjcYWuvEChRS+fN21kSeDOcjbU2nqhRBWJc61RFRjJ8scShRpYoTQn5tNOeSsRIgAfzfmYRK1tp3NzhGDbQM/t6ytgrsToE9ehXnyKIKCVknQl5mkfT3Jw5S+xgB","format":"anthropic-claude-v1","index":0}],"tool_calls":[{"id":"toolu_01QueSgW64L24gT3TZdWbizV","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence, Italy\"}"}}],"provider_metadata":{"anthropic":{"usage":{"input_tokens":424,"output_tokens":109,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7765415.569026,"endTime":7767783.415776,"statusCode":200,"providerResponseId":"msg_015136shD3sTPiMES5sYeqsD"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002907","marketCost":"0.002907","generationId":"gen_01KGF3CESJKXWS3VT4KZ7Z4H0S","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":424,"completion_tokens":109,"total_tokens":533,"cost":0.002907,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002907},"system_fingerprint":"fp_zqq5kppgz1","generationId":"gen_01KGF3CESJKXWS3VT4KZ7Z4H0S"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.513099333s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1938
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"toolu_01QueSgW64L24gT3TZdWbizV","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"format":"anthropic-claude-v1","index":0,"signature":"EqUDCkYICxgCKkB94vhGG6xKjNnGimHMfRxMKRoDnfxu8X0ubqexC/CZ0gU1q1TlbdRN/J4R0tWVpSFl6fFlfjxBILkP/+4vk0rsEgxEmjcKGGfHXogpkvoaDIJiOn8VbzE+KqPLBCIwyk+17OatdTJTKgOrfaX2tZL5Qmx9Mm1mCs2Djj2mmm5pnDwGymarqbOQn4al+112KowCfd3UWJ1pnfvuMtHp4LCLBjiLWnPPq+gZnlgsNecPBSBXKDt73jMGOd0NQBN7lOOZBy2AR9oQzKpCbyH5CY475OUYjbr8Rz+Xi3JIBit+AL96bsHSares7CpY1y2KVT0d8EPZZMmRr2SEK0AYtccALMpN3n/+QTu0eOlC1Jsv1ygyiRhoPszCqW98h/OdlMzWQyLu60Hir9D91svBFCQ1umLHR3wiJQ/fN025OVtiffGmkjcYWuvEChRS+fN21kSeDOcjbU2nqhRBWJc61RFRjJ8scShRpYoTQn5tNOeSsRIgAfzfmYRK1tp3NzhGDbQM/t6ytgrsToE9ehXnyKIKCVknQl5mkfT3Jw5S+xgB","text":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The location is clearly specified as \"Florence, Italy\" so I have all the required parameters to make the function call.","type":"reasoning.text"}],"reasoning":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The location is clearly specified as \"Florence, Italy\" so I have all the required parameters to make the function call."},{"content":"40 C","tool_call_id":"toolu_01QueSgW64L24gT3TZdWbizV","role":"tool"}],"model":"anthropic/claude-sonnet-4","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3CH7MBCX5TG98WJF2BTYT","object":"chat.completion","created":1770033402,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"The current weather in Florence, Italy is 40°C (104°F). That''s quite hot! It''s a very warm day in Florence.","provider_metadata":{"anthropic":{"usage":{"input_tokens":548,"output_tokens":34,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1505902.416236,"endTime":1508977.489215,"statusCode":200,"providerResponseId":"msg_01RG65Q4UDkyK2BAznqpD7GE"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002154","marketCost":"0.002154","generationId":"gen_01KGF3CH7MBCX5TG98WJF2BTYT","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":548,"completion_tokens":34,"total_tokens":582,"cost":0.002154,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002154},"system_fingerprint":"fp_9mdcax34m","generationId":"gen_01KGF3CH7MBCX5TG98WJF2BTYT"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 3.165230708s
diff --git a/providertests/testdata/TestVercelThinking/claude-sonnet-4/thinking-streaming.yaml b/providertests/testdata/TestVercelThinking/claude-sonnet-4/thinking-streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..d60e25640403d5d0adff33a0d52e788bdf2a11aa
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/claude-sonnet-4/thinking-streaming.yaml
@@ -0,0 +1,171 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 533
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"anthropic/claude-sonnet-4","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":"The user is asking for","reasoning_details":[{"type":"reasoning.text","text":"The user is asking for","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" weather","reasoning_details":[{"type":"reasoning.text","text":" weather","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" information for Florence, Italy. I have","reasoning_details":[{"type":"reasoning.text","text":" information for Florence, Italy. I have","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" a weather","reasoning_details":[{"type":"reasoning.text","text":" a weather","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" function available","reasoning_details":[{"type":"reasoning.text","text":" function available","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" that takes","reasoning_details":[{"type":"reasoning.text","text":" that takes","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" a location parameter.","reasoning_details":[{"type":"reasoning.text","text":" a location parameter.","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" The","reasoning_details":[{"type":"reasoning.text","text":" The","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" user has","reasoning_details":[{"type":"reasoning.text","text":" user has","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" provided the location as","reasoning_details":[{"type":"reasoning.text","text":" provided the location as","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" \"Florence, Italy\" which","reasoning_details":[{"type":"reasoning.text","text":" \"Florence, Italy\" which","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" is specific","reasoning_details":[{"type":"reasoning.text","text":" is specific","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" enough for","reasoning_details":[{"type":"reasoning.text","text":" enough for","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" the weather function.","reasoning_details":[{"type":"reasoning.text","text":" the weather function.","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" I have","reasoning_details":[{"type":"reasoning.text","text":" I have","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" all the required parameters to make the function","reasoning_details":[{"type":"reasoning.text","text":" all the required parameters to make the function","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":" call.","reasoning_details":[{"type":"reasoning.text","text":" call.","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":"","reasoning_details":[{"type":"reasoning.text","text":"","signature":"","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"reasoning":"","reasoning_details":[{"type":"reasoning.text","text":"","signature":"EtYDCkYICxgCKkD9mnV1Hds6SXvRNDaaVGP9IRFYqdtRgWJOe8g0L7Ud8hYHbJ+xtiLx6BOulBrCSpqk0qL0Ppqn5ZjggFDrpOl9Egxi/ODyXHn/gED5bk8aDDdrhkgNzG+ZAsd/4CIwZMUjUcbSZEuLEEhx8gHG8s25q5UMj5UqA0XYiTXvWMiyDOplOPRYIpyFzeBIzoHTKr0C51eUyyUS9b37iYdk2gZ5G+fU3BJMMgrDaNCSeiT6A47YXYO+w4sN60Fr3fXXyfNewEnfycIkFcsSUeoraqRtMXYmtpZ1U3hTMNf97Ve2ITFHwdKtZqo6KOV3PZEPPXBA8y59K6s+WD8kEKWb3126miv3moQ8fH2A5Dtk9bzXqNtWnAFI97JnnZgvmSH6tqYS2RkHMtj31LPaxYjWjqc2IusllrCoI1WEsu5bpABezlPKEWayq7FHjqUyeF+w4hEkQ4mjRjLHsVfNC2Pb79DEuGttQ8esezKiaVLhWZ8NngPU/Kv0J8Mtc0DTbBxlk58PMwO2zVeLAuthixkX5OiSfVtNVX3DDe4odTAxiFouPl5OOw964A+L6u27r+7nsurLHkZkrw7hpSP7saLGSUUX3++WmIFEZnz/d/cqCU4YAQ==","format":"anthropic-claude-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"toolu_01LCB6569oxJKyPag7eFnnjx","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"loca"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"tio"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"n\": \"Flore"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"nc"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"e,"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Italy\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_moyu1cwxfr"}
+
+ data: {"id":"gen_01KGF3AVVKYFARGPVSM4MZY14H","object":"chat.completion.chunk","created":1770033348,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":424,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":118,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7093511.188939,"endTime":7097175.93529,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7093511.188939,"endTime":7097175.93529,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.003042","marketCost":"0.003042","generationId":"gen_01KGF3AVVKYFARGPVSM4MZY14H","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":424,"completion_tokens":118,"total_tokens":542,"cost":0.003042,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003042},"system_fingerprint":"fp_moyu1cwxfr","generationId":"gen_01KGF3AVVKYFARGPVSM4MZY14H"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 3.850747333s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 2159
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"toolu_01LCB6569oxJKyPag7eFnnjx","function":{"arguments":"{\"location\": \"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"format":"anthropic-claude-v1","index":0,"signature":"EtYDCkYICxgCKkD9mnV1Hds6SXvRNDaaVGP9IRFYqdtRgWJOe8g0L7Ud8hYHbJ+xtiLx6BOulBrCSpqk0qL0Ppqn5ZjggFDrpOl9Egxi/ODyXHn/gED5bk8aDDdrhkgNzG+ZAsd/4CIwZMUjUcbSZEuLEEhx8gHG8s25q5UMj5UqA0XYiTXvWMiyDOplOPRYIpyFzeBIzoHTKr0C51eUyyUS9b37iYdk2gZ5G+fU3BJMMgrDaNCSeiT6A47YXYO+w4sN60Fr3fXXyfNewEnfycIkFcsSUeoraqRtMXYmtpZ1U3hTMNf97Ve2ITFHwdKtZqo6KOV3PZEPPXBA8y59K6s+WD8kEKWb3126miv3moQ8fH2A5Dtk9bzXqNtWnAFI97JnnZgvmSH6tqYS2RkHMtj31LPaxYjWjqc2IusllrCoI1WEsu5bpABezlPKEWayq7FHjqUyeF+w4hEkQ4mjRjLHsVfNC2Pb79DEuGttQ8esezKiaVLhWZ8NngPU/Kv0J8Mtc0DTbBxlk58PMwO2zVeLAuthixkX5OiSfVtNVX3DDe4odTAxiFouPl5OOw964A+L6u27r+7nsurLHkZkrw7hpSP7saLGSUUX3++WmIFEZnz/d/cqCU4YAQ==","text":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The user has provided the location as \"Florence, Italy\" which is specific enough for the weather function. I have all the required parameters to make the function call.","type":"reasoning.text"}],"reasoning":"The user is asking for weather information for Florence, Italy. I have a weather function available that takes a location parameter. The user has provided the location as \"Florence, Italy\" which is specific enough for the weather function. I have all the required parameters to make the function call."},{"content":"40 C","tool_call_id":"toolu_01LCB6569oxJKyPag7eFnnjx","role":"tool"}],"model":"anthropic/claude-sonnet-4","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"The current"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" weather in Florence, Italy is 40"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"°C (104°F). That"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"'s quite"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" hot"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"! This is a"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" high"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" temperature that"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" suggests"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" very"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" warm,"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" potentially"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" uncomfortable"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" weather conditions"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":". You might want to stay"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" hydrated and seek"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" air"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" conditioning"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" or shade if"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" you're planning to be in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" Florence"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":" today"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_wkyq4vz6ii"}
+
+ data: {"id":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","object":"chat.completion.chunk","created":1770033350,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"delta":{"provider_metadata":{"anthropic":{"usage":{"input_tokens":557,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":63,"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1456427.826085,"endTime":1457451.848654,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":1456427.826085,"endTime":1457451.848654,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.002616","marketCost":"0.002616","generationId":"gen_01KGF3B0WTSB5GEBEY54E4B78Q","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":557,"completion_tokens":63,"total_tokens":620,"cost":0.002616,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002616},"system_fingerprint":"fp_wkyq4vz6ii","generationId":"gen_01KGF3B0WTSB5GEBEY54E4B78Q"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 1.12508025s
diff --git a/providertests/testdata/TestVercelThinking/claude-sonnet-4/thinking.yaml b/providertests/testdata/TestVercelThinking/claude-sonnet-4/thinking.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..57198183090a6045a0d282a7eb93476e5d307c52
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/claude-sonnet-4/thinking.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 479
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"anthropic/claude-sonnet-4","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3AQBSB35WNS62SPSARQ6W","object":"chat.completion","created":1770033342,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning":"The user is asking for weather information for Florence, Italy. I have access to a weather function that requires a \"location\" parameter. The user has provided the location as \"Florence, Italy\" which is specific enough to use for the weather query.\n\nI should call the weather function with \"Florence, Italy\" as the location parameter.","reasoning_details":[{"type":"reasoning.text","text":"The user is asking for weather information for Florence, Italy. I have access to a weather function that requires a \"location\" parameter. The user has provided the location as \"Florence, Italy\" which is specific enough to use for the weather query.\n\nI should call the weather function with \"Florence, Italy\" as the location parameter.","signature":"EvcDCkYICxgCKkAcv+JiUJrSmNoeyAKGVOi/csdYyFzgyZwNioa99UTlL/tPju5ML6OZ4LOvKaFwaUZyzcNW4uQLu7jI2eVLu1iBEgz1tmAQP8hgL/Hy0u0aDBov3mK2gXR/f7z0iiIw8orugLuO+L2R5wuK35rGJkQhVHAphISN2F2FNjrGts/gbB+dJtP1ncNCWYFSp2NjKt4Cq7EYeQ0x9ie1oKSCG9n9bGZ0br1TVg4ClNZEQQou4gAMGZonFMnDy0uwPwk5F1rujCQbIJVzttyhb/lVmqUeEy/IFbYDmIi/1MAHlpN8qhX/0NhviIlZGobT7wzZUuNgQYT10+Wr8AfCNuHrMfjN1XnW+72e2p7QmcMEBcR8/sO24stZFAuTrnZytWOrINqsgbuEKcklViQw8RqQNkWUOGlOS+BOWZXIcLinY5LCPftHjLCKrFFG37bGwWKlWpbu9z/whcQ9UVE+TnrIdnhwdhxoljIbuzDBQTuY8MhlOXBzUujm6QaqxOWX0bnyPe+8eq+T1zsq3BLU2OLg5P/6rMZCYxrSjCTSnX0dM/UKxasn7cqT0QwWeVt1hMRDdO3heoFOfQgHmx9w4RuDvlZ9xh0xMKG/Amy8PhqU8tzE8U1+uMCl1PpaOa42MpcWleUklf24hkwZVqM488rdUjIYAQ==","format":"anthropic-claude-v1","index":0}],"tool_calls":[{"id":"toolu_01VvThmBhnhGHEcRJeyCRSHe","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence, Italy\"}"}}],"provider_metadata":{"anthropic":{"usage":{"input_tokens":424,"output_tokens":129,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7088911.419434,"endTime":7091508.412367,"statusCode":200,"providerResponseId":"msg_01Um7d6HWfESfBhnukpiBeuy"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.003207","marketCost":"0.003207","generationId":"gen_01KGF3AQBSB35WNS62SPSARQ6W","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":424,"completion_tokens":129,"total_tokens":553,"cost":0.003207,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.003207},"system_fingerprint":"fp_da7b9rssdj","generationId":"gen_01KGF3AQBSB35WNS62SPSARQ6W"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.754280458s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 2226
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"toolu_01VvThmBhnhGHEcRJeyCRSHe","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning":"The user is asking for weather information for Florence, Italy. I have access to a weather function that requires a \"location\" parameter. The user has provided the location as \"Florence, Italy\" which is specific enough to use for the weather query.\n\nI should call the weather function with \"Florence, Italy\" as the location parameter.","reasoning_details":[{"format":"anthropic-claude-v1","index":0,"signature":"EvcDCkYICxgCKkAcv+JiUJrSmNoeyAKGVOi/csdYyFzgyZwNioa99UTlL/tPju5ML6OZ4LOvKaFwaUZyzcNW4uQLu7jI2eVLu1iBEgz1tmAQP8hgL/Hy0u0aDBov3mK2gXR/f7z0iiIw8orugLuO+L2R5wuK35rGJkQhVHAphISN2F2FNjrGts/gbB+dJtP1ncNCWYFSp2NjKt4Cq7EYeQ0x9ie1oKSCG9n9bGZ0br1TVg4ClNZEQQou4gAMGZonFMnDy0uwPwk5F1rujCQbIJVzttyhb/lVmqUeEy/IFbYDmIi/1MAHlpN8qhX/0NhviIlZGobT7wzZUuNgQYT10+Wr8AfCNuHrMfjN1XnW+72e2p7QmcMEBcR8/sO24stZFAuTrnZytWOrINqsgbuEKcklViQw8RqQNkWUOGlOS+BOWZXIcLinY5LCPftHjLCKrFFG37bGwWKlWpbu9z/whcQ9UVE+TnrIdnhwdhxoljIbuzDBQTuY8MhlOXBzUujm6QaqxOWX0bnyPe+8eq+T1zsq3BLU2OLg5P/6rMZCYxrSjCTSnX0dM/UKxasn7cqT0QwWeVt1hMRDdO3heoFOfQgHmx9w4RuDvlZ9xh0xMKG/Amy8PhqU8tzE8U1+uMCl1PpaOa42MpcWleUklf24hkwZVqM488rdUjIYAQ==","text":"The user is asking for weather information for Florence, Italy. I have access to a weather function that requires a \"location\" parameter. The user has provided the location as \"Florence, Italy\" which is specific enough to use for the weather query.\n\nI should call the weather function with \"Florence, Italy\" as the location parameter.","type":"reasoning.text"}]},{"content":"40 C","tool_call_id":"toolu_01VvThmBhnhGHEcRJeyCRSHe","role":"tool"}],"model":"anthropic/claude-sonnet-4","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3AT2W4QFA7ZW3ASZ8571P","object":"chat.completion","created":1770033344,"model":"anthropic/claude-sonnet-4","choices":[{"index":0,"message":{"role":"assistant","content":"The current weather in Florence, Italy is 40°C (104°F). That''s quite hot! It''s a very warm day in Florence.","provider_metadata":{"anthropic":{"usage":{"input_tokens":568,"output_tokens":34,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"service_tier":"standard"},"cacheCreationInputTokens":0,"stopSequence":null,"container":null},"gateway":{"routing":{"originalModelId":"anthropic/claude-sonnet-4","resolvedProvider":"anthropic","resolvedProviderApiModelId":"claude-sonnet-4-20250514","internalResolvedModelId":"anthropic:claude-sonnet-4-20250514","fallbacksAvailable":["vertexAnthropic","bedrock"],"internalReasoning":"Selected anthropic as preferred provider for claude-sonnet-4. 2 fallback(s) available: vertexAnthropic, bedrock","planningReasoning":"System credentials planned for: anthropic, vertexAnthropic, bedrock. Total execution order: anthropic(system) → vertexAnthropic(system) → bedrock(system)","canonicalSlug":"anthropic/claude-sonnet-4","finalProvider":"anthropic","attempts":[{"provider":"anthropic","internalModelId":"anthropic:claude-sonnet-4-20250514","providerApiModelId":"claude-sonnet-4-20250514","credentialType":"system","success":true,"startTime":7712011.428399,"endTime":7713764.18868,"statusCode":200,"providerResponseId":"msg_01Xc77vidcSXUVZGp5byrDUm"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"anthropic/claude-sonnet-4","canonicalSlug":"anthropic/claude-sonnet-4","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.002214","marketCost":"0.002214","generationId":"gen_01KGF3AT2W4QFA7ZW3ASZ8571P","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":568,"completion_tokens":34,"total_tokens":602,"cost":0.002214,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.002214},"system_fingerprint":"fp_k3wp9lnz45","generationId":"gen_01KGF3AT2W4QFA7ZW3ASZ8571P"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 1.837599167s
diff --git a/providertests/testdata/TestVercelThinking/gemini-3-pro-preview/thinking-streaming.yaml b/providertests/testdata/TestVercelThinking/gemini-3-pro-preview/thinking-streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c43673bda15707364ba05a86f338eb7902dd6828
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/gemini-3-pro-preview/thinking-streaming.yaml
@@ -0,0 +1,87 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 535
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"google/gemini-3-pro-preview","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","object":"chat.completion.chunk","created":1770033385,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_q2vuvpzyv8"}
+
+ data: {"id":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","object":"chat.completion.chunk","created":1770033385,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"reasoning":"**Analyzing the User's Query**\n\nI'm focused on understanding the user's intent. My primary task is to identify the location for the weather query. It's evident the user wants weather data for Florence, Italy. I'll utilize the `weather` tool and set the `location` parameter accordingly.\n\n\n","reasoning_details":[{"type":"reasoning.text","text":"**Analyzing the User's Query**\n\nI'm focused on understanding the user's intent. My primary task is to identify the location for the weather query. It's evident the user wants weather data for Florence, Italy. I'll utilize the `weather` tool and set the `location` parameter accordingly.\n\n\n","format":"google-gemini-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_q2vuvpzyv8"}
+
+ data: {"id":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","object":"chat.completion.chunk","created":1770033385,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"SmUJTLmrRxi0lu0v","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_q2vuvpzyv8"}
+
+ data: {"id":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","object":"chat.completion.chunk","created":1770033385,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"location\":\"Florence, Italy\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_q2vuvpzyv8"}
+
+ data: {"id":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","object":"chat.completion.chunk","created":1770033385,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"reasoning_details":[{"type":"reasoning.encrypted","data":"CiQBjz1rXzHrIG8VyKxoyvNfn34I0fU0MFB3Xbo4yGmi5lXxz9oKZgGPPWtfH7TJlamiXjXsugVyW8VxgOUJprUjmiUwJi/stNqMS3LooRoUA1fBkdgztTDDIGWmRMXQtWqouGUTAeueCke7VJzsJm3GwC5Czg9laR24rLZ/AU+1oJpvT5AmZHm0AYnOGAp3AY89a1+1SkejrgsX83pkwVBjFrYRepT+UEelh8Kexyj/KndelV/yYbA+gWgGGSMKe4zq3JKh99Toc1/OqRXykl9qKTNXZj1xaIkP98KH/4mRnVw4Mvc3mE2R97bmzKTFSxzAlJ7+XFtYnZjg7PiNxuwEiZIlG3kKNAGPPWtfzlrIZvrYjj2PtuKOaHbd5iP/2u4dRMmmPZ8fi8DHZdSpnDnJAKI/TVQikZmdBZo=","format":"google-gemini-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_q2vuvpzyv8"}
+
+ data: {"id":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","object":"chat.completion.chunk","created":1770033385,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":39,"promptTokenCount":28,"candidatesTokenCount":9,"totalTokenCount":76,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7750944.987373,"endTime":7754447.770022,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7750944.987373,"endTime":7754447.770022,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000632","marketCost":"0.000632","generationId":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":28,"completion_tokens":9,"total_tokens":37,"cost":0.000632,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":39,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000632},"system_fingerprint":"fp_q2vuvpzyv8","generationId":"gen_01KGF3C0Q49GHB7YJE7PKYYXEK"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 3.681428625s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1286
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"SmUJTLmrRxi0lu0v","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"data":"CiQBjz1rXzHrIG8VyKxoyvNfn34I0fU0MFB3Xbo4yGmi5lXxz9oKZgGPPWtfH7TJlamiXjXsugVyW8VxgOUJprUjmiUwJi/stNqMS3LooRoUA1fBkdgztTDDIGWmRMXQtWqouGUTAeueCke7VJzsJm3GwC5Czg9laR24rLZ/AU+1oJpvT5AmZHm0AYnOGAp3AY89a1+1SkejrgsX83pkwVBjFrYRepT+UEelh8Kexyj/KndelV/yYbA+gWgGGSMKe4zq3JKh99Toc1/OqRXykl9qKTNXZj1xaIkP98KH/4mRnVw4Mvc3mE2R97bmzKTFSxzAlJ7+XFtYnZjg7PiNxuwEiZIlG3kKNAGPPWtfzlrIZvrYjj2PtuKOaHbd5iP/2u4dRMmmPZ8fi8DHZdSpnDnJAKI/TVQikZmdBZo=","format":"google-gemini-v1","index":0,"type":"reasoning.encrypted"}]},{"content":"40 C","tool_call_id":"SmUJTLmrRxi0lu0v","role":"tool"}],"model":"google/gemini-3-pro-preview","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3C4C0A7ZEXSENPBN82KKW","object":"chat.completion.chunk","created":1770033396,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kt7kxbesam"}
+
+ data: {"id":"gen_01KGF3C4C0A7ZEXSENPBN82KKW","object":"chat.completion.chunk","created":1770033396,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"reasoning":"**Analyzing Weather Data**\n\nI've just received the weather data for Florence. My current task is to clearly convey the 40 degrees Celsius temperature reading to the user. I'm focusing on the best way to present this information so it's easily understood and actionable.\n\n\n","reasoning_details":[{"type":"reasoning.text","text":"**Analyzing Weather Data**\n\nI've just received the weather data for Florence. My current task is to clearly convey the 40 degrees Celsius temperature reading to the user. I'm focusing on the best way to present this information so it's easily understood and actionable.\n\n\n","format":"google-gemini-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kt7kxbesam"}
+
+ data: {"id":"gen_01KGF3C4C0A7ZEXSENPBN82KKW","object":"chat.completion.chunk","created":1770033396,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":"The current weather in Florence"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kt7kxbesam"}
+
+ data: {"id":"gen_01KGF3C4C0A7ZEXSENPBN82KKW","object":"chat.completion.chunk","created":1770033396,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"content":", Italy is 40°C."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_kt7kxbesam"}
+
+ data: {"id":"gen_01KGF3C4C0A7ZEXSENPBN82KKW","object":"chat.completion.chunk","created":1770033396,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"delta":{"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":29,"promptTokenCount":40,"candidatesTokenCount":14,"totalTokenCount":83,"trafficType":"ON_DEMAND"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":1491866.50627,"endTime":1502204.735086,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":1491866.50627,"endTime":1502204.735086,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.000596","marketCost":"0.000596","generationId":"gen_01KGF3C4C0A7ZEXSENPBN82KKW","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":40,"completion_tokens":14,"total_tokens":54,"cost":0.000596,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":29,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000596},"system_fingerprint":"fp_kt7kxbesam","generationId":"gen_01KGF3C4C0A7ZEXSENPBN82KKW"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 10.48104525s
diff --git a/providertests/testdata/TestVercelThinking/gemini-3-pro-preview/thinking.yaml b/providertests/testdata/TestVercelThinking/gemini-3-pro-preview/thinking.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5dc01fb6a05b8f842a1ef95b90b6860815c301ce
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/gemini-3-pro-preview/thinking.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 481
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"google/gemini-3-pro-preview","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3BTEQ7ZXNXTXM5HCM0ZW5","object":"chat.completion","created":1770033379,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning":"**Determining the Weather**\n\nI''ve identified the need for weather data. I believe the `weather` function is a solid choice. It''s now a matter of calling this function. I''ll pass it ''Florence, Italy'' to retrieve the current conditions.\n\n\n","reasoning_details":[{"type":"reasoning.text","text":"**Determining the Weather**\n\nI''ve identified the need for weather data. I believe the `weather` function is a solid choice. It''s now a matter of calling this function. I''ll pass it ''Florence, Italy'' to retrieve the current conditions.\n\n\n","format":"google-gemini-v1","index":0}],"tool_calls":[{"id":"Zwo8e1JcXjoJ0bPs","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence, Italy\"}"}}],"provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"thoughtsTokenCount":67,"promptTokenCount":28,"candidatesTokenCount":9,"totalTokenCount":104,"trafficType":"PROVISIONED_THROUGHPUT"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":390947.964322,"endTime":394738.481613,"statusCode":200,"providerResponseId":"35CAacnTN9X8tfAPg7j5QA"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.000968","marketCost":"0.000968","generationId":"gen_01KGF3BTEQ7ZXNXTXM5HCM0ZW5","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":28,"completion_tokens":9,"total_tokens":37,"cost":0.000968,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":67,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000968},"system_fingerprint":"fp_t3b6jfaxsx","generationId":"gen_01KGF3BTEQ7ZXNXTXM5HCM0ZW5"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 4.135991625s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 1114
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"Zwo8e1JcXjoJ0bPs","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"format":"google-gemini-v1","index":0,"text":"**Determining the Weather**\n\nI''ve identified the need for weather data. I believe the `weather` function is a solid choice. It''s now a matter of calling this function. I''ll pass it ''Florence, Italy'' to retrieve the current conditions.\n\n\n","type":"reasoning.text"},{"format":"google-gemini-v1","index":0,"type":"reasoning.encrypted"}]},{"content":"40 C","tool_call_id":"Zwo8e1JcXjoJ0bPs","role":"tool"}],"model":"google/gemini-3-pro-preview","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3BYDZXE5BFFQQRPX4SSCP","object":"chat.completion","created":1770033382,"model":"google/gemini-3-pro-preview","choices":[{"index":0,"message":{"role":"assistant","content":"The current temperature in Florence, Italy is 40°C.","provider_metadata":{"google":{"promptFeedback":null,"groundingMetadata":null,"urlContextMetadata":null,"safetyRatings":null,"usageMetadata":{"promptTokenCount":97,"candidatesTokenCount":14,"totalTokenCount":111,"trafficType":"PROVISIONED_THROUGHPUT"}},"gateway":{"routing":{"originalModelId":"google/gemini-3-pro-preview","resolvedProvider":"vertex","resolvedProviderApiModelId":"gemini-3-pro-preview","internalResolvedModelId":"vertex:gemini-3-pro-preview","fallbacksAvailable":["google"],"internalReasoning":"Selected vertex as preferred provider for gemini-3-pro-preview. 1 fallback(s) available: google","planningReasoning":"System credentials planned for: vertex, google. Total execution order: vertex(system) → google(system)","canonicalSlug":"google/gemini-3-pro-preview","finalProvider":"vertex","attempts":[{"provider":"vertex","internalModelId":"vertex:gemini-3-pro-preview","providerApiModelId":"gemini-3-pro-preview","credentialType":"system","success":true,"startTime":7748615.626226,"endTime":7750847.973285,"statusCode":200,"providerResponseId":"45CAae7FNaahmPUPueDE6QU"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"google/gemini-3-pro-preview","canonicalSlug":"google/gemini-3-pro-preview","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.000362","marketCost":"0.000362","generationId":"gen_01KGF3BYDZXE5BFFQQRPX4SSCP","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":97,"completion_tokens":14,"total_tokens":111,"cost":0.000362,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.000362},"system_fingerprint":"fp_02078i909k","generationId":"gen_01KGF3BYDZXE5BFFQQRPX4SSCP"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 2.353875042s
diff --git a/providertests/testdata/TestVercelThinking/gpt-5/thinking-streaming.yaml b/providertests/testdata/TestVercelThinking/gpt-5/thinking-streaming.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..289beba53995a94d1dd82af49cef013e8665a480
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/gpt-5/thinking-streaming.yaml
@@ -0,0 +1,343 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 520
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"openai/gpt-5","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"**Getting","reasoning_details":[{"type":"reasoning.summary","summary":"**Getting","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" weather","reasoning_details":[{"type":"reasoning.summary","summary":" weather","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" information","reasoning_details":[{"type":"reasoning.summary","summary":" information","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"**\n\nI","reasoning_details":[{"type":"reasoning.summary","summary":"**\n\nI","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" need","reasoning_details":[{"type":"reasoning.summary","summary":" need","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" to","reasoning_details":[{"type":"reasoning.summary","summary":" to","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" retrieve","reasoning_details":[{"type":"reasoning.summary","summary":" retrieve","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" weather","reasoning_details":[{"type":"reasoning.summary","summary":" weather","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" using","reasoning_details":[{"type":"reasoning.summary","summary":" using","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" designated","reasoning_details":[{"type":"reasoning.summary","summary":" designated","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" tool","reasoning_details":[{"type":"reasoning.summary","summary":" tool","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":",","reasoning_details":[{"type":"reasoning.summary","summary":",","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" specifically","reasoning_details":[{"type":"reasoning.summary","summary":" specifically","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" functions","reasoning_details":[{"type":"reasoning.summary","summary":" functions","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".weather","reasoning_details":[{"type":"reasoning.summary","summary":".weather","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" with","reasoning_details":[{"type":"reasoning.summary","summary":" with","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" location","reasoning_details":[{"type":"reasoning.summary","summary":" location","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" parameter","reasoning_details":[{"type":"reasoning.summary","summary":" parameter","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".","reasoning_details":[{"type":"reasoning.summary","summary":".","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" Even","reasoning_details":[{"type":"reasoning.summary","summary":" Even","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" though","reasoning_details":[{"type":"reasoning.summary","summary":" though","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" there's","reasoning_details":[{"type":"reasoning.summary","summary":" there's","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" a","reasoning_details":[{"type":"reasoning.summary","summary":" a","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" multi","reasoning_details":[{"type":"reasoning.summary","summary":" multi","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"_tool","reasoning_details":[{"type":"reasoning.summary","summary":"_tool","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"_use","reasoning_details":[{"type":"reasoning.summary","summary":"_use","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".parallel","reasoning_details":[{"type":"reasoning.summary","summary":".parallel","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" option","reasoning_details":[{"type":"reasoning.summary","summary":" option","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" for","reasoning_details":[{"type":"reasoning.summary","summary":" for","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" running","reasoning_details":[{"type":"reasoning.summary","summary":" running","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" multiple","reasoning_details":[{"type":"reasoning.summary","summary":" multiple","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" tools","reasoning_details":[{"type":"reasoning.summary","summary":" tools","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":",","reasoning_details":[{"type":"reasoning.summary","summary":",","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" I'm","reasoning_details":[{"type":"reasoning.summary","summary":" I'm","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" focused","reasoning_details":[{"type":"reasoning.summary","summary":" focused","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" on","reasoning_details":[{"type":"reasoning.summary","summary":" on","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" just","reasoning_details":[{"type":"reasoning.summary","summary":" just","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" one","reasoning_details":[{"type":"reasoning.summary","summary":" one","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" tool","reasoning_details":[{"type":"reasoning.summary","summary":" tool","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" here","reasoning_details":[{"type":"reasoning.summary","summary":" here","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":",","reasoning_details":[{"type":"reasoning.summary","summary":",","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" so","reasoning_details":[{"type":"reasoning.summary","summary":" so","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" I'll","reasoning_details":[{"type":"reasoning.summary","summary":" I'll","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" go","reasoning_details":[{"type":"reasoning.summary","summary":" go","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" ahead","reasoning_details":[{"type":"reasoning.summary","summary":" ahead","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" and","reasoning_details":[{"type":"reasoning.summary","summary":" and","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" call","reasoning_details":[{"type":"reasoning.summary","summary":" call","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" functions","reasoning_details":[{"type":"reasoning.summary","summary":" functions","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".weather","reasoning_details":[{"type":"reasoning.summary","summary":".weather","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" directly","reasoning_details":[{"type":"reasoning.summary","summary":" directly","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" with","reasoning_details":[{"type":"reasoning.summary","summary":" with","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" \"","reasoning_details":[{"type":"reasoning.summary","summary":" \"","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"Flor","reasoning_details":[{"type":"reasoning.summary","summary":"Flor","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"ence","reasoning_details":[{"type":"reasoning.summary","summary":"ence","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":",","reasoning_details":[{"type":"reasoning.summary","summary":",","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" Italy","reasoning_details":[{"type":"reasoning.summary","summary":" Italy","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".\"","reasoning_details":[{"type":"reasoning.summary","summary":".\"","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" I'll","reasoning_details":[{"type":"reasoning.summary","summary":" I'll","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" make","reasoning_details":[{"type":"reasoning.summary","summary":" make","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" sure","reasoning_details":[{"type":"reasoning.summary","summary":" sure","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" to","reasoning_details":[{"type":"reasoning.summary","summary":" to","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" use","reasoning_details":[{"type":"reasoning.summary","summary":" use","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" commentary","reasoning_details":[{"type":"reasoning.summary","summary":" commentary","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" channel","reasoning_details":[{"type":"reasoning.summary","summary":" channel","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" for","reasoning_details":[{"type":"reasoning.summary","summary":" for","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" this","reasoning_details":[{"type":"reasoning.summary","summary":" this","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" call","reasoning_details":[{"type":"reasoning.summary","summary":" call","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".","reasoning_details":[{"type":"reasoning.summary","summary":".","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" Once","reasoning_details":[{"type":"reasoning.summary","summary":" Once","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" I","reasoning_details":[{"type":"reasoning.summary","summary":" I","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" receive","reasoning_details":[{"type":"reasoning.summary","summary":" receive","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" weather","reasoning_details":[{"type":"reasoning.summary","summary":" weather","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" response","reasoning_details":[{"type":"reasoning.summary","summary":" response","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":",","reasoning_details":[{"type":"reasoning.summary","summary":",","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" I'll","reasoning_details":[{"type":"reasoning.summary","summary":" I'll","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" present","reasoning_details":[{"type":"reasoning.summary","summary":" present","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" the","reasoning_details":[{"type":"reasoning.summary","summary":" the","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" information","reasoning_details":[{"type":"reasoning.summary","summary":" information","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" clearly","reasoning_details":[{"type":"reasoning.summary","summary":" clearly","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" and","reasoning_details":[{"type":"reasoning.summary","summary":" and","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" succinct","reasoning_details":[{"type":"reasoning.summary","summary":" succinct","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"ly","reasoning_details":[{"type":"reasoning.summary","summary":"ly","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":".","reasoning_details":[{"type":"reasoning.summary","summary":".","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" Let's","reasoning_details":[{"type":"reasoning.summary","summary":" Let's","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":" go","reasoning_details":[{"type":"reasoning.summary","summary":" go","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning":"!","reasoning_details":[{"type":"reasoning.summary","summary":"!","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"reasoning_details":[{"type":"reasoning.encrypted","data":"gAAAAABpgJDXAuR0HjlWRtFfesnymrYPPQR9I9gY-4gyB4kiZ_mdXFEOJLsYevTBaNB1wjNviCSnJU0F9Icw2vm542wsByAW0SCh-u5tckaejCd1Eo5gMrgWWSwGKT3xmHzZHMjqxkUGG7orIHGQlIZPr7pHwxTGLp8jmQK_mH7oiDADSjmclCD73KGLOoLlYQLMTq1HGZHAKjCtv-l7uNB1Vst33Hnd2rwayvRXRCQBtgZwotY7AE4vF2Em3pOZSiWu-1u0FkkDhOQd9QupaKRTcPX5PZpFG_FfD6Elwsp-MMH4wtpk96WDc7y0dLouWW5H_pxblrvXQqbpeFVyk1wJ9Xzy7NjcJYnVwt04rdtUjqXBwFJN0HOtYH8TvW2u3mz8x-nj29UxwRMtzPDwXLoAiSRYo6KAZRU4cryLCqiOlTMB3Yedr0RuWkIWU4_oO38whChA8vawvTlcHgPPEYeKAlmEYyOR4mlDAR-r6zGw6fFCSjQ_J9HdlOpeLXm-Y-a5WFzl_FXYE0CVqUzBMMR2PSs6VO4DR73ATdl62SIVW-4kLgPYVurYyv8VUM3H1Z_bb2kInDpqXwK2IUwX08BNRnMvi_wPvm7pTEeKQCxj9-D8rLTIsK8C2tfaDZReKhCymy0KBF9UWDFKlHcM58zU1N7o2YHfVO6b61SWYLra4H7eewBv2levoiSoeVFjar787rf8bqeoPn-mkwASjgKWyDvUwcsLA2vMm8eMclk4qryY8LbgCvX320Zo5byUXblt9f2wTDZhQblmXLaW-9vTBjrbPqtDc2LW_ZkLoSApnrlQxvu0AnaqVUDGHVFERlbZcuU35JJ-","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","format":"openai-responses-v1","index":0}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_0bKx1gHreGnPuO8CzsleyyRQ","type":"function","function":{"name":"weather","arguments":""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"location"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\":\""}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"Flor"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"ence"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":","}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":" Italy"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"}"}}]},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5gf37iohnb"}
+
+ data: {"id":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","object":"chat.completion.chunk","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_0430adf43712f48201698090d6c4048196b485fe56c0face13","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1725623.377813,"endTime":1725855.622852,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1725623.377813,"endTime":1725855.622852,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.00219875","marketCost":"0.00219875","generationId":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":63,"completion_tokens":148,"total_tokens":211,"cost":0.00219875,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":64,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00219875},"system_fingerprint":"fp_5gf37iohnb","generationId":"gen_01KGF3BHK17PHK9V9DEN2A1ZAE"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 339.492ms
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 2375
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"call_0bKx1gHreGnPuO8CzsleyyRQ","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"format":"openai-responses-v1","index":0,"summary":"**Getting weather information**\n\nI need to retrieve the weather using the designated tool, specifically the functions.weather with the location parameter. Even though there''s a multi_tool_use.parallel option for running multiple tools, I''m focused on just one tool here, so I''ll go ahead and call functions.weather directly with \"Florence, Italy.\" I''ll make sure to use the commentary channel for this call. Once I receive the weather response, I''ll present the information clearly and succinctly. Let''s go!","type":"reasoning.summary"},{"data":"gAAAAABpgJDXAuR0HjlWRtFfesnymrYPPQR9I9gY-4gyB4kiZ_mdXFEOJLsYevTBaNB1wjNviCSnJU0F9Icw2vm542wsByAW0SCh-u5tckaejCd1Eo5gMrgWWSwGKT3xmHzZHMjqxkUGG7orIHGQlIZPr7pHwxTGLp8jmQK_mH7oiDADSjmclCD73KGLOoLlYQLMTq1HGZHAKjCtv-l7uNB1Vst33Hnd2rwayvRXRCQBtgZwotY7AE4vF2Em3pOZSiWu-1u0FkkDhOQd9QupaKRTcPX5PZpFG_FfD6Elwsp-MMH4wtpk96WDc7y0dLouWW5H_pxblrvXQqbpeFVyk1wJ9Xzy7NjcJYnVwt04rdtUjqXBwFJN0HOtYH8TvW2u3mz8x-nj29UxwRMtzPDwXLoAiSRYo6KAZRU4cryLCqiOlTMB3Yedr0RuWkIWU4_oO38whChA8vawvTlcHgPPEYeKAlmEYyOR4mlDAR-r6zGw6fFCSjQ_J9HdlOpeLXm-Y-a5WFzl_FXYE0CVqUzBMMR2PSs6VO4DR73ATdl62SIVW-4kLgPYVurYyv8VUM3H1Z_bb2kInDpqXwK2IUwX08BNRnMvi_wPvm7pTEeKQCxj9-D8rLTIsK8C2tfaDZReKhCymy0KBF9UWDFKlHcM58zU1N7o2YHfVO6b61SWYLra4H7eewBv2levoiSoeVFjar787rf8bqeoPn-mkwASjgKWyDvUwcsLA2vMm8eMclk4qryY8LbgCvX320Zo5byUXblt9f2wTDZhQblmXLaW-9vTBjrbPqtDc2LW_ZkLoSApnrlQxvu0AnaqVUDGHVFERlbZcuU35JJ-","format":"openai-responses-v1","id":"rs_0430adf43712f48201698090d71990819682f523d5f4a4cd6a","index":0,"type":"reasoning.encrypted"}]},{"content":"40 C","tool_call_id":"call_0bKx1gHreGnPuO8CzsleyyRQ","role":"tool"}],"model":"openai/gpt-5","stream_options":{"include_usage":true},"tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true},"stream":true}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ body: |+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"role":"assistant"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"It"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"’s"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" currently"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" around"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" "},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"40"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"°C"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" Florence"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" Italy"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" If"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" you"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"’d"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" like"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":","},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" I"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" can"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" also"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" provide"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" a"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" brief"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" forecast"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" or"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" tips"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" for"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" staying"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" cool"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" in"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" the"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":" heat"},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"content":"."},"logprobs":null,"finish_reason":null}],"system_fingerprint":"fp_5vwx38gjaf"}
+
+ data: {"id":"gen_01KGF3BP39K37NP6M0N1QWVXE1","object":"chat.completion.chunk","created":1770033371,"model":"openai/gpt-5","choices":[{"index":0,"delta":{"provider_metadata":{"openai":{"responseId":"resp_0430adf43712f48201698090db6338819696794d34dd844e52","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1477248.277749,"endTime":1477458.808981,"statusCode":200}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":true,"providerAttemptCount":1,"providerAttempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1477248.277749,"endTime":1477458.808981,"statusCode":200}]}],"totalProviderAttemptCount":1},"cost":"0.00049125","marketCost":"0.00049125","generationId":"gen_01KGF3BP39K37NP6M0N1QWVXE1","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":97,"completion_tokens":37,"total_tokens":134,"cost":0.00049125,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":0,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00049125},"system_fingerprint":"fp_5vwx38gjaf","generationId":"gen_01KGF3BP39K37NP6M0N1QWVXE1"}
+
+ data: [DONE]
+
+ headers:
+ Content-Type:
+ - text/event-stream
+ status: 200 OK
+ code: 200
+ duration: 304.872667ms
diff --git a/providertests/testdata/TestVercelThinking/gpt-5/thinking.yaml b/providertests/testdata/TestVercelThinking/gpt-5/thinking.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..0b1b34f723c33da6890fbcba75507b7f04e321b6
--- /dev/null
+++ b/providertests/testdata/TestVercelThinking/gpt-5/thinking.yaml
@@ -0,0 +1,63 @@
+---
+version: 2
+interactions:
+- id: 0
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 466
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"}],"model":"openai/gpt-5","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3B3C7Q42KHM2W985XF2T3","object":"chat.completion","created":1770033356,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":null,"reasoning":"**Checking weather in Florence**\n\nI need to answer the user regarding the weather in Florence, Italy. I have access to a functions.weather tool for this purpose. Since we''re only calling one tool, I don’t need to use the multi_tool_use feature, which is meant for parallel calls. I’ll simply use functions.weather directly. I’ll provide the location as \"Florence, Italy\" and then wait for the results. Fingers crossed the tool gives us the correct data!","reasoning_details":[{"type":"reasoning.summary","summary":"**Checking weather in Florence**\n\nI need to answer the user regarding the weather in Florence, Italy. I have access to a functions.weather tool for this purpose. Since we''re only calling one tool, I don’t need to use the multi_tool_use feature, which is meant for parallel calls. I’ll simply use functions.weather directly. I’ll provide the location as \"Florence, Italy\" and then wait for the results. Fingers crossed the tool gives us the correct data!","id":"rs_0562170428b0ad7001698090c89354819687c27b2705c3ce4c","format":"openai-responses-v1","index":0},{"type":"reasoning.encrypted","data":"gAAAAABpgJDMsf0VPNBZL3A8tONVzmCdRytZjL7k3QaiavhXgEfFZ0_E6LPvHdpQha_hZs16TnpTURpI-a0UEqxQ0ogIISECklCdduz3wdG0_h55n2hL-NL07dwRdFhygz4tmLJo9mqbUsn1D0uWEu-4afSiPP1HUVoyM3P-XAqG0iDZBG0S3MTxzLCkS9kRgQlzROJlaXEmEB9AJdyFXmb7zAABESJ5kGlH6sT0Iakwvl8vVr34M-OwgYCCGQ6ppz-m0UQmNhCBlcq08d8KkpYElyOQ8hbbykatWslxGZzBWLz7leWClihD4iMM72zbWnwXZDshOqp4lObx1TZuLlDI_naQj6yNXVMRolOSq7g_SygrgJ4o8vmDWUu8Tt_pAHcjWTbzhhTOo-X0-OubpEPgOdjvjdGnQ3tuS5BZs39XVsN0CL2L_XzL6zdVKGdCkqEwoiXjJSLtSFZLgQvn5bzmIPY0II0xX4CAeSN8oHhE4CnocBqWrU3PRaKPHM0WypqB0UuM254n_cZBvdKC9OaJfWKmVbdI1H5R0arzb3KYBG8DXpuWVO354MtLSZ6ZaqxJDNapHX9nwGZ2muBBzYSqxsdYFuLSxz3J-uAwA8YM8o6yb8otfhXrmiHS_562EofNf1yKoFX2j4lACJFTFRWpDRl-ytnfW_VCXvdEelBlmB40JuFu6qy_lF0_g-CndYzGXOi714BIPR0dvcNOLpX_w71QA4WHJUvm7udhzvcHvIkNZHu3O8lUl7htEJGYnx-6x1vn_XLJBD47TUi4QbbuvmqPcHVfbQ5Z-9Hn-Dc9JMGXhao72RRnilCBeiJcJmjTYTWn4JjgE0yMr9BdJjQv9j5E2p3oPHIB2Dqw1FiIHpw1VaGan4T8N3yRPD6-AinoZggBNkULFTS0lWBPPI0vk4uMWIruJS5l7z8rs08PsBS5kTk6-J4IEp-3--Yy5YJND8Z_zboGaKewpWFeft0FqRklGdJ00e_FGaPD2aOfcOygzlCtKumLhU2XG_E8VvGxjz4-TLlzM3LR35Hgm03amQVV_20JMdI1XB_OSoPKoGCZubzBQsf7E_8zVj23J3wVkFEv6o1Fh4XJ4unWcLeQjjLvT7Bkv-smny6wWN-Fd6SM9yU8fMlTHbRCCVdcGRN6QjcX1K5eOiI8U4qmvQw8Tn9_MtMejUdEkWdiKxACIhOhAqJRlTl8JwQL9ggL1gc4iVMepQuaSvauSVjNWalgq94e-k1tSSkobHt6yGD3Fd9jUwyC6KrWraEWR7tmbWesc1KR_zbsd9J_B57szRFLz0JU6GmTCwRM9sblytuCLLdIeW8FLlqIRyhkYm5HrgKyoYwBLp9yOkfllj6C35ZW5ZTOpLNhmeDi3BOLMh6IvMgak4TCaNJjvmPD7ZVU6Y_--LOe_SCJta3yppo2f4-eOduTsUXcXC-gmpbvAhUBgIyOV55OTSE8OGYHZ86sTdF7UVnzftznjQ-5mZKPiHMTNgastAmdKdNhcjDunKlL-qbyEsX4Eeb9TKXM2koCcxZ-Dfs84wSS","id":"rs_0562170428b0ad7001698090c89354819687c27b2705c3ce4c","format":"openai-responses-v1","index":0}],"tool_calls":[{"id":"call_iHMVWYLENDMIMaQBppQsnQ2Y","type":"function","function":{"name":"weather","arguments":"{\"location\":\"Florence, Italy\"}"}}],"provider_metadata":{"openai":{"responseId":"resp_0562170428b0ad7001698090c836608196820886f8d884db01","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":1469621.176344,"endTime":1473996.358343,"statusCode":200,"providerResponseId":"resp_0562170428b0ad7001698090c836608196820886f8d884db01"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.00215875","marketCost":"0.00215875","generationId":"gen_01KGF3B3C7Q42KHM2W985XF2T3","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"tool_calls"}],"usage":{"prompt_tokens":63,"completion_tokens":144,"total_tokens":207,"cost":0.00215875,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":64,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00215875},"system_fingerprint":"fp_5jkdir3bke","generationId":"gen_01KGF3B3C7Q42KHM2W985XF2T3"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 4.531842958s
+- id: 1
+ request:
+ proto: HTTP/1.1
+ proto_major: 1
+ proto_minor: 1
+ content_length: 2977
+ host: ""
+ body: '{"messages":[{"content":"You are a helpful assistant","role":"system"},{"content":"What''s the weather in Florence, Italy?","role":"user"},{"tool_calls":[{"id":"call_iHMVWYLENDMIMaQBppQsnQ2Y","function":{"arguments":"{\"location\":\"Florence, Italy\"}","name":"weather"},"type":"function"}],"role":"assistant","reasoning_details":[{"format":"openai-responses-v1","index":0,"summary":"**Checking weather in Florence**\n\nI need to answer the user regarding the weather in Florence, Italy. I have access to a functions.weather tool for this purpose. Since we''re only calling one tool, I don’t need to use the multi_tool_use feature, which is meant for parallel calls. I’ll simply use functions.weather directly. I’ll provide the location as \"Florence, Italy\" and then wait for the results. Fingers crossed the tool gives us the correct data!","type":"reasoning.summary"},{"data":"gAAAAABpgJDMsf0VPNBZL3A8tONVzmCdRytZjL7k3QaiavhXgEfFZ0_E6LPvHdpQha_hZs16TnpTURpI-a0UEqxQ0ogIISECklCdduz3wdG0_h55n2hL-NL07dwRdFhygz4tmLJo9mqbUsn1D0uWEu-4afSiPP1HUVoyM3P-XAqG0iDZBG0S3MTxzLCkS9kRgQlzROJlaXEmEB9AJdyFXmb7zAABESJ5kGlH6sT0Iakwvl8vVr34M-OwgYCCGQ6ppz-m0UQmNhCBlcq08d8KkpYElyOQ8hbbykatWslxGZzBWLz7leWClihD4iMM72zbWnwXZDshOqp4lObx1TZuLlDI_naQj6yNXVMRolOSq7g_SygrgJ4o8vmDWUu8Tt_pAHcjWTbzhhTOo-X0-OubpEPgOdjvjdGnQ3tuS5BZs39XVsN0CL2L_XzL6zdVKGdCkqEwoiXjJSLtSFZLgQvn5bzmIPY0II0xX4CAeSN8oHhE4CnocBqWrU3PRaKPHM0WypqB0UuM254n_cZBvdKC9OaJfWKmVbdI1H5R0arzb3KYBG8DXpuWVO354MtLSZ6ZaqxJDNapHX9nwGZ2muBBzYSqxsdYFuLSxz3J-uAwA8YM8o6yb8otfhXrmiHS_562EofNf1yKoFX2j4lACJFTFRWpDRl-ytnfW_VCXvdEelBlmB40JuFu6qy_lF0_g-CndYzGXOi714BIPR0dvcNOLpX_w71QA4WHJUvm7udhzvcHvIkNZHu3O8lUl7htEJGYnx-6x1vn_XLJBD47TUi4QbbuvmqPcHVfbQ5Z-9Hn-Dc9JMGXhao72RRnilCBeiJcJmjTYTWn4JjgE0yMr9BdJjQv9j5E2p3oPHIB2Dqw1FiIHpw1VaGan4T8N3yRPD6-AinoZggBNkULFTS0lWBPPI0vk4uMWIruJS5l7z8rs08PsBS5kTk6-J4IEp-3--Yy5YJND8Z_zboGaKewpWFeft0FqRklGdJ00e_FGaPD2aOfcOygzlCtKumLhU2XG_E8VvGxjz4-TLlzM3LR35Hgm03amQVV_20JMdI1XB_OSoPKoGCZubzBQsf7E_8zVj23J3wVkFEv6o1Fh4XJ4unWcLeQjjLvT7Bkv-smny6wWN-Fd6SM9yU8fMlTHbRCCVdcGRN6QjcX1K5eOiI8U4qmvQw8Tn9_MtMejUdEkWdiKxACIhOhAqJRlTl8JwQL9ggL1gc4iVMepQuaSvauSVjNWalgq94e-k1tSSkobHt6yGD3Fd9jUwyC6KrWraEWR7tmbWesc1KR_zbsd9J_B57szRFLz0JU6GmTCwRM9sblytuCLLdIeW8FLlqIRyhkYm5HrgKyoYwBLp9yOkfllj6C35ZW5ZTOpLNhmeDi3BOLMh6IvMgak4TCaNJjvmPD7ZVU6Y_--LOe_SCJta3yppo2f4-eOduTsUXcXC-gmpbvAhUBgIyOV55OTSE8OGYHZ86sTdF7UVnzftznjQ-5mZKPiHMTNgastAmdKdNhcjDunKlL-qbyEsX4Eeb9TKXM2koCcxZ-Dfs84wSS","format":"openai-responses-v1","id":"rs_0562170428b0ad7001698090c89354819687c27b2705c3ce4c","index":0,"type":"reasoning.encrypted"}]},{"content":"40 C","tool_call_id":"call_iHMVWYLENDMIMaQBppQsnQ2Y","role":"tool"}],"model":"openai/gpt-5","tool_choice":"auto","tools":[{"function":{"name":"weather","strict":false,"description":"Get weather information for a location","parameters":{"properties":{"location":{"description":"the city","type":"string"}},"required":["location"],"type":"object"}},"type":"function"}],"reasoning":{"enabled":true}}'
+ headers:
+ Accept:
+ - application/json
+ Content-Type:
+ - application/json
+ User-Agent:
+ - OpenAI/Go 2.7.1
+ url: https://ai-gateway.vercel.sh/v1/chat/completions
+ method: POST
+ response:
+ proto: HTTP/2.0
+ proto_major: 2
+ proto_minor: 0
+ content_length: -1
+ uncompressed: true
+ body: '{"id":"gen_01KGF3B7PMN3C6EZGFX1P9A78S","object":"chat.completion","created":1770033366,"model":"openai/gpt-5","choices":[{"index":0,"message":{"role":"assistant","content":"Right now in Florence, Italy it’s about 40°C (104°F). Want a forecast or more details?","reasoning":"**Presenting the temperature**\n\nThe tool returned \"40 C,\" which feels a bit too brief. I think I should present this clearly to the user. Converting 40 C to Fahrenheit gives us 104 F. I want to keep it concise, so I’ll say, \"Right now in Florence, it’s about 40°C (104°F).\" I should also offer to get a forecast or details like humidity, while sticking with the details that are most relevant and avoiding assumptions about the weather.**Considering the heat advisory**\n\nI realize that 40 C is extremely hot! I could include a simple advisory like \"stay hydrated,\" but it might come off as unsolicited. Since the instructions emphasize being concise, I think I’ll keep the final message straightforward: \"Right now in Florence, Italy, it''s around 40°C (104°F). Would you like a forecast or more details?\" That way, I’m providing the info without overstepping.","reasoning_details":[{"type":"reasoning.summary","summary":"**Presenting the temperature**\n\nThe tool returned \"40 C,\" which feels a bit too brief. I think I should present this clearly to the user. Converting 40 C to Fahrenheit gives us 104 F. I want to keep it concise, so I’ll say, \"Right now in Florence, it’s about 40°C (104°F).\" I should also offer to get a forecast or details like humidity, while sticking with the details that are most relevant and avoiding assumptions about the weather.**Considering the heat advisory**\n\nI realize that 40 C is extremely hot! I could include a simple advisory like \"stay hydrated,\" but it might come off as unsolicited. Since the instructions emphasize being concise, I think I’ll keep the final message straightforward: \"Right now in Florence, Italy, it''s around 40°C (104°F). Would you like a forecast or more details?\" That way, I’m providing the info without overstepping.","id":"rs_0562170428b0ad7001698090cd65008196b1811384c1eb1d6c","format":"openai-responses-v1","index":0},{"type":"reasoning.encrypted","data":"gAAAAABpgJDWD7uuI9cHJYRhaE0aumxBFm7lcXL0q4zfSOYK50X0LE6YwVz7CUc7g6HDCOxpi78m5CX5xe4sR7mloQRkr8YuAFOv_draZ0tZ21FJhKoEr7x8XyzCgrx-Mxv98HGsZE7V3cF61q8b4VZVb4r5MAPDCaZyUINTj2tLAdZChdxpwq4ZBDGhUVrYdqoPbFZm-rx9gkWOKSP7ir9aWU3L5qkQcay0i7zYj0p2Gp8iL1A--48RYacfVaXOgpfYGCBvo0whLwTVtjXxCy0_OEmkSp4bMjkd9dq3PibuD_XwN5mU3QxPW-qiF1zwsS26WQ1Zw0xwvg188l5-MMSaWhJZkZdkWFGmsmazBglfMOncPQO3khM2158ca0W6aeo0WryrEQWNeb37sJjrT258fQ_0NA9Udn0YWUXWdOndCXM7el37_JqxB-4fng9iseMEM9jx5wJ4gtinOVovootaQPYe8Vg68juw0FWgcywsJsbK1GKZNaT7-ISsgcy6Cq8uijY6S9jDn2mUxry1PZz702OrpQSkuYn_YLwXM3bPBsMIn_5sTTm4Z4FZUEXVHndT5U5-klkfzBtAYXpA1cnT65_FVqZydKo_KSLYwbssjUZL8K2QCq1MWJ8X2Lq84i0lmbX-i8Nh205TEi31ub_syPKa-pQ-r-6W0glXUCUTIuqpvGMthEOGb6YVeBhVkzenPtPSeVXWeF0oHZuuQpFbfaF2m1lxGIkETgowuRvDU7S2UOb-B1kTfDpzfFsgxXHtbBhE03tw49_EU5h8h-fCBxiR8Tc6ZylJsAUsEszEH0ofcsuF33IrhTpbLlCXN3wsfSucUq9O4NtgLO-B5VuqPOdFTJ4mbR70C_Cve-Wt4VmGekrsmD1wTImf0o9X3d_ZvZ190dkG7XDAJRDdCMK5uflIBY-fYb7TEKqtnV9WrGR1wY38lpJDzboxOXit99XOHGL64z5oCiD9K0_4BPTRbaHL9Gn8ohO4lQo0NIN4wGRD2YYHaPPjFDK4Fgr_sq8JVp4GsdZ82VyhWjE9XmX2L6VMZff44je18xTHbCRNU0BnTlkpqYea_LFip7pdZcbITnMgDrZi9zrqEpx5AjVoqBr3v7tsLP206LYwQ2g1KjNzhTStPgw3FEyKgcfrLDD9FQ7xjmvHRGWAQ_29MdVTG93M8ypEE77GkMf4AdDwa0uXOhw-k7wJe3QR206ZFzZT4fn1sDy55O0_1F-fmoPm9Ow1Cuw7W0p2oZgBShQU_IhVR3NtRF269WM28bCoCyohF71tgSzMm_dyW2qtkPhptO6Xpw2r2xUpH7AqPIC073m8O3PvfPnmr_MKQ6tS6mUH5sOqu8wrqhwuLsM3j3Pcze-2sCb8gRsw7UfrE0ed_ZTbJmbWRZbKSbX7nvGs_TVB4SpKTCe8VNtmk_4CKc0TP0ZHimi_O8CkOUn7WE7edN--E-6xuZxA47IsE1DkLXtJPuAbJZrk2XshkePp-icDeWPQ0csiLAriBRFlZQBiquXNWBsALiZK0RdchPSq5uLOPVEisXlzPgDAalfxNY2eti3vxTMIAGjZnu4QBYIrd4bUg2AAA9d5OX-TsSO0m3j1lS2sHtekYdr34ofA5dT0ntWdsaQ2WS-8WHYDmGN7TZBcfTJC784EPpoKXuTIwr9NiUAB71FRyk_wY6TdhoDqDw4KtCw28l1QMXGFK3wv0koIHOGVCjuB5IQK7NWNnyned5kSqVgkGY-epfBtvEdcdc7CCBcA7yf-qoGd7idCBnjqcMszsKMD2d95sDDO3nqNV51vhjfA9fxuo-HlGNv12PbsePQTZXSzRM9kVX7jWiu-MFgUfPtZrzYMVh97QA586AZH40Zp5D2NZpfpFFCHFxWCHbhtRhklzeBu1gQ-iWmpxzns2XypqiL5STk4JeBYoav4B7-ypRBO8mwQUEzheZgKO5Hi0jWElzqcWvO2sAouwciUP7-8Tjl0NDLAs7MzuvwtCkzH8o9ikw1vR8MmLToCgUZ1BFHZn5_EH-VWGiZ0x2kikoLM-iHi0fBFUcdj2XrVQ4mnU6IbHh2ST4Xfltx7CmssTxVvK357mX_5Aq5U-13XAJRjGaYX1rsclnudN8N2ib8LYiukfq_Rqxzxdm0QjLuc-vdGLm5V2vdJ2qX5fwrVMaVJgwt393P42SsVoyzkYPpwn4eXfiQssdjPdLkJpLFcjQ==","id":"rs_0562170428b0ad7001698090cd65008196b1811384c1eb1d6c","format":"openai-responses-v1","index":0}],"provider_metadata":{"openai":{"responseId":"resp_0562170428b0ad7001698090ccce248196b6d739df157f9b65","serviceTier":"default"},"gateway":{"routing":{"originalModelId":"openai/gpt-5","resolvedProvider":"openai","resolvedProviderApiModelId":"gpt-5-2025-08-07","internalResolvedModelId":"openai:gpt-5-2025-08-07","fallbacksAvailable":["azure"],"internalReasoning":"Selected openai as preferred provider for gpt-5. 1 fallback(s) available: azure","planningReasoning":"System credentials planned for: openai, azure. Total execution order: openai(system) → azure(system)","canonicalSlug":"openai/gpt-5","finalProvider":"openai","attempts":[{"provider":"openai","internalModelId":"openai:gpt-5-2025-08-07","providerApiModelId":"gpt-5-2025-08-07","credentialType":"system","success":true,"startTime":7725848.499705,"endTime":7735703.317098,"statusCode":200,"providerResponseId":"resp_0562170428b0ad7001698090ccce248196b6d739df157f9b65"}],"modelAttemptCount":1,"modelAttempts":[{"modelId":"openai/gpt-5","canonicalSlug":"openai/gpt-5","success":false,"providerAttemptCount":0,"providerAttempts":[]}],"totalProviderAttemptCount":0},"cost":"0.00479","marketCost":"0.00479","generationId":"gen_01KGF3B7PMN3C6EZGFX1P9A78S","billableWebSearchCalls":0}}},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":216,"completion_tokens":260,"total_tokens":476,"cost":0.00479,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0,"upstream_inference_completions_cost":0},"completion_tokens_details":{"reasoning_tokens":192,"image_tokens":0},"cache_creation_input_tokens":0,"market_cost":0.00479},"system_fingerprint":"fp_bemblx56dt","generationId":"gen_01KGF3B7PMN3C6EZGFX1P9A78S"}'
+ headers:
+ Content-Type:
+ - application/json
+ status: 200 OK
+ code: 200
+ duration: 10.00759025s
diff --git a/providertests/vercel_test.go b/providertests/vercel_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..0361ec0bafc8cc5b6b129a785790e9de02d279f4
--- /dev/null
+++ b/providertests/vercel_test.go
@@ -0,0 +1,124 @@
+package providertests
+
+import (
+ "net/http"
+ "os"
+ "testing"
+
+ "charm.land/fantasy"
+ "charm.land/fantasy/providers/anthropic"
+ "charm.land/fantasy/providers/vercel"
+ "charm.land/x/vcr"
+ "github.com/stretchr/testify/require"
+)
+
+var vercelTestModels = []testModel{
+ {"claude-sonnet-4", "anthropic/claude-sonnet-4", true},
+ {"gemini-2.5-flash", "google/gemini-2.5-flash", false},
+ {"gpt-5", "openai/gpt-5", true},
+ {"gemini-3-pro-preview", "google/gemini-3-pro-preview", true},
+}
+
+func TestVercelCommon(t *testing.T) {
+ var pairs []builderPair
+ for _, m := range vercelTestModels {
+ pairs = append(pairs, builderPair{m.name, vercelBuilder(m.model), nil, nil})
+ }
+ testCommon(t, pairs)
+}
+
+func TestVercelCommonWithAnthropicCache(t *testing.T) {
+ testCommon(t, []builderPair{
+ {"claude-sonnet-4", vercelBuilder("anthropic/claude-sonnet-4"), nil, addAnthropicCaching},
+ })
+}
+
+func TestVercelThinking(t *testing.T) {
+ enabled := true
+ opts := fantasy.ProviderOptions{
+ vercel.Name: &vercel.ProviderOptions{
+ Reasoning: &vercel.ReasoningOptions{
+ Enabled: &enabled,
+ },
+ },
+ }
+
+ var pairs []builderPair
+ for _, m := range vercelTestModels {
+ if !m.reasoning {
+ continue
+ }
+ pairs = append(pairs, builderPair{m.name, vercelBuilder(m.model), opts, nil})
+ }
+ testThinking(t, pairs, testVercelThinking)
+
+ // test anthropic signature
+ testThinking(t, []builderPair{
+ {"claude-sonnet-4-sig", vercelBuilder("anthropic/claude-sonnet-4"), opts, nil},
+ }, testVercelThinkingWithSignature)
+}
+
+func testVercelThinkingWithSignature(t *testing.T, result *fantasy.AgentResult) {
+ reasoningContentCount := 0
+ signaturesCount := 0
+ // Test if we got the signature
+ for _, step := range result.Steps {
+ for _, msg := range step.Messages {
+ for _, content := range msg.Content {
+ if content.GetType() == fantasy.ContentTypeReasoning {
+ reasoningContentCount += 1
+ reasoningContent, ok := fantasy.AsContentType[fantasy.ReasoningPart](content)
+ if !ok {
+ continue
+ }
+ if len(reasoningContent.ProviderOptions) == 0 {
+ continue
+ }
+
+ anthropicReasoningMetadata, ok := reasoningContent.ProviderOptions[anthropic.Name]
+ if !ok {
+ continue
+ }
+ if reasoningContent.Text != "" {
+ if typed, ok := anthropicReasoningMetadata.(*anthropic.ReasoningOptionMetadata); ok {
+ require.NotEmpty(t, typed.Signature)
+ signaturesCount += 1
+ }
+ }
+ }
+ }
+ }
+ }
+ require.Greater(t, reasoningContentCount, 0)
+ require.Greater(t, signaturesCount, 0)
+ require.Equal(t, reasoningContentCount, signaturesCount)
+ // we also add the anthropic metadata so test that
+ testAnthropicThinking(t, result)
+}
+
+func testVercelThinking(t *testing.T, result *fantasy.AgentResult) {
+ reasoningContentCount := 0
+ for _, step := range result.Steps {
+ for _, msg := range step.Messages {
+ for _, content := range msg.Content {
+ if content.GetType() == fantasy.ContentTypeReasoning {
+ reasoningContentCount += 1
+ }
+ }
+ }
+ }
+ require.Greater(t, reasoningContentCount, 0)
+}
+
+func vercelBuilder(model string) builderFunc {
+ return func(t *testing.T, r *vcr.Recorder) (fantasy.LanguageModel, error) {
+ provider, err := vercel.New(
+ vercel.WithAPIKey(os.Getenv("FANTASY_VERCEL_API_KEY")),
+ vercel.WithHTTPClient(&http.Client{Transport: r}),
+ )
+ if err != nil {
+ return nil, err
+ }
+ return provider.LanguageModel(t.Context(), model)
+ }
+}