Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ OPENAI_API_KEY=your_openai_api_key # Required for embeddings and OpenAI m

# Optional API Keys
OPENROUTER_API_KEY=your_openrouter_api_key # Required only if using OpenRouter models
ORCAROUTER_API_KEY=your_orcarouter_api_key # Required only if using OrcaRouter models

# AWS Bedrock Configuration
AWS_ACCESS_KEY_ID=your_aws_access_key_id # Required for AWS Bedrock models
Expand All @@ -53,6 +54,7 @@ If you're not using Ollama mode, you need to configure an OpenAI API key for emb
> - Get a Google API key from [Google AI Studio](https://makersuite.google.com/app/apikey)
> - Get an OpenAI API key from [OpenAI Platform](https://platform.openai.com/api-keys)
> - Get an OpenRouter API key from [OpenRouter](https://openrouter.ai/keys)
> - Get an OrcaRouter API key from [OrcaRouter](https://www.orcarouter.ai)
> - Get AWS credentials from [AWS IAM Console](https://console.aws.amazon.com/iam/)

#### Advanced Environment Configuration
Expand All @@ -63,6 +65,7 @@ DeepWiki supports multiple LLM providers. The environment variables above are re
- **Google Gemini**: Requires `GOOGLE_API_KEY`
- **OpenAI**: Requires `OPENAI_API_KEY`
- **OpenRouter**: Requires `OPENROUTER_API_KEY`
- **OrcaRouter**: Requires `ORCAROUTER_API_KEY`
- **AWS Bedrock**: Requires `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
- **Ollama**: No API key required (runs locally)

Expand All @@ -83,7 +86,7 @@ DeepWiki now uses JSON configuration files to manage various system components i

1. **`generator.json`**: Configuration for text generation models
- Located in `api/config/` by default
- Defines available model providers (Google, OpenAI, OpenRouter, AWS Bedrock, Ollama)
- Defines available model providers (Google, OpenAI, OpenRouter, OrcaRouter, AWS Bedrock, Ollama)
- Specifies default and available models for each provider
- Contains model-specific parameters like temperature and top_p

Expand Down
23 changes: 23 additions & 0 deletions api/chat/_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
LITELLM_API_KEY,
OPENAI_API_KEY,
OPENROUTER_API_KEY,
ORCAROUTER_API_KEY,
)
from api.logger import get_logger

Expand Down Expand Up @@ -228,6 +229,28 @@ def _build_client(self):
return LiteLLMClient()


class OrcaRouterChatStreamer(_OpenAICompatStreamer):
provider = "orcarouter"
error_hint = (
"Please check that you have set the ORCAROUTER_API_KEY "
"environment variable with a valid API key."
)

def __init__(self, *, model: str, model_config: MODEL_CFG):
if not ORCAROUTER_API_KEY:
logger.warning(
"ORCAROUTER_API_KEY not configured, but continuing with request"
)
# We'll let the OrcaRouterClient handle this and return an error message

super().__init__(model=model, model_config=model_config)

def _build_client(self):
from api.clients import OrcaRouterClient

return OrcaRouterClient()


class BedrockChatStreamer(ChatStreamer):
provider = "bedrock"
error_hint = (
Expand Down
2 changes: 2 additions & 0 deletions api/clients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .litellm import LiteLLMClient
from .ollama import OllamaClient
from .openrouter import OpenRouterClient
from .orcarouter import OrcaRouterClient

__all__ = [
"AnthropicBedrockClient",
Expand All @@ -27,4 +28,5 @@
"OllamaClient",
"OpenAIClient",
"OpenRouterClient",
"OrcaRouterClient",
]
62 changes: 62 additions & 0 deletions api/clients/orcarouter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""OrcaRouter OpenAI-compatible client."""

import os
from typing import Literal, Optional

from adalflow.components.model_client.openai_client import OpenAIClient
from openai import AsyncOpenAI, OpenAI


class OrcaRouterClient(OpenAIClient):
"""
OrcaRouter OpenAI-compatible client.

OrcaRouter is an OpenAI-compatible routing gateway that fronts multiple
upstream providers behind namespaced model ids (e.g. ``openai/gpt-5.5``).
It exposes an OpenAI-compatible API surface, so we can reuse almost all
OpenAIClient behavior while overriding only the client initialization.

Expected environment variables:

ORCAROUTER_API_KEY=sk-orca-...

Example model names:
openai/gpt-5.5
openai/gpt-4o
anthropic/claude-sonnet-4.5
"""

def __init__(
self,
api_key: Optional[str] = None,
input_type: Literal["text", "messages"] = "text",
base_url: Optional[str] = None,
env_api_key_name: str = "ORCAROUTER_API_KEY",
):
resolved_base_url = base_url or os.getenv(
"ORCAROUTER_BASE_URL", "https://api.orcarouter.ai/v1"
)
if not resolved_base_url.endswith("/v1"):
resolved_base_url = f"{resolved_base_url.rstrip('/')}/v1"
super().__init__(
api_key=api_key,
input_type=input_type,
base_url=resolved_base_url,
env_api_key_name=env_api_key_name,
)

def init_sync_client(self):
"""Initialize synchronous OrcaRouter OpenAI-compatible client."""
api_key = self._api_key or os.getenv(self._env_api_key_name, "dummy")
return OpenAI(
api_key=api_key,
base_url=self.base_url,
)

def init_async_client(self):
"""Initialize asynchronous OrcaRouter OpenAI-compatible client."""
api_key = self._api_key or os.getenv(self._env_api_key_name, "dummy")
return AsyncOpenAI(
api_key=api_key,
base_url=self.base_url,
)
6 changes: 6 additions & 0 deletions api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
OllamaClient,
OpenAIClient,
OpenRouterClient,
OrcaRouterClient,
)
from api.logger import get_logger

Expand All @@ -30,6 +31,7 @@
LITELLM_API_KEY = os.environ.get("LITELLM_API_KEY")
GOOGLE_API_KEY = os.environ.get("GOOGLE_API_KEY")
OPENROUTER_API_KEY = os.environ.get("OPENROUTER_API_KEY")
ORCAROUTER_API_KEY = os.environ.get("ORCAROUTER_API_KEY")
AWS_ACCESS_KEY_ID = os.environ.get("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.environ.get("AWS_SECRET_ACCESS_KEY")
AWS_SESSION_TOKEN = os.environ.get("AWS_SESSION_TOKEN")
Expand All @@ -45,6 +47,8 @@
os.environ["GOOGLE_API_KEY"] = GOOGLE_API_KEY
if OPENROUTER_API_KEY:
os.environ["OPENROUTER_API_KEY"] = OPENROUTER_API_KEY
if ORCAROUTER_API_KEY:
os.environ["ORCAROUTER_API_KEY"] = ORCAROUTER_API_KEY
if AWS_ACCESS_KEY_ID:
os.environ["AWS_ACCESS_KEY_ID"] = AWS_ACCESS_KEY_ID
if AWS_SECRET_ACCESS_KEY:
Expand Down Expand Up @@ -74,6 +78,7 @@
OpenAIClient.__name__: OpenAIClient,
LiteLLMClient.__name__: LiteLLMClient,
OpenRouterClient.__name__: OpenRouterClient,
OrcaRouterClient.__name__: OrcaRouterClient,
OllamaClient.__name__: OllamaClient,
BedrockClient.__name__: BedrockClient,
AzureAIClient.__name__: AzureAIClient,
Expand All @@ -87,6 +92,7 @@
"openai": OpenAIClient,
"litellm": LiteLLMClient,
"openrouter": OpenRouterClient,
"orcarouter": OrcaRouterClient,
"ollama": OllamaClient,
"bedrock": BedrockClient,
"azure": AzureAIClient,
Expand Down
28 changes: 28 additions & 0 deletions api/config/generator.json
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,34 @@
}
}
},
"orcarouter": {
"default_model": "openai/gpt-5.5",
"supportsCustomModel": true,
"models": {
"openai/gpt-5.5": {
"temperature": 0.7,
"top_p": 0.8
},
"openai/gpt-5-nano": {
"temperature": 1.0
},
"openai/gpt-5-mini": {
"temperature": 1.0
},
"openai/gpt-4o": {
"temperature": 0.7,
"top_p": 0.8
},
"openai/gpt-4.1": {
"temperature": 0.7,
"top_p": 0.8
},
"anthropic/claude-sonnet-4.5": {
"temperature": 0.7,
"top_p": 0.8
}
}
},
"ollama": {
"default_model": "qwen3:1.7b",
"supportsCustomModel": true,
Expand Down
3 changes: 3 additions & 0 deletions src/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (Local)",
"localOllama": "Local Ollama Model",
"experimental": "Experimental",
"useOpenRouter": "Use OpenRouter API",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "OpenRouter Model",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Use Openai API",
"openaiModel": "Openai Model",
"useCustomModel": "Use custom model",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (Local)",
"localOllama": "Modelo Ollama Local",
"experimental": "Experimental",
"useOpenRouter": "Usar API de OpenRouter",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "Modelo OpenRouter",
Comment on lines 52 to 54

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Localize the OrcaRouter labels

The new useOrcaRouter and orcaRouterModel labels remain in English in every changed non-English catalog, leaving these controls inconsistent with the surrounding localized interface.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Usar API de Openai",
"openaiModel": "Modelo Openai",
"useCustomModel": "Usar modelo personalizado",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (Local)",
"localOllama": "Modèle Ollama local",
"experimental": "Expérimental",
"useOpenRouter": "Utiliser l’API OpenRouter",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "Modèle OpenRouter",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Utiliser l’API OpenAI",
"openaiModel": "Modèle OpenAI",
"useCustomModel": "Utiliser un modèle personnalisé",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama(ローカル)",
"localOllama": "ローカルOllamaモデル",
"experimental": "実験的",
"useOpenRouter": "OpenRouter APIを使用",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "OpenRouterモデル",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Openai APIを使用",
"openaiModel": "Openaiモデル",
"useCustomModel": "カスタムモデルを使用",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/kr.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "구글",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (로컬)",
"localOllama": "로컬 Ollama 모델",
"experimental": "실험적",
"useOpenRouter": "OpenRouter API 사용",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "OpenRouter 모델",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Openai API 사용",
"openaiModel": "Openai 모델",
"useCustomModel": "사용자 정의 모델 사용",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/pt-br.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (Local)",
"localOllama": "Modelo Ollama Local",
"experimental": "Experimental",
"useOpenRouter": "Usar API OpenRouter",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "Modelo OpenRouter",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Usar API OpenAI",
"openaiModel": "Modelo OpenAI",
"useCustomModel": "Usar modelo personalizado",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (локально)",
"localOllama": "Локальная модель Ollama",
"experimental": "Экспериментально",
"useOpenRouter": "Использовать API OpenRouter",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "Модель OpenRouter",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Использовать API OpenAI",
"openaiModel": "Модель OpenAI",
"useCustomModel": "Использовать пользовательскую модель",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/vi.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (Cục bộ)",
"localOllama": "Mô hình Ollama cục bộ",
"experimental": "Thử nghiệm",
"useOpenRouter": "Sử dụng API OpenRouter",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "Mô hình OpenRouter",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "Sử dụng API Openai",
"openaiModel": "Mô hình Openai",
"useCustomModel": "Sử dụng mô hình tùy chỉnh",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama(本機)",
"localOllama": "本機 Ollama 模型",
"experimental": "實驗性",
"useOpenRouter": "使用 OpenRouter API",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "OpenRouter 模型",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "使用 OpenAI API",
"openaiModel": "OpenAI 模型",
"useCustomModel": "使用自訂模型",
Expand Down
3 changes: 3 additions & 0 deletions src/messages/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,14 @@
"providerGoogle": "Google",
"providerOpenAI": "OpenAI",
"providerOpenRouter": "OpenRouter",
"providerOrcaRouter": "OrcaRouter",
"providerOllama": "Ollama (本地)",
"localOllama": "本地Ollama模型",
"experimental": "实验性",
"useOpenRouter": "使用OpenRouter API",
"useOrcaRouter": "Use OrcaRouter API",
"openRouterModel": "OpenRouter模型",
"orcaRouterModel": "OrcaRouter Model",
"useOpenai": "使用Openai API",
"openaiModel": "Openai 模型",
"useCustomModel": "使用自定义模型",
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/test_chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
OllamaChatStreamer,
OpenAIChatStreamer,
OpenRouterChatStreamer,
OrcaRouterChatStreamer,
)


Expand All @@ -25,6 +26,7 @@
("dashscope", DashScopeChatStreamer),
("google", GoogleGenerativeChatStreamer),
("litellm", LiteLLMChatStreamer),
("orcarouter", OrcaRouterChatStreamer),
("anthropic", AnthropicChatStreamer),
],
)
Expand All @@ -43,6 +45,7 @@ def test_every_provider_is_registered(provider, expected):
("dashscope", DashScopeChatStreamer),
("google", GoogleGenerativeChatStreamer),
("litellm", LiteLLMChatStreamer),
("orcarouter", OrcaRouterChatStreamer),
("anthropic", AnthropicChatStreamer),
],
)
Expand Down