fix(tui): delegate OAuth/setup-token summarization to claude CLI#58
Merged
jalehman merged 6 commits intoMar 18, 2026
Merged
Conversation
bd3fe5f to
1682b29
Compare
Setup-tokens (sk-ant-oat01-...) cannot authenticate directly against api.anthropic.com, which returns 401 'OAuth authentication is currently not supported'. This breaks all compaction operations (backfill, recompact, rewrite) for Claude Max subscribers using lcm-tui. When an OAuth token is detected, delegate to the `claude` CLI binary (`claude --print -p <prompt>`) which already holds valid Max OAuth credentials and handles the exchange transparently. ANTHROPIC_API_KEY is unset in the subprocess environment so the CLI uses its own stored OAuth credentials rather than the setup-token. Also fixes resolveGatewayURL() to look for port under gateway.port (nested) in addition to the top-level port field, matching actual OpenClaw config layout. Non-OAuth flow is unchanged: regular API keys still hit api.anthropic.com directly with x-api-key header. Fixes Martian-Engineering#57
1682b29 to
2b11b80
Compare
Contributor
Author
Evidence: lcm-tui working with Claude Max setup-tokenTest environment:
What the screenshot shows:
All 5 tests pass: |
Shows lcm-tui rewrite dry-run succeeding with Claude Max OAuth setup-token, no ANTHROPIC_API_KEY needed. The claude CLI handles the OAuth exchange transparently.
0fb80ef to
4f82d1f
Compare
billzhuang6569
pushed a commit
to billzhuang6569/lossless-claw
that referenced
this pull request
Mar 21, 2026
…tian-Engineering#58) * fix(tui): delegate OAuth/setup-token calls to claude CLI subprocess Setup-tokens (sk-ant-oat01-...) cannot authenticate directly against api.anthropic.com, which returns 401 'OAuth authentication is currently not supported'. This breaks all compaction operations (backfill, recompact, rewrite) for Claude Max subscribers using lcm-tui. When an OAuth token is detected, delegate to the `claude` CLI binary (`claude --print -p <prompt>`) which already holds valid Max OAuth credentials and handles the exchange transparently. ANTHROPIC_API_KEY is unset in the subprocess environment so the CLI uses its own stored OAuth credentials rather than the setup-token. Also fixes resolveGatewayURL() to look for port under gateway.port (nested) in addition to the top-level port field, matching actual OpenClaw config layout. Non-OAuth flow is unchanged: regular API keys still hit api.anthropic.com directly with x-api-key header. Fixes Martian-Engineering#57 * docs: add screenshot evidence of setup-token auth working Shows lcm-tui rewrite dry-run succeeding with Claude Max OAuth setup-token, no ANTHROPIC_API_KEY needed. The claude CLI handles the OAuth exchange transparently. * docs: replace screenshot with redacted version (cache bust) * fix(tui): preserve oauth CLI summary settings * chore: add changeset for oauth summary fix * chore: remove oauth evidence screenshot --------- Co-authored-by: Josh Lehman <josh@martian.engineering>
GodsBoy
added a commit
to GodsBoy/lossless-claw
that referenced
this pull request
Apr 19, 2026
When the user has a ChatGPT Plus/Pro subscription (no raw OPENAI_API_KEY but a populated ~/.codex/auth.json), route openai-codex summarization through the local `codex` CLI so it can use its stored OAuth credentials. Mirrors the existing Anthropic OAuth delegate pattern (PR Martian-Engineering#58). Changes in tui/repair.go: - Hoist cliSummarizationSystemPrompt constant, reused by both CLI delegates. - Add hasCodexOAuth() that probes ~/.codex/auth.json presence. - Add summarizeViaCodexCLI() that runs `codex exec` with a restrictive sandbox (--sandbox read-only), --ephemeral, --output-last-message, and streams the prompt on stdin. The system directive is prepended to the stdin payload because codex has no --system-prompt flag. - Add filteredOpenAIChildEnv() that strips every OPENAI_* env var from the child environment, preventing OPENAI_BASE_URL or proxy vars from re-routing OAuth traffic to an unintended endpoint. - Gate in summarize(): allow an empty apiKey when provider is openai-codex and hasCodexOAuth() returns true. - Branch in summarizeOpenAI(): delegate to summarizeViaCodexCLI() when the Codex OAuth path applies. - resolveProviderAPIKey(): when Codex OAuth is available, return an empty string with nil error so the caller can route to the CLI delegate instead of failing hard. When OAuth is absent, the error now hints at `codex login`. Tests in tui/codex_oauth_test.go cover: - hasCodexOAuth: file absent, empty, present, directory. - OAuth path delegates to CLI (HTTP transport never called). - API-key path still uses direct HTTP (regression). - Empty key without OAuth still errors. - resolveProviderAPIKey returns empty sentinel under OAuth; hints at `codex login` without OAuth. - CLI missing from PATH yields an actionable error. - Non-zero exit surfaces stderr. - Empty and oversized CLI output are rejected. - filteredOpenAIChildEnv removes every OPENAI_* var and preserves unrelated env. Closes Martian-Engineering#469 Refs Martian-Engineering#58 (Anthropic delegate pattern), Martian-Engineering#273 (plugin-side Codex OAuth).
6 tasks
jalehman
added a commit
that referenced
this pull request
Apr 23, 2026
* feat(tui): support Codex OAuth via codex CLI delegate When the user has a ChatGPT Plus/Pro subscription (no raw OPENAI_API_KEY but a populated ~/.codex/auth.json), route openai-codex summarization through the local `codex` CLI so it can use its stored OAuth credentials. Mirrors the existing Anthropic OAuth delegate pattern (PR #58). Changes in tui/repair.go: - Hoist cliSummarizationSystemPrompt constant, reused by both CLI delegates. - Add hasCodexOAuth() that probes ~/.codex/auth.json presence. - Add summarizeViaCodexCLI() that runs `codex exec` with a restrictive sandbox (--sandbox read-only), --ephemeral, --output-last-message, and streams the prompt on stdin. The system directive is prepended to the stdin payload because codex has no --system-prompt flag. - Add filteredOpenAIChildEnv() that strips every OPENAI_* env var from the child environment, preventing OPENAI_BASE_URL or proxy vars from re-routing OAuth traffic to an unintended endpoint. - Gate in summarize(): allow an empty apiKey when provider is openai-codex and hasCodexOAuth() returns true. - Branch in summarizeOpenAI(): delegate to summarizeViaCodexCLI() when the Codex OAuth path applies. - resolveProviderAPIKey(): when Codex OAuth is available, return an empty string with nil error so the caller can route to the CLI delegate instead of failing hard. When OAuth is absent, the error now hints at `codex login`. Tests in tui/codex_oauth_test.go cover: - hasCodexOAuth: file absent, empty, present, directory. - OAuth path delegates to CLI (HTTP transport never called). - API-key path still uses direct HTTP (regression). - Empty key without OAuth still errors. - resolveProviderAPIKey returns empty sentinel under OAuth; hints at `codex login` without OAuth. - CLI missing from PATH yields an actionable error. - Non-zero exit surfaces stderr. - Empty and oversized CLI output are rejected. - filteredOpenAIChildEnv removes every OPENAI_* var and preserves unrelated env. Closes #469 Refs #58 (Anthropic delegate pattern), #273 (plugin-side Codex OAuth). * docs: clarify tui codex oauth usage --------- Co-authored-by: Josh Lehman <josh@martian.engineering>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Problem
summarizeAnthropic()intui/repair.gosends requests directly tohttps://api.anthropic.com/v1/messages. When the user has a Claude Max OAuth setup-token (sk-ant-oat01-...), PR #40 correctly detects it viaisOAuthToken(). However, Anthropic's public API endpoint does not support OAuth/setup-tokens, returning401 authentication_error: OAuth authentication is currently not supported.This breaks all TUI compaction operations (backfill, recompact, rewrite) for Claude Max subscribers.
Note: The lossless-claw plugin (Node.js, running inside OpenClaw) handles this correctly via
runtime.modelAuth.resolveApiKeyForProvider(), which goes through OpenClaw's provider layer and handles the OAuth exchange internally. The TUI binary (Go) is the only component that bypasses OpenClaw and hits api.anthropic.com directly.Solution
When
isOAuthToken(c.apiKey)returns true, delegate the summarization call to theclaudeCLI binary (Claude Code) as a subprocess instead of making a direct HTTP request:summarizeViaCLI()helper runsclaude --print -p <prompt>, which uses its own stored Max OAuth credentialsANTHROPIC_API_KEYis filtered from the subprocess environment so the CLI uses its OAuth flow, not the setup-token as an API keyclaudeCLI is not found in PATH, guiding the user to install Claude Code or use--provider openaihttps://api.anthropic.com/v1/messagesdirectly withx-api-keyheaderresolveGatewayURL()fix: port lookup now checksgateway.port(nested) in addition to top-levelport, matching real OpenClaw config layoutWhy not gateway proxy?
The initial approach (commit fb24e25) attempted to proxy through OpenClaw's local gateway. Investigation revealed OpenClaw does not expose an HTTP proxy endpoint for Anthropic API calls. All
200responses from gateway paths (/anthropic/v1/messages,/v1/proxy/messages) were the Control UI HTML, not API endpoints. TheclaudeCLI subprocess approach is simpler and works immediately without requiring any gateway changes.Evidence
Setup-token auth working via
claudeCLI delegation (dry-run rewrite, noANTHROPIC_API_KEYset):Testing
5 tests in
tui/llm_client_test.go, all passing:TestIsOAuthToken: verifies token prefix detectionTestResolveGatewayURL: reads port from temp config file (both top-level and nestedgateway.port)TestResolveGatewayURLMissingFile: returns empty when config absentTestSummarizeAnthropicOAuthDelegatesToCLI: OAuth token delegates to CLI, HTTP transport is never calledTestSummarizeAnthropicRegularKeyHitsDirectAPI: regular key hits api.anthropic.com withx-api-keyheaderFixes #57