mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-31 11:01:36 +08:00
4a0b5c3dec54093233ce50520e65f7bdad59ed87
31 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6a34253934 |
feat: add Codex OAuth (ChatGPT Plus/Pro) reverse proxy support
Adds a new managed OAuth provider that lets Claude Code route requests through a user's ChatGPT Plus/Pro subscription via the chatgpt.com backend-api/codex endpoint. - CodexOAuthManager: OpenAI Device Code flow with multi-account support, JWT-based account identification, and automatic access_token refresh. - Reuses the generic managed-auth command surface (auth_start_login, auth_poll_for_account, etc.) via provider dispatch in commands/auth.rs. - ClaudeAdapter detects codex_oauth providers, forces the base URL to the ChatGPT backend, pins api_format to openai_responses, and emits Authorization + originator headers; the forwarder injects the dynamic access_token and ChatGPT-Account-Id per request. - transform_responses gains an is_codex_oauth path that aligns the body with OpenAI's codex-rs ResponsesApiRequest contract: sets store:false, appends reasoning.encrypted_content to include, strips max_output_tokens / temperature / top_p, injects default instructions/tools/parallel_tool_calls, and forces stream:true. Covered by 9 new unit tests plus regression guards for the non-Codex path. - Stream check reuses the same transform flag so detection matches the production request shape. - Frontend adds CodexOAuthSection + useCodexOauth hook, integrates it into ClaudeFormFields / ProviderForm / AuthCenterPanel, ships a new "Codex (ChatGPT Plus/Pro)" preset, and adds zh/en/ja i18n strings. |
||
|
|
84998aa217 |
feat: differentiate fetch models error messages by failure type
Distinguish between missing API key, missing endpoint, auth failure, unsupported provider (404/405), and timeout errors instead of showing a generic failure toast for all cases. |
||
|
|
5017002938 |
feat: add auto-fetch models from provider's /v1/models endpoint
Add ability to fetch available models from third-party aggregation providers (SiliconFlow, OpenRouter, etc.) via OpenAI-compatible GET /v1/models endpoint. Users can click "Fetch Models" button in the provider form, then select models from a dropdown on each model input field. - Backend: new model_fetch service + Tauri command (Rust) - Frontend: ModelInputWithFetch shared component - Integrated into all 5 app forms (Claude/Codex/Gemini/OpenCode/OpenClaw) - i18n support for zh/en/ja |
||
|
|
67e074c0a7 |
refactor(proxy): transparent header forwarding via hyper client (#1714)
* style(frontend): reformat provider forms, constants and hooks
Apply prettier formatting across 5 frontend files. No logic changes.
Changed files:
- AddProviderDialog.tsx: reformat generic type annotation and callback
- ClaudeFormFields.tsx: consolidate multi-line useState and Collapsible props
- CodexConfigSections.tsx: expand single-line React imports to multi-line,
collapse removeCodexTopLevelField() call
- constants.ts: merge TemplateType into single line
- useSkills.ts: expand single-line TanStack Query imports to multi-line,
reformat uninstallSkill mutationFn chain
* deps(proxy): add hyper ecosystem crates and manual decompression libs
reqwest internally normalizes all header names to lowercase and does not
preserve insertion order, causing proxied requests to differ from the
original client requests. To achieve transparent header forwarding with
original casing and order, introduce lower-level hyper HTTP client libs.
New dependencies:
- hyper-util 0.1: TokioExecutor + legacy Client with
preserve_header_case support for HTTP/1.1
- hyper-rustls 0.27: rustls-based TLS connector for hyper
- http 1 / http-body 1 / http-body-util 0.1: HTTP type crates for
hyper 1.x request/response construction
- flate2 1: manual gzip/deflate decompression (replaces reqwest auto)
- brotli 7: manual brotli decompression
Changed dependencies:
- serde_json: enable preserve_order feature to keep JSON field order
- reqwest: drop gzip feature to prevent reqwest from overriding the
client's original accept-encoding header
* refactor(proxy): use hyper client for header-case preserving forwarding
Previously the proxy used reqwest for all upstream requests. reqwest
normalizes header names to lowercase and reorders them internally,
making proxied requests distinguishable from direct CLI requests.
Some upstream providers are sensitive to these differences.
This commit replaces reqwest with a hyper-based HTTP client on the
default (non-proxy) path, achieving wire-level header fidelity:
Server layer (server.rs):
- Replace axum::serve with a manual hyper HTTP/1.1 accept loop
- Enable preserve_header_case(true) so incoming header casing is
captured in a HeaderCaseMap extension on each request
- Bridge hyper requests to axum Router via tower::Service
New hyper client module (hyper_client.rs):
- Lazy-initialized hyper-util Client with preserve_header_case
- ProxyResponse enum wrapping both hyper::Response and reqwest::Response
behind a unified interface (status, headers, bytes, bytes_stream)
- send_request() builds requests with ordered HeaderMap + case map
Request handlers (handlers.rs):
- Switch from (HeaderMap, Json<Value>) extractors to raw
axum::extract::Request to preserve Extensions (containing the
HeaderCaseMap from the accept loop)
- Pass extensions through the forwarding chain
Forwarder (forwarder.rs):
- Remove HEADER_BLACKLIST array; replace with ordered header iteration
that preserves original header sequence and casing
- Build ordered_headers by iterating client headers, skipping only
auth/host/content-length, and inserting auth headers at the original
authorization position to maintain order
- Handle anthropic-beta (ensure claude-code-20250219 tag) and
anthropic-version (passthrough or default) inline during iteration
- Remove should_force_identity_encoding() — accept-encoding is now
transparently forwarded to upstream
- Use hyper client by default; fall back to reqwest only when an
HTTP/SOCKS5 proxy tunnel is configured
Provider adapters (adapter.rs, claude.rs, codex.rs, gemini.rs):
- Replace add_auth_headers(RequestBuilder) -> RequestBuilder with
get_auth_headers(AuthInfo) -> Vec<(HeaderName, HeaderValue)>
- Adapters now return header pairs instead of mutating a reqwest builder
- Claude adapter: merge Anthropic/ClaudeAuth/Bearer into single branch;
move Copilot fingerprint headers into get_auth_headers
Response processing (response_processor.rs):
- Add manual decompression (gzip/deflate/brotli via flate2 + brotli)
for non-streaming responses, since reqwest auto-decompression is now
disabled to allow accept-encoding passthrough
- Add compressed-SSE warning log for streaming responses
- Accept ProxyResponse instead of reqwest::Response
HTTP client (http_client.rs):
- Disable reqwest auto-decompression (.no_gzip/.no_brotli/.no_deflate)
on both global and per-provider clients
Streaming adapters (streaming.rs, streaming_responses.rs):
- Generalize stream error type from reqwest::Error to generic E: Error
Misc:
- log_codes.rs: add SRV-005 (ACCEPT_ERR) and SRV-006 (CONN_ERR)
- stream_check.rs: reformat copilot header lines
- transform.rs: fix trailing whitespace alignment
* fix(lint): resolve 35 clippy warnings across Rust codebase
Fix all clippy warnings reported by `cargo clippy --lib`:
- codex_config.rs: fix doc_overindented_list_items (3 spaces -> 2)
- commands/copilot.rs: inline format args in 2 log::error! calls
- commands/provider.rs: inline format args in 3 map_err closures
- proxy/hyper_client.rs: inline format arg in log::debug! call
- proxy/providers/copilot_auth.rs: inline format args in 16 locations
(log macros, format! in headers, error constructors)
- proxy/thinking_optimizer.rs: inline format args in 2 log::info! calls
- services/skill.rs: inline format args in log::debug! call
- services/webdav_sync.rs: inline format args in 6 format! calls
(version compat messages, download limit messages)
- services/webdav_sync/archive.rs: inline format args in 2 format! calls
- session_manager/providers/opencode.rs: inline format args in
source_path format!
All fixes use the clippy::uninlined_format_args suggestion pattern:
format!("msg: {}", var) -> format!("msg: {var}")
* deps(proxy): add raw HTTP write and native TLS cert dependencies
Add crates required for the raw TCP/TLS write path that bypasses
hyper's header encoder to preserve original header name casing:
- httparse: parse raw TCP peek bytes to capture header casings
- tokio-rustls + rustls: direct TLS connections for raw write path
- webpki-roots: Mozilla CA bundle baseline
- rustls-native-certs: load system keychain CAs (trusts proxy MITM
certificates from Clash, mitmproxy, etc.)
* fix(proxy): address code review feedback on response handling
Fixes from PR #1714 code review:
- Extract `read_decoded_body()` and `strip_entity_headers_for_rebuilt_body()`
in response_processor to properly clean content-encoding/content-length
headers after decompression
- Reuse `read_decoded_body()` in handlers.rs for Claude transform path,
ensuring compressed responses are decoded before format conversion
- Make `build_proxy_url_from_config()` public so forwarder can pass proxy
URL to the hyper raw write path
- Add `has_system_proxy_env()` utility with test coverage
- Add 50ms backoff after accept() failures in server.rs to prevent
tight-loop CPU spin on transient socket errors
* feat(proxy): implement raw TCP/TLS write with HTTP CONNECT tunnel
Rewrite hyper_client with a two-tier strategy for header case preservation:
Primary path (raw write):
- Peek raw TCP bytes in server.rs to capture OriginalHeaderCases before
hyper lowercases them
- Build raw HTTP/1.1 request bytes with exact original header name casing
- Write directly to TLS stream, then use WriteFilter to let hyper parse
the response while discarding its duplicate request writes
- Support HTTP CONNECT tunneling through upstream proxies, so header case
is preserved even when a proxy (Clash, V2Ray) is configured
Fallback path (hyper-util Client):
- Used when OriginalHeaderCases is empty or raw write fails
- Configured with title_case_headers(true) for best-effort casing
TLS improvements:
- Load native system certificates alongside webpki roots so proxy MITM
CAs (installed in system keychain) are trusted through CONNECT tunnels
Key types added:
- OriginalHeaderCases: maps lowercase name → original wire-casing bytes
- WriteFilter<S>: AsyncRead+AsyncWrite wrapper that discards writes
- connect_via_proxy(): HTTP CONNECT tunnel establishment
- ExtensionDebugMarker: diagnostic marker for extension chain debugging
* refactor(proxy): route requests through hyper with proxy-aware forwarding
Rework forwarder request dispatch to always prefer the hyper raw write
path (header case preservation) over reqwest:
Request routing:
- HTTP/HTTPS proxy: hyper raw write through CONNECT tunnel (case preserved)
- SOCKS5 proxy: reqwest fallback (CONNECT not supported for SOCKS5)
- No proxy: hyper raw write direct connection
Header handling improvements:
- Replace host header in-place at original position instead of
skip-and-append, preserving client's header ordering
- Preserve client's original accept-encoding for transparent passthrough;
only force identity encoding when transform path needs decompression
- Add should_force_identity_encoding() to centralize the decision
- Remove hardcoded 'br, gzip, deflate' override that masked client values
Proxy URL resolution (priority order):
1. Provider-specific proxy config (if enabled)
2. Global proxy URL configured in CC Switch
3. Direct connection (no proxy)
* chore(proxy): remove dead code, redundant tests and debug scaffolding
- Inline should_force_identity_encoding() (was just `needs_transform`)
and delete its 5 test cases
- Remove ExtensionDebugMarker diagnostic type
- Remove unused has_system_proxy_env() and its test
- Remove strip_entity_headers test
- Simplify hyper path: remove redundant is_socks_proxy ternary
- Update hyper_client module doc to reflect CONNECT tunnel support
* fix(proxy): block direct-connect fallback and complete CONNECT tunnel support
* feat(hooks): improve proxy requirement warnings with specific reasons
- Remove redundant OpenAI format hint toast messages
- Add detailed reason detection for proxy requirements (OpenAI Chat, OpenAI Responses, full URL mode)
- Update i18n files with new reason-specific keys
* style(*): format code with prettier
- Remove extra whitespace in http_client.rs
- Fix formatting issues in useProviderActions.ts
* fix(proxy): post-merge fixes for forward return type and clippy warnings
- Restore forward() return type to (ProxyResponse, Option<String>)
to pass claude_api_format through to callers
- Inline format args in log::warn! macro (clippy::uninlined_format_args)
- Suppress too_many_arguments for check_claude_stream
* refactor(proxy): preserve original header wire order and add non-streaming body timeout
- Rewrite build_raw_request to emit headers in original
client-sent sequence instead of hash-map order
- Remove unused OriginalHeaderCases::get_all method
- Add body_timeout to read_decoded_body to prevent
requests hanging when upstream stalls after headers
|
||
|
|
8cae7b7b73 |
feat(proxy): add full URL mode and refactor endpoint rewriting (#1561)
* feat(proxy): add full URL mode and refactor endpoint rewriting - Add `isFullUrl` provider meta to treat base_url as complete API endpoint - Remove hardcoded `?beta=true` from Claude adapter, pass through from client - Refactor forwarder endpoint rewriting with proper query string handling - Block provider switching when proxy is required but not running - Add full URL toggle UI in endpoint field with i18n (zh/en/ja) * refactor(proxy): remove beta query handling * fix(proxy): strip beta query when rewriting Claude endpoints * feat(codex): complete full URL support * refactor(ui): refine full URL endpoint hint |
||
|
|
8ccfbd36d6 |
feat(copilot): add GitHub Copilot reverse proxy support (#930)
* refactor(toolsearch): replace binary patch with ENABLE_TOOL_SEARCH env var toggle
- Remove toolsearch_patch.rs binary patching mechanism (~590 lines)
- Delete `toolsearch_patch.rs` and `commands/toolsearch.rs`
- Remove auto-patch startup logic and command registration from lib.rs
- Remove `tool_search_bypass` field from settings.rs
- Remove frontend settings ToggleRow, useSettings hook sync logic, and API methods
- Clean up zh/en/ja i18n keys (notifications + settings)
- Add ENABLE_TOOL_SEARCH toggle to Claude provider form
- Add checkbox in CommonConfigEditor.tsx (alongside teammates toggle)
- When enabled, writes `"env": { "ENABLE_TOOL_SEARCH": "true" }`
- When disabled, removes the key; takes effect on provider switch
- Add zh/en/ja i18n key: `claudeConfig.enableToolSearch`
Claude Code 2.1.76+ natively supports this env var, eliminating the need for binary patching.
* feat(claude): add effortLevel high toggle to provider form
- Add "high-effort thinking" checkbox to Claude provider config form
- When checked, writes `"effortLevel": "high"`; when unchecked, removes the field
- Add zh/en/ja i18n translations
* refactor(claude): remove deprecated alwaysThinking toggle
- Claude Code now enables extended thinking by default; alwaysThinkingEnabled is a no-op
- Thinking control is now handled via effortLevel (added in prior commit)
- Remove state, switch case, and checkbox UI from CommonConfigEditor
- Clean up alwaysThinking i18n keys across zh/en/ja locales
* feat(opencode): add setCacheKey: true to all provider presets
- Add setCacheKey: true to options in all 33 regular presets
- Add setCacheKey: true to OPENCODE_DEFAULT_CONFIG for custom providers
- Exclude 2 OMO presets (Oh My OpenCode / Slim) which have their own config mechanism
Closes #1523
* fix(codex): resolve 1M context window toggle causing MCP editor flicker
- Add localValueRef to short-circuit duplicate CodeMirror updateListener callbacks,
breaking the React state → CodeMirror → stale onChange → React state feedback loop
- Use localValueRef.current in handleContextWindowToggle and handleCompactLimitChange
to avoid stale closure reads
- Change compact limit input from type="number" to type="text" with inputMode="numeric"
to remove unnecessary spinner buttons
* feat(codex): add 1M context window toggle utilities and i18n keys
- Add extractCodexTopLevelInt, setCodexTopLevelInt, removeCodexTopLevelField
TOML helpers in providerConfigUtils.ts
- Add i18n keys for contextWindow1M, autoCompactLimit in zh/en/ja locales
* feat(claude): collapse model mapping fields by default
- Wrap 5 model mapping inputs in a Collapsible, collapsed by default
- Auto-expand when any model value is present (including preset-filled)
- Show hint text when collapsed explaining most users need no config
- Add zh/en/ja i18n keys for toggle label and collapsed hint
- Use variant={null} to avoid ghost button hover style clash in dark mode
* feat(claude): merge advanced fields into single collapsible section
- Merge API format, auth field, and model mapping into a unified "Advanced Options" collapsible
- Extend smart-expand logic to detect non-default values across all advanced fields
- Preserve model mapping sub-header and hint with a separator line
- Update zh/en/ja i18n keys (advancedOptionsToggle, advancedOptionsHint, modelMappingLabel, modelMappingHint)
* feat(copilot): add GitHub Copilot reverse proxy support
Add GitHub Copilot as a Claude provider variant with OAuth device code
authentication and Anthropic ↔ OpenAI format transformation.
Backend:
- Add CopilotAuthManager for GitHub OAuth device code flow
- Implement Copilot token auto-refresh (60s before expiry)
- Persist GitHub token to ~/.cc-switch/copilot_auth.json
- Add ProviderType::GitHubCopilot and AuthStrategy::GitHubCopilot
- Modify forwarder to use /chat/completions for Copilot
- Add Copilot-specific headers (Editor-Version, Editor-Plugin-Version)
Frontend:
- Add CopilotAuthSection component for OAuth UI
- Add useCopilotAuth hook for OAuth state management
- Auto-copy user code to clipboard and open browser
- Use 8-second polling interval to avoid GitHub rate limits
- Skip API Key validation for Copilot providers
- Add GitHub Copilot preset with claude-sonnet-4 model
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* fix(copilot): remove is_expired() calls from tests
Remove references to deleted is_expired() method in test code.
Only is_expiring_soon() is needed for token refresh logic.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* feat(copilot): add real-time model listing from Copilot API
- Add fetch_models() to CopilotAuthManager calling GET /models endpoint
- Add copilot_get_models Tauri command
- Add copilotGetModels() frontend API wrapper
- Modify ClaudeFormFields to show model dropdown for Copilot providers
- Fetches available models on component mount when isCopilotPreset
- Groups models by vendor (Anthropic, OpenAI, Google, etc.)
- Input + dropdown button combo allows both manual entry and selection
- Non-Copilot providers keep original plain Input behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): add usage query integration
- Add Copilot usage API integration (fetch_usage method)
- Add copilot_get_usage Tauri command
- Add GitHub Copilot template in usage query modal
- Unify naming: copilot → github_copilot
- Add constants management (TEMPLATE_TYPES, PROVIDER_TYPES)
- Improve error handling with detailed error messages
- Add database migration (v5 → v6) for template type update
- Add i18n translations (zh, en, ja)
- Improve type safety with TemplateType
- Apply code formatting (cargo fmt, prettier)
* 修复github 登录和注销问题 ,模型选择问题
* feat(copilot): add multi-account support for GitHub Copilot
- Add multi-account storage structure with v1 to v2 migration
- Add per-account token caching and auto-refresh
- Add new Tauri commands for account management
- Integrate account selection in Proxy forwarder
- Add account selection UI in CopilotAuthSection
- Save githubAccountId to ProviderMeta
- Add i18n translations for multi-account features (zh/en/ja)
* 修复用量查询Reset字段出现多余字符
* refactor(auth-binding): introduce generic provider auth binding primitives
- add shared authBinding types in Rust and TypeScript while keeping githubAccountId as a compatibility field\n- resolve Copilot token, models, and usage through provider-bound account lookup instead of only the implicit default account\n- fix the Unix build regression in settings.rs by restoring std::io::Write for write_all()\n- remove the accidental .github ignore entry and drop leftover Copilot form debug logs\n- keep the first migration step non-breaking by writing both authBinding and the legacy githubAccountId field from the form
* refactor(auth-service): add managed auth command surface and explicit default account state
- introduce generic managed auth commands and frontend auth API wrappers for provider-scoped login, status, account listing, removal, logout, and default-account selection\n- store an explicit Copilot default_account_id instead of relying on HashMap iteration order, and use it consistently for fallback token/model/usage resolution\n- sort managed accounts deterministically and surface default-account state to the UI\n- refactor the Copilot form hook to wrap a generic useManagedAuth implementation while preserving the existing component contract\n- add default-account controls to the Copilot auth section and extend Copilot auth status serialization/tests for the new state
* feat(auth-center): add a dedicated settings entrypoint for managed OAuth accounts
- add an Auth Center tab to Settings so managed OAuth accounts are no longer hidden inside individual provider forms\n- introduce a first AuthCenterPanel that hosts GitHub Copilot account management as the initial managed auth provider\n- keep the provider form experience intact while establishing a global account-management surface for future providers such as OpenAI\n- validate that the new settings tab works cleanly with the generic managed auth hook and existing Copilot account controls
* feat(add-provider): expose managed OAuth sources alongside universal providers
- add an OAuth tab to the Add Provider flow so managed auth sources sit beside app-specific and universal providers\n- reuse the new Auth Center panel inside the dialog, keeping account management discoverable during provider creation\n- make the dialog footer adapt to the OAuth tab so account setup does not pretend to create a provider directly\n- align the add-provider UX with the new architecture where OAuth accounts are global assets and providers bind to them later
* fix(auth-reliability): harden managed auth persistence and refresh behavior
- replace direct Copilot auth store writes with private temp-file writes and atomic rename semantics, and document the local token storage limitation\n- add per-account refresh locks plus a double-check path so concurrent requests do not stampede GitHub token refresh\n- surface legacy migration failures through auth status, expose them in the UI, and add translated copy for the new account-state labels\n- stop writing the legacy githubAccountId field from the provider form while keeping compatibility reads in place\n- add logout error recovery and Copilot model-load toasts so auth failures are no longer silently swallowed
* refactor(copilot-detection): prefer provider type before URL fallbacks
- update forwarder endpoint rewriting to treat providerType as the primary GitHub Copilot signal\n- keep githubcopilot.com string matching only as a compatibility fallback for older provider records without providerType\n- reduce one more path where Copilot behavior depended purely on URL heuristics
* fix(copilot-auth): add cancel button to error state in CopilotAuthSection
- 错误状态下仅有"重试"按钮,用户无法退出(如不可恢复的 403 未订阅错误)
- 新增"取消"按钮,复用已有的 cancelAuth 逻辑重置为 idle 状态
* 修复打包后github账号头像显示异常
* 修复github copilot 来源的模型测试报错
* feat(copilot-preset): add default model presets for GitHub Copilot
- 补充 Copilot 预设的默认模型配置,用户选完预设即可直接使用
- ANTHROPIC_MODEL: claude-opus-4.6
- ANTHROPIC_DEFAULT_HAIKU_MODEL: claude-haiku-4.5
- ANTHROPIC_DEFAULT_SONNET_MODEL: claude-sonnet-4.6
- ANTHROPIC_DEFAULT_OPUS_MODEL: claude-opus-4.6
---------
Co-authored-by: Jason <farion1231@gmail.com>
Co-authored-by: 周梦泽 <mengze.zhou@dafeng-tech.com>
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
|
||
|
|
dd971246be | feat: restore Claude provider auth field selector (AUTH_TOKEN / API_KEY) | ||
|
|
a30e2096bb |
feat: add OpenAI Responses API format conversion (api_format = "openai_responses")
Support Anthropic ↔ OpenAI Responses API format conversion alongside existing Chat Completions conversion. The Responses API uses a flat input/output structure with lifted function_call/function_call_output items and named SSE lifecycle events. |
||
|
|
859f413756 |
revert: restore full config overwrite + Common Config Snippet (revert 992dda5c)
Revert the partial key-field merging refactoring introduced in |
||
|
|
8ea9638b9d |
feat: Add AWS Bedrock Provider Support (AKSK & API Key) (#1047)
* Add AWS Bedrock provider integration design document Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add AWS Bedrock provider implementation plan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update implementation plan: add OpenCode Bedrock support Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add cloud_provider category to ProviderCategory type Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add AWS Bedrock (AKSK) Claude Code provider preset with tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add AWS Bedrock (API Key) Claude Code provider preset with tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add AWS Bedrock OpenCode provider preset with @ai-sdk/amazon-bedrock Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add AWS Bedrock provider feature summary for PR Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove internal planning documents Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * docs: add AWS Bedrock support to README (EN/ZH/JA) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add AWS Bedrock UI merge design document Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Add AWS Bedrock UI merge implementation plan Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: skip optional template values in validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: support isSecret template fields and hide base URL for Bedrock Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add Bedrock validation, cleanup, and isBedrock prop in ProviderForm Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: extend TemplateValueConfig and merge Bedrock presets Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: mask Bedrock API Key as secret and support GovCloud regions - Add isSecret: true to BEDROCK_API_KEY template value - Update region regex to support multi-segment regions (us-gov-west-1) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: replace AWS icon with updated logo Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: replace AWS icon with updated logo Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * style: replace AWS icon with new PNG image Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address code review findings - Fix AWS icon: use SVG with embedded <image> instead of raw <img> tag - Hide duplicate ApiKeySection for Bedrock (auth via template fields only) - Guard settingsConfig cleanup against unresolved template placeholders Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove planning documents Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: address PR review - split Bedrock into two presets, restore SVG icon Based on maintainer review feedback on PR #1047: 1. Split merged "AWS Bedrock" back into two separate presets: - "AWS Bedrock (AKSK)": uses AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY - "AWS Bedrock (API Key)": uses top-level apiKey field via standard UI input 2. Restore aws.svg to pure vector SVG (was PNG-in-SVG) 3. Remove all Bedrock-specific logic from shared components: - Remove isBedrock prop from ClaudeFormFields - Remove Bedrock validation/cleanup blocks from ProviderForm - Remove optional/isSecret from TemplateValueConfig - Remove optional skip from useTemplateValues 4. Add cloud_provider category handling: - Skip API Key/Base URL required validation - Hide Speed Test and Base URL for cloud_provider - Hide API format selector for cloud_provider (always Anthropic) - Show API Key input only when config has apiKey field 5. Fix providerConfigUtils to support top-level apiKey: - getApiKeyFromConfig: check config.apiKey before env fields - setApiKeyInConfig: write to config.apiKey when present - hasApiKeyField: detect top-level apiKey property 6. Add OpenClaw Bedrock preset (bedrock-converse-stream protocol) 7. Update model IDs: - Sonnet: global.anthropic.claude-sonnet-4-6 - Opus: global.anthropic.claude-opus-4-6-v1 - Haiku: global.anthropic.claude-haiku-4-5-20251001-v1:0 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(test): align Bedrock API Key test assertions with preset implementation The API Key preset was refactored to use standard UI input (apiKey: "") instead of template variables, but the tests were not updated accordingly. --------- Co-authored-by: root <root@ip-10-0-11-189.ap-northeast-1.compute.internal> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Jason <farion1231@gmail.com> |
||
|
|
992dda5c5c |
refactor(provider): switch from full config overwrite to partial key-field merging (#1098)
* refactor(provider): switch from full config overwrite to partial key-field merging Replace the provider switching mechanism for Claude/Codex/Gemini from full settings_config overwrite to partial key-field replacement, preserving user's non-provider settings (plugins, MCP, permissions, etc.) across switches. - Add write_live_partial() with per-app implementations for Claude (JSON env merge), Codex (auth replace + TOML partial merge), and Gemini (env merge) - Add backfill_key_fields() to extract only provider-specific fields when saving live config back to provider entries - Update switch_normal, sync_current_to_live, add, update to use partial merge - Remove common config snippet feature for Claude/Codex/Gemini (no longer needed with partial merging); preserve OMO common config - Delete 6 frontend files (3 components + 3 hooks), clean up 11 modified files - Remove backend extract_common_config_* methods, 3 Tauri commands, CommonConfigSnippets struct, and related migration code - Update integration tests to validate key-field-only backfill behavior * refactor(cleanup): remove dead code and redundant MCP sync after partial-merge refactor - Remove ConfigService legacy full-overwrite sync methods (~150 lines) - Remove redundant McpService::sync_all_enabled from switch_normal - Switch proxy fallback recovery from write_live_snapshot to write_live_partial - Remove dead ProviderService::write_gemini_live wrapper - Update tests to reflect partial-merge behavior (MCP preserved, not re-synced) * feat(claude): add Quick Toggles for common Claude Code preferences Add checkbox toggles for hideAttribution, alwaysThinking, and enableTeammates that write directly to the live settings file via RFC 7396 JSON Merge Patch. Mirror changes to the form editor using form.watch for reactive updates. * fix(provider): add missing key fields to partial-merge constants Add provider-specific fields verified against official docs to prevent key residue or loss during provider switching: - Claude: CLAUDE_CODE_SUBAGENT_MODEL (env), model (top-level) - Codex: review_model, plan_mode_reasoning_effort - Gemini: GOOGLE_API_KEY (official alternative to GEMINI_API_KEY) * fix(provider): expand partial-merge key fields for Bedrock, Vertex, Foundry and behavior settings Add missing env/top-level fields to CLAUDE_KEY_ENV_FIELDS and CLAUDE_KEY_TOP_LEVEL so that provider switching correctly replaces (and clears) credentials and flags for AWS Bedrock, Google Vertex AI, Microsoft Foundry, and provider behavior overrides like max output tokens and prompt caching. * feat(provider): add auth field selector for Claude providers (AUTH_TOKEN / API_KEY) Allow users to choose between ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY when creating or editing custom Claude providers, persisted in meta.apiKeyField. * refactor(preset): remove AiHubMix hardcoded API_KEY in favor of generic auth selector AiHubMix was the only preset that hardcoded ANTHROPIC_API_KEY before the generic auth field selector was introduced. Now that users can freely choose between AUTH_TOKEN and API_KEY via the UI, remove the special-case and default AiHubMix to the standard ANTHROPIC_AUTH_TOKEN. |
||
|
|
809a1fcf84 |
feat(ui): dynamic endpoint hint based on API format selection (#860)
- Add apiHintOAI i18n key for OpenAI Chat Completions format hint - Update ClaudeFormFields to show format-specific endpoint hints - When API format is "openai_chat", show OAI-specific hint - Maintains consistency between hint and selected API format Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
81b975c47c |
feat(claude): add API format selector for third-party providers
Replace the OpenRouter-specific compatibility toggle with a generic
API format selector that allows all Claude providers to choose between:
- Anthropic Messages (native): Direct passthrough, no conversion
- OpenAI Chat Completions: Enables Anthropic ↔ OpenAI format conversion
Changes:
- Add ClaudeApiFormat type ("anthropic" | "openai_chat") to types.ts
- Replace openRouterCompatToggle with apiFormat dropdown in ClaudeFormFields
- Update ProviderForm to manage apiFormat state via settingsConfig.api_format
- Refactor claude.rs: add get_api_format() method, update needs_transform()
- Maintain backward compatibility with legacy openrouter_compat_mode field
- Update i18n translations (zh, en, ja)
|
||
|
|
99c910e58e |
fix(provider): persist endpoint auto-select state (#611)
- Add endpointAutoSelect field to ProviderMeta for persistence - Lift autoSelect state from EndpointSpeedTest to ProviderForm - Save auto-select preference when provider is saved - Restore preference when editing existing provider Fixes https://github.com/farion1231/cc-switch/issues/589 |
||
|
|
2105f2d05b | fix(i18n): remove hardcoded defaultValue and unused placeholder for reasoning model | ||
|
|
e6f18ba801 |
Feat/usage model extraction (#455)
* feat(proxy): extract model name from API response for accurate usage tracking - Add model field extraction in TokenUsage parsing for Claude, OpenAI, and Codex - Prioritize response model over request model in usage logging - Update model extractors to use parsed usage.model first - Add tests for model extraction in stream and non-stream responses * feat(proxy): implement streaming timeout control with validation - Add first byte timeout (0 or 1-180s) for streaming requests - Add idle timeout (0 or 60-600s) for streaming data gaps - Add non-streaming timeout (0 or 60-1800s) for total request - Implement timeout logic in response processor - Add 1800s global timeout fallback when disabled - Add database schema migration for timeout fields - Add i18n translations for timeout settings * feat(proxy): add model mapping module for provider-based model substitution - Add model_mapper.rs with ModelMapping struct to extract model configs from Provider - Support ANTHROPIC_MODEL, ANTHROPIC_REASONING_MODEL, and default models for haiku/sonnet/opus - Implement thinking mode detection for reasoning model priority - Include comprehensive unit tests for all mapping scenarios * fix(proxy): bypass circuit breaker for single provider scenario When failover is disabled (single provider), circuit breaker open state would block all requests causing poor UX. Now bypasses circuit breaker check in this scenario. Also integrates model mapping into request flow. * feat(ui): add reasoning model field to Claude provider form Add ANTHROPIC_REASONING_MODEL configuration field for Claude providers, allowing users to specify a dedicated model for thinking/reasoning tasks. * feat(proxy): add openrouter_compat_mode for optional format conversion Add configurable OpenRouter compatibility mode that enables Anthropic to OpenAI format conversion. When enabled, rewrites endpoint to /v1/chat/completions and transforms request/response formats. Defaults to enabled for OpenRouter. * feat(ui): add OpenRouter compatibility mode toggle Add UI toggle for OpenRouter providers to enable/disable compatibility mode which uses OpenAI Chat Completions format with SSE conversion. * feat(stream-check): use provider-configured model for health checks Extract model from provider's settings_config (ANTHROPIC_MODEL, GEMINI_MODEL, or Codex config.toml) instead of always using default test models. * refactor(ui): remove timeout settings from AutoFailoverConfigPanel Remove streaming/non-streaming timeout configuration from failover panel as these settings have been moved to a dedicated location. * refactor(database): migrate proxy_config to per-app three-row structure Replace singleton proxy_config table with app_type primary key structure, allowing independent proxy settings for Claude, Codex, and Gemini. Add GlobalProxyConfig queries and per-app config management in DAO layer. * feat(proxy): add GlobalProxyConfig and AppProxyConfig types Add new type definitions for the refactored proxy configuration: - GlobalProxyConfig: shared settings (enabled, address, port, logging) - AppProxyConfig: per-app settings (failover, timeouts, circuit breaker) * refactor(proxy): update service layer for per-app config structure Adapt proxy service, handler context, and provider router to use the new per-app configuration model. Read enabled/timeout settings from proxy_config table instead of settings table. * feat(commands): add global and per-app proxy config commands Add new Tauri commands for the refactored proxy configuration: - get_global_proxy_config / update_global_proxy_config - get_proxy_config_for_app / update_proxy_config_for_app Update startup restore logic to read from proxy_config table. * feat(api): add frontend API and Query hooks for proxy config Add TypeScript wrappers and TanStack Query hooks for: - Global proxy config (address, port, logging) - Per-app proxy config (failover, timeouts, circuit breaker) - Proxy takeover status management * refactor(ui): redesign proxy panel with inline config controls Replace ProxySettingsDialog with inline controls in ProxyPanel. Add per-app takeover switches and global address/port settings. Simplify AutoFailoverConfigPanel by removing timeout settings. * feat(i18n): add proxy takeover translations and update types Add i18n strings for proxy takeover status in zh/en/ja. Update TypeScript types for GlobalProxyConfig and AppProxyConfig. * refactor(proxy): load circuit breaker config per-app instead of globally Extract app_type from router key and read circuit breaker settings from the corresponding proxy_config row for each application. |
||
|
|
346f916048 |
refactor(endpoint): separate edit and create mode endpoint management (#192)
Optimize custom endpoint management logic to distinguish between edit and create modes: - Edit mode: endpoints are read/written directly to backend via API - Create mode: use draftCustomEndpoints to stage, save on submit - Remove duplicate endpoint loading in useSpeedTestEndpoints - Add isSaving state and initialCustomUrls tracking |
||
|
|
34b8aa1008 |
fix(ui): remove misleading model placeholders from input fields
Clear placeholder values for model input fields to avoid suggesting specific model names that may not be applicable to all providers. This prevents user confusion when configuring different Claude providers. |
||
|
|
5f78e58ffc |
feat: add partner promotion feature for Zhipu GLM
- Add isPartner and partnerPromotionKey fields to Provider and ProviderPreset types - Display gold star badge on partner presets in selector - Show promotional message in API Key section for partners - Configure Zhipu GLM as official partner with 10% discount promotion - Support both Claude and Codex provider presets - Add i18n support for partner promotion messages (zh/en) |
||
|
|
0778347f84 |
refactor(endpoints): implement deferred submission and fix clear-all bug
Implement Solution A (complete deferred submission) for custom endpoint
management, replacing the dual-mode system with unified local staging.
Changes:
- Remove immediate backend saves from EndpointSpeedTest
* handleAddEndpoint: local state update only
* handleRemoveEndpoint: local state update only
* handleSelect: remove lastUsed timestamp update
- Add explicit clear detection in ProviderForm
* Distinguish "user cleared endpoints" from "user didn't modify"
* Pass empty object {} as clear signal vs null for no-change
- Fix mergeProviderMeta to handle three distinct cases:
* null/undefined: don't modify endpoints (no meta sent)
* empty object {}: explicitly clear endpoints (send empty meta)
* with data: add/update endpoints (overwrite)
Fixed Critical Bug:
When users deleted all custom endpoints, changes were not saved because:
- draftCustomEndpoints=[] resulted in customEndpointsToSave=null
- mergeProviderMeta(meta, null) returned undefined
- Backend interpreted missing meta as "don't modify", preserving old values
Solution:
Detect when user had endpoints and cleared them (hadEndpoints && length===0),
then pass empty object to mergeProviderMeta as explicit clear signal.
Architecture Improvements:
- Transaction atomicity: all fields submitted together on form save
- UX consistency: add/edit modes behave identically
- Cancel button: true rollback with no immediate saves
- Code simplification: removed ~40 lines of immediate save error handling
Testing:
- TypeScript type check: passed
- Rust backend tests: 10/10 passed
- Build: successful
|
||
|
|
85334d8dce |
refine(usage): enhance query robustness and error handling
Backend improvements:
- Add InvalidHttpMethod error enum for better error semantics
- Clamp HTTP timeout to 2-30s to prevent config abuse
- Strict HTTP method validation instead of silent fallback to GET
Frontend improvements:
- Add i18n support for usage query errors (en/zh)
- Improve error handling with type-safe unknown instead of any
- Optimize i18n import (direct import instead of dynamic)
- Disable auto-retry for usage queries to avoid API stampede
Additional changes:
- Apply prettier formatting to affected files
Files changed:
- src-tauri/src/error.rs (+2)
- src-tauri/src/usage_script.rs (+8 -2)
- src/i18n/locales/{en,zh}.json (+4 -1 each)
- src/lib/api/usage.ts (+21 -4)
- src/lib/query/queries.ts (+1)
- style: prettier formatting on 6 other files
|
||
|
|
b4f10d8316 |
refine(ui): improve model placeholders and simplify provider hints
- Add dedicated Haiku model placeholder "GLM-4.5-Air" - Unify API key hints for all non-official providers - Fix AiHubMix category from cn_official to aggregator - Standardize GLM model name format (glm-4.6) |
||
|
|
cb83089866 |
refactor(config): rename providerPresets to claudeProviderPresets
- Rename src/config/providerPresets.ts to claudeProviderPresets.ts - Update all import statements across 11 files to reflect the new name - Establish symmetrical naming convention with codexProviderPresets.ts - Improve code clarity and maintainability |
||
|
|
ebb7106102 |
refactor(ui): remove redundant KimiModelSelector and unify model configuration
Remove KimiModelSelector component and useKimiModelSelector hook to eliminate code duplication and unify model configuration across all Claude-compatible providers. **Problem Statement:** Previously, we maintained two separate implementations for the same functionality: - KimiModelSelector: API-driven dropdown with 211 lines of code - ClaudeFormFields: Simple text inputs for model configuration After removing API fetching logic from KimiModelSelector, both components became functionally identical (4 text inputs), violating DRY principle and creating unnecessary maintenance burden. **Changes:** Backend (Rust): - No changes (model normalization logic already in place) Frontend (React): - Delete KimiModelSelector.tsx (-211 lines) - Delete useKimiModelSelector.ts (-142 lines) - Update ClaudeFormFields.tsx: remove Kimi-specific props (-35 lines) - Update ProviderForm.tsx: unify display logic (-31 lines) - Clean up hooks/index.ts: remove useKimiModelSelector export (-1 line) Configuration: - Update Kimi preset: kimi-k2-turbo-preview → kimi-k2-0905-preview * Uses official September 2025 release * 256K context window (vs 128K in older version) Internationalization: - Remove kimiSelector.* i18n keys (15 keys × 2 languages = -36 lines) - Remove providerForm.kimiApiKeyHint **Unified Architecture:** Before (complex branching): ProviderForm ├─ if Kimi → useKimiModelSelector → KimiModelSelector (4 inputs) └─ else → useModelState → ClaudeFormFields inline (4 inputs) After (single path): ProviderForm └─ useModelState → ClaudeFormFields (4 inputs for all providers) Display logic simplified: - Old: shouldShowModelSelector = category !== "official" && !shouldShowKimiSelector - New: shouldShowModelSelector = category !== "official" **Impact:** Code Quality: - Remove 457 lines of redundant code (-98.5%) - Eliminate dual-track maintenance - Improve code consistency - Pass TypeScript type checking with zero errors - Zero remaining references to deleted code User Experience: - Consistent UI across all providers (including Kimi) - Same model configuration workflow for everyone - No functional changes from user perspective Architecture: - Single source of truth for model configuration - Easier to extend for future providers - Reduced bundle size (removed lucide-react icons dependency) **Testing:** - ✅ TypeScript compilation passes - ✅ No dangling references - ✅ All model configuration fields functional - ✅ Display logic works for official/cn_official/aggregator categories **Migration Notes:** - Existing Kimi users: configurations automatically upgraded to new model name - No manual intervention required - Backend normalization ensures backward compatibility |
||
|
|
4811aa2dcd |
refactor(models): migrate to granular model configuration architecture
Upgrade Claude model configuration from dual-key to quad-key system for better model tier differentiation. **Breaking Changes:** - Replace `ANTHROPIC_SMALL_FAST_MODEL` with three granular keys: - `ANTHROPIC_DEFAULT_HAIKU_MODEL` - `ANTHROPIC_DEFAULT_SONNET_MODEL` - `ANTHROPIC_DEFAULT_OPUS_MODEL` **Backend (Rust):** - Add `normalize_claude_models_in_value()` for automatic migration - Implement fallback chain: `DEFAULT_* || SMALL_FAST || MODEL` - Auto-cleanup: remove legacy `SMALL_FAST` key after normalization - Apply normalization across 6 critical paths: - Add/update provider - Read from live config - Write to live config - Refresh config snapshot **Frontend (React):** - Expand UI from 2 to 4 model input fields - Implement smart fallback in `useModelState` hook - Update `useKimiModelSelector` for Kimi model picker - Add i18n keys for Haiku/Sonnet/Opus labels (zh/en) **Configuration:** - Update all 7 provider presets to new format - DeepSeek/Qwen/Moonshot: use same model for all tiers - Zhipu: preserve tier differentiation (glm-4.5-air for Haiku) **Backward Compatibility:** - Old configs auto-upgrade on first read/write - Fallback chain ensures graceful degradation - No manual migration required Closes #[issue-number] |
||
|
|
8e4a0a1bbb |
refactor(types): rename AppType to AppId for semantic clarity
Rename `AppType` to `AppId` across the entire frontend codebase to better reflect its purpose as an application identifier rather than a type category. This aligns frontend naming with backend command parameter conventions. Changes: - Rename type `AppType` to `AppId` in src/lib/api/types.ts - Remove `AppType` export from src/lib/api/index.ts - Update all component props from `appType` to `appId` (43 files) - Update all variable names from `appType` to `appId` - Synchronize documentation (CHANGELOG, refactoring plans) - Update test files and MSW mocks BREAKING CHANGE: `AppType` type is no longer exported. Use `AppId` instead. All component props have been renamed from `appType` to `appId`. |
||
|
|
eb6948a562 |
i18n: complete internationalization for provider and usage query panels
- Add 45+ new translation keys for usage query and usage script features - Fix duplicate provider object in translation files that caused missing translations - Remove all hardcoded Chinese text and defaultValue fallbacks from components - Add proper translations for: * Usage footer (query status, plan usage display) * Usage script modal (script editor, validation, test controls) * Provider forms (basic fields, endpoints, model selectors) * Provider dialogs (add/edit hints and titles) Modified 16 files: - 2 translation files (zh.json, en.json) - 14 component files (removed defaultValue, added t() calls) All UI text now properly supports Chinese/English switching. |
||
|
|
57552b3159 |
fix: unify dialog layout and fix content padding issues
- Fix negative margin overflow in all dialog content areas - Standardize dialog structure with flex-col layout - Add consistent py-4 spacing to all content areas - Ensure proper spacing between header, content, and footer Affected components: - AddProviderDialog, EditProviderDialog - McpFormModal, McpPanel - UsageScriptModal - SettingsDialog All dialogs now follow unified layout pattern: - DialogContent: flex flex-col max-h-[90vh] - Content area: flex-1 overflow-y-auto px-6 py-4 - No negative margins that cause content overflow |
||
|
|
c1f5ddf763 |
refactor: unify directory structure and extract shared components
- Migrate all form components from ProviderForm/ to providers/forms/ - Create shared components to eliminate code duplication: * ApiKeySection: unified API key input with "Get API Key" link * EndpointField: unified endpoint URL input with manage button - Refactor ClaudeFormFields (-31% lines) and CodexFormFields (-33% lines) - Update all import paths to use new locations - Reduce code duplication from ~12% to ~7% This change improves maintainability and makes the codebase more DRY. |
||
|
|
17f350f2d3 |
feat: add useSpeedTestEndpoints hook to collect all endpoint candidates for speed test modal
- Create useSpeedTestEndpoints hook that collects endpoints from: 1. Current baseUrl/codexBaseUrl 2. Initial data URL (edit mode) 3. Preset's endpointCandidates array - Pass speedTestEndpoints to ClaudeFormFields and CodexFormFields - Update EndpointSpeedTest to use collected endpoints instead of just current URL - Fix PackyCode preset endpoints not appearing in speed test modal |
||
|
|
0868a71576 |
refactor: split ProviderForm into smaller focused components
- Created ProviderPresetSelector component (80 lines) - Created BasicFormFields component (60 lines) - Created ClaudeFormFields component (272 lines) - Created CodexFormFields component (131 lines) - Reduced ProviderForm from 866 to 544 lines (37% reduction) Each component now has a clear single responsibility: - ProviderPresetSelector: Handles preset selection UI - BasicFormFields: Name and website URL inputs - ClaudeFormFields: All Claude-specific form fields - CodexFormFields: All Codex-specific form fields - ProviderForm: Orchestrates hooks and component composition Benefits: - Better code organization and maintainability - Easier to test individual components - Clearer separation of concerns - More reusable components |