Repository navigation
fix(vertex_ai): route Model Garden models through the generateContent adapter - #41836
devin-ai-integration[bot] wants to merge 7 commits into
Conversation
… adapter Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
|
Merging this PR will not alter performance
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
bugbot run |
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
@greptileai please re-review the merge commit da29aa8 that resolved the conflict with main in tests/test_litellm/test_utils.py |
…eneratecontent_route
…eneratecontent_route
|
Automatic reviews are disabled for this repository. |
|
@litereview code-review |
✅ code-review5/5 · Ready for human reviewScope: full · Full PR review. No correctness findings. Checks and execution details
The PR description includes inspectable manual E2E evidence: real Vertex AI on 2026-10-15, before and after SHAs The streamed grok spend is The countTokens leg returns 200 after the change, where it returned 500 before. The gemini and claude regression legs still return 200.
For The adapter handler no longer wraps errors in View review · Reviewed |
…chat completions Streamed Model Garden calls through the generateContent adapter now request stream usage where the deployment supports it, keep cached-token details, and look up the provider-relative cost key, so they bill like the non-stream call. The adapter forwards router metadata, passes upstream errors through with their status, countTokens falls back to local counting for non-Gemini routes, and the native Gemini config is limited to the Gemini routes.
|
@litereview code-review |
TLDR
Problem this solves:
xai/grok-*404s on:generateContentand:streamGenerateContent:countTokensfor the same model returned 500How it solves it:
:countTokenson non-Gemini routes falls back to local countingDecisions worth a look. The native config allowlists the Gemini routes, so every other route,
openai/<endpoint id>included, calls the endpoint's chat completions API, since anxai/special case leaves the next publisher on the 404. Stream usage is asked for only where the deployment supportsstream_options, the proxy's rule for streamed chat.:countTokensuses the local estimate, since Model Garden has no count endpointUser Flow
Before: a developer pointing the Google GenAI SDK at a Vertex Grok deployment gets errors on every Gemini-style call, while the same deployment answers on chat completions
model_name: grok-4.6withlitellm_params.model: vertex_ai/xai/grok-4.6, and POST https://litellm-domain/v1/chat/completions answers 200litellm.NotFoundError: Vertex_aiException:streamGenerateContent404s the same way, and a request withmaxOutputTokens: -5also 404s instead of rejecting the bad valueInternal server errorAfter: the same SDK calls succeed and bill like chat completions, and bad input gets a 400
model_name: grok-4.6withlitellm_params.model: vertex_ai/xai/grok-4.6, and POST https://litellm-domain/v1/chat/completions answers 200candidates[0].content.parts[0].textfilled in andfinishReason: STOP:streamGenerateContentstreams the same reply, andmaxOutputTokens: -5now gets a 400 from VertextotalTokensgrok-4.6Relevant issues
Fixes #41835
Linear ticket
Resolves LIT-8120
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/unit/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or moreDelays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
Live run against real Vertex AI on 2026-10-15 with the reporter's client, the Google GenAI SDK (
google-genai2.31.0), plus curl for chat and spend. Our project has nogrok-4.6access, so the deployment isvertex_ai/xai/grok-4.20-non-reasoningon the same Model Garden route. Each leg runs one 2-worker proxy on a fresh Postgres database144, key spend $0.0000915144max_output_tokens=-5total_tokens=20144144144144144144144144Shared setup
config.yamlprisma db pushthe proxy schema into it, and bootpython -m litellm.proxy.proxy_cli --config config.yaml --host 127.0.0.1 --port $PORT --num_workers 2 --timeout_worker_healthcheck 900withDATABASE_URLpointing at it andGOOGLE_APPLICATION_CREDENTIALSpointing at the service-account key, then wait forGET /health/livelinessto answer 200VIRTUAL_KEY=$(curl -s $BASE/key/generate -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" -d '{"key_alias": "lit8120-<leg>-grok-stream"}' | jq -r .key)genai_client.py BASE KEY call|stream|bad|count MODELBefore (0ececab)
grok streamGenerateContent and its spend
python genai_client.py $BASE $VIRTUAL_KEY stream grok-4.20-non-reasoningcurl -s "$BASE/key/info?key=$VIRTUAL_KEY" -H "Authorization: Bearer $LITELLM_MASTER_KEY" | jq -c "{key_alias: .info.key_alias, spend: .info.spend}"grok generateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY call grok-4.20-non-reasoninggrok generateContent with
max_output_tokens=-5Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY bad grok-4.20-non-reasoninggrok countTokens
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY count grok-4.20-non-reasoninggemini generateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY call gemini-3.8-flashclaude generateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY call claude-haiku-4-5gemini streamGenerateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY stream gemini-3.8-flashgrok chat completions (control)
Steps
curl -s $BASE/v1/chat/completions -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" -d '{"model": "grok-4.20-non-reasoning", "messages": [{"role": "user", "content": "What is 12*12? Reply with only the number."}]}' | jq -c "{model: .model, content: .choices[0].message.content, usage: .usage.total_tokens}"spend log rows
Steps
curl -s "$BASE/spend/logs/ui?start_date=2026-10-15%2000:00:00&end_date=2026-10-16%2000:00:00" -H "Authorization: Bearer $LITELLM_MASTER_KEY" | jq -c ".data | sort_by(.startTime) | .[] | {call_type, model, model_group, spend, prompt_tokens, completion_tokens}"After (371d5b6)
grok streamGenerateContent and its spend
python genai_client.py $BASE $VIRTUAL_KEY stream grok-4.20-non-reasoningcurl -s "$BASE/key/info?key=$VIRTUAL_KEY" -H "Authorization: Bearer $LITELLM_MASTER_KEY" | jq -c "{key_alias: .info.key_alias, spend: .info.spend}"grok generateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY call grok-4.20-non-reasoninggrok generateContent with
max_output_tokens=-5Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY bad grok-4.20-non-reasoninggrok countTokens
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY count grok-4.20-non-reasoninggemini generateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY call gemini-3.8-flashclaude generateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY call claude-haiku-4-5gemini streamGenerateContent
Steps
python genai_client.py $BASE $LITELLM_MASTER_KEY stream gemini-3.8-flashgrok chat completions (control)
Steps
curl -s $BASE/v1/chat/completions -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H "Content-Type: application/json" -d '{"model": "grok-4.20-non-reasoning", "messages": [{"role": "user", "content": "What is 12*12? Reply with only the number."}]}' | jq -c "{model: .model, content: .choices[0].message.content, usage: .usage.total_tokens}"spend log rows
Steps
curl -s "$BASE/spend/logs/ui?start_date=2026-10-15%2000:00:00&end_date=2026-10-16%2000:00:00" -H "Authorization: Bearer $LITELLM_MASTER_KEY" | jq -c ".data | sort_by(.startTime) | .[] | {call_type, model, model_group, spend, prompt_tokens, completion_tokens}"Observations from the run
Type
🐛 Bug Fix
Caveats (if any)
Low
gemma/*andagent_engine/*deployments now use the adapter, not live-tested hereusageMetadatareads 0 to the client, while billing is correct:countTokenson non-Gemini routes is a local estimate and skips server-side system promptsFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/22a1bdcb2f9c4c59bf930c39cf178e80
Open in Devin Desktop: https://app.devin.ai/desktop/session/22a1bdcb2f9c4c59bf930c39cf178e80?variant=devin