Skip to content

feat(openai): support ChatGPT OAuth for Responses vision - #40

Open
scotthuang wants to merge 4 commits into
openclaw:mainfrom
scotthuang:fix/openai-oauth-vision
Open

feat(openai): support ChatGPT OAuth for Responses vision#40
scotthuang wants to merge 4 commits into
openclaw:mainfrom
scotthuang:fix/openai-oauth-vision

Conversation

@scotthuang

@scotthuang scotthuang commented Jul 23, 2026

Copy link
Copy Markdown

What problem this solves

ChatGPT OAuth access tokens are not OpenAI Platform API keys. Tachikoma previously resolved the stored OAuth access token as a generic bearer credential and sent it to https://api.openai.com/v1/responses. That endpoint rejects the token before image understanding can run.

The OAuth path must instead use the ChatGPT Codex Responses backend, include the ChatGPT account identifier carried by the token, and safely refresh rotated OAuth credentials. Stored login credentials persist their refresh chain; credentials explicitly supplied through the environment remain process-local. The public OpenAI API-key path remains unchanged.

Request path

ModelMessage (text + image)
  -> OpenAIResponsesProvider
  -> resolve ChatGPT OAuth + account ID
  -> POST chatgpt.com/backend-api/codex/responses
  -> streamed Responses events
  -> ProviderResponse

Implementation

  • distinguish OpenAI API keys from ChatGPT OAuth credentials
  • refresh stored OAuth sessions and atomically persist access token, rotated refresh token, and expiry together
  • keep refreshed environment OAuth sessions in a process-local cache without writing them to the credential store
  • invalidate the environment cache when the source environment values or ignore-environment setting changes
  • deduplicate concurrent refreshes and keep environment/store credential sources coherent
  • encode text, image, tool, and streaming requests for the Codex Responses transport
  • omit the public-API-only max_output_tokens field from Codex requests
  • cover GPT-5.5 and GPT-5.6 Sol, Terra, and Luna image payloads

Evidence

Red: the previous endpoint rejects the OAuth credential

A minimal Responses request was sent with the same valid ChatGPT OAuth access token used by the green test below. The token is redacted here.

POST https://api.openai.com/v1/responses
Authorization: Bearer <redacted ChatGPT OAuth token>

Observed response:

HTTP_STATUS:401
You have insufficient permissions for this operation.
Missing scopes: api.responses.write.

This is the concrete failure behind the bug: login succeeds, but the resulting OAuth token cannot be used as a Platform API credential.

Green: live OAuth vision through the Codex backend

The committed live integration test uses a deterministic 16x16 solid-red PNG and the prompt:

Reply with the single lowercase word red if this image is red.

Sanitized request observed from the provider:

{
  "model": "gpt-5.6-sol",
  "stream": true,
  "store": false,
  "input": [{
    "role": "user",
    "content": [
      {"type": "input_text", "text": "Reply with the single lowercase word red if this image is red."},
      {"type": "input_image", "image_url": "data:image/png;base64,<redacted>"}
    ]
  }]
}

The request was sent to:

https://chatgpt.com/backend-api/codex/responses

Observed SSE result:

response.output_text.delta: "red"
response.output_text.done:  "red"
response.completed: status=completed
usage: input_tokens=31, output_tokens=24, total_tokens=55

Result: the real GPT-5.6 Sol OAuth vision request passed in 6.252 seconds.

The local machine cannot reach chatgpt.com directly, so this live invocation supplied a SOCKS-backed URLSession only to the test instance. No proxy implementation is included in this PR.

Reproducibility

On a machine that can reach the Codex endpoint directly and has Peekaboo-compatible OpenAI OAuth credentials:

INTEGRATION_TESTS=1 \
TACHIKOMA_INTEGRATION_PROFILE_DIR=.peekaboo \
swift test --no-parallel -Xswiftc -DLIVE_PROVIDER_TESTS \
  --filter "OpenAI Codex OAuth - GPT-5_6 Sol Vision Support"

