From 743ebc2a659c9adf8dc78122125d0232b7930e51 Mon Sep 17 00:00:00 2001 From: Kyle D Date: Tue, 3 Mar 2026 19:42:23 +0000 Subject: [PATCH] feat: add Avian as a new OpenAI-compatible provider Add Avian (avian.io) as a JSON-configured OpenAI-compatible provider using the JSONProviderRegistry pattern (no custom handler code). Changes: - Add avian entry in providers.json with base URL and API key env - Add 4 model entries in model_prices_and_context_window.json (deepseek-v3.2, kimi-k2.5, glm-5, minimax-m2.5) - Add endpoint support declaration (chat_completions only) - Add docs page with SDK and proxy usage examples - Add sidebar navigation entry - Add unit tests for provider registration, env var resolution, and URL construction Co-Authored-By: Claude Opus 4.6 --- docs/my-website/docs/providers/avian.md | 130 ++++++++++++++++++ docs/my-website/sidebars.js | 1 + litellm/llms/openai_like/providers.json | 4 + model_prices_and_context_window.json | 49 +++++++ provider_endpoints_support.json | 17 +++ .../llms/openai_like/test_avian_provider.py | 50 +++++++ 6 files changed, 251 insertions(+) create mode 100644 docs/my-website/docs/providers/avian.md create mode 100644 tests/litellm/llms/openai_like/test_avian_provider.py diff --git a/docs/my-website/docs/providers/avian.md b/docs/my-website/docs/providers/avian.md new file mode 100644 index 00000000000..2fa71a7b5a6 --- /dev/null +++ b/docs/my-website/docs/providers/avian.md @@ -0,0 +1,130 @@ +# Avian + +## Overview + +| Property | Details | +|-------|-------| +| Description | Avian is an AI inference platform providing fast access to top open-source models through an OpenAI-compatible API. | +| Provider Route on LiteLLM | `avian/` | +| Link to Provider Doc | [Avian ↗](https://avian.io) | +| Base URL | `https://api.avian.io/v1` | +| Supported Operations | [`/chat/completions`](#usage---litellm-python-sdk), [`/models`](#supported-models) | + +
+ +## Required Variables + +```python showLineNumbers title="Environment Variables" +os.environ["AVIAN_API_KEY"] = "" # your Avian API key +``` + +Get your Avian API key from [avian.io](https://avian.io). + +## Usage - LiteLLM Python SDK + +### Non-streaming + +```python showLineNumbers title="Avian Non-streaming Completion" +import os +import litellm +from litellm import completion + +os.environ["AVIAN_API_KEY"] = "" # your Avian API key + +messages = [{"content": "What is the capital of France?", "role": "user"}] + +# Avian call +response = completion( + model="avian/deepseek/deepseek-v3.2", + messages=messages +) + +print(response) +``` + +### Streaming + +```python showLineNumbers title="Avian Streaming Completion" +import os +import litellm +from litellm import completion + +os.environ["AVIAN_API_KEY"] = "" # your Avian API key + +messages = [{"content": "What is the capital of France?", "role": "user"}] + +# Avian streaming call +response = completion( + model="avian/deepseek/deepseek-v3.2", + messages=messages, + stream=True +) + +for chunk in response: + print(chunk) +``` + +## Usage - LiteLLM Proxy Server + +Add to your `config.yaml`: + +```yaml showLineNumbers title="config.yaml" +model_list: + - model_name: deepseek-v3 + litellm_params: + model: avian/deepseek/deepseek-v3.2 + api_key: os.environ/AVIAN_API_KEY + - model_name: kimi-k2.5 + litellm_params: + model: avian/moonshotai/kimi-k2.5 + api_key: os.environ/AVIAN_API_KEY + - model_name: glm-5 + litellm_params: + model: avian/z-ai/glm-5 + api_key: os.environ/AVIAN_API_KEY + - model_name: minimax-m2.5 + litellm_params: + model: avian/minimax/minimax-m2.5 + api_key: os.environ/AVIAN_API_KEY +``` + +Start the proxy: + +```bash +litellm --config config.yaml +``` + +Send a request: + +```bash +curl http://localhost:4000/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-1234" \ + -d '{ + "model": "deepseek-v3", + "messages": [{"role": "user", "content": "Hello!"}] + }' +``` + +## Supported Models + +| Model | Model ID | +|-------|----------| +| DeepSeek V3.2 | `avian/deepseek/deepseek-v3.2` | +| Kimi K2.5 | `avian/moonshotai/kimi-k2.5` | +| GLM-5 | `avian/z-ai/glm-5` | +| MiniMax M2.5 | `avian/minimax/minimax-m2.5` | + +## Supported OpenAI Parameters + +Avian supports standard OpenAI chat completion parameters including: + +| Parameter | Supported | +|-----------|-----------| +| `temperature` | Yes | +| `top_p` | Yes | +| `max_tokens` / `max_completion_tokens` | Yes | +| `stream` | Yes | +| `stop` | Yes | +| `tools` / `tool_choice` | Yes | +| `response_format` | Yes | diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js index f7487d24b12..456c985fb9f 100644 --- a/docs/my-website/sidebars.js +++ b/docs/my-website/sidebars.js @@ -804,6 +804,7 @@ const sidebars = { "providers/amazon_nova", "providers/anyscale", "providers/apertis", + "providers/avian", "providers/baseten", "providers/bytez", "providers/cerebras", diff --git a/litellm/llms/openai_like/providers.json b/litellm/llms/openai_like/providers.json index b3125d4ad38..e673ba84cfb 100644 --- a/litellm/llms/openai_like/providers.json +++ b/litellm/llms/openai_like/providers.json @@ -69,6 +69,10 @@ "base_url": "https://api.abliteration.ai/v1", "api_key_env": "ABLITERATION_API_KEY" }, + "avian": { + "base_url": "https://api.avian.io/v1", + "api_key_env": "AVIAN_API_KEY" + }, "llamagate": { "base_url": "https://api.llamagate.dev/v1", "api_key_env": "LLAMAGATE_API_KEY", diff --git a/model_prices_and_context_window.json b/model_prices_and_context_window.json index 412f99791a0..cfc240fbc3b 100644 --- a/model_prices_and_context_window.json +++ b/model_prices_and_context_window.json @@ -279,6 +279,55 @@ "mode": "image_generation", "output_cost_per_image": 0.06 }, + "avian/deepseek/deepseek-v3.2": { + "max_tokens": 65536, + "max_input_tokens": 163840, + "max_output_tokens": 65536, + "input_cost_per_token": 2.6e-07, + "output_cost_per_token": 3.8e-07, + "litellm_provider": "avian", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "supports_response_schema": true, + "source": "https://avian.io" + }, + "avian/moonshotai/kimi-k2.5": { + "max_tokens": 262144, + "max_input_tokens": 131072, + "max_output_tokens": 262144, + "input_cost_per_token": 4.5e-07, + "output_cost_per_token": 2.2e-06, + "litellm_provider": "avian", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://avian.io" + }, + "avian/z-ai/glm-5": { + "max_tokens": 131072, + "max_input_tokens": 131072, + "max_output_tokens": 131072, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 2.55e-06, + "litellm_provider": "avian", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://avian.io" + }, + "avian/minimax/minimax-m2.5": { + "max_tokens": 131072, + "max_input_tokens": 1048576, + "max_output_tokens": 131072, + "input_cost_per_token": 3e-07, + "output_cost_per_token": 1.1e-06, + "litellm_provider": "avian", + "mode": "chat", + "supports_function_calling": true, + "supports_tool_choice": true, + "source": "https://avian.io" + }, "us.writer.palmyra-x4-v1:0": { "input_cost_per_token": 2.5e-06, "litellm_provider": "bedrock_converse", diff --git a/provider_endpoints_support.json b/provider_endpoints_support.json index 8834d8b19c0..5a936399771 100644 --- a/provider_endpoints_support.json +++ b/provider_endpoints_support.json @@ -66,6 +66,23 @@ "a2a": false } }, + "avian": { + "display_name": "Avian (`avian`)", + "url": "https://docs.litellm.ai/docs/providers/avian", + "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 + } + }, "aiml": { "display_name": "AI/ML API (`aiml`)", "url": "https://docs.litellm.ai/docs/providers/aiml", diff --git a/tests/litellm/llms/openai_like/test_avian_provider.py b/tests/litellm/llms/openai_like/test_avian_provider.py new file mode 100644 index 00000000000..410b68a8341 --- /dev/null +++ b/tests/litellm/llms/openai_like/test_avian_provider.py @@ -0,0 +1,50 @@ +""" +Unit tests for the Avian OpenAI-like provider. +""" + +import os +import sys + +sys.path.insert( + 0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../..")) +) + +from litellm.llms.openai_like.dynamic_config import create_config_class +from litellm.llms.openai_like.json_loader import JSONProviderRegistry + +AVIAN_BASE_URL = "https://api.avian.io/v1" + + +def _get_config(): + provider = JSONProviderRegistry.get("avian") + assert provider is not None + config_class = create_config_class(provider) + return config_class() + + +def test_avian_provider_registered(): + provider = JSONProviderRegistry.get("avian") + assert provider is not None + assert provider.base_url == AVIAN_BASE_URL + assert provider.api_key_env == "AVIAN_API_KEY" + + +def test_avian_resolves_env_api_key(monkeypatch): + config = _get_config() + monkeypatch.setenv("AVIAN_API_KEY", "test-key") + api_base, api_key = config._get_openai_compatible_provider_info(None, None) + assert api_base == AVIAN_BASE_URL + assert api_key == "test-key" + + +def test_avian_complete_url_appends_endpoint(): + config = _get_config() + url = config.get_complete_url( + api_base=AVIAN_BASE_URL, + api_key="test-key", + model="avian/deepseek/deepseek-v3.2", + optional_params={}, + litellm_params={}, + stream=False, + ) + assert url == f"{AVIAN_BASE_URL}/chat/completions"