Skip to content

Add Codex OAuth provider support#2748

Open
junjunjunbong wants to merge 10 commits into
tinyhumansai:mainfrom
junjunjunbong:codex/add-codex-oauth-provider
Open

Add Codex OAuth provider support#2748
junjunjunbong wants to merge 10 commits into
tinyhumansai:mainfrom
junjunjunbong:codex/add-codex-oauth-provider

Conversation

@junjunjunbong
Copy link
Copy Markdown

@junjunjunbong junjunjunbong commented May 27, 2026

Summary

  • Adds Codex/ChatGPT OAuth as an OpenAI provider sign-in option in the AI settings flow.
  • Imports an existing Codex CLI login from ~/.codex/auth.json and persists it as the OpenAI OAuth profile.
  • Routes OpenAI OAuth-backed inference through the ChatGPT Codex backend with required account and client-version metadata.
  • Accepts both OpenAI-style { data: [...] } and Codex-style { models: [...] } model catalog responses.
  • Hardens the setup flow so existing API-key credentials are preserved until Codex setup succeeds, localized errors use stable codes, and CodeRabbit review findings are resolved.

Problem

OpenAI provider setup could use API keys, but not the user's existing Codex/ChatGPT OAuth session. After adding the OAuth route, the Codex backend model catalog also rejected requests missing client_version, then returned a { models: [...] } payload that the OpenAI-compatible catalog parser did not accept.

Solution

  • Add OpenAI OAuth RPC operations and UI wiring for importing Codex CLI credentials.
  • Store and refresh OAuth token-set credentials under the OpenAI provider profile.
  • Add provider support for extra query params so Codex OAuth requests include client_version.
  • Normalize provider catalog responses from OpenAI-compatible data[].id, Codex models[].slug, and string model entries.
  • Delay OpenAI API-key clearing until Codex provider flush/persist succeeds, and keep normal API-key routing tolerant of broken OAuth metadata.
  • Add Windows home-directory fallback and structured diagnostics for Codex CLI auth import.

Submission Checklist

If a section does not apply to this change, mark the item as N/A with a one-line reason. Do not delete items.

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage >= 80% — N/A locally: full lcov diff coverage was not run; focused Rust/app tests cover the changed OAuth/catalog paths, and CI remains authoritative.
  • Coverage matrix updated — N/A: provider-auth/model-catalog behavior change, no feature matrix row added or removed.
  • All affected feature IDs from the matrix are listed in the PR description under ## Related — N/A: no coverage-matrix feature ID changed.
  • No new external network dependencies introduced (mock backend used per Testing Strategy)
  • Manual smoke checklist updated if this touches release-cut surfaces (docs/RELEASE-MANUAL-SMOKE.md) — N/A: targeted provider setup fix only.
  • Linked issue closed via Closes #NNN in the ## Related section — N/A: user-reported local regression, no GitHub issue.

Impact

Desktop app users can connect OpenAI through Codex OAuth and list/use Codex backend models without the client_version or missing data array failures. No migration is required; existing API-key OpenAI provider behavior is preserved.

Related

  • Closes: N/A
  • Follow-up PR(s)/TODOs: N/A

AI Authored PR Metadata (required for Codex/Linear PRs)

Keep this section for AI-authored PRs. For human-only PRs, mark each field N/A.

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: codex/add-codex-oauth-provider
  • Commit SHA: 0db55dc6990c53469e3c6ee965f02ebd4621e922

Validation Run

  • pnpm --filter openhuman-app exec vitest run --config test/vitest.config.ts src/components/settings/panels/__tests__/AIPanel.test.tsx src/services/api/__tests__/aiSettingsApi.test.ts
  • pnpm debug rust openai_oauth
  • pnpm debug rust lookup_key_for_slug_routes_openai_oauth_lookup_path
  • pnpm debug rust model_catalog_accepts; pnpm debug rust openai_codex_models_url_includes_client_version_query; pnpm debug rust extra_query_params_are_applied_to_codex_urls
  • pnpm i18n:check
  • pnpm lint (passes with existing warnings)
  • pnpm typecheck
  • pnpm format:check with Rust toolchain PATH configured
  • GGML_NATIVE=OFF cargo check --manifest-path Cargo.toml
  • Pre-push hook: format:check, lint, compile, rust:check