The input image is embedded in the test, so the visual assertion is deterministic and does not capture the host desktop.

Credential-boundary, refresh, and concurrency proof

The focused authentication suite directly verifies both persistence modes and their failure/concurrency boundaries:

OpenAI Codex OAuth refresh rotates and persists credentials                         passed
OpenAI Codex OAuth caches refreshed environment credentials without persisting      passed
OpenAI Codex OAuth continues an environment refresh chain in memory                 passed
OpenAI Codex OAuth environment changes invalidate the in-memory refresh chain        passed
OpenAI Codex OAuth ignore-environment changes invalidate the in-memory refresh chain passed
OpenAI Codex OAuth refreshes an explicit environment account over another stored account passed
OpenAI Codex OAuth concurrent callers share one refresh                             passed

The environment tests assert that TKCredentialStore().load() remains empty, that a pre-existing stored account remains byte-for-byte unchanged, that rotated refresh tokens continue in memory, and that changes to the environment source or ignore setting discard the cache. The stored-session test verifies atomic persistence. Failure tests verify HTTP and malformed responses preserve existing credentials, while the concurrency test starts eight simultaneous callers and observes one refresh request with eight identical results.

Reproduction command:

/usr/bin/arch -arm64 swift test --filter AuthManagerTests

Observed result: 19 tests passed.

Compatibility and upgrade matrix

Existing configuration Expected behavior after upgrade Evidence Coverage
Explicit configured OpenAI API key Keep using api.openai.com/v1/responses; do not enter Codex OAuth transport Responses provider hits /v1/responses and encodes body ✅ Direct test
Stored API key plus stored OAuth token noise API key keeps priority and OAuth tokens are not loaded as Platform keys OpenAI API key credential is preferred over OAuth token noise; OAuth tokens are not loaded as OpenAI API keys ✅ Direct tests
Environment API key plus stored API key Environment API key keeps existing priority env preferred over creds ✅ Direct test
Valid environment OAuth plus a different stored OAuth account Use the explicit environment account without mixing stored credentials OpenAI Codex OAuth prefers a valid environment account ✅ Direct test
Valid stored OAuth session Use Codex endpoint, account header, streaming image payload, and omit unsupported platform fields Codex OAuth provider sends image input through ChatGPT Responses transport for GPT-5.5 and all GPT-5.6 variants ✅ Direct tests
Expired stored OAuth plus refresh token Refresh at auth.openai.com, rotate tokens, and persist access/refresh/expiry together OpenAI Codex OAuth refresh rotates and persists credentials ✅ Direct test
Expired environment OAuth plus refresh token Refresh in memory, reuse the refreshed access token, and never create/update the credential file OpenAI Codex OAuth caches refreshed environment credentials without persisting ✅ Direct test
Rotated environment refresh token followed by another refresh Continue from the in-memory rotated token rather than the stale environment token OpenAI Codex OAuth continues an environment refresh chain in memory ✅ Direct test
Environment values or ignore-environment setting changes Invalidate the process-local cache and resolve/refresh from the new source state environment-change and ignore-environment cache invalidation tests ✅ Direct tests
Expired environment OAuth plus a different stored account Refresh the explicit environment account without overwriting or switching to the stored account OpenAI Codex OAuth refreshes an explicit environment account over another stored account ✅ Direct test
Malformed/unrefreshable environment token plus refreshable stored OAuth Fall back to the stored refresh chain OpenAI Codex OAuth refresh ignores an unrefreshable environment token ✅ Direct test
Refresh endpoint returns non-2xx or malformed token JSON Fail authentication without persisting partial credentials HTTP failure and invalid refresh payload preservation tests ✅ Direct tests
Truly simultaneous callers encounter an expired token Share one actor-coordinated refresh task OpenAI Codex OAuth concurrent callers share one refresh verifies eight callers and one refresh request ✅ Direct test

Every compatibility and upgrade path in this matrix is covered by a focused direct test.

User impact

Applications embedding Tachikoma, including Peekaboo, can use OpenAI OAuth credentials for Responses-based visual understanding without requiring a separate OpenAI API key. Existing API-key configurations retain their current endpoint and request behavior. Environment-provided sessions remain ephemeral; use the normal login flow when refresh rotation must persist across launches.

Downstream dependency

This PR is a prerequisite for openclaw/Peekaboo#293, which updates Peekaboo's OAuth availability handling and Tachikoma submodule pointer. Peekaboo #293 is ready for review but must merge after this PR.

Validation

  • live GPT-5.6 Sol OAuth vision: deterministic red PNG returned red in 6.252 seconds
  • /usr/bin/arch -arm64 swift test --filter AuthManagerTests — 19 tests passed
  • /usr/bin/arch -arm64 swift test --filter OpenAIResponsesProviderTests — 30 tests passed, including GPT-5.5 and all GPT-5.6 variants
  • /usr/bin/arch -arm64 swift test --no-parallel — 842 of 843 tests passed; the only failure is an unrelated existing OpenAI audio network-error test that sends to the real api.openai.com endpoint and timed out after 60 seconds
  • git diff --check

@scotthuang
scotthuang marked this pull request as ready for review July 23, 2026 09:20
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Jul 27, 2026
@clawsweeper

clawsweeper Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed July 30, 2026, 4:14 PM ET / 20:14 UTC.

ClawSweeper review

What this changes

This PR distinguishes ChatGPT OAuth credentials from OpenAI Platform API keys, routes OAuth-backed Responses vision requests through the ChatGPT Codex backend, and adds refresh, credential-isolation, image, streaming, and concurrency coverage.

Merge readiness

⚠️ Ready for maintainer review - 3 items remain

This PR has strong concrete proof and no discrete correctness defect found in the supplied branch review, but it introduces a new supported credential-routing contract to the ChatGPT Codex backend. Keep it open for an explicit maintainer decision on whether that backend and token-refresh behavior belong in Tachikoma’s public OpenAI provider surface.

Priority: P2
Reviewed head: d4cd49f0e8ec178c7224df436b6ea9604ed34cbc
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A well-evidenced, focused provider feature with no concrete patch defect found, held for maintainer ownership of the new OAuth transport contract.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (live_output): The PR body includes redacted after-fix live OAuth vision output from the changed backend path, a deterministic image assertion, and focused credential/transport validation results.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (live_output): The PR body includes redacted after-fix live OAuth vision output from the changed backend path, a deterministic image assertion, and focused credential/transport validation results.
Evidence reviewed 5 items Scoped production and test change: The branch modifies two production files and three focused test files to add OAuth credential classification, refresh behavior, Codex transport encoding, and live/provider coverage.
Credential and transport coverage: The PR adds direct tests for stored and environment OAuth refresh chains, source-cache invalidation, atomic persistence boundaries, concurrent refresh sharing, and ChatGPT account-header/image request encoding.
Real behavior proof: The PR body provides redacted after-fix live output for a GPT-5.6 Sol image request sent to the Codex Responses endpoint, including the observed completed SSE result of red, plus focused validation commands and results.
Findings None None.
Security None None.

How this fits together

Tachikoma’s OpenAI Responses provider turns application model messages into streamed OpenAI requests. This change inserts credential classification and refresh handling before transport selection, preserving the Platform API route for API keys while sending qualifying ChatGPT OAuth sessions to the Codex Responses backend.

flowchart LR
  A[Application model message] --> B[OpenAI Responses provider]
  B --> C[Resolve API key or ChatGPT OAuth]
  C --> D{Credential type}
  D -->|Platform API key| E[OpenAI Responses API]
  D -->|ChatGPT OAuth| F[Refresh and account lookup]
  F --> G[ChatGPT Codex Responses API]
  E --> H[Streamed provider response]
  G --> H
Loading

Decision needed

Question Recommendation
Should Tachikoma formally support ChatGPT OAuth by routing qualifying credentials through the ChatGPT Codex Responses backend rather than treating the OpenAI provider as Platform-API-key-only? Sponsor the OAuth transport: Accept the Codex backend as a supported OpenAI-provider path, retain the tested API-key compatibility behavior, and merge before the dependent Peekaboo change.

