|
53 | 53 |
|
54 | 54 | logger = logging.getLogger(__name__) |
55 | 55 |
|
| 56 | +# Newer Codex models are gated on the first-party client identity; the previous |
| 57 | +# browser-shaped User-Agent returned "Model not found" for Luna (#2643). |
| 58 | +# Use a neutral version because Hindsight must not claim a specific Codex release. |
| 59 | +_CODEX_ORIGINATOR = "codex_cli_rs" |
| 60 | +_CODEX_USER_AGENT = "codex_cli_rs/0.0.0 (Hindsight)" |
| 61 | + |
56 | 62 | # Name of the single forced function tool used to carry structured output when |
57 | 63 | # strict_schema is on. The Codex backend speaks the OpenAI Responses API, so a |
58 | 64 | # forced function call gives us constrained decoding straight into the response |
@@ -187,6 +193,18 @@ def access_token(self, v: str) -> None: |
187 | 193 | def account_id(self) -> str: |
188 | 194 | return self._auth_manager.account_id |
189 | 195 |
|
| 196 | + def _build_request_headers(self) -> httpx.Headers: |
| 197 | + return httpx.Headers( |
| 198 | + { |
| 199 | + "Authorization": f"Bearer {self.access_token}", |
| 200 | + "Content-Type": "application/json", |
| 201 | + "OpenAI-Account-ID": self.account_id, |
| 202 | + "User-Agent": _CODEX_USER_AGENT, |
| 203 | + "Origin": "https://chatgpt.com", |
| 204 | + "originator": _CODEX_ORIGINATOR, |
| 205 | + } |
| 206 | + ) |
| 207 | + |
190 | 208 | @property |
191 | 209 | def refresh_token(self) -> str | None: |
192 | 210 | return self._auth_manager.refresh_token |
@@ -475,13 +493,7 @@ async def call( |
475 | 493 | payload["tool_choice"] = {"type": "function", "name": _STRUCTURED_TOOL_NAME} |
476 | 494 | payload["parallel_tool_calls"] = False |
477 | 495 |
|
478 | | - headers = { |
479 | | - "Authorization": f"Bearer {self.access_token}", |
480 | | - "Content-Type": "application/json", |
481 | | - "OpenAI-Account-ID": self.account_id, |
482 | | - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", |
483 | | - "Origin": "https://chatgpt.com", |
484 | | - } |
| 496 | + headers = self._build_request_headers() |
485 | 497 |
|
486 | 498 | url = f"{self.base_url}/codex/responses" |
487 | 499 |
|
@@ -843,13 +855,7 @@ async def call_with_tools( |
843 | 855 | "prompt_cache_key": str(uuid.uuid4()), |
844 | 856 | } |
845 | 857 |
|
846 | | - headers = { |
847 | | - "Authorization": f"Bearer {self.access_token}", |
848 | | - "Content-Type": "application/json", |
849 | | - "OpenAI-Account-ID": self.account_id, |
850 | | - "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)", |
851 | | - "Origin": "https://chatgpt.com", |
852 | | - } |
| 858 | + headers = self._build_request_headers() |
853 | 859 |
|
854 | 860 | url = f"{self.base_url}/codex/responses" |
855 | 861 |
|
|
0 commit comments