Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
9a6e1db
chore: ignore .worktrees directory
gustavokch Mar 16, 2026
12d94f9
fix: resolve proxy bugs — input filtering, session duplication, race …
gustavokch Mar 16, 2026
bbd1ac3
fix: add timeout to query(), disable tools by default on /v1/messages
gustavokch Mar 16, 2026
cef13d0
chore: update poetry.lock and test suite for pydantic 2.13 and poetry…
gustavokch Mar 16, 2026
c53cdca
feat: v2.3.0 — bug fixes, async concurrency, and SDK options wiring
gustavokch Mar 17, 2026
4bf3e2a
chore: ignore .worktrees directory
gustavokch Mar 24, 2026
9d671c7
fix: add latest models and update default model to Sonnet 4.6
gustavokch Mar 24, 2026
e91c5fe
Change repository URL to new GitHub location
gustavokch Mar 24, 2026
81a91bc
feat: add Gemini CLI proxy support and interactive chat client
gustavokch Apr 6, 2026
c70750c
Merge pull request #1 from gustavokch/feature/gemini-proxy
gustavokch Apr 6, 2026
b203291
perf: optimize CLI latency via parallel prewarming and add process co…
gustavokch Apr 6, 2026
7db1124
Merge pull request #2 from gustavokch/feature/optimize-latency-and-co…
gustavokch Apr 6, 2026
6b38489
fix: resolve Gemini history echoing and improve session continuity
gustavokch Apr 6, 2026
07938a1
Merge pull request #3 from gustavokch/fix/gemini-history-echoing
gustavokch Apr 6, 2026
8e1c831
fix: address streaming echo for Gemini and Claude response failures
gustavokch Apr 6, 2026
5a5e7cc
Merge pull request #4 from gustavokch/fix/streaming-echo-and-claude-r…
gustavokch Apr 6, 2026
596b1f8
fix: improve Claude content extraction and streaming robustness
gustavokch Apr 6, 2026
ed73ae9
fix: refine content filtering to reduce false negatives
gustavokch Apr 6, 2026
53bfa82
Fix wrapper session handling for model switches
gustavokch Apr 6, 2026
8020032
Merge pull request #5 from gustavokch/fix/session-handling-chat-model…
gustavokch Apr 6, 2026
5157ce4
docs: add design spec for sync + SDK 0.2.134 upgrade + GLM-5.2 passth…
Aug 10, 2026
3e102f7
docs: add implementation plan for sync + SDK 0.2.134 upgrade + GLM-5.2
Aug 10, 2026
2651d9d
chore: fix pytest pythonpath and filter Python 3.14 dependency warnings
Aug 10, 2026
5f54ae2
Merge remote-tracking branch 'upstream/main' into feat/sync-sdk-upgra…
Aug 10, 2026
f61e9b1
fix: return None from parse_claude_message when no text found
Aug 10, 2026
4e06732
test: update run_completion test for claude_options design
Aug 10, 2026
8968125
chore: bump claude-agent-sdk 0.1.18 -> 0.2.134
Aug 10, 2026
12aba7e
refactor: harden SDK message parser with typed isinstance dispatch
Aug 11, 2026
5efb841
fix: use isinstance for verify_cli early-break under SDK 0.2.x
Aug 11, 2026
42cd175
feat: advertise glm-5.2 as a passthrough model in /v1/models
Aug 11, 2026
b6189a9
docs: update SDK version to 0.2.134+ and document GLM-5.2 passthrough
Aug 11, 2026
291d490
test: strengthen parser asserts and relax run_completion check; docs:…
Aug 11, 2026
f9934cc
feat: pin SDK to local Claude Code build, add glm-5.2[1m], harden mod…
Aug 11, 2026
0ee1d2a
fix: stop glm-5.2 passthrough tripping max_turns cap and model warning
Aug 11, 2026
d8006d4
fix: eliminate agent SDK system-prompt bloat (18.5k -> 105 input tokens)
Aug 11, 2026
cbf322c
Merge pull request #6 from gustavokch/feat/sync-sdk-upgrade-glm
gustavokch Aug 11, 2026
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
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Claude CLI Configuration
CLAUDE_CLI_PATH=claude

# Gemini CLI Configuration
# GEMINI_API_KEY=your-gemini-api-key-here
# GOOGLE_API_KEY=your-google-api-key-here
GEMINI_CLI_PATH=gemini

# Authentication Method (optional - explicit selection)
# Set this to override auto-detection. Values: cli, api_key, bedrock, vertex
# If not set, auto-detects based on available env vars (ANTHROPIC_API_KEY, etc.)
Expand All @@ -13,6 +18,8 @@ CLAUDE_CLI_PATH=claude

