A wrapper around AsyncOpenAI that provides a unified interface for OpenRouter chat completions. OpenRouter uses OpenAI-compatible API, so we can use AsyncOpenAI client with OpenRouter's base URL. This class accepts AsyncOpenAI parameters and provides methods for chat completions
| 37 | from src.tool.types import Tool |
| 38 | |
| 39 | class ChatOpenRouter(BaseModel): |
| 40 | """ |
| 41 | A wrapper around AsyncOpenAI that provides a unified interface for OpenRouter chat completions. |
| 42 | |
| 43 | OpenRouter uses OpenAI-compatible API, so we can use AsyncOpenAI client with OpenRouter's base URL. |
| 44 | This class accepts AsyncOpenAI parameters and provides methods for chat completions |
| 45 | with support for tools, response_format, and streaming. |
| 46 | """ |
| 47 | |
| 48 | model_config = ConfigDict(arbitrary_types_allowed=True, extra="allow") |
| 49 | |
| 50 | # Model configuration |
| 51 | model: Union[ChatModel, str] |
| 52 | |
| 53 | # Model params |
| 54 | temperature: Optional[float] = 0.7 |
| 55 | frequency_penalty: Optional[float] = 0.3 |
| 56 | reasoning: Optional[Dict[str, Any]] = None |
| 57 | seed: Optional[int] = None |
| 58 | top_p: Optional[float] = None |
| 59 | max_completion_tokens: Optional[int] = 16384 |
| 60 | |
| 61 | # OpenRouter plugins (for PDF parsing, etc.) |
| 62 | plugins: Optional[List[Dict[str, Any]]] = None |
| 63 | |
| 64 | # Client initialization parameters |
| 65 | api_key: Optional[str] = None |
| 66 | base_url: Optional[Union[str, httpx.URL]] = "https://openrouter.ai/api/v1" |
| 67 | timeout: Optional[Union[float, httpx.Timeout]] = None |
| 68 | max_retries: int = 5 |
| 69 | default_headers: Optional[Mapping[str, str]] = None |
| 70 | default_query: Optional[Mapping[str, object]] = None |
| 71 | http_client: Optional[httpx.AsyncClient] = None |
| 72 | _strict_response_validation: bool = False |
| 73 | |
| 74 | # OpenRouter specific headers |
| 75 | http_referer: Optional[str] = None # HTTP-Referer header |
| 76 | x_title: Optional[str] = None # X-Title header |
| 77 | |
| 78 | reasoning_models: Optional[List[Union[ChatModel, str]]] = Field( |
| 79 | default_factory=lambda: [] |
| 80 | ) |
| 81 | |
| 82 | @property |
| 83 | def provider(self) -> str: |
| 84 | return 'openrouter' |
| 85 | |
| 86 | def _get_client_params(self) -> dict[str, Any]: |
| 87 | """Prepare client parameters dictionary.""" |
| 88 | # Prepare default headers for OpenRouter |
| 89 | headers = dict(self.default_headers) if self.default_headers else {} |
| 90 | |
| 91 | # Add OpenRouter-specific headers |
| 92 | if self.http_referer: |
| 93 | headers['HTTP-Referer'] = self.http_referer |
| 94 | if self.x_title: |
| 95 | headers['X-Title'] = self.x_title |
| 96 |