Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ node_modules/
dist/
cli
cli-dev
openclaw/
47 changes: 47 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Common commands

```bash
# Install dependencies
bun install

# Standard build (./cli)
bun run build

# Dev build (./cli-dev)
bun run build:dev

# Dev build with all experimental features (./cli-dev)
bun run build:dev:full

# Compiled build (./dist/cli)
bun run compile

# Run from source without compiling
bun run dev
```

Run the built binary with `./cli` or `./cli-dev`. Set `ANTHROPIC_API_KEY` in the environment or use OAuth via `./cli /login`.

## High-level architecture

- **Entry point/UI loop**: src/entrypoints/cli.tsx bootstraps the CLI, with the main interactive UI in src/screens/REPL.tsx (Ink/React).
- **Command/tool registries**: src/commands.ts registers slash commands; src/tools.ts registers tool implementations. Implementations live in src/commands/ and src/tools/.
- **LLM query pipeline**: src/QueryEngine.ts coordinates message flow, tool use, and model invocation.
- **Core subsystems**:
- src/services/: API clients, OAuth/MCP integration, analytics stubs
- src/state/: app state store
- src/hooks/: React hooks used by UI/flows
- src/components/: terminal UI components (Ink)
- src/skills/: skill system
- src/plugins/: plugin system
- src/bridge/: IDE bridge
- src/voice/: voice input
- src/tasks/: background task management

## Build system

- scripts/build.ts is the build script and feature-flag bundler. Feature flags are set via build arguments (e.g., `--feature=ULTRAPLAN`) or presets like `--feature-set=dev-full` (see README for details).
24 changes: 24 additions & 0 deletions changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Codex API Support: Feature Parity & UI Overhaul

## Summary
This pull request introduces full feature parity and explicit UI support for the OpenAI Codex backend (`chatgpt.com/backend-api/codex/responses`). The codebase is now entirely backend-agnostic and smoothly transitions between Anthropic Claude and OpenAI Codex schemas based on current authentication, without losing features like reasoning animations, token billing, or multi-modal visual inputs.

## Key Changes

### 1. Codex API Gateway Adapter (`codex-fetch-adapter.ts`)
- **Native Vision Translation**: Anthropic `base64` image schemas now map precisely to the Codex expected `input_image` payloads.
- **Strict Payload Mapping**: Refactored the internal mapping logic to translate `msg.content` items precisely into `input_text`, sidestepping OpenAI's strict `v1/responses` validation rules (`Invalid value: 'text'`).
- **Tool Logic Fixes**: Properly routed `tool_result` items into top-level `function_call_output` objects to guarantee that local CLI tool executions (File Reads, Bash loops) cleanly feed back into Codex logic without throwing "No tool output found" errors.
- **Cache Stripping**: Cleanly stripped Anthropic-only `cache_control` annotations from tool bindings and prompts prior to transmission so the Codex API doesn't reject malformed JSON.

### 2. Deep UI & Routing Integration
- **Model Cleanups (`model.ts`)**: Updated `getPublicModelDisplayName` and `getClaudeAiUserDefaultModelDescription` to recognize Codex GPT strings. Models like `gpt-5.1-codex-max` now beautifully map to `Codex 5.1 Max` in the CLI visual outputs instead of passing the raw proxy IDs.
- **Default Reroutes**: Made `getDefaultMainLoopModelSetting` aware of `isCodexSubscriber()`, automatically defaulting to `gpt-5.2-codex` instead of `sonnet46`.
- **Billing Visuals (`logoV2Utils.ts`)**: Refactored `formatModelAndBilling` logic to render `Codex API Billing` proudly inside the terminal header when authenticated.

### 3. Reasoning & Metrics Support
- **Thinking Animations**: `codex-fetch-adapter` now intentionally intercepts the proprietary `response.reasoning.delta` SSE frames emitted by `codex-max` models. It wraps them into Anthropic `<thinking>` events, ensuring the standard CLI "Thinking..." spinner continues to function flawlessly for OpenAI reasoning.
- **Token Accuracy**: Bound logic to track `response.completed` completion events, fetching `usage.input_tokens` and `output_tokens`. These are injected natively into the final `message_stop` token handler, meaning Codex queries correctly trigger the terminal's Token/Price tracker summary logic.

### 4. Git Housekeeping
- Configured `.gitignore` to securely and durably exclude the `openclaw/` gateway directory from staging commits.
23 changes: 22 additions & 1 deletion src/cli/handlers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
getOauthAccountInfo,
getSubscriptionType,
isUsing3PServices,
saveCodexOAuthTokens,
saveOAuthTokensIfNeeded,
validateForceLoginOrg,
} from '../../utils/auth.js'
Expand All @@ -43,6 +44,16 @@ import {
buildAPIProviderProperties,
} from '../../utils/status.js'

/**
* Returns true if the token carries any Anthropic-issued scope (user:* or org:*).
* Codex tokens use OpenID Connect scopes (openid, profile, email, offline_access)
* which are not Anthropic scopes, so this returns false for them.
*/
function hasAnyAnthropicScope(scopes: string[] | undefined): boolean {
if (!scopes?.length) return false
return scopes.some((s) => s.startsWith('user:') || s.startsWith('org:'))
}

/**
* Shared post-token-acquisition logic. Saves tokens, fetches profile/roles,
* and sets up the local auth state.
Expand Down Expand Up @@ -96,14 +107,24 @@ export async function installOAuthTokens(tokens: OAuthTokens): Promise<void> {
await fetchAndStoreClaudeCodeFirstTokenDate().catch(err =>
logForDebugging(String(err), { level: 'error' }),
)
} else {
} else if (hasAnyAnthropicScope(tokens.scopes)) {
// API key creation is critical for Console users — let it throw.
const apiKey = await createAndStoreApiKey(tokens.accessToken)
if (!apiKey) {
throw new Error(
'Unable to create API key. The server accepted the request but did not return a key.',
)
}
} else {
// Third-party provider (e.g. OpenAI Codex) — tokens carry no Anthropic
// scopes. Skip Anthropic API key creation entirely and store the tokens
// in their own dedicated config slot.
saveCodexOAuthTokens({
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken ?? '',
expiresAt: tokens.expiresAt ?? Date.now() + 3600_000,
accountId: (tokens.tokenAccount?.uuid ?? ''),
})
Comment on lines +118 to +127

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Expose Codex sessions through authStatus().

This branch persists a successful Codex login, but authStatus() below still computes loggedIn and authMethod only from Anthropic token/API-key sources. A Codex-only user will immediately get “Not logged in” and exit code 1 after a successful login.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/handlers/auth.ts` around lines 118 - 127, authStatus() currently
derives loggedIn and authMethod only from Anthropic API key/token sources, so a
user who only completed Codex OAuth (persisted by saveCodexOAuthTokens) is
treated as "Not logged in"; update authStatus() to detect the presence of Codex
session tokens (the same config slot written by saveCodexOAuthTokens) and set
loggedIn = true and authMethod = "codex" when no Anthropic credentials exist but
Codex tokens are present, ensuring all downstream checks use this updated
status.

}

await clearAuthRelatedCaches()
Expand Down
Loading