fix(clients): preserve gemini tool call responses

This commit is contained in:
2026-05-19 21:32:50 +08:00
parent baffccf8f8
commit 69d23efb57
2 changed files with 102 additions and 5 deletions
+57
View File
@@ -655,6 +655,63 @@ func TestGeminiClientChatRestoresToolContext(t *testing.T) {
}
}
func TestGeminiClientChatConvertsFunctionCallResponse(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_ = json.NewEncoder(w).Encode(map[string]any{
"candidates": []any{map[string]any{
"finishReason": "STOP",
"content": map[string]any{"parts": []any{
map[string]any{"functionCall": map[string]any{
"name": "get_weather",
"args": map[string]any{"city": "SF"},
}},
}},
}},
})
}))
defer server.Close()
response, err := (GeminiClient{HTTPClient: server.Client()}).Run(context.Background(), Request{
Kind: "chat.completions",
Model: "gemini:gemini-2.5-flash",
Body: map[string]any{
"model": "gemini:gemini-2.5-flash",
"messages": []any{map[string]any{"role": "user", "content": "weather?"}},
"tools": []any{map[string]any{
"type": "function",
"function": map[string]any{"name": "get_weather"},
}},
},
Candidate: store.RuntimeModelCandidate{
BaseURL: server.URL,
ProviderModelName: "gemini-2.5-flash",
ModelType: "chat",
Credentials: map[string]any{"apiKey": "gemini-key"},
},
})
if err != nil {
t.Fatalf("run gemini client: %v", err)
}
choices, _ := response.Result["choices"].([]any)
choice, _ := choices[0].(map[string]any)
if choice["finish_reason"] != "tool_calls" {
t.Fatalf("Gemini function call should use tool_calls finish reason: %+v", response.Result)
}
message, _ := choice["message"].(map[string]any)
if message["content"] != nil {
t.Fatalf("tool-only Gemini response should keep nullable content: %+v", message)
}
toolCalls, _ := message["tool_calls"].([]any)
if len(toolCalls) != 1 {
t.Fatalf("Gemini function call was not converted: %+v", message)
}
toolCall, _ := toolCalls[0].(map[string]any)
function, _ := toolCall["function"].(map[string]any)
if toolCall["type"] != "function" || toolCall["id"] != "call_0" || function["name"] != "get_weather" || function["arguments"] != `{"city":"SF"}` {
t.Fatalf("unexpected Gemini tool call: %+v", toolCall)
}
}
func TestGeminiURLAcceptsVersionedBaseURL(t *testing.T) {
got := geminiURL("https://generativelanguage.googleapis.com/v1beta", "gemini-2.5-flash", "test-key")
want := "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key=test-key"