diff --git a/litellm/constants.py b/litellm/constants.py index 6b984c2673c..16f014ad60e 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -893,6 +893,7 @@ openai_compatible_endpoints: Final[list] = [ "https://pinstripes.io/v1", "https://api.meta.ai/v1", "https://api.cognition.ai/v1", + "https://api.hubris.pw/v1", "https://api.scx.ai/v1", "https://gigachat.devices.sberbank.ru/api/v1", ] @@ -965,6 +966,7 @@ openai_compatible_providers: Final[list] = [ "darkbloom", "meta", # Meta Model API (Muse Spark) - JSON-configured provider "cognition", + "hubris", "scx-ai", ] openai_text_completion_compatible_providers: Final[list] = [ # providers that support `/v1/completions` diff --git a/litellm/llms/openai_like/providers.json b/litellm/llms/openai_like/providers.json index a458a209ea9..78cfde357d3 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"] + }, + "hubris": { + "base_url": "https://api.hubris.pw/v1", + "api_key_env": "HUBRIS_API_KEY", + "api_base_env": "HUBRIS_API_BASE", + "supported_endpoints": ["/v1/chat/completions", "/v1/responses", "/v1/messages"] } } diff --git a/litellm/model_prices_and_context_window_backup.json b/litellm/model_prices_and_context_window_backup.json index 7fa09951eae..01c16ea037f 100644 --- a/litellm/model_prices_and_context_window_backup.json +++ b/litellm/model_prices_and_context_window_backup.json @@ -60550,6 +60550,312 @@ "supports_tool_choice": true, "supports_vision": true }, + "hubris/anthropic/claude-haiku-4.5": { + "input_cost_per_token": 1.46138e-06, + "output_cost_per_token": 7.30644e-06, + "litellm_provider": "hubris", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "prompt_cache_min_tokens": 4096, + "source": "https://hubris.pw/models", + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_native_structured_output": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true + }, + "hubris/anthropic/claude-opus-5": { + "input_cost_per_token": 7.30644e-06, + "output_cost_per_token": 3.6532e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "prompt_cache_min_tokens": 512, + "source": "https://hubris.pw/models", + "supports_adaptive_thinking": true, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_max_reasoning_effort": true, + "supports_mid_conversation_system": true, + "supports_native_structured_output": true, + "supports_output_config": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_sampling_params": false, + "supports_speed": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/anthropic/claude-sonnet-5": { + "input_cost_per_token": 2.92265e-06, + "output_cost_per_token": 1.46128e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "prompt_cache_min_tokens": 1024, + "source": "https://hubris.pw/models", + "supports_adaptive_thinking": true, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_max_reasoning_effort": true, + "supports_mid_conversation_system": true, + "supports_native_structured_output": true, + "supports_output_config": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_sampling_params": false, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/deepseek/deepseek-v4-flash": { + "input_cost_per_token": 1.2952e-07, + "output_cost_per_token": 2.5904e-07, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 384000, + "max_tokens": 384000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_assistant_prefill": true, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": false + }, + "hubris/deepseek/deepseek-v4-pro": { + "input_cost_per_token": 1.39593e-06, + "output_cost_per_token": 2.79185e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 384000, + "max_tokens": 384000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_assistant_prefill": true, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": false + }, + "hubris/google/gemini-3.7-flash": { + "input_cost_per_token": 1.09607e-06, + "output_cost_per_token": 5.47986e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 65536, + "max_tokens": 65536, + "mode": "chat", + "prompt_cache_min_tokens": 4096, + "source": "https://hubris.pw/models", + "supports_audio_input": true, + "supports_audio_output": false, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_url_context": true, + "supports_video_input": true, + "supports_vision": true, + "supports_web_search": true + }, + "hubris/google/gemini-3.8-flash": { + "input_cost_per_token": 1.09607e-06, + "output_cost_per_token": 5.47986e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 65536, + "max_tokens": 65536, + "mode": "chat", + "prompt_cache_min_tokens": 4096, + "source": "https://hubris.pw/models", + "supports_audio_input": true, + "supports_audio_output": false, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_url_context": true, + "supports_video_input": true, + "supports_vision": true, + "supports_web_search": true + }, + "hubris/minimax/minimax-m3": { + "input_cost_per_token": 4.38403e-07, + "output_cost_per_token": 1.75361e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 512000, + "max_tokens": 512000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true + }, + "hubris/moonshotai/kimi-k3": { + "input_cost_per_token": 4.38391e-06, + "output_cost_per_token": 2.19192e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 943718, + "max_tokens": 943718, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_video_input": true, + "supports_vision": true + }, + "hubris/openai/gpt-5.4-mini": { + "input_cost_per_token": 1.09607e-06, + "output_cost_per_token": 6.57581e-06, + "litellm_provider": "hubris", + "max_input_tokens": 400000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_minimal_reasoning_effort": false, + "supports_native_streaming": true, + "supports_none_reasoning_effort": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/openai/gpt-5.6-luna": { + "input_cost_per_token": 2.92346e-07, + "output_cost_per_token": 1.75361e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_minimal_reasoning_effort": false, + "supports_native_streaming": true, + "supports_none_reasoning_effort": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_cache_breakpoint": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/openai/gpt-6-astra": { + "input_cost_per_token": 1.46128e-05, + "output_cost_per_token": 7.30638e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_computer_use": true, + "supports_function_calling": true, + "supports_max_reasoning_effort": true, + "supports_minimal_reasoning_effort": false, + "supports_native_streaming": true, + "supports_none_reasoning_effort": false, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_cache_breakpoint": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/x-ai/grok-4.6": { + "input_cost_per_token": 2.92265e-06, + "output_cost_per_token": 8.76771e-06, + "litellm_provider": "hubris", + "max_input_tokens": 500000, + "max_output_tokens": 450000, + "max_tokens": 450000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true + }, + "hubris/z-ai/glm-5.3": { + "input_cost_per_token": 2.04584e-06, + "output_cost_per_token": 6.42964e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1310720, + "max_output_tokens": 943718, + "max_tokens": 943718, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": false + }, "mistral/mistral-medium-3.5": { "cache_read_input_token_cost": 1.5e-07, "input_cost_per_token": 1.5e-06, diff --git a/litellm/provider_endpoints_support_backup.json b/litellm/provider_endpoints_support_backup.json index dbeaccdda2d..613b2e0c237 100644 --- a/litellm/provider_endpoints_support_backup.json +++ b/litellm/provider_endpoints_support_backup.json @@ -1239,6 +1239,24 @@ "interactions": true } }, + "hubris": { + "display_name": "Hubris (`hubris`)", + "url": "https://hubris.pw/docs", + "endpoints": { + "chat_completions": true, + "messages": true, + "responses": true, + "embeddings": true, + "image_generations": true, + "audio_transcriptions": true, + "audio_speech": true, + "moderations": false, + "batches": false, + "rerank": false, + "a2a": false, + "interactions": false + } + }, "hyperbolic": { "display_name": "Hyperbolic (`hyperbolic`)", "url": "https://docs.litellm.ai/docs/providers/hyperbolic", diff --git a/litellm/proxy/public_endpoints/provider_create_fields.json b/litellm/proxy/public_endpoints/provider_create_fields.json index cd781abee26..95f00e56f8c 100644 --- a/litellm/proxy/public_endpoints/provider_create_fields.json +++ b/litellm/proxy/public_endpoints/provider_create_fields.json @@ -2851,6 +2851,34 @@ ], "default_model_placeholder": "sap/gpt-4" }, + { + "provider": "HUBRIS", + "provider_display_name": "Hubris", + "litellm_provider": "hubris", + "credential_fields": [ + { + "key": "api_base", + "label": "API Base", + "placeholder": "https://api.hubris.pw/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": "hubris/anthropic/claude-sonnet-5" + }, { "provider": "SCX_AI", "provider_display_name": "SCX.ai", diff --git a/litellm/types/utils.py b/litellm/types/utils.py index e3ea37dc0c8..89a1df98646 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -4011,6 +4011,7 @@ class LlmProviders(str, Enum): LIBERTAI = "libertai" PINSTRIPES = "pinstripes" COGNITION = "cognition" + HUBRIS = "hubris" SCX_AI = "scx-ai" DARKBLOOM = "darkbloom" META = "meta" diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 7fa09951eae..01c16ea037f 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -60550,6 +60550,312 @@ "supports_tool_choice": true, "supports_vision": true }, + "hubris/anthropic/claude-haiku-4.5": { + "input_cost_per_token": 1.46138e-06, + "output_cost_per_token": 7.30644e-06, + "litellm_provider": "hubris", + "max_input_tokens": 200000, + "max_output_tokens": 64000, + "max_tokens": 64000, + "mode": "chat", + "prompt_cache_min_tokens": 4096, + "source": "https://hubris.pw/models", + "supports_assistant_prefill": true, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_native_structured_output": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true + }, + "hubris/anthropic/claude-opus-5": { + "input_cost_per_token": 7.30644e-06, + "output_cost_per_token": 3.6532e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "prompt_cache_min_tokens": 512, + "source": "https://hubris.pw/models", + "supports_adaptive_thinking": true, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_max_reasoning_effort": true, + "supports_mid_conversation_system": true, + "supports_native_structured_output": true, + "supports_output_config": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_sampling_params": false, + "supports_speed": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/anthropic/claude-sonnet-5": { + "input_cost_per_token": 2.92265e-06, + "output_cost_per_token": 1.46128e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1000000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "prompt_cache_min_tokens": 1024, + "source": "https://hubris.pw/models", + "supports_adaptive_thinking": true, + "supports_assistant_prefill": false, + "supports_computer_use": true, + "supports_function_calling": true, + "supports_max_reasoning_effort": true, + "supports_mid_conversation_system": true, + "supports_native_structured_output": true, + "supports_output_config": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_sampling_params": false, + "supports_tool_choice": true, + "supports_vision": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/deepseek/deepseek-v4-flash": { + "input_cost_per_token": 1.2952e-07, + "output_cost_per_token": 2.5904e-07, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 384000, + "max_tokens": 384000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_assistant_prefill": true, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": false + }, + "hubris/deepseek/deepseek-v4-pro": { + "input_cost_per_token": 1.39593e-06, + "output_cost_per_token": 2.79185e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 384000, + "max_tokens": 384000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_assistant_prefill": true, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": false + }, + "hubris/google/gemini-3.7-flash": { + "input_cost_per_token": 1.09607e-06, + "output_cost_per_token": 5.47986e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 65536, + "max_tokens": 65536, + "mode": "chat", + "prompt_cache_min_tokens": 4096, + "source": "https://hubris.pw/models", + "supports_audio_input": true, + "supports_audio_output": false, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_url_context": true, + "supports_video_input": true, + "supports_vision": true, + "supports_web_search": true + }, + "hubris/google/gemini-3.8-flash": { + "input_cost_per_token": 1.09607e-06, + "output_cost_per_token": 5.47986e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 65536, + "max_tokens": 65536, + "mode": "chat", + "prompt_cache_min_tokens": 4096, + "source": "https://hubris.pw/models", + "supports_audio_input": true, + "supports_audio_output": false, + "supports_function_calling": true, + "supports_native_streaming": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_url_context": true, + "supports_video_input": true, + "supports_vision": true, + "supports_web_search": true + }, + "hubris/minimax/minimax-m3": { + "input_cost_per_token": 4.38403e-07, + "output_cost_per_token": 1.75361e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 512000, + "max_tokens": 512000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true + }, + "hubris/moonshotai/kimi-k3": { + "input_cost_per_token": 4.38391e-06, + "output_cost_per_token": 2.19192e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1048576, + "max_output_tokens": 943718, + "max_tokens": 943718, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_video_input": true, + "supports_vision": true + }, + "hubris/openai/gpt-5.4-mini": { + "input_cost_per_token": 1.09607e-06, + "output_cost_per_token": 6.57581e-06, + "litellm_provider": "hubris", + "max_input_tokens": 400000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_minimal_reasoning_effort": false, + "supports_native_streaming": true, + "supports_none_reasoning_effort": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/openai/gpt-5.6-luna": { + "input_cost_per_token": 2.92346e-07, + "output_cost_per_token": 1.75361e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_minimal_reasoning_effort": false, + "supports_native_streaming": true, + "supports_none_reasoning_effort": true, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_cache_breakpoint": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/openai/gpt-6-astra": { + "input_cost_per_token": 1.46128e-05, + "output_cost_per_token": 7.30638e-05, + "litellm_provider": "hubris", + "max_input_tokens": 1050000, + "max_output_tokens": 128000, + "max_tokens": 128000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_computer_use": true, + "supports_function_calling": true, + "supports_max_reasoning_effort": true, + "supports_minimal_reasoning_effort": false, + "supports_native_streaming": true, + "supports_none_reasoning_effort": false, + "supports_parallel_function_calling": true, + "supports_pdf_input": true, + "supports_prompt_cache_breakpoint": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_system_messages": true, + "supports_tool_choice": true, + "supports_vision": true, + "supports_web_search": true, + "supports_xhigh_reasoning_effort": true + }, + "hubris/x-ai/grok-4.6": { + "input_cost_per_token": 2.92265e-06, + "output_cost_per_token": 8.76771e-06, + "litellm_provider": "hubris", + "max_input_tokens": 500000, + "max_output_tokens": 450000, + "max_tokens": 450000, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": true + }, + "hubris/z-ai/glm-5.3": { + "input_cost_per_token": 2.04584e-06, + "output_cost_per_token": 6.42964e-06, + "litellm_provider": "hubris", + "max_input_tokens": 1310720, + "max_output_tokens": 943718, + "max_tokens": 943718, + "mode": "chat", + "source": "https://hubris.pw/models", + "supports_function_calling": true, + "supports_prompt_caching": true, + "supports_reasoning": true, + "supports_response_schema": true, + "supports_tool_choice": true, + "supports_vision": false + }, "mistral/mistral-medium-3.5": { "cache_read_input_token_cost": 1.5e-07, "input_cost_per_token": 1.5e-06, diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index c71f4a82a4a..35865c8c0e3 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -1336,6 +1336,24 @@ "interactions": true } }, + "hubris": { + "display_name": "Hubris (`hubris`)", + "url": "https://hubris.pw/docs", + "endpoints": { + "chat_completions": true, + "messages": true, + "responses": true, + "embeddings": true, + "image_generations": true, + "audio_transcriptions": true, + "audio_speech": true, + "moderations": false, + "batches": false, + "rerank": false, + "a2a": false, + "interactions": false + } + }, "hyperbolic": { "display_name": "Hyperbolic (`hyperbolic`)", "url": "https://docs.litellm.ai/docs/providers/hyperbolic", diff --git a/tests/test_litellm/llms/openai_like/test_hubris_provider.py b/tests/test_litellm/llms/openai_like/test_hubris_provider.py new file mode 100644 index 00000000000..4f1d792abb7 --- /dev/null +++ b/tests/test_litellm/llms/openai_like/test_hubris_provider.py @@ -0,0 +1,191 @@ +""" +Tests for the Hubris provider. + +Hubris (https://hubris.pw) is an OpenAI-compatible LLM gateway registered purely +via the JSON provider registry (``litellm/llms/openai_like/providers.json``); +it has no hand-written transformation class. Model ids on Hubris always use the +full ``vendor/model`` form (e.g. ``anthropic/claude-sonnet-5``), which LiteLLM +passes through verbatim after stripping the ``hubris/`` prefix. +""" + +import json + +import pytest + +import litellm +from litellm import completion +from litellm.llms.openai_like.dynamic_config import create_config_class +from litellm.llms.openai_like.json_loader import JSONProviderRegistry + +API_BASE = "https://api.hubris.pw/v1" +CHAT_URL = f"{API_BASE}/chat/completions" +MODEL = "hubris/anthropic/claude-sonnet-5" +BARE_MODEL = "anthropic/claude-sonnet-5" + + +def _new_config(): + return create_config_class(JSONProviderRegistry.get("hubris"))() + + +def _completion_payload(content="Hi from Hubris!"): + return { + "id": "chatcmpl-123", + "object": "chat.completion", + "created": 1677652288, + "model": BARE_MODEL, + "choices": [ + { + "index": 0, + "message": {"role": "assistant", "content": content}, + "finish_reason": "stop", + } + ], + "usage": {"prompt_tokens": 9, "completion_tokens": 12, "total_tokens": 21}, + } + + +class TestHubrisProviderRegistration: + def test_hubris_registered_in_json_registry(self): + assert JSONProviderRegistry.exists("hubris") + + config = JSONProviderRegistry.get("hubris") + assert config is not None + assert config.base_url == API_BASE + assert config.api_key_env == "HUBRIS_API_KEY" + assert config.api_base_env == "HUBRIS_API_BASE" + + def test_hubris_listed(self): + assert "hubris" in JSONProviderRegistry.list_providers() + + def test_hubris_config_defaults(self): + config = JSONProviderRegistry.get("hubris") + assert config.base_class == "openai_gpt" + assert config.param_mappings == {} + assert config.constraints == {} + assert config.special_handling == {} + + def test_hubris_advertises_responses_api(self): + assert JSONProviderRegistry.supports_responses_api("hubris") is True + + +class TestHubrisProviderResolution: + def test_get_llm_provider_resolves_hubris(self, monkeypatch): + monkeypatch.setenv("HUBRIS_API_KEY", "sk-gw-test") + + model, custom_llm_provider, dynamic_api_key, api_base = ( + litellm.get_llm_provider(model=MODEL) + ) + + # Only the leading "hubris/" is stripped; the vendor prefix stays. + assert model == BARE_MODEL + assert custom_llm_provider == "hubris" + assert dynamic_api_key == "sk-gw-test" + assert api_base == API_BASE + + def test_get_llm_provider_uses_explicit_api_key(self, monkeypatch): + monkeypatch.setenv("HUBRIS_API_KEY", "env-key") + + _, _, dynamic_api_key, _ = litellm.get_llm_provider( + model=MODEL, api_key="sk-explicit" + ) + assert dynamic_api_key == "sk-explicit" + + def test_get_llm_provider_honors_api_base_override(self): + _, custom_llm_provider, _, api_base = litellm.get_llm_provider( + model=MODEL, api_base="https://custom.example/v1" + ) + assert custom_llm_provider == "hubris" + assert api_base == "https://custom.example/v1" + + def test_get_llm_provider_honors_api_base_env(self, monkeypatch): + monkeypatch.setenv("HUBRIS_API_BASE", "https://env.example/v1") + monkeypatch.setenv("HUBRIS_API_KEY", "env-key") + + _, custom_llm_provider, _, api_base = litellm.get_llm_provider(model=MODEL) + assert custom_llm_provider == "hubris" + assert api_base == "https://env.example/v1" + +class TestHubrisDynamicConfig: + def test_custom_llm_provider(self): + assert _new_config().custom_llm_provider == "hubris" + + def test_get_complete_url_appends_chat_completions(self): + url = _new_config().get_complete_url( + api_base=API_BASE, + api_key="k", + model=BARE_MODEL, + optional_params={}, + litellm_params={}, + ) + assert url == CHAT_URL + + def test_get_complete_url_falls_back_to_base_url(self): + url = _new_config().get_complete_url( + api_base=None, + api_key="k", + model=BARE_MODEL, + optional_params={}, + litellm_params={}, + ) + assert url == CHAT_URL + + def test_provider_info_resolves_from_env(self, monkeypatch): + monkeypatch.setenv("HUBRIS_API_KEY", "env-key") + base, key = _new_config()._get_openai_compatible_provider_info(None, None) + assert base == API_BASE + assert key == "env-key" + + def test_standard_sampling_params_pass_through(self): + out = _new_config().map_openai_params( + non_default_params={"temperature": 0.6, "top_p": 0.9}, + optional_params={}, + model=BARE_MODEL, + drop_params=False, + ) + assert out == {"temperature": 0.6, "top_p": 0.9} + + +class TestHubrisCompletion: + @pytest.fixture(autouse=True) + def _disable_aiohttp(self, monkeypatch): + # respx mocks the httpx transport, so the aiohttp transport must be off. + monkeypatch.setattr(litellm, "disable_aiohttp_transport", True) + + @pytest.mark.respx() + def test_completion_sends_correct_url_and_body(self, respx_mock): + route = respx_mock.post(CHAT_URL).respond( + json=_completion_payload(), status_code=200 + ) + + response = completion( + model=MODEL, + messages=[{"role": "user", "content": "say hi"}], + api_key="sk-gw-test", + api_base=API_BASE, + temperature=0.6, + ) + + assert route.called + request = route.calls.last.request + assert str(request.url) == CHAT_URL + assert request.headers["authorization"] == "Bearer sk-gw-test" + body = json.loads(request.content) + assert body["model"] == BARE_MODEL + assert body["messages"] == [{"role": "user", "content": "say hi"}] + assert body["temperature"] == 0.6 + assert response.choices[0].message.content == "Hi from Hubris!" + assert response.usage.total_tokens == 21 + + def test_streaming_yields_content_chunks(self): + chunks = list( + completion( + model=MODEL, + messages=[{"role": "user", "content": "hi"}], + api_key="sk-gw-test", + stream=True, + mock_response="Hello from Hubris", + ) + ) + assert len(chunks) > 0 + text = "".join((c.choices[0].delta.content or "") for c in chunks) + assert "Hello from Hubris" in text diff --git a/ui/litellm-dashboard/public/assets/logos/hubris.svg b/ui/litellm-dashboard/public/assets/logos/hubris.svg new file mode 100644 index 00000000000..5f1bbc2553f --- /dev/null +++ b/ui/litellm-dashboard/public/assets/logos/hubris.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + +