litellm/tests/unit/llms/cohere/embed
zhengqiuyang ad24ca9f31
fix(cohere): honor COHERE_API_BASE for embeddings (#50249)
* fix(cohere): honor COHERE_API_BASE for embeddings

The cohere embedding branch in the dispatch passed the caller's api_base
straight through with no env fallback, so COHERE_API_BASE was silently
ignored for embeddings — the request went to the hardcoded
api.cohere.ai/v2/embed host. The rerank path (rerank_api/main.py) already
reads the same variable, and the databricks/hosted_vllm/openrouter
embedding branches follow the same convention; this branch was the
asymmetric one (same family as voyage's #49411).

Adds two respx regression tests: the env-routed gateway URL is used when
the variable is set, and the hardcoded default still applies when it is
not.

Signed-off-by: 郑润泽 <506166760@qq.com>

* fix(cohere): route COHERE_API_BASE through ensure_api_route and pin the url semantics

Review follow-up on #50249: COHERE_API_BASE means different things across
cohere's own paths (chat reads it as the full /v2/chat endpoint, rerank as
a base URL) and the PR initially used the verbatim reading — which breaks
a bare-host gateway silently (the request would land on the gateway root).

get_complete_url now runs whichever value it receives through
ensure_api_route(..., "v2/embed"): a bare host joins the route, a full
/v2/embed endpoint passes verbatim, and the no-env default is unchanged.
The default domain (api.cohere.ai vs the api.cohere.com the siblings use)
is left alone on purpose — flagging it here for a maintainer call instead
of bundling a behavior change into this fix.

Tests: three get_complete_url unit pins (bare host joins, full endpoint
verbatim, default unchanged) plus the env-routed respx test reshaped to
the bare-host form. 76 passed in tests/unit/llms/cohere/embed/.

Signed-off-by: 郑润泽 <506166760@qq.com>

* fix(cohere): fail fast when COHERE_API_BASE is a chat endpoint; pin verbatim-path semantics

Review of #50249 surfaced two gaps:

1. Chat reads COHERE_API_BASE as a complete URL (the value may end in
   /v2/chat or /v1/chat), while embeddings now treat it as a base to join
   /v2/embed onto. A chat-configured deployment upgrading would get
   embeddings at <chat-url>/v2/embed and 404. get_complete_url now fails
   fast with an actionable error when the value is a chat endpoint, so
   the user configures embeddings separately instead of silently losing
   them on upgrade.

2. The added tests only covered a bare gateway host — the one shape
   where join and verbatim agree. Adds a /v1/embed verbatim pin (the
   issue's original shape) and a chat-endpoint rejection test.

The query-string corruption in ensure_api_route (pre-existing, locked by
test_url_utils.py) is real but out of scope here — it predates this PR
and needs its own change plus a decision on the locked assertion.

Release-note-worthy: chat-only deployments that set COHERE_API_BASE and
then configure embeddings will now see the fail-fast error instead of a
silent 404.

Signed-off-by: 郑润泽 <506166760@qq.com>

* fix(cohere): resolve the embed api base without rebinding the parameter

AGENTS.md asks for no variable mutation and no comments that restate the code. The base is now a Final local next to cohere_key, and the three-line comment is gone. py_compile passes; the local pytest run is blocked by an unreleased native symbol (NativeRedisClient), so CI verifies the suite.

* fix(cohere): keep an explicit embedding endpoint verbatim

The route was appended to any path that did not already end in /v2/embed, so a gateway exposing /v1/embed or /embeddings received /v1/embed/v2/embed. An explicit embedding endpoint is now used as given, and a chat endpoint still fails fast.

* fix(cohere): keep the configured URL out of the chat-endpoint error

The message reaches proxy error responses, and a server-configured URL can carry credentials in its userinfo or query string.

* fix(cohere): raise BadRequestError for a chat-endpoint base and fix the verbatim test

Review on #50249: aembedding wrapped the guard ValueError into APIConnectionError, so the proxy answered a network error instead of 400. Raise litellm.BadRequestError and assert it. The explicit-endpoint test compared against api_base.rstrip(/) while the code returns the base untouched; compare against api_base. Also drop a corrupted character in the message.

Signed-off-by: 郑润泽 <506166760@qq.com>

* fix(cohere): send embeddings for a chat-endpoint COHERE_API_BASE to the same host's embed route

* fix(cohere): keep an explicit embed api_base as is and derive COHERE_API_BASE safely

An explicit api_base is the full request URL again, as before this PR.
Only COHERE_API_BASE is turned into an embed URL: a trailing /vN,
/vN/chat or /vN/rerank is dropped, /v2/embed is joined on the path so a
query string survives, and only a path ending in /embed is used as is.
litellm.api_base is no longer consulted for Cohere embeddings.

* test(cohere): drop an extra blank line in the embed URL tests

* fix(cohere): read COHERE_API_BASE for embeddings from the environment only

A proxy with a secret manager no longer makes an extra lookup on every
Cohere embedding call, and a bare /chat or /rerank path is now covered
by tests.

---------

Signed-off-by: 郑润泽 <506166760@qq.com>
Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-11-14 04:30:11 -05:00
..
__init__.py test(unit): make every tests/unit directory a package so pytest collection is unique 2026-09-20 11:50:59 +00:00
test_cohere_embedding_handler.py fix(cohere): honor COHERE_API_BASE for embeddings (#50249) 2026-11-14 04:30:11 -05:00
test_cohere_embedding_transformation.py fix(cohere): price native Cohere embed calls on Foundry relays and the Cohere passthrough (#48978) 2026-10-29 05:17:11 -07:00
test_transformation.py fix(cohere): honor COHERE_API_BASE for embeddings (#50249) 2026-11-14 04:30:11 -05:00
test_v1_transformation.py fix(rate-limit): estimate embedding image and audio data URIs as media in TPM pre-call checks (#49831) 2026-11-03 22:06:59 +00:00