@caeliq/claude-code-router 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +92 -10
  2. package/dist/cli.js +910 -802
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  ## ✨ Features
6
6
 
7
7
  - **Model Routing**: Route requests to different models based on your needs (e.g., background tasks, thinking, long context).
8
- - **Multi-Provider Support**: Supports various model providers like OpenRouter, DeepSeek, Ollama, Gemini, Volcengine, SiliconFlow, Codex, Claude subscription, Qwen, Chrome On-Device, and Cursor (SDK).
8
+ - **Multi-Provider Support**: Supports various model providers like OpenRouter, DeepSeek, Ollama, Gemini, Antigravity, Volcengine, SiliconFlow, Codex, Claude subscription, Qwen, Chrome On-Device, and Cursor (SDK).
9
9
  - **Request/Response Transformation**: Customize requests and responses for different providers using transformers.
10
10
  - **Dynamic Model Switching**: Switch models on-the-fly within Claude Code using the `/model` command.
11
11
  - **CLI Model Management**: Manage models and providers directly from the terminal with `ccr model`.
@@ -21,10 +21,11 @@ This fork is based on [claude-code-router](https://github.com/musistudio/claude-
21
21
  - **Mistral Integration**: Added specific handling for Mistral's reasoning parameters and decoupled transformation logic.
22
22
  - **Build & Deployment**: Integrated the UI package into the Docker build process and added a Docker Compose configuration.
23
23
  - **Code Quality**: Localized codebase (English comments), improved error handling, and addressed Copilot review feedback.
24
- - **Gemini Stability & Tool Use Fixes**: Corrected `thoughtSignature` placement in Gemini request bodies (must be a standalone `thought: true` part, not attached to text/function-call parts); filtered synthetic `ccr_` placeholder signatures from outgoing Gemini requests to prevent Gemini 500 errors; fixed `tool_result` content-array serialization in the Anthropic transformer so models receive plain text instead of JSON-wrapped arrays (resolves "Error editing file" in Claude Code); fixed Fastify `onSend` hook to prevent `invalid type 'object'` unhandled rejections on error responses.
24
+ - **Gemini Stability & Tool Use Fixes**: Corrected `thoughtSignature` placement in Gemini request bodies (Gemini 3 expects it as a sibling field on the `functionCall` part itself, and validates only the first such part per step); filtered synthetic `ccr_` placeholder signatures from outgoing Gemini requests to prevent Gemini 500 errors; fixed `tool_result` content-array serialization in the Anthropic transformer so models receive plain text instead of JSON-wrapped arrays (resolves "Error editing file" in Claude Code); fixed Fastify `onSend` hook to prevent `invalid type 'object'` unhandled rejections on error responses.
25
25
  - **Codex (ChatGPT) Integration**: Added Codex transformer for the ChatGPT backend API (Responses API), supporting both OAuth-based authentication (`ccr codex-auth`) and PAT auth via `api_key: "at-..."`, plus SSE streaming, reasoning/thinking content, tool calls with web search, and image handling.
26
26
  - **Cursor SDK Integration**: Added `cursor-sdk` transformer that runs Cursor models in-process via `@cursor/sdk`. Default **bridge** mode keeps Claude Code as the tool host (Cursor built-ins denied); supports `plan` / `agent` modes, `crsr_` / `CURSOR_API_KEY` auth, `ccr model get cursor` model discovery, and Docker runtime install of the SDK native packages.
27
27
  - **Claude Subscription Integration**: Added `claude-auth` support for routing through a Claude Pro or Max subscription via OAuth (`ccr claude-auth`), using the `claude-auth` + `Anthropic` transformer chain.
28
+ - **Antigravity Integration**: Added Google Antigravity OAuth via `ccr antigravity-auth`, with the `antigravity-auth` + `gemini` transformer chain targeting the Antigravity / `cloudcode-pa` API. Supports Gemini and Claude models under that quota, thought-signature round-tripping / fallback, and Claude tool-schema sanitization for Gemini-backed Claude models. Requires `gemini` options `{"cachedContent": false}` because Antigravity has no Google `cachedContents` resource (leaving the default `true` causes 404s).
28
29
  - **Qwen Chat Integration**: Added `qwen-auth` transformer for the Qwen Chat backend (`qwen.aikit.club/v1/chat/completions`), supporting JWT-based authentication (`ccr qwen-auth`) where the user pastes a token copied from `chat.qwen.ai` localStorage, automatic token rotation, and stripping of the trailing `<details>...</details>` metadata block Qwen injects into responses.
29
30
  - **DeepSeek Reasoning Replay**: Implemented mandatory reasoning replay for DeepSeek models (e.g., via OpenCode/ZenGo). DeepSeek requires previous assistant reasoning content to be included in subsequent requests — the `reasoning` transformer automatically replays reasoning output from prior turns.
30
31
  - **Model Discovery**: Enabled non-interactive model discovery for arbitrary API providers. Using `ccr model get <provider>`, the tool automatically fetches remote models, parses custom JSON structures using configurable paths, and appends missing models to the local configuration while preserving existing settings.
@@ -324,16 +325,19 @@ The CLI tool validates all inputs and provides helpful prompts to guide you thro
324
325
  For non-interactive model discovery, you can also test provider access and list remote models directly:
325
326
 
326
327
  ```shell
327
- ccr model get openai
328
+ ccr model get claude
328
329
  ccr model get gemini
330
+ ccr model get openai
329
331
  ```
330
332
 
331
333
  This command:
332
334
  - Calls the provider's model-list endpoint using the configured API key
333
335
  - Prints the remote models returned by the provider
334
- - Prompts to append only missing models to the configured `models` array
336
+ - Prompts to append missing models and remove configured models that the API no longer returns
335
337
 
336
- Built-in endpoint support is included for `openai` and `gemini`. For other providers, you can configure `models_api_url` and a custom `models_response_format` to handle different JSON response structures.
338
+ Built-in endpoint support is included for `anthropic`/`claude`, `gemini`, `openai`, `codex`, and `cursor`. For Claude subscription providers using `claude-auth`, discovery reads `~/.claude-code-router/claude_auth.json` and sends the required Anthropic OAuth beta headers; the provider `api_key` is only a placeholder in that mode. For other providers, you can configure `models_api_url` and a custom `models_response_format` to handle different JSON response structures.
339
+
340
+ For the `codex` provider, model discovery sends the current Codex CLI `client_version` because the ChatGPT backend can gate newly released Codex model slugs by client version. CCR defaults to the latest stable version known at release time; override it with `codex_client_version` on the provider or `CCR_CODEX_CLIENT_VERSION` when testing a newer Codex CLI rollout. Runtime Codex requests are handled separately by the core Codex transformer, which spoofs the Codex CLI request version and identity headers without depending on CCR's CLI package.
337
341
 
338
342
  The `models_response_format` object supports:
339
343
  - `listPath`: JSON path to the array of models (e.g., `"data"`, `"models"`, or `""` for root array)
@@ -361,10 +365,50 @@ You can also override these settings via CLI flags for testing:
361
365
  ccr model get my-provider --list-path data --id-path id --strip-prefix "v1/"
362
366
  ```
363
367
 
364
- If the provider returns additional models, `ccr model get <provider>` can append only the missing entries while keeping existing configured models unchanged.
368
+ If the provider returns model changes, `ccr model get <provider>` can append missing entries and remove unavailable configured entries, each behind a separate confirmation prompt.
365
369
 
366
370
  > **Note**: After syncing models into `config.json`, restart the service with `ccr restart` so the updated provider list is picked up by the running server.
367
371
 
372
+ #### Antigravity Authentication
373
+
374
+ Route Claude Code through Google's Antigravity gateway (`cloudcode-pa`) using account OAuth instead of an API key.
375
+
376
+ ```shell
377
+ ccr antigravity-auth
378
+ # or, for headless/remote:
379
+ ccr antigravity-auth --manual
380
+ ccr antigravity-auth --project <gcp-project-id>
381
+ ```
382
+
383
+ This command:
384
+ 1. Prints a Google OAuth URL (PKCE; callback `http://localhost:51121/oauth-callback`)
385
+ 2. The CCR server handles the public `/oauth-callback` route (Docker maps `51121:3456`, like Codex `1455:3456`)
386
+ 3. Tokens land in `~/.claude-code-router/antigravity_auth.json` (mounted config dir in Docker)
387
+
388
+ Example provider:
389
+
390
+ ```json
391
+ {
392
+ "name": "antigravity",
393
+ "api_base_url": "https://daily-cloudcode-pa.sandbox.googleapis.com",
394
+ "api_key": "oauth",
395
+ "project_id": "$ANTIGRAVITY_PROJECT_ID",
396
+ "models": ["gemini-3-flash", "claude-sonnet-4-6", "claude-opus-4-6-thinking"],
397
+ "transformer": {
398
+ "use": [
399
+ ["gemini", { "cachedContent": false, "thoughtSignatureFallback": "skip" }],
400
+ "antigravity-auth"
401
+ ]
402
+ }
403
+ }
404
+ ```
405
+
406
+ Why those Gemini options:
407
+ - **`cachedContent: false`** — Antigravity has no Google `cachedContents` resource. The Gemini default is `true`; leaving it on causes 404s.
408
+ - **`thoughtSignatureFallback: "skip"`** — explicit form of the default. When a tool call is replayed without a cached `thoughtSignature`, CCR stamps Google's `skip_thought_signature_validator` sentinel so the gateway does not 400. Only change this to `"none"` if your endpoint rejects that sentinel.
409
+
410
+ > **Note**: Keep the CCR server running during auth. Using Antigravity IDE OAuth client credentials from a non-IDE client may violate Google's terms.
411
+
368
412
  #### Codex Provider Authentication
369
413
 
370
414
  The Codex provider supports two authentication modes:
@@ -384,7 +428,14 @@ This command:
384
428
  1. Opens your browser to the OpenAI OAuth authorization page
385
429
  2. After you sign in, the OAuth callback is handled by the running CCR server
386
430
  3. Tokens are stored in `~/.claude-code-router/codex_auth.json`
387
- 4. The Codex transformer automatically refreshes tokens when they expire
431
+ 4. The CLI and server independently refresh tokens five minutes before expiry
432
+
433
+ CCR derives the selected ChatGPT workspace and FedRAMP routing state from the
434
+ OAuth ID token. Runtime requests and `ccr model get codex` both send the same
435
+ Codex bearer, account, and routing headers. Refreshes use an atomic credential
436
+ file and a cross-process lock so a separately running CLI and server cannot
437
+ reuse the same rotating refresh token. A runtime OAuth 401 performs one guarded
438
+ credential reload/refresh retry.
388
439
 
389
440
  > **Note**: The server must be running for `ccr codex-auth` to work, as it hosts the OAuth callback endpoint.
390
441
 
@@ -414,7 +465,16 @@ If your provider `api_key` starts with `at-`, CCR treats it as a Codex Personal
414
465
  }
415
466
  ```
416
467
 
417
- On the first request, CCR resolves the required account headers from OpenAI and caches the result in memory. If `api_key` is not a PAT, CCR falls back to OAuth tokens from `~/.claude-code-router/codex_auth.json`.
468
+ CCR resolves the PAT's account, user, plan, and FedRAMP metadata through
469
+ OpenAI's `/whoami` endpoint before calling the Codex backend. Both runtime
470
+ requests and `ccr model get codex` then send `Authorization`,
471
+ `ChatGPT-Account-ID`, and `X-OpenAI-Fedramp` when required. Metadata requests
472
+ are deduplicated and cached briefly by the server.
473
+
474
+ Auth mode is explicit: an `at-` value is always treated as a PAT. An invalid or
475
+ revoked PAT fails as PAT authentication and is never silently replaced with
476
+ OAuth. Any non-PAT placeholder selects OAuth tokens from
477
+ `~/.claude-code-router/codex_auth.json`.
418
478
 
419
479
  > **See also**: Full Codex setup and troubleshooting are documented in `docs/docs/server/guides/codex.md`.
420
480
 
@@ -447,8 +507,12 @@ Example provider:
447
507
  ```
448
508
 
449
509
  - **bridge** (default): Claude Code hosts tools; Cursor built-ins are denied in an isolated workspace under `~/.claude-code-router/cursor-sdk-workspaces/`
510
+ - Cursor builds its harness prompt server-side from the SDK workspace root, so bridge mode grounds the model in the host environment instead: the project root and platform from the incoming `<env>` block are injected through the workspace `AGENTS.md`, the head and tail of the agent prompt, and the built-in denial message. Host tool calls whose arguments reference the isolated workspace are intercepted, answered with a correction rather than forwarded to Claude Code, and counted in the session metrics. Isolated workspaces are removed with their session and swept when orphaned.
450
511
  - Discover models with `ccr model get cursor` (lists via `Cursor.models.list`, not REST `/models`)
451
512
  - Docker Compose passes `CURSOR_API_KEY` into the container when set; local Cursor sandboxing is forced off in Docker
513
+ - Cursor prompt caching is native to the held-open SDK agent session. CCR reports per-request token estimates to Claude Code and maps SDK cache-read deltas back as bounded Anthropic cache-read usage.
514
+ - Cursor thinking is forwarded from both SDK stream `thinking` messages and token-level `Agent.send({ onDelta })` `thinking-delta` updates, then closed with a synthetic signature so Claude Code can render it as Anthropic extended thinking. Claude Code 2.1.89+ hides interactive thinking summaries by default; enable `"showThinkingSummaries": true` in the settings file passed to Claude Code to display them. This is a client rendering setting: CCR still transports the thinking block when it is disabled.
515
+ - Cursor turns are coordinated per Claude conversation. Identical overlapping retries share one bounded response producer (and recent completed result), so only one consumer reads the Cursor iterator and only one `agent.send` is submitted. Stopping the last subscriber awaits bounded run/iterator retirement before re-entry. Pure, exactly matched tool results resume a live parked run; a rejected result plus meaningful replacement text, an unmatched/dead run, or divergent transcript retires the old agent and replays the full conversation. Idle agents receive slim follow-ups only when the incoming transcript is exactly the committed host-visible transcript plus one supported user message; larger suffixes are fully replayed. CCR does not use `local.force` to bypass Cursor's active-run guard.
452
516
 
453
517
  > **See also**: Full Cursor setup is documented in `docs/docs/server/guides/cursor.md`.
454
518
 
@@ -685,7 +749,9 @@ Transformers allow you to modify the request and response payloads to ensure com
685
749
 
686
750
  - `Anthropic`:If you use only the `Anthropic` transformer, it will preserve the original request and response parameters(you can use it to connect directly to an Anthropic endpoint).
687
751
  - `deepseek`: Adapts requests/responses for DeepSeek API.
688
- - `gemini`: Adapts requests/responses for Gemini API.
752
+ - `gemini`: Adapts requests/responses for Gemini API (also the dialect stage used with Antigravity; same options apply to `vertex-gemini`). Claude Code's effort setting (sent as `output_config.effort`) drives thinking depth: `thinkingLevel` for Gemini 3+ (`low`/`high` on Gemini 3 Pro, plus `medium` on later Pro minors, plus `minimal` on Flash/Lite) or `thinkingBudget` for Gemini 2.5 and Claude-via-Antigravity — never both (the API rejects that mix). Efforts outside a family's range round up (`medium` on Gemini 3 Pro, `xhigh`/`max` anywhere → `high`), and the configured model id is never rewritten (a tier-pinned `gemini-3-pro-low` keeps talking to `gemini-3-pro-low`). Pass options as `["gemini", { ... }]`:
753
+ - **`cachedContent`** (boolean, default `true`): whether CCR may use Google's separate **`cachedContents` HTTP resource** to store/reuse prompt prefixes on the public Gemini API. This is Gemini server-side context cache — **not** Anthropic `cache_control` and **not** Claude Code's local prompt cache. Leave `true` for normal Gemini; set **`false` for Antigravity** (and any gateway without `cachedContents`) or you get 404s.
754
+ - **`thoughtSignatureFallback`** (`"skip"` \| `"none"`, default `"skip"`): what to do when a replayed tool call has no cached Gemini `thoughtSignature` (Claude Code's Anthropic `tool_use` cannot carry that field, so CCR caches signatures by tool-call id and restores them; a miss otherwise 400s). `"skip"` means stamp Google's documented sentinel `skip_thought_signature_validator` on the **first** `functionCall` of the step — the value name refers to that sentinel, **not** “disable the fallback.” Leave `"skip"` for Gemini/Antigravity; set `"none"` only if the endpoint rejects the sentinel (some Vertex). Real cached signatures are always preferred; the sentinel is a last resort.
689
755
  - `mistral`: Adapts requests/responses for Mistral API.
690
756
  - `openrouter`: Adapts requests/responses for OpenRouter API. It can also accept a `provider` routing parameter to specify which underlying providers OpenRouter should use. For more details, refer to the [OpenRouter documentation](https://openrouter.ai/docs/features/provider-routing). See an example below:
691
757
  ```json
@@ -719,6 +785,7 @@ Transformers allow you to modify the request and response payloads to ensure com
719
785
  - `rovo-cli` (experimental): Unofficial support for gpt-5 via Atlassian Rovo Dev CLI [rovo-cli.js](https://gist.github.com/SaseQ/c2a20a38b11276537ec5332d1f7a5e53).
720
786
  - `codex`: Adapts requests/responses for the Codex (ChatGPT) backend API. Supports OAuth via `ccr codex-auth` or PAT auth when `api_key` starts with `at-`.
721
787
  - `claude-auth`: Authenticates requests to Anthropic's API using your Claude Pro or Max subscription OAuth token. Converts Unified format to Anthropic format and handles SSE response conversion. Use it together with `Anthropic` in the provider chain, and authenticate via `ccr claude-auth`.
788
+ - `antigravity-auth`: OAuth + envelope middleware for Google's Antigravity gateway (`cloudcode-pa`). Chain **after** `gemini`. For Antigravity you must set `cachedContent: false` on the Gemini stage (no `cachedContents` resource there); keep `thoughtSignatureFallback: "skip"` unless the endpoint rejects Google's thought-signature sentinel. Authenticate with `ccr antigravity-auth`.
722
789
  - `chrome-on-device`: Routes requests to Chrome's on-device Gemini Nano model via the Prompt API. Uses `responseConstraint` for structured JSON output. Requires a bridge process running on the host (`ccr chrome-bridge`).
723
790
 
724
791
  **Chrome On-Device Provider Configuration:**
@@ -984,6 +1051,21 @@ Please help me analyze this code snippet for potential optimizations...
984
1051
  export CLAUDE_CODE_SUBAGENT_MODEL="openrouter,anthropic/claude-3.5-sonnet"
985
1052
  ```
986
1053
 
1054
+ ## Prompt Caching
1055
+
1056
+ CCR translates Claude Code's Anthropic cache intent into each upstream's native caching mechanism automatically:
1057
+
1058
+ - Anthropic, Claude Auth, and Vertex Claude use Anthropic automatic prompt caching while preserving bounded explicit block markers.
1059
+ - OpenAI Chat and Responses use stable `prompt_cache_key` values; GPT-5.6+ models also receive explicit content breakpoints. Codex uses its separate native contract for every model: a stable prompt key plus session-routing headers, with no explicit content breakpoints.
1060
+ - OpenRouter uses sticky `session_id` routing plus model-native caching. Vercel AI Gateway receives `providerOptions.gateway.caching: "auto"`.
1061
+ - Mistral and Cerebras receive native `prompt_cache_key` values. Qwen/DashScope receives a final-content cache marker. DeepSeek, Groq, and Vertex OpenAI retain their native implicit caching.
1062
+ - Gemini and Vertex Gemini use implicit caching and create/reuse native CachedContent resources for sufficiently large stable system/tool prefixes.
1063
+ - Cursor SDK and Chrome On-Device reuse stable native sessions.
1064
+
1065
+ Provider-incompatible cache fields are removed only after translation. Cache read/write usage reported upstream is converted back to Anthropic `cache_read_input_tokens` and `cache_creation_input_tokens` for Claude Code.
1066
+
1067
+ See [the implementation plan and review](tasks/caching-plan.md) for the provider matrix and verification scope.
1068
+
987
1069
  ## Status Line (Beta)
988
1070
  To better monitor the status of claude-code-router at runtime, version v1.0.40 includes a built-in statusline tool, which you can enable in the UI.
989
1071
  ![statusline-config.png](/blog/images/statusline-config.png)
@@ -1057,4 +1139,4 @@ This setup allows for interesting automations, like running tasks during off-pea
1057
1139
 
1058
1140
  - [Codex API](https://developers.openai.com/codex/sdk) — Developer docs for the ChatGPT backend API used by the `codex` transformer (OAuth PKCE, Responses API, streaming, tool calls)
1059
1141
  - [Chrome Prompt API](https://developer.chrome.com/docs/ai/prompt-api) — On-device Gemini Nano API used by the `chrome-on-device` transformer and bridge
1060
- - [Provider Integration Lessons](tasks/lessons.md) — Hard-won knowledge for LLM provider integrations (DeepSeek, Mistral, Gemini, Codex, Gemini Nano)
1142
+ - [Provider Integration Lessons](tasks/lessons.md) — Hard-won knowledge for LLM provider integrations (DeepSeek, Mistral, Gemini, Codex, Gemini Nano)