# Server Configuration
PORT=8000
# Maximum number of concurrent CLI processes allowed (default: 3)
# MAX_CONCURRENT_PROCESSES=3
# Host binding address - use 127.0.0.1 for local-only access, 0.0.0.0 for all interfaces
# CLAUDE_WRAPPER_HOST=0.0.0.0
# Maximum request body size in bytes (default: 10MB)
Expand All @@ -21,6 +28,10 @@ PORT=8000
# Timeout Configuration (milliseconds)
MAX_TIMEOUT=600000

# Prewarming Configuration
# Prompt to use during startup for prewarming the CLI backends (default: Hello)
# PREWARM_PROMPT=Hello

# CORS Configuration
CORS_ORIGINS=["*"]

Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ logs/
# Testing
.coverage
.pytest_cache/
.hypothesis/
htmlcov/

# Claude Code
Expand All @@ -57,4 +58,5 @@ test_debug_*.py
test_performance_*.py
test_user_*.py
test_new_*.py
test_roocode_compatibility.py
test_roocode_compatibility.py
.worktrees/
24 changes: 24 additions & 0 deletions PR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Release v2.3.0: Concurrency improvements, SDK options wiring, and critical bug fixes

This PR introduces version 2.3.0, focusing on significant reliability improvements, full support for concurrent SDK calls, wiring of new Claude API options, and resolutions for several critical proxy bugs.

## Features & Enhancements
* **SDK Options Wiring:** Full support for `reasoning_effort`, `response_format`, `thinking`, `max_budget_usd`, and `user` fields passed directly to the Claude SDK.
* **Concurrency:** Removed `os.environ` mutex (`_env_lock`) by passing auth via `options.env`, allowing fully concurrent SDK calls. `SessionManager` has been refactored to use `asyncio.Lock` with all session methods converted to async.
* **Token & Reason Mapping:** Extracts real token counts directly from the SDK's `ResultMessage` and properly maps `stop_reason` to `finish_reason` (e.g., `max_tokens` → `length`).
* **Tool Handling:** Changed `AnthropicMessagesRequest.enable_tools` default to `False` so simple message requests do not trigger unintended 10-turn loops.

## Bug Fixes
* **Session Continuity:** Fixed session continuation by correcting `continue_session` to `continue_conversation` and replaced list appending with replacement to prevent exponential duplication.
* **Timeouts & Hangs:** Wrapped async `query()` iterations with `asyncio.timeout` to prevent indefinite hangs when the SDK subprocess stalls.
* **Proxy Reliability:**
* Removed `filter_content()` from user input which was silently stripping XML-like tags.
* Secured `/v1/auth/status` endpoint with the `verify_api_key()` auth guard.
* Marked the Bash tool as `is_safe=False`.
* Replaced bare `except:` clauses with `except Exception:`.

## Maintenance & Chores
* Updated `poetry.lock` and the test suite for compatibility with `pydantic 2.13` and `poetry 2.3`.
* Replaced deprecated `datetime.utcnow()` with `datetime.now(timezone.utc)`.
* Ignored `.worktrees` directories in `.gitignore`.
* Added diagnostic print statements for `/v1/messages` and improved the `test_message.py` script.
27 changes: 27 additions & 0 deletions PR_GEMINI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Gemini CLI Proxy Support and Interactive Chat Client

This PR introduces support for the Gemini CLI as an alternative backend, allowing users to use Gemini models (like Gemini 3 and 2.5) through the OpenAI-compatible proxy. It also includes a new interactive chat client with Markdown rendering.

## New Features
* **Gemini CLI Proxy:**
* New `GeminiCodeCLI` wrapper for the `@google/gemini-cli` tool.
* Real-time NDJSON stream parsing for low-latency responses.
* Full session continuity support using the CLI's `--resume` flag.
* Integrated model routing: models starting with `gemini-` or using aliases like `pro`, `flash`, `auto` are automatically routed to Gemini.
* **Interactive Chat Client:**
* Added `examples/interactive_chat.py` which manages the background server, provides a rich TUI with `rich` for Markdown rendering, and supports live streaming.
* **Unified Model Listing:**
* Updated `/v1/models` to return both Claude and Gemini models with correct metadata.

## Enhancements
* **Authentication:** Added support for `GEMINI_API_KEY` and `GOOGLE_API_KEY` in the `ClaudeCodeAuthManager`.
* **Constants:** Defined the latest Gemini model IDs and aliases.
* **Configuration:** Updated `.env.example` with Gemini-specific settings.

