diff --git a/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request.go b/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request.go index f03020a5..975e6479 100644 --- a/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request.go +++ b/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request.go @@ -59,7 +59,7 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _ } out = applyOpenAIThinkingCompatibilityToAntigravity(out, rawJSON) - // Temperature/top_p/top_k/max_tokens + // Temperature/top_p/top_k/max_tokens/max_completion_tokens if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number { out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num) } @@ -71,6 +71,8 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _ } if maxTok := gjson.GetBytes(rawJSON, "max_tokens"); maxTok.Exists() && maxTok.Type == gjson.Number { out, _ = sjson.SetBytes(out, "request.generationConfig.maxOutputTokens", maxTok.Num) + } else if mct := gjson.GetBytes(rawJSON, "max_completion_tokens"); mct.Exists() && mct.Type == gjson.Number { + out, _ = sjson.SetBytes(out, "request.generationConfig.maxOutputTokens", mct.Num) } // Map OpenAI response_format to Antigravity structured output settings. diff --git a/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request_test.go b/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request_test.go index ac884848..5d9a649d 100644 --- a/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request_test.go +++ b/internal/translator/antigravity/openai/chat-completions/antigravity_openai_request_test.go @@ -455,3 +455,40 @@ func TestConvertOpenAIRequestToAntigravityTranslatesVideoURL(t *testing.T) { t.Fatalf("inlineData.data = %q, want AAAAIGZ0eXBtcDQy. Output: %s", got, out) } } + +func TestConvertOpenAIRequestToAntigravity_MaxCompletionTokens(t *testing.T) { + tests := []struct { + name string + body string + expected float64 + }{ + { + name: "only max_tokens", + body: `{"model":"gemini-2.5-flash","messages":[{"role":"user","content":"hi"}],"max_tokens":100}`, + expected: 100, + }, + { + name: "only max_completion_tokens", + body: `{"model":"gemini-2.5-flash","messages":[{"role":"user","content":"hi"}],"max_completion_tokens":200}`, + expected: 200, + }, + { + name: "max_tokens preferred over max_completion_tokens", + body: `{"model":"gemini-2.5-flash","messages":[{"role":"user","content":"hi"}],"max_tokens":100,"max_completion_tokens":200}`, + expected: 100, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + out := ConvertOpenAIRequestToAntigravity("gemini-2.5-flash", []byte(tt.body), false) + got := gjson.GetBytes(out, "request.generationConfig.maxOutputTokens") + if !got.Exists() { + t.Fatalf("request.generationConfig.maxOutputTokens missing. Output: %s", out) + } + if got.Float() != tt.expected { + t.Fatalf("maxOutputTokens = %v, want %v. Output: %s", got.Float(), tt.expected, out) + } + }) + } +}