Skip to content

fix(tui): delegate OAuth/setup-token summarization to claude CLI#58

Merged
jalehman merged 6 commits into
Martian-Engineering:mainfrom
GodsBoy:fix/tui-oauth-gateway-proxy
Mar 18, 2026
Merged

fix(tui): delegate OAuth/setup-token summarization to claude CLI#58
jalehman merged 6 commits into
Martian-Engineering:mainfrom
GodsBoy:fix/tui-oauth-gateway-proxy

Conversation

@GodsBoy

@GodsBoy GodsBoy commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Problem

summarizeAnthropic() in tui/repair.go sends requests directly to https://api.anthropic.com/v1/messages. When the user has a Claude Max OAuth setup-token (sk-ant-oat01-...), PR #40 correctly detects it via isOAuthToken(). However, Anthropic's public API endpoint does not support OAuth/setup-tokens, returning 401 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 the claude CLI binary (Claude Code) as a subprocess instead of making a direct HTTP request:

  • summarizeViaCLI() helper runs claude --print -p <prompt>, which uses its own stored Max OAuth credentials
  • ANTHROPIC_API_KEY is filtered from the subprocess environment so the CLI uses its OAuth flow, not the setup-token as an API key
  • Clear error if OAuth token is present but claude CLI is not found in PATH, guiding the user to install Claude Code or use --provider openai
  • Non-OAuth flow is unchanged: regular API keys still hit https://api.anthropic.com/v1/messages directly with x-api-key header
  • resolveGatewayURL() fix: port lookup now checks gateway.port (nested) in addition to top-level port, matching real OpenClaw config layout

Why 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 200 responses from gateway paths (/anthropic/v1/messages, /v1/proxy/messages) were the Control UI HTML, not API endpoints. The claude CLI subprocess approach is simpler and works immediately without requiring any gateway changes.

Evidence

Setup-token auth working via claude CLI delegation (dry-run rewrite, no ANTHROPIC_API_KEY set):

lcm-tui setup-token evidence

Testing

5 tests in tui/llm_client_test.go, all passing:

  • TestIsOAuthToken: verifies token prefix detection
  • TestResolveGatewayURL: reads port from temp config file (both top-level and nested gateway.port)
  • TestResolveGatewayURLMissingFile: returns empty when config absent
  • TestSummarizeAnthropicOAuthDelegatesToCLI: OAuth token delegates to CLI, HTTP transport is never called
  • TestSummarizeAnthropicRegularKeyHitsDirectAPI: regular key hits api.anthropic.com with x-api-key header
=== RUN   TestIsOAuthToken
--- PASS: TestIsOAuthToken (0.00s)
=== RUN   TestResolveGatewayURL
--- PASS: TestResolveGatewayURL (0.00s)
=== RUN   TestResolveGatewayURLMissingFile
--- PASS: TestResolveGatewayURLMissingFile (0.00s)
=== RUN   TestSummarizeAnthropicOAuthDelegatesToCLI
--- PASS: TestSummarizeAnthropicOAuthDelegatesToCLI (2.05s)
=== RUN   TestSummarizeAnthropicRegularKeyHitsDirectAPI
--- PASS: TestSummarizeAnthropicRegularKeyHitsDirectAPI (0.00s)
PASS
ok      github.com/Martian-Engineering/lossless-claw/tui    2.061s

Fixes #57

@GodsBoy GodsBoy force-pushed the fix/tui-oauth-gateway-proxy branch from bd3fe5f to 1682b29 Compare March 13, 2026 09:43
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
@GodsBoy GodsBoy force-pushed the fix/tui-oauth-gateway-proxy branch from 1682b29 to 2b11b80 Compare March 13, 2026 09:44
@GodsBoy GodsBoy changed the title fix(tui): proxy setup-token requests through OpenClaw gateway fix(tui): delegate OAuth/setup-token calls to claude CLI subprocess Mar 13, 2026
@GodsBoy GodsBoy changed the title fix(tui): delegate OAuth/setup-token calls to claude CLI subprocess fix(tui): delegate OAuth/setup-token summarization to claude CLI Mar 13, 2026
@GodsBoy

GodsBoy commented Mar 13, 2026

Copy link
Copy Markdown
Contributor Author

Evidence: lcm-tui working with Claude Max setup-token

lcm-tui-pr58-evidence

Test environment:

  • VPS: Ubuntu 24.04 (root), Hetzner
  • OpenClaw v2026.3.12, lossless-claw plugin v0.3.0
  • Claude Max subscriber, setup-token (sk-ant-oat01-...) stored in ~/.openclaw/openclaw.json
  • ANTHROPIC_API_KEY is not set in the environment
  • claude CLI installed (v2.1.68), authenticated via Max OAuth

What the screenshot shows:

  1. Auth profiles from OpenClaw config confirmed (setup-token detected)
  2. ANTHROPIC_API_KEY is unset (no direct API key available)
  3. lcm-tui rewrite 46 --summary sum_47d7e50442c62900 --dry-run runs successfully
  4. Summary rewritten: 342 tokens -> 223 tokens (saved 119 tokens)
  5. The claude CLI handled the OAuth exchange transparently

All 5 tests pass: go test ./tui/ -v (see test results in PR body)

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.
@GodsBoy GodsBoy force-pushed the fix/tui-oauth-gateway-proxy branch from 0fb80ef to 4f82d1f Compare March 13, 2026 09:48
@jalehman jalehman merged commit ae260f7 into Martian-Engineering:main Mar 18, 2026
1 check passed
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).
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>
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.

fix(tui): setup-token (OAuth) cannot authenticate against api.anthropic.com

2 participants