## Bug Fixes & Refactoring
* **Unified Interface:** Refactored `main.py` endpoints to use a common `get_cli_for_model` helper, making it easier to add more backends in the future.
* **Metadata Extraction:** Improved metadata and usage parsing to handle both Anthropic and Gemini formats consistently.

## Testing
* Added `tests/test_gemini_cli_unit.py` with 100% coverage for the new wrapper.
* Verified both streaming and non-streaming responses for both backends.
163 changes: 137 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Claude Code OpenAI API Wrapper

An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Code with any OpenAI client library. **Now powered by the official Claude Agent SDK v0.1.18** with enhanced authentication and features.
An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Code with any OpenAI client library. **Now powered by the official Claude Agent SDK v0.2.134+** with enhanced authentication and features.

## Version

Expand All @@ -9,11 +9,16 @@ An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Cod
- **Dynamic default Sonnet:** `DEFAULT_MODEL` resolves to the latest Sonnet at startup when `ANTHROPIC_API_KEY` is configured; falls back to `claude-sonnet-4-6` otherwise
- **Operator overrides:** New `CLAUDE_MODELS_OVERRIDE`, `FAST_MODEL`, and `MODEL_LIST_*` env vars
- **Updated catalog:** Claude 4.6 family added to the static fallback list
- **Bug fixes:** `continue_conversation` SDK field corrected; `max_thinking_tokens` now wired through; real token counts from SDK; `finish_reason` mapped from actual `stop_reason`
- **Concurrent requests:** Auth env vars passed via `options.env` — no more serialising lock
- **New parameters:** `reasoning_effort`, `response_format`, `max_budget_usd`, `thinking` added to request models
- **Async session manager:** `threading.Lock` replaced with `asyncio.Lock` for proper async safety
- **SDK options refactor:** `run_completion` simplified to accept a `claude_options` dict, enabling generic passthrough of any SDK field

**Upgrading from v1.x?**
**Upgrading from v2.2.0:**
1. Pull latest code: `git pull origin main`
2. Update dependencies: `poetry install`
3. Restart server - that's it!
3. Restart server — no breaking changes to the OpenAI/Anthropic API surface

**Migration Resources:**
- [MIGRATION_STATUS.md](./MIGRATION_STATUS.md) - Detailed v2.0.0 migration status
Expand All @@ -22,7 +27,7 @@ An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Cod
## Status

🎉 **Production Ready** - All core features working and tested:
- ✅ Chat completions endpoint with **official Claude Agent SDK v0.1.18**
- ✅ Chat completions endpoint with **official Claude Agent SDK v0.2.134+**
- ✅ **Anthropic Messages API** (`/v1/messages`) for native compatibility
- ✅ Streaming and non-streaming responses
- ✅ Full OpenAI SDK compatibility
Expand All @@ -32,7 +37,9 @@ An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Cod
- ✅ Model selection support with validation
- ✅ **Fast by default** - Tools disabled for OpenAI compatibility (5-10x faster)
- ✅ Optional tool usage (Read, Write, Bash, etc.) when explicitly enabled
- ✅ **Real-time cost and token tracking** from SDK
- ✅ **Real token counts** from SDK metadata (no more estimates)
- ✅ **Accurate `finish_reason`** mapped from SDK `stop_reason`
- ✅ **Fully concurrent requests** — no serialising lock for auth env vars
- ✅ **Session continuity** with conversation history across requests
- ✅ **Session management endpoints** for full session control
- ✅ Health, auth status, and models endpoints
Expand All @@ -48,11 +55,13 @@ An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Cod
- Automatic model validation and selection

### 🛠 **Claude Agent SDK Integration**
- **Official Claude Agent SDK** integration (v0.1.18) 🆕
- **Official Claude Agent SDK** integration (v0.2.134+) 🆕
- **Real-time cost tracking** - actual costs from SDK metadata
- **Accurate token counting** - input/output tokens from SDK
- **Real token counting** - input/output tokens directly from SDK (no estimation)
- **Accurate finish_reason** - mapped from SDK `stop_reason` (`end_turn` → `stop`, `max_tokens` → `length`)
- **Session management** - proper session IDs and continuity
- **Enhanced error handling** with detailed authentication diagnostics
- **Fully concurrent** - auth env vars passed via SDK options, no serialising mutex
- **Modern SDK features** - Latest capabilities and improvements

### 🔐 **Multi-Provider Authentication**
Expand All @@ -66,6 +75,10 @@ An OpenAI API-compatible wrapper for Claude Code, allowing you to use Claude Cod
- **System prompt support** via SDK options
- **Optional tool usage** - Enable Claude Code tools (Read, Write, Bash, etc.) when needed
- **Fast default mode** - Tools disabled by default for OpenAI API compatibility
- **`reasoning_effort`** - Map OpenAI `reasoning_effort: "low"|"medium"|"high"` to SDK `effort`
- **`response_format`** - Pass `{"type": "json_object"}` or JSON Schema for structured outputs
- **`thinking`** - Explicit thinking config `{"type": "enabled", "budget_tokens": N}` (overrides `max_tokens` mapping)
- **`max_budget_usd`** - Per-request cost cap in USD
- **Development mode** with auto-reload (`uvicorn --reload`)
- **Interactive API key protection** - Optional security with auto-generated tokens
- **Comprehensive logging** and debugging capabilities
Expand All @@ -83,7 +96,7 @@ Get started in under 2 minutes:

```bash
# 1. Clone and setup the wrapper
git clone https://github.com/RichardAtCT/claude-code-openai-wrapper
git clone https://github.com/gustavokch/claude-code-openai-wrapper
cd claude-code-openai-wrapper
poetry install # Installs SDK with bundled Claude Code CLI

Expand Down Expand Up @@ -121,13 +134,13 @@ poetry run python test_endpoints.py
```
- **Option C**: Use AWS Bedrock or Google Vertex AI (see Configuration section)

> **Note:** The Claude Code CLI is bundled with the SDK (v0.1.18+). No separate Node.js or npm installation required!
> **Note:** The Claude Code CLI is bundled with the SDK (v0.2.134+). No separate Node.js or npm installation required!

## Installation

1. Clone the repository:
```bash
git clone https://github.com/RichardAtCT/claude-code-openai-wrapper
git clone https://github.com/gustavokch/claude-code-openai-wrapper
cd claude-code-openai-wrapper
```

Expand Down Expand Up @@ -473,6 +486,71 @@ for chunk in stream:
print(chunk.choices[0].delta.content, end="")
```

## Advanced Parameters

These extra fields extend the standard OpenAI request body and are passed through to the Claude Agent SDK.

### `reasoning_effort`

Controls the depth of Claude's thinking. Maps to the SDK `effort` field.

```python
response = client.chat.completions.create(
model="claude-sonnet-4-5-20250929",
messages=[{"role": "user", "content": "Solve this math problem..."}],
extra_body={"reasoning_effort": "high"} # "low" | "medium" | "high"
)
```

### `response_format`

Request structured output. Passed through as SDK `output_format`.

```python
response = client.chat.completions.create(
model="claude-sonnet-4-5-20250929",
messages=[{"role": "user", "content": "Return JSON with name and age fields."}],
extra_body={"response_format": {"type": "json_object"}}
)
```

### `thinking`

Explicit thinking configuration — takes precedence over the `max_tokens → max_thinking_tokens` mapping.

```python
response = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Hard reasoning task"}],
extra_body={"thinking": {"type": "enabled", "budget_tokens": 8000}}
)
# Also: {"type": "adaptive"} or {"type": "disabled"}
```

### `max_budget_usd`

Cap per-request cost in USD. The SDK will stop generation when the budget is reached.

```python
response = client.chat.completions.create(
model="claude-sonnet-4-5-20250929",
messages=[{"role": "user", "content": "Long task..."}],
extra_body={"max_budget_usd": 0.05} # stop at $0.05
)
```

### `max_tokens` / `max_completion_tokens`

Maps to the SDK's `max_thinking_tokens` (best-effort). For precise control use `thinking` above.

```python
response = client.chat.completions.create(
model="claude-sonnet-4-5-20250929",
messages=[{"role": "user", "content": "Brief answer please"}],
max_tokens=512
)
```

## Supported Models

The wrapper exposes Claude's full model catalog. When `ANTHROPIC_API_KEY` is set, `/v1/models` returns Anthropic's live list (cached for 1 hour) and the wrapper picks the latest Sonnet as `DEFAULT_MODEL` at startup. When the key is absent — for example, when running with Bedrock, Vertex, or Claude CLI subscription auth — the static list below is served and `claude-sonnet-4-6` is used as the fallback default. Operators who want a curated list regardless of auth can set `CLAUDE_MODELS_OVERRIDE`.
Expand All @@ -493,6 +571,30 @@ The wrapper exposes Claude's full model catalog. When `ANTHROPIC_API_KEY` is set

**Note:** Claude 3.x models are not supported by the Claude Agent SDK. The model parameter is passed to Claude Code via the SDK's model selection.

## Using non-Claude models via passthrough (e.g. GLM-5.2)

The wrapper can serve any model that your Claude Code installation can reach,
including non-Anthropic models such as **GLM-5.2**. The wrapper does not call
the model provider directly — it forwards the model name to Claude Code, which
must already be configured to reach the provider.

**Prerequisite — point Claude Code at the provider.** Set these on the Claude
Code process (your environment, not wrapper code):
- `ANTHROPIC_BASE_URL` — your proxy that speaks the Anthropic API format and
forwards to the provider (e.g. a GLM endpoint).
- `ANTHROPIC_AUTH_TOKEN` or `ANTHROPIC_API_KEY` — the credential your proxy
requires, if any.

**Use it through the wrapper.** Send the model name in the request:
```bash
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"glm-5.2","messages":[{"role":"user","content":"hello"}]}'
```

To make GLM the default, set `DEFAULT_MODEL=glm-5.2` for the wrapper. `glm-5.2`
is advertised in `GET /v1/models`.

## Session Continuity 🆕

The wrapper now supports **session continuity**, allowing you to maintain conversation context across multiple requests. This is a powerful feature that goes beyond the standard OpenAI API.
Expand Down Expand Up @@ -607,26 +709,32 @@ See `examples/session_continuity.py` for comprehensive Python examples and `exam
### 🚫 **Current Limitations**
- **Images in messages** are converted to text placeholders
- **Function calling** not supported (tools work automatically based on prompts)
- **OpenAI parameters** not yet mapped: `temperature`, `top_p`, `max_tokens`, `logit_bias`, `presence_penalty`, `frequency_penalty`
- **OpenAI parameters** not mapped: `temperature`, `top_p`, `logit_bias`, `presence_penalty`, `frequency_penalty` (ignored with a warning)
- **Multiple responses** (`n > 1`) not supported

### 🛣 **Planned Enhancements**
- [ ] **Tool configuration** - allowed/disallowed tools endpoints
- [ ] **OpenAI parameter mapping** - temperature, top_p, max_tokens support
- [ ] **Enhanced streaming** - better chunk handling
### 🛣 **Planned Enhancements**
- [ ] **Token-level streaming** - `include_partial_messages` for finer chunks
- [ ] **MCP integration** - Model Context Protocol server support

### ✅ **Recent Improvements (v2.2.0)**
- **Interactive Landing Page**: API explorer with live endpoint testing
- **Anthropic Messages API**: Native `/v1/messages` endpoint
- **Explicit Auth Selection**: `CLAUDE_AUTH_METHOD` env var
- **Tool Execution Fix**: `enable_tools: true` now works correctly
- [ ] **Temperature/top_p** - native SDK mapping when available

### ✅ **Recent Improvements (v2.3.0)**
- **Bug fixes:** `continue_conversation` field corrected; `max_thinking_tokens` now wired through to SDK
- **Real token counts**: response `usage` comes from SDK metadata, not character estimation
- **Accurate `finish_reason`**: mapped from SDK `stop_reason` (`max_tokens` → `length`, etc.)
- **Concurrent requests**: auth env vars via `options.env` — no serialising mutex
- **New parameters**: `reasoning_effort`, `response_format`, `max_budget_usd`, `thinking`
- **Async session manager**: `threading.Lock` → `asyncio.Lock` for proper async safety

### ✅ **v2.2.0 Features**
- Interactive Landing Page: API explorer with live endpoint testing
- Anthropic Messages API: Native `/v1/messages` endpoint
- Explicit Auth Selection: `CLAUDE_AUTH_METHOD` env var
- Tool Execution Fix: `enable_tools: true` now works correctly

### ✅ **v2.0.0 - v2.1.0 Features**
- Claude Agent SDK v0.1.18 with bundled CLI
- Claude Agent SDK v0.2.134+ with bundled CLI
- Multi-provider auth (CLI, API key, Bedrock, Vertex AI)
- Session continuity and management
- Real-time cost and token tracking
- System prompt support

## Troubleshooting
Expand Down Expand Up @@ -679,13 +787,16 @@ curl http://localhost:8000/v1/auth/status | python -m json.tool
### ⚙️ **Development Tools**
```bash
# Install development dependencies
poetry install --with dev
poetry install

# Format code
poetry run black .

# Run full tests (when implemented)
poetry run pytest tests/
# Run unit tests (no server required)
PYTHONPATH=$(pwd) poetry run pytest tests/test_claude_cli_unit.py tests/test_session_manager_unit.py tests/test_models_unit.py -v

# Run full test suite (unit + integration, server must be running for integration tests)
PYTHONPATH=$(pwd) poetry run pytest tests/ -v
```

### ✅ **Expected Results**
Expand Down
Loading
Loading