feat: Add Codex provider config bridge#18
feat: Add Codex provider config bridge#18hanxuanliang wants to merge 1 commit intopaoloanzn:mainfrom
Conversation
📝 WalkthroughWalkthroughThis PR introduces a provider bridge abstraction layer for API client initialization, replacing direct token-based provider selection with a configuration-driven approach. A new module resolves provider bridges from environment variables and config files, API clients leverage this bridge for authentication, and auth logic is updated to validate subscription through provider resolution rather than direct token checks. Changes
Sequence Diagram(s)sequenceDiagram
participant Client Code
participant Provider Bridge Resolver
participant Config/Env Reader
participant API Client Factory
participant Fetch Adapter
participant SDK Client
Client Code->>Provider Bridge Resolver: resolveCodexProviderBridge(options)
Provider Bridge Resolver->>Config/Env Reader: Read codexHomeDir, config.toml, auth.json
Config/Env Reader-->>Provider Bridge Resolver: Config, API keys, tokens
Provider Bridge Resolver->>Provider Bridge Resolver: Validate provider & wire_api<br/>Resolve authentication
alt API Key Available
Provider Bridge Resolver-->>Client Code: kind='responses' bridge<br/>(endpoint, apiKey, headers)
else No API Key, OpenAI Default
Provider Bridge Resolver-->>Client Code: kind='chatgpt' bridge<br/>(accessToken)
end
Client Code->>API Client Factory: getAnthropicClient(bridge)
alt bridge.kind === 'chatgpt'
API Client Factory->>Fetch Adapter: createCodexFetch(bridge.accessToken)
else bridge.kind === 'responses'
API Client Factory->>Fetch Adapter: createResponsesFetch(bridge)
end
Fetch Adapter-->>API Client Factory: fetch implementation
API Client Factory->>SDK Client: Initialize with fetch
SDK Client-->>Client Code: Ready SDK client
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/services/api/client.ts (1)
313-332:⚠️ Potential issue | 🟡 MinorUse
tryResolveCodexProviderBridgeto gracefully handle bridge resolution errors.
resolveCodexProviderBridgethrows errors when the provider is not found (line 196) or whenwire_apiis not"responses"(line 201). At line 315 in client.ts, this function is called without error handling, so misconfiguration in~/.codex/config.tomlwill cause an uncaught exception rather than falling back to the default behavior.The codebase already provides
tryResolveCodexProviderBridge(a try-catch wrapper that returnsnullon error) for this exact scenario. Use it instead to match the fallback pattern established by the null-check on line 319.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/api/client.ts` around lines 313 - 332, The code calls resolveCodexProviderBridge directly (inside the getAPIProvider() === 'openai' branch) which can throw; replace that call with tryResolveCodexProviderBridge to safely return null on errors, then keep the existing null-check and bridge handling intact (use the same variables: codexTokens, bridgeFetch creation using createCodexFetch/createResponsesFetch, clientConfig and new Anthropic(...)) so misconfigured ~/.codex/config.toml won’t raise an uncaught exception.
🧹 Nitpick comments (3)
src/services/api/codex-provider-bridge.ts (2)
239-247: Error swallowing may hide configuration issues.
tryResolveCodexProviderBridgecatches all errors and returnsnull, which is appropriate forisCodexSubscriber()checks but could hide misconfiguration issues (e.g., malformed TOML, missing required fields).Consider logging errors at debug level before returning
nullto aid troubleshooting:🔧 Suggested improvement
export function tryResolveCodexProviderBridge( options: ResolveCodexProviderBridgeOptions = {}, ): CodexProviderBridgeConfig | null { try { return resolveCodexProviderBridge(options) - } catch { + } catch (error) { + // Log at debug level to aid troubleshooting without disrupting normal flow + if (process.env.DEBUG) { + console.error('[codex-provider-bridge] Resolution failed:', error) + } return null } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/api/codex-provider-bridge.ts` around lines 239 - 247, The tryResolveCodexProviderBridge function currently swallows all exceptions from resolveCodexProviderBridge; update it to catch the error, log the error (at debug/verbose level) including the error object and a brief context message that resolving the Codex provider bridge failed, then return null; reference tryResolveCodexProviderBridge and resolveCodexProviderBridge so you add the logging inside the catch before the null return.
68-78: Synchronous file I/O may block the event loop.
readFileSyncis used here to readconfig.toml. While this is acceptable during initialization, ifresolveCodexProviderBridgeis called frequently during request handling, it could cause latency issues.Consider caching the parsed config or using async reads if this function is called on hot paths. Based on the usage in
client.ts, this appears to be called per-client creation, which should be infrequent enough that sync I/O is acceptable.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/api/codex-provider-bridge.ts` around lines 68 - 78, readCodexConfig currently uses synchronous readFileSync which can block the event loop; change it to avoid hot-path sync I/O by either (A) caching the parsed config per codexHomeDir inside this module (e.g., a Map keyed by codexHomeDir) and returning the cached CodexConfigToml if present before doing a single sync read on first load, or (B) convert readCodexConfig to an async function that uses Bun.file(...).text() or fs.promises.readFile and update callers such as resolveCodexProviderBridge and client.ts to await the async call; prefer option A if callers are not ready for async to minimize call-site changes. Ensure the ENOENT handling remains and the cache invalidation strategy (none or a manual reset) is documented.src/services/api/codex-fetch-adapter.ts (1)
742-763: Internal type naming could be clearer.The
accessTokenfield inResponsesBridgeFetchOptionsis used for both OAuth access tokens (increateCodexFetch) and API keys (increateResponsesFetch). Consider renaming to something more generic likeauthTokenorbearerTokento clarify its dual purpose, or add a comment explaining the usage.This is a minor readability concern since the type is internal.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/api/codex-fetch-adapter.ts` around lines 742 - 763, Rename the ambiguous field accessToken in the ResponsesBridgeFetchOptions type to a more generic name (e.g., authToken or bearerToken) and update all references in createResponsesBridgeFetch to use the new name (including the parameter destructuring and resolveAccessToken assignment); also update any callers or related helpers such as createCodexFetch and createResponsesFetch (or add a short inline comment on ResponsesBridgeFetchOptions) to clarify whether the value is an OAuth token or API key so the dual-purpose intent is explicit.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/services/api/client.ts`:
- Around line 313-332: The code calls resolveCodexProviderBridge directly
(inside the getAPIProvider() === 'openai' branch) which can throw; replace that
call with tryResolveCodexProviderBridge to safely return null on errors, then
keep the existing null-check and bridge handling intact (use the same variables:
codexTokens, bridgeFetch creation using createCodexFetch/createResponsesFetch,
clientConfig and new Anthropic(...)) so misconfigured ~/.codex/config.toml won’t
raise an uncaught exception.
---
Nitpick comments:
In `@src/services/api/codex-fetch-adapter.ts`:
- Around line 742-763: Rename the ambiguous field accessToken in the
ResponsesBridgeFetchOptions type to a more generic name (e.g., authToken or
bearerToken) and update all references in createResponsesBridgeFetch to use the
new name (including the parameter destructuring and resolveAccessToken
assignment); also update any callers or related helpers such as createCodexFetch
and createResponsesFetch (or add a short inline comment on
ResponsesBridgeFetchOptions) to clarify whether the value is an OAuth token or
API key so the dual-purpose intent is explicit.
In `@src/services/api/codex-provider-bridge.ts`:
- Around line 239-247: The tryResolveCodexProviderBridge function currently
swallows all exceptions from resolveCodexProviderBridge; update it to catch the
error, log the error (at debug/verbose level) including the error object and a
brief context message that resolving the Codex provider bridge failed, then
return null; reference tryResolveCodexProviderBridge and
resolveCodexProviderBridge so you add the logging inside the catch before the
null return.
- Around line 68-78: readCodexConfig currently uses synchronous readFileSync
which can block the event loop; change it to avoid hot-path sync I/O by either
(A) caching the parsed config per codexHomeDir inside this module (e.g., a Map
keyed by codexHomeDir) and returning the cached CodexConfigToml if present
before doing a single sync read on first load, or (B) convert readCodexConfig to
an async function that uses Bun.file(...).text() or fs.promises.readFile and
update callers such as resolveCodexProviderBridge and client.ts to await the
async call; prefer option A if callers are not ready for async to minimize
call-site changes. Ensure the ENOENT handling remains and the cache invalidation
strategy (none or a manual reset) is documented.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e8617db1-8881-450e-b8fc-454c70239146
📒 Files selected for processing (6)
package.jsonsrc/services/api/client.tssrc/services/api/codex-fetch-adapter.tssrc/services/api/codex-provider-bridge.test.tssrc/services/api/codex-provider-bridge.tssrc/utils/auth.ts
|
@paoloanzn Can you please open github issues for community engagement. |
|
From what I have seen in other popular cc forks, issues become spammed, and hard to manage |
done. sorry for the delay but this project came unexpected for obvious reasons i did not had the time to organize properly. there is a specific direction i have in mind to bring this forward, but i'm still planning. any good maintainers that wants to help is welcome. feel free to email me at paolo@gladium.ai linking your github profile. |
|
@paoloanzn Would've opened a issue but I couldn't. [*] Cloning repository... |
|
I just made an issue
|
Hey I sent you an email! Thanks for a nice project! |
Summary
This PR adds a Codex-style provider/auth/config bridge to free-code while keeping the existing Anthropic -> Responses conversion flow unchanged.
~/.codex/config.toml~/.codex/auth.json,OPENAI_API_KEY, andCODEX_API_KEYbase_url + /responsesFeatures
model_providerandmodel_providersbase_url, headers, env-backed headers, and query param supportauth.json.OPENAI_API_KEYTesting
src/services/api/codex-provider-bridge.test.tsauth.jsonAPI key loading, ChatGPT token fallback, and non-Responses rejectionRelated
Closes the gap around reusing local Codex provider/auth/config in free-code.
Summary by CodeRabbit
Chores
bun testnpm script for running tests.Tests