Validation Blocked

  • command: pnpm i18n:bundle:check
  • error: verify-i18n-bundle: dist directory does not exist or is not a directory: /Users/junwon/Projects/openhuman/app/dist
  • impact: Bundle verification requires a built app/dist; i18n source coverage passed via pnpm i18n:check.

Behavior Changes

  • Intended behavior change: OpenAI Codex OAuth can import Codex CLI credentials and list/use Codex backend models.
  • User-visible effect: AI settings OpenAI/Codex auth no longer fails on model listing due to missing client_version or Codex models response shape.

Parity Contract

  • Legacy behavior preserved: API-key OpenAI and generic OpenAI-compatible providers still use existing auth headers and data model catalogs.
  • Guard/fallback/dispatch parity checks: New query params are opt-in for Codex OAuth; catalog parsing still rejects responses without data or models arrays.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): None found for junjunjunbong:codex/add-codex-oauth-provider.
  • Canonical PR: This PR.
  • Resolution (closed/superseded/updated): N/A

@junjunjunbong junjunjunbong requested a review from a team May 27, 2026 09:36
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Codex CLI ChatGPT auth import and account_id-aware OpenAI OAuth handling: import from CODEX_HOME/~/.codex/auth.json, persist OAuth profile with optional account_id, expose RPC/controller/schema for import, route OAuth-backed OpenAI requests via a Codex backend with extra headers/query params, and add frontend UI, API facades, and tests to trigger/import Codex OAuth.

Changes

OpenAI Codex CLI OAuth & Account ID Routing

