| 139 | |
| 140 | |
| 141 | class OpenRouterModel(BaseModel): |
| 142 | _API_KEY_FIELD = "openrouter_api_key" |
| 143 | _ENV_VAR = "OPENROUTER_API_KEY" |
| 144 | _LOG_SOURCE = "openrouter" |
| 145 | _MAX_RATE_LIMIT_RETRIES = 5 |
| 146 | _MAX_TRANSIENT_RETRIES = 5 |
| 147 | _DEFAULT_CONFIG_CLASS = OpenRouterModelConfig |
| 148 | |
| 149 | def _request_headers(self) -> dict[str, str]: |
| 150 | headers = { |
| 151 | "Content-Type": "application/json", |
| 152 | "Authorization": f"Bearer {self.config.openrouter_api_key}", |
| 153 | } |
| 154 | if _is_openrouter_endpoint(self.config.openrouter_endpoint) and self.config.http_referer: |
| 155 | headers["HTTP-Referer"] = self.config.http_referer |
| 156 | if _is_openrouter_endpoint(self.config.openrouter_endpoint) and self.config.app_title: |
| 157 | headers["X-Title"] = self.config.app_title |
| 158 | return headers |
| 159 | |
| 160 | def _post_url(self) -> str: |
| 161 | return self.config.openrouter_endpoint |
| 162 | |
| 163 | def _build_payload(self, messages: list[dict[str, Any]]) -> dict[str, Any]: |
| 164 | payload: dict[str, Any] = { |
| 165 | "model": self.config.model_name, |
| 166 | "messages": _serialize_chat_messages(messages), |
| 167 | "stream": False, |
| 168 | "response_format": { |
| 169 | "type": "json_schema", |
| 170 | "json_schema": { |
| 171 | "name": "playwright_step", |
| 172 | "strict": True, |
| 173 | "schema": self._response_schema(), |
| 174 | }, |
| 175 | }, |
| 176 | } |
| 177 | if _is_openai_endpoint(self.config.openrouter_endpoint) and self.config.model_name.startswith("gpt-5"): |
| 178 | payload["max_completion_tokens"] = self.config.max_output_tokens |
| 179 | else: |
| 180 | payload["max_tokens"] = self.config.max_output_tokens |
| 181 | if self.config.provider_require_parameters and _is_openrouter_endpoint(self.config.openrouter_endpoint): |
| 182 | payload["provider"] = {"require_parameters": True} |
| 183 | return payload |
| 184 | |
| 185 | def _build_text_payload(self, messages: list[dict[str, Any]]) -> dict[str, Any]: |
| 186 | payload: dict[str, Any] = { |
| 187 | "model": self.config.model_name, |
| 188 | "messages": _serialize_chat_messages(messages), |
| 189 | "stream": False, |
| 190 | } |
| 191 | if _is_openai_endpoint(self.config.openrouter_endpoint) and self.config.model_name.startswith("gpt-5"): |
| 192 | payload["max_completion_tokens"] = self.config.max_output_tokens |
| 193 | else: |
| 194 | payload["max_tokens"] = self.config.max_output_tokens |
| 195 | if self.config.provider_require_parameters and _is_openrouter_endpoint(self.config.openrouter_endpoint): |
| 196 | payload["provider"] = {"require_parameters": True} |
| 197 | return payload |
| 198 |
nothing calls this directly
no outgoing calls
no test coverage detected