* Custom fetch implementation for Codex API * * Handles: * - Token refresh when expired * - URL rewriting for Codex backend * - Request body transformation * - OAuth header injection * - SSE to JSON conversion for non-tool requests * - Error handling a
( input: Request | string | URL, init?: RequestInit, )
| 144 | * @returns Response from Codex API |
| 145 | */ |
| 146 | async fetch( |
| 147 | input: Request | string | URL, |
| 148 | init?: RequestInit, |
| 149 | ): Promise<Response> { |
| 150 | // Step 1: Check and refresh token if needed |
| 151 | let currentAuth = await getAuth(); |
| 152 | if (shouldRefreshToken(currentAuth)) { |
| 153 | const refreshResult = await refreshAndUpdateToken( |
| 154 | getAuth, |
| 155 | client, |
| 156 | ); |
| 157 | if (!refreshResult.success) { |
| 158 | return refreshResult.response; |
| 159 | } |
| 160 | // Reload auth after refresh to get updated tokens |
| 161 | currentAuth = refreshResult.auth; |
| 162 | } |
| 163 | |
| 164 | // Step 2: Extract and rewrite URL for Codex backend |
| 165 | const originalUrl = extractRequestUrl(input); |
| 166 | const url = rewriteUrlForCodex(originalUrl); |
| 167 | // Step 3: Transform request body with model-specific Codex instructions |
| 168 | // Instructions are fetched per model family (codex-max, codex, gpt-5.1) |
| 169 | // Capture original stream value before transformation |
| 170 | // generateText() sends no stream field, streamText() sends stream=true |
| 171 | const originalBody = init?.body ? JSON.parse(init.body as string) : {}; |
| 172 | const isStreaming = originalBody.stream === true; |
| 173 | |
| 174 | const transformation = await transformRequestForCodex( |
| 175 | init, |
| 176 | url, |
| 177 | userConfig, |
| 178 | codexMode, |
| 179 | ); |
| 180 | const requestInit = transformation?.updatedInit ?? init; |
| 181 | |
| 182 | // Step 4: Create headers with OAuth and ChatGPT account info |
| 183 | const accessToken = (currentAuth as any).accessToken ?? (currentAuth as any).access ?? ""; |
| 184 | const headers = createCodexHeaders( |
| 185 | requestInit, |
| 186 | accountId, |
| 187 | accessToken, |
| 188 | { |
| 189 | model: transformation?.body.model, |
| 190 | promptCacheKey: (transformation?.body as any)?.prompt_cache_key, |
| 191 | }, |
| 192 | ); |
| 193 | |
| 194 | // Step 5: Make request to Codex API |
| 195 | let response = await fetch(url, { |
| 196 | ...requestInit, |
| 197 | headers, |
| 198 | }); |
| 199 | |
| 200 | // Check for 401 or token_invalidated error |
| 201 | let shouldRetry = response.status === 401; |
| 202 | if (!shouldRetry && !response.ok) { |
| 203 | try { |
no test coverage detected