fix(together_ai): default endpoints to api.together.ai instead of api.together.xyz - #38233
Conversation
….together.xyz Together AI moved its canonical API host from api.together.xyz to api.together.ai. Default the provider api_base and the rerank handler to the new host, make rerank honor api_base and TOGETHER_AI_API_BASE like chat already does, map both hosts to together_ai when passed as api_base, and delete the dead models/info fetch in factory.py.
Greptile SummaryThe PR migrates Together AI defaults to the canonical
Confidence Score: 3/5The PR does not yet appear safe to merge because the previously reported credential and endpoint isolation failure remains reachable. The rerank path still allows a selected API base to determine the authenticated POST destination while the credential can independently fall back to the server’s Together environment key. Files Needing Attention: litellm/rerank_api/main.py and litellm/llms/together_ai/rerank/handler.py
|
| Filename | Overview |
|---|---|
| litellm/litellm_core_utils/get_llm_provider_logic.py | Maps both Together hosts to the provider, defaults to the canonical host, and preserves explicit API-key precedence. |
| litellm/llms/together_ai/rerank/handler.py | Routes rerank calls through the selected API base, but the previously reported credential and endpoint isolation issue remains. |
| litellm/rerank_api/main.py | Resolves a configurable Together rerank base while retaining the previously reported unsafe pairing with server-resolved credentials. |
| litellm/constants.py | Registers the canonical Together endpoint alongside the supported legacy endpoint. |
| litellm/litellm_core_utils/prompt_templates/factory.py | Removes an unused Together model-information request against the legacy host. |
| tests/test_litellm/litellm_core_utils/test_get_llm_provider_endpoint_match.py | Covers both Together host mappings, explicit-key precedence, and the canonical default. |
| tests/test_litellm/rerank_api/test_main.py | Covers default, explicit, and environment-selected rerank API bases with mocked HTTP requests. |
Reviews (4): Last reviewed commit: "fix(together_ai): let an explicit api_ke..." | Re-trigger Greptile
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
@greptileai On the summary security concern: every rerank provider already pairs caller api_base with the server-key fallback, matching chat's trust model. |
|
That’s fair. Re-checking the flow, Together rerank resolves |
2 similar comments
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5e6b6c6. Configure here.
…ges surfaces Adds streaming, async, /v1/responses, and /v1/messages coverage for the Together AI overhaul (BerriAI#38233, BerriAI#38248, BerriAI#38230, BerriAI#38265, BerriAI#38275), plus the legacy api.together.xyz host and TOGETHER_AI_API_BASE through litellm.completion. Each new test fails under a one-line mutation of the merged code.
TLDR
Problem this solves:
How it solves it:
User Flow
Before: a developer moving their LiteLLM gateway to Together's new api.together.ai host finds rerank pinned to the legacy host and bare-model api_base requests rejected
TOGETHER_AI_API_BASE=https://api.together.ai/v1and restart their proxy with atogether_ai/chat model and atogether_ai/rerank model configured{"model": "together-gemma", ...}and get a 200; Together's request log shows the call arriving on api.together.ai{"model": "together-rerank", "query": ..., "documents": [...]}and the request goes out to https://api.together.xyz/v1/rerank anyway; an egress rule that only allows api.together.ai blocks every rerank calllitellm.completion(model="google/gemma-3n-E4B-it", api_base="https://api.together.xyz/v1")and get back a 400 "LLM Provider NOT provided"After: the same setup sends every Together call to the host the developer chose, and both Together hosts resolve as api_base
TOGETHER_AI_API_BASE=https://api.together.ai/v1and restart their proxy with the same config{"model": "together-gemma", ...}and get a 200 arriving on api.together.ailitellm.completion(model="google/gemma-3n-E4B-it", api_base="https://api.together.xyz/v1")call returns a completion routed to Together, and so doesapi_base="https://api.together.ai/v1"Relevant issues
Linear ticket
Resolves LIT-5962
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<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 more@greptileaito re-request a review after pushing changes)Screenshots / Proof of Fix
Live proxies, real TOGETHER_API_KEY, no mocks, both legs booted with
--num_workers 2(2 uvicorn workers, no database). Before leg from a worktree at the merge base 1d695a7 on port 41227; after leg from the PR tip 5e6b6c6 on port 57971. Configtogether_qa_config.yaml:Together currently has zero serverless rerank models (
GET https://api.together.ai/v1/modelslists Salesforce/Llama-Rank-V1 and mixedbread-ai/mxbai-rerank-large-v2 as dedicated-only), so every live rerank call returns Together's genuine 400model_not_available. That real provider response plus the proxy debug log is the host evidence: the request authenticated against the real Together API on the host under test. Chat calls are full live completions.Before (1d695a7, merge base)
chat defaults to the legacy host
curl -s http://localhost:41227/v1/chat/completions -H "Authorization: Bearer sk-litellm-together-qa" -H "Content-Type: application/json" -d '{"model":"together-gemma","messages":[{"role":"user","content":"say hi in 3 words"}],"max_tokens":30}'https://api.together.xyz/v1/rerank defaults to the legacy host
curl -s http://localhost:41227/v1/rerank -H "Authorization: Bearer sk-litellm-together-qa" -H "Content-Type: application/json" -d '{"model":"together-rerank","query":"what is reranking","documents":["reranking orders documents by relevance","bananas are yellow"]}'model_not_availablecomes back; debug log shows the outbound POST going tohttps://api.together.xyz/v1/rerankper-deployment api_base pins the legacy host (unchanged by this PR)
"model":"together-gemma-xyz-pinned"(deployment carriesapi_base: https://api.together.xyz/v1)https://api.together.xyz/v1/rerank ignores TOGETHER_AI_API_BASE
TOGETHER_AI_API_BASE=https://api.together.ai/v1https://api.together.ai/v1/(chat honors the env var)https://api.together.xyz/v1/rerank(rerank hardcodes the host)bare model + Together api_base fails provider resolution
litellm.completion(model="google/gemma-3n-E4B-it", api_base="https://api.together.xyz/v1", messages=[...])from the SDKlitellm.exceptions.LiteLLMUnknownProvider: litellm.BadRequestError: Unmapped LLM provider for this endpoint. You passed model=google/gemma-3n-E4B-it, custom_llm_provider=None(the legacy host sits in the endpoint list with no provider mapping); withapi_base=https://api.together.ai/v1it raiseslitellm.BadRequestError: LLM Provider NOT provided. ... You passed model=google/gemma-3n-E4B-it(the current host is not recognized at all)After (5e6b6c6)
chat defaults to the current host
https://api.together.ai/v1/rerank defaults to the current host
model_not_availablecomes back (its message now even linkshttps://api.together.ai/models/...); debug log shows the outbound POST going tohttps://api.together.ai/v1/rerankrerank honors TOGETHER_AI_API_BASE
TOGETHER_AI_API_BASE=https://api.together.xyz/v1(inverted on purpose: the env var now points at the legacy host)https://api.together.xyz/v1/https://api.together.xyz/v1/rerank; both surfaces follow the env var, and the legacy host still works end to endbare model + Together api_base resolves to together_ai
litellm.completion(model="google/gemma-3n-E4B-it", api_base="https://api.together.xyz/v1", messages=[{"role":"user","content":"say hi in 3 words"}], max_tokens=30)from the SDK with onlyTOGETHER_API_KEYin the envmodel=together_ai/google/gemma-3n-E4B-it; same call withapi_base="https://api.together.ai/v1"also returns a real completionper-deployment api_base still pins the legacy host
curl -s http://localhost:57971/v1/chat/completions ... -d '{"model":"together-gemma-xyz-pinned", ...}'(deployment carriesapi_base: https://api.together.xyz/v1)https://api.together.xyz/v1/QA run notes:
Type
🐛 Bug Fix
Caveats (if any)
Rerank credential model
Together rerank keeps rerank_api/main.py's uniform credential precedence: api_base resolves dynamic/config/global/default and the key falls back to the Together env key, exactly as the cohere, infinity, and bedrock branches and Together chat already do. A caller cannot select the base on the proxy: api_base sits in
_BANNED_REQUEST_BODY_PARAMSandis_request_body_safe(litellm/proxy/auth/auth_utils.py) rejects it with a 400 on every authed route viapre_db_read_auth_checks, unless the admin opts in throughallow_client_side_credentialsor a deployment'sconfigurable_clientside_auth_params(the huntr 4001e1a2 hardening). SDK callers own the process env that holds the key. So the env-key fallback only ever pairs with an admin-selected base, which is the mainline this PR enables: a config api_base plus TOGETHER_API_KEY in the envFinal Attestation
The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR
5e6b6c6 passes /live-pr-risk
Note
Medium Risk
Changes default outbound URLs and provider inference for Together (chat and rerank), which can affect egress allowlists and deployments that relied on implicit
.xyzdefaults; legacy host pinning and env overrides remain supported and tests were added.Overview
Aligns Together AI routing with the api.together.ai canonical host while keeping api.together.xyz working when explicitly configured.
Provider resolution: Adds
api.together.ai/v1to openai-compatible endpoints and maps both Together hosts totogether_aiin endpoint-basedget_llm_provider, including API key resolution from the existing Together env vars. The defaulttogether_aiapi_baseis nowhttps://api.together.ai/v1instead of the legacy.xyzURL.Rerank: Stops hardcoding
https://api.together.xyz/v1/rerank; rerank builds the URL fromapi_base(sync and async).rerank_api/main.pypasses throughdynamic_api_base/TOGETHER_AI_API_BASEwith the same default as chat.Cleanup: Removes unused Together-specific
get_model_info/ legacy prompt-template code fromprompt_templates/factory.pythat called the old models/info endpoint.Regression tests cover provider resolution and rerank default/custom/env
api_basebehavior.Reviewed by Cursor Bugbot for commit 5e6b6c6. Bugbot is set up for automated code reviews on this repo. Configure here.