Layer / File(s) Summary
Flow, RPC handler, controller schema & tests
src/openhuman/inference/openai_oauth/flow.rs, src/openhuman/inference/ops.rs, src/openhuman/inference/schemas.rs, src/openhuman/inference/schemas_tests.rs
Adds import_openai_oauth_from_codex_cli, inference_openai_oauth_import_codex_cli RPC op, public controller schema/handler registration, and schema/tests asserting registration and no inputs.
OAuth store: account_id, JWT helpers, Codex CLI import
src/openhuman/inference/openai_oauth/store.rs
Introduces OpenAiOAuthCredentials { access_token, account_id }, refactors JWT payload decoding, updates persistence to accept/store optional account_id, adds lookup_openai_oauth_credentials, and implements Codex CLI auth.json import (CODEX_HOME/~/ .codex/auth.json) with token normalization and persistence.
Provider: extra headers & query params + tests
src/openhuman/inference/provider/compatible.rs, src/openhuman/inference/provider/compatible_tests.rs
Adds extra_headers and extra_query_params to OpenAiCompatibleProvider, builder helpers with_extra_header/with_extra_query_param, helpers to apply headers and append query params (URL parsing with fallback), ensures streaming requests include extra headers, and unit tests.
Provider ops & factory: OAuth-aware routing and catalog parsing
src/openhuman/inference/provider/ops.rs, src/openhuman/inference/provider/factory.rs, src/openhuman/inference/provider/openai_codex.rs
list_configured_models_from_config detects OpenAI OAuth usage, selects Codex backend when OAuth-active, appends client_version, conditionally includes ChatGPT-Account-ID header, refactors model-catalog parsing to accept OpenAI data, Codex models, and string entries; factory routes openai providers via Codex backend and injects headers/query param when appropriate.
Frontend API facades & tests
app/src/services/api/aiSettingsApi.ts, app/src/services/api/__tests__/aiSettingsApi.test.ts
Adds error-code constants and RPC facades startOpenAiCodexOAuth, completeOpenAiCodexOAuth, importOpenAiCodexCliAuth, types for start result, and tests asserting error behavior for missing auth/callback URLs.
Frontend UI: AIPanel Codex button, connect flow and tests
app/src/components/settings/panels/AIPanel.tsx, app/src/components/settings/panels/__tests__/AIPanel.test.tsx
Adds LuKeyRound icon and a “Codex 인증” button, codexAuthError state, extends connectProvider with credentialMode: 'codex_oauth' (suppresses stored-key writes and skips /models probing), implements connectOpenAiViaCodexAuth that imports Codex CLI auth and persists provider state, clears stored OpenAI key on successful Codex import, and updates/adds tests to validate flows and UI.
Flow & import tests (Rust)
src/openhuman/inference/openai_oauth/flow_tests.rs
Adds tests verifying successful Codex CLI auth import stores OAuth profile and token lookups, and that importing a missing file yields an error suggesting codex login.
i18n: Codex OAuth messages
app/src/lib/i18n/*, app/src/lib/i18n/en.ts
Adds settings.ai.codexOauthMissingAuthUrl and settings.ai.codexOauthMissingCallbackUrl translation entries across many locale chunks and English core.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2265: Earlier work on OpenAI OAuth start/complete/status/disconnect and key lookup that this PR extends with Codex CLI import.

Suggested reviewers

  • senamakel
  • graycyrus

"🐰 I found a key in ~/.codex today,
I hopped it in and stowed away,
Tokens tidy, account IDs sewn,
Backends routed, headers grown,
Now connect clicks greet the day!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.65% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add Codex OAuth provider support' directly and clearly summarizes the main change: adding Codex OAuth as an OpenAI-provider authentication option.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. labels May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
src/openhuman/inference/provider/factory.rs (1)

832-851: ⚡ Quick win

Log the Codex routing branch explicitly.

The info log above still reports entry.endpoint, but this branch can silently send traffic to https://chatgpt.com/backend-api/codex and add ChatGPT-Account-ID. Moving the log after endpoint selection, or adding a dedicated branch log here, will make OAuth routing failures much easier to diagnose. As per coding guidelines "Log entry/exit, branches, external calls, retries/timeouts, state transitions, and errors with verbose diagnostics using stable grep-friendly prefixes and correlation fields".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/inference/provider/factory.rs` around lines 832 - 851, Move or
add an info log immediately after the endpoint selection (the `endpoint = if
using_openai_oauth { ... } else { &entry.endpoint }` block) that explicitly
records which branch was taken and the effective endpoint value, and also log
whether a ChatGPT-Account-ID header was added (i.e., whether
`using_openai_oauth` is true and `openai_oauth_credentials` provided an
`account_id`), so when constructing the `OpenAiCompatibleProvider` (via
`OpenAiCompatibleProvider::new`) you emit a stable, grep-friendly message
containing the chosen `endpoint` and a flag or the actual account id that will
be passed to `provider.with_extra_header("ChatGPT-Account-ID", ...)`.
src/openhuman/inference/provider/ops.rs (1)

61-75: ⚡ Quick win

Centralize the OpenAI OAuth routing/header decision.

This duplicates the Codex base-URL and ChatGPT-Account-ID selection logic from factory.rs, and the two paths have already drifted: the provider path drops blank account_id values via with_extra_header(), while this probe path would still send an empty header. Please extract one shared helper that returns the effective base URL plus optional extra headers, and reuse it here and in the factory.

Also applies to: 100-107

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/inference/provider/ops.rs` around lines 61 - 75, The probe path
duplicates the OpenAI OAuth routing and ChatGPT-Account-ID header logic from
factory.rs (the using_openai_oauth/base/header selection), causing drift and
sending blank headers; extract a single helper (e.g.,
resolve_openai_base_and_headers or get_openai_routing_and_headers) that returns
(base_url: String, extra_headers: Option<HeaderMap>) and centralizes: 1)
detecting OAuth via lookup_openai_oauth_credentials, 2) choosing the
codex/chatgpt base URL, and 3) only adding ChatGPT-Account-ID when account_id is
non-empty (matching with_extra_header behavior). Replace the inline
using_openai_oauth/base/header logic in ops.rs (and in factory.rs) to call that
helper so both paths reuse the same routing and header decision.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/settings/panels/AIPanel.tsx`:
- Around line 2690-2705: The Codex auth error state (codexAuthError) isn't
cleared when the user successfully connects OpenAI via a non-Codex path; update
the success paths to explicitly reset this state: after the await
connectProvider(...) call in connectOpenAiViaCodexAuth, call
setCodexAuthError(null) so a prior error is removed on success, and apply the
same change to the other OpenAI connect handler that also calls connectProvider
(the API-key/normal connect path) so any successful connect clears
codexAuthError as well.
- Around line 2629-2632: The code currently calls
clearCloudProviderKey('openai') immediately when isCodexOAuth && slug ===
'openai', which can remove the user’s existing OpenAI key before
flushCloudProviders(...) and persist(...) succeed; change the flow so you do NOT
clear the existing key here and instead call clearCloudProviderKey('openai')
only after flushCloudProviders(...) and persist(...) have both completed
successfully (and handle errors so the clear is skipped on failure). Locate
references to clearCloudProviderKey, setCloudProviderKey, flushCloudProviders,
persist, isCodexOAuth and slug in AIPanel.tsx and move the clearCloudProviderKey
invocation to the success path after the flush/persist operations, ensuring
proper error handling so the old key is preserved if either write fails.

In `@app/src/services/api/aiSettingsApi.ts`:
- Around line 342-345: Replace the hard-coded English Error throws around the
authUrl check (the throw after checking const authUrl =
res?.result?.authUrl?.trim()) and the similar throw later in this module with a
stable machine-readable error code instead of prose (for example throw new
Error('OPENAI_CODEX_OAUTH_MISSING') or throw { code:
'OPENAI_CODEX_OAUTH_MISSING' }); keep the check logic the same but return/throw
the code so callers can map it to localized copy via useT(); update both
occurrences in aiSettingsApi.ts that validate res?.result?.authUrl and the
similar block at the other validation point, and add a corresponding English
localization entry for that new error key in the i18n English resources so
callers can t('...') it.

In `@src/openhuman/inference/openai_oauth/store.rs`:
- Around line 100-157: The import_codex_cli_auth_from_path function lacks
structured entry/exit/branch/error diagnostics; add grep-friendly logs (e.g.,
prefix OPENAI_OAUTH_IMPORT) at function entry and exit, before/after each
failure branch (file read, JSON parse, missing tokens, empty access token), and
around the external persistence call persist_openai_oauth_token_set, including
correlation fields path (path.display()), provider ("codex"), and
profile_id/account_id (when available) but never logging token values or
secrets; use the project's existing logging facility (tracing or the local
logger) and include references to import_codex_cli_auth_from_path,
persist_openai_oauth_token_set, extract_account_id_from_access_token, and
extract_expires_at_from_access_token so logs show context for debugging.
- Around line 94-97: The code currently only reads std::env::var_os("HOME") to
build the auth path, which fails on Windows; update the path-resolution logic
(the block producing home and building
Ok(home.join(".codex").join("auth.json"))) to fall back to Windows env vars: if
"HOME" is unset, try std::env::var_os("USERPROFILE"), then try combining
"HOMEDRIVE" + "HOMEPATH" if needed, and use the first non-empty PathBuf; then
join ".codex/auth.json" as before so the function (the home resolution that
produces the PathBuf) works on Windows as well.

In `@src/openhuman/inference/provider/factory.rs`:
- Around line 788-797: Replace the unconditional fatal error on
lookup_openai_oauth_credentials with a tolerant lookup: call
lookup_openai_oauth_credentials(config) and on Err convert to None but record
that the lookup failed; compute using_openai_oauth from
openai_oauth_credentials.as_ref().is_some_and(|c| c.access_token == key); if the
lookup previously failed AND using_openai_oauth is true then propagate the
error, otherwise treat openai_oauth_credentials as None and continue so normal
API-key routing still works. Ensure you modify the block around
lookup_openai_oauth_credentials, openai_oauth_credentials and using_openai_oauth
to implement this logic.

---

Nitpick comments:
In `@src/openhuman/inference/provider/factory.rs`:
- Around line 832-851: Move or add an info log immediately after the endpoint
selection (the `endpoint = if using_openai_oauth { ... } else { &entry.endpoint
}` block) that explicitly records which branch was taken and the effective
endpoint value, and also log whether a ChatGPT-Account-ID header was added
(i.e., whether `using_openai_oauth` is true and `openai_oauth_credentials`
provided an `account_id`), so when constructing the `OpenAiCompatibleProvider`
(via `OpenAiCompatibleProvider::new`) you emit a stable, grep-friendly message
containing the chosen `endpoint` and a flag or the actual account id that will
be passed to `provider.with_extra_header("ChatGPT-Account-ID", ...)`.

In `@src/openhuman/inference/provider/ops.rs`:
- Around line 61-75: The probe path duplicates the OpenAI OAuth routing and
ChatGPT-Account-ID header logic from factory.rs (the
using_openai_oauth/base/header selection), causing drift and sending blank
headers; extract a single helper (e.g., resolve_openai_base_and_headers or
get_openai_routing_and_headers) that returns (base_url: String, extra_headers:
Option<HeaderMap>) and centralizes: 1) detecting OAuth via
lookup_openai_oauth_credentials, 2) choosing the codex/chatgpt base URL, and 3)
only adding ChatGPT-Account-ID when account_id is non-empty (matching
with_extra_header behavior). Replace the inline using_openai_oauth/base/header
logic in ops.rs (and in factory.rs) to call that helper so both paths reuse the
same routing and header decision.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 01fb2d23-8b9e-4701-86d7-ad1580ef354d

📥 Commits

Reviewing files that changed from the base of the PR and between abbde49 and e53dcc8.

📒 Files selected for processing (14)
  • app/src/components/settings/panels/AIPanel.tsx
  • app/src/components/settings/panels/__tests__/AIPanel.test.tsx
  • app/src/services/api/aiSettingsApi.ts
  • src/openhuman/inference/openai_oauth/flow.rs
  • src/openhuman/inference/openai_oauth/flow_tests.rs
  • src/openhuman/inference/openai_oauth/mod.rs
  • src/openhuman/inference/openai_oauth/store.rs
  • src/openhuman/inference/ops.rs
  • src/openhuman/inference/provider/compatible.rs
  • src/openhuman/inference/provider/compatible_tests.rs
  • src/openhuman/inference/provider/factory.rs
  • src/openhuman/inference/provider/ops.rs
  • src/openhuman/inference/schemas.rs
  • src/openhuman/inference/schemas_tests.rs

Comment thread app/src/components/settings/panels/AIPanel.tsx Outdated
Comment thread app/src/components/settings/panels/AIPanel.tsx
Comment thread app/src/services/api/aiSettingsApi.ts
Comment thread src/openhuman/inference/openai_oauth/store.rs Outdated
Comment thread src/openhuman/inference/openai_oauth/store.rs
Comment thread src/openhuman/inference/provider/factory.rs Outdated
@junjunjunbong junjunjunbong changed the title [codex] Use Codex CLI auth for OpenAI sign-in Add Codex OAuth provider support May 27, 2026
@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/openhuman/inference/openai_oauth/store.rs (1)

249-260: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix JWT base64url decoding in decode_access_token_payload

decode_access_token_payload pads the JWT payload with = and then decodes it using general_purpose::URL_SAFE_NO_PAD, which rejects padded (=) input. The fallback to general_purpose::STANDARD is also incorrect for JWT base64url alphabet: STANDARD expects +/ and rejects -_, so account_id/exp extraction can fail for tokens with URL-safe characters.

🐛 Proposed fix
 fn decode_access_token_payload(access_token: &str) -> Option<serde_json::Value> {
     let payload = access_token.split('.').nth(1)?;
-    let padded = match payload.len() % 4 {
-        0 => payload.to_string(),
-        n => format!("{}{}", payload, "=".repeat(4 - n)),
-    };
-    let bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD
-        .decode(padded.as_bytes())
-        .or_else(|_| base64::engine::general_purpose::STANDARD.decode(padded.as_bytes()))
-        .ok()?;
+    // JWT payloads are base64url-encoded without padding
+    let bytes = base64::engine::general_purpose::URL_SAFE_NO_PAD
+        .decode(payload)
+        .or_else(|_| {
+            // Some tokens may have padding; try with padding added
+            let padded = match payload.len() % 4 {
+                0 => payload.to_string(),
+                n => format!("{}{}", payload, "=".repeat(4 - n)),
+            };
+            base64::engine::general_purpose::URL_SAFE.decode(&padded)
+        })
+        .ok()?;
     serde_json::from_slice(&bytes).ok()
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/openhuman/inference/openai_oauth/store.rs` around lines 249 - 260, The
JWT payload decoding in decode_access_token_payload incorrectly pads then uses
URL_SAFE_NO_PAD and falls back to STANDARD (which uses the wrong alphabet);
update decode_access_token_payload to decode using the URL-safe base64 alphabet
that accepts padding: first create the correctly padded payload string (as you
already do) and call base64::engine::general_purpose::URL_SAFE.decode(...) (not
URL_SAFE_NO_PAD), and if that fails fall back to URL_SAFE_NO_PAD.decode(...) —
remove the use of STANDARD entirely — then parse the resulting bytes with
serde_json::from_slice as before.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/openhuman/inference/openai_oauth/store.rs`:
- Around line 249-260: The JWT payload decoding in decode_access_token_payload
incorrectly pads then uses URL_SAFE_NO_PAD and falls back to STANDARD (which
uses the wrong alphabet); update decode_access_token_payload to decode using the
URL-safe base64 alphabet that accepts padding: first create the correctly padded
payload string (as you already do) and call
base64::engine::general_purpose::URL_SAFE.decode(...) (not URL_SAFE_NO_PAD), and
if that fails fall back to URL_SAFE_NO_PAD.decode(...) — remove the use of
STANDARD entirely — then parse the resulting bytes with serde_json::from_slice
as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 709a89b3-4feb-475e-935d-6689549915bf

📥 Commits

Reviewing files that changed from the base of the PR and between 70cea03 and b739127.

📒 Files selected for processing (31)
  • app/src/components/settings/panels/AIPanel.tsx
  • app/src/components/settings/panels/__tests__/AIPanel.test.tsx
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/ar-4.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/bn-4.ts
  • app/src/lib/i18n/chunks/de-1.ts
  • app/src/lib/i18n/chunks/de-4.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/en-4.ts
  • app/src/lib/i18n/chunks/es-1.ts
  • app/src/lib/i18n/chunks/es-4.ts
  • app/src/lib/i18n/chunks/fr-1.ts
  • app/src/lib/i18n/chunks/fr-4.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/hi-4.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/id-4.ts
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/it-4.ts
  • app/src/lib/i18n/chunks/pt-1.ts
  • app/src/lib/i18n/chunks/pt-4.ts
  • app/src/lib/i18n/chunks/ru-1.ts
  • app/src/lib/i18n/chunks/ru-4.ts
  • app/src/lib/i18n/chunks/zh-CN-1.ts
  • app/src/lib/i18n/chunks/zh-CN-4.ts
  • app/src/lib/i18n/en.ts
  • app/src/services/api/__tests__/aiSettingsApi.test.ts
  • app/src/services/api/aiSettingsApi.ts
  • src/openhuman/inference/openai_oauth/store.rs
  • src/openhuman/inference/provider/factory.rs
✅ Files skipped from review due to trivial changes (13)
  • app/src/lib/i18n/chunks/it-1.ts
  • app/src/lib/i18n/chunks/en-4.ts
  • app/src/lib/i18n/chunks/hi-4.ts
  • app/src/lib/i18n/chunks/hi-1.ts
  • app/src/lib/i18n/chunks/zh-CN-4.ts
  • app/src/lib/i18n/chunks/fr-4.ts
  • app/src/lib/i18n/chunks/en-1.ts
  • app/src/lib/i18n/chunks/de-4.ts
  • app/src/lib/i18n/chunks/bn-1.ts
  • app/src/lib/i18n/chunks/id-1.ts
  • app/src/lib/i18n/chunks/ar-1.ts
  • app/src/lib/i18n/chunks/id-4.ts
  • app/src/lib/i18n/chunks/ru-1.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • app/src/services/api/aiSettingsApi.ts
  • app/src/components/settings/panels/tests/AIPanel.test.tsx
  • src/openhuman/inference/provider/factory.rs
  • app/src/components/settings/panels/AIPanel.tsx

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 27, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/lib/i18n/chunks/ko-1.ts`:
- Around line 617-619: The two translation keys
'settings.ai.codexOauthMissingAuthUrl' and
'settings.ai.codexOauthMissingCallbackUrl' are duplicated across chunks; remove
one set so each key appears only once. Locate the duplicate key entries (the
strings 'settings.ai.codexOauthMissingAuthUrl' and
'settings.ai.codexOauthMissingCallbackUrl') and delete them from either ko-1.ts
or ko-4.ts, keeping the copy that best fits the feature grouping/organization;
ensure the remaining entry's text is correct and run the merge/build to verify
no duplicate-key warnings.

In `@app/src/lib/i18n/chunks/ko-4.ts`:
- Around line 279-281: Duplicate translation keys
'settings.ai.codexOauthMissingAuthUrl' and
'settings.ai.codexOauthMissingCallbackUrl' appear in multiple Korean chunks;
remove the duplicate definitions so each key exists exactly once—either delete
these two entries from the ko-4 chunk or remove the ones in ko-1 and keep them
where they best fit in your grouping convention (pick one canonical chunk for
AI/settings strings), then verify the merged locale contains only the retained
entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c95cc9a7-8b39-48c8-bf78-bfff1f162a11

📥 Commits

Reviewing files that changed from the base of the PR and between b5a9964 and 4f330db.

📒 Files selected for processing (2)
  • app/src/lib/i18n/chunks/ko-1.ts
  • app/src/lib/i18n/chunks/ko-4.ts

Comment thread app/src/lib/i18n/chunks/ko-1.ts Outdated
Comment thread app/src/lib/i18n/chunks/ko-4.ts
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 27, 2026
Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@junjunjunbong hey! The code looks solid to me — all of CodeRabbit's findings are properly addressed, the feature is well-tested, and the implementation is clean. However, CI is still running (coverage and E2E tests pending). Once those all pass, I'll circle back and approve this. Let me know if you hit any snags!

AI Summary

What it does: Adds Codex OAuth provider support to OpenAI — users can now authenticate via ChatGPT Codex by importing existing Codex CLI credentials (~/.codex/auth.json) instead of using API keys. The implementation adds new OAuth RPC operations, model catalog normalization (supports both OpenAI data and Codex models response formats), and structured error handling with localized messages.

Breaking risk: Low. New credential mode codex_oauth is opt-in. Model catalog parsing is backward-compatible (accepts both response shapes). No public API changes, no DB schema changes.

Security risk: Low. File I/O reads from local ~/.codex/auth.json, validates on read, no secrets logged, tokens stored via existing encrypted auth profiles. Windows home-dir fallback is correctly implemented. OAuth metadata is tolerant of broken profiles when API-key fallback exists.

Bottom line: Safe to merge once CI passes.


Verification Checklist

  • Codex key clear moved after persist() succeeds (safe transaction order)
  • codexAuthError state properly cleared on successful OpenAI connect
  • OAuth validation errors translated via error codes, not English strings
  • Windows home-directory fallback (HOME, USERPROFILE, HOMEDRIVE+HOMEPATH)
  • Structured diagnostics for Codex CLI import (grep-friendly logs)
  • OAuth metadata lookup is tolerant when API-key routing is available
  • Korean i18n duplicates removed from ko-1.ts, canonical entries in ko-4.ts
  • Tests cover happy + failure paths, error localization verified
  • No lint warnings, TypeScript checks pass

@junjunjunbong
Copy link
Copy Markdown
Author

CI is now green on the latest head (2de8ab3). The earlier Rust Core Coverage failure was a GitHub runner disk issue (), so I pushed an empty rerun commit and the rerun passed, including diff-cover, Rust coverage, Tauri coverage, Linux/Windows/macOS E2E, build, and smoke checks.\n\nCould you please re-review/approve when you get a chance?

@junjunjunbong
Copy link
Copy Markdown
Author

CI is now green on the latest head (2de8ab3). The earlier Rust Core Coverage failure was a GitHub runner disk issue: No space left on device. I pushed an empty rerun commit and the rerun passed, including diff-cover, Rust coverage, Tauri coverage, Linux/Windows/macOS E2E, build, and smoke checks.

Could you please re-review/approve when you get a chance?

@graycyrus
Copy link
Copy Markdown
Contributor

@junjunjunbong unresolved review feedback — please address before we review.

Copy link
Copy Markdown
Contributor

@graycyrus graycyrus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continuation review — my prior COMMENT deferred approval while CI was running. CI is now fully green across all jobs.

The new commit routes Codex OAuth inference through the Responses API. Changes are well-structured and tested.

What changed since last review:

  • responses_api_primary flag routes all three chat paths (with history, without, streaming) directly to the Responses API for Codex OAuth, instead of first attempting chat completions. Clean separation — the flag is opt-in, so all other providers are unaffected.
  • ResponsesContentPart properly types message content. The input_text/output_text distinction correctly maps user/tool messages as input and assistant messages as output, which is what the Responses API expects. Tool-role messages normalizing to assistant in the response format while getting input_text kind is correct.
  • Account ID extraction now checks the namespaced JWT claim https://api.openai.com/auth.chatgpt_account_id before falling back to sub. This matches how Codex CLI JWTs are structured.
  • merge_openai_codex_model_hints injects well-known Codex model IDs when the catalog doesn't return them. Deduplication is case-insensitive — correct.
  • originator header and user agent added to model listing requests when using OAuth, matching what the Codex backend expects.

One thing worth a follow-up PR: the streaming branch for responses_api_primary calls chat_via_responses and emits the entire response as a single TextDelta. The Responses API supports SSE, so users on Codex OAuth will see a pause until the full response arrives rather than incremental output. Functional and safe, but not a great UX on long responses. Worth wiring up SSE for this path later.

Tests cover the new JWT claim shape, the responses_api_primary mock-server routing, model hint deduplication, and the updated Responses prompt content structure. Coverage gate passed.

Code is clean. Approving.

@graycyrus
Copy link
Copy Markdown
Contributor

Unresolved review feedback from coderabbitai[bot] — please address before we review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants