litellm/tests/unit/llms/openai_like
Algirdas Č. 57090e94a4
feat!: add Hostinger Router as an OpenAI-compatible provider (#44863)
* feat: add Hostinger Router as an OpenAI-compatible provider

Adds hostinger_router (https://router.hostinger.com/v1) to the
JSON-configured openai_like providers with chat completions, responses,
messages, and embeddings endpoints, cost-map entries for claude-sonnet-5,
gpt-5.2 and the two text-embedding-3 models (credits converted at
1 credit = $0.01, sourced from the public
https://router.hostinger.com/v1/models catalog), the endpoint-support
matrix, Admin UI add-model form fields and logo, and respx-mocked unit
tests covering all declared endpoints.

Also routes /v1/embeddings for JSON-configured providers that declare it
in providers.json; previously embedding calls for these providers fell
through to LiteLLMUnknownProvider.

* fix(hostinger_router): match prices to the live catalog, drop retired max_tokens, regenerate the endpoint matrix

* fix(hostinger_router): keep api_base detection off, send embeddings headers as HTTP headers, drop generic key fallback

Unprefixed models called with Hostinger's api_base keep their own provider, JSON provider
embeddings no longer borrow OPENAI_LIKE_API_KEY or litellm.api_key, and the openai_like
embedding handler sends extra_headers as request headers instead of in the JSON body

* fix(openai_like): route Hostinger messages and responses per model, keep the configured key header

Native /v1/messages and /v1/responses calls for a JSON provider now also follow the
model's cost-map supported_endpoints, so Hostinger models without the route go
through chat completions instead of a 403. Embedding key headers replace
extra_headers case-insensitively, and pinstripes stops declaring /v1/embeddings.

* fix(openai_like): let embeddings extra_headers override the key's headers as chat does

Embeddings now match chat through the OpenAI SDK, so an extra_headers entry replaces the key's header of the same name in any letter case. The Hostinger capability test checks that the supports_* lookups agree with each cost-map row instead of pinning vendor flags

* fix(openai_like): send numeric embeddings extra_headers as text and keep Hostinger's 1h cache TTL

A config.yaml header like X-Org-Id: 12345 loads as an int, which the embeddings header check rejected with a 500. Int and float values now go out as their decimal text. Hostinger Router accepts and bills a 1h cache_control TTL on /v1/messages, so its provider entry opts into keeping it.

* fix(openai_like): send Hostinger's 1h cache TTL as the 5-minute default so cache writes bill at its charge

* fix(openai_like): route Hostinger natives per model from providers.json, refuse non-text embeddings headers unless drop_params

* fix(openai_like): refuse Host, Content-Length and Transfer-Encoding in embeddings extra_headers unless drop_params

* fix(openai_like): refuse malformed embeddings extra_headers and ignore transport headers

Header names must be HTTP tokens and values printable ASCII on one line, so a
colon in a name or a line break in a value answers 400 unless drop_params drops
it. Host, Content-Length and Transfer-Encoding are ignored, since a 400 for them
sends the call to the deployment's fallback with the same headers.

* fix(openai_like): trim embeddings extra_headers values and drop values HTTP cannot carry

HTTP ignores spaces and tabs around a header value, so values are trimmed
before they are sent. A value that is not printable ASCII on one line after
trimming is dropped with a warning instead of failing the call, since the
proxy adds headers itself from key aliases and forwarded client headers that
the caller cannot fix. A malformed header name or a non-text value still
answers 400 unless drop_params drops it.

* fix(openai_like): ignore hop-by-hop extra_headers and trim line breaks around values

TE, Upgrade, Connection, Keep-Alive, Proxy-Connection and Trailer in
extra_headers are now ignored like Host, Content-Length and
Transfer-Encoding, since litellm builds the request and TE: gzip fails
HTTP/2 while Upgrade makes some upstreams hang. Line breaks at the ends of a
value are trimmed along with spaces and tabs, so a secret read from a file
with a trailing newline is sent instead of dropped. The drop warning now
names the model.

* fix(embeddings): keep one request's extra_headers out of the deployment's headers and ignore Expect

embedding() merged a request's extra_headers into the headers dict it got
from the deployment's litellm_params. The router only shallow-copies those
params, so the merge wrote the caller's headers into the deployment itself,
and later embeddings calls through that deployment sent them too. Build a
new dict instead, and drop the None checks that can no longer be true.

Also treat Expect as a transport header that hostinger_router embeddings
never forwards, and name the model with %r in the dropped-value warning.

* fix(embeddings): keep name and value pairs working in headers and answer 400 for other non-object values

The previous commit merged headers and extra_headers with dict unpacking,
which only takes a mapping, so a list of name and value pairs that
dict.update used to accept now raised a TypeError and the proxy answered
500. Merge through dict() so pairs keep working, and answer 400 for any
other value, or drop it under drop_params, as the litellm convention does
for an unsupported param.

---------

Co-authored-by: mateo-berri <277851410+mateo-berri@users.noreply.github.com>
2026-10-31 00:38:45 -07:00
..
chat fix(streaming): keep merged think tags balanced and split SSE lines only on CR/LF (#48755) 2026-10-28 17:00:29 -07:00
embedding test: migrate local_testing SDK and provider tests out of build_and_test (#45760) 2026-10-10 23:14:25 +00:00
messages refactor(anthropic): rename llms/anthropic/pass_through to llms/anthropic/messages (#48510) 2026-10-27 10:08:25 -07:00
responses test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
__init__.py test: add package initializers to migrated unit test directories 2026-09-20 11:52:07 +00:00
test_abliteration_provider.py feat(abliteration): add model pricing and capabilities (#48498) 2026-10-26 18:08:29 -07:00
test_aiand_provider.py fix(aiand)!: show ai&'s name and logo, and sync ai&'s model list (#49158) 2026-10-30 10:55:26 -07:00
test_assemblyai_provider.py refactor(llms): expose public names for private provider helpers (#45037) 2026-10-07 08:49:25 -07:00
test_charity_engine.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_cognition_provider.py refactor(llms): expose public names for private provider helpers (#45037) 2026-10-07 08:49:25 -07:00
test_coralbricks_provider.py feat(providers): add CoralBricks as a native provider (#44700) 2026-10-12 21:56:59 +00:00
test_cortecs_provider.py feat: generate provider_endpoints_support.json from the cost map (#48619) 2026-10-27 12:06:55 -07:00
test_dynamic_config.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_empiriolabs_provider.py refactor(llms): expose public names for private provider helpers (#45037) 2026-10-07 08:49:25 -07:00
test_hostinger_router_provider.py feat!: add Hostinger Router as an OpenAI-compatible provider (#44863) 2026-10-31 00:38:45 -07:00
test_inferenceapis_provider.py feat(providers): add Inference APIs as OpenAI-compatible provider (#41669) 2026-10-15 08:17:36 -07:00
test_json_loader.py fix(crusoe): update base URL to current endpoint (#33121) 2026-10-15 19:10:58 -07:00
test_json_providers.py refactor(llms): expose public names for private provider helpers (#45037) 2026-10-07 08:49:25 -07:00
test_kyma_provider.py fix(cost): bill a provider reported usage.cost on every path unless the deployment is priced (#48953) 2026-10-29 20:30:42 -07:00
test_libertai_provider.py feat: generate provider_endpoints_support.json from the cost map (#48619) 2026-10-27 12:06:55 -07:00
test_meta_provider.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_model_info.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_openinfer_provider.py refactor(cost-map): drop the legacy max_tokens field in favor of max_input_tokens and max_output_tokens (#48471) 2026-10-26 17:03:05 -07:00
test_pinstripes_provider.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_prism_provider.py feat: generate provider_endpoints_support.json from the cost map (#48619) 2026-10-27 12:06:55 -07:00
test_provider_affinity_forwarding.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_refuseless_provider.py feat(refuseless): add provider and model pricing (#48497) 2026-10-26 18:08:42 -07:00
test_reka_provider.py feat: generate provider_endpoints_support.json from the cost map (#48619) 2026-10-27 12:06:55 -07:00
test_scx_ai_provider.py feat(cost-map): add scx-ai DeepSeek-V4.1-flash, GLM-5.3 and Kimi-K3 (#46496) 2026-10-14 20:22:16 -07:00
test_streamlake_provider.py feat!: add StreamLake provider metadata (#41006) 2026-10-28 20:19:06 -07:00
test_tensormesh_provider.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_xiaomi_mimo.py test: move tests/test_litellm/llms into tests/unit/llms (#43191) 2026-09-25 12:43:23 -07:00
test_zerogpu_provider.py feat(providers): add ZeroGPU as an OpenAI-compatible provider (#43874) 2026-10-28 12:40:32 -07:00