Skip to content

fix(providers/google): omit function call ID for vertex ai to prevent error 400#278

Open
eswar-7116 wants to merge 3 commits into
charmbracelet:mainfrom
eswar-7116:vertexai-omit-id-265
Open

fix(providers/google): omit function call ID for vertex ai to prevent error 400#278
eswar-7116 wants to merge 3 commits into
charmbracelet:mainfrom
eswar-7116:vertexai-omit-id-265

Conversation

@eswar-7116

Copy link
Copy Markdown

Fixes #265

Summary

  • The Vertex AI REST endpoint rejects id as an unknown field on FunctionCall and FunctionResponse parts in multi-turn tool history. The Gemini Developer API accepts it so the fix is backend-aware rather than unconditional.
  • toGooglePrompt now accepts an isVertexAI bool parameter and omits ID on both structs when targeting Vertex. The field is retained for the Developer API path keeping existing cassettes valid.

Tests

  • I don't have GCP credentials to re-record the affected Vertex cassettes so I manually removed the id field from the request body sections of the vertex-gemini-2-5-flash and vertex-gemini-2-5-pro tool cassettes. Response sections are untouched. This keeps CI from hanging on the VCR matcher without requiring live Vertex credentials.

  • Ran go test ./... -v -count=1 and all tests pass.

  • I have read CONTRIBUTING.md.

  • I have created a discussion that was approved by a maintainer (for new features).

@eswar-7116 eswar-7116 force-pushed the vertexai-omit-id-265 branch from 3c4e7e3 to f0bb8ab Compare June 9, 2026 11:42
@eswar-7116 eswar-7116 force-pushed the vertexai-omit-id-265 branch from f0bb8ab to 3311f59 Compare June 9, 2026 11:44

@andreynering andreynering left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions to make the code shorter and easier to understand.

Args: result,
},
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
geminiPart := &genai.Part{
FunctionCall: &genai.FunctionCall{
ID: toolCall.ToolCallID,
Name: toolCall.ToolName,
Args: result,
},
}
// Vertex breaks with a 400 if this field be present.
if isVertexAI {
geminiPart.FunctionCall.ID = ""
}
}

Comment thread providers/google/google.go Outdated
Comment on lines +520 to +532
var functionResponse *genai.FunctionResponse
if isVertexAI {
functionResponse = &genai.FunctionResponse{
Response: response,
Name: toolCall.ToolName,
}
} else {
functionResponse = &genai.FunctionResponse{
ID: result.ToolCallID,
Response: response,
Name: toolCall.ToolName,
},
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var functionResponse *genai.FunctionResponse
if isVertexAI {
functionResponse = &genai.FunctionResponse{
Response: response,
Name: toolCall.ToolName,
}
} else {
functionResponse = &genai.FunctionResponse{
ID: result.ToolCallID,
Response: response,
Name: toolCall.ToolName,
},
}
}
var functionResponse &genai.FunctionResponse{
ID: result.ToolCallID,
Response: response,
Name: toolCall.ToolName,
}
// Vertex breaks with a 400 if this field be present.
if isVertexAI {
functionResponse.ID = ""
}

Comment thread providers/google/google.go Outdated
Comment on lines +544 to +556
var functionResponse *genai.FunctionResponse
if isVertexAI {
functionResponse = &genai.FunctionResponse{
Response: response,
Name: toolCall.ToolName,
}
} else {
functionResponse = &genai.FunctionResponse{
ID: result.ToolCallID,
Response: response,
Name: toolCall.ToolName,
},
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var functionResponse *genai.FunctionResponse
if isVertexAI {
functionResponse = &genai.FunctionResponse{
Response: response,
Name: toolCall.ToolName,
}
} else {
functionResponse = &genai.FunctionResponse{
ID: result.ToolCallID,
Response: response,
Name: toolCall.ToolName,
},
}
}
var functionResponse &genai.FunctionResponse{
ID: result.ToolCallID,
Response: response,
Name: toolCall.ToolName,
}
// Vertex breaks with a 400 if this field be present.
if isVertexAI {
functionResponse.ID = ""
}

Comment thread providers/google/google.go Outdated
}

systemInstructions, content, warnings := toGooglePrompt(call.Prompt)
systemInstructions, content, warnings := toGooglePrompt(call.Prompt, g.providerOptions.backend == genai.BackendVertexAI)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
systemInstructions, content, warnings := toGooglePrompt(call.Prompt, g.providerOptions.backend == genai.BackendVertexAI)
isVertexAI := g.providerOptions.backend == genai.BackendVertexAI
systemInstructions, content, warnings := toGooglePrompt(call.Prompt, isVertexAI)

@eswar-7116

Copy link
Copy Markdown
Author

Thanks for the review and the suggestions @andreynering !
I have applied the suggestions to make the code cleaner and easier to understand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

google provider: Vertex AI rejects multi-turn tool history — id set on FunctionCall/FunctionResponse parts is unknown to Vertex

2 participants