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 <noreply@anthropic.com>
This commit is contained in:
Kyle D 2026-03-03 19:42:23 +00:00
parent 4c1b15d685
commit 743ebc2a65
6 changed files with 251 additions and 0 deletions

View file

@ -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) |
<br />
## 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 |

View file

@ -804,6 +804,7 @@ const sidebars = {
"providers/amazon_nova",
"providers/anyscale",
"providers/apertis",
"providers/avian",
"providers/baseten",
"providers/bytez",
"providers/cerebras",

View file

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

View file

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

View file

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

View file

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