Commit Graph

1978 Commits

Author SHA1 Message Date
Jason c797b2a3fb test(providers): align preset selector tests with official-first ordering
The official-first/prime-partner sort changed Original mode order, but the
selector tests still asserted the old raw array order. Update the three
stale assertions and add a dedicated case covering the prime-partner group
and the exclusivity rule (an official preset also flagged primePartner
stays only in the official group).
2026-06-22 10:53:00 +08:00
Jason c4630b5c26 feat(providers): add Volcengine Ark usage query with AK/SK signing
Query coding-plan / agent-plan usage for Volcengine Ark via the
control-plane OpenAPI (open.volcengineapi.com), which requires
account-level AccessKey signing rather than the inference API key.

- Implement Volcengine Signature V4 (an AWS SigV4 variant: fixed
  canonical header order, "HMAC-SHA256" algorithm without the AWS4
  prefix, scope ending in "request", service "ark") in
  services/coding_plan.rs
- Auto-detect the plan by probing GetAFPUsage (Agent Plan, AFP
  five-hour/weekly/monthly quotas) first, falling back to
  GetCodingPlanUsage (Coding Plan, session/weekly/monthly percentages);
  a single credential covers whichever plan the account holds
- Parse the real response shape: the window label lives in the `Level`
  field; guard ResetTimestamp <= 0 (session returns -1)
- Store account-level credentials on UsageScript (accessKeyId /
  secretAccessKey), threaded through both the test command and the
  TOKEN_PLAN auto-refresh path
- Add an independent AK/SK input block with a detailed hint pointing to
  the Volcengine console -> API Access Keys
- Add the `monthly` tier label (frontend TIER_I18N_KEYS + tray
  TIER_LABEL_GROUPS + subscription service)
- Sync zh / en / ja / zh-TW locales and the usage-query docs
2026-06-22 10:28:10 +08:00
Jason a3b3a06f5e feat(providers): tighten Add Provider header spacing and add footer hint
- Reduce title->tabs and tabs->card vertical gaps from 24px to 12px
- Add an always-visible footer hint guiding users to fill the fields
  below after choosing a preset (pinned footer, never scrolls off)
- FullScreenPanel: add optional contentClassName prop to scope content
  padding overrides without affecting the other panels that share it
- i18n: add provider.addFooterHint in zh/en/ja/zh-TW
2026-06-22 10:28:10 +08:00
Jason e648b7425e fix(providers): rename OpenCode/OpenClaw Kimi preset to "Kimi"
The OpenCode and OpenClaw presets were labeled "Kimi K2.7 Code", unlike
the plain "Kimi" used by the other apps. Rename the preset (and the
OpenCode provider display name) to "Kimi" for consistency; the model
label stays "Kimi K2.7 Code" since it describes the actual model.
2026-06-22 10:28:10 +08:00
Jason c26d867f79 feat(providers): order preset selector — official first, prime partner next
In the default (Original) sort mode, float official-category presets to
the very top, followed by prime partners (Kimi), then the rest in their
original array order. Implemented as a three-way partition+concat so each
group keeps its internal order and no preset is listed twice.
2026-06-22 10:28:10 +08:00
Jason 26be9324dd feat(icons): refresh Kimi logo, K adapts to theme via currentColor
Replace the inline Kimi placeholder mark with the vendor's refreshed
logo. The K glyph uses `currentColor` so it follows the theme text color
(dark in light mode, white in dark mode), while the brand accent dot is
pinned to the new #1783FF. Align the metadata fallback color accordingly.
2026-06-22 10:28:10 +08:00
Jason 142c8c1da7 feat(providers): rebrand CTok to ETok across presets, icons, and docs
The vendor renamed its domain, API endpoints, and trademark from CTok to
ETok. Update all user-facing branding accordingly:

- Presets (claude, claude-desktop, codex, gemini, hermes, openclaw,
  opencode): ctok.ai -> etok.ai, api.ctok.ai -> api.etok.ai, internal
  provider id ctok -> etok, display name CTok.ai -> ETok.ai
- Icons: replace inline placeholder SVG with the new ETok brand PNG,
  moved from `icons` to `iconUrls`; key ctok -> etok; banner logo
  ctok.png -> etok.png
