From 2da31fc541aec216cf2cd23272daf8a0a08b19c6 Mon Sep 17 00:00:00 2001 From: Kunal Das Date: Mon, 2 Nov 2026 09:40:37 +0000 Subject: [PATCH 1/3] feat(providers): add Kimchi as JSON-configured openai_like provider --- litellm/constants.py | 2 + litellm/llms/openai_like/providers.json | 8 ++ litellm/types/utils.py | 1 + .../llms/openai_like/test_kimchi_provider.py | 129 ++++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 tests/unit/llms/openai_like/test_kimchi_provider.py diff --git a/litellm/constants.py b/litellm/constants.py index cd7c0176428..8c80f184aa9 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -1082,6 +1082,7 @@ openai_compatible_endpoints: Final[list[str]] = [ "https://api.cognition.ai/v1", "https://inference.coralbricks.ai/v1", "https://api.cortecs.ai/v1", + "https://llm.kimchi.dev/openai/v1", "https://api.scx.ai/v1", "https://api.prisminference.com/v1", "https://api.reka.ai/v1", @@ -1170,6 +1171,7 @@ openai_compatible_providers: Final[list[str]] = [ "prism", "hostinger_router", "sail", + "kimchi", # Kimchi - JSON-configured provider "reka", "streamlake", ] diff --git a/litellm/llms/openai_like/providers.json b/litellm/llms/openai_like/providers.json index a71a9c3bb9b..25c11a78343 100644 --- a/litellm/llms/openai_like/providers.json +++ b/litellm/llms/openai_like/providers.json @@ -302,5 +302,13 @@ "preserve_cache_control": true }, "supported_endpoints": ["/v1/chat/completions"] + }, + "kimchi": { + "base_url": "https://llm.kimchi.dev/openai/v1", + "api_key_env": "KIMCHI_API_KEY", + "api_base_env": "KIMCHI_API_BASE", + "supported_endpoints": [ + "/v1/chat/completions" + ] } } diff --git a/litellm/types/utils.py b/litellm/types/utils.py index da1d99957a7..45016785ccc 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -4594,6 +4594,7 @@ class LlmProviders(str, Enum): V0 = "v0" MORPH = "morph" OPENCODE_GO = "opencode_go" + KIMCHI = "kimchi" LAMBDA_AI = "lambda_ai" INCEPTION = "inception" TEXT_COMPLETION_INCEPTION = "text-completion-inception" diff --git a/tests/unit/llms/openai_like/test_kimchi_provider.py b/tests/unit/llms/openai_like/test_kimchi_provider.py new file mode 100644 index 00000000000..053bfcbdf87 --- /dev/null +++ b/tests/unit/llms/openai_like/test_kimchi_provider.py @@ -0,0 +1,129 @@ +""" +Tests for the Kimchi provider identity. + +Kimchi exposes an OpenAI-compatible /v1/chat/completions surface at +https://llm.kimchi.dev/openai/v1. Its provider identity must resolve to a +distinct `kimchi` slug so OpenAI-specific pricing and provider-level reporting +never apply to traffic routed through Kimchi. +""" + +import json +from pathlib import Path +from typing import Final + +import pytest +import respx + +import litellm + + +class TestKimchiProviderIdentity: + def test_kimchi_is_a_registered_provider(self): + from litellm import LlmProviders + + assert LlmProviders.KIMCHI.value == "kimchi" + assert "kimchi" in litellm.provider_list + + def test_kimchi_json_config(self): + from litellm.llms.openai_like.json_loader import JSONProviderRegistry + + kimchi = JSONProviderRegistry.get("kimchi") + assert kimchi is not None + assert kimchi.base_url == "https://llm.kimchi.dev/openai/v1" + assert kimchi.api_key_env == "KIMCHI_API_KEY" + assert kimchi.api_base_env == "KIMCHI_API_BASE" + + def test_kimchi_in_openai_compatible_providers(self): + from litellm.constants import openai_compatible_providers + + assert "kimchi" in openai_compatible_providers + + def test_prefixed_model_resolves_to_kimchi_not_openai(self): + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + model, provider, _, api_base = get_llm_provider( + model="kimchi/kimi-k3", + custom_llm_provider=None, + api_base=None, + api_key=None, + ) + + assert model == "kimi-k3" + assert provider == "kimchi" + assert api_base == "https://llm.kimchi.dev/openai/v1" + + def test_explicit_api_base_and_key_win(self): + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + _, provider, api_key, api_base = get_llm_provider( + model="kimchi/kimi-k3", + custom_llm_provider=None, + api_base="https://kimchi.internal.example/v1", + api_key="sk-test", + ) + + assert provider == "kimchi" + assert api_base == "https://kimchi.internal.example/v1" + assert api_key == "sk-test" + + def test_api_base_autodetects_kimchi(self, monkeypatch): + from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider + + monkeypatch.setenv("KIMCHI_API_KEY", "sk-test") + + _, provider, api_key, api_base = get_llm_provider( + model="kimi-k3", + custom_llm_provider=None, + api_base="https://llm.kimchi.dev/openai/v1", + api_key=None, + ) + + assert provider == "kimchi" + assert api_base == "https://llm.kimchi.dev/openai/v1" + assert api_key == "sk-test" + + +def test_kimchi_chat_request(monkeypatch: pytest.MonkeyPatch): + monkeypatch.setenv("KIMCHI_API_KEY", "kimchi-test-key") + + with respx.mock() as upstream: + route: Final = upstream.post("https://llm.kimchi.dev/openai/v1/chat/completions").respond( + 200, + json={ + "id": "chatcmpl-kimchi", + "object": "chat.completion", + "created": 1_789_550_000, + "model": "kimi-k3", + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": {"role": "assistant", "content": "pong"}, + } + ], + "usage": {"prompt_tokens": 4, "completion_tokens": 1, "total_tokens": 5}, + }, + ) + response: Final = litellm.completion( + model="kimchi/kimi-k3", + messages=[{"role": "user", "content": "Reply with the single word: pong"}], + ) + + request: Final = route.calls.last.request + assert route.call_count == 1 + assert str(request.url) == "https://llm.kimchi.dev/openai/v1/chat/completions" + assert request.headers["authorization"] == "Bearer kimchi-test-key" + body: Final = json.loads(request.content) + assert body["model"] == "kimi-k3" + assert response.choices[0].message.content == "pong" + + +def test_kimchi_cost_map_registry_mirrors_cost_map(): + package_root: Final = Path(litellm.__file__).parent + + cost_map: Final = json.loads((package_root.parent / "model_prices_and_context_window.json").read_text()) + backup: Final = json.loads((package_root / "model_prices_and_context_window_backup.json").read_text()) + + kimchi_entries: Final = {name: cost_map[name] for name in cost_map if name.startswith("kimchi/")} + assert kimchi_entries + assert kimchi_entries == {name: backup[name] for name in kimchi_entries} From 2b6437a3d7c6f1e0f58a7746ed27d0dcfc7c6fb6 Mon Sep 17 00:00:00 2001 From: Kunal Das Date: Mon, 2 Nov 2026 09:40:37 +0000 Subject: [PATCH 2/3] fix(ci): register kimchi in provider doc + add-model dropdown registries code-quality failed on check_provider_folders_documented because every openai_like provider needs an entry in provider_endpoints_support.json, and proxy-endpoints failed on the Add Model dropdown drift test that requires a provider_create_fields.json entry instead of growing the frozen unlisted set. Adds both entries with chat completions only, matching what the Kimchi gateway exposes today. --- .../provider_create_fields.json | 35 +++++++++++++++++-- provider_endpoints_support.json | 18 ++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index 044b8a1de6e..8b4d8ab71d4 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -488,7 +488,7 @@ "key": "api_base", "label": "Upstream API Base", "placeholder": "https://api.anthropic.com", - "tooltip": "Optional. Where the proxy forwards requests upstream. Leave blank to use Anthropic's public API. Set this only for private Anthropic deployments or reverse proxies. Do NOT set this to your LiteLLM proxy URL — that causes a recursive loop.", + "tooltip": "Optional. Where the proxy forwards requests upstream. Leave blank to use Anthropic's public API. Set this only for private Anthropic deployments or reverse proxies. Do NOT set this to your LiteLLM proxy URL \u2014 that causes a recursive loop.", "required": false, "field_type": "text", "options": null, @@ -2455,7 +2455,10 @@ "tooltip": "jwt_bearer_obo: on-behalf-of with the JWT bearer grant (Microsoft Entra). rfc8693: standard OAuth 2.0 token exchange.", "required": false, "field_type": "select", - "options": ["jwt_bearer_obo", "rfc8693"], + "options": [ + "jwt_bearer_obo", + "rfc8693" + ], "default_value": "jwt_bearer_obo" }, { @@ -4424,5 +4427,33 @@ } ], "default_model_placeholder": "bigmodel/glm-5.3" + }, + { + "provider": "Kimchi", + "provider_display_name": "Kimchi", + "litellm_provider": "kimchi", + "credential_fields": [ + { + "key": "api_key", + "label": "Kimchi API Key", + "placeholder": null, + "tooltip": null, + "required": true, + "field_type": "password", + "options": null, + "default_value": null + }, + { + "key": "api_base", + "label": "API Base", + "placeholder": "https://llm.kimchi.dev/openai/v1", + "tooltip": null, + "required": false, + "field_type": "text", + "options": null, + "default_value": null + } + ], + "default_model_placeholder": "kimchi/kimi-k3" } ] diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 700a35edb06..816d0b9f622 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -2657,6 +2657,24 @@ "generateContent": false } }, + "kimchi": { + "display_name": "Kimchi (`kimchi`)", + "url": "https://docs.litellm.ai/docs/providers/kimchi", + "endpoints": { + "chat_completions": true, + "messages": false, + "responses": false, + "embeddings": false, + "image_generations": false, + "audio_transcriptions": false, + "audio_speech": false, + "moderations": false, + "batches": false, + "rerank": false, + "a2a": false, + "interactions": false + } + }, "morph": { "display_name": "Morph (`morph`)", "url": "https://docs.litellm.ai/docs/providers/morph", From d1426748c19cf83886df98d42861526b6a984862 Mon Sep 17 00:00:00 2001 From: Kunal Das Date: Mon, 2 Nov 2026 09:40:37 +0000 Subject: [PATCH 3/3] fix(pricing): add kimchi model costs and request-level test --- ...odel_prices_and_context_window_backup.json | 131 ++++++++++++++++++ .../provider_create_fields.json | 7 +- model_prices_and_context_window.json | 131 ++++++++++++++++++ 3 files changed, 264 insertions(+), 5 deletions(-) diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index d68eb3ce775..9db14d628a1 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -63165,6 +63165,137 @@ "supports_prompt_caching": true, "source": "https://docs.devin.ai/desktop/models" }, + "kimchi/kimi-k3": { + "max_tokens": 262144, + "max_input_tokens": 262144, + "max_output_tokens": 262144, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "cache_read_input_token_cost": 3e-07, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/kimi-k2.7": { + "max_tokens": 262144, + "max_input_tokens": 262144, + "max_output_tokens": 262144, + "input_cost_per_token": 9.5e-07, + "output_cost_per_token": 4e-06, + "cache_read_input_token_cost": 1.9e-07, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/nemotron-3-ultra-fp4": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 6e-07, + "output_cost_per_token": 3.6e-06, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_native_streaming": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/deepseek-v4-flash": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.4e-07, + "output_cost_per_token": 2.8e-07, + "cache_read_input_token_cost": 7e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_native_streaming": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/deepseek-v4-flash-0731": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.4e-07, + "output_cost_per_token": 2.8e-07, + "cache_read_input_token_cost": 7e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_native_streaming": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/deepseek-v4.1-flash": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 6e-09, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_native_streaming": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/glm-5.3": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "cache_read_input_token_cost": 2.6e-07, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/glm-5.3-flash": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 5e-07, + "cache_read_input_token_cost": 3e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/minimax-m3": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 6e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_prompt_caching": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, "pinstripes/ps/glm-4.5-air": { "max_input_tokens": 128000, "max_output_tokens": 128000, diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index 8b4d8ab71d4..d42ca60ce97 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -488,7 +488,7 @@ "key": "api_base", "label": "Upstream API Base", "placeholder": "https://api.anthropic.com", - "tooltip": "Optional. Where the proxy forwards requests upstream. Leave blank to use Anthropic's public API. Set this only for private Anthropic deployments or reverse proxies. Do NOT set this to your LiteLLM proxy URL \u2014 that causes a recursive loop.", + "tooltip": "Optional. Where the proxy forwards requests upstream. Leave blank to use Anthropic's public API. Set this only for private Anthropic deployments or reverse proxies. Do NOT set this to your LiteLLM proxy URL — that causes a recursive loop.", "required": false, "field_type": "text", "options": null, @@ -2455,10 +2455,7 @@ "tooltip": "jwt_bearer_obo: on-behalf-of with the JWT bearer grant (Microsoft Entra). rfc8693: standard OAuth 2.0 token exchange.", "required": false, "field_type": "select", - "options": [ - "jwt_bearer_obo", - "rfc8693" - ], + "options": ["jwt_bearer_obo", "rfc8693"], "default_value": "jwt_bearer_obo" }, { diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index d68eb3ce775..9db14d628a1 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -63165,6 +63165,137 @@ "supports_prompt_caching": true, "source": "https://docs.devin.ai/desktop/models" }, + "kimchi/kimi-k3": { + "max_tokens": 262144, + "max_input_tokens": 262144, + "max_output_tokens": 262144, + "input_cost_per_token": 3e-06, + "output_cost_per_token": 1.5e-05, + "cache_read_input_token_cost": 3e-07, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/kimi-k2.7": { + "max_tokens": 262144, + "max_input_tokens": 262144, + "max_output_tokens": 262144, + "input_cost_per_token": 9.5e-07, + "output_cost_per_token": 4e-06, + "cache_read_input_token_cost": 1.9e-07, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/nemotron-3-ultra-fp4": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 6e-07, + "output_cost_per_token": 3.6e-06, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_native_streaming": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/deepseek-v4-flash": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.4e-07, + "output_cost_per_token": 2.8e-07, + "cache_read_input_token_cost": 7e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_native_streaming": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/deepseek-v4-flash-0731": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.4e-07, + "output_cost_per_token": 2.8e-07, + "cache_read_input_token_cost": 7e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_native_streaming": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/deepseek-v4.1-flash": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 6e-09, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_native_streaming": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/glm-5.3": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.4e-06, + "output_cost_per_token": 4.4e-06, + "cache_read_input_token_cost": 2.6e-07, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/glm-5.3-flash": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 1.5e-07, + "output_cost_per_token": 5e-07, + "cache_read_input_token_cost": 3e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, + "kimchi/minimax-m3": { + "max_tokens": 1000000, + "max_input_tokens": 1000000, + "max_output_tokens": 1000000, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.2e-06, + "cache_read_input_token_cost": 6e-08, + "litellm_provider": "kimchi", + "mode": "chat", + "supports_function_calling": true, + "supports_parallel_function_calling": true, + "supports_prompt_caching": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "source": "https://docs.kimchi.dev/docs/model-apis-pricing" + }, "pinstripes/ps/glm-4.5-air": { "max_input_tokens": 128000, "max_output_tokens": 128000,