From e443ca19368ae396509663be173d618bf7a69d1a Mon Sep 17 00:00:00 2001 From: Ivan Charapanau Date: Sun, 20 Sep 2026 15:40:58 +0000 Subject: [PATCH 1/5] feat(providers): add Viktor as a JSON-configured OpenAI-compatible provider Registers `viktor` in litellm/llms/openai_like/providers.json so that `model="viktor/viktor"` works with `VIKTOR_API_KEY`, without passing `openai/` plus a custom `api_base`. Viktor serves Chat Completions and the Responses API at https://api.viktor.com/api/compat/v1 and accepts `max_completion_tokens` as is, so no parameter mapping is needed. Also registers the slug in `LlmProviders`, the OpenAI-compatible provider and endpoint lists (api base autodetection) and the endpoint support matrix, and adds mocked unit tests. --- litellm/constants.py | 2 + litellm/llms/openai_like/providers.json | 6 + .../provider_endpoints_support_backup.json | 17 ++ litellm/types/utils.py | 1 + provider_endpoints_support.json | 17 ++ .../llms/openai_like/test_viktor_provider.py | 156 ++++++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 tests/test_litellm/llms/openai_like/test_viktor_provider.py diff --git a/litellm/constants.py b/litellm/constants.py index e7ba1f6b07f..063f1f66ad4 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -947,6 +947,7 @@ openai_compatible_endpoints: Final[list] = [ "https://api.meta.ai/v1", "https://api.cognition.ai/v1", "https://api.scx.ai/v1", + "https://api.viktor.com/api/compat/v1", "https://gigachat.devices.sberbank.ru/api/v1", ] @@ -1020,6 +1021,7 @@ openai_compatible_providers: Final[list] = [ "meta", # Meta Model API (Muse Spark) - JSON-configured provider "cognition", "scx-ai", + "viktor", # Viktor - JSON-configured provider ] OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS: Final = frozenset({"openai"} | frozenset(openai_compatible_providers)) diff --git a/litellm/llms/openai_like/providers.json b/litellm/llms/openai_like/providers.json index fe10293c420..a1719b6cf9f 100644 --- a/litellm/llms/openai_like/providers.json +++ b/litellm/llms/openai_like/providers.json @@ -200,5 +200,11 @@ "temperature_max": 1.99 }, "supported_endpoints": ["/v1/chat/completions"] + }, + "viktor": { + "base_url": "https://api.viktor.com/api/compat/v1", + "api_key_env": "VIKTOR_API_KEY", + "api_base_env": "VIKTOR_API_BASE", + "supported_endpoints": ["/v1/chat/completions", "/v1/responses"] } } diff --git a/litellm/provider_endpoints_support_backup.json b/litellm/provider_endpoints_support_backup.json index 1fcb7600a5e..bdede3542ce 100644 --- a/litellm/provider_endpoints_support_backup.json +++ b/litellm/provider_endpoints_support_backup.json @@ -2263,6 +2263,23 @@ "interactions": true } }, + "viktor": { + "display_name": "Viktor (`viktor`)", + "url": "https://docs.litellm.ai/docs/providers/viktor", + "endpoints": { + "chat_completions": true, + "messages": false, + "responses": true, + "embeddings": false, + "image_generations": false, + "audio_transcriptions": false, + "audio_speech": false, + "moderations": false, + "batches": false, + "rerank": false, + "a2a": false + } + }, "vllm": { "display_name": "VLLM (`vllm`)", "url": "https://docs.litellm.ai/docs/providers/vllm", diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 3e306b48887..00b46e55a37 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -4116,6 +4116,7 @@ class LlmProviders(str, Enum): PINSTRIPES = "pinstripes" COGNITION = "cognition" SCX_AI = "scx-ai" + VIKTOR = "viktor" DARKBLOOM = "darkbloom" META = "meta" LITELLM_AGENT = "litellm_agent" diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index e6cb0592a15..42f01a6ee72 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -2592,6 +2592,23 @@ "interactions": true } }, + "viktor": { + "display_name": "Viktor (`viktor`)", + "url": "https://docs.litellm.ai/docs/providers/viktor", + "endpoints": { + "chat_completions": true, + "messages": false, + "responses": true, + "embeddings": false, + "image_generations": false, + "audio_transcriptions": false, + "audio_speech": false, + "moderations": false, + "batches": false, + "rerank": false, + "a2a": false + } + }, "vllm": { "display_name": "VLLM (`vllm`)", "url": "https://docs.litellm.ai/docs/providers/vllm", diff --git a/tests/test_litellm/llms/openai_like/test_viktor_provider.py b/tests/test_litellm/llms/openai_like/test_viktor_provider.py new file mode 100644 index 00000000000..abb45187079 --- /dev/null +++ b/tests/test_litellm/llms/openai_like/test_viktor_provider.py @@ -0,0 +1,156 @@ +""" +Tests for Viktor provider configuration and integration. +""" + +import json +from pathlib import Path + +import pytest + +import litellm + +VIKTOR_API_BASE = "https://api.viktor.com/api/compat/v1" + + +class TestViktorProviderConfig: + def test_viktor_in_provider_list(self): + from litellm import LlmProviders + + assert hasattr(LlmProviders, "VIKTOR") + assert LlmProviders.VIKTOR.value == "viktor" + assert "viktor" in litellm.provider_list + + def test_viktor_json_config_exists(self): + from litellm.llms.openai_like.json_loader import JSONProviderRegistry + + assert JSONProviderRegistry.exists("viktor") + + viktor = JSONProviderRegistry.get("viktor") + assert viktor is not None + assert viktor.base_url == VIKTOR_API_BASE + assert viktor.api_key_env == "VIKTOR_API_KEY" + assert viktor.api_base_env == "VIKTOR_API_BASE" + assert viktor.param_mappings == {} + assert viktor.constraints == {} + + def test_viktor_supports_responses_api(self): + from litellm.llms.openai_like.json_loader import JSONProviderRegistry + + assert JSONProviderRegistry.supports_responses_api("viktor") is True + + def test_viktor_in_openai_compatible_providers(self): + from litellm.constants import openai_compatible_endpoints, openai_compatible_providers + + assert "viktor" in openai_compatible_providers + assert VIKTOR_API_BASE in openai_compatible_endpoints + + def test_viktor_provider_resolution(self): + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + model, provider, api_key, api_base = get_llm_provider( + model="viktor/viktor", + custom_llm_provider=None, + api_base=None, + api_key=None, + ) + + assert model == "viktor" + assert provider == "viktor" + assert api_base == VIKTOR_API_BASE + + def test_viktor_api_base_override(self): + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + model, provider, api_key, api_base = get_llm_provider( + model="viktor/viktor", + custom_llm_provider=None, + api_base="https://viktor-gateway.internal.example/api/compat/v1", + api_key="zt_test_sk_example", + ) + + assert provider == "viktor" + assert api_base == "https://viktor-gateway.internal.example/api/compat/v1" + assert api_key == "zt_test_sk_example" + + def test_viktor_url_autodetection(self): + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + # Viktor serves one agent and does not validate the `model` field, so any + # un-prefixed model string sent to its base url should route to the provider + model, provider, api_key, api_base = get_llm_provider( + model="default", + custom_llm_provider=None, + api_base=VIKTOR_API_BASE, + api_key=None, + ) + assert model == "default" + assert provider == "viktor" + assert api_base == VIKTOR_API_BASE + + def test_viktor_env_api_key_is_read_from_viktor_variable(self, monkeypatch: pytest.MonkeyPatch): + from litellm.llms.openai_like.dynamic_config import create_config_class + from litellm.llms.openai_like.json_loader import JSONProviderRegistry + + monkeypatch.delenv("OPENAI_API_KEY", raising=False) + monkeypatch.delenv("VIKTOR_API_BASE", raising=False) + monkeypatch.setenv("VIKTOR_API_KEY", "zt_test_sk_env") + + provider = JSONProviderRegistry.get("viktor") + assert provider is not None + + api_base, api_key = create_config_class(provider)()._get_openai_compatible_provider_info(None, None) + assert api_base == VIKTOR_API_BASE + assert api_key == "zt_test_sk_env" + + def test_viktor_max_completion_tokens_passed_through(self): + from litellm.llms.openai_like.dynamic_config import create_config_class + from litellm.llms.openai_like.json_loader import JSONProviderRegistry + + provider = JSONProviderRegistry.get("viktor") + assert provider is not None + config = create_config_class(provider)() + + optional_params = config.map_openai_params( + non_default_params={"max_completion_tokens": 256}, + optional_params={}, + model="viktor", + drop_params=False, + ) + assert optional_params["max_completion_tokens"] == 256 + + def test_viktor_router_config(self): + from litellm import Router + + router = Router( + model_list=[ + { + "model_name": "viktor", + "litellm_params": { + "model": "viktor/viktor", + "api_key": "test-key", + }, + } + ] + ) + + assert len(router.model_list) == 1 + assert router.model_list[0]["model_name"] == "viktor" + + +class TestViktorEndpointMatrix: + @staticmethod + def _endpoints(path: Path) -> dict: + return json.loads(path.read_text())["providers"]["viktor"]["endpoints"] + + def test_viktor_supported_endpoints_matrix(self): + endpoints = self._endpoints(Path(litellm.__file__).parent / "provider_endpoints_support_backup.json") + + assert endpoints["chat_completions"] is True + assert endpoints["responses"] is True + assert endpoints["embeddings"] is False + + def test_viktor_endpoint_matrix_synced_to_backup(self): + root = Path(__file__).parents[4] / "provider_endpoints_support.json" + backup = Path(litellm.__file__).parent / "provider_endpoints_support_backup.json" + + assert self._endpoints(root) == self._endpoints(backup) From c7f8b4b8f9335be6a30a8f5da352e115e48c8e47 Mon Sep 17 00:00:00 2001 From: Ivan Charapanau Date: Thu, 24 Sep 2026 10:15:19 +0000 Subject: [PATCH 2/5] docs(readme): list Viktor in the supported providers table --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e927c80b8b4..78af68bc6c6 100644 --- a/README.md +++ b/README.md @@ -371,6 +371,7 @@ For MCP OAuth, an upstream may advertise dynamic client registration but refuse | [Triton (`triton`)](https://docs.litellm.ai/docs/providers/triton-inference-server) | ✅ | ✅ | ✅ | | | | | | | | | [V0 (`v0`)](https://docs.litellm.ai/docs/providers/v0) | ✅ | ✅ | ✅ | | | | | | | | | [Vercel AI Gateway (`vercel_ai_gateway`)](https://docs.litellm.ai/docs/providers/vercel_ai_gateway) | ✅ | ✅ | ✅ | | | | | | | | +| [Viktor (`viktor`)](https://docs.litellm.ai/docs/providers/viktor) | ✅ | | ✅ | | | | | | | | | [VLLM (`vllm`)](https://docs.litellm.ai/docs/providers/vllm) | ✅ | ✅ | ✅ | | | | | | | | | [Volcengine (`volcengine`)](https://docs.litellm.ai/docs/providers/volcano) | ✅ | ✅ | ✅ | | | | | | | | | [Voyage AI (`voyage`)](https://docs.litellm.ai/docs/providers/voyage) | | | | ✅ | | | | | | | From 4f01ff13d5d598593d379c7a55f12024752bad08 Mon Sep 17 00:00:00 2001 From: Ivan Charapanau Date: Fri, 25 Sep 2026 11:32:45 +0000 Subject: [PATCH 3/5] feat(providers): list Viktor in the Add Model form --- .../provider_create_fields.json | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index 87d38606aba..c0c5bea1c54 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -3403,6 +3403,34 @@ ], "default_model_placeholder": "voyage/" }, + { + "provider": "Viktor", + "provider_display_name": "Viktor", + "litellm_provider": "viktor", + "credential_fields": [ + { + "key": "api_base", + "label": "API Base", + "placeholder": "https://api.viktor.com/api/compat/v1", + "tooltip": null, + "required": false, + "field_type": "text", + "options": null, + "default_value": null + }, + { + "key": "api_key", + "label": "API Key", + "placeholder": null, + "tooltip": null, + "required": true, + "field_type": "password", + "options": null, + "default_value": null + } + ], + "default_model_placeholder": "viktor/viktor" + }, { "provider": "WANDB", "provider_display_name": "Wandb", From 4d0467a79514130b04d0bbe1cc95cdc5c7007cb7 Mon Sep 17 00:00:00 2001 From: Ivan Charapanau Date: Fri, 25 Sep 2026 11:53:02 +0000 Subject: [PATCH 4/5] fix(providers): keep Viktor out of the audio and image routing list Viktor only serves chat completions and Responses, so it no longer joins openai_compatible_providers, which also routes transcription, speech and image calls. Base URL autodetection still works through the endpoint list Tests now call completion, responses, transcription and the router against a mocked Viktor API and check the request, instead of checking registry flags --- litellm/constants.py | 1 - .../llms/openai_like/test_viktor_provider.py | 276 +++++++++--------- 2 files changed, 134 insertions(+), 143 deletions(-) diff --git a/litellm/constants.py b/litellm/constants.py index 063f1f66ad4..ceb8266c248 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1021,7 +1021,6 @@ openai_compatible_providers: Final[list] = [ "meta", # Meta Model API (Muse Spark) - JSON-configured provider "cognition", "scx-ai", - "viktor", # Viktor - JSON-configured provider ] OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS: Final = frozenset({"openai"} | frozenset(openai_compatible_providers)) diff --git a/tests/test_litellm/llms/openai_like/test_viktor_provider.py b/tests/test_litellm/llms/openai_like/test_viktor_provider.py index abb45187079..1369cc11157 100644 --- a/tests/test_litellm/llms/openai_like/test_viktor_provider.py +++ b/tests/test_litellm/llms/openai_like/test_viktor_provider.py @@ -1,156 +1,148 @@ -""" -Tests for Viktor provider configuration and integration. -""" - import json from pathlib import Path +import httpx import pytest +import respx import litellm +from litellm.llms.openai_like.json_loader import JSONProviderRegistry -VIKTOR_API_BASE = "https://api.viktor.com/api/compat/v1" +CHAT_COMPLETION = { + "id": "chatcmpl-1", + "object": "chat.completion", + "created": 1, + "model": "viktor", + "choices": [{"index": 0, "message": {"role": "assistant", "content": "hello"}, "finish_reason": "stop"}], + "usage": {"prompt_tokens": 1, "completion_tokens": 1, "total_tokens": 2}, +} + +RESPONSE = { + "id": "resp-1", + "object": "response", + "created_at": 1, + "status": "completed", + "model": "viktor", + "output": [ + { + "type": "message", + "id": "msg_1", + "role": "assistant", + "status": "completed", + "content": [{"type": "output_text", "text": "hello", "annotations": []}], + } + ], + "usage": {"input_tokens": 1, "output_tokens": 1, "total_tokens": 2}, +} + +MESSAGES = [{"role": "user", "content": "hi"}] -class TestViktorProviderConfig: - def test_viktor_in_provider_list(self): - from litellm import LlmProviders - - assert hasattr(LlmProviders, "VIKTOR") - assert LlmProviders.VIKTOR.value == "viktor" - assert "viktor" in litellm.provider_list - - def test_viktor_json_config_exists(self): - from litellm.llms.openai_like.json_loader import JSONProviderRegistry - - assert JSONProviderRegistry.exists("viktor") - - viktor = JSONProviderRegistry.get("viktor") - assert viktor is not None - assert viktor.base_url == VIKTOR_API_BASE - assert viktor.api_key_env == "VIKTOR_API_KEY" - assert viktor.api_base_env == "VIKTOR_API_BASE" - assert viktor.param_mappings == {} - assert viktor.constraints == {} - - def test_viktor_supports_responses_api(self): - from litellm.llms.openai_like.json_loader import JSONProviderRegistry - - assert JSONProviderRegistry.supports_responses_api("viktor") is True - - def test_viktor_in_openai_compatible_providers(self): - from litellm.constants import openai_compatible_endpoints, openai_compatible_providers - - assert "viktor" in openai_compatible_providers - assert VIKTOR_API_BASE in openai_compatible_endpoints - - def test_viktor_provider_resolution(self): - from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider - - model, provider, api_key, api_base = get_llm_provider( - model="viktor/viktor", - custom_llm_provider=None, - api_base=None, - api_key=None, - ) - - assert model == "viktor" - assert provider == "viktor" - assert api_base == VIKTOR_API_BASE - - def test_viktor_api_base_override(self): - from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider - - model, provider, api_key, api_base = get_llm_provider( - model="viktor/viktor", - custom_llm_provider=None, - api_base="https://viktor-gateway.internal.example/api/compat/v1", - api_key="zt_test_sk_example", - ) - - assert provider == "viktor" - assert api_base == "https://viktor-gateway.internal.example/api/compat/v1" - assert api_key == "zt_test_sk_example" - - def test_viktor_url_autodetection(self): - from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider - - # Viktor serves one agent and does not validate the `model` field, so any - # un-prefixed model string sent to its base url should route to the provider - model, provider, api_key, api_base = get_llm_provider( - model="default", - custom_llm_provider=None, - api_base=VIKTOR_API_BASE, - api_key=None, - ) - assert model == "default" - assert provider == "viktor" - assert api_base == VIKTOR_API_BASE - - def test_viktor_env_api_key_is_read_from_viktor_variable(self, monkeypatch: pytest.MonkeyPatch): - from litellm.llms.openai_like.dynamic_config import create_config_class - from litellm.llms.openai_like.json_loader import JSONProviderRegistry - - monkeypatch.delenv("OPENAI_API_KEY", raising=False) - monkeypatch.delenv("VIKTOR_API_BASE", raising=False) - monkeypatch.setenv("VIKTOR_API_KEY", "zt_test_sk_env") - - provider = JSONProviderRegistry.get("viktor") - assert provider is not None - - api_base, api_key = create_config_class(provider)()._get_openai_compatible_provider_info(None, None) - assert api_base == VIKTOR_API_BASE - assert api_key == "zt_test_sk_env" - - def test_viktor_max_completion_tokens_passed_through(self): - from litellm.llms.openai_like.dynamic_config import create_config_class - from litellm.llms.openai_like.json_loader import JSONProviderRegistry - - provider = JSONProviderRegistry.get("viktor") - assert provider is not None - config = create_config_class(provider)() - - optional_params = config.map_openai_params( - non_default_params={"max_completion_tokens": 256}, - optional_params={}, - model="viktor", - drop_params=False, - ) - assert optional_params["max_completion_tokens"] == 256 - - def test_viktor_router_config(self): - from litellm import Router - - router = Router( - model_list=[ - { - "model_name": "viktor", - "litellm_params": { - "model": "viktor/viktor", - "api_key": "test-key", - }, - } - ] - ) - - assert len(router.model_list) == 1 - assert router.model_list[0]["model_name"] == "viktor" +@pytest.fixture +def base_url() -> str: + provider = JSONProviderRegistry.get("viktor") + assert provider is not None + return provider.base_url -class TestViktorEndpointMatrix: - @staticmethod - def _endpoints(path: Path) -> dict: +@pytest.fixture(autouse=True) +def viktor_env(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("VIKTOR_API_KEY", "env-key") + monkeypatch.delenv("VIKTOR_API_BASE", raising=False) + + +@pytest.fixture +def viktor_http(): + with respx.mock(assert_all_called=False) as router: + yield router + + +def test_completion_posts_to_viktor_with_the_env_key(viktor_http: respx.MockRouter, base_url: str) -> None: + route = viktor_http.post(f"{base_url}/chat/completions").mock( + return_value=httpx.Response(200, json=CHAT_COMPLETION) + ) + + response = litellm.completion(model="viktor/viktor", messages=MESSAGES, max_completion_tokens=256) + + assert response.choices[0].message.content == "hello" + request = route.calls.last.request + assert request.headers["authorization"] == "Bearer env-key" + body = json.loads(request.content) + assert body["model"] == "viktor" + assert body["max_completion_tokens"] == 256 + + +def test_responses_posts_to_viktor(viktor_http: respx.MockRouter, base_url: str) -> None: + route = viktor_http.post(f"{base_url}/responses").mock(return_value=httpx.Response(200, json=RESPONSE)) + + response = litellm.responses(model="viktor/viktor", input="hi") + + assert response.output[-1].content[0].text == "hello" + assert json.loads(route.calls.last.request.content)["model"] == "viktor" + + +def test_api_base_env_override_is_used(viktor_http: respx.MockRouter, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("VIKTOR_API_BASE", "https://gateway.example/api/compat/v1") + route = viktor_http.post("https://gateway.example/api/compat/v1/chat/completions").mock( + return_value=httpx.Response(200, json=CHAT_COMPLETION) + ) + + litellm.completion(model="viktor/viktor", messages=MESSAGES) + + assert route.called + + +def test_explicit_api_base_and_key_win(viktor_http: respx.MockRouter) -> None: + route = viktor_http.post("https://explicit.example/v1/chat/completions").mock( + return_value=httpx.Response(200, json=CHAT_COMPLETION) + ) + + litellm.completion( + model="viktor/viktor", messages=MESSAGES, api_base="https://explicit.example/v1", api_key="explicit-key" + ) + + assert route.calls.last.request.headers["authorization"] == "Bearer explicit-key" + + +def test_unprefixed_model_on_the_viktor_base_url_uses_the_viktor_key( + viktor_http: respx.MockRouter, base_url: str +) -> None: + route = viktor_http.post(f"{base_url}/chat/completions").mock( + return_value=httpx.Response(200, json=CHAT_COMPLETION) + ) + + litellm.completion(model="agent", messages=MESSAGES, api_base=base_url) + + assert route.calls.last.request.headers["authorization"] == "Bearer env-key" + + +def test_router_deployment_reaches_viktor(viktor_http: respx.MockRouter, base_url: str) -> None: + route = viktor_http.post(f"{base_url}/chat/completions").mock( + return_value=httpx.Response(200, json=CHAT_COMPLETION) + ) + router = litellm.Router(model_list=[{"model_name": "agent", "litellm_params": {"model": "viktor/viktor"}}]) + + response = router.completion(model="agent", messages=MESSAGES) + + assert response.choices[0].message.content == "hello" + assert route.called + + +def test_transcription_is_refused_without_calling_viktor(viktor_http: respx.MockRouter) -> None: + catch_all = viktor_http.route().mock(return_value=httpx.Response(500)) + + with pytest.raises(ValueError): + litellm.transcription(model="viktor/viktor", file=("a.wav", b"RIFF", "audio/wav")) + + assert not catch_all.called + + +def test_endpoint_matrix_matches_its_backup() -> None: + def endpoints(path: Path) -> dict: return json.loads(path.read_text())["providers"]["viktor"]["endpoints"] - def test_viktor_supported_endpoints_matrix(self): - endpoints = self._endpoints(Path(litellm.__file__).parent / "provider_endpoints_support_backup.json") + root = Path(__file__).parents[4] / "provider_endpoints_support.json" + backup = Path(litellm.__file__).parent / "provider_endpoints_support_backup.json" - assert endpoints["chat_completions"] is True - assert endpoints["responses"] is True - assert endpoints["embeddings"] is False - - def test_viktor_endpoint_matrix_synced_to_backup(self): - root = Path(__file__).parents[4] / "provider_endpoints_support.json" - backup = Path(litellm.__file__).parent / "provider_endpoints_support_backup.json" - - assert self._endpoints(root) == self._endpoints(backup) + assert endpoints(root) == endpoints(backup) + assert endpoints(root)["responses"] is JSONProviderRegistry.supports_responses_api("viktor") From 51928d44ea020bc7c7fac349ce61e3317c7dd463 Mon Sep 17 00:00:00 2001 From: Ivan Charapanau Date: Fri, 25 Sep 2026 12:04:28 +0000 Subject: [PATCH 5/5] test(providers): match the Viktor transcription refusal message --- tests/test_litellm/llms/openai_like/test_viktor_provider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_litellm/llms/openai_like/test_viktor_provider.py b/tests/test_litellm/llms/openai_like/test_viktor_provider.py index 1369cc11157..47f460c1c16 100644 --- a/tests/test_litellm/llms/openai_like/test_viktor_provider.py +++ b/tests/test_litellm/llms/openai_like/test_viktor_provider.py @@ -131,7 +131,7 @@ def test_router_deployment_reaches_viktor(viktor_http: respx.MockRouter, base_ur def test_transcription_is_refused_without_calling_viktor(viktor_http: respx.MockRouter) -> None: catch_all = viktor_http.route().mock(return_value=httpx.Response(500)) - with pytest.raises(ValueError): + with pytest.raises(ValueError, match="Unmapped provider"): litellm.transcription(model="viktor/viktor", file=("a.wav", b"RIFF", "audio/wav")) assert not catch_all.called