This commit is contained in:
Konstantin Romankov 2026-09-12 18:47:24 +08:00 committed by GitHub
commit b7126d6b4c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 901 additions and 0 deletions

View file

@ -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`

View file

@ -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"]
}
}

View file

@ -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,

View file

@ -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",

View file

@ -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",

View file

@ -4011,6 +4011,7 @@ class LlmProviders(str, Enum):
LIBERTAI = "libertai"
PINSTRIPES = "pinstripes"
COGNITION = "cognition"
HUBRIS = "hubris"
SCX_AI = "scx-ai"
DARKBLOOM = "darkbloom"
META = "meta"

View file

@ -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,

View file

@ -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",

View file

@ -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

View file

@ -0,0 +1,25 @@
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g stroke="#8B6BFF" stroke-width="0.7" opacity="0.4">
<line x1="12" y1="12" x2="12" y2="3.5"/>
<line x1="12" y1="12" x2="20.5" y2="12"/>
<line x1="12" y1="12" x2="12" y2="20.5"/>
<line x1="12" y1="12" x2="3.5" y2="12"/>
</g>
<g stroke="#8B6BFF" stroke-width="0.7" opacity="0.3">
<line x1="12" y1="12" x2="18.5" y2="5.5"/>
<line x1="12" y1="12" x2="18.5" y2="18.5"/>
<line x1="12" y1="12" x2="5.5" y2="18.5"/>
<line x1="12" y1="12" x2="5.5" y2="5.5"/>
</g>
<g fill="#8B6BFF">
<circle cx="12" cy="12" r="2.4"/>
<circle cx="12" cy="3.5" r="1.4" opacity="0.85"/>
<circle cx="20.5" cy="12" r="1.4" opacity="0.85"/>
<circle cx="12" cy="20.5" r="1.4" opacity="0.85"/>
<circle cx="3.5" cy="12" r="1.4" opacity="0.85"/>
<circle cx="18.5" cy="5.5" r="1.1" opacity="0.6"/>
<circle cx="18.5" cy="18.5" r="1.1" opacity="0.6"/>
<circle cx="5.5" cy="18.5" r="1.1" opacity="0.6"/>
<circle cx="5.5" cy="5.5" r="1.1" opacity="0.6"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1,000 B