- README (en/zh/ja/de) partner banner: new logo, links, and copy
- i18n (en/ja/zh/zh-TW): partnerPromotion key ctok -> etok

Keep "ctok" in the Codex history-migration whitelist as a legacy id and
add "etok", so existing users' local session history stays correctly
bucketed after the rename.
2026-06-22 10:28:10 +08:00
PENG 6ec86cff46 docs: remove deprecated Homebrew tap step (#4319) 2026-06-22 09:55:51 +08:00
Huei Feng 455556380b Chat API: skip tool calls with missing function names (#4159)
* Chat API: skip tool calls with missing function names

Some providers send empty or absent function names in streaming
tool call deltas. Previously these produced invalid output items.

- Don't overwrite accumulated state.name with empty deltas
- Skip tool calls that never received a valid name (instead of
  falling back to 'unknown_tool')
- Apply the same defensive guard in finalize_tools and the
  non-streaming path

* Address review: defer empty-name skip to finalization

Require both call_id and name before triggering should_add,
instead of skipping eagerly when name is absent in the first
delta.  This handles providers that send id before name,
as suggested in the Codex review.

* Guard legacy function_call against empty name

Return Option<Value> from chat_legacy_function_call_to_response_item,
returning None when function_call.name is missing or empty. This covers
the legacy message.function_call path that the original guard missed.

* Remove unreachable unknown_tool fallback

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-06-19 23:38:25 +08:00
Arc 510aa250c5 add glm-5.2 pricing (#4385) 2026-06-18 23:24:20 +08:00
Jason d1b5df9a7b docs(partners): point Volcengine Coding Plan link to ai618 campaign 2026-06-18 17:43:11 +08:00
Jason dfa03b746a feat(providers): add prime-partner heart badge for Kimi presets
Introduce an optional primePartner flag on all provider preset interfaces.
Regular partners keep the gold star badge; prime partners render a solid
gold heart (no badge frame). Mark the first-party Moonshot Kimi presets
(Kimi / Kimi For Coding / Kimi K2.7 Code) across claude, codex, claude
desktop, opencode, openclaw and hermes as prime partners.
2026-06-17 13:04:23 +08:00
Jason 3d30dc03e8 docs(partners): swap pinned banner from MiniMax to Kimi K2.6 2026-06-17 11:54:36 +08:00
Jason 95495ad19e docs(partners): swap CCSub banner to high-res SVG, aligned aspect ratio
Replace the low-res ccsub.jpg with a vector SVG. Letterbox it from
2046x648 (3.157:1) to 2046x850 (~2.406:1) so it matches the other
sponsor-table banners and renders at the same height (62px @ width=150).
Point all four README locales at the new asset.
2026-06-17 11:10:39 +08:00
Jason b724f5dde9 revert(proxy): drop Anthropic system-message hoisting (#3775)
The unrelated Windows test fixes from #3775 are kept; tool-thinking-history normalization is unchanged.

Refs #4297
2026-06-16 22:39:27 +08:00
Jason 69341db284 fix(codex): probe CODEX_SQLITE_HOME when locating state DB for history migration
The session-history migration only scanned ~/.codex/state_5.sqlite and the
config.toml `sqlite_home` location. When Codex's SQLite state is relocated via
the CODEX_SQLITE_HOME env var, the state DB was never scanned and its threads
kept their old provider bucket. Add a CODEX_SQLITE_HOME fallback (config
`sqlite_home` still takes precedence) in the shared codex_state_db_paths helper
used by both the third-party and unified-session history migrations, plus serial
env tests.
2026-06-16 22:34:00 +08:00
Xinyu Kuo 0bb3b7515a feat(usage): support importing model pricing from models.dev (#4079)
* feat(usage): support importing model pricing from models.dev

Add an "Import from models.dev" button to the Add Pricing panel that
fetches https://models.dev/api.json, lists priced models sorted by
release date (newest 50 by default, full-text search across ~4800),
and bulk-imports the selected entries through the same
update_model_pricing command as manual entry.

- Normalize imported model IDs to match the backend's
  clean_model_id_for_pricing rules (strip vendor prefix, lowercase,
  truncate ':' suffix, map '@' to '-', drop the [1m] marker) so the
  stored rows actually match cost-attribution lookups
- Dedupe selections that collapse to the same model_id and report
  skipped duplicates in the success toast
- Invalidate usage queries on settled (not just success) so partial
  import failures still refresh the pricing list
- Keep ESC inside the picker's search input from closing the dialog
  and discarding the selection
- Add i18n keys for zh/en/zh-TW/ja and unit tests for the
  normalization, price formatting and flattening logic

Fixes #4017

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(usage): match scoped cost backfill against raw model aliases

The scoped backfill selected zero-cost rows via exact SQL string match,
but log columns store raw model strings (route prefixes, :free variants,
date suffixes), so alias rows were skipped until the next full backfill
on startup. Filter rows in Rust with the same model_pricing_candidates
normalization used by the pricing lookup; pricing decision logic is
untouched. Pre-existing gap from schema v11, surfaced by bulk import.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(usage): restrict models.dev pricing import to a single model

Each update_model_pricing call triggers a backfill pass that loads
every zero-cost usage row before filtering by model, so bulk-importing
N entries scaled as selectedModels x allZeroCostLogs full scans.
Re-importing pricing is rare, so drop the batch path instead of
optimizing it: the picker is now single-select, one import runs exactly
one update_model_pricing call and one backfill pass. This also removes
the normalized-ID dedup logic and the useImportModelPricing hook in
favor of the existing useUpdateModelPricing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 22:01:56 +08:00
Ruixe Wolf 81d6002ace 修复 添加供应商页面 搜索预设后无法点击选中搜索结果 (#4315)
* fix(provider-preset-selector): after searching presets, it is impossible to select search results.
feat(provider-preset-selector): add keyboard shortcut for search input and improve focus handling.

* fix(provider-list): prevent keydown event from triggering when default is prevented

* fix(provider-preset): keep preset clickable after search and restore keyboard UX

- ProviderList: scope the typing guard to the Ctrl/Cmd+F branch so Escape
  still closes the search panel (the top-level early return swallowed it);
  reuse isTextEditableTarget instead of re-implementing the check.
- ProviderPresetSelector: drop the rAF select() that raced with typing and
  ate the first character (gateway -> ateway), and restore the input
  autoFocus for the open-by-click path; refocus via rAF when Ctrl/Cmd+F is
  pressed while the box is already open so focus returns to the input.
- Add a regression test for the re-focus-on-shortcut behavior.

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-06-16 17:51:23 +08:00
Sean Wang caa912e3a3 fix: prevent duplicate codex base_url entries (#4316) 2026-06-16 17:01:01 +08:00
Zhou Kai 1042fb2a32 fix(terminal): respect user shell for provider terminals (#4140)
* fix(terminal): detect user default shell instead of hardcoded bash

All macOS/Linux terminal launch functions in misc.rs hardcoded `bash` as
the execution shell, causing zsh users' .zshrc to not load. Now detect
the user's default shell via $SHELL (macOS fallback /bin/zsh, Linux
fallback /bin/bash) and use it consistently across shebang, AppleScript,
spawn args, and interactive shell flags.

- Add get_user_shell(), get_shell_name(), interactive_flags_for_shell()
- Replace 10 hardcoded bash locations with dynamic shell detection
- zsh gets --norcs --no-globalrcs, bash keeps --norc --noprofile
- run_tool_lifecycle_silently unchanged (bash-specific syntax)
- Fixes #1546, Related #2385

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(terminal): use POSIX sh for script execution, user shell for interactive session

Address code review issues:
1. Replace shell-specific `read -n 1 -s`/`read -k 1 -s` with POSIX `read -r _`
   (press Enter to close) — ensures portability across bash/zsh/fish/dash
2. Unify AppleScript to use `sh` consistently (not mixing shell/shell_name)
3. Protect fish users: scripts always interpreted by POSIX sh, not fish
   (fish doesn't support trap/exec). exec line switches to user's shell.
4. Use build_exec_line to avoid trailing space when interactive_flags is empty

All terminal launchers now execute scripts via `sh`. Script shebangs are
`#!/bin/sh`. The exec line at script end switches to the user's detected
shell with appropriate clean-start flags. Terminal launcher functions no
longer need shell/shell_name parameters — simplified signatures.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix: validate user shell for terminal launch

* fix: load user shell config after terminal command

* test: align terminal shell exec expectations

* refactor(terminal): remove dead code, quote Warp path, unify shebangs

- Remove `interactive_flags_for_shell` (always returned "") and
  `get_shell_name` (no longer needed after removing flags); simplify
  `build_exec_line` to single-arg form
- Quote the Warp launcher script path with `shell_single_quote` for
  consistency with the main launcher scripts
- Unify all script shebangs to `#!/usr/bin/env sh` for better
  portability (e.g. NixOS where /bin/sh may not exist)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(terminal): fix linux shell exec helper call

* fix(terminal): run provider command through user shell

* fix(terminal): validate user shell executable

* fix(terminal): avoid interactive provider shell job

* fix(terminal): harden user shell launcher

Load zsh provider commands through the user's login and interactive environment, preserve launch cwd handling, and replace Terminal/iTerm launcher shells so the final user shell is restored cleanly.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-16 16:54:25 +08:00
Xu Song de0a149df5 feat(session-manager): show source file name in session detail header (#4113)
* feat(session-manager): show source file name in session detail header

Display the session log file name (with full path on hover) alongside
the project directory, so users can locate and copy the underlying
JSONL file directly from the UI.

* fix(session-manager): truncate long source file name in detail header

Long, space-less JSONL basenames (e.g. Codex rollout files at ~70 chars)
overflowed the flex meta row and bled into the action-button area on
narrow windows. Mirror the sibling project-dir span by capping the
filename at max-w-[200px] with truncation; the full path stays available
via the hover tooltip and click-to-copy.

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-06-16 12:08:48 +08:00
chen-985211 36b557b2e6 fix(codex): restore cached tool call fields (#4160)
* fix(codex): restore cached tool call fields

* refactor(codex): merge duplicate enrich loops in chat history

enrich_call_item_from_cache copied the fill-if-empty loop for
reasoning_content/reasoning. The two loops are identical and key
order is irrelevant, so fold both key sets into a single loop.

Pure refactor, no behavior change; codex_chat_history tests pass.

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-06-16 10:59:16 +08:00
Mask 3e38889ccc feat(proxy): strip effort params when thinking:disabled for DeepSeek endpoint (#4239)
DeepSeek's Anthropic-compatible endpoint rejects requests where
thinking.type=disabled coexists with effort parameters, returning
HTTP 400. This breaks Claude Code 2.1.166+ sub-agents (Workflow/Dynamic
Workflow), which hardcode thinking:disabled.

Rather than overriding thinking:disabled, remove the conflicting effort
parameters (output_config.effort / reasoning_effort) to respect Claude
Code's intent — sub-agents don't need to display reasoning.

Fixes: https://github.com/deepseek-ai/DeepSeek-V3/issues/1397

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 10:23:16 +08:00
muleizh 12567b3229 fix(settings): reset scroll on tab switch (#4165) 2026-06-16 08:29:36 +08:00
Jason c548e7fcba docs(guides): add trilingual Codex unified session-history guide
New zh/en/ja guide for the unified Codex session-history toggle: what opt-in migration (on enable) and ledger-based restore (on disable) actually do, why session data is never truly deleted (tag-only rewrite + automatic backups), and how to verify files on disk versus just being filed under another provider drawer. Includes a symptom reference table for the common "my sessions are gone" misunderstanding and on-disk verification commands for macOS/Linux/Windows.

Link the guide as the lead item in the "Usage Guides" section of the v3.16.3 release notes (zh/en/ja).
2026-06-15 10:17:25 +08:00
Jason 21e695f68a chore(release): prepare v3.16.3
- Bump version to 3.16.3 (package.json, tauri.conf.json, Cargo.toml, Cargo.lock)
- Add CHANGELOG entry for v3.16.3 (59 commits since v3.16.2)
- Add trilingual release notes (zh / en / ja) under docs/release-notes/
v3.16.3
2026-06-15 00:08:21 +08:00
Jason c678374c59 chore(presets): update Volcengine Ark Coding Plan invite link and promo copy
- Replace activity/agentplan links with the new codingplan invite URL
  (ac=MMAP8JTTCAQ2, rc=6J6FV5N2) across all 6 app presets
- Refresh partnerPromotion copy in all 4 locales: two-month 75% off plus
  invite code 6J6FV5N2; correct product name from Agent Plan to Coding Plan
- README: swap the CN-mainland redirect link in EN/DE, refresh the ZH promo
  copy, and add the redirect link to the JA BytePlus entry
2026-06-14 23:03:31 +08:00
Jason d307df92e9 chore(presets): drop isPartner flag from MiniMax presets across all apps
Remove the gold star badge and the partner promotion banner for MiniMax by
deleting the isPartner flag from all 12 MiniMax presets (cn + en) across
claude, claude-desktop, codex, opencode, openclaw, and hermes.

Both the preset-selector star (gated on isPartner) and the API-key promotion
banner (gated on isPartner && partnerPromotionKey) disappear as a result.
The partnerPromotionKey and the minimax_cn/minimax_en i18n copy are kept
dormant so the partnership can be re-enabled with a single line if needed.
MiniMax stays as a regular cn_official provider, keeping its icon and theme.
2026-06-14 21:47:46 +08:00
Jason 5092fe51ce fix(updater): prevent codex self-update from breaking npm platform-dispatch installs
Codex ships as an npm platform-dispatch package (JS launcher @openai/codex + per-platform binary optional deps like @openai/codex-darwin-arm64). The upgrade chain ran `<bin>/codex update || <bin>/npm i -g @openai/codex@latest`, which can leave codex throwing "Missing optional dependency @openai/codex-darwin-arm64":

- `codex update` on an npm install is a bare `npm install -g @openai/codex` that prints success and exits 0 even when the platform binary fails to land, short-circuiting the `||` npm fallback.

- The npm fallback is a no-op when version==latest and only targets the main package, so it can never re-land the missing platform binary.

Fixes: (1) remove codex from prefers_official_update (Posix+Windows) so npm-managed codex no longer runs the false-success `codex update`; (2) add a runnable=false gate in installs_anchored_command emitting an uninstall+install self-heal — the only repair that re-lands the platform binary; (3) narrow by source/real to npm-managed sources (nvm/fnm/mise/homebrew, non-brew-formula) so broken brew-formula/volta/bun installs fall back to their own anchored commands instead of being mis-repaired with npm. Reuses the existing enumerate runnable signal; no new FS probing.
2026-06-14 21:21:45 +08:00
Jason 34001aaffc perf(about): cache tool version probes across tab switches with a TTL
Settings uses Radix tabs, which unmount inactive tab content. Every time
the About tab was reopened, AboutSection remounted and its mount effect
re-ran all six tool version probes (a `--version` subprocess plus an
npm/github/pypi request each) -- wasteful, since versions rarely change
within a session and a manual Refresh already exists.

Add a module-scoped cache (lives for the app session, survives
unmount/remount) with a 10-minute TTL:

- on remount within the TTL the cached results are reused, skipping all
  probes; state is lazily initialized from the cache so the first paint
  shows the values with no loading flash
- a stale cache shows the old values immediately and revalidates per
  tool in the background (stale-while-revalidate)
- the Refresh button forces a re-probe; single-tool refreshes (shell
  change / post-update) update cached data without resetting the TTL
- cold-cache entries start at at=0 (a "not yet fully loaded" sentinel)
  so a partial cache left by a mid-probe tab switch is treated as stale
  and re-fetched rather than served as if complete; the real timestamp
  is only stamped once a full load finishes

The app's own version is cached too, purely to avoid a loading flash on
remount.
2026-06-14 21:21:45 +08:00
Jason 780acfa7de fix(about): decouple app version badge from tool version probes
getVersion() is a local, millisecond call but was awaited together with
loadAllToolVersions() in a single Promise.all, so setVersion and
setIsLoadingVersion only fired after all six tool checks finished. The
version badge under the app icon therefore waited for the whole batch.

Split the mount effect into two independent chains: loadAppVersion sets
the app version (and clears its loading flag) the moment getVersion()
resolves, while loadAllToolVersions runs its own progressive fan-out.
The two no longer block each other.
2026-06-14 21:21:45 +08:00
Jason 6bda3b0131 feat(about): render tool version checks progressively per tool
Fan out the six tool version probes concurrently instead of awaiting
one sequential batch, so each tool card updates the moment its own
check finishes rather than waiting for the slowest one.

- loadAllToolVersions now calls refreshToolVersions per tool via
  Promise.all, reusing the existing per-name merge and per-tool
  loading flags
- card loading derives from per-tool state
  (loadingTools[t] || (isLoadingTools && !resolved)) so a resolved
  card leaves loading independently while the batch is still in flight
- WSL shell/flag selects reuse the per-card loading flag, matching the
  install/update buttons' early-enable behavior

This also drops total wall time from the sum of six sequential probes
to the slowest single probe. get_single_tool_version_impl is already
isolated and read-only (shared HTTP client, spawn_blocking subprocess,
no shared state), so concurrent probes are safe.
2026-06-14 21:21:45 +08:00
Jason 89ff2d58d1 fix(usage): improve usage-query resilience and error surfacing
- useUsageQuery: retry once + keep-last-good — show the last successful
  result for up to 10min when a query fails transiently (network/timeout/
  HTTP 5xx), so a single blip no longer flips the card to red. Deterministic
  failures (auth, empty key, unknown provider, 4xx) surface immediately and
  clear the snapshot so a stale quota can't resurface after credentials change.
- bump native balance/coding-plan/subscription request timeouts 10s -> 15s
  for slow cross-border endpoints.
- coding_plan: return explicit errors ("API key is empty" / "Unknown coding
  plan provider") instead of a blank failure, mirroring balance.
- add unit tests for keep-last-good and transient/deterministic classification.
2026-06-14 21:21:45 +08:00
Jason 9a3d6a4e84 feat(about): add Fable 5 Verified banner to About section
Display the Fable 5 Verified banner to the right of the app name and version block on the settings About page, marking this as a special build. Center the version badge under the app name so the two rows share a common axis.

The app-side asset lives at src/assets/fable5-verified.png (imported via the @ alias and bundled by Vite); the original source banner is kept under assets/partners/banners/ alongside the other partner banners.
2026-06-14 21:21:45 +08:00
Jason fee354d09e fix(health-check): disable connectivity check for official providers, restore 6s degraded threshold
Official providers (Claude/Codex/Gemini/Claude Desktop) use OAuth with an intentionally empty base_url and connect via the client's default endpoint, so cc-switch has no reliable reachability target. Probing a guessed endpoint either hits the wrong target or returns a meaningless green light. Hide the connectivity button for category === 'official'; reachability stays available for copilot/codex-oauth/third-party/custom providers, which is where the old real-request probe produced false negatives. Revert the official base_url fallback added earlier — resolve_base_url is back to extract-or-error.

The 1500ms degraded threshold was too strict; normal ~1s probe latencies showed as 'slow'. Restore the original 6000ms scale (default + config panel + per-provider range). Keep the reachability-appropriate 8s timeout / 1 retry.
2026-06-14 21:21:45 +08:00
Jason a5903d8600 feat(health-check): replace real-LLM probe with HTTP reachability check
The provider panel health check sent a real streaming model request, which many third-party providers block (401/403/WAF), causing false negatives while only stable official endpoints passed. Replace it with a lightweight reachability probe: GET the provider base_url and treat any HTTP response (200/4xx/5xx) as reachable; only DNS/connect/TLS/timeout count as failure. Latency is the probe's TTFB.

Backend (services/stream_check.rs): rewrite ~2200 -> ~350 lines, dropping real-request building, format conversion, auth and API-path resolution while keeping per-app base_url extraction. Defaults: 8s timeout, 1 retry, 1500ms degraded threshold.

Failover invariant: the reachability check must never reset the circuit breaker (reachable != usable; a 403 host is reachable but broken for real traffic). Remove the resetCircuitBreaker call from useStreamCheck; failover failure detection stays driven solely by real proxy traffic (forwarder/circuit_breaker untouched). useResetCircuitBreaker is kept dormant for a future manual-recovery entry.

Open the check to all providers: drop the official/copilot/codex-oauth/third-party gating and the 'sends a real request' confirm dialog. For official providers whose base_url is intentionally empty, fall back to the endpoint the client actually uses (Claude -> api.anthropic.com, Codex -> chatgpt.com/backend-api/codex, Gemini -> generativelanguage). Non-official providers with a missing base_url still error to avoid a false green light. Claude Desktop Official is native 1P mode (talks to claude.ai, cc-switch not in the request path, no reliable endpoint) so its button stays hidden.

Slim StreamCheckConfig and per-provider testConfig to timeout/threshold/retries (drop test model + prompt); sync zh/en/ja/zh-TW. Retain the now-unused anthropic_to_openai/anthropic_to_gemini transform utilities and their test suites.
2026-06-14 21:21:45 +08:00
WangJiati b7ad1c4bf8 调整预设供应商按钮外观与搜索框位置 (#4183)
* 调整预设供应商按钮外观与搜索框位置

1. 调整预设供应商按钮外观,显示默认图标,大小统一;
2. 调整预设供应商搜索框位置。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(provider): 新增预设按钮外观与 inline 搜索的单元测试

覆盖:
1. 所有预设按钮固定 200px 宽度,视觉对齐一致
2. preset.icon 存在时按钮内渲染 ProviderIcon
3. preset 无 icon 且无 theme.icon 时渲染占位元素保持文字对齐
4. 点击放大镜 inline 切换搜索输入框可见性,ESC 收起并清空

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* refactor(provider-preset): responsive grid layout and search polish

- Replace fixed-width preset buttons with a responsive CSS grid (auto-fill, 150px min column)
- Add a leading placeholder to the custom button so its label aligns with iconed presets
- Close the inline search box on outside click, restoring the old Popover behavior
- Span the empty-state hint across the full grid row
- Update component tests for the new layout and behaviors

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-06-14 18:18:43 +08:00
thisTom 0c46efe1be fix(macos): prevent duplicate provider terminal sessions (#4156)
* fix(macos): prevent duplicate provider terminals

* fix(macos): keep Ghostty fallback on AppleScript failure

---------

Co-authored-by: thisTom <19346741+thisTom@users.noreply.github.com>
2026-06-14 16:55:23 +08:00
Jason 11572b1337 feat(codex): restore Kimi For Coding preset with thinking on by default
The Kimi For Coding preset was removed (74104946) because the coding
endpoint (api.kimi.com/coding/v1) enforces a User-Agent whitelist that
rejects Codex's default codex-cli UA with 403. The provider-level custom
User-Agent feature now lets users override the UA (to claude-cli/*) under
proxy takeover, so the preset can be restored.

- Re-add the Codex Kimi For Coding preset (openai_chat, kimi-for-coding,
  256K context) in the same position it was removed from.
- Enable thinking mode by default via codexChatReasoning (supportsThinking
  true, thinkingParam "thinking"), mirroring the general Kimi preset since
  both target the same Moonshot model family. The proxy injects
  thinking:{type:enabled} when Codex requests reasoning.
- Restore the trilingual user-manual row to "Kimi / Kimi For Coding".

Note: this preset requires proxy takeover and a whitelisted custom
User-Agent to work; the default codex-cli UA still gets 403.
2026-06-13 23:47:27 +08:00
Jason 3bb17434fb test: align preset tests with Kimi K2.7 and Fable model tiers
Update the Codex chat preset test's Kimi expectation (kimi-k2.6 -> kimi-k2.7-code) after the Kimi K2.7 upgrade, update the Claude Desktop form test for the four-tier (Sonnet/Opus/Fable/Haiku) routes, and reformat UsageDateRangePicker imports (prettier).
2026-06-13 23:16:11 +08:00
Jason efbb52a3fc feat(presets): add GLM 5.1 context window for AtlasCloud Codex preset
Declare the 200000-token context window for zai-org/glm-5.1, matching the other GLM 5.1 preset entries.
2026-06-13 23:16:11 +08:00
Jason b37a9e8f60 chore: remove stray nested preset file accidentally committed in #667
cc-switch-main/src/config/universalProviderPresets.ts was an outdated duplicate of the real preset file, introduced by mistake in #667 and referenced by no code. Remove the orphaned nested directory.
2026-06-13 23:16:11 +08:00
Jason 1992d6be72 feat: add Kimi K2.7 Code model and upgrade official Kimi presets
Add kimi-k2.7-code pricing seed (in $0.95 / out $4.00 / cache-read $0.19
per 1M tokens, 256K context) and point all six official Moonshot Kimi
presets (Claude Code, Codex, Claude Desktop, Hermes, OpenCode, OpenClaw)
at the new model. Rename the version-tagged OpenCode/OpenClaw presets to
"Kimi K2.7 Code" and correct the OpenClaw context window to 262144.

The seed is applied via the idempotent INSERT OR IGNORE path that runs on
every startup, so existing users pick up the new pricing without a schema
migration. Kimi For Coding and Nvidia presets are intentionally untouched.
2026-06-13 22:26:36 +08:00
Jason 276b2572a3 fix(providers): scope preset search to provider names only
The preset search text also included websiteUrl and the shared category label, producing imprecise matches: a single category term matched the whole group, and URL fragments like "com"/"api" matched nearly everything. Restrict the search text to the display name and raw name; category labels are still used for rendering.
2026-06-13 22:15:32 +08:00
Jason cd8252c7d9 fix(ui): raise popover/tooltip z-index above fullscreen panels
PopoverContent and TooltipContent used z-50, below FullScreenPanel's z-[60] opaque overlay. Popovers such as the provider preset search therefore rendered behind the panel and looked unresponsive on click. Bump both to z-[100], matching the select dropdown: above fullscreen panels, below modal dialogs (z-[110]).
2026-06-13 22:15:31 +08:00
Jason 526bb60f5c fix(ui): make Claude Desktop model-mapping placeholders role-consistent
The menu display name and request model columns used mismatched example
brands (DeepSeek vs Kimi), implying a display name maps to an unrelated
request model. Derive both placeholders from the row role so each row
stays brand-consistent, and route the lightweight Haiku tier to a flash
example (deepseek-v4-flash) while other tiers use deepseek-v4-pro.
2026-06-13 20:16:09 +08:00
Jason 4f8a79c273 feat: add Claude Fable 5 model mapping across Claude Code and Desktop
- Wire claude-fable-5 as a fourth tier on both proxy paths, with a
  fable -> opus -> default fallback mirroring the official downgrade.
- Whitelist the fable- prefix for the Desktop 1.12603.1+ validator.
- Clarify fallbackModelHint (zh/en/ja/zh-TW): a blank tier on
  third-party endpoints forwards the literal model name and 404s.

Refs #3980, #4026, #4049.
2026-06-13 19:12:34 +08:00
Jason 6e519a7496 fix(usage): compact toolbar controls and unify visual style
- Reduce all four filter controls to w-[100px] h-9
- Add ChevronDown icon to date picker trigger for consistency
- Suppress focus border highlight on select triggers after close
2026-06-12 23:48:41 +08:00
Jason a95b22dd79 fix(ui): keep ToggleRow icon from shrinking next to long descriptions 2026-06-12 23:35:07 +08:00
Jason eab6bfd20c feat(codex): add opt-in migration and ledger-based restore for unified session history
- Enable dialog gains a checkbox (default off) to migrate existing
  official sessions from the built-in "openai" bucket into the shared
  "custom" bucket, with per-generation backups; failed migrations retry
  at startup
- Disable dialog offers a precise restore driven by the backup ledger:
  only sessions recorded as "openai" in backups are flipped back, and
  sessions created while the toggle was on are never touched
- Completion marker and backup generations are bound to the canonical
  Codex config dir; migrate/restore serialize on an op lock and the
  marker is written conditionally inside the settings write lock
- save_settings rolls back the toggle and fails the save when the live
  rewrite fails; migration additionally requires the live config to
  actually route to the shared bucket (skips with live_not_unified so
  refused injection or proxy takeover can't split history)
- Restore refuses to run while the toggle is (re-)enabled and reports
  nothing_to_restore instead of a zero-count success; local migration
  markers are now backend-owned in merge_settings_for_save so stale
  frontend payloads can't resurrect them
- Settings autosave reverts optimistic form state on failure so a
  failed toggle change can't be replayed by an unrelated save
- ConfirmDialog supports an optional checkbox; all four locales updated
2026-06-12 23:35:01 +08:00