Skip to content

feat: add OpenAI Codex (ChatGPT subscription) OAuth chat provider#1733

Open
FFFFFFpy wants to merge 3 commits into
Tencent:mainfrom
FFFFFFpy:codex/openai-codex-oauth
Open

feat: add OpenAI Codex (ChatGPT subscription) OAuth chat provider#1733
FFFFFFpy wants to merge 3 commits into
Tencent:mainfrom
FFFFFFpy:codex/openai-codex-oauth

Conversation

@FFFFFFpy

Copy link
Copy Markdown
Contributor

PR Body (paste into the GitHub PR description)

Description

Adds a new chat model provider, openai-codex, that authenticates against an
OpenAI ChatGPT / Codex subscription via OAuth (PKCE) instead of an API key,
and talks to the Codex Responses backend (chatgpt.com/backend-api/codex).
This lets operators back the interactive Q&A and article-summary chat slots with
a ChatGPT subscription rather than per-token API billing.

It does not touch the embedding/rerank path — the Codex subscription only
exposes chat, so those slots keep using existing providers.

Design

The Codex Responses protocol is not OpenAI chat-completions compatible (different
request/response shape, SSE event stream, stateless store:false), so this
follows the existing AnthropicChat precedent: a standalone CodexChat
implementation dispatched in NewRemoteChat, rather than a providerAdapter
override (the adapter interface has no response-translation hook). All new logic
is isolated in new files; shared-code changes are minimal:

  • internal/models/chat/codex.goCodexChat, implements the Chat interface
  • internal/models/chat/codex_oauth.go — token store: load / refresh (rotation
    write-back) / cache / account_id extraction, concurrency-safe (RWMutex)
  • internal/models/chat/codex_login.go — PKCE + authorize URL + code exchange
  • internal/models/chat/codex_responses.go — request translation + Responses SSE parse
  • internal/handler/codex_auth.go — OAuth start / complete / status endpoints (Admin-gated)
  • one-line dispatch branch in internal/models/chat/chat.go
  • provider registration in internal/models/provider/openai_codex.go (+ enum, DetectProvider)
  • frontend model-editor login panel + i18n (en/zh/ko/ru), docker-compose.yml volume, .env.example

Auth model (OpenClaw-style)

  • In-app OAuth login: operator opens the authorize URL, logs in with a
    dedicated ChatGPT account, and pastes the localhost:1455 callback URL back
    (the Codex CLI public client only whitelists that redirect URI).
  • Credentials are stored in an independent file (default
    /data/weknora/codex_auth.json, on a private volume, 0600), owned and
    refreshed exclusively by WeKnora. Refresh tokens rotate and are written back.
  • Documented deployment constraint (.env.example): use a separate account and
    do not log the same account in from another client, or refresh-token rotation
    will log them out of each other.

Type of Change

  • ✨ New feature

Related Issue

Fixes #

Testing

  • Unit tests added in internal/models/chat/codex_test.go and
    internal/models/provider/provider_test.go, covering:
    • authorize-URL construction (param set + %20 space encoding, not +)
    • refresh-token rotation + write-back + file permission 0600
    • OAuth error-object decoding
    • shouldRefresh timing (exp skew / max-age)
    • request translation (instructions, tools, parallel tool calls)
    • Responses SSE parse (text, reasoning, tool calls with/without output_index)
    • in-memory credential cache; expired pending-OAuth state sweep
    • DetectProvider mapping for chatgpt.com/backend-api/codex
  • Run: go test ./internal/models/chat/ ./internal/models/provider/
  • Manual E2E (what was actually exercised): completed OAuth login with a
    dedicated account and verified the interactive agent chat path only —
    streaming and non-streaming Q&A, token usage recorded on both.

⚠️ Not yet tested end-to-end: the summary-extraction and wiki
analysis (map-reduce synthesis)
paths have not been exercised against the
Codex backend. See "Known limitations / untested paths" below.

Checklist

  • make fmt && make lint && make test pass locally
  • Self-reviewed the code
  • Added/updated tests covering the change
  • Updated related documentation (README, docs/, Swagger annotations on the
    3 new /models/codex/oauth/* handlers
    , etc.)
  • Breaking changes are clearly called out in the description above (none)

Screenshots / Recordings


Known limitations / untested paths

The following are unverified against the live Codex backend and may need
follow-up before relying on them (each has a concrete reason it might differ from
the interactive chat path that was tested):

  • Summary extraction — exercises the structured-output mapping
    (opts.Format → Responses text.format, json_object / json_schema), which is
    only covered by unit tests, not against the real backend.
  • Wiki analysis (map-reduce synthesis) — long inputs/outputs via non-streaming
    Chat(). Two specifics to watch: (1) max_output_tokens is intentionally not
    sent (the Codex Responses backend rejects it), so any output-length cap the wiki
    pipeline sets is silently dropped; (2) long synthesis calls may approach
    defaultChatTimeout.
  • Reasoning effort — currently derived from opts.Thinking (true → medium,
    false → low). Batch slots that enable thinking will spend more of the
    subscription's rate budget.
  • Rate limiting under batch load — subscription rate limits are tuned for
    interactive use; bulk summary/wiki ingest can hit them. Throttling on the
    WeKnora side is not part of this PR.

Scoping suggestion: this PR can be treated as interactive-chat support, with
summary/wiki validation as a follow-up — or held until those paths are tested,
per maintainer preference.


Compliance / scope note for maintainers

This provider authenticates a ChatGPT/Codex subscription via OAuth, reusing
the Codex CLI public client id, and routes requests to the Codex Responses
backend. OpenAI sanctions subscription OAuth in personal coding-assistant
tools (Codex CLI, OpenClaw); using it to back a self-hosted service is a
grayer area under OpenAI's terms. The feature is therefore strictly opt-in:
it is a separate, non-default provider, requires an explicit operator login with
a dedicated account, ships with the deployment caveats above, and changes nothing
for existing API-key providers. Flagging this so maintainers can decide on
inclusion and whether to attach a usage disclaimer in the docs.

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.

1 participant