Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b6bacd6b4a | |||
| df01755328 | |||
| 74b9f52d90 | |||
| 8838317087 | |||
| 4d570691e1 | |||
| 337224546c | |||
| 7d21663e6d | |||
| 926e69b8c9 | |||
| a03ad4f47f | |||
| c38bef517a | |||
| 7526a031a7 | |||
| 84bc98cf83 | |||
| af679cda25 | |||
| a83bd90fa9 | |||
| 794795cad4 | |||
| eff85dc66d | |||
| 3aef5217cb | |||
| e4b58c7206 | |||
| 8c32610a7d | |||
| afdda27bd5 | |||
| 7f1963ab49 | |||
| 68df60bd4a |
@@ -5,7 +5,7 @@ All notable changes to CC Switch will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## [3.13.0] - 2026-04-10
|
||||
|
||||
Development since v3.12.3 focuses on quota visibility, provider workflow upgrades, stronger proxy compatibility, and lower-overhead tray / session workflows.
|
||||
|
||||
@@ -13,7 +13,7 @@ Development since v3.12.3 focuses on quota visibility, provider workflow upgrade
|
||||
|
||||
- **Lightweight Mode**: Added a tray-only mode that destroys the main window and keeps CC Switch running from the system tray, with the window recreated when users reopen it.
|
||||
- **Provider Model Auto-Fetch**: Added OpenAI-compatible `/v1/models` discovery for Claude, Codex, Gemini, OpenCode, and OpenClaw provider forms, including grouped dropdown selection and failure-specific error messages.
|
||||
- **Quota & Balance Visibility**: Added inline quota or balance display for official Claude / Codex / Gemini providers, GitHub Copilot premium interactions, Codex OAuth providers, Token Plan providers (Kimi / Zhipu GLM / MiniMax), and official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI.
|
||||
- **Quota & Balance Visibility**: Added inline quota or balance display for official Claude / Codex / Gemini providers, GitHub Copilot premium interactions, Codex OAuth providers, Token Plan providers (Kimi / Zhipu GLM / MiniMax), and official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI. Copilot / ChatGPT OAuth and CLI subscription quota now only auto-poll for the currently active provider, preventing unnecessary API calls and misleading displays on non-current cards.
|
||||
- **Skills Discovery & Batch Updates**: Added SHA-256 based skill update detection, per-skill and batch update actions, a storage-location toggle between CC Switch and `~/.agents/skills`, and public `skills.sh` search integration.
|
||||
- **Session Workflow Upgrades**: Added batch delete in Session Manager, a directory picker before launching Claude terminal restore commands, usage import from Claude / Codex / Gemini session logs without requiring proxy interception, and per-app usage filtering for Claude / Codex / Gemini dashboards.
|
||||
- **Codex OAuth Reverse Proxy**: Added ChatGPT Plus / Pro based Codex OAuth reverse proxy support for Claude provider cards, including managed OAuth login and inline subscription quota display.
|
||||
@@ -21,6 +21,22 @@ Development since v3.12.3 focuses on quota visibility, provider workflow upgrade
|
||||
- **Full URL Endpoint Mode**: Added a provider option that treats `base_url` as a complete upstream endpoint so proxy forwarding and stream checks can work with vendors that require nonstandard URL layouts.
|
||||
- **OpenCode StepFun Step Plan Preset**: Added a StepFun Step Plan provider preset for OpenCode.
|
||||
- **Copilot Interaction Optimizer**: Added request classification and routing logic to reduce unnecessary GitHub Copilot premium interaction consumption.
|
||||
- **First-Run Welcome Dialog**: Added a one-time welcome dialog on fresh installs explaining how existing configuration is preserved as a default provider and how the bundled official preset enables one-click revert. Upgrade users are excluded.
|
||||
- **Official Provider Seeding**: Added automatic seeding of Claude Official, OpenAI Official, and Google Official provider entries on startup, giving every user a one-click path back to the official endpoint.
|
||||
- **OpenCode / OpenClaw Auto-Import**: Added automatic startup import of live OpenCode and OpenClaw provider configurations, matching the auto-import behavior already present for Claude, Codex, and Gemini.
|
||||
- **Common Config Editor Guidance**: Added an informational guide and empty-state prompt to the Common Config snippet editor modal for Claude, Codex, and Gemini, with i18n support.
|
||||
- **Common Config First-Run Notice**: Added a one-time informational dialog explaining Common Config Snippets when users first open the provider add/edit form.
|
||||
- **Claude Session Titles**: Added meaningful title extraction for Claude sessions using a priority chain: custom-title metadata, first real user message, then directory basename fallback.
|
||||
- **Session Search Highlighting**: Added keyword highlighting in session titles and messages during Session Manager search.
|
||||
- **URL-Based Provider Icons**: Added a dual rendering mode to the icon system supporting Vite URL imports for large SVGs and raster images (PNG, JPG, WebP), keeping small SVGs inlined.
|
||||
- **Kaku Terminal Support**: Added Kaku as a selectable terminal for session launch on macOS, reusing the WezTerm-compatible launch path.
|
||||
- **OMO Slim Council Support**: Restored first-class council support as a built-in oh-my-opencode-slim agent with updated metadata and UI copy.
|
||||
- **TheRouter Provider Preset**: Added TheRouter provider presets across Claude, Codex, Gemini, OpenCode, and OpenClaw.
|
||||
- **DDSHub Provider Preset**: Added DDSHub as a third-party partner provider for Claude with icon and partner promotion text.
|
||||
- **LionCCAPI Provider Preset**: Added LionCCAPI as a third-party partner provider across all five apps with anthropic-messages protocol for OpenCode and OpenClaw.
|
||||
- **Shengsuanyun Provider Preset**: Added Shengsuanyun (胜算云) as an aggregator partner provider across all five apps with URL-based icon and localized display name.
|
||||
- **PIPELLM Provider Preset**: Added PIPELLM provider preset across Claude, Codex, OpenCode, and OpenClaw with full model definitions and icon.
|
||||
- **E-FlowCode Provider Preset**: Added E-FlowCode provider preset across all five apps with per-app protocol configuration.
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -47,12 +63,19 @@ Development since v3.12.3 focuses on quota visibility, provider workflow upgrade
|
||||
- **Linux UI Unresponsive on Startup**: Fixed a bug where the window UI (including native title bar buttons) couldn't receive clicks on Linux until the user manually maximized and restored the window. Root causes: (1) Tauri webview did not acquire keyboard focus after `show()` on Linux, so the first click was consumed by X11/Wayland click-to-activate (Tauri #10746, wry #637); (2) GTK surface's input region failed to renegotiate on the `visible:false → show()` path under some WebKitGTK/compositor combinations, leaving the entire window unresponsive. Mitigations: set `WEBKIT_DISABLE_COMPOSITING_MODE=1` at startup, and added a new `linux_fix::nudge_main_window` helper that performs `set_focus` + a ±1px no-op resize ~200ms after show, equivalent to a visually invisible "maximize-and-restore". Wired into all window-re-show paths (normal startup, deeplink, single_instance, tray `show_main`, lightweight exit).
|
||||
- **Linux Drag Region on Header**: Removed `data-tauri-drag-region` from the top header bar on Linux to avoid triggering `gtk_window_begin_move_drag` paths affected by Tauri #13440 under Wayland. macOS drag behavior is preserved.
|
||||
- **OpenCode / OpenClaw Stream Check Edge Cases**: Fixed custom-header passthrough, OpenClaw custom auth-header detection, Bedrock error messaging, and OpenCode default `baseURL` fallback handling in Stream Check.
|
||||
- **Duplicate Toast on Provider Switch**: Fixed double toast notifications (proxy-required warning followed by switch-success) when switching to Copilot, ChatGPT, or OpenAI-format providers with the proxy not running.
|
||||
- **Session Search Accuracy & Chinese Support**: Fixed session search result truncation across providers and switched FlexSearch tokenizer to full mode for proper Chinese substring matching.
|
||||
- **Adaptive Thinking Reasoning Effort**: Fixed `resolve_reasoning_effort()` mapping adaptive thinking to `xhigh` instead of incorrectly using `high` in OpenAI format conversions.
|
||||
- **Thinking Model Fallback Display**: Fixed the Claude provider form showing an empty Thinking model field after saving only a main model by applying read-only fallback to ANTHROPIC_MODEL.
|
||||
- **Auth Tab Localization**: Fixed missing i18n translation keys for the settings auth tab label across all locale bundles.
|
||||
- **Schema Migration Guard**: Fixed database migrations failing when skills or model_pricing tables did not exist by adding table-existence checks before ALTER and UPDATE operations.
|
||||
|
||||
### Docs
|
||||
|
||||
- **User Manual Refresh**: Updated the EN / ZH / JA manuals for tray submenus, lightweight mode, provider model fetching, session management, workspace files, WebDAV v2 behavior, OpenCode / OpenClaw activation, and other provider workflow improvements.
|
||||
- **Community & Contribution Docs**: Added `CONTRIBUTING.md`, `SECURITY.md`, `CODE_OF_CONDUCT.md`, bilingual issue / PR templates, Dependabot config, and CI quality checks.
|
||||
- **Release Notes Risk Notice**: Added a Copilot reverse proxy risk notice and anchored highlight links in the v3.12.3 release notes across all three languages.
|
||||
- **Sponsor Partners**: Added Shengsuanyun, LionCC, and DDS as sponsor partners in README across all languages.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
## Overview
|
||||
|
||||
CC Switch v3.13.0 is a major feature release centered on observability, provider workflow ergonomics, and proxy compatibility. It adds inline **quota and balance displays** across official Claude / Codex / Gemini providers plus Token Plan, Copilot, and third-party balance APIs; introduces a **Lightweight Mode** that keeps CC Switch running from the system tray without a main window; delivers **automatic model discovery** via OpenAI-compatible `/v1/models` across all five supported applications; ships a **Codex OAuth reverse proxy** for ChatGPT Plus / Pro subscribers; reorganizes the tray menu into **per-app submenus**; rebuilds the proxy forwarding stack on a **Hyper-based client**; and overhauls the **Skills workflow** with discovery, batch updates, and storage-location toggling. Additional improvements include full URL endpoint mode, session-log usage tracking without proxy interception, the Copilot interaction optimizer, a UTF-8 streaming chunk boundary fix for multi-byte output, and a Linux startup UI responsiveness fix.
|
||||
CC Switch v3.13.0 is a major feature release centered on observability, provider workflow ergonomics, and proxy compatibility. It adds inline **quota and balance displays** across official Claude / Codex / Gemini providers plus Token Plan, Copilot, and third-party balance APIs; introduces a **Lightweight Mode** that keeps CC Switch running from the system tray without a main window; delivers **automatic model discovery** via OpenAI-compatible `/v1/models` across all five supported applications; ships a **Codex OAuth reverse proxy** for ChatGPT subscribers; reorganizes the tray menu into **per-app submenus**; rebuilds the proxy forwarding stack on a **Hyper-based client**; and overhauls the **Skills workflow** with discovery, batch updates, storage-location toggling, and built-in skills.sh search and install. Additional improvements include full URL endpoint mode, enhanced token usage tracking, the Copilot interaction optimizer, a UTF-8 streaming chunk boundary fix for multi-byte output, a Linux startup UI responsiveness fix, and a friendlier new-user onboarding experience.
|
||||
|
||||
**Release Date**: 2026-04-08
|
||||
**Release Date**: 2026-04-10
|
||||
|
||||
**Update Scale**: 98 commits | 229 files changed | +23,891 / -2,305 lines
|
||||
**Update Scale**: 139 commits | 280 files changed | +31,627 / -3,042 lines
|
||||
|
||||
---
|
||||
|
||||
@@ -21,9 +21,9 @@ CC Switch v3.13.0 is a major feature release centered on observability, provider
|
||||
- **Lightweight Mode**: Tray-only operating mode that destroys the main window on exit to tray and recreates it on demand, reducing CC Switch's desktop footprint to near zero when idle
|
||||
- **Quota & Balance Visibility**: Inline quota or balance readout across provider cards — official Claude / Codex / Gemini subscriptions, GitHub Copilot premium interactions, Codex OAuth, Token Plan providers (Kimi / Zhipu GLM / MiniMax), plus official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI
|
||||
- **Provider Model Auto-Fetch**: OpenAI-compatible `/v1/models` discovery across Claude, Codex, Gemini, OpenCode, and OpenClaw provider forms, with grouped dropdown selection and failure-specific error messages
|
||||
- **Codex OAuth Reverse Proxy**: ChatGPT Plus / Pro Codex reverse proxy exposed as a new Claude provider card with managed OAuth login and inline subscription quota display ([⚠️ Risk Notice](#️-risk-notice))
|
||||
- **Codex OAuth Reverse Proxy**: ChatGPT Codex reverse proxy exposed as a new Claude provider card type, allowing users to use their ChatGPT subscription in Claude Code. Includes managed OAuth login and inline subscription quota display ([⚠️ Risk Notice](#️-risk-notice))
|
||||
- **Tray Per-App Submenus**: Reworked the tray menu into per-application submenus so it never overflows the screen and background provider switching scales to dozens of providers per app
|
||||
- **Skills Discovery & Batch Updates**: SHA-256-based skill update detection, per-skill and "Update All" batch actions, public `skills.sh` search integration, and a storage-location toggle between CC Switch storage and `~/.agents/skills`
|
||||
- **Skills Discovery & Batch Updates**: SHA-256-based skill update detection, per-skill and "Update All" batch actions, `skills.sh` search integration, and a storage-location toggle between CC Switch storage and `~/.agents/skills`
|
||||
- **Session Workflow Upgrades**: Batch session deletion, a directory picker before launching Claude terminal restore, usage import from Claude / Codex / Gemini session logs without proxy interception, precise Codex JSONL parsing, and per-app usage filtering
|
||||
- **OpenCode / OpenClaw Stream Check Coverage**: OpenCode detection via npm package mapping, OpenClaw `openai-completions` support, and the remaining OpenClaw protocol variants — with custom-header passthrough and auth-header detection fixes
|
||||
- **Full URL Endpoint Mode**: Provider option that treats `base_url` as a complete upstream endpoint, unblocking vendors that require nonstandard URL layouts
|
||||
@@ -31,6 +31,10 @@ CC Switch v3.13.0 is a major feature release centered on observability, provider
|
||||
- **Copilot Interaction Optimizer**: Request classification and routing logic that reduces unnecessary GitHub Copilot premium interaction consumption
|
||||
- **UTF-8 Stream Chunk Boundary Fix**: All four SSE streaming paths now preserve incomplete multi-byte UTF-8 sequences across TCP chunks, eliminating intermittent U+FFFD garbled output via the Copilot reverse proxy
|
||||
- **Linux Startup UI Fix**: Fixed the long-standing issue where the window UI couldn't receive clicks on Linux until the user manually maximized and restored the window
|
||||
- **First-Run Onboarding**: One-time welcome dialog on fresh installs, automatic seeding of Claude / OpenAI / Google official presets, and auto-import of OpenCode / OpenClaw live configurations on startup
|
||||
- **Claude Session Titles & Search Highlighting**: Meaningful title extraction for Claude sessions using a priority chain (custom-title metadata → first user message → directory basename), plus keyword highlighting in Session Manager search results
|
||||
- **URL-Based Provider Icons**: Dual rendering mode supporting Vite URL imports for large SVGs and raster images (PNG, JPG, WebP), keeping small SVGs inlined
|
||||
- **New Provider Presets**: TheRouter, DDSHub, LionCCAPI, Shengsuanyun (胜算云), PIPELLM, and E-FlowCode across supported applications
|
||||
|
||||
---
|
||||
|
||||
@@ -50,9 +54,9 @@ Added inline quota and balance readouts to provider cards so users can see remai
|
||||
|
||||
- **Official subscriptions**: Inline quota display for Claude, Codex, and Gemini official providers
|
||||
- **GitHub Copilot**: Premium interactions quota display on the Copilot provider card
|
||||
- **Codex OAuth**: ChatGPT Plus / Pro subscription quota inline with the Codex OAuth provider card
|
||||
- **Token Plan providers**: Kimi, Zhipu GLM, and MiniMax with corrected quota math and consistent 0% → 100% usage progression
|
||||
- **Third-party balances**: Official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI
|
||||
- **Codex OAuth**: ChatGPT subscription quota inline with the Codex OAuth provider card
|
||||
- **Token Plan providers**: Kimi, Zhipu GLM, and MiniMax usage progression display (requires manual activation to avoid confusion)
|
||||
- **Third-party balances**: Official balance queries for DeepSeek, StepFun, SiliconFlow, OpenRouter, and Novita AI (requires manual activation to avoid confusion)
|
||||
- Health-check and usage-config buttons are hidden for official providers to keep the card clean
|
||||
|
||||
### Provider Model Auto-Fetch
|
||||
@@ -66,13 +70,12 @@ Added OpenAI-compatible model discovery to every provider form, removing the man
|
||||
|
||||
### Codex OAuth Reverse Proxy
|
||||
|
||||
Added a reverse proxy path for ChatGPT Plus / Pro subscribers who want to route their Codex OAuth session through CC Switch.
|
||||
Added a reverse proxy path for ChatGPT subscribers who want to use their ChatGPT subscription in Claude Code.
|
||||
|
||||
- Managed OAuth login flow with ChatGPT Plus / Pro authentication
|
||||
- Managed OAuth login flow with ChatGPT authentication
|
||||
- Surfaces as a new Claude provider card type alongside API-key providers
|
||||
- Inline subscription quota display
|
||||
- Integrated into the Auth Center with tightened copy, layout, and icon presentation
|
||||
- Bumped the Codex OAuth preset to the GPT-5.4 model family
|
||||
- Integrated into the Auth Center for unified token management
|
||||
- See the [⚠️ Risk Notice](#️-risk-notice) below before enabling
|
||||
|
||||
### Tray Per-App Submenus
|
||||
@@ -131,6 +134,54 @@ Added request classification and routing logic that reduces unnecessary GitHub C
|
||||
- Classifies incoming requests by intent and weight
|
||||
- Routes low-value requests away from premium interaction consumption paths
|
||||
- Designed to extend the usable lifetime of a Copilot subscription
|
||||
- Note: Even with optimized consumption, using the Copilot API outside of Copilot still consumes more than using it within Copilot.
|
||||
|
||||
### First-Run Welcome Dialog
|
||||
|
||||
Added a one-time welcome dialog on fresh installs to guide new users through the CC Switch workflow.
|
||||
|
||||
- Explains how existing live configuration is preserved as a default provider
|
||||
- Introduces the bundled official preset that enables one-click revert to official endpoints
|
||||
- Upgrade users are automatically excluded via empty provider check
|
||||
|
||||
### Official Provider Seeding
|
||||
|
||||
- Added automatic seeding of Claude Official, OpenAI Official, and Google Official provider entries on startup, giving every user a one-click path back to the official endpoint
|
||||
|
||||
### OpenCode / OpenClaw Auto-Import
|
||||
|
||||
- Added automatic startup import of live OpenCode and OpenClaw provider configurations, matching the auto-import behavior already present for Claude, Codex, and Gemini
|
||||
|
||||
### Common Config Editor Guidance
|
||||
|
||||
- Added an informational guide and empty-state prompt to the Common Config snippet editor modal for Claude, Codex, and Gemini
|
||||
- Added a one-time informational dialog explaining Common Config Snippets when users first open the provider add/edit form
|
||||
|
||||
### Claude Session Titles & Search Highlighting
|
||||
|
||||
- Added meaningful title extraction for Claude sessions using a priority chain: custom-title metadata, first real user message, then directory basename fallback
|
||||
- Added keyword highlighting in session titles and messages during Session Manager search
|
||||
|
||||
### URL-Based Provider Icons
|
||||
|
||||
- Added a dual rendering mode to the icon system: small SVGs are inlined as React components, while large SVGs and raster images (PNG, JPG, WebP) are loaded via Vite URL imports as `<img>` tags
|
||||
|
||||
### Kaku Terminal Support
|
||||
|
||||
- Added Kaku as a selectable terminal for session launch on macOS, reusing the WezTerm-compatible launch path (#1983, thanks @yovinchen)
|
||||
|
||||
### OMO Slim Council Support
|
||||
|
||||
- Restored first-class council support as a built-in oh-my-opencode-slim agent with updated metadata and UI copy (#1982, thanks @yovinchen)
|
||||
|
||||
### New Provider Presets
|
||||
|
||||
- **TheRouter**: Added across Claude, Codex, Gemini, OpenCode, and OpenClaw (#1891, #1892, thanks @cmzz)
|
||||
- **DDSHub**: Added as a third-party partner provider for Claude with icon and partner promotion text
|
||||
- **LionCCAPI**: Added across all five apps with anthropic-messages protocol for OpenCode and OpenClaw
|
||||
- **Shengsuanyun (胜算云)**: Added as an aggregator partner provider across all five apps with URL-based icon and localized display name
|
||||
- **PIPELLM**: Added across Claude, Codex, OpenCode, and OpenClaw with full model definitions and icon
|
||||
- **E-FlowCode**: Added across all five apps with per-app protocol configuration
|
||||
|
||||
---
|
||||
|
||||
@@ -263,6 +314,31 @@ Fixed a long-standing Linux bug where the window UI (including native title bar
|
||||
- Bedrock error messaging
|
||||
- OpenCode default `baseURL` fallback handling
|
||||
|
||||
### Duplicate Toast on Provider Switch
|
||||
|
||||
- Fixed double toast notifications (proxy-required warning followed by switch-success) when switching to Copilot, ChatGPT, or OpenAI-format providers with the proxy not running
|
||||
|
||||
### Session Search Accuracy & Chinese Support
|
||||
|
||||
- Fixed session search result truncation across providers
|
||||
- Switched FlexSearch tokenizer to full mode for proper Chinese substring matching
|
||||
|
||||
### Adaptive Thinking Reasoning Effort
|
||||
|
||||
- Fixed `resolve_reasoning_effort()` mapping adaptive thinking to `xhigh` instead of incorrectly using `high` in OpenAI format conversions
|
||||
|
||||
### Thinking Model Fallback Display
|
||||
|
||||
- Fixed the Claude provider form showing an empty Thinking model field after saving only a main model by applying read-only fallback to ANTHROPIC_MODEL (#1984, thanks @yovinchen)
|
||||
|
||||
### Auth Tab Localization
|
||||
|
||||
- Fixed missing i18n translation keys for the settings auth tab label across all locale bundles (#1985, thanks @yovinchen)
|
||||
|
||||
### Schema Migration Guard
|
||||
|
||||
- Fixed database migrations failing when skills or model_pricing tables did not exist by adding table-existence checks before ALTER and UPDATE operations
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
@@ -282,16 +358,20 @@ Fixed a long-standing Linux bug where the window UI (including native title bar
|
||||
|
||||
- Added a Copilot reverse proxy risk notice and anchored highlight links in the v3.12.3 release notes across all three languages
|
||||
|
||||
### Sponsor Partners
|
||||
|
||||
- Added Shengsuanyun, LionCC, and DDS as sponsor partners in README across all languages
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Risk Notice
|
||||
|
||||
**Codex OAuth Reverse Proxy Disclaimer**
|
||||
|
||||
The Codex OAuth reverse proxy introduced in this release accesses ChatGPT Plus / Pro Codex services through reverse-engineered OAuth flows. Please be aware of the following risks before enabling this feature:
|
||||
The Codex OAuth reverse proxy introduced in this release accesses ChatGPT Codex services through reverse-engineered OAuth flows. Please be aware of the following risks before enabling this feature:
|
||||
|
||||
1. **Terms of Service**: Using reverse-engineered OAuth flows to access OpenAI services may violate OpenAI's terms of service, which prohibit unauthorized automated access, service reproduction, and circumventing intended access paths.
|
||||
2. **Account Risk**: OpenAI may flag unusual usage patterns as suspicious automated activity, potentially resulting in temporary or permanent restrictions on ChatGPT Plus / Pro access.
|
||||
2. **Account Risk**: OpenAI may flag unusual usage patterns as suspicious automated activity, potentially resulting in temporary or permanent restrictions on ChatGPT access.
|
||||
3. **No Guarantee**: OpenAI may update its authentication and detection mechanisms at any time, and usage patterns that work today may be flagged in the future.
|
||||
|
||||
The **GitHub Copilot reverse proxy** introduced in v3.12.3 also remains subject to its existing risk notice — see the [v3.12.3 release notes](v3.12.3-en.md#️-risk-notice) for the full disclosure.
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
## 概要
|
||||
|
||||
CC Switch v3.13.0 は、可観測性、プロバイダーワークフローの使いやすさ、プロキシ互換性を中心とした大型機能リリースです。Claude / Codex / Gemini の公式プロバイダー、Token Plan、Copilot、サードパーティ残高 API にわたる**クォータと残高のインライン表示**を追加し、メインウィンドウなしでシステムトレイから CC Switch を動作させる**軽量モード**を導入しました。OpenAI 互換の `/v1/models` による**自動モデル発見**を 5 つのサポート対象アプリケーションすべてに提供し、ChatGPT Plus / Pro サブスクライバー向けの **Codex OAuth リバースプロキシ**を同梱しています。トレイメニューを**アプリ別サブメニュー**に再編成し、プロキシ転送スタックを **Hyper ベースのクライアント**に再構築し、**Skills ワークフロー**を発見、バッチ更新、ストレージ位置切り替えで刷新しました。さらに、フル URL エンドポイントモード、プロキシ傍受なしのセッションログ用量追跡、Copilot インタラクション最適化、マルチバイト UTF-8 ストリームチャンク境界修正、Linux 起動時の UI 応答性修正なども含まれます。
|
||||
CC Switch v3.13.0 は、可観測性、プロバイダーワークフローの使いやすさ、プロキシ互換性を中心とした大型機能リリースです。Claude / Codex / Gemini の公式プロバイダー、Token Plan、Copilot、サードパーティ残高 API にわたる**クォータと残高のインライン表示**を追加し、メインウィンドウなしでシステムトレイから CC Switch を動作させる**軽量モード**を導入しました。OpenAI 互換の `/v1/models` による**自動モデル発見**を 5 つのサポート対象アプリケーションすべてに提供し、ChatGPT サブスクライバー向けの **Codex OAuth リバースプロキシ**を同梱しています。トレイメニューを**アプリ別サブメニュー**に再編成し、プロキシ転送スタックを **Hyper ベースのクライアント**に再構築し、**Skills ワークフロー**を発見、バッチ更新、ストレージ位置切り替え、および組み込みの skills.sh 検索・インストールで刷新しました。さらに、フル URL エンドポイントモード、強化されたトークン用量追跡、Copilot インタラクション最適化、マルチバイト UTF-8 ストリームチャンク境界修正、Linux 起動時の UI 応答性修正、およびよりフレンドリーな新規ユーザーオンボーディングなども含まれます。
|
||||
|
||||
**リリース日**: 2026-04-08
|
||||
**リリース日**: 2026-04-10
|
||||
|
||||
**更新規模**: 98 commits | 229 files changed | +23,891 / -2,305 lines
|
||||
**更新規模**: 139 commits | 280 files changed | +31,627 / -3,042 lines
|
||||
|
||||
---
|
||||
|
||||
@@ -21,9 +21,9 @@ CC Switch v3.13.0 は、可観測性、プロバイダーワークフローの
|
||||
- **軽量モード**: トレイ専用の動作モード。トレイへの終了時にメインウィンドウを破棄し、必要時に再作成することで、アイドル時の CC Switch のデスクトップフットプリントを最小化
|
||||
- **クォータと残高の可視化**: プロバイダーカードでのインラインクォータ/残高表示 — Claude / Codex / Gemini 公式サブスクリプション、GitHub Copilot premium interactions、Codex OAuth、Token Plan プロバイダー(Kimi / Zhipu GLM / MiniMax)、および DeepSeek / StepFun / SiliconFlow / OpenRouter / Novita AI の公式残高クエリをカバー
|
||||
- **プロバイダーモデル自動取得**: Claude / Codex / Gemini / OpenCode / OpenClaw のプロバイダーフォームに OpenAI 互換の `/v1/models` 発見機能を追加。グループ化ドロップダウンと失敗時の具体的なエラーメッセージ付き
|
||||
- **Codex OAuth リバースプロキシ**: ChatGPT Plus / Pro の Codex リバースプロキシを新しい Claude プロバイダーカードタイプとして追加。マネージド OAuth ログインとサブスクリプションクォータのインライン表示を提供([⚠️ リスクに関する注意事項](#️-リスクに関する注意事項))
|
||||
- **Codex OAuth リバースプロキシ**: ChatGPT の Codex リバースプロキシを新しい Claude プロバイダーカードタイプとして追加。ユーザーは ChatGPT サブスクリプションを Claude Code で利用可能に。マネージド OAuth ログインとサブスクリプションクォータのインライン表示を提供([⚠️ リスクに関する注意事項](#️-リスクに関する注意事項))
|
||||
- **トレイのアプリ別サブメニュー**: トレイメニューをアプリ別サブメニューに再編成し、プロバイダー数が多くてもメニューがオーバーフローせず、バックグラウンドのプロバイダー切り替えが長いリストでもスケール
|
||||
- **Skills 発見とバッチ更新**: SHA-256 ベースの skill 更新検出、各 skill および「すべて更新」のバッチ更新、公開 `skills.sh` 検索統合、CC Switch ストレージと `~/.agents/skills` の間のストレージ位置切り替え
|
||||
- **Skills 発見とバッチ更新**: SHA-256 ベースの skill 更新検出、各 skill および「すべて更新」のバッチ更新、`skills.sh` 検索統合、CC Switch ストレージと `~/.agents/skills` の間のストレージ位置切り替え
|
||||
- **セッションワークフローの改善**: Session Manager でのバッチ削除、Claude ターミナル復元前のディレクトリピッカー、プロキシ傍受なしでの Claude / Codex / Gemini セッションログからの用量インポート、正確な Codex JSONL 解析、アプリ別の用量フィルタリング
|
||||
- **OpenCode / OpenClaw Stream Check カバレッジ**: OpenCode の npm パッケージマッピング検出、OpenClaw `openai-completions` サポート、および残りの OpenClaw プロトコルバリアント
|
||||
- **フル URL エンドポイントモード**: `base_url` を完全な上流エンドポイントとして扱うプロバイダーオプションを追加し、非標準 URL レイアウトを要求するベンダーに対応
|
||||
@@ -31,6 +31,10 @@ CC Switch v3.13.0 は、可観測性、プロバイダーワークフローの
|
||||
- **Copilot インタラクション最適化**: GitHub Copilot premium interaction の不要な消費を削減するリクエスト分類とルーティングロジックを追加
|
||||
- **UTF-8 ストリームチャンク境界修正**: マルチバイト UTF-8 シーケンスが TCP チャンクを跨いで分割された際の Copilot リバースプロキシ経由での文字化け(U+FFFD 置換文字)を解消するため、すべての 4 つの SSE ストリーミングパスを修正
|
||||
- **Linux 起動時 UI 修正**: ユーザーが手動でウィンドウを最大化・復元するまでウィンドウ UI がクリックを受け付けない長年の問題を修正
|
||||
- **初回起動オンボーディング**: 新規インストール時のワンタイムウェルカムダイアログ、Claude / OpenAI / Google 公式プリセットの自動シード、起動時の OpenCode / OpenClaw ライブ設定の自動インポート
|
||||
- **Claude セッションタイトルと検索ハイライト**: カスタムタイトルメタデータ → 最初のユーザーメッセージ → ディレクトリベースネームの優先チェーンによる Claude セッションの意味のあるタイトル抽出、Session Manager 検索でのキーワードハイライト
|
||||
- **URL ベースのプロバイダーアイコン**: 大きな SVG とラスター画像(PNG / JPG / WebP)を Vite URL import でロードし、小さな SVG はインライン保持するデュアルレンダリングモード
|
||||
- **新プロバイダープリセット**: TheRouter、DDSHub、LionCCAPI、Shengsuanyun(胜算云)、PIPELLM、E-FlowCode を対応アプリケーションに追加
|
||||
|
||||
---
|
||||
|
||||
@@ -50,9 +54,9 @@ CC Switch のアイドル時のデスクトップフットプリントを大幅
|
||||
|
||||
- **公式サブスクリプション**: Claude / Codex / Gemini 公式プロバイダーのサブスクリプションクォータ表示
|
||||
- **GitHub Copilot**: Copilot プロバイダーカードに premium interactions 残量を表示
|
||||
- **Codex OAuth**: Codex OAuth カードに ChatGPT Plus / Pro サブスクリプションクォータをインライン表示
|
||||
- **Token Plan プロバイダー**: Kimi、Zhipu GLM、MiniMax。クォータ計算と 0% → 100% 使用量進行を修正
|
||||
- **サードパーティ残高**: DeepSeek、StepFun、SiliconFlow、OpenRouter、Novita AI に公式残高クエリを追加
|
||||
- **Codex OAuth**: Codex OAuth カードに ChatGPT サブスクリプションクォータをインライン表示
|
||||
- **Token Plan プロバイダー**: Kimi、Zhipu GLM、MiniMax の使用量進行表示(混乱を避けるため手動で有効化が必要)
|
||||
- **サードパーティ残高**: DeepSeek、StepFun、SiliconFlow、OpenRouter、Novita AI に公式残高クエリを追加(混乱を避けるため手動で有効化が必要)
|
||||
- 公式プロバイダーではヘルスチェックと用量設定ボタンを非表示にし、カードをクリーンに保つ
|
||||
|
||||
### プロバイダーモデル自動取得
|
||||
@@ -66,13 +70,12 @@ CC Switch のアイドル時のデスクトップフットプリントを大幅
|
||||
|
||||
### Codex OAuth リバースプロキシ
|
||||
|
||||
ChatGPT Plus / Pro のサブスクライバーが Codex OAuth セッションを CC Switch 経由で利用できるリバースプロキシパスを追加。
|
||||
ChatGPT サブスクライバーが ChatGPT サブスクリプションを Claude Code で利用できるリバースプロキシパスを追加。
|
||||
|
||||
- ChatGPT Plus / Pro 認証を使ったマネージド OAuth ログインフロー
|
||||
- ChatGPT 認証を使ったマネージド OAuth ログインフロー
|
||||
- API キー型プロバイダーと並ぶ新しい Claude プロバイダーカードタイプとして表示
|
||||
- サブスクリプションクォータのインライン表示
|
||||
- Auth Center との緊密な統合と、コピー・レイアウト・アイコンの調整
|
||||
- Codex OAuth プリセットを GPT-5.4 モデルファミリーに更新
|
||||
- Auth Center との統合によるトークンの一元管理
|
||||
- 有効化前に下記の [⚠️ リスクに関する注意事項](#️-リスクに関する注意事項) をご確認ください
|
||||
|
||||
### トレイのアプリ別サブメニュー
|
||||
@@ -131,6 +134,54 @@ GitHub Copilot premium interaction の不要な消費を削減するリクエス
|
||||
- 受信リクエストを意図と重要度で分類
|
||||
- 価値の低いリクエストを premium interaction 消費パスから迂回
|
||||
- Copilot サブスクリプションの使用可能期間を延長することを目的
|
||||
- 注意: 消費を最適化しても、Copilot 外で Copilot API を使用する場合、Copilot 内で使用するよりも消費量は多くなります。
|
||||
|
||||
### 初回起動ウェルカムダイアログ
|
||||
|
||||
新規インストールのユーザーに CC Switch のワークフローを案内するワンタイムウェルカムダイアログを追加。
|
||||
|
||||
- 既存のライブ設定がデフォルトプロバイダーとして保持される仕組みを説明
|
||||
- 内蔵の公式プリセットによるワンクリックでの公式エンドポイント復帰を紹介
|
||||
- アップグレードユーザーは空プロバイダーチェックにより自動的にスキップ
|
||||
|
||||
### 公式プロバイダーの自動シード
|
||||
|
||||
- 起動時に Claude Official / OpenAI Official / Google Official プロバイダーエントリを自動シードし、すべてのユーザーにワンクリックで公式エンドポイントに戻るパスを提供
|
||||
|
||||
### OpenCode / OpenClaw 自動インポート
|
||||
|
||||
- 起動時に OpenCode と OpenClaw のライブプロバイダー設定を自動インポート。Claude / Codex / Gemini で既にある自動インポート動作と同等に
|
||||
|
||||
### Common Config エディタガイダンス
|
||||
|
||||
- Claude / Codex / Gemini の Common Config スニペットエディタモーダルに情報ガイドと空状態プロンプトを追加
|
||||
- ユーザーがプロバイダー追加/編集フォームを初めて開く際、Common Config Snippets を説明するワンタイムダイアログを追加
|
||||
|
||||
### Claude セッションタイトルと検索ハイライト
|
||||
|
||||
- Claude セッションの意味のあるタイトル抽出を追加。優先チェーン: カスタムタイトルメタデータ → 最初の実ユーザーメッセージ → ディレクトリベースネームフォールバック
|
||||
- Session Manager 検索時にセッションタイトルとメッセージ内のキーワードをハイライト
|
||||
|
||||
### URL ベースのプロバイダーアイコン
|
||||
|
||||
- アイコンシステムにデュアルレンダリングモードを追加: 小さな SVG は React コンポーネントとしてインライン、大きな SVG とラスター画像(PNG / JPG / WebP)は Vite URL import で `<img>` タグとしてロード
|
||||
|
||||
### Kaku ターミナルサポート
|
||||
|
||||
- macOS でセッション起動用の選択可能なターミナルとして Kaku を追加。WezTerm 互換の起動パスを再利用 (#1983, @yovinchen に感謝)
|
||||
|
||||
### OMO Slim Council サポート
|
||||
|
||||
- 内蔵 oh-my-opencode-slim エージェントとしての council のファーストクラスサポートを復元。メタデータと UI コピーを更新 (#1982, @yovinchen に感謝)
|
||||
|
||||
### 新プロバイダープリセット
|
||||
|
||||
- **TheRouter**: Claude / Codex / Gemini / OpenCode / OpenClaw の 5 アプリに追加 (#1891, #1892, @cmzz に感謝)
|
||||
- **DDSHub**: Claude のサードパーティパートナープロバイダーとして追加。アイコンとパートナープロモーションテキスト付き
|
||||
- **LionCCAPI**: 5 アプリすべてに追加。OpenCode / OpenClaw は anthropic-messages プロトコルを使用
|
||||
- **Shengsuanyun(胜算云)**: アグリゲーターパートナープロバイダーとして 5 アプリすべてに追加。URL ベースのアイコンとローカライズ名をサポート
|
||||
- **PIPELLM**: Claude / Codex / OpenCode / OpenClaw に追加。完全なモデル定義とアイコン付き
|
||||
- **E-FlowCode**: 5 アプリすべてに追加。アプリごとに異なるプロトコル設定
|
||||
|
||||
---
|
||||
|
||||
@@ -263,6 +314,31 @@ Claude Code で Copilot リバースプロキシ経由時、中国語文字や
|
||||
- Bedrock エラーメッセージを修正
|
||||
- OpenCode デフォルト `baseURL` のフォールバック処理を修正
|
||||
|
||||
### プロバイダー切り替え時の重複 Toast
|
||||
|
||||
- プロキシ未実行時に Copilot / ChatGPT / OpenAI フォーマットプロバイダーに切り替えた際の二重 toast 通知(プロキシ必要警告 + 切り替え成功)を修正
|
||||
|
||||
### セッション検索精度と中国語サポート
|
||||
|
||||
- プロバイダーをまたぐセッション検索結果の切り詰めを修正
|
||||
- FlexSearch トークナイザーを full モードに切り替え、中国語サブストリングマッチングを正しく動作させる
|
||||
|
||||
### 適応的思考の推論エフォート
|
||||
|
||||
- `resolve_reasoning_effort()` が適応的思考を `high` ではなく正しく `xhigh` にマッピングするよう修正(OpenAI フォーマット変換時)
|
||||
|
||||
### Thinking モデルフォールバック表示
|
||||
|
||||
- Claude プロバイダーフォームでメインモデルのみ保存後に Thinking モデルフィールドが空で表示される問題を修正。ANTHROPIC_MODEL への読み取り専用フォールバックを適用 (#1984, @yovinchen に感謝)
|
||||
|
||||
### Auth タブのローカライゼーション
|
||||
|
||||
- 設定の auth タブラベルに不足していた i18n 翻訳キーをすべてのロケールバンドルで修正 (#1985, @yovinchen に感謝)
|
||||
|
||||
### スキーマ移行ガード
|
||||
|
||||
- skills または model_pricing テーブルが存在しない場合にデータベース移行が失敗する問題を修正。ALTER および UPDATE 操作の前にテーブル存在チェックを追加
|
||||
|
||||
---
|
||||
|
||||
## ドキュメント
|
||||
@@ -282,16 +358,20 @@ Claude Code で Copilot リバースプロキシ経由時、中国語文字や
|
||||
|
||||
- v3.12.3 の release notes に Copilot リバースプロキシのリスク通知とハイライトリンクのアンカーを 3 言語すべてに追加
|
||||
|
||||
### スポンサーパートナー
|
||||
|
||||
- README の 3 言語すべてに Shengsuanyun、LionCC、DDS をスポンサーパートナーとして追加
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ リスクに関する注意事項
|
||||
|
||||
**Codex OAuth リバースプロキシに関する免責事項**
|
||||
|
||||
本リリースで追加された Codex OAuth リバースプロキシ機能は、リバースエンジニアリングによる OAuth フローを通じて ChatGPT Plus / Pro の Codex サービスにアクセスします。この機能を有効にする前に、以下のリスクをご確認ください:
|
||||
本リリースで追加された Codex OAuth リバースプロキシ機能は、リバースエンジニアリングによる OAuth フローを通じて ChatGPT の Codex サービスにアクセスします。この機能を有効にする前に、以下のリスクをご確認ください:
|
||||
|
||||
1. **利用規約違反の可能性**: リバースエンジニアリングされた OAuth フローを使用して OpenAI サービスにアクセスすることは、OpenAI の利用規約に違反する可能性があります。これらの規約では、未承認の自動アクセス、サービス複製、および意図されたアクセスパスの回避が禁止されています。
|
||||
2. **アカウントリスク**: OpenAI は異常な使用パターンを疑わしい自動化活動としてフラグ付けし、ChatGPT Plus / Pro へのアクセスに一時的または永久的な制限を科す可能性があります。
|
||||
2. **アカウントリスク**: OpenAI は異常な使用パターンを疑わしい自動化活動としてフラグ付けし、ChatGPT へのアクセスに一時的または永久的な制限を科す可能性があります。
|
||||
3. **将来の利用保証なし**: OpenAI は認証および検出メカニズムをいつでも更新する可能性があり、現在動作する使用パターンが将来的にフラグ付けされる可能性があります。
|
||||
|
||||
v3.12.3 で導入された **GitHub Copilot リバースプロキシ**も、既存のリスク通知の対象となります — 詳細は [v3.12.3 リリースノート](v3.12.3-ja.md#️-リスクに関する注意事項) を参照してください。
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
|
||||
## 概览
|
||||
|
||||
CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供应商工作流与代理兼容性。本版本在各主要供应商卡片上新增了**配额与余额展示**,覆盖 Claude / Codex / Gemini 官方订阅、Token Plan(Kimi / Zhipu GLM / MiniMax)、Copilot premium interactions 以及 DeepSeek / StepFun / SiliconFlow / OpenRouter / Novita AI 等第三方余额查询;引入了**轻量模式**,让 CC Switch 可以仅驻留在系统托盘中运行;通过 OpenAI 兼容的 `/v1/models` 端点在 Claude / Codex / Gemini / OpenCode / OpenClaw 五个应用的供应商表单中实现了**模型自动发现**;为 ChatGPT Plus / Pro 订阅者提供了 **Codex OAuth 反向代理**;将托盘菜单重构为**按应用分级的子菜单**;将代理转发层重建在 **Hyper 客户端**之上;并完成了 **Skills 工作流**的发现、批量更新和存储位置切换改造。其他改进还包括完整 URL 端点模式、无需代理拦截的会话日志用量追踪、Copilot 调用优化器、多字节 UTF-8 流式分片边界修复以及 Linux 启动时 UI 无响应修复等。
|
||||
CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供应商工作流与代理兼容性。本版本在各主要供应商卡片上新增了**配额与余额展示**,覆盖 Claude / Codex / Gemini 官方订阅、Token Plan(Kimi / Zhipu GLM / MiniMax)、Copilot premium interactions 以及 DeepSeek / StepFun / SiliconFlow / OpenRouter / Novita AI 等第三方余额查询;引入了**轻量模式**,让 CC Switch 可以仅驻留在系统托盘中运行;通过 OpenAI 兼容的 `/v1/models` 端点在 Claude / Codex / Gemini / OpenCode / OpenClaw 五个应用的供应商表单中实现了**模型自动发现**;为 ChatGPT 订阅者提供了 **Codex OAuth 反向代理**;将托盘菜单重构为**按应用分级的子菜单**;将代理转发层重建在 **Hyper 客户端**之上;并完成了 **Skills 工作流**的发现、批量更新和存储位置切换改造,内置了 skills.sh 搜索安装。其他改进还包括完整 URL 端点模式、更完善的 token 用量追踪、Copilot 调用优化器、多字节 UTF-8 流式分片边界修复以及 Linux 启动时 UI 无响应修复,以及更友善的新用户引导等。
|
||||
|
||||
**发布日期**:2026-04-08
|
||||
**发布日期**:2026-04-10
|
||||
|
||||
**更新规模**:98 commits | 229 files changed | +23,891 / -2,305 lines
|
||||
**更新规模**:139 commits | 280 files changed | +31,627 / -3,042 lines
|
||||
|
||||
---
|
||||
|
||||
@@ -21,9 +21,9 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
- **轻量模式**:新增仅托盘运行模式,退出到托盘时销毁主窗口、按需重建,空闲时资源占用接近零
|
||||
- **配额与余额展示**:供应商卡片上直接展示配额或余额 —— 覆盖 Claude / Codex / Gemini 官方订阅、GitHub Copilot premium interactions、Codex OAuth、Token Plan(Kimi / Zhipu GLM / MiniMax),以及 DeepSeek / StepFun / SiliconFlow / OpenRouter / Novita AI 的官方余额查询
|
||||
- **供应商模型自动获取**:为 Claude / Codex / Gemini / OpenCode / OpenClaw 的供应商表单新增 OpenAI 兼容的 `/v1/models` 发现能力,按分组下拉展示并提供针对性错误提示
|
||||
- **Codex OAuth 反向代理**:新增 ChatGPT Plus / Pro 的 Codex 反向代理,作为新的 Claude 供应商卡片类型,包含受管 OAuth 登录流程和订阅配额展示([⚠️ 风险提示](#️-风险提示))
|
||||
- **Codex OAuth 反向代理**:新增 ChatGPT 的 Codex 反向代理,作为新的 Claude 供应商卡片类型,让用户在可以在 Claude Code 里面使用 ChatGPT 订阅。包含受管 OAuth 登录流程和订阅配额展示([⚠️ 风险提示](#️-风险提示))
|
||||
- **托盘按应用分级菜单**:将托盘菜单重构为按应用分组的子菜单,防止供应商多时菜单溢出,让后台切换供应商在大量供应商场景下仍可用
|
||||
- **Skills 发现与批量更新**:基于 SHA-256 内容哈希的更新检测、单项和"全部更新"批量操作、`skills.sh` 公共注册表搜索集成,以及 CC Switch 与 `~/.agents/skills` 的存储位置切换
|
||||
- **Skills 发现与批量更新**:基于 SHA-256 内容哈希的更新检测、单项和"全部更新"批量操作、`skills.sh` 表搜索集成,以及 CC Switch 与 `~/.agents/skills` 的存储位置切换
|
||||
- **会话工作流升级**:会话管理器批量删除、Claude 终端恢复前的目录选择器、无需代理拦截即可导入 Claude / Codex / Gemini 会话日志用量、精确的 Codex JSONL 解析、按应用筛选用量面板
|
||||
- **OpenCode / OpenClaw 流式检测覆盖**:新增 OpenCode 的 npm 包映射检测、OpenClaw `openai-completions` 支持,以及其余所有 OpenClaw 协议变体
|
||||
- **完整 URL 端点模式**:新增将 `base_url` 视作完整上游端点的供应商选项,支持非标准 URL 布局的厂商
|
||||
@@ -31,6 +31,10 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
- **Copilot 调用优化器**:新增请求分类和路由逻辑,降低 GitHub Copilot premium interaction 的不必要消耗
|
||||
- **UTF-8 流式分片边界修复**:所有 4 条 SSE 流式路径改为跨分片保留残留多字节序列,消除 Copilot 反代下中文/emoji 乱码
|
||||
- **Linux 启动 UI 修复**:修复长期存在的 Linux 窗口初次无法响应点击、需用户手动最大化再还原才能操作的问题
|
||||
- **首次运行引导**:新安装时弹出一次性欢迎对话框、自动种入 Claude / OpenAI / Google 官方预设、启动时自动导入 OpenCode / OpenClaw 的 live 配置
|
||||
- **Claude 会话标题与搜索高亮**:从 Claude 会话中提取有意义的标题(自定义标题 → 首条用户消息 → 目录名),在会话管理器搜索时高亮匹配关键词
|
||||
- **URL 图标支持**:图标系统新增双渲染模式,大 SVG 和光栅图片(PNG / JPG / WebP)通过 Vite URL import 加载,小 SVG 保持内联
|
||||
- **新供应商预设**:新增 TheRouter、DDSHub、LionCCAPI、胜算云、PIPELLM、E-FlowCode 预设
|
||||
|
||||
---
|
||||
|
||||
@@ -50,9 +54,9 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
|
||||
- **官方订阅**:Claude / Codex / Gemini 官方供应商的订阅配额展示
|
||||
- **GitHub Copilot**:在 Copilot 供应商卡片上显示 premium interactions 剩余量
|
||||
- **Codex OAuth**:在 Codex OAuth 卡片上内联展示 ChatGPT Plus / Pro 订阅配额
|
||||
- **Token Plan 供应商**:Kimi、Zhipu GLM、MiniMax,修正配额数学与 0% → 100% 用量进度
|
||||
- **第三方余额**:为 DeepSeek、StepFun、SiliconFlow、OpenRouter、Novita AI 提供官方余额查询
|
||||
- **Codex OAuth**:在 Codex OAuth 卡片上内联展示 ChatGPT 订阅配额
|
||||
- **Token Plan 供应商**:Kimi、Zhipu GLM、MiniMax 用量进度显示(为避免混淆,需要手动开启)
|
||||
- **第三方余额**:为 DeepSeek、StepFun、SiliconFlow、OpenRouter、Novita AI 提供官方余额查询(为避免混淆,需要手动开启)
|
||||
- 官方供应商的健康检查和用量配置按钮自动隐藏,保持卡片简洁
|
||||
|
||||
### 供应商模型自动获取
|
||||
@@ -66,13 +70,12 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
|
||||
### Codex OAuth 反向代理
|
||||
|
||||
新增 ChatGPT Plus / Pro 订阅者的 Codex OAuth 反向代理路径,让 ChatGPT 订阅者可以在 Claude Code 中使用自己的订阅。
|
||||
新增 ChatGPT 订阅者的 Codex OAuth 反向代理路径,让 ChatGPT 订阅者可以在 Claude Code 中使用自己的订阅。
|
||||
|
||||
- 受管 OAuth 登录流程,通过 ChatGPT Plus / Pro 认证
|
||||
- 受管 OAuth 登录流程,通过 ChatGPT 认证
|
||||
- 作为新的 Claude 供应商卡片类型出现在列表中,与 API-key 型供应商并列
|
||||
- 订阅配额内联展示
|
||||
- 与 Auth Center UI 紧密集成,统一管理 Token
|
||||
- Codex OAuth 预设升级到 GPT-5.4 系列
|
||||
- 启用前请参见下文的 [⚠️ 风险提示](#️-风险提示)
|
||||
|
||||
### 托盘按应用分级菜单
|
||||
@@ -131,6 +134,54 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
- 根据请求意图和权重进行分类
|
||||
- 将低价值请求路由到非 premium 通道
|
||||
- 旨在延长 Copilot 订阅的可用时长
|
||||
- 注意,即使优化过消耗以后,在 Copilot 外使用 Copilot 的 API 消耗仍然会高于在 Copilot 内使用。
|
||||
|
||||
### 首次运行欢迎对话框
|
||||
|
||||
新安装用户首次打开时显示一次性欢迎对话框,引导了解 CC Switch 工作流程。
|
||||
|
||||
- 说明已有 live 配置如何被保留为默认供应商
|
||||
- 介绍内置官方预设如何实现一键回滚到官方端点
|
||||
- 升级用户通过空供应商检查自动跳过
|
||||
|
||||
### 官方供应商自动种入
|
||||
|
||||
- 启动时自动种入 Claude Official / OpenAI Official / Google Official 供应商条目,为每位用户提供一键回滚到官方端点的路径
|
||||
|
||||
### OpenCode / OpenClaw 自动导入
|
||||
|
||||
- 启动时自动导入 OpenCode 和 OpenClaw 的 live 供应商配置,与 Claude / Codex / Gemini 已有的自动导入行为对齐
|
||||
|
||||
### Common Config 编辑器引导
|
||||
|
||||
- 在 Claude / Codex / Gemini 的 Common Config 代码片段编辑器弹窗中添加引导信息和空状态提示
|
||||
- 用户首次打开供应商添加/编辑表单时弹出一次性对话框说明 Common Config Snippets
|
||||
|
||||
### Claude 会话标题与搜索高亮
|
||||
|
||||
- 为 Claude 会话新增有意义的标题提取,优先链:自定义标题元数据 → 首条真实用户消息 → 目录名回退
|
||||
- 在会话管理器搜索时高亮匹配关键词
|
||||
|
||||
### URL 图标支持
|
||||
|
||||
- 图标系统新增双渲染模式:小 SVG 以 React 组件内联,大 SVG 和光栅图片(PNG / JPG / WebP)通过 Vite URL import 以 `<img>` 标签加载
|
||||
|
||||
### Kaku 终端支持
|
||||
|
||||
- macOS 上新增 Kaku 作为可选终端用于启动会话,复用 WezTerm 兼容的启动路径 (#1983, 感谢 @yovinchen)
|
||||
|
||||
### OMO Slim Council 支持
|
||||
|
||||
- 恢复 council 作为内置 oh-my-opencode-slim agent 的一等支持,更新元数据和 UI 文案 (#1982, 感谢 @yovinchen)
|
||||
|
||||
### 新供应商预设
|
||||
|
||||
- **TheRouter**:覆盖 Claude / Codex / Gemini / OpenCode / OpenClaw 五个应用 (#1891, #1892, 感谢 @cmzz)
|
||||
- **DDSHub**:作为 Claude 的第三方合作伙伴供应商,含图标和推广文案
|
||||
- **LionCCAPI**:覆盖全部五个应用,OpenCode / OpenClaw 使用 anthropic-messages 协议
|
||||
- **胜算云 (Shengsuanyun)**:作为聚合类合作伙伴供应商覆盖全部五个应用,支持 URL 图标和本地化名称
|
||||
- **PIPELLM**:覆盖 Claude / Codex / OpenCode / OpenClaw,含完整模型定义和图标
|
||||
- **E-FlowCode**:覆盖全部五个应用,按应用配置不同协议
|
||||
|
||||
---
|
||||
|
||||
@@ -264,6 +315,31 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
- 修复 Bedrock 错误消息
|
||||
- 修复 OpenCode 默认 `baseURL` 回退处理
|
||||
|
||||
### 供应商切换时重复 Toast
|
||||
|
||||
- 修复代理未运行时切换到 Copilot / ChatGPT / OpenAI 格式供应商时出现双重 toast 通知(代理必需警告 + 切换成功)
|
||||
|
||||
### 会话搜索精度与中文支持
|
||||
|
||||
- 修复会话搜索结果在跨供应商时被截断的问题
|
||||
- 将 FlexSearch 分词器切换为 full 模式以支持中文子串匹配
|
||||
|
||||
### 自适应思维推理力度
|
||||
|
||||
- 修复 `resolve_reasoning_effort()` 将自适应思维错误映射为 `high`,应为 `xhigh`(OpenAI 格式转换场景)
|
||||
|
||||
### Thinking 模型回退显示
|
||||
|
||||
- 修复 Claude 供应商表单仅填写主模型后 Thinking 模型字段显示为空,改为只读回退到 ANTHROPIC_MODEL (#1984, 感谢 @yovinchen)
|
||||
|
||||
### Auth Tab 本地化
|
||||
|
||||
- 修复设置面板 auth tab 标签在所有语言包中缺失 i18n 翻译 key (#1985, 感谢 @yovinchen)
|
||||
|
||||
### 数据库迁移守卫
|
||||
|
||||
- 修复 skills 或 model_pricing 表不存在时数据库迁移失败,在 ALTER 和 UPDATE 操作前添加表存在性检查
|
||||
|
||||
---
|
||||
|
||||
## 文档
|
||||
@@ -283,16 +359,20 @@ CC Switch v3.13.0 是一次重要的功能版本,聚焦于可观测性、供
|
||||
|
||||
- 在三语 v3.12.3 release notes 中新增 Copilot 反代风险提示,并为重点内容添加锚点链接
|
||||
|
||||
### 赞助商合作伙伴
|
||||
|
||||
- 在三语 README 中新增胜算云、LionCC、DDS 作为赞助商合作伙伴
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 风险提示
|
||||
|
||||
**Codex OAuth 反向代理免责声明**
|
||||
|
||||
本版本新增的 Codex OAuth 反向代理功能通过逆向工程的 OAuth 流程访问 ChatGPT Plus / Pro 的 Codex 服务。启用此功能前,请注意以下风险:
|
||||
本版本新增的 Codex OAuth 反向代理功能通过逆向工程的 OAuth 流程访问 ChatGPT 的 Codex 服务。启用此功能前,请注意以下风险:
|
||||
|
||||
1. **违反服务条款**:使用逆向 OAuth 流程访问 OpenAI 服务可能违反 OpenAI 的服务条款,其中禁止未经授权的自动化访问、服务复制以及绕过既定的访问路径。
|
||||
2. **账号风险**:OpenAI 可能将异常使用模式标记为可疑的自动化行为,从而对 ChatGPT Plus / Pro 访问施加临时或永久限制。
|
||||
2. **账号风险**:OpenAI 可能将异常使用模式标记为可疑的自动化行为,从而对 ChatGPT 访问施加临时或永久限制。
|
||||
3. **无法保证长期可用**:OpenAI 可能随时更新其认证和检测机制,当前可用的使用方式未来可能被标记。
|
||||
|
||||
v3.12.3 引入的 **GitHub Copilot 反向代理**同样适用原有风险提示 —— 详见 [v3.12.3 release notes](v3.12.3-zh.md#️-风险提示)。
|
||||
@@ -307,26 +387,26 @@ v3.12.3 引入的 **GitHub Copilot 反向代理**同样适用原有风险提示
|
||||
|
||||
### 系统要求
|
||||
|
||||
| 系统 | 最低版本 | 架构 |
|
||||
| ------- | ----------------------------- | ----------------------------------- |
|
||||
| Windows | Windows 10 及以上 | x64 |
|
||||
| macOS | macOS 12 (Monterey) 及以上 | Intel (x64) / Apple Silicon (arm64) |
|
||||
| Linux | 见下表 | x64 |
|
||||
| 系统 | 最低版本 | 架构 |
|
||||
| ------- | -------------------------- | ----------------------------------- |
|
||||
| Windows | Windows 10 及以上 | x64 |
|
||||
| macOS | macOS 12 (Monterey) 及以上 | Intel (x64) / Apple Silicon (arm64) |
|
||||
| Linux | 见下表 | x64 |
|
||||
|
||||
### Windows
|
||||
|
||||
| 文件 | 说明 |
|
||||
| ------------------------------------------ | ----------------------------------- |
|
||||
| `CC-Switch-v3.13.0-Windows.msi` | **推荐** - MSI 安装包,支持自动更新 |
|
||||
| `CC-Switch-v3.13.0-Windows-Portable.zip` | 便携版,解压即用,不写入注册表 |
|
||||
| 文件 | 说明 |
|
||||
| ---------------------------------------- | ----------------------------------- |
|
||||
| `CC-Switch-v3.13.0-Windows.msi` | **推荐** - MSI 安装包,支持自动更新 |
|
||||
| `CC-Switch-v3.13.0-Windows-Portable.zip` | 便携版,解压即用,不写入注册表 |
|
||||
|
||||
### macOS
|
||||
|
||||
| 文件 | 说明 |
|
||||
| ---------------------------------- | --------------------------------------------------------- |
|
||||
| `CC-Switch-v3.13.0-macOS.dmg` | **推荐** - DMG 安装包,拖入 Applications 即可 |
|
||||
| `CC-Switch-v3.13.0-macOS.zip` | 解压后拖入 Applications,Universal Binary |
|
||||
| `CC-Switch-v3.13.0-macOS.tar.gz` | 用于 Homebrew 安装和自动更新 |
|
||||
| 文件 | 说明 |
|
||||
| -------------------------------- | --------------------------------------------- |
|
||||
| `CC-Switch-v3.13.0-macOS.dmg` | **推荐** - DMG 安装包,拖入 Applications 即可 |
|
||||
| `CC-Switch-v3.13.0-macOS.zip` | 解压后拖入 Applications,Universal Binary |
|
||||
| `CC-Switch-v3.13.0-macOS.tar.gz` | 用于 Homebrew 安装和自动更新 |
|
||||
|
||||
> macOS 版本已通过 Apple 代码签名和公证,可直接安装使用。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cc-switch",
|
||||
"version": "3.12.3",
|
||||
"version": "3.13.0",
|
||||
"description": "All-in-One Assistant for Claude Code, Codex & Gemini CLI",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ICONS_DIR = path.join(__dirname, '../src/icons/extracted');
|
||||
const INDEX_FILE = path.join(ICONS_DIR, 'index.ts');
|
||||
const METADATA_FILE = path.join(ICONS_DIR, 'metadata.ts');
|
||||
|
||||
// Known metadata from previous configuration
|
||||
const KNOWN_METADATA = {
|
||||
openai: { name: 'openai', displayName: 'OpenAI', category: 'ai-provider', keywords: ['gpt', 'chatgpt'], defaultColor: '#00A67E' },
|
||||
anthropic: { name: 'anthropic', displayName: 'Anthropic', category: 'ai-provider', keywords: ['claude'], defaultColor: '#D4915D' },
|
||||
claude: { name: 'claude', displayName: 'Claude', category: 'ai-provider', keywords: ['anthropic'], defaultColor: '#D4915D' },
|
||||
google: { name: 'google', displayName: 'Google', category: 'ai-provider', keywords: ['gemini', 'bard'], defaultColor: '#4285F4' },
|
||||
gemini: { name: 'gemini', displayName: 'Gemini', category: 'ai-provider', keywords: ['google'], defaultColor: '#4285F4' },
|
||||
deepseek: { name: 'deepseek', displayName: 'DeepSeek', category: 'ai-provider', keywords: ['deep', 'seek'], defaultColor: '#1E88E5' },
|
||||
moonshot: { name: 'moonshot', displayName: 'Moonshot', category: 'ai-provider', keywords: ['kimi', 'moonshot'], defaultColor: '#6366F1' },
|
||||
kimi: { name: 'kimi', displayName: 'Kimi', category: 'ai-provider', keywords: ['moonshot'], defaultColor: '#6366F1' },
|
||||
stepfun: { name: 'stepfun', displayName: 'StepFun', category: 'ai-provider', keywords: ['stepfun', 'step', 'jieyue', '阶跃星辰'], defaultColor: '#005AFF' },
|
||||
zhipu: { name: 'zhipu', displayName: 'Zhipu AI', category: 'ai-provider', keywords: ['chatglm', 'glm'], defaultColor: '#0F62FE' },
|
||||
minimax: { name: 'minimax', displayName: 'MiniMax', category: 'ai-provider', keywords: ['minimax'], defaultColor: '#FF6B6B' },
|
||||
baidu: { name: 'baidu', displayName: 'Baidu', category: 'ai-provider', keywords: ['ernie', 'wenxin'], defaultColor: '#2932E1' },
|
||||
alibaba: { name: 'alibaba', displayName: 'Alibaba', category: 'ai-provider', keywords: ['qwen', 'tongyi'], defaultColor: '#FF6A00' },
|
||||
tencent: { name: 'tencent', displayName: 'Tencent', category: 'ai-provider', keywords: ['hunyuan'], defaultColor: '#00A4FF' },
|
||||
meta: { name: 'meta', displayName: 'Meta', category: 'ai-provider', keywords: ['facebook', 'llama'], defaultColor: '#0081FB' },
|
||||
microsoft: { name: 'microsoft', displayName: 'Microsoft', category: 'ai-provider', keywords: ['copilot', 'azure'], defaultColor: '#00A4EF' },
|
||||
cohere: { name: 'cohere', displayName: 'Cohere', category: 'ai-provider', keywords: ['cohere'], defaultColor: '#39594D' },
|
||||
perplexity: { name: 'perplexity', displayName: 'Perplexity', category: 'ai-provider', keywords: ['perplexity'], defaultColor: '#20808D' },
|
||||
packycode: { name: 'packycode', displayName: 'PackyCode', category: 'ai-provider', keywords: ['packycode', 'packy', 'packyapi'], defaultColor: 'currentColor' },
|
||||
mistral: { name: 'mistral', displayName: 'Mistral', category: 'ai-provider', keywords: ['mistral'], defaultColor: '#FF7000' },
|
||||
huggingface: { name: 'huggingface', displayName: 'Hugging Face', category: 'ai-provider', keywords: ['huggingface', 'hf'], defaultColor: '#FFD21E' },
|
||||
aws: { name: 'aws', displayName: 'AWS', category: 'cloud', keywords: ['amazon', 'cloud'], defaultColor: '#FF9900' },
|
||||
azure: { name: 'azure', displayName: 'Azure', category: 'cloud', keywords: ['microsoft', 'cloud'], defaultColor: '#0078D4' },
|
||||
huawei: { name: 'huawei', displayName: 'Huawei', category: 'cloud', keywords: ['huawei', 'cloud'], defaultColor: '#FF0000' },
|
||||
cloudflare: { name: 'cloudflare', displayName: 'Cloudflare', category: 'cloud', keywords: ['cloudflare', 'cdn'], defaultColor: '#F38020' },
|
||||
github: { name: 'github', displayName: 'GitHub', category: 'tool', keywords: ['git', 'version control'], defaultColor: '#181717' },
|
||||
gitlab: { name: 'gitlab', displayName: 'GitLab', category: 'tool', keywords: ['git', 'version control'], defaultColor: '#FC6D26' },
|
||||
docker: { name: 'docker', displayName: 'Docker', category: 'tool', keywords: ['container'], defaultColor: '#2496ED' },
|
||||
kubernetes: { name: 'kubernetes', displayName: 'Kubernetes', category: 'tool', keywords: ['k8s', 'container'], defaultColor: '#326CE5' },
|
||||
vscode: { name: 'vscode', displayName: 'VS Code', category: 'tool', keywords: ['editor', 'ide'], defaultColor: '#007ACC' },
|
||||
settings: { name: 'settings', displayName: 'Settings', category: 'other', keywords: ['config', 'preferences'], defaultColor: '#6B7280' },
|
||||
folder: { name: 'folder', displayName: 'Folder', category: 'other', keywords: ['directory'], defaultColor: '#6B7280' },
|
||||
file: { name: 'file', displayName: 'File', category: 'other', keywords: ['document'], defaultColor: '#6B7280' },
|
||||
link: { name: 'link', displayName: 'Link', category: 'other', keywords: ['url', 'hyperlink'], defaultColor: '#6B7280' },
|
||||
};
|
||||
|
||||
// Get all SVG files
|
||||
const files = fs.readdirSync(ICONS_DIR).filter(file => file.endsWith('.svg'));
|
||||
|
||||
console.log(`Found ${files.length} SVG files.`);
|
||||
|
||||
// Generate index.ts
|
||||
const indexContent = `// Auto-generated icon index
|
||||
// Do not edit manually
|
||||
|
||||
export const icons: Record<string, string> = {
|
||||
${files.map(file => {
|
||||
const name = path.basename(file, '.svg');
|
||||
const svg = fs.readFileSync(path.join(ICONS_DIR, file), 'utf-8');
|
||||
const escaped = svg.replace(/`/g, '\\`').replace(/\$/g, '\\$');
|
||||
return ` '${name}': \`${escaped}\`,`;
|
||||
}).join('\n')}
|
||||
};
|
||||
|
||||
export const iconList = Object.keys(icons);
|
||||
|
||||
export function getIcon(name: string): string {
|
||||
return icons[name.toLowerCase()] || '';
|
||||
}
|
||||
|
||||
export function hasIcon(name: string): boolean {
|
||||
return name.toLowerCase() in icons;
|
||||
}
|
||||
`;
|
||||
|
||||
fs.writeFileSync(INDEX_FILE, indexContent);
|
||||
console.log(`Generated ${INDEX_FILE}`);
|
||||
|
||||
// Generate metadata.ts
|
||||
const metadataEntries = files.map(file => {
|
||||
const name = path.basename(file, '.svg').toLowerCase();
|
||||
const known = KNOWN_METADATA[name];
|
||||
|
||||
if (known) {
|
||||
return ` ${name}: ${JSON.stringify(known)},`;
|
||||
}
|
||||
|
||||
// Default metadata for unknown icons
|
||||
return ` '${name}': { name: '${name}', displayName: '${name}', category: 'other', keywords: [], defaultColor: 'currentColor' },`;
|
||||
});
|
||||
|
||||
const metadataContent = `// Icon metadata for search and categorization
|
||||
import { IconMetadata } from '@/types/icon';
|
||||
|
||||
export const iconMetadata: Record<string, IconMetadata> = {
|
||||
${metadataEntries.join('\n')}
|
||||
};
|
||||
|
||||
export function getIconMetadata(name: string): IconMetadata | undefined {
|
||||
return iconMetadata[name.toLowerCase()];
|
||||
}
|
||||
|
||||
export function searchIcons(query: string): string[] {
|
||||
const lowerQuery = query.toLowerCase();
|
||||
return Object.values(iconMetadata)
|
||||
.filter(meta =>
|
||||
meta.name.includes(lowerQuery) ||
|
||||
meta.displayName.toLowerCase().includes(lowerQuery) ||
|
||||
meta.keywords.some(k => k.includes(lowerQuery))
|
||||
)
|
||||
.map(meta => meta.name);
|
||||
}
|
||||
`;
|
||||
|
||||
fs.writeFileSync(METADATA_FILE, metadataContent);
|
||||
console.log(`Generated ${METADATA_FILE}`);
|
||||
@@ -735,7 +735,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc-switch"
|
||||
version = "3.12.3"
|
||||
version = "3.13.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arboard",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "cc-switch"
|
||||
version = "3.12.3"
|
||||
version = "3.13.0"
|
||||
description = "All-in-One Assistant for Claude Code, Codex & Gemini CLI"
|
||||
authors = ["Jason Young"]
|
||||
license = "MIT"
|
||||
|
||||
@@ -948,6 +948,7 @@ exec bash --norc --noprofile
|
||||
"kitty" => launch_macos_open_app("kitty", &script_file, false),
|
||||
"ghostty" => launch_macos_open_app("Ghostty", &script_file, true),
|
||||
"wezterm" => launch_macos_open_app("WezTerm", &script_file, true),
|
||||
"kaku" => launch_macos_open_app("Kaku", &script_file, true),
|
||||
_ => launch_macos_terminal_app(&script_file), // "terminal" or default
|
||||
};
|
||||
|
||||
|
||||
@@ -282,9 +282,9 @@ pub struct ProviderMeta {
|
||||
/// 是否将 base_url 视为完整 API 端点(不拼接 endpoint 路径)
|
||||
#[serde(rename = "isFullUrl", skip_serializing_if = "Option::is_none")]
|
||||
pub is_full_url: Option<bool>,
|
||||
/// Prompt cache key for OpenAI-compatible endpoints.
|
||||
/// When set, injected into converted requests to improve cache hit rate.
|
||||
/// If not set, provider ID is used automatically during format conversion.
|
||||
/// Prompt cache key for OpenAI Responses-compatible endpoints.
|
||||
/// When set, injected into converted Responses requests to improve cache hit rate.
|
||||
/// If not set, provider ID is used automatically during Claude -> Responses conversion.
|
||||
#[serde(rename = "promptCacheKey", skip_serializing_if = "Option::is_none")]
|
||||
pub prompt_cache_key: Option<String>,
|
||||
/// 累加模式应用中,该 provider 是否已写入 live config。
|
||||
|
||||
@@ -81,14 +81,13 @@ pub fn transform_claude_request_for_api_format(
|
||||
provider: &Provider,
|
||||
api_format: &str,
|
||||
) -> Result<serde_json::Value, ProxyError> {
|
||||
let cache_key = provider
|
||||
.meta
|
||||
.as_ref()
|
||||
.and_then(|m| m.prompt_cache_key.as_deref())
|
||||
.unwrap_or(&provider.id);
|
||||
|
||||
match api_format {
|
||||
"openai_responses" => {
|
||||
let cache_key = provider
|
||||
.meta
|
||||
.as_ref()
|
||||
.and_then(|m| m.prompt_cache_key.as_deref())
|
||||
.unwrap_or(&provider.id);
|
||||
// Codex OAuth (ChatGPT Plus/Pro 反代) 需要在请求体里强制 store: false
|
||||
// + include: ["reasoning.encrypted_content"],由 transform 层统一处理。
|
||||
let is_codex_oauth = provider
|
||||
@@ -102,7 +101,7 @@ pub fn transform_claude_request_for_api_format(
|
||||
is_codex_oauth,
|
||||
)
|
||||
}
|
||||
"openai_chat" => super::transform::anthropic_to_openai(body, Some(cache_key)),
|
||||
"openai_chat" => super::transform::anthropic_to_openai(body),
|
||||
_ => Ok(body),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ pub fn supports_reasoning_effort(model: &str) -> bool {
|
||||
/// `low`/`medium`/`high` map 1:1; `max` maps to `xhigh`
|
||||
/// (supported by mainstream GPT models). Unknown values are ignored.
|
||||
/// 2. Fallback: `thinking.type` + `budget_tokens`:
|
||||
/// - `adaptive` → `high` (mirrors optimizer semantics where adaptive ≈ max effort)
|
||||
/// - `adaptive` → `xhigh` (adaptive = maximum reasoning effort)
|
||||
/// - `enabled` with budget → `low` (<4 000) / `medium` (4 000–15 999) / `high` (≥16 000)
|
||||
/// - `enabled` without budget → `high` (conservative default)
|
||||
/// - `disabled` / absent → `None`
|
||||
@@ -57,7 +57,7 @@ pub fn resolve_reasoning_effort(body: &Value) -> Option<&'static str> {
|
||||
// --- Priority 2: thinking.type + budget_tokens fallback ---
|
||||
let thinking = body.get("thinking")?;
|
||||
match thinking.get("type").and_then(|t| t.as_str()) {
|
||||
Some("adaptive") => Some("high"),
|
||||
Some("adaptive") => Some("xhigh"),
|
||||
Some("enabled") => {
|
||||
let budget = thinking.get("budget_tokens").and_then(|b| b.as_u64());
|
||||
match budget {
|
||||
@@ -71,10 +71,8 @@ pub fn resolve_reasoning_effort(body: &Value) -> Option<&'static str> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Anthropic 请求 → OpenAI 请求
|
||||
///
|
||||
/// `cache_key`: optional prompt_cache_key to inject for improved cache routing
|
||||
pub fn anthropic_to_openai(body: Value, cache_key: Option<&str>) -> Result<Value, ProxyError> {
|
||||
/// Anthropic 请求 → OpenAI Chat Completions 请求
|
||||
pub fn anthropic_to_openai(body: Value) -> Result<Value, ProxyError> {
|
||||
let mut result = json!({});
|
||||
|
||||
// NOTE: 模型映射由上游统一处理(proxy::model_mapper),格式转换层只做结构转换。
|
||||
@@ -175,11 +173,6 @@ pub fn anthropic_to_openai(body: Value, cache_key: Option<&str>) -> Result<Value
|
||||
result["tool_choice"] = v.clone();
|
||||
}
|
||||
|
||||
// Inject prompt_cache_key for improved cache routing on OpenAI-compatible endpoints
|
||||
if let Some(key) = cache_key {
|
||||
result["prompt_cache_key"] = json!(key);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -569,7 +562,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["model"], "claude-3-opus");
|
||||
assert_eq!(result["max_tokens"], 1024);
|
||||
assert_eq!(result["messages"][0]["role"], "user");
|
||||
@@ -585,7 +578,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["messages"][0]["role"], "system");
|
||||
assert_eq!(
|
||||
result["messages"][0]["content"],
|
||||
@@ -607,7 +600,7 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["tools"][0]["type"], "function");
|
||||
assert_eq!(result["tools"][0]["function"]["name"], "get_weather");
|
||||
}
|
||||
@@ -627,7 +620,7 @@ mod tests {
|
||||
]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["messages"].as_array().unwrap().len(), 2);
|
||||
assert_eq!(result["messages"][0]["role"], "system");
|
||||
assert_eq!(
|
||||
@@ -651,7 +644,7 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
let msg = &result["messages"][0];
|
||||
assert_eq!(msg["role"], "assistant");
|
||||
assert!(msg.get("tool_calls").is_some());
|
||||
@@ -671,7 +664,7 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
let msg = &result["messages"][0];
|
||||
assert_eq!(msg["role"], "tool");
|
||||
assert_eq!(msg["tool_call_id"], "call_123");
|
||||
@@ -743,31 +736,19 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["model"], "gpt-4o");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_openai_with_cache_key() {
|
||||
fn test_anthropic_to_openai_does_not_inject_prompt_cache_key() {
|
||||
let input = json!({
|
||||
"model": "claude-3-opus",
|
||||
"max_tokens": 1024,
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, Some("provider-123")).unwrap();
|
||||
assert_eq!(result["prompt_cache_key"], "provider-123");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anthropic_to_openai_no_cache_key() {
|
||||
let input = json!({
|
||||
"model": "claude-3-opus",
|
||||
"max_tokens": 1024,
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert!(result.get("prompt_cache_key").is_none());
|
||||
}
|
||||
|
||||
@@ -793,7 +774,7 @@ mod tests {
|
||||
}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
// System message cache_control preserved
|
||||
assert_eq!(result["messages"][0]["cache_control"]["type"], "ephemeral");
|
||||
// Text block cache_control preserved
|
||||
@@ -1019,9 +1000,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_thinking_adaptive_maps_high() {
|
||||
fn test_thinking_adaptive_maps_xhigh() {
|
||||
let body = json!({"thinking": {"type": "adaptive"}});
|
||||
assert_eq!(resolve_reasoning_effort(&body), Some("high"));
|
||||
assert_eq!(resolve_reasoning_effort(&body), Some("xhigh"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1047,7 +1028,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert!(result.get("reasoning_effort").is_none());
|
||||
}
|
||||
|
||||
@@ -1060,7 +1041,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["reasoning_effort"], "medium");
|
||||
}
|
||||
|
||||
@@ -1073,7 +1054,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["reasoning_effort"], "xhigh");
|
||||
}
|
||||
|
||||
@@ -1086,7 +1067,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["reasoning_effort"], "low");
|
||||
}
|
||||
|
||||
@@ -1099,8 +1080,8 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
assert_eq!(result["reasoning_effort"], "high");
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["reasoning_effort"], "xhigh");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1111,7 +1092,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert!(result.get("reasoning_effort").is_none());
|
||||
}
|
||||
|
||||
@@ -1124,7 +1105,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert!(
|
||||
result.get("max_tokens").is_none(),
|
||||
"{model} should not have max_tokens"
|
||||
@@ -1144,7 +1125,7 @@ mod tests {
|
||||
"messages": [{"role": "user", "content": "Hello"}]
|
||||
});
|
||||
|
||||
let result = anthropic_to_openai(input, None).unwrap();
|
||||
let result = anthropic_to_openai(input).unwrap();
|
||||
assert_eq!(result["max_tokens"], 1024);
|
||||
assert!(result.get("max_completion_tokens").is_none());
|
||||
}
|
||||
|
||||
@@ -1047,7 +1047,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_responses_thinking_adaptive_sets_reasoning_high() {
|
||||
fn test_responses_thinking_adaptive_sets_reasoning_xhigh() {
|
||||
let input = json!({
|
||||
"model": "gpt-5.4",
|
||||
"max_tokens": 1024,
|
||||
@@ -1056,7 +1056,7 @@ mod tests {
|
||||
});
|
||||
|
||||
let result = anthropic_to_responses(input, None, false).unwrap();
|
||||
assert_eq!(result["reasoning"]["effort"], "high");
|
||||
assert_eq!(result["reasoning"]["effort"], "xhigh");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -372,7 +372,7 @@ impl StreamCheckService {
|
||||
anthropic_to_responses(anthropic_body, Some(&provider.id), is_codex_oauth)
|
||||
.map_err(|e| AppError::Message(format!("Failed to build test request: {e}")))?
|
||||
} else if is_openai_chat {
|
||||
anthropic_to_openai(anthropic_body, Some(&provider.id))
|
||||
anthropic_to_openai(anthropic_body)
|
||||
.map_err(|e| AppError::Message(format!("Failed to build test request: {e}")))?
|
||||
} else {
|
||||
anthropic_body
|
||||
|
||||
@@ -20,6 +20,7 @@ pub fn launch_terminal(
|
||||
"ghostty" => launch_ghostty(command, cwd),
|
||||
"kitty" => launch_kitty(command, cwd),
|
||||
"wezterm" => launch_wezterm(command, cwd),
|
||||
"kaku" => launch_kaku(command, cwd),
|
||||
"alacritty" => launch_alacritty(command, cwd),
|
||||
"custom" => launch_custom(command, cwd, custom_config),
|
||||
_ => Err(format!("Unsupported terminal target: {target}")),
|
||||
@@ -153,25 +154,10 @@ fn launch_kitty(command: &str, cwd: Option<&str>) -> Result<(), String> {
|
||||
fn launch_wezterm(command: &str, cwd: Option<&str>) -> Result<(), String> {
|
||||
// wezterm start --cwd ... -- command
|
||||
// To invoke via `open`, we use `open -na "WezTerm" --args start ...`
|
||||
|
||||
let full_command = build_shell_command(command, None);
|
||||
|
||||
let mut args = vec!["-na", "WezTerm", "--args", "start"];
|
||||
|
||||
if let Some(dir) = cwd {
|
||||
args.push("--cwd");
|
||||
args.push(dir);
|
||||
}
|
||||
|
||||
// Invoke shell to run the command string (to handle pipes, etc)
|
||||
let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string());
|
||||
args.push("--");
|
||||
args.push(&shell);
|
||||
args.push("-c");
|
||||
args.push(&full_command);
|
||||
let args = build_wezterm_compatible_args("WezTerm", command, cwd);
|
||||
|
||||
let status = Command::new("open")
|
||||
.args(&args)
|
||||
.args(args.iter().map(String::as_str))
|
||||
.status()
|
||||
.map_err(|e| format!("Failed to launch WezTerm: {e}"))?;
|
||||
|
||||
@@ -182,6 +168,54 @@ fn launch_wezterm(command: &str, cwd: Option<&str>) -> Result<(), String> {
|
||||
}
|
||||
}
|
||||
|
||||
fn launch_kaku(command: &str, cwd: Option<&str>) -> Result<(), String> {
|
||||
// Kaku is a WezTerm-derived terminal and keeps a compatible `start` entrypoint.
|
||||
let args = build_wezterm_compatible_args("Kaku", command, cwd);
|
||||
|
||||
let status = Command::new("open")
|
||||
.args(args.iter().map(String::as_str))
|
||||
.status()
|
||||
.map_err(|e| format!("Failed to launch Kaku: {e}"))?;
|
||||
|
||||
if status.success() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Failed to launch Kaku.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn build_wezterm_compatible_args(app_name: &str, command: &str, cwd: Option<&str>) -> Vec<String> {
|
||||
let shell = std::env::var("SHELL").unwrap_or_else(|_| "/bin/zsh".to_string());
|
||||
build_wezterm_compatible_args_with_shell(app_name, command, cwd, &shell)
|
||||
}
|
||||
|
||||
fn build_wezterm_compatible_args_with_shell(
|
||||
app_name: &str,
|
||||
command: &str,
|
||||
cwd: Option<&str>,
|
||||
shell: &str,
|
||||
) -> Vec<String> {
|
||||
let full_command = build_shell_command(command, None);
|
||||
let mut args = vec![
|
||||
"-na".to_string(),
|
||||
app_name.to_string(),
|
||||
"--args".to_string(),
|
||||
"start".to_string(),
|
||||
];
|
||||
|
||||
if let Some(dir) = cwd {
|
||||
args.push("--cwd".to_string());
|
||||
args.push(dir.to_string());
|
||||
}
|
||||
|
||||
// Invoke shell to run the command string (to handle pipes, etc)
|
||||
args.push("--".to_string());
|
||||
args.push(shell.to_string());
|
||||
args.push("-c".to_string());
|
||||
args.push(full_command);
|
||||
args
|
||||
}
|
||||
|
||||
fn launch_alacritty(command: &str, cwd: Option<&str>) -> Result<(), String> {
|
||||
// Alacritty: open -na Alacritty --args --working-directory ... -e shell -c command
|
||||
let full_command = build_shell_command(command, None);
|
||||
@@ -305,4 +339,30 @@ mod tests {
|
||||
"raw:echo foo\\\\\\\\bar\\npwd\\n"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wezterm_compatible_terminals_use_start_and_cwd_arguments() {
|
||||
let args = build_wezterm_compatible_args_with_shell(
|
||||
"Kaku",
|
||||
"claude --resume abc-123",
|
||||
Some("/tmp/project dir"),
|
||||
"/bin/zsh",
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
args,
|
||||
vec![
|
||||
"-na".to_string(),
|
||||
"Kaku".to_string(),
|
||||
"--args".to_string(),
|
||||
"start".to_string(),
|
||||
"--cwd".to_string(),
|
||||
"/tmp/project dir".to_string(),
|
||||
"--".to_string(),
|
||||
"/bin/zsh".to_string(),
|
||||
"-c".to_string(),
|
||||
"claude --resume abc-123".to_string(),
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ pub struct AppSettings {
|
||||
|
||||
// ===== 终端设置 =====
|
||||
/// 首选终端应用(可选,默认使用系统默认终端)
|
||||
/// - macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty"
|
||||
/// - macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty" | "wezterm" | "kaku"
|
||||
/// - Windows: "cmd" | "powershell" | "wt" (Windows Terminal)
|
||||
/// - Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty"
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "CC Switch",
|
||||
"version": "3.12.3",
|
||||
"version": "3.13.0",
|
||||
"identifier": "com.ccswitch.desktop",
|
||||
"build": {
|
||||
"frontendDist": "../dist",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { getIcon, hasIcon, getIconMetadata } from "@/icons/extracted";
|
||||
import {
|
||||
getIcon,
|
||||
hasIcon,
|
||||
getIconMetadata,
|
||||
getIconUrl,
|
||||
isUrlIcon,
|
||||
} from "@/icons/extracted";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface ProviderIconProps {
|
||||
@@ -19,21 +25,28 @@ export const ProviderIcon: React.FC<ProviderIconProps> = ({
|
||||
className,
|
||||
showFallback = true,
|
||||
}) => {
|
||||
// 获取图标 SVG
|
||||
// 获取内联 SVG 字符串
|
||||
const iconSvg = useMemo(() => {
|
||||
if (icon && hasIcon(icon)) {
|
||||
if (icon && !isUrlIcon(icon) && hasIcon(icon)) {
|
||||
return getIcon(icon);
|
||||
}
|
||||
return "";
|
||||
}, [icon]);
|
||||
|
||||
// 获取图标 URL(URL_ICONS 列表中的 SVG / 光栅图片)
|
||||
const iconUrl = useMemo(() => {
|
||||
if (icon && isUrlIcon(icon)) {
|
||||
return getIconUrl(icon);
|
||||
}
|
||||
return "";
|
||||
}, [icon]);
|
||||
|
||||
// 计算尺寸样式
|
||||
const sizeStyle = useMemo(() => {
|
||||
const sizeValue = typeof size === "number" ? `${size}px` : size;
|
||||
return {
|
||||
width: sizeValue,
|
||||
height: sizeValue,
|
||||
// 内嵌 SVG 使用 1em 作为尺寸基准,这里同步 fontSize 让图标实际跟随 size 放大
|
||||
fontSize: sizeValue,
|
||||
lineHeight: 1,
|
||||
};
|
||||
@@ -41,14 +54,11 @@ export const ProviderIcon: React.FC<ProviderIconProps> = ({
|
||||
|
||||
// 获取有效颜色:优先使用传入的有效 color,否则从元数据获取 defaultColor
|
||||
const effectiveColor = useMemo(() => {
|
||||
// 只有当 color 是有效的非空字符串时才使用
|
||||
if (color && typeof color === "string" && color.trim() !== "") {
|
||||
return color;
|
||||
}
|
||||
// 否则从元数据获取 defaultColor
|
||||
if (icon) {
|
||||
const metadata = getIconMetadata(icon);
|
||||
// 只有当 defaultColor 不是 currentColor 时才使用
|
||||
if (metadata?.defaultColor && metadata.defaultColor !== "currentColor") {
|
||||
return metadata.defaultColor;
|
||||
}
|
||||
@@ -56,7 +66,7 @@ export const ProviderIcon: React.FC<ProviderIconProps> = ({
|
||||
return undefined;
|
||||
}, [color, icon]);
|
||||
|
||||
// 如果有图标,显示图标
|
||||
// 内联 SVG 渲染(支持 CSS currentColor 着色)
|
||||
if (iconSvg) {
|
||||
return (
|
||||
<span
|
||||
@@ -70,6 +80,22 @@ export const ProviderIcon: React.FC<ProviderIconProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
// URL-based 图标(大型 SVG / 光栅图片):以 <img> 渲染
|
||||
if (iconUrl) {
|
||||
return (
|
||||
<img
|
||||
src={iconUrl}
|
||||
alt={name}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center flex-shrink-0 object-contain",
|
||||
className,
|
||||
)}
|
||||
style={{ width: sizeStyle.width, height: sizeStyle.height }}
|
||||
loading="lazy"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback:显示首字母
|
||||
if (showFallback) {
|
||||
const initials = name
|
||||
|
||||
@@ -1264,12 +1264,22 @@ export function OmoFormFields({
|
||||
) : undefined,
|
||||
maxHeightClass: "max-h-[500px]",
|
||||
children: (
|
||||
<Textarea
|
||||
value={otherFieldsStr}
|
||||
onChange={(e) => onOtherFieldsStrChange(e.target.value)}
|
||||
placeholder='{ "custom_key": "value" }'
|
||||
className="font-mono text-xs min-h-[60px]"
|
||||
/>
|
||||
<>
|
||||
<Textarea
|
||||
value={otherFieldsStr}
|
||||
onChange={(e) => onOtherFieldsStrChange(e.target.value)}
|
||||
placeholder='{ "custom_key": "value" }'
|
||||
className="font-mono text-xs min-h-[60px]"
|
||||
/>
|
||||
{isSlim && (
|
||||
<p className="mt-1 text-[10px] text-muted-foreground">
|
||||
{t("omo.slimOtherFieldsHint", {
|
||||
defaultValue:
|
||||
"Use this area for top-level OMO Slim config such as council, fallback, multiplexer, disabled_mcps, and todoContinuation.",
|
||||
})}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -14,10 +14,11 @@ function parseModelsFromConfig(settingsConfig: string) {
|
||||
const env = cfg?.env || {};
|
||||
const model =
|
||||
typeof env.ANTHROPIC_MODEL === "string" ? env.ANTHROPIC_MODEL : "";
|
||||
const reasoning =
|
||||
const explicitReasoning =
|
||||
typeof env.ANTHROPIC_REASONING_MODEL === "string"
|
||||
? env.ANTHROPIC_REASONING_MODEL
|
||||
: "";
|
||||
const reasoning = explicitReasoning || model;
|
||||
const small =
|
||||
typeof env.ANTHROPIC_SMALL_FAST_MODEL === "string"
|
||||
? env.ANTHROPIC_SMALL_FAST_MODEL
|
||||
@@ -92,10 +93,11 @@ export function useModelState({
|
||||
const env = cfg?.env || {};
|
||||
const model =
|
||||
typeof env.ANTHROPIC_MODEL === "string" ? env.ANTHROPIC_MODEL : "";
|
||||
const reasoning =
|
||||
const explicitReasoning =
|
||||
typeof env.ANTHROPIC_REASONING_MODEL === "string"
|
||||
? env.ANTHROPIC_REASONING_MODEL
|
||||
: "";
|
||||
const reasoning = explicitReasoning || model;
|
||||
const small =
|
||||
typeof env.ANTHROPIC_SMALL_FAST_MODEL === "string"
|
||||
? env.ANTHROPIC_SMALL_FAST_MODEL
|
||||
@@ -148,16 +150,17 @@ export function useModelState({
|
||||
? JSON.parse(settingsConfig)
|
||||
: { env: {} };
|
||||
if (!currentConfig.env) currentConfig.env = {};
|
||||
const env = currentConfig.env as Record<string, unknown>;
|
||||
|
||||
// 新键仅写入;旧键不再写入
|
||||
const trimmed = value.trim();
|
||||
if (trimmed) {
|
||||
currentConfig.env[field] = trimmed;
|
||||
env[field] = trimmed;
|
||||
} else {
|
||||
delete currentConfig.env[field];
|
||||
delete env[field];
|
||||
}
|
||||
// 删除旧键
|
||||
delete currentConfig.env["ANTHROPIC_SMALL_FAST_MODEL"];
|
||||
delete env["ANTHROPIC_SMALL_FAST_MODEL"];
|
||||
|
||||
onConfigChange(JSON.stringify(currentConfig, null, 2));
|
||||
} catch (err) {
|
||||
|
||||
@@ -16,6 +16,7 @@ const MACOS_TERMINALS = [
|
||||
{ value: "kitty", labelKey: "settings.terminal.options.macos.kitty" },
|
||||
{ value: "ghostty", labelKey: "settings.terminal.options.macos.ghostty" },
|
||||
{ value: "wezterm", labelKey: "settings.terminal.options.macos.wezterm" },
|
||||
{ value: "kaku", labelKey: "settings.terminal.options.macos.kaku" },
|
||||
] as const;
|
||||
|
||||
const WINDOWS_TERMINALS = [
|
||||
|
||||
@@ -80,6 +80,22 @@ export const providerPresets: ProviderPreset[] = [
|
||||
icon: "anthropic",
|
||||
iconColor: "#D4915D",
|
||||
},
|
||||
{
|
||||
name: "Shengsuanyun",
|
||||
nameKey: "providerForm.presets.shengsuanyun",
|
||||
websiteUrl: "https://www.shengsuanyun.com",
|
||||
apiKeyUrl: "https://www.shengsuanyun.com/?from=CH_4HHXMRYF",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "https://router.shengsuanyun.com/api",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
},
|
||||
},
|
||||
category: "aggregator",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "shengsuanyun",
|
||||
icon: "shengsuanyun",
|
||||
},
|
||||
{
|
||||
name: "DeepSeek",
|
||||
websiteUrl: "https://platform.deepseek.com",
|
||||
@@ -634,7 +650,7 @@ export const providerPresets: ProviderPreset[] = [
|
||||
category: "third_party",
|
||||
isPartner: true, // 合作伙伴
|
||||
partnerPromotionKey: "x-code", // 促销信息 i18n key
|
||||
icon: "x-code",
|
||||
icon: "xcode",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
@@ -653,6 +669,58 @@ export const providerPresets: ProviderPreset[] = [
|
||||
icon: "ctok",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "DDSHub",
|
||||
websiteUrl: "https://www.ddshub.cc",
|
||||
apiKeyUrl: "https://ddshub.short.gy/ccswitch",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "https://www.ddshub.cc",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
},
|
||||
},
|
||||
category: "third_party",
|
||||
isPartner: true, // 合作伙伴
|
||||
partnerPromotionKey: "ddshub", // 促销信息 i18n key
|
||||
icon: "dds",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "E-FlowCode",
|
||||
websiteUrl: "https://e-flowcode.cc",
|
||||
apiKeyUrl: "https://e-flowcode.cc",
|
||||
settingsConfig: {
|
||||
effortLevel: "high",
|
||||
env: {
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
ANTHROPIC_BASE_URL: "https://e-flowcode.cc",
|
||||
},
|
||||
enabledPlugins: {
|
||||
"superpowers@superpowers-marketplace": true,
|
||||
},
|
||||
includeCoAuthoredBy: false,
|
||||
ENABLE_TOOL_SEARCH: true,
|
||||
skipWebFetchPreflight: true,
|
||||
},
|
||||
category: "third_party",
|
||||
endpointCandidates: ["https://e-flowcode.cc"],
|
||||
icon: "eflowcode",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "LionCCAPI",
|
||||
websiteUrl: "https://vibecodingapi.ai",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "https://vibecodingapi.ai",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
},
|
||||
},
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "lionccapi",
|
||||
icon: "lioncc",
|
||||
},
|
||||
{
|
||||
name: "OpenRouter",
|
||||
websiteUrl: "https://openrouter.ai",
|
||||
@@ -671,6 +739,24 @@ export const providerPresets: ProviderPreset[] = [
|
||||
icon: "openrouter",
|
||||
iconColor: "#6566F1",
|
||||
},
|
||||
{
|
||||
name: "TheRouter",
|
||||
websiteUrl: "https://therouter.ai",
|
||||
apiKeyUrl: "https://dashboard.therouter.ai",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "https://api.therouter.ai",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
ANTHROPIC_API_KEY: "",
|
||||
ANTHROPIC_MODEL: "anthropic/claude-sonnet-4.6",
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: "anthropic/claude-haiku-4.5",
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL: "anthropic/claude-sonnet-4.6",
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL: "anthropic/claude-opus-4.6",
|
||||
},
|
||||
},
|
||||
category: "aggregator",
|
||||
endpointCandidates: ["https://api.therouter.ai"],
|
||||
},
|
||||
{
|
||||
name: "Novita AI",
|
||||
websiteUrl: "https://novita.ai",
|
||||
@@ -710,7 +796,7 @@ export const providerPresets: ProviderPreset[] = [
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "Codex (ChatGPT Plus/Pro)",
|
||||
name: "Codex",
|
||||
websiteUrl: "https://openai.com/chatgpt/pricing",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
@@ -749,6 +835,24 @@ export const providerPresets: ProviderPreset[] = [
|
||||
icon: "nvidia",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "PIPELLM",
|
||||
websiteUrl: "https://www.pipellm.ai",
|
||||
apiKeyUrl: "https://code.pipellm.ai/login?ref=uvw650za",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
ANTHROPIC_BASE_URL: "https://cc-api.pipellm.ai",
|
||||
ANTHROPIC_AUTH_TOKEN: "",
|
||||
ANTHROPIC_MODEL: "claude-opus-4-6",
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: "claude-haiku-4-5-20251001",
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL: "claude-sonnet-4-6",
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL: "claude-opus-4-6",
|
||||
},
|
||||
includeCoAuthoredBy: false,
|
||||
},
|
||||
category: "aggregator",
|
||||
icon: "pipellm",
|
||||
},
|
||||
{
|
||||
name: "Xiaomi MiMo",
|
||||
websiteUrl: "https://platform.xiaomimimo.com",
|
||||
|
||||
@@ -78,6 +78,22 @@ export const codexProviderPresets: CodexProviderPreset[] = [
|
||||
icon: "openai",
|
||||
iconColor: "#00A67E",
|
||||
},
|
||||
{
|
||||
name: "Shengsuanyun",
|
||||
nameKey: "providerForm.presets.shengsuanyun",
|
||||
websiteUrl: "https://www.shengsuanyun.com",
|
||||
apiKeyUrl: "https://www.shengsuanyun.com/?from=CH_4HHXMRYF",
|
||||
auth: generateThirdPartyAuth(""),
|
||||
config: generateThirdPartyConfig(
|
||||
"shengsuanyun",
|
||||
"https://router.shengsuanyun.com/api/v1",
|
||||
"gpt-5.4",
|
||||
),
|
||||
category: "aggregator",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "shengsuanyun",
|
||||
icon: "shengsuanyun",
|
||||
},
|
||||
{
|
||||
name: "Azure OpenAI",
|
||||
websiteUrl:
|
||||
@@ -331,7 +347,7 @@ requires_openai_auth = true`,
|
||||
category: "third_party",
|
||||
isPartner: true, // 合作伙伴
|
||||
partnerPromotionKey: "x-code", // 促销信息 i18n key
|
||||
icon: "x-code",
|
||||
icon: "xcode",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
@@ -351,6 +367,66 @@ requires_openai_auth = true`,
|
||||
icon: "ctok",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "LionCCAPI",
|
||||
websiteUrl: "https://vibecodingapi.ai",
|
||||
auth: generateThirdPartyAuth(""),
|
||||
config: generateThirdPartyConfig(
|
||||
"lionccapi",
|
||||
"https://vibecodingapi.ai/v1",
|
||||
"gpt-5.4",
|
||||
),
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "lionccapi",
|
||||
icon: "lioncc",
|
||||
},
|
||||
{
|
||||
name: "E-FlowCode",
|
||||
websiteUrl: "https://e-flowcode.cc",
|
||||
apiKeyUrl: "https://e-flowcode.cc",
|
||||
auth: {
|
||||
OPENAI_API_KEY: "",
|
||||
},
|
||||
config: `model_provider = "e-flowcode"
|
||||
model = "gpt-5.4"
|
||||
model_reasoning_effort = "high"
|
||||
disable_response_storage = true
|
||||
personality = "pragmatic"
|
||||
|
||||
[model_providers.e-flowcode]
|
||||
name = "e-flowcode"
|
||||
base_url = "https://e-flowcode.cc/v1"
|
||||
wire_api = "responses"
|
||||
requires_openai_auth = true
|
||||
model_context_window = 1000000
|
||||
model_auto_compact_token_limit = 9000000`,
|
||||
category: "third_party",
|
||||
endpointCandidates: ["https://e-flowcode.cc/v1"],
|
||||
icon: "eflowcode",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "PIPELLM",
|
||||
websiteUrl: "https://www.pipellm.ai",
|
||||
apiKeyUrl: "https://code.pipellm.ai/login?ref=uvw650za",
|
||||
auth: {
|
||||
OPENAI_API_KEY: "",
|
||||
},
|
||||
config: `model_provider = "custom"
|
||||
model = "gpt-5.4"
|
||||
model_reasoning_effort = "medium"
|
||||
disable_response_storage = true
|
||||
|
||||
[model_providers.custom]
|
||||
name = "custom"
|
||||
wire_api = "responses"
|
||||
requires_openai_auth = true
|
||||
base_url = "https://cc-api.pipellm.ai/v1"`,
|
||||
category: "aggregator",
|
||||
endpointCandidates: ["https://cc-api.pipellm.ai/v1"],
|
||||
icon: "pipellm",
|
||||
},
|
||||
{
|
||||
name: "OpenRouter",
|
||||
websiteUrl: "https://openrouter.ai",
|
||||
@@ -365,4 +441,17 @@ requires_openai_auth = true`,
|
||||
icon: "openrouter",
|
||||
iconColor: "#6566F1",
|
||||
},
|
||||
{
|
||||
name: "TheRouter",
|
||||
websiteUrl: "https://therouter.ai",
|
||||
apiKeyUrl: "https://dashboard.therouter.ai",
|
||||
auth: generateThirdPartyAuth(""),
|
||||
config: generateThirdPartyConfig(
|
||||
"therouter",
|
||||
"https://api.therouter.ai/v1",
|
||||
"openai/gpt-5.3-codex",
|
||||
),
|
||||
endpointCandidates: ["https://api.therouter.ai/v1"],
|
||||
category: "aggregator",
|
||||
},
|
||||
];
|
||||
|
||||
@@ -50,6 +50,25 @@ export const geminiProviderPresets: GeminiProviderPreset[] = [
|
||||
icon: "gemini",
|
||||
iconColor: "#4285F4",
|
||||
},
|
||||
{
|
||||
name: "Shengsuanyun",
|
||||
nameKey: "providerForm.presets.shengsuanyun",
|
||||
websiteUrl: "https://www.shengsuanyun.com",
|
||||
apiKeyUrl: "https://www.shengsuanyun.com/?from=CH_4HHXMRYF",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
GOOGLE_GEMINI_BASE_URL: "https://router.shengsuanyun.com/api",
|
||||
GEMINI_MODEL: "gemini-3.1-pro",
|
||||
},
|
||||
},
|
||||
baseURL: "https://router.shengsuanyun.com/api",
|
||||
model: "gemini-3.1-pro",
|
||||
description: "Shengsuanyun",
|
||||
category: "aggregator",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "shengsuanyun",
|
||||
icon: "shengsuanyun",
|
||||
},
|
||||
{
|
||||
name: "PackyCode",
|
||||
websiteUrl: "https://www.packyapi.com",
|
||||
@@ -224,6 +243,58 @@ export const geminiProviderPresets: GeminiProviderPreset[] = [
|
||||
icon: "ctok",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "LionCCAPI",
|
||||
websiteUrl: "https://vibecodingapi.ai",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
GOOGLE_GEMINI_BASE_URL: "https://vibecodingapi.ai",
|
||||
GEMINI_MODEL: "gemini-3.1-pro",
|
||||
},
|
||||
},
|
||||
baseURL: "https://vibecodingapi.ai",
|
||||
model: "gemini-3.1-pro",
|
||||
description: "LionCCAPI",
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "lionccapi",
|
||||
icon: "lioncc",
|
||||
},
|
||||
{
|
||||
name: "E-FlowCode",
|
||||
websiteUrl: "https://e-flowcode.cc",
|
||||
apiKeyUrl: "https://e-flowcode.cc",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
GOOGLE_GEMINI_BASE_URL: "https://e-flowcode.cc",
|
||||
GEMINI_API_KEY: "",
|
||||
GEMINI_MODEL: "gemini-3.1-pro-preview",
|
||||
},
|
||||
config: {
|
||||
general: {
|
||||
previewFeatures: true,
|
||||
sessionRetention: {
|
||||
enabled: true,
|
||||
maxAge: "30d",
|
||||
warningAcknowledged: true,
|
||||
},
|
||||
},
|
||||
mcpServers: {},
|
||||
security: {
|
||||
auth: {
|
||||
selectedType: "gemini-api-key",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
baseURL: "https://e-flowcode.cc",
|
||||
model: "gemini-3.1-pro-preview",
|
||||
description: "E-FlowCode",
|
||||
category: "third_party",
|
||||
endpointCandidates: ["https://e-flowcode.cc"],
|
||||
icon: "eflowcode",
|
||||
iconColor: "#000000",
|
||||
},
|
||||
{
|
||||
name: "OpenRouter",
|
||||
websiteUrl: "https://openrouter.ai",
|
||||
@@ -241,6 +312,22 @@ export const geminiProviderPresets: GeminiProviderPreset[] = [
|
||||
icon: "openrouter",
|
||||
iconColor: "#6566F1",
|
||||
},
|
||||
{
|
||||
name: "TheRouter",
|
||||
websiteUrl: "https://therouter.ai",
|
||||
apiKeyUrl: "https://dashboard.therouter.ai",
|
||||
settingsConfig: {
|
||||
env: {
|
||||
GOOGLE_GEMINI_BASE_URL: "https://api.therouter.ai",
|
||||
GEMINI_MODEL: "gemini-2.5-pro",
|
||||
},
|
||||
},
|
||||
baseURL: "https://api.therouter.ai",
|
||||
model: "gemini-2.5-pro",
|
||||
description: "TheRouter",
|
||||
category: "aggregator",
|
||||
endpointCandidates: ["https://api.therouter.ai"],
|
||||
},
|
||||
{
|
||||
name: "自定义",
|
||||
websiteUrl: "",
|
||||
|
||||
@@ -58,6 +58,52 @@ export const openclawApiProtocols = [
|
||||
* OpenClaw provider presets list
|
||||
*/
|
||||
export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
{
|
||||
name: "Shengsuanyun",
|
||||
nameKey: "providerForm.presets.shengsuanyun",
|
||||
websiteUrl: "https://www.shengsuanyun.com",
|
||||
apiKeyUrl: "https://www.shengsuanyun.com/?from=CH_4HHXMRYF",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://router.shengsuanyun.com/api",
|
||||
apiKey: "",
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "claude-opus-4-6",
|
||||
name: "Claude Opus 4.6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 5, output: 25 },
|
||||
},
|
||||
{
|
||||
id: "claude-sonnet-4-6",
|
||||
name: "Claude Sonnet 4.6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 3, output: 15 },
|
||||
},
|
||||
],
|
||||
},
|
||||
category: "aggregator",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "shengsuanyun",
|
||||
icon: "shengsuanyun",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
suggestedDefaults: {
|
||||
model: {
|
||||
primary: "shengsuanyun/claude-opus-4-6",
|
||||
fallbacks: ["shengsuanyun/claude-sonnet-4-6"],
|
||||
},
|
||||
modelCatalog: {
|
||||
"shengsuanyun/claude-opus-4-6": { alias: "Opus" },
|
||||
"shengsuanyun/claude-sonnet-4-6": { alias: "Sonnet" },
|
||||
},
|
||||
},
|
||||
},
|
||||
// ========== Chinese Officials ==========
|
||||
{
|
||||
name: "DeepSeek",
|
||||
@@ -719,6 +765,72 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TheRouter",
|
||||
websiteUrl: "https://therouter.ai",
|
||||
apiKeyUrl: "https://dashboard.therouter.ai",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://api.therouter.ai/v1",
|
||||
apiKey: "",
|
||||
api: "openai-completions",
|
||||
models: [
|
||||
{
|
||||
id: "anthropic/claude-sonnet-4.6",
|
||||
name: "Claude Sonnet 4.6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
||||
},
|
||||
{
|
||||
id: "openai/gpt-5.3-codex",
|
||||
name: "GPT-5.3 Codex",
|
||||
contextWindow: 400000,
|
||||
cost: { input: 5, output: 40, cacheRead: 0.5 },
|
||||
},
|
||||
{
|
||||
id: "openai/gpt-5.2",
|
||||
name: "GPT-5.2",
|
||||
contextWindow: 400000,
|
||||
cost: { input: 1.75, output: 14, cacheRead: 0.175 },
|
||||
},
|
||||
{
|
||||
id: "google/gemini-3-flash-preview",
|
||||
name: "Gemini 3 Flash Preview",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 0.5, output: 3, cacheRead: 0.05 },
|
||||
},
|
||||
{
|
||||
id: "qwen/qwen3-coder-480b",
|
||||
name: "Qwen3 Coder 480B",
|
||||
contextWindow: 262144,
|
||||
cost: { input: 0.6, output: 2.35 },
|
||||
},
|
||||
],
|
||||
},
|
||||
category: "aggregator",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "sk-...",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
suggestedDefaults: {
|
||||
model: {
|
||||
primary: "therouter/anthropic/claude-sonnet-4.6",
|
||||
fallbacks: [
|
||||
"therouter/openai/gpt-5.2",
|
||||
"therouter/google/gemini-3-flash-preview",
|
||||
],
|
||||
},
|
||||
modelCatalog: {
|
||||
"therouter/anthropic/claude-sonnet-4.6": { alias: "Sonnet" },
|
||||
"therouter/openai/gpt-5.2": { alias: "GPT-5.2" },
|
||||
"therouter/google/gemini-3-flash-preview": { alias: "Gemini Flash" },
|
||||
"therouter/openai/gpt-5.3-codex": { alias: "Codex" },
|
||||
"therouter/qwen/qwen3-coder-480b": { alias: "Qwen Coder" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ModelScope",
|
||||
websiteUrl: "https://modelscope.cn",
|
||||
@@ -895,6 +1007,56 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
modelCatalog: { "nvidia/moonshotai/kimi-k2.5": { alias: "Kimi" } },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PIPELLM",
|
||||
websiteUrl: "https://www.pipellm.ai",
|
||||
apiKeyUrl: "https://code.pipellm.ai/login?ref=uvw650za",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://cc-api.pipellm.ai",
|
||||
apiKey: "",
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "claude-opus-4-6",
|
||||
name: "claude-opus-4-6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 5, output: 25 },
|
||||
},
|
||||
{
|
||||
id: "claude-sonnet-4-6",
|
||||
name: "claude-sonnet-4-6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 3, output: 15 },
|
||||
},
|
||||
{
|
||||
id: "claude-haiku-4-5-20251001",
|
||||
name: "claude-haiku-4-5-20251001",
|
||||
contextWindow: 200000,
|
||||
cost: { input: 0.8, output: 4 },
|
||||
},
|
||||
],
|
||||
},
|
||||
category: "aggregator",
|
||||
icon: "pipellm",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "pipe-...",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
suggestedDefaults: {
|
||||
model: {
|
||||
primary: "pipellm/claude-opus-4-6",
|
||||
fallbacks: ["pipellm/claude-sonnet-4-6"],
|
||||
},
|
||||
modelCatalog: {
|
||||
"pipellm/claude-opus-4-6": { alias: "Opus" },
|
||||
"pipellm/claude-sonnet-4-6": { alias: "Sonnet" },
|
||||
"pipellm/claude-haiku-4-5-20251001": { alias: "Haiku" },
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// ========== Third Party Partners ==========
|
||||
{
|
||||
@@ -1380,6 +1542,112 @@ export const openclawProviderPresets: OpenClawProviderPreset[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LionCCAPI",
|
||||
websiteUrl: "https://vibecodingapi.ai",
|
||||
settingsConfig: {
|
||||
baseUrl: "https://vibecodingapi.ai",
|
||||
apiKey: "",
|
||||
api: "anthropic-messages",
|
||||
models: [
|
||||
{
|
||||
id: "claude-opus-4-6",
|
||||
name: "Claude Opus 4.6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 5, output: 25 },
|
||||
},
|
||||
{
|
||||
id: "claude-sonnet-4-6",
|
||||
name: "Claude Sonnet 4.6",
|
||||
contextWindow: 1000000,
|
||||
cost: { input: 3, output: 15 },
|
||||
},
|
||||
],
|
||||
},
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "lionccapi",
|
||||
icon: "lioncc",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
suggestedDefaults: {
|
||||
model: {
|
||||
primary: "lionccapi/claude-opus-4-6",
|
||||
fallbacks: ["lionccapi/claude-sonnet-4-6"],
|
||||
},
|
||||
modelCatalog: {
|
||||
"lionccapi/claude-opus-4-6": { alias: "Opus" },
|
||||
"lionccapi/claude-sonnet-4-6": { alias: "Sonnet" },
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "E-FlowCode",
|
||||
websiteUrl: "https://e-flowcode.cc",
|
||||
apiKeyUrl: "https://e-flowcode.cc",
|
||||
settingsConfig: {
|
||||
api: "openai-responses",
|
||||
apiKey: "",
|
||||
baseUrl: "https://e-flowcode.cc/v1",
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"codex_cli_rs/0.77.0 (Windows 10.0.26100; x86_64) WindowsTerminal",
|
||||
},
|
||||
models: [
|
||||
{
|
||||
contextWindow: 200000,
|
||||
cost: {
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
input: 0,
|
||||
output: 0,
|
||||
},
|
||||
id: "gpt-5.3-codex",
|
||||
maxTokens: 32000,
|
||||
name: "gpt-5.3-codex",
|
||||
},
|
||||
{
|
||||
id: "gpt-5.4",
|
||||
name: "gpt-5.4",
|
||||
},
|
||||
{
|
||||
id: "gpt-5.2-codex",
|
||||
name: "gpt-5.2-codex",
|
||||
},
|
||||
{
|
||||
id: "gpt-5.2",
|
||||
name: "gpt-5.2",
|
||||
},
|
||||
],
|
||||
},
|
||||
category: "third_party",
|
||||
icon: "eflowcode",
|
||||
iconColor: "#000000",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "sk-...",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
suggestedDefaults: {
|
||||
model: {
|
||||
primary: "eflowcode/gpt-5.3-codex",
|
||||
fallbacks: ["eflowcode/gpt-5.4", "eflowcode/gpt-5.2-codex"],
|
||||
},
|
||||
modelCatalog: {
|
||||
"eflowcode/gpt-5.3-codex": { alias: "gpt-5.3-codex" },
|
||||
"eflowcode/gpt-5.4": { alias: "gpt-5.4" },
|
||||
"eflowcode/gpt-5.2-codex": { alias: "gpt-5.2-codex" },
|
||||
"eflowcode/gpt-5.2": { alias: "gpt-5.2" },
|
||||
},
|
||||
},
|
||||
},
|
||||
// ========== Cloud Providers ==========
|
||||
{
|
||||
name: "AWS Bedrock",
|
||||
|
||||
@@ -291,6 +291,36 @@ export function getPresetModelDefaults(
|
||||
}
|
||||
|
||||
export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
{
|
||||
name: "Shengsuanyun",
|
||||
nameKey: "providerForm.presets.shengsuanyun",
|
||||
websiteUrl: "https://www.shengsuanyun.com",
|
||||
apiKeyUrl: "https://www.shengsuanyun.com/?from=CH_4HHXMRYF",
|
||||
settingsConfig: {
|
||||
npm: "@ai-sdk/anthropic",
|
||||
name: "Shengsuanyun",
|
||||
options: {
|
||||
baseURL: "https://router.shengsuanyun.com/api/v1",
|
||||
apiKey: "",
|
||||
setCacheKey: true,
|
||||
},
|
||||
models: {
|
||||
"claude-opus-4-6": { name: "Claude Opus 4.6" },
|
||||
"claude-sonnet-4-6": { name: "Claude Sonnet 4.6" },
|
||||
},
|
||||
},
|
||||
category: "aggregator",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "shengsuanyun",
|
||||
icon: "shengsuanyun",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DeepSeek",
|
||||
websiteUrl: "https://platform.deepseek.com",
|
||||
@@ -879,6 +909,37 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TheRouter",
|
||||
websiteUrl: "https://therouter.ai",
|
||||
apiKeyUrl: "https://dashboard.therouter.ai",
|
||||
settingsConfig: {
|
||||
npm: "@ai-sdk/openai-compatible",
|
||||
name: "TheRouter",
|
||||
options: {
|
||||
baseURL: "https://api.therouter.ai/v1",
|
||||
apiKey: "",
|
||||
setCacheKey: true,
|
||||
},
|
||||
models: {
|
||||
"anthropic/claude-sonnet-4.6": { name: "Claude Sonnet 4.6" },
|
||||
"openai/gpt-5.3-codex": { name: "GPT-5.3 Codex" },
|
||||
"openai/gpt-5.2": { name: "GPT-5.2" },
|
||||
"google/gemini-3-flash-preview": {
|
||||
name: "Gemini 3 Flash Preview",
|
||||
},
|
||||
"qwen/qwen3-coder-480b": { name: "Qwen3 Coder 480B" },
|
||||
},
|
||||
},
|
||||
category: "aggregator",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "sk-...",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Novita AI",
|
||||
websiteUrl: "https://novita.ai",
|
||||
@@ -933,6 +994,34 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PIPELLM",
|
||||
websiteUrl: "https://www.pipellm.ai",
|
||||
apiKeyUrl: "https://code.pipellm.ai/login?ref=uvw650za",
|
||||
settingsConfig: {
|
||||
npm: "@ai-sdk/anthropic",
|
||||
name: "PIPELLM",
|
||||
options: {
|
||||
baseURL: "https://cc-api.pipellm.ai",
|
||||
apiKey: "",
|
||||
setCacheKey: true,
|
||||
},
|
||||
models: {
|
||||
"claude-opus-4-6": { name: "claude-opus-4-6" },
|
||||
"claude-sonnet-4-6": { name: "claude-sonnet-4-6" },
|
||||
"claude-haiku-4-5-20251001": { name: "claude-haiku-4-5-20251001" },
|
||||
},
|
||||
},
|
||||
category: "aggregator",
|
||||
icon: "pipellm",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "pipe-...",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "PackyCode",
|
||||
@@ -1222,7 +1311,7 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "x-code",
|
||||
icon: "x-code",
|
||||
icon: "xcode",
|
||||
iconColor: "#000000",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
@@ -1262,6 +1351,64 @@ export const opencodeProviderPresets: OpenCodeProviderPreset[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LionCCAPI",
|
||||
websiteUrl: "https://vibecodingapi.ai",
|
||||
settingsConfig: {
|
||||
npm: "@ai-sdk/anthropic",
|
||||
name: "LionCCAPI",
|
||||
options: {
|
||||
baseURL: "https://vibecodingapi.ai/v1",
|
||||
apiKey: "",
|
||||
setCacheKey: true,
|
||||
},
|
||||
models: {
|
||||
"claude-opus-4-6": { name: "Claude Opus 4.6" },
|
||||
"claude-sonnet-4-6": { name: "Claude Sonnet 4.6" },
|
||||
},
|
||||
},
|
||||
category: "third_party",
|
||||
isPartner: true,
|
||||
partnerPromotionKey: "lionccapi",
|
||||
icon: "lioncc",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "E-FlowCode",
|
||||
websiteUrl: "https://e-flowcode.cc",
|
||||
apiKeyUrl: "https://e-flowcode.cc",
|
||||
settingsConfig: {
|
||||
npm: "@ai-sdk/openai",
|
||||
options: {
|
||||
apiKey: "",
|
||||
baseURL: "https://e-flowcode.cc/v1",
|
||||
},
|
||||
models: {
|
||||
"gpt-5.2-codex": {
|
||||
name: "gpt-5.2-codex",
|
||||
},
|
||||
"gpt-5.3-codex": {
|
||||
name: "gpt-5.3-codex",
|
||||
},
|
||||
},
|
||||
},
|
||||
category: "third_party",
|
||||
icon: "eflowcode",
|
||||
iconColor: "#000000",
|
||||
templateValues: {
|
||||
apiKey: {
|
||||
label: "API Key",
|
||||
placeholder: "sk-...",
|
||||
editorValue: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AWS Bedrock",
|
||||
websiteUrl: "https://aws.amazon.com/bedrock/",
|
||||
|
||||
@@ -243,6 +243,7 @@
|
||||
"title": "Settings",
|
||||
"general": "General",
|
||||
"tabGeneral": "General",
|
||||
"tabAuth": "Auth",
|
||||
"tabAdvanced": "Advanced",
|
||||
"tabProxy": "Proxy",
|
||||
"authCenter": {
|
||||
@@ -535,7 +536,8 @@
|
||||
"alacritty": "Alacritty",
|
||||
"kitty": "Kitty",
|
||||
"ghostty": "Ghostty",
|
||||
"wezterm": "WezTerm"
|
||||
"wezterm": "WezTerm",
|
||||
"kaku": "Kaku"
|
||||
},
|
||||
"windows": {
|
||||
"cmd": "Command Prompt",
|
||||
@@ -772,7 +774,10 @@
|
||||
"ucloud": "Compshare offers an exclusive bonus for CC Switch users — register via this link to get ¥5 platform trial credit!",
|
||||
"micu": "Micu is an official partner of CC Switch",
|
||||
"x-code": "XCodeAPI offers a special bonus for CC Switch users — register via this link and get 10% extra credit on your first order (contact admin to claim)",
|
||||
"ctok": "Join the CTok community on the official website and subscribe to a plan."
|
||||
"ctok": "Join the CTok community on the official website and subscribe to a plan.",
|
||||
"ddshub": "DDSHub offers a special bonus for CC Switch users — register via this link and get 10% extra credit on your first top-up (contact group admin to claim)!",
|
||||
"lionccapi": "LionCCAPI offers exclusive benefits for CC Switch users. After registration, add WeChat HSQBJ088888888 and mention 'cc-switch' to receive $10 free credits!",
|
||||
"shengsuanyun": "Shengsuanyun offers exclusive benefits for CC Switch users. New users who register via this link get ¥10 free credits and 10% bonus on first top-up!"
|
||||
},
|
||||
"presets": {
|
||||
"ucloud": "Compshare"
|
||||
@@ -2275,6 +2280,7 @@
|
||||
"enabledModelsCount": "{{count}} configured models available",
|
||||
"source": "from:",
|
||||
"otherFieldsJson": "Other Fields (JSON)",
|
||||
"slimOtherFieldsHint": "Use this area for top-level OMO Slim config such as council, fallback, multiplexer, disabled_mcps, and todoContinuation.",
|
||||
"searchOrType": "Search or type custom value...",
|
||||
"noMatches": "No matches",
|
||||
"jsonMustBeObject": "{{field}} must be a JSON object",
|
||||
@@ -2351,7 +2357,8 @@
|
||||
"librarian": "Librarian",
|
||||
"explorer": "Explorer",
|
||||
"designer": "Designer",
|
||||
"fixer": "Fixer"
|
||||
"fixer": "Fixer",
|
||||
"council": "Council"
|
||||
},
|
||||
"slimAgentTooltip": {
|
||||
"orchestrator": "Writes executable code, orchestrates multi-agent workflow, summons experts",
|
||||
@@ -2359,7 +2366,8 @@
|
||||
"librarian": "Documentation lookup, GitHub code search (read-only)",
|
||||
"explorer": "Regex search, AST pattern matching, file discovery (read-only)",
|
||||
"designer": "Modern responsive design, CSS/Tailwind expertise",
|
||||
"fixer": "Code implementation, refactoring, testing, verification"
|
||||
"fixer": "Code implementation, refactoring, testing, verification",
|
||||
"council": "Multi-model consensus agent. Runs multiple read-only councillors in parallel, then lets the master synthesize the final answer."
|
||||
}
|
||||
},
|
||||
"openclawConfig": {
|
||||
|
||||
@@ -243,6 +243,7 @@
|
||||
"title": "設定",
|
||||
"general": "一般",
|
||||
"tabGeneral": "一般",
|
||||
"tabAuth": "認証",
|
||||
"tabAdvanced": "詳細",
|
||||
"tabProxy": "プロキシ",
|
||||
"authCenter": {
|
||||
@@ -535,7 +536,8 @@
|
||||
"alacritty": "Alacritty",
|
||||
"kitty": "Kitty",
|
||||
"ghostty": "Ghostty",
|
||||
"wezterm": "WezTerm"
|
||||
"wezterm": "WezTerm",
|
||||
"kaku": "Kaku"
|
||||
},
|
||||
"windows": {
|
||||
"cmd": "コマンドプロンプト",
|
||||
@@ -772,7 +774,10 @@
|
||||
"ucloud": "Compshare は CC Switch ユーザー向けに特別ボーナスを提供しています。このリンクから登録すると、5元のプラットフォーム体験クレジットがもらえます!",
|
||||
"micu": "Micu は CC Switch の公式パートナーです",
|
||||
"x-code": "XCodeAPI は CC Switch ユーザー向けに特別ボーナスを提供しています。このリンクから登録すると、初回注文で 10% の追加クレジットがもらえます(管理者に連絡して受け取り)",
|
||||
"ctok": "公式サイトで CTok コミュニティに参加し、プランを購読してください。"
|
||||
"ctok": "公式サイトで CTok コミュニティに参加し、プランを購読してください。",
|
||||
"ddshub": "DDSHub は CC Switch ユーザー向けに特別ボーナスを提供しています。このリンクから登録すると、初回チャージで 10% の追加クレジットがもらえます(グループ管理者に連絡して受け取り)!",
|
||||
"lionccapi": "LionCCAPIはCC Switchユーザーに特別特典を提供しています。登録後、WeChat HSQBJ088888888を追加し、「cc-switch」と伝えると$10分のクレジットがもらえます!",
|
||||
"shengsuanyun": "胜算云はCC Switchユーザーに特別特典を提供しています。このリンクから登録すると、10元分の無料クレジットと初回チャージ10%ボーナスがもらえます!"
|
||||
},
|
||||
"presets": {
|
||||
"ucloud": "Compshare"
|
||||
@@ -2275,6 +2280,7 @@
|
||||
"enabledModelsCount": "設定済みモデル {{count}} 件",
|
||||
"source": "出典:",
|
||||
"otherFieldsJson": "その他のフィールド (JSON)",
|
||||
"slimOtherFieldsHint": "council、fallback、multiplexer、disabled_mcps、todoContinuation など、OMO Slim のトップレベル設定はここに記述します。",
|
||||
"searchOrType": "検索またはカスタム値を入力...",
|
||||
"noMatches": "一致する項目がありません",
|
||||
"jsonMustBeObject": "{{field}} は JSON オブジェクトである必要があります",
|
||||
@@ -2351,7 +2357,8 @@
|
||||
"librarian": "ライブラリアン",
|
||||
"explorer": "エクスプローラー",
|
||||
"designer": "デザイナー",
|
||||
"fixer": "フィクサー"
|
||||
"fixer": "フィクサー",
|
||||
"council": "カウンシル"
|
||||
},
|
||||
"slimAgentTooltip": {
|
||||
"orchestrator": "実行コードの作成、マルチエージェントワークフローの調整、エキスパートの召喚",
|
||||
@@ -2359,7 +2366,8 @@
|
||||
"librarian": "ドキュメント検索、GitHubコード検索(読み取り専用)",
|
||||
"explorer": "正規表現検索、ASTパターンマッチング、ファイル検出(読み取り専用)",
|
||||
"designer": "モダンなレスポンシブデザイン、CSS/Tailwindの専門知識",
|
||||
"fixer": "コード実装、リファクタリング、テスト、検証"
|
||||
"fixer": "コード実装、リファクタリング、テスト、検証",
|
||||
"council": "複数モデルの合議エージェント。複数の読み取り専用 councillor を並列実行し、master が最終回答を統合します。"
|
||||
}
|
||||
},
|
||||
"openclawConfig": {
|
||||
|
||||
@@ -243,6 +243,7 @@
|
||||
"title": "设置",
|
||||
"general": "通用",
|
||||
"tabGeneral": "通用",
|
||||
"tabAuth": "认证",
|
||||
"tabAdvanced": "高级",
|
||||
"tabProxy": "代理",
|
||||
"authCenter": {
|
||||
@@ -535,7 +536,8 @@
|
||||
"alacritty": "Alacritty",
|
||||
"kitty": "Kitty",
|
||||
"ghostty": "Ghostty",
|
||||
"wezterm": "WezTerm"
|
||||
"wezterm": "WezTerm",
|
||||
"kaku": "Kaku"
|
||||
},
|
||||
"windows": {
|
||||
"cmd": "命令提示符",
|
||||
@@ -772,10 +774,14 @@
|
||||
"ucloud": "优云智算为CC Switch 的用户提供了特殊优惠,通过此链接注册,可以获得五元平台体验金!",
|
||||
"micu": "Micu 是 CC Switch 的官方合作伙伴",
|
||||
"x-code": "XCodeAPI 为CC Switch 的用户提供特别福利,使用此链接注册后首单加赠10%的额度(联系站长领取)",
|
||||
"ctok": "官网加入CTok社群,订阅套餐。"
|
||||
"ctok": "官网加入CTok社群,订阅套餐。",
|
||||
"ddshub": "呆呆兽为CC Switch 的用户提供了特别福利,通过此链接注册后,首单充值可额外赠送 10% 额度(联系群主领取)!",
|
||||
"lionccapi": "LionCCAPI 为 CC Switch 的用户提供了特别福利,注册后添加客服微信HSQBJ088888888,发暗号cc-switch备注即可送10美金额度!",
|
||||
"shengsuanyun": "胜算云为 CC Switch 的用户提供了特别福利,使用此链接注册的新用户可获 10 元模力及首充 10% 赠送!"
|
||||
},
|
||||
"presets": {
|
||||
"ucloud": "优云智算"
|
||||
"ucloud": "优云智算",
|
||||
"shengsuanyun": "胜算云"
|
||||
},
|
||||
"parameterConfig": "参数配置 - {{name}} *",
|
||||
"mainModel": "主模型 (可选)",
|
||||
@@ -2275,6 +2281,7 @@
|
||||
"enabledModelsCount": "可选已配置模型 {{count}} 个",
|
||||
"source": "来源:",
|
||||
"otherFieldsJson": "其他字段 (JSON)",
|
||||
"slimOtherFieldsHint": "OMO Slim 的 council、fallback、multiplexer、disabled_mcps、todoContinuation 等顶层配置请写在这里。",
|
||||
"searchOrType": "搜索或输入自定义值...",
|
||||
"noMatches": "无匹配项",
|
||||
"jsonMustBeObject": "{{field}} 必须是 JSON 对象",
|
||||
@@ -2351,7 +2358,8 @@
|
||||
"librarian": "图书管理员",
|
||||
"explorer": "探索者",
|
||||
"designer": "设计师",
|
||||
"fixer": "修复者"
|
||||
"fixer": "修复者",
|
||||
"council": "议会"
|
||||
},
|
||||
"slimAgentTooltip": {
|
||||
"orchestrator": "编写执行代码,编排多代理工作流,召唤专家",
|
||||
@@ -2359,7 +2367,8 @@
|
||||
"librarian": "文档查询、GitHub 代码搜索(只读)",
|
||||
"explorer": "正则搜索、AST 模式匹配、文件发现(只读)",
|
||||
"designer": "现代响应式设计、CSS/Tailwind 精通",
|
||||
"fixer": "代码实现、重构、测试、验证"
|
||||
"fixer": "代码实现、重构、测试、验证",
|
||||
"council": "多模型共识代理,并行运行多个只读 councillor,再由 master 汇总最终答案。"
|
||||
}
|
||||
},
|
||||
"openclawConfig": {
|
||||
|
||||
|
After Width: | Height: | Size: 1.4 MiB |
|
After Width: | Height: | Size: 62 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
@@ -107,6 +107,13 @@ export const iconMetadata: Record<string, IconMetadata> = {
|
||||
keywords: ["cubence", "api", "relay"],
|
||||
defaultColor: "#4B5563",
|
||||
},
|
||||
dds: {
|
||||
name: "dds",
|
||||
displayName: "DDS",
|
||||
category: "other",
|
||||
keywords: [],
|
||||
defaultColor: "currentColor",
|
||||
},
|
||||
deepseek: {
|
||||
name: "deepseek",
|
||||
displayName: "DeepSeek",
|
||||
@@ -338,6 +345,13 @@ export const iconMetadata: Record<string, IconMetadata> = {
|
||||
keywords: [],
|
||||
defaultColor: "currentColor",
|
||||
},
|
||||
xcode: {
|
||||
name: "xcode",
|
||||
displayName: "Xcode",
|
||||
category: "tool",
|
||||
keywords: ["apple", "xcode", "ide"],
|
||||
defaultColor: "currentColor",
|
||||
},
|
||||
zhipu: {
|
||||
name: "zhipu",
|
||||
displayName: "Zhipu AI",
|
||||
@@ -352,6 +366,34 @@ export const iconMetadata: Record<string, IconMetadata> = {
|
||||
keywords: ["openrouter", "router", "aggregator"],
|
||||
defaultColor: "#6566F1",
|
||||
},
|
||||
pipellm: {
|
||||
name: "pipellm",
|
||||
displayName: "PIPELLM",
|
||||
category: "ai-provider",
|
||||
keywords: ["pipellm", "pipe"],
|
||||
defaultColor: "currentColor",
|
||||
},
|
||||
eflowcode: {
|
||||
name: "eflowcode",
|
||||
displayName: "E-FlowCode",
|
||||
category: "ai-provider",
|
||||
keywords: ["eflowcode", "e-flowcode", "flow"],
|
||||
defaultColor: "currentColor",
|
||||
},
|
||||
shengsuanyun: {
|
||||
name: "shengsuanyun",
|
||||
displayName: "Shengsuanyun",
|
||||
category: "ai-provider",
|
||||
keywords: ["shengsuanyun", "shengsuanyun"],
|
||||
defaultColor: "currentColor",
|
||||
},
|
||||
lioncc: {
|
||||
name: "lioncc",
|
||||
displayName: "LionCC",
|
||||
category: "ai-provider",
|
||||
keywords: ["lioncc", "lion"],
|
||||
defaultColor: "#F9DA3C",
|
||||
},
|
||||
longcat: {
|
||||
name: "longcat",
|
||||
displayName: "LongCat",
|
||||
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 212 KiB |
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32">
|
||||
<path d="M0 0 C10.56 0 21.12 0 32 0 C32 10.56 32 21.12 32 32 C21.44 32 10.88 32 0 32 C0 21.44 0 10.88 0 0 Z " fill="#E9F5FC" transform="translate(0,0)"/>
|
||||
<path d="M0 0 C0.7734375 -0.00773438 1.546875 -0.01546875 2.34375 -0.0234375 C4.98245826 0.4641499 5.89157252 1.26136133 7.5 3.375 C7.5 4.035 7.5 4.695 7.5 5.375 C4.86 5.375 2.22 5.375 -0.5 5.375 C-0.5 4.715 -0.5 4.055 -0.5 3.375 C-1.49 3.87 -1.49 3.87 -2.5 4.375 C-2.96751788 6.73099235 -2.96751788 6.73099235 -3.125 9.4375 C-3.19976562 10.35660156 -3.27453125 11.27570312 -3.3515625 12.22265625 C-3.40054687 12.93292969 -3.44953125 13.64320312 -3.5 14.375 C-2.84 14.375 -2.18 14.375 -1.5 14.375 C-1.17 13.385 -0.84 12.395 -0.5 11.375 C2.14 11.375 4.78 11.375 7.5 11.375 C7.83 12.365 8.16 13.355 8.5 14.375 C9.16 14.705 9.82 15.035 10.5 15.375 C10.5 14.385 10.5 13.395 10.5 12.375 C11.82 12.375 13.14 12.375 14.5 12.375 C15.07570686 15.08904664 14.79565729 16.83296164 13.46875 19.265625 C10.63940674 22.8167395 8.44343278 24.19169857 3.94140625 25.06640625 C-1.09124454 25.30083101 -5.51954121 25.45246753 -10.02734375 23 C-13.19959195 20.09372762 -14.38901731 18.24700687 -14.9375 13.9375 C-14.793125 13.091875 -14.64875 12.24625 -14.5 11.375 C-11.86 13.355 -9.22 15.335 -6.5 17.375 C-6.5 16.385 -6.5 15.395 -6.5 14.375 C-6.83 14.045 -7.16 13.715 -7.5 13.375 C-7.703125 11.1953125 -7.703125 11.1953125 -7.75 8.5 C-7.77578125 7.61570312 -7.8015625 6.73140625 -7.828125 5.8203125 C-7.5 3.375 -7.5 3.375 -6.265625 1.578125 C-4.03939632 0.06113732 -2.67866058 -0.02678661 0 0 Z " fill="#EAF3FB" transform="translate(16.5,7.625)"/>
|
||||
<path d="M0 0 C5.28 0 10.56 0 16 0 C16 10.56 16 21.12 16 32 C13.36 32 10.72 32 8 32 C8.42152344 31.55269531 8.84304687 31.10539062 9.27734375 30.64453125 C13.5377979 26.01600234 13.5377979 26.01600234 15 20 C13.68 20 12.36 20 11 20 C11 20.99 11 21.98 11 23 C9.68 22.34 8.36 21.68 7 21 C7.33 20.34 7.66 19.68 8 19 C6.700625 19.12375 5.40125 19.2475 4.0625 19.375 C2.96615234 19.47941406 2.96615234 19.47941406 1.84765625 19.5859375 C1.23792969 19.72257812 0.62820312 19.85921875 0 20 C-0.33 20.66 -0.66 21.32 -1 22 C-1.66 22 -2.32 22 -3 22 C-3 18.7 -3 15.4 -3 12 C-2.01 11.67 -1.02 11.34 0 11 C0 11.66 0 12.32 0 13 C2.64 13 5.28 13 8 13 C7.12355567 10.82271927 7.12355567 10.82271927 5 9 C0.32120751 8.25069618 -3.02499663 8.34999775 -7 11 C-7 8 -7 8 -5.46875 6.39453125 C-4.8190625 5.87246094 -4.169375 5.35039063 -3.5 4.8125 C-2.8503125 4.28269531 -2.200625 3.75289063 -1.53125 3.20703125 C-1.0259375 2.80871094 -0.520625 2.41039062 0 2 C0 3.32 0 4.64 0 6 C1.918125 5.938125 1.918125 5.938125 3.875 5.875 C6.0546875 5.8046875 6.0546875 5.8046875 8 6 C10 8 10 8 10.125 10.625 C10.08375 11.40875 10.0425 12.1925 10 13 C11.65 13 13.3 13 15 13 C13.53713212 6.51171219 13.53713212 6.51171219 9 2 C6.00593079 1.38980973 3.04998138 1.13034108 0 1 C0 0.67 0 0.34 0 0 Z " fill="#F3F6FC" transform="translate(16,0)"/>
|
||||
<path d="M0 0 C0.7734375 -0.00773438 1.546875 -0.01546875 2.34375 -0.0234375 C4.98245826 0.4641499 5.89157252 1.26136133 7.5 3.375 C7.5 4.035 7.5 4.695 7.5 5.375 C4.86 5.375 2.22 5.375 -0.5 5.375 C-0.5 4.715 -0.5 4.055 -0.5 3.375 C-1.49 3.87 -1.49 3.87 -2.5 4.375 C-2.96751788 6.73099235 -2.96751788 6.73099235 -3.125 9.4375 C-3.19976563 10.35660156 -3.27453125 11.27570312 -3.3515625 12.22265625 C-3.40054687 12.93292969 -3.44953125 13.64320312 -3.5 14.375 C-2.84 14.375 -2.18 14.375 -1.5 14.375 C-1.17 13.385 -0.84 12.395 -0.5 11.375 C2.14 11.375 4.78 11.375 7.5 11.375 C5.625 15.25 5.625 15.25 4.5 16.375 C2.5390625 16.578125 2.5390625 16.578125 0.125 16.625 C-0.66648437 16.65078125 -1.45796875 16.6765625 -2.2734375 16.703125 C-4.5 16.375 -4.5 16.375 -6.265625 15.171875 C-7.89392995 12.80155767 -7.90051705 11.23290924 -7.875 8.375 C-7.88273438 7.50875 -7.89046875 6.6425 -7.8984375 5.75 C-7.5 3.375 -7.5 3.375 -6.2578125 1.5859375 C-4.03658417 0.05575798 -2.68137219 -0.02681372 0 0 Z " fill="#243FC5" transform="translate(16.5,7.625)"/>
|
||||
<path d="M0 0 C4.29 0 8.58 0 13 0 C13 0.33 13 0.66 13 1 C11.63875 1.37125 11.63875 1.37125 10.25 1.75 C5.85279848 3.42719983 5.85279848 3.42719983 3 7 C2.66982425 10.69051287 2.77068363 14.30545853 3 18 C2.34 18 1.68 18 1 18 C2.27040826 24.22500049 4.65519565 27.37183885 9 32 C6.03 32 3.06 32 0 32 C0 21.44 0 10.88 0 0 Z " fill="#FAFCFD" transform="translate(0,0)"/>
|
||||
<path d="M0 0 C6.82771306 -0.70631514 6.82771306 -0.70631514 9.8671875 1.125 C12.83250747 3.8491217 13.92030982 5.28278834 14.375 9.375 C14.25125 10.24125 14.1275 11.1075 14 12 C12.35 12 10.7 12 9 12 C8.814375 11.05125 8.62875 10.1025 8.4375 9.125 C7.26599195 5.61628301 7.26599195 5.61628301 3.375 4.625 C2.26125 4.41875 1.1475 4.2125 0 4 C0 2.68 0 1.36 0 0 Z " fill="#219DF4" transform="translate(17,1)"/>
|
||||
<path d="M0 0 C-0.97866338 1.14626322 -1.95794587 2.29199788 -2.9375 3.4375 C-3.48277344 4.07558594 -4.02804688 4.71367188 -4.58984375 5.37109375 C-5.36795695 6.26991149 -6.15936528 7.15936528 -7 8 C-7.36760731 10.32817964 -7.70241581 12.6618385 -8 15 C-9.32 15 -10.64 15 -12 15 C-12.89533679 7.5388601 -12.89533679 7.5388601 -10.875 4.06640625 C-7.51165489 0.41402367 -5.09930851 -0.72847264 0 0 Z " fill="#1448D6" transform="translate(14,1)"/>
|
||||
<path d="M0 0 C1.32 0 2.64 0 4 0 C4.46703469 2.64652992 4.39884037 4.36924133 2.9453125 6.66796875 C0.76718269 9.14632727 -0.85756827 10.80140524 -4.1796875 11.37890625 C-6.375 11.375 -6.375 11.375 -10 11 C-10 9.68 -10 8.36 -10 7 C-8.906875 6.773125 -7.81375 6.54625 -6.6875 6.3125 C-2.4291168 4.79680428 -2.08798785 3.77826372 0 0 Z " fill="#0E49D9" transform="translate(27,20)"/>
|
||||
<path d="M0 0 C4.52615993 3.67832017 8.39424999 7.41086363 12 12 C9.00710226 12.42755682 6.86261474 12.55953389 4.265625 10.875 C1.27173282 8.13772715 0.08435644 6.75920797 -0.375 2.625 C-0.25125 1.75875 -0.1275 0.8925 0 0 Z " fill="#0B89F0" transform="translate(2,19)"/>
|
||||
<path d="M0 0 C1.43655854 -0.08131463 2.8744483 -0.13933559 4.3125 -0.1875 C5.51326172 -0.23970703 5.51326172 -0.23970703 6.73828125 -0.29296875 C9 0 9 0 10.79296875 1.38671875 C12 3 12 3 12 5 C9.36 5 6.72 5 4 5 C4 4.34 4 3.68 4 3 C2.68 3.33 1.36 3.66 0 4 C0 2.68 0 1.36 0 0 Z " fill="#3852CA" transform="translate(12,8)"/>
|
||||
<path d="M0 0 C5.28 0 10.56 0 16 0 C16 3.96 16 7.92 16 12 C15.67 12 15.34 12 15 12 C14.7525 11.0925 14.505 10.185 14.25 9.25 C12.88118077 5.69107 12.12750908 4.16519859 9 2 C6.00675528 1.38480808 3.05004295 1.13034372 0 1 C0 0.67 0 0.34 0 0 Z " fill="#FEFEFE" transform="translate(16,0)"/>
|
||||
<path d="M0 0 C0.33 0 0.66 0 1 0 C1 3.96 1 7.92 1 12 C-1.64 12 -4.28 12 -7 12 C-6.57847656 11.55269531 -6.15695313 11.10539062 -5.72265625 10.64453125 C-1.4622021 6.01600234 -1.4622021 6.01600234 0 0 Z " fill="#FDFEFE" transform="translate(31,20)"/>
|
||||
<path d="M0 0 C0.33 0 0.66 0 1 0 C1 4.62 1 9.24 1 14 C0.01 13.34 -0.98 12.68 -2 12 C-2.36328125 9.6875 -2.36328125 9.6875 -2.3125 7 C-2.30863281 6.113125 -2.30476562 5.22625 -2.30078125 4.3125 C-2 2 -2 2 0 0 Z " fill="#1939C2" transform="translate(11,9)"/>
|
||||
<path d="M0 0 C1.98 0.99 1.98 0.99 4 2 C4 4.31 4 6.62 4 9 C2.68 9 1.36 9 0 9 C0 6.03 0 3.06 0 0 Z " fill="#059CF3" transform="translate(2,7)"/>
|
||||
<path d="M0 0 C1.98 0 3.96 0 6 0 C6.66 1.32 7.32 2.64 8 4 C5.36 4 2.72 4 0 4 C0 2.68 0 1.36 0 0 Z " fill="#0773EE" transform="translate(17,27)"/>
|
||||
<path d="M0 0 C2.64 0 5.28 0 8 0 C7.34 1.32 6.68 2.64 6 4 C4.02 4 2.04 4 0 4 C0 2.68 0 1.36 0 0 Z " fill="#0CB7F7" transform="translate(17,1)"/>
|
||||
<path d="M0 0 C2.64 0 5.28 0 8 0 C7.34 1.32 6.68 2.64 6 4 C3.69 3.67 1.38 3.34 -1 3 C-0.67 2.01 -0.34 1.02 0 0 Z " fill="#2F4AC8" transform="translate(16,19)"/>
|
||||
<path d="M0 0 C0.99 0.33 1.98 0.66 3 1 C2.01 2.32 1.02 3.64 0 5 C-1.32 4.67 -2.64 4.34 -4 4 C-2.68 2.68 -1.36 1.36 0 0 Z " fill="#053FD7" transform="translate(7,4)"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
|
After Width: | Height: | Size: 286 KiB |
@@ -166,7 +166,7 @@ export interface ProviderMeta {
|
||||
apiKeyField?: ClaudeApiKeyField;
|
||||
// 是否将 base_url 视为完整 API 端点(代理直接使用此 URL,不拼接路径)
|
||||
isFullUrl?: boolean;
|
||||
// Prompt cache key for OpenAI-compatible endpoints (improves cache hit rate)
|
||||
// Prompt cache key for OpenAI Responses-compatible endpoints (improves cache hit rate)
|
||||
promptCacheKey?: string;
|
||||
// 供应商类型(用于识别 Copilot 等特殊供应商)
|
||||
providerType?: string;
|
||||
@@ -313,7 +313,7 @@ export interface Settings {
|
||||
|
||||
// ===== 终端设置 =====
|
||||
// 首选终端应用(可选,默认使用系统默认终端)
|
||||
// macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty"
|
||||
// macOS: "terminal" | "iterm2" | "warp" | "alacritty" | "kitty" | "ghostty" | "wezterm" | "kaku"
|
||||
// Windows: "cmd" | "powershell" | "wt"
|
||||
// Linux: "gnome-terminal" | "konsole" | "xfce4-terminal" | "alacritty" | "kitty" | "ghostty"
|
||||
preferredTerminal?: string;
|
||||
|
||||
@@ -362,6 +362,14 @@ export const OMO_SLIM_BUILTIN_AGENTS: OmoAgentDef[] = [
|
||||
recommended: "gpt-5.4",
|
||||
group: "sub",
|
||||
},
|
||||
{
|
||||
key: "council",
|
||||
display: "Council",
|
||||
descKey: "omo.slimAgentDesc.council",
|
||||
tooltipKey: "omo.slimAgentTooltip.council",
|
||||
recommended: "gpt-5.4-mini",
|
||||
group: "sub",
|
||||
},
|
||||
];
|
||||
|
||||
export const OMO_SLIM_DISABLEABLE_AGENTS = [
|
||||
@@ -371,6 +379,7 @@ export const OMO_SLIM_DISABLEABLE_AGENTS = [
|
||||
{ value: "explorer", label: "Explorer" },
|
||||
{ value: "designer", label: "Designer" },
|
||||
{ value: "fixer", label: "Fixer" },
|
||||
{ value: "council", label: "Council" },
|
||||
] as const;
|
||||
|
||||
export const OMO_SLIM_DISABLEABLE_MCPS = [
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { opencodeProviderPresets } from "@/config/opencodeProviderPresets";
|
||||
import { openclawProviderPresets } from "@/config/openclawProviderPresets";
|
||||
|
||||
describe("TheRouter OpenCode and OpenClaw presets", () => {
|
||||
it("uses OpenAI-compatible config for OpenCode", () => {
|
||||
const preset = opencodeProviderPresets.find((item) => item.name === "TheRouter");
|
||||
const models = preset?.settingsConfig.models ?? {};
|
||||
|
||||
expect(preset).toBeDefined();
|
||||
expect(preset?.websiteUrl).toBe("https://therouter.ai");
|
||||
expect(preset?.apiKeyUrl).toBe("https://dashboard.therouter.ai");
|
||||
expect(preset?.category).toBe("aggregator");
|
||||
expect(preset?.settingsConfig.npm).toBe("@ai-sdk/openai-compatible");
|
||||
expect(preset?.settingsConfig.options?.baseURL).toBe(
|
||||
"https://api.therouter.ai/v1",
|
||||
);
|
||||
expect(preset?.settingsConfig.options?.setCacheKey).toBe(true);
|
||||
expect(models).toHaveProperty("openai/gpt-5.3-codex");
|
||||
expect(models).toHaveProperty("anthropic/claude-sonnet-4.6");
|
||||
expect(models).toHaveProperty("google/gemini-3-flash-preview");
|
||||
});
|
||||
|
||||
it("uses OpenAI completions config for OpenClaw", () => {
|
||||
const preset = openclawProviderPresets.find((item) => item.name === "TheRouter");
|
||||
const modelIds = (preset?.settingsConfig.models ?? []).map((model) => model.id);
|
||||
|
||||
expect(preset).toBeDefined();
|
||||
expect(preset?.websiteUrl).toBe("https://therouter.ai");
|
||||
expect(preset?.apiKeyUrl).toBe("https://dashboard.therouter.ai");
|
||||
expect(preset?.category).toBe("aggregator");
|
||||
expect(preset?.settingsConfig.baseUrl).toBe("https://api.therouter.ai/v1");
|
||||
expect(preset?.settingsConfig.api).toBe("openai-completions");
|
||||
expect(modelIds).toEqual(
|
||||
expect.arrayContaining([
|
||||
"anthropic/claude-sonnet-4.6",
|
||||
"openai/gpt-5.3-codex",
|
||||
"openai/gpt-5.2",
|
||||
"google/gemini-3-flash-preview",
|
||||
]),
|
||||
);
|
||||
expect(preset?.suggestedDefaults?.model).toEqual({
|
||||
primary: "therouter/anthropic/claude-sonnet-4.6",
|
||||
fallbacks: [
|
||||
"therouter/openai/gpt-5.2",
|
||||
"therouter/google/gemini-3-flash-preview",
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,66 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { providerPresets } from "@/config/claudeProviderPresets";
|
||||
import { codexProviderPresets } from "@/config/codexProviderPresets";
|
||||
import { geminiProviderPresets } from "@/config/geminiProviderPresets";
|
||||
|
||||
describe("TheRouter provider presets", () => {
|
||||
it("uses the Anthropic-compatible root endpoint for Claude", () => {
|
||||
const preset = providerPresets.find((item) => item.name === "TheRouter");
|
||||
|
||||
expect(preset).toBeDefined();
|
||||
expect(preset?.websiteUrl).toBe("https://therouter.ai");
|
||||
expect(preset?.apiKeyUrl).toBe("https://dashboard.therouter.ai");
|
||||
expect(preset?.category).toBe("aggregator");
|
||||
expect(preset?.endpointCandidates).toEqual(["https://api.therouter.ai"]);
|
||||
|
||||
const env = (preset?.settingsConfig as { env: Record<string, string> }).env;
|
||||
expect(env.ANTHROPIC_BASE_URL).toBe("https://api.therouter.ai");
|
||||
expect(env.ANTHROPIC_AUTH_TOKEN).toBe("");
|
||||
expect(env.ANTHROPIC_API_KEY).toBe("");
|
||||
expect(env.ANTHROPIC_MODEL).toBe("anthropic/claude-sonnet-4.6");
|
||||
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe(
|
||||
"anthropic/claude-haiku-4.5",
|
||||
);
|
||||
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe(
|
||||
"anthropic/claude-sonnet-4.6",
|
||||
);
|
||||
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe(
|
||||
"anthropic/claude-opus-4.6",
|
||||
);
|
||||
});
|
||||
|
||||
it("uses the OpenAI-compatible v1 endpoint for Codex", () => {
|
||||
const preset = codexProviderPresets.find((item) => item.name === "TheRouter");
|
||||
|
||||
expect(preset).toBeDefined();
|
||||
expect(preset?.websiteUrl).toBe("https://therouter.ai");
|
||||
expect(preset?.apiKeyUrl).toBe("https://dashboard.therouter.ai");
|
||||
expect(preset?.category).toBe("aggregator");
|
||||
expect(preset?.endpointCandidates).toEqual([
|
||||
"https://api.therouter.ai/v1",
|
||||
]);
|
||||
expect(preset?.auth).toEqual({ OPENAI_API_KEY: "" });
|
||||
expect(preset?.config).toContain('model_provider = "therouter"');
|
||||
expect(preset?.config).toContain('model = "openai/gpt-5.3-codex"');
|
||||
expect(preset?.config).toContain(
|
||||
'base_url = "https://api.therouter.ai/v1"',
|
||||
);
|
||||
expect(preset?.config).toContain('wire_api = "responses"');
|
||||
});
|
||||
|
||||
it("uses the Gemini-native root endpoint for Gemini", () => {
|
||||
const preset = geminiProviderPresets.find((item) => item.name === "TheRouter");
|
||||
|
||||
expect(preset).toBeDefined();
|
||||
expect(preset?.websiteUrl).toBe("https://therouter.ai");
|
||||
expect(preset?.apiKeyUrl).toBe("https://dashboard.therouter.ai");
|
||||
expect(preset?.category).toBe("aggregator");
|
||||
expect(preset?.endpointCandidates).toEqual(["https://api.therouter.ai"]);
|
||||
expect(preset?.baseURL).toBe("https://api.therouter.ai");
|
||||
expect(preset?.model).toBe("gemini-2.5-pro");
|
||||
|
||||
const env = (preset?.settingsConfig as { env: Record<string, string> }).env;
|
||||
expect(env.GOOGLE_GEMINI_BASE_URL).toBe("https://api.therouter.ai");
|
||||
expect(env.GEMINI_MODEL).toBe("gemini-2.5-pro");
|
||||
});
|
||||
});
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
buildOmoProfilePreview,
|
||||
buildOmoSlimProfilePreview,
|
||||
OMO_SLIM_BUILTIN_AGENTS,
|
||||
OMO_SLIM_DISABLEABLE_AGENTS,
|
||||
parseOmoOtherFieldsObject,
|
||||
} from "@/types/omo";
|
||||
|
||||
@@ -28,3 +31,38 @@ describe("buildOmoProfilePreview", () => {
|
||||
expect(fromObject).toEqual({ foo: "bar" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildOmoSlimProfilePreview", () => {
|
||||
it("保留 top-level council 配置,同时写入 council agent 模型", () => {
|
||||
const preview = buildOmoSlimProfilePreview(
|
||||
{
|
||||
council: { model: "openai/gpt-5.4-mini" },
|
||||
},
|
||||
'{ "council": { "default_preset": "default" }, "fallback": { "enabled": true } }',
|
||||
);
|
||||
|
||||
expect(preview).toEqual({
|
||||
council: { default_preset: "default" },
|
||||
fallback: { enabled: true },
|
||||
agents: {
|
||||
council: { model: "openai/gpt-5.4-mini" },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("OMO Slim metadata", () => {
|
||||
it("将 council 视为内置且可禁用的 agent", () => {
|
||||
expect(OMO_SLIM_BUILTIN_AGENTS).toContainEqual(
|
||||
expect.objectContaining({
|
||||
key: "council",
|
||||
display: "Council",
|
||||
group: "sub",
|
||||
}),
|
||||
);
|
||||
expect(OMO_SLIM_DISABLEABLE_AGENTS).toContainEqual({
|
||||
value: "council",
|
||||
label: "Council",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||