mirror of
https://gh-proxy.org/https://github.com/klinsmaya/CLIProxyAPI.git
synced 2026-11-09 18:06:50 +08:00
feat(translator): map OpenAI max_tokens to Gemini's maxOutputTokens
- Added logic to convert OpenAI `max_tokens` and `max_completion_tokens` to `generationConfig.maxOutputTokens`. - Implemented unit tests to validate proper mapping behavior, including precedence of `max_tokens` over `max_completion_tokens`. Closes: #4108
This commit is contained in:
@@ -68,6 +68,13 @@ func ConvertOpenAIRequestToGemini(modelName string, inputRawJSON []byte, _ bool)
|
||||
out, _ = sjson.SetBytes(out, "generationConfig.topK", tkr.Num)
|
||||
}
|
||||
|
||||
// OpenAI max_tokens / max_completion_tokens -> Gemini generationConfig.maxOutputTokens
|
||||
if mt := gjson.GetBytes(rawJSON, "max_tokens"); mt.Exists() && mt.Type == gjson.Number {
|
||||
out, _ = sjson.SetBytes(out, "generationConfig.maxOutputTokens", mt.Num)
|
||||
} else if mct := gjson.GetBytes(rawJSON, "max_completion_tokens"); mct.Exists() && mct.Type == gjson.Number {
|
||||
out, _ = sjson.SetBytes(out, "generationConfig.maxOutputTokens", mct.Num)
|
||||
}
|
||||
|
||||
// Candidate count (OpenAI 'n' parameter)
|
||||
if n := gjson.GetBytes(rawJSON, "n"); n.Exists() && n.Type == gjson.Number {
|
||||
if val := n.Int(); val > 1 {
|
||||
|
||||
@@ -140,6 +140,39 @@ func TestConvertOpenAIRequestToGeminiSkipsEmptyTextPartsWithoutNulls(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertOpenAIRequestToGeminiMapsMaxTokens(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
body string
|
||||
want int64
|
||||
}{
|
||||
{
|
||||
name: "max_tokens",
|
||||
body: `{"model":"gemini-2.0-flash","messages":[{"role":"user","content":"hi"}],"max_tokens":30}`,
|
||||
want: 30,
|
||||
},
|
||||
{
|
||||
name: "max_completion_tokens",
|
||||
body: `{"model":"gemini-2.0-flash","messages":[{"role":"user","content":"hi"}],"max_completion_tokens":40}`,
|
||||
want: 40,
|
||||
},
|
||||
{
|
||||
name: "max_tokens preferred over max_completion_tokens",
|
||||
body: `{"model":"gemini-2.0-flash","messages":[{"role":"user","content":"hi"}],"max_tokens":30,"max_completion_tokens":40}`,
|
||||
want: 30,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
out := ConvertOpenAIRequestToGemini("gemini-2.0-flash", []byte(tt.body), false)
|
||||
if got := gjson.GetBytes(out, "generationConfig.maxOutputTokens").Int(); got != tt.want {
|
||||
t.Fatalf("generationConfig.maxOutputTokens = %d, want %d. Output: %s", got, tt.want, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertOpenAIRequestToGeminiCleansToolSchemaRequiredFields(t *testing.T) {
|
||||
inputJSON := `{
|
||||
"model": "gemini-2.0-flash",
|
||||
|
||||
Reference in New Issue
Block a user