Why: The implementation is coherent and evidenced, but deciding to support a separate ChatGPT backend, account header, and refresh lifecycle is an SDK product and compatibility commitment rather than a mechanical patch choice.

Before merge

  • Resolve merge risk (P1) - Merging makes the ChatGPT Codex Responses endpoint, account header, and OAuth-refresh contract part of Tachikoma’s supported behavior; an upstream backend or token-contract change could stop OAuth-backed calls while Platform API-key users continue to work.
  • Resolve merge risk (P2) - Existing users who supplied a valid JWT-shaped OPENAI_ACCESS_TOKEN may be routed differently after upgrade, so the intended credential classification and fallback contract need maintainer ownership even though the PR includes focused compatibility tests.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch scope 5 files affected: 2 production, 3 test; 1,269 added and 87 removed The sizeable but focused change combines provider routing with credential lifecycle behavior, so maintainers should assess the supported-contract boundary rather than only individual tests.
Focused validation 19 auth tests and 30 provider tests reported; 1 live OAuth vision run reported The contributor supplied both credential-boundary coverage and observed after-fix provider behavior.

Merge-risk options

Maintainer options:

  1. Confirm and merge the supported transport (recommended)
    Explicitly accept the Codex OAuth endpoint and refresh contract as supported behavior, then merge with the existing API-key compatibility coverage.
  2. Document a narrower supported boundary first
    Require maintainer-approved documentation of credential precedence, endpoint ownership, and upgrade expectations before merge.
  3. Pause the feature direction
    Close or defer the branch if Tachikoma should remain limited to the public Platform API transport.

Technical review

Best possible solution:

If maintainers endorse ChatGPT OAuth as a supported Tachikoma capability, merge it as the single documented transport boundary, preserve API-key precedence and environment credential isolation, and coordinate the downstream Peekaboo submodule update after the source change lands.

Do we have a high-confidence way to reproduce the issue?

Yes for the reported OAuth mismatch, with medium confidence: the PR supplies a concrete live request/result and a committed integration-test path, but this read-only review could not execute the credential-bound test against a real account.

Is this the best way to solve the issue?

Unclear: the implementation is a focused solution with strong compatibility coverage, but whether the ChatGPT Codex backend is the best supported Tachikoma transport is a maintainer product-contract decision.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 590cbc5a6ebf.

Labels

Label justifications:

  • P2: This is a significant but bounded provider capability and upgrade decision, with no demonstrated active outage or security bypass.
  • merge-risk: 🚨 compatibility: A valid JWT-shaped OpenAI access-token configuration may follow a different endpoint and header path after upgrade.
  • merge-risk: 🚨 auth-provider: The patch adds OAuth credential parsing, account extraction, refresh rotation, and source-specific persistence behavior.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes redacted after-fix live OAuth vision output from the changed backend path, a deterministic image assertion, and focused credential/transport validation results.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes redacted after-fix live OAuth vision output from the changed backend path, a deterministic image assertion, and focused credential/transport validation results.

Evidence

What I checked:

Likely related people:

  • steipete: The repository policy explicitly requires coordinating Tachikoma changes with Peekaboo, and this PR identifies a dependent Peekaboo integration; exact current-main line ownership could not be independently established in the read-only review environment. (role: likely cross-repository owner; confidence: low; files: AGENTS.md, Sources/Tachikoma/Auth/AuthManager.swift, Sources/Tachikoma/Providers/OpenAI/OpenAIResponsesProvider.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Obtain explicit maintainer confirmation that the ChatGPT Codex backend and refresh lifecycle are supported Tachikoma behavior.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (12 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-30T00:58:45.395Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T02:52:26.221Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T03:57:04.798Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T09:38:59.870Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T14:33:57.350Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T15:30:30.176Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T17:19:50.016Z sha d4cd49f :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T18:59:30.022Z sha d4cd49f :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jul 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant