Skip to content

runtime: codex-backend LlmContext leg — make OpenAI/ChatGPT subscriptions usable for ctx.llm #198

Closed

Description

@khaliqgant

Why

Operator expectation: "all subscription credentials should work" for ctx.llm. Today that's true for Anthropic (Claude Pro/Max access tokens are accepted by the Messages API with the OAuth beta header — the CLAUDE_CODE_OAUTH_TOKEN contract) but impossible for OpenAI via the platform API, probe-verified 2026-06-04 against a real codex subscription tokens.access_token:

  • POST api.openai.com/v1/chat/completions + subscription bearer → auth ACCEPTED, billing refused:
    {"error":{"message":"You exceeded your current quota...","type":"insufficient_quota","code":"insufficient_quota"}}
  • POST api.openai.com/v1/responses (the sign-in-with-ChatGPT path, tried gpt-5.5-codex and gpt-5.5) → scope-blocked:
    {"error":{"message":"You have insufficient permissions for this operation. Missing scopes: api.responses.write...","type":"invalid_request_error"}}

So cloud's resolver correctly refuses to inject these tokens as OPENAI_API_KEY (cloud#1890) — injecting one produces configured-then-insufficient_quota on every call, strictly worse than the explicit stub. The current mitigations are workarounds: anthropic cross-stamp for openai-family personas (workforce#197), house relay-managed key, or platform BYOK.

What

A third provider leg in packages/runtime/src/cloud-llm.ts that speaks the codex/ChatGPT backend protocol (what the codex CLI itself uses for subscription inference) instead of the platform API:

  1. New credential source recognized by selectCredential (e.g. CODEX_OAUTH_TOKEN / a structured env the cloud resolver can emit for provider_oauth + openai once this leg exists).
  2. The leg implements the codex backend session/completion exchange (endpoint, headers, account_id from the auth blob, streaming shape) and adapts it to the LlmContext interface.
  3. Token refresh: subscription access tokens expire in hours — compose with the existing refresh seam (cloud's refreshHarnessCliCredentialIfStale already refreshes openai blobs via auth.openai.com/oauth/token).
  4. Cloud follow-up (separate PR): lift the provider_oauth+openai rejection in resolveCredentialValue to emit the new env contract instead of throwing, and stamp openai-family selections in the deploy clients.

Open questions

  • Protocol stability/ToS: the ChatGPT backend API is not a published platform contract; assess maintenance risk before committing (the codex CLI's own implementation is the reference).
  • Model mapping: subscription backend serves codex-tuned models; resolveModel needs a mapping table rather than pass-through.

Context

cloud#1890 (rejection + rationale), workforce#196/#197 (selections stamping + cross-stamp fallback), probe transcript in the team channel 2026-06-04.

🤖 Generated with Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions