Commit Graph
2455 Commits
Author SHA1 Message Date
Jason 09498c30cd fix(ui): render monochrome preset icons in the foreground color
Icons that paint with currentColor inherited the preset button's
text-muted-foreground, so the same icon looked mid-gray in the preset
selector but near-black in the form's icon preview and on the provider
card. The mismatch hit all 28 monochrome icons and was most visible on
9527CODE, whose 0.82-opacity base layer lightened the gray further.

Unselected preset icons now take text-foreground; selected ones still
inherit the button's text-white. The universal preset row gets the same
treatment. Brand-colored icons are unaffected because ProviderIcon sets
their color inline.
2026-09-21 21:45:23 +08:00
Jason 060099d72a docs(user-manual): point Chat-only Codex examples at plan endpoints
Baidu Qianfan and StepFun now ship native Responses presets for their
pay-as-you-go APIs, so the Chat-only examples name the offerings that
still route through Chat: Baidu Qianfan Coding Plan and StepFun Step
Plan. Synced across the zh/en/ja manuals.
2026-09-21 21:45:23 +08:00
Jason d8e98be2c7 fix(pricing): restore DeepSeek V4 Pro price and seed Qwen3.8 and Hy4 models
- deepseek-v4-pro returns to its peak list price 1.32/3.96/0.044. The
  2026-09-11 move to the V4.1 Flash price anticipated a cutover that
  DeepSeek retracted on 2026-09-12. Replace that repair entry with one
  that restores rows still at 0.3/1.2/0.006; keeping both would rewrite
  the row back and forth on every start.
- Seed hy4-preview (CNY 6/18/0.3 at 7.14), qwen3.8-2.4t-a95b and
  qwen3.8-27b (Alibaba Cloud international list prices).
2026-09-21 21:45:23 +08:00
Jason e06ff90f8f fix(presets): move MiniMax CN and BaiLing to their current official endpoints
- MiniMax CN: the remaining apps switch from api.minimaxi.com to
  api.minimax.cn (Anthropic root /anthropic). Usage detection recognizes
  both hosts and now matches on host labels (frontend, and the global
  host in the backend), so look-alike hosts and URLs that only carry the
  domain in their path are ignored. The quota query keeps
  api.minimaxi.com, the only CN host documented for that endpoint.
- BaiLing: the remaining apps switch from api.tbox.cn to
  api.ant-ling.com (/v1 and /anthropic) and default to Ling-2.6-1T,
  since Ling-2.5-1T is no longer listed in the current docs. Ling-2.6-1T
  is registered as text-only (vision ships as separate -VL models).
- Reword the DeepSeek V4 Pro note in the text-only registry: the vendor
  keeps serving V4 Pro after September 14, 2026.
2026-09-21 21:45:23 +08:00
Jason 48e572cc87 feat(codex): refresh CN presets from the Responses API audit
- Kimi For Coding: kimi-for-coding now serves K2.8 Preview (up to 1M,
  text+image, low/high/max); the highspeed variant stays at 256K.
- DeepSeek: default to deepseek-flash (V4.1 Flash, text+image) and
  declare deepseek-v4-pro text-only, matching the bundled official
  catalog.
- Add native Responses presets for StepFun API (CN/intl,
  step-3.7-flash), Baidu Qianfan pay-as-you-go (/v2) and iFlytek Astron
  Coding Plan; subscription plans on the same hosts stay on Chat.
- Add hy4-preview to Tencent Hunyuan, and the open-weight
  qwen3.8-2.4t-a95b / qwen3.8-27b to both pay-as-you-go Qwen platforms.
- MiniMax CN moves to api.minimax.cn and BaiLing to api.ant-ling.com.
- Disable Codex web_search on StepFun (function tools only), and
  conservatively on Qianfan and Astron, whose Responses docs document no
  hosted tools. The new hosts stay out of CODEX_NATIVE_RESPONSES_HOSTS
  so Chat plans on the same hosts are never reclassified as native.
- Tencent Enterprise Token Plans stay on Chat: /plan/v3/responses is
  listed, but TokenHub marks Kimi K2.7 Code unsupported and several
  models as server-side Chat conversions, and the catalog levels were
  verified on Chat only.
2026-09-21 21:45:23 +08:00
Jason 7f39d88584 test(claude-desktop): run Linux path tests on unix hosts and cover Linux in provider sync tests
Follow-up to #7331 (Claude Desktop 3P configuration on Linux):

- Compile the Linux config-dir resolver and its three unit tests under
  any unix test build so they run on macOS as well as CI ubuntu. The
  gate is unix rather than test because the assertions use POSIX
  absolute paths, which are not absolute on Windows.
- Open the provider -> Claude Desktop profile sync integration tests to
  Linux: add the Linux profile path helper and pin XDG_CONFIG_HOME under
  the temporary home (saved on construction, restored on drop).
- Update the support-scope table in the en/zh/ja user manuals to list
  Linux and note that the Flatpak build always uses the host ~/.config.
2026-09-21 21:45:23 +08:00
Jason 2c735bd9de fix(ui): stop expanding stale cached usage tiers on ineligible provider cards
A disabled React Query observer still returns the existing cache entry for
the same key, so a provider switched to the official subscription template
(or with its usage script disabled) kept showing the multi-plan chevron and
the expanded tiers left over from a previous script result.

Gate hasMultiplePlans with the same predicate that enables the usage query,
extracted as scriptUsageActive so the two cannot drift apart again.
2026-09-21 21:45:23 +08:00
xie well 8272707d5e fix(skills): 支持 skillId 与目录名不一致的技能安装和更新 (#6381)
* fix(skills): resolve mismatched skillId directories

* fix(skills): preserve source path during updates

* fix(skills): refresh source URL after repository relocation

* test(skills): isolate relocation fixture from legacy home
2026-09-21 11:38:30 +08:00
funkpopo fdbe3a85b2 feat(opencode): 支持从获取的模型列表中搜索并批量添加所选模型 (#7515)
* feat: implement fetched models selection and UI components

* fix(opencode): prevent model search from submitting provider form
2026-09-20 22:27:20 +08:00
Tony Yu 1408f38279 Add Kimi Global preset variants (kimi.ai platform + api endpoints) (#7526)
Add a "Kimi Global" twin immediately after the domestic "Kimi" API preset and a "Kimi For Coding Global" twin after the domestic "Kimi For Coding" preset, in every preset file that ships them (claude, claude-desktop, codex, hermes, openclaw, opencode, pi).

"Kimi Global" points to the international open platform https://platform.kimi.ai?aff=cc-switch (apiKeyUrl mirrored as https://platform.kimi.ai/console/api-keys?aff=cc-switch) and swaps the endpoint host api.moonshot.cn for api.moonshot.ai with each file's path unchanged (/v1 or /anthropic).

"Kimi For Coding Global" points to the international site https://www.kimi.ai/code/?aff=cc-switch and swaps the endpoint host api.kimi.com for api.kimi.ai with the path unchanged (e.g. https://api.kimi.ai/coding/v1).

Domestic presets are unchanged; category, icons, apiFormat, model catalogs, endpointCandidates (host swapped), partnerPromotionKey and settings otherwise mirror the domestic blocks exactly.

primePartner stays only on the domestic presets so the new variants do not alter prime-partner ordering.

The Pi twins get distinct providerKey values ("cc-switch-kimi-global", "cc-switch-kimi-for-coding-global") because providerKey is the preset-level primary key and must not collide with the domestic presets.
2026-09-20 17:44:47 +08:00
Tony Yu f2d0b2a6c8 Rebalance sponsor CTAs around Kimi Code plan with dual-region links (#7522)
Kimi Code plan purchases have resumed, so the README sponsor sections go back to leading with the coding plan instead of the API-only flow written during the purchase pause.
All four locales (EN/ZH/JA/DE) now present Kimi Code plan (中文站 | Global) as the primary CTA and the Kimi Open Platform API (中文站 | Global, with the first-top-up bonus) as the secondary one, mirroring the domestic|global split already used for API links.
The aff and track_id values are unchanged.
2026-09-20 17:44:34 +08:00
Allen Xu a659440b9f fix(prompts): refresh active prompts after external file edits (#7194)
Reload the enabled prompt from its live file when the Prompts list loads, and refresh the open panel when the window regains focus, so external edits to CLAUDE.md / AGENTS.md show up without a restart.

- Keep saved templates available when the live file cannot be read.
- Skip the backfill for empty or whitespace-only files, matching enable_prompt.
- Skip the backfill while a sync/restore holds the sync lock, so a list load cannot write a stale live file into a freshly restored database.
2026-09-20 17:13:55 +08:00
yovinchen 33c806269f fix(skills): raise archive entry limit so large skill repos install (#7489)
Installing hugohe3/ppt-master from skills.sh failed with
ARCHIVE_TOO_MANY_ENTRIES: the GitHub archive we download is the whole
repository (13,248 entries), and the 10,000-entry cap added in #5811
treated it as a zip bomb.

- Raise MAX_ARCHIVE_ENTRIES to 30,000 for both the remote archive and
  local ZIP paths, and align WebDAV's MAX_EXTRACT_ENTRIES so a skills.zip
  containing such a skill still restores.
- Charge every file entry at least one 4 KiB block against the existing
  512 MiB budget, mirroring directory accounting, so empty-file archives
  are bounded by the byte budget rather than by the entry count alone.
- Add tests for a 13k-entry repo archive and for the per-file minimum
  charge.

Fixes: https://github.com/farion1231/cc-switch/issues/7475
2026-09-20 16:24:30 +08:00
SaladDay 06082e189d feat: add MiniMax Code harness support (#7383)
Add MiniMax Code (mcode) as a managed application: provider and model management through the native custom_provider configuration, MCP servers, Skills, global instructions (AGENTS.md), read-only local session history with resume, and usage import from the native runtime database. Native files shared by the TUI and desktop are written under the native lock with rollback when the database commit fails, unrelated native configuration is preserved, and the data directory honors MINIMAX_DATA_DIR and MAVIS_DATA_DIR. Deleting sessions stays in the native application because they are coupled to runtime state.
2026-09-15 12:33:49 +08:00
SaladDay 15884b2038 fix(codex): recover stale account bindings during takeover (#7395)
After deleting a managed ChatGPT account and logging in again, a Codex provider can still reference the old local account ID, which made route switching, takeover, startup restoration and rebinding fail permanently.

Distinguish a missing outgoing account from an existing account with no matching live token. A missing account only releases its ownership marker after the persisted account store is verified; the target write policy stays in force. A stale target now reports an account-selection instruction instead of a bare not-found error, including when takeover is already enabled.

Fixes #7392
2026-09-15 11:30:24 +08:00
Railgun 42ac174dbc feat(claude-desktop): support 3P configuration on Linux (#7331)
Add Claude Desktop 3P configuration support on Linux. Resolve the config root from an absolute XDG_CONFIG_HOME, falling back to ~/.config; when CC Switch itself runs as a Flatpak, use the host ~/.config instead of the sandbox-private XDG_CONFIG_HOME. Update the en/zh/ja user manuals with Linux paths and the Flatpak boundary.

Fixes #4855
2026-09-14 17:09:18 +08:00
Sailing LoongandSailingLoong bd247a4adb fix(proxy): omit missing tool descriptions instead of serializing null (#7319)
Co-authored-by: SailingLoong <309827397+SailingLoong@users.noreply.github.com>
2026-09-13 23:41:36 +08:00
Sailing LoongandSailingLoong c6286e1436 fix(proxy): keep reasoning effort for grok-4.6 and pass xhigh through verbatim (#7318)
Co-authored-by: SailingLoong <309827397+SailingLoong@users.noreply.github.com>
2026-09-13 23:21:37 +08:00
雨奇晴好 f49c7d68ad fix(models): support Zhipu OpenAI Responses model lists (#7330)
Zhipu's Responses endpoint (open.bigmodel.cn/api/v1) serves its model list in the Codex remote catalog shape (models[].slug) instead of the OpenAI-compatible data[].id shape, so the Codex form's model fetch came back empty. The parser now falls back to models[].slug when data is absent.
2026-09-13 23:06:50 +08:00
Sean Sun 556bb2cab6 fix(misc): fetch npm dist-tags from the dedicated endpoint with the probe timeout (#7346)
The tool version probe requested the full npm packument for each package (metadata for every historical version, 14-25 MB uncompressed for codex / opencode / openclaw) only to read its dist-tags, and it was the only latest-version probe without LATEST_PROBE_TIMEOUT, so it fell back to the proxy client's 600 s total timeout and the cards sat on "loading" for minutes on slow links while the large downloads starved the Hermes GitHub probe into "unknown".

Switch fetch_npm_dist_tags to registry.npmjs.org/-/package/{package}/dist-tags, whose body is the dist-tags object itself (tens of bytes to a few KB), escape scoped names as %2f, and apply the same 15 s probe timeout as the GitHub and PyPI probes. No data is lost: the only consumer reads latest and the tool's prerelease tags.

Fixes #7339
2026-09-13 21:11:07 +08:00
Juexe dc0febe503 feat(usage): display output tokens per second in request log table and detail panel (#3369)
Show tokens/s next to the output token count in the request log table and the request detail panel.

The generation window prefers an explicit duration when present, otherwise latency minus first-token time for streaming requests, and falls back to full latency for non-streaming requests. Rows without a positive token count or window show nothing.

Closes #5936
2026-09-13 18:05:36 +08:00
Jason 1d5d90f4ab fix(presets): update APIKEY.FUN URLs to apikey.fan 2026-09-12 20:27:33 +08:00
Jason d695a2d77f docs(release): add v3.20.3 release notes v3.20.3 2026-09-11 23:23:51 +08:00
Jason 1a7250162c chore(release): v3.20.3 2026-09-11 23:23:51 +08:00
Jason 746e228852 fix(pricing): move retired DeepSeek V4 family to the V4.1 Flash tier
DeepSeek retired V4 Flash and announced that V4 Pro is routed to V4.1
Flash and billed at the Flash price from 2026-09-14 12:00 (Beijing).
Executing that callback early per maintainer decision.

- Seed `deepseek-flash` (the only currently recommended id) and
  `deepseek-v4-flash-vision-exp` so the `LIKE '{id}-%'` prefix fallback
  cannot silently bill them at zero.
- Reprice `deepseek-v4-flash` / `-0731` / `-pro` to 0.3 / 1.2 / 0.006
  with chained repair guards ordered after the 2026-08-16 peak/off-peak
  rows; `deepseek-chat` / `deepseek-reasoner` stay untouched for lack of
  an authoritative source.
- Drop `deepseek-v4-pro` from the confirmed text-only registry: it now
  lands on a vision-capable model, so the image sanitizer must fail open.
  Fixtures that relied on it being text-only switch to `qwen3-coder-plus`,
  including the two media_sanitizer tests #7286 had just pointed at it.
2026-09-11 16:56:34 +08:00
Jason 6867b64de1 fix(presets): declare third-party Token Plan DeepSeek V4 rows text-only
DeepSeek's official endpoint now routes the legacy deepseek-v4-flash id to
the vision-capable V4.1 Flash, so #7286 removed it from the confirmed
text-only registry and the id fails open everywhere. Baidu Qianfan and
Tencent Token Plan still host the text-only V4 deployments (Qianfan's
Coding Plan doc states image input returns 400; Tencent's 2026-09-10 plan
rosters list V4 only), so their preset rows must carry an explicit
inputModalities: ["text"] declaration instead of relying on the registry.

Covers the flash and pro families incl. -0731/-0813/-202605/-202606 rows,
and adds a preset test that also locks the official DeepSeek preset to
stay undeclared (fail-open).

Follow-up to #7283.
2026-09-11 16:47:47 +08:00
Jason f874803f27 feat(presets): rename DouBaoSeed preset to localized Volcengine Doubao
Rename the DouBaoSeed provider preset across all seven app preset files
and localize its display name: zh/zh-TW show "火山 豆包AI", en/ja show
"Volcengine Doubao" via the new providerForm.presets.doubaoseed key.

Following the existing Qiniu/Compshare convention, the top-level name
holds the latin fallback (so the preset stays searchable in both
scripts) and the localized name lives in the locale files. OpenCode and
Pi settingsConfig.name, which is written into the client config files,
keeps the ASCII form.

Live-config identifiers are deliberately untouched: the Codex TOML
provider name, the Hermes node key doubao_seed, Pi's providerKey, the
OpenClaw model-ref prefix, partnerPromotionKey and icon.
2026-09-11 16:47:47 +08:00
Jason 45b9a952a6 fix(codex): skip unchanged incomplete rollout tails
Follow-up to #7219. The parser counted only fully consumed records toward
the persisted byte length, so a rollout that ends mid-record or in
whitespace (a crashed session that was never resumed) always looked
shorter than its file size and was fully reparsed on every sync pass.

Count the bytes of the incomplete tail as observed too. The line cursor
still stops before the incomplete record, so it is retried as soon as the
file grows, while an unchanged file is skipped on the mtime+size gate.
Tests prove the skip via total_changes() rather than a zero import count.
2026-09-11 16:47:47 +08:00
Jason 5c05362600 fix(claude): align quick model selection with form order 2026-09-11 16:47:47 +08:00
Jason 3b1292fee5 fix(tray): show bound ChatGPT account quota for managed Codex cards
Since #6537 the tray deliberately dropped the usage suffix for Codex
official cards bound to a managed ChatGPT account: the tray only had an
app-wide subscription cache fed by whatever login the Codex CLI holds
(macOS Keychain first, then auth.json), which cannot represent
account-scoped quota safely once several accounts are bound. The provider
card queried the bound account through `get_codex_oauth_quota`, but that
result never reached the tray, so users with multiple ChatGPT logins saw
`Codex · <name>` with no quota at all.

- UsageCache: add an account-keyed `codex_oauth` snapshot map
  (`put_codex_oauth` / `with_codex_oauth`), cleared by `invalidate_all`.
- `get_codex_oauth_quota`: write the `Ok` snapshot through to the cache
  under the resolved account id and schedule a tray label refresh.
  Transport errors keep the last good snapshot; auth/HTTP failures replace
  it so the tray hides an invalid quota instead of a stale one.
- Tray: introduce `TrayUsageSource` so the refresh path and the display
  path share one decision. Managed Codex cards read only their bound
  account's snapshot (never a provider-scoped or CLI snapshot as fallback),
  default to enabled when no usage toggle has been saved (matching
  ProviderCard), and the fixed official card takes the managed path too
  when it carries a binding. Rebinding a card switches to the new
  account's snapshot immediately and a late response for the previous
  account cannot overwrite the label.
- Tests: source selection across binding/toggle/legacy shapes, label
  rendering across switch, rebind, late response, disabled and expired
  states, and the native fixed card still using the CLI subscription.

Fixes #7267
2026-09-11 16:47:47 +08:00
Jason deb0e874ff feat(claude): add "Disable Artifact Tool" quick toggle to provider editor
Some third-party Anthropic-compatible gateways (e.g. DeepSeek) validate
tool JSON Schemas with a strict regex checker and reject the Unicode
property escapes (\p{Cc}...) that Claude Code's Artifact tool emits when
its str_replace db capability is rolled out, failing every request with
400 "Invalid schema for function 'Artifact'". The failure is independent
of the model selected.

Add a sixth checkbox next to the existing Claude quick toggles that sets
env.CLAUDE_CODE_DISABLE_ARTIFACT="1" on the provider, which keeps the
Artifact tool out of the tools array entirely. Unchecking removes the key
like the other toggles do. Labels added for zh/en/ja/zh-TW and the user
manual toggle table updated in zh/en/ja.
2026-09-11 16:47:47 +08:00
Jason 5e1292736e feat(codex): refresh aggregator model presets and catalogs 2026-09-11 16:47:47 +08:00
Jason 08984ba591 feat(codex): switch Kimi presets to native Responses direct-connect
Both Kimi open platform (api.moonshot.cn/v1) and Kimi For Coding
(api.kimi.com/coding/v1) now serve /v1/responses natively and their
official Codex guides require wire_api = "responses", so the two presets
move from openai_chat (proxy Responses->Chat conversion, routing takeover
required) to openai_responses (Codex connects directly). Verified against
both endpoints with real keys using the exact Codex 0.153.4 request shape
(include reasoning.encrypted_content, reasoning.summary, hosted web_search,
replayed reasoning items) and with codex exec end-to-end tool loops.

- kimi-k3 becomes the default open-platform model and first catalog row;
  kimi-k2.7-code stays as a second row (it also answers on /v1/responses,
  although the OpenAPI only lists kimi-k3)
- drop codexChatReasoning (Chat-conversion only) from both presets and
  promptCacheRouting from Kimi For Coding (Codex sends prompt_cache_key
  itself on the native path; the proxy auto-detects the host anyway)
- declare supportsParallelToolCalls on every Kimi row, mirroring the
  official Kimi Code models.json
- no reasoning default is declared: config.toml model_reasoning_effort
  wins over the catalog default, which only marks the /model picker
- move the two presets from the Chat list to the native list in the
  preset tests; invert the prompt-cache-routing assertion
- refresh the user manual (zh/en/ja) so the "Chat-only" examples name
  providers that still use Chat routing, and correct the stale
  userAgentPresets note about Kimi Code rejecting codex-cli

No backend change. Existing Kimi cards keep their stored openai_chat
format and continue to work through routing; switch a card's upstream
format to Responses (or re-add the preset) to connect directly.
2026-09-11 16:47:46 +08:00
Jason bfbbf15cb2 fix(usage): show Claude Fable weekly limit from the usage API limits array
The Claude OAuth usage API now reports model-scoped weekly limits in a
top-level `limits[]` array (`kind: "weekly_scoped"`, `scope.model.display_name`,
`percent`) instead of dedicated top-level windows. The parser only read the
legacy windows, so the Fable limit never showed up in the provider card or
the tray.

- Extract `parse_claude_quota` and parse `limits[]` into `seven_day_fable`,
  `seven_day_opus` and `seven_day_sonnet`; scoped rows override the legacy
  window of the same name, duplicates and malformed rows are skipped, and
  legacy windows / extra usage / unknown windows are preserved.
- Tray: give Fable its own label group so it is not merged into the weekly
  max value.
- Frontend: add the `seven_day_fable` label ("Fable") in all four locales.
- Tests: parser edge cases, tray summary for both quota and flattened script
  paths, and footer rendering for inline/expanded layouts and locales.
2026-09-11 16:47:46 +08:00
Sailing Loong 7726c83476 fix(codex): mirror vision-capable DeepSeek catalog and un-gate the legacy v4-flash alias (#7286)
Refresh the bundled DeepSeek official Codex catalog to the vendor's current models.json (slug deepseek-flash, image input modality, supports_image_detail_original) and remove deepseek-v4-flash from the confirmed text-only registry: the legacy id is still accepted by DeepSeek and routed to the vision-capable V4.1 Flash, so both the proxy media sanitizer and the generated Codex catalog must fail open for it. deepseek-v4-pro stays text-only per the vendor catalog.

Fixes #7283
2026-09-11 11:47:30 +08:00
Sailing Loong 6e4b0e6e21 fix(proxy): clamp sub-floor max_tokens to the Responses API minimum (#7287)
The Responses API rejects max_output_tokens below 16, but Anthropic clients legitimately send tiny probe budgets (Claude Desktop's model-availability probe uses max_tokens=1). The Anthropic→Responses conversion copied the value verbatim, so strict upstreams returned 400 and Claude Desktop reported the mapped model as unavailable under local routing.

Clamp 1..=15 up to 16 during conversion; 16+, 0 and non-integer values keep their pass-through semantics. Normal session requests convert byte-for-byte as before, and the Codex OAuth path still strips max_output_tokens afterwards.

Fixes #7103
2026-09-11 10:23:19 +08:00
GGbondandBigStrongSun 5e0f3442ea fix(codex): coalesce adjacent commentary with pending tool calls (#7280)
The Codex Responses -> Chat Completions converter emitted two consecutive
assistant messages when one Responses model turn contained a commentary
message directly followed by function_call items. Chat upstreams imitate
the text-only assistant message as a complete turn and return
finish_reason=stop before the expected tool call, so long agent tasks end
after a progress update.

Merge pending tool calls into the directly adjacent assistant message when
it carries no tool_calls yet, attach pending reasoning per segment so
parallel calls do not duplicate it, and keep the new-message path for every
other boundary shape (user/tool boundaries, prior tool-call batches, media
flushes). The reasoning placeholder backfill still applies to coalesced
calls without reasoning.

Fixes #6529
Supersedes #6530

Co-authored-by: BigStrongSun <BigStrongSun@users.noreply.github.com>
2026-09-11 10:23:12 +08:00
Gongzhen Hu b78192e8fe fix(proxy): skip empty reasoning_content placeholders in Anthropic SSE streaming (#7227)
Some OpenAI-compatible upstreams (GLM, Qwen, DeepSeek-V4-Pro via ModelScope/DashScope,
Bailian, JD Cloud, ...) keep a `reasoning_content: ""` placeholder in every content
chunk instead of omitting the field. The reasoning branch of the OpenAI Chat -> Anthropic
SSE converter only checked for presence, and it shares `current_non_tool_block_type`
with the content branch, so every content chunk closed the open text block, opened an
empty thinking block, then reopened a text block. N content chunks became 2N content
blocks, half of them empty thinking blocks, which Claude Code rendered as one line per
token with dozens of empty Thought blocks and bloated the session JSONL.

Filter empty reasoning before entering the branch, matching the `!content.is_empty()`
guard the content branch already had and the non-streaming `openai_to_anthropic`
converter. Two regression tests pin block index, type and order: the placeholder shape
must yield a single text block and no thinking_delta at all, and real reasoning must
still yield one thinking block followed by one text block.

Fixes #5028
Fixes #4404
2026-09-11 09:25:00 +08:00
woniuxiaoshu 45f9e8190d fix(codex): detect growing rollouts with a persisted byte cursor (#7219)
Codex keeps the rollout append handle open for the whole session, so on Windows NTFS the file mtime does not advance while the file grows and the pure-mtime gate skipped growing rollouts forever. Persist the observed byte length in session_log_sync.last_byte_offset for Codex rows and skip a file only when both mtime and size are unchanged. The parser now splits records on newlines manually so an incomplete trailing record is retried on the next pass without advancing the line cursor.

Fixes #6060
2026-09-11 08:24:14 +08:00
e098279934 fix(codex): proxy image edits and Images API follow-ups (#7177)
* fix(codex): proxy image edits and Images API follow-ups

Follow-ups to #7036 for Codex's built-in ImageGen over the local proxy:

- Register `/images/edits` aliases (bare, `/v1`, `/v1/v1`, `/codex/v1`)
  and forward them through the shared Codex standalone passthrough.
  ImageGen posts to `images/edits` whenever a call references existing
  images, and the router returned an empty 404 for it.
- Add `CodexStandaloneEndpoint::ImagesEdits`. Both Images endpoints share
  one full-URL suffix table, so a complete Responses / Compact / Chat
  Completions / Images URL derives the sibling endpoint (and vice versa)
  while opaque full URLs keep failing closed.
- Apply the standalone sibling rewrite when the base URL is pasted as a
  complete endpoint with the full-URL switch off, mirroring
  `codex_chat_base_is_full_endpoint`; standalone requests no longer become
  `.../chat/completions/images/generations`.
- Parse Images API streaming usage: `image_generation.completed` carries
  `usage` on the event top level, so scan for `usage.input_tokens` before
  falling back to the Chat Completions stream parser.

Related #7036

* fix(codex): match standalone URL suffixes case-insensitively

Keep endpoint detection and sibling rewriting consistent while preserving the original URL prefix and query. Cover mixed-case Images and Alpha Search endpoints through URL and proxy regression cases.

---------

Co-authored-by: thisTom <19346741+thisTom@users.noreply.github.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-09-10 22:57:52 +08:00
Komi 11317c628f fix(proxy): preserve per-app settings on shutdown and port allocation (#7210)
On normal exit, stop_with_restore_keep_state() called the legacy global
proxy-config writer to clear the long-retired live_takeover_active flag.
That writer reads the Claude row and runs an UPDATE without a WHERE clause,
so every shutdown copied Claude's max_retries and the three timeout fields
onto the Codex, Gemini and Grok Build rows — and the UPDATE never carried
live_takeover_active in the first place, so the step had no effect beyond
the clobber. The ephemeral listen-port path did the same on every proxy
start.

Drop the dead write-back (live-config restore, backup cleanup and health
reset are unchanged) and persist the resolved ephemeral port through the
global-config interface, which only touches the shared listen/logging
columns. Two regression tests seed distinct per-app settings for all four
apps and assert they survive both paths.

Fixes #7204
2026-09-10 17:11:21 +08:00
Komi e0c2fd2b10 fix(provider): preserve child metadata during universal sync (#7212)
Syncing a universal provider regenerates its Claude/Codex/Gemini child
providers. The child's `settings_config` was merged with the existing row,
but `meta`, `created_at` and `sort_index` were taken from the generated
object, and the universal provider never carries any of them from the UI.
The UPDATE therefore wiped the child's usage script, common-config opt-out,
endpoint auto-select and other per-app settings to `{}` and reset the sort
index to NULL, which pushed the card to the bottom of the list and looked
like the provider had been deleted and re-created.

Keep the existing child's `meta`, `created_at` and `sort_index` when the
row already exists. Name, base URL, key, models, website and notes are
still driven by the universal provider, and first-time creation still
inherits the parent's metadata.

Fixes #7134
2026-09-10 17:07:05 +08:00
shigz 2f3c026242 feat(presets): rebrand DashScope as 千问AI平台 and refresh Qwen models (#7183)
Rename the domestic Bailian presets to 千问AI平台 with a dedicated icon, refresh the Qwen family to the 3.8 generation across Claude Code, Claude Desktop, Codex, Hermes, OpenClaw, OpenCode and Pi, add the domestic Token Plan presets, restore the international QwenCloud Coding Plan presets, and align OpenClaw/OpenCode/Pi model metadata with the official client docs.
2026-09-10 15:59:38 +08:00
Komi 99f9dd2ca7 fix(codex): honor proxy URL when model_provider is omitted (#7263)
When a Codex provider card's TOML has no `model_provider`, Codex falls back to
its built-in `openai` provider, but takeover wrote the proxy address as a
top-level `base_url` that Codex never reads, so requests bypassed the local
proxy and went straight to api.openai.com.

Treat the missing selector as the built-in `openai` provider and write the
proxy address to `openai_base_url`; the existing legacy-reroute migration then
turns it into a `cc-switch` custom provider table carrying the `PROXY_MANAGED`
bearer, the same shape every other third-party takeover uses. Explicit
provider selections are unchanged.

Refs #6256, #7217
2026-09-10 15:36:42 +08:00
Jelly Suandsaladday 2d54e261c8 fix(provider): update MiniMax defaults to M3 and remove expired offers (#7255)
* fix(provider): refresh MiniMax M3 presets and remove expired promotions

* fix(provider): complete MiniMax M3 capability declarations

---------

Co-authored-by: saladday <1203511142@qq.com>
2026-09-09 22:14:09 +08:00
Jason f21e09449a chore(provider): remove Atlas Cloud sponsor status, keep presets
Atlas Cloud is no longer a sponsor. Drop the sponsor identity everywhere
while keeping the provider presets themselves intact:

- README (en/zh/ja/de): remove the Atlas Cloud row from the sponsor table
  and delete the now-unreferenced banner image
- Presets (Claude Code, Claude Desktop, Codex, OpenCode, OpenClaw, Hermes,
  Pi): strip `isPartner` / `partnerPromotionKey` from the AtlasCloud entry
  and move it from the sponsor group to the non-sponsor group (endpoints,
  models and icon unchanged)
- i18n (zh/en/ja/zh-TW): remove `providerForm.partnerPromotion.atlascloud`
2026-09-09 17:04:53 +08:00
Jason f3b18df120 docs(release): add v3.20.2 release notes v3.20.2 2026-09-07 21:54:01 +08:00
Jason b6254432a9 chore(release): v3.20.2 2026-09-07 21:54:01 +08:00
Jason 389dd96cb8 feat(provider): add SoleAPI sponsor presets across all nine apps
SoleAPI (soleapi.com) joins as a sponsor, placed directly above Micu in
the sponsor order (preset files and the four README sponsor tables stay
in sync).

- Presets for Claude Code, Claude Desktop, Codex, Gemini CLI, Grok
  Build, OpenCode, OpenClaw, Hermes and Pi. Endpoints follow the
  vendor's CC Switch setup page: Anthropic/Gemini-style clients use the
  bare host, OpenAI-style clients (Codex, Grok, Responses) use /v1.
- Haiku's upstream ID carries a date suffix
  (claude-haiku-4-5-20251001), so the Desktop preset uses mappedRoutes
  and the multi-model presets list the dated ID.
- Codex defaults to gpt-5.6-sol (vendor config.toml), Gemini to
  gemini-3.8-flash.
- No OpenClaw/Hermes cost fields: site prices are official rates times
  a per-channel multiplier and change with promotions.
- Referral link only in apiKeyUrl and README hrefs; request endpoints
  stay bare.
- Inline currentColor icon traced from the vendor SVG, metadata entry,
  four-locale partnerPromotion copy, and a 1920x786 banner.
2026-09-07 20:23:32 +08:00
Jason e724270dbb fix(codex): proxy image edits endpoint
Codex's built-in ImageGen switches from `/images/generations` to
`/images/edits` whenever it references existing images (explicit paths or
the last N generated images). After #7036 the generations route is proxied,
but edits still hit an empty local route and the tool fails with 404.

Add `CodexStandaloneEndpoint::ImagesEdits` and route the four local aliases
through the same standalone passthrough as generations. The full-URL sibling
derivation now uses a shared suffix table for the Images family, so a
provider configured with either `/images/generations` or `/images/edits` as
a complete URL derives the other route; opaque URLs still fail closed.

Tests cover the effective-endpoint match, full-URL rewrites in both
directions, and an end-to-end alias test that asserts auth replacement,
body preservation (data-URL images) and usage logging with the real Images
API `input_tokens_details` shape.
2026-09-07 20:23:32 +08:00