Skip to content

support ChatGPT subscription routing through the gateway - #184

Open
peterj wants to merge 7 commits into
mainfrom
peterj/codexsubscription
Open

peterj wants to merge 7 commits into
mainfrom
peterj/codexsubscription

Conversation

@peterj

@peterj peterj commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

Adds programs.codex.auth: subscription so Codex can retain its ChatGPT
login while authenticating separately to the organization’s gateway.

Agentdesktop generates the Codex provider and pairing header automatically.
The local proxy forwards the ChatGPT token separately from gateway identity; the gateway validates identity before restoring the provider credential.

  • Requires a user-mode daemon and llmGateway.proxyUrl.
  • Adds controller subscription-billing classification.
  • Shares subscription-auth classification without changing Claude’s direct-helper flow.
  • Splits proxy caching, routing, and tests into separate modules.
  • Updates schemas, configuration-builder handling, documentation, and examples.

Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Comment thread crates/agent/src/llm_proxy.rs
Comment thread examples/codex-subscription/README.md Outdated
Comment thread examples/codex-subscription/agentgateway.yaml Outdated
Comment thread examples/codex-subscription/agentgateway.yaml Outdated
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Routing, system-mode readability, and shared callback-listener coordination need corrections before supported subscription flows work reliably.

3 open issues
1 file not reviewed
  • frontend/pnpm-lock.yaml: Generated file
What changed in this PR

Adds ChatGPT subscription support to Codex through Agentdesktop’s credential helper and gateway, alongside existing Claude integrations.

Changes:

  • Adds OpenAI OAuth, token refresh, composite credentials, and subscription billing classification.
  • Updates Codex configuration generation and separates proxy routing, caching, and tests.
  • Adds schemas, examples, documentation, and integration coverage.
File Description
schema/​daemon-config.md Documents Codex subscription authentication.
schema/​daemon-config.json Adds the Codex authentication field.
README.md Explains subscription setup and routing.
frontend/​pnpm-lock.yaml Updates optional YAML dependency resolution.
frontend/​controller/​src/​views/​ConfigurationView.stories.tsx Covers subscription configuration output.
examples/​codex-subscription/​README.md Documents setup and validation limits.
examples/​codex-subscription/​dex.yaml Configures demonstration identity authentication.
examples/​codex-subscription/​config.yaml Provides subscription daemon settings.
examples/​codex-subscription/​compose.yaml Runs example gateway and identity services.
examples/​codex-subscription/​agentgateway.yaml Validates identity and restores provider credentials.
crates/​core/​src/​config.rs Adds subscription configuration and shared classification.
crates/​controller/​src/​service.rs Recognizes Codex subscription billing.
crates/​agent/​tests/​common/​gateway.rs Extends mock subscription request validation.
crates/​agent/​src/​subscription.rs Composes provider-specific credentials.
crates/​agent/​src/​subscription_oauth/​openai.rs Implements ChatGPT OAuth and refresh.
crates/​agent/​src/​subscription_oauth/​mod.rs Shares subscription credential lifecycle logic.
crates/​agent/​src/​subscription_oauth/​anthropic.rs Adapts Claude to shared OAuth infrastructure.
crates/​agent/​src/​provider/​codex/​reconcile.rs Generates subscription provider configuration.
crates/​agent/​src/​provider/​codex/​mod.rs Updates reconciliation wiring and system-mode coverage.
crates/​agent/​src/​provider/​codex/​integration_tests.rs Adds native Codex subscription lifecycle coverage.
crates/​agent/​src/​oidc.rs Supports a separate provider callback listener.
crates/​agent/​src/​llm_proxy/​tests.rs Extracts tests and adds Codex passthrough coverage.
crates/​agent/​src/​llm_proxy/​routes.rs Extracts routing and adds the Codex route.
crates/​agent/​src/​llm_proxy/​cache.rs Extracts credential caching and its tests.
crates/​agent/​src/​lib.rs Wires shared OAuth modules.
crates/​agent/​src/​daemon.rs Starts authentication for configured subscription providers.
crates/​agent/​src/​api.rs Resolves provider-specific subscription credentials.

Review effort: Balanced

Comment thread crates/agent/src/provider/codex/reconcile.rs Outdated
Comment thread crates/agent/src/provider/codex/reconcile.rs Outdated
Comment thread crates/agent/src/subscription_oauth/mod.rs
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
Signed-off-by: Peter Jausovec <peter.jausovec@solo.io>
@peterj
peterj requested a review from ilackarms October 21, 2026 18:04
@peterj

peterj commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	frontend/pnpm-lock.yaml

Co-authored-by: peterj <11080940+peterj@users.noreply.github.com>

Copilot AI commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved in 58fdc2c by merging main and reconciling the frontend lockfile with the merged manifests. Frozen install, frontend builds, lint/type checks, and 22 packaging tests passed (one platform-specific skip). Final review found no issues; CodeQL reported no alerts.

@ilackarms ilackarms left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The direct credential-helper flow and shared OAuth extraction look consistent with the existing Claude integration. I found one login-recovery defect: a permanent nested refresh-token rejection leaves the helper retrying the unusable token instead of reopening sign-in. Please address that before merging.

if !status.is_success() {
let invalid_grant = response.json::<Value>().await.ok().is_some_and(|body| {
matches!(
body["error"].as_str(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could we recognize permanent refresh errors in the nested OpenAI error envelope as well? An HTTP 400 response such as {"error":{"code":"refresh_token_reused"}} currently falls through to the generic error because body["error"].as_str() is None. OpenAi::refresh therefore returns an error instead of Ok(None), and the shared credential path exits before starting browser sign-in. Every subsequent request retries the same stored refresh token, so restarting the daemon cannot recover the subscription. Codex 0.153.4 explicitly covers this response in refresh_token_does_not_retry_after_bad_request_reused_failure. Please classify the nested permanent codes as reauthorization-required and add a regression test, while keeping transient failures non-destructive.

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants