Insert sponsor row in all three README locales linking to runapi.co.
EN/JA copy adapted from the Chinese original. Banner center-cropped to
the project standard 1920x798 aspect ratio (preserves the logo and
slogan, trims the decorative top/bottom padding) and saved as JPEG to
keep file size reasonable (1.3 MB PNG -> 206 KB JPEG).
Insert sponsor row in all three README locales linking to claudecn.top.
EN/JA copy adapted from the Chinese original. Banner normalized to the
project standard sponsor image spec (1920x798 RGB on white background)
and recompressed; alt text unified to "ClaudeCN" across all three files.
Replace byteplus.png with localized huoshan.png (Volcengine/火山引擎)
in README_ZH.md so Chinese readers see the regional brand. EN/JA
README continue to use the BytePlus logo and link to byteplus.com.
The new logo is normalized to the project's standard sponsor image
spec: 1920x798 RGB on a white background.
Insert sponsor row in all three README locales. EN/JA point to
byteplus.com/modelark; ZH points to volcengine.com/agentplan
(Volcengine being the China-region counterpart). Logo normalized
to the project-standard 1920x798 RGB white background and
recompressed (432K -> 84K).
- New src/config/claudeDesktopProviderPresets.ts with the Claude Code
preset list re-shaped into Desktop's three-segment route format
(routeId / upstreamModel / displayName); excludes OAuth providers,
AWS Bedrock (no SigV4 support) and KAT-Coder (placeholder URL).
- Non-Claude upstream presets show upstream model id as displayName
(e.g. deepseek-v4-pro) so the Desktop model list reflects what is
actually being requested. OpenRouter/TheRouter/PIPELLM keep
Sonnet/Opus/Haiku since their upstream really is Anthropic Claude.
- Wire ProviderPresetSelector into ClaudeDesktopProviderForm so
selecting a preset back-fills baseUrl, mode, routes and apiFormat.
- Drop the hard-coded ANTHROPIC_AUTH_TOKEN write in handleSubmit so
ANTHROPIC_API_KEY presets (LemonData / AiHubMix / Gemini Native)
save under the correct env key, and clear the opposite key on switch.
- Hide the universal-providers tab for claude-desktop because its
meta-driven routing has no analogue in the universal flat-env shape.
- Add apps."claude-desktop" i18n key (zh/en/ja) so the dialog tab
label resolves instead of showing the literal key.
- Apply rustfmt diffs in claude_desktop_config.rs
- Allow needless_return on current_platform_paths (cfg-mirrored arms)
- Allow too_many_arguments on RequestForwarder::forward
- Replace `let mut + reassign` with struct literals in tests
(settings, backup, provider, response_processor)
- Use Path::new instead of PathBuf::from to fix cmp_owned in misc tests
- Replace 3.14 with 3.5 in config test to avoid approx_constant lint
- Add ClaudeAPI as new sponsor (all 3 languages)
- Remove ChefShop sponsor entry (all 3 languages)
- Convert shengsuanyun logo from SVG to PNG
- Standardize partner logos to 1920x798 canvas
- Fix ClaudeAPI alt text typo and spacing
- Sync sponsor order across zh/en/ja READMEs
Direct-mode providers no longer display a badge since routing is
optional for them. Proxy-mode providers now show "需要路由" / "Requires
routing" to clarify that local routing must be active.
Claude Desktop strips the [1M] suffix from model IDs when sending
requests, causing route lookup to fail with "model route is not
configured". Fall back to base-name comparison when exact match misses.
- Remove "Import from Claude" button from main provider list (keep in empty state)
- Remove "Desktop model" column from proxy mode mapping table; route names are now auto-generated
- Rename "upstream model" label to "requested model" and equalize column widths
- Rewrite model mapping hint and toggle description for end-user clarity
- Update validation messages and remove dead i18n keys (routeModelLabel)
The route toggle in the top-right corner already communicates proxy
state; the extra warning banner was redundant and inconsistent with
other managed apps.
- services/proxy.rs: collapse 10 repeated `OpenCode | OpenClaw | Hermes |
ClaudeDesktop` match arms into `_` fallthroughs.
- claude_desktop_config.rs: extract a `with_rollback` closure shared by
apply_provider_to_paths and restore_official_at_paths.
- useProviderActions.ts: replace the triple-nested ternary picking the
switch-success toast message with a flat let/if/else block.
Net -36 lines. No behavior change; cargo test and pnpm typecheck pass.
Adds a new ClaudeDesktop AppType that writes Claude Desktop's third-party
inference profile under configLibrary/, sharing _meta.json with other
launchers (Ollama-compatible) so cc-switch can coexist with them.
Two switch modes:
- direct: provider already exposes claude-* / anthropic/claude-* model
ids on Anthropic Messages, Claude Desktop connects to it directly.
- proxy: cc-switch's local proxy acts as the inference gateway,
presenting only claude-* route names to Claude Desktop and mapping
them to real upstream models. Required after Anthropic restricted
Claude Desktop to claude-family ids.
Backend:
- New module claude_desktop_config with snapshot/rollback, official seed
bypass, /claude-desktop/v1/{models,messages} routes, and a single
source of truth for default proxy routes.
- Gateway token persisted in SQLite, validated on every proxied request.
- get_claude_desktop_status surfaces drift signals (stale models,
missing routes, proxy stopped, base URL mismatch, missing token).
Frontend:
- Slim ClaudeDesktopProviderForm independent from ProviderForm,
controlled by a top-level appId guard.
- ProviderList banner consumes the status query (5s polling) and
renders actionable diagnostics.
- ClaudeDesktopRouteToggle in the header to start/stop the local
gateway without touching takeover state.
- Three-locale i18n synchronised.
The hyper raw-write path preserves original header casing but rebuilds
TCP+TLS on every request — there is no connection pool — which was the
root cause of slow reverse-proxy throughput.
Only Anthropic-native requests actually need exact header-case
preservation. Route OpenAI/Copilot/Codex/Gemini/codex_oauth requests
through the pooled reqwest client (pool_max_idle_per_host=10,
tcp_keepalive=60s) instead, so warm connections get reused.
Streaming requests get a precise first-byte timeout via
tokio::time::timeout around reqwest's send() (which resolves on
response headers), with the body phase handed off to response_processor.
The streaming-detection helper now also covers Gemini SSE endpoints
and Accept: text/event-stream, not just body.stream.
Prevents `git fetch origin pull/<N>/head:main` failures on fork PRs
whose head branch is also named `main` — using a SHA puts the runner
in detached HEAD so the main ref is free for the action's internal fetch.
Now that the view transition animation is gone, setTheme no longer
needs click coordinates. Reduce the API surface to (theme: Theme) =>
void and simplify the call sites in mode-toggle and ThemeSettings.
The View Transitions API used here crashes WebKitGTK with SIGSEGV on
Linux. Rather than gating document.startViewTransition per platform
(see PR #2502), drop the animation entirely — it's a low-value visual
flourish on a low-frequency action that doesn't justify a permanent
platform branch.
Removes the ::view-transition-* CSS block and the coordinate plumbing
in setTheme. The optional event parameter is kept on the API surface
to keep call sites compiling; they'll be cleaned up in a follow-up
commit.
Cap was too tight — review tasks need 8-15 turns to read files, analyze,
and post results. The first run after the previous prompt change failed
with error_max_turns at turn 6. The disallowedTools list already keeps
the agent in read-only mode, so an explicit turn cap is redundant.
Previous prompt produced 5-10 findings per PR including dead-code/style
nits mixed with real bugs. New prompt adds severity tiering, an 80
confidence threshold, an explicit anti-pattern list, a 5-nit cap, and
permits zero-comment LGTM as a valid outcome. Calibration follows
Anthropic Code Review docs and the claude-plugins-official prompt.
- Restrict to repo collaborators via author_association check
- Use OAuth token for subscription billing
- Disable Edit/Write tools and set contents:read permission to enforce review-only
Anthropic SDK assigns distinct semantics to the two env vars:
- ANTHROPIC_API_KEY -> x-api-key
- ANTHROPIC_AUTH_TOKEN -> Authorization: Bearer
The Claude adapter previously collapsed both into AuthStrategy::Anthropic
and then emitted Authorization: Bearer regardless, breaking strict
Anthropic-protocol endpoints (Anthropic official, Cloudflare AI Gateway,
OpenCode Go, DashScope) and silently overriding the user's intended auth
scheme.
- claude::extract_auth: infer strategy from env var name
(ANTHROPIC_AUTH_TOKEN -> ClaudeAuth, ANTHROPIC_API_KEY -> Anthropic),
matching the precedence already used by extract_key.
- claude::get_auth_headers: split the Anthropic arm so it emits
x-api-key, while ClaudeAuth and Bearer continue to use Bearer.
- stream_check: reuse ClaudeAdapter::get_auth_headers as the single
source of truth, replacing the prior "always Bearer + maybe x-api-key"
double injection that produced auth conflicts and false-negative
health checks.
- Cover each strategy -> header mapping and env-var precedence with
new unit tests in claude.rs.
Refs #2368, #2380
Claude Code injects a dynamic `x-anthropic-billing-header` line at the
start of `system` content. Its rotating `cch=` token was forwarded into
OpenAI Responses `instructions` and Chat system messages, which broke
upstream prefix prompt cache reuse — a stable ~95k-token prefix was
getting re-charged on every request.
Strip only the leading occurrence in both anthropic_to_openai and
anthropic_to_responses; later occurrences are preserved so user-authored
prompt text containing the same string is not lost.
Hermes aggregates all in-process API calls into a single sessions row
with the `model` field locked to the initial model, so the usage
dashboard cannot cleanly surface per-call billing context. Two rounds
of UI workarounds (raw mapping, then `<model> @ <host>` display) did
not resolve the user-facing confusion, so the whole tracking
integration is dropped for now.
Removes session_usage_hermes service (and its 17 tests), sync wiring
in commands/usage.rs and lib.rs, _hermes_session/hermes_session
entries in usage_stats SQL (provider_name_coalesce CASE and
effective_usage_log_filter IN clause), frontend Tab/banner/dropdown/
icon entries, and four i18n keys per locale.
Hermes app integration outside usage tracking (proxy routing,
session manager, config) is preserved. Pre-existing hermes rows in
proxy_request_logs are left as orphans — filtered out by the
updated SQL and never surfaced in the UI.
Zhipu's `data.limits[]` returns 1 entry for legacy plans (subscribed
before 2026-02-12) and 2 entries for current plans. Previously every
TOKENS_LIMIT entry was hardcoded as `five_hour`, so the weekly bucket
was rendered with the 5-hour i18n label.
Sort TOKENS_LIMIT entries by nextResetTime ascending and assign
`five_hour` to index 0, `weekly_limit` to index 1. Legacy plans
naturally degrade to a single five_hour tier.
Also harden the parser: case-insensitive type match (defends against
upstream casing changes), reuse TIER_FIVE_HOUR/TIER_WEEKLY_LIMIT
constants, and add 8 unit tests covering both plan shapes plus
defensive edge cases.
* fix(dashscope): enhance usage parsing robustness to prevent VSCode crashes
Enhanced build_anthropic_usage_from_responses() to handle null, missing, empty,
and partial usage fields gracefully. This prevents VSCode Extension crashes with
"Cannot read properties of null (reading 'output_tokens')" when connecting to
DashScope (Alibaba Cloud Bailian) models.
Changes:
- Added defensive null checks and empty object detection
- Implemented OpenAI field name fallbacks (prompt_tokens/completion_tokens)
- Added comprehensive logging for malformed usage scenarios
- Fixed streaming SSE event handlers with null-safe usage access
- Preserved cache token fields even when input/output tokens are missing
This ensures the proxy never crashes on malformed Responses API usage objects,
returning valid Anthropic-compatible usage structures (input_tokens/output_tokens)
in all cases.
* fix(proxy): tighten Responses API usage fix per review
- Drop redundant fallback in streaming.rs Chat Completions path; the
existing if-let-Some guard already prevents usage:null, so the extra
layer was dead code and caused a fmt-breaking indentation issue.
- Demote partial-usage warn to debug. Streaming chunks legitimately
arrive with partial token counts and the warn-level log was noisy.
- Rewrite CHANGELOG entry: reference #2422, broaden scope from
DashScope-only to all api_format=openai_responses users (Codex OAuth
is the strongest signal; DashScope compatible-mode/v1/responses is
the original report).
- cargo fmt to clear 12 formatting differences vs main.
---------
Co-authored-by: Jason <farion1231@gmail.com>
* fix(config): sort JSON keys alphabetically for deterministic output
Ensures settings.json keys are written in sorted order, preventing
non-deterministic git diffs when switching configs.
* test(config): add unit tests for sort_json_keys and fix formatting
Cover top-level sort, nested recursion, array order preservation,
primitive pass-through, empty collections, and the core determinism
guarantee (different insertion orders must yield identical output).
Also fix line-length in write_json_file flagged by `cargo fmt --check`.
---------
Co-authored-by: Jason <farion1231@gmail.com>