Commit Graph
2308 Commits
Author SHA1 Message Date
zayoka 46f19a1583 fix(usage): count DeepSeek cache-hit tokens in chat-format usage (#6126)
DeepSeek Chat defines cache hits through the documented fields
prompt_cache_hit_tokens / prompt_cache_miss_tokens. CC Switch previously
only read the standard/OpenAI-compatible cache fields, so responses that
omit prompt_tokens_details.cached_tokens lost cache-hit accounting. This
adds the DeepSeek-documented field as a last-resort fallback in both the
usage parser (proxy_request_logs / usage page) and the Codex
chat-to-Responses usage synthesis (shared by streaming and non-streaming
paths).

The official endpoint currently also mirrors the value into the
undocumented prompt_tokens_details.cached_tokens (verified 2026-08-05
against api.deepseek.com), which is why existing accounting was
unaffected there. The fallback aligns with the documented contract,
defends against the undocumented mirror disappearing, and covers relays
that only pass through the documented fields. Behavior is unchanged
whenever the upstream sends any standard cache field — the DeepSeek
field sits last in the or_else chain.

Refs #6073
2026-08-16 18:44:08 +08:00
Jason 4080a8e95c feat(presets): add Baidu Qianfan Token Plan preset across six apps
Token Plan (personal) replaced Coding Plan for new purchases on
2026-07-13; existing Coding Plan presets stay untouched since active
subscriptions remain valid until expiry.

- claude/claude-desktop: /anthropic/tokenplan/personal, all roles on
  deepseek-v4-pro per the official Claude Code integration guide
- codex: /v2/tokenplan/personal via openai_chat local routing with a
  six-model catalog; first Qianfan preset with supportsEffort enabled
  (no alias indirection anymore, and the default model is on the
  official reasoning_effort support list) using effortValueMode
  "deepseek", which matches Qianfan's own low/medium->high,
  xhigh->max compatibility mapping verbatim; deepseek models omit
  defaultReasoningLevel so the fallback (max) matches the platform's
  automatic max for agent requests
- opencode/hermes: full six-model lineup on the OpenAI-compatible
  endpoint per the official integration guides
- openclaw: model entry mirrors the official OpenClaw guide verbatim
  (context 98304 is the vendor's OpenClaw-specific figure, not the
  platform model list's 1M)

ernie-5.1 is excluded (official retirement on 8/20). New test locks
endpoints, lineups and OpenClaw figures across five apps; codex is
covered by the existing chat preset and reasoning level tests.
2026-08-16 10:51:29 +08:00
Jason af06356d53 feat(presets): enable reasoning effort for Kimi per vendor's own guide
2026-08-15 audit, Kimi group. Both Kimi presets declared
supportsEffort:false, yet Moonshot's two official Codex integration
guides - which use CC Switch as their worked example - explicitly
instruct users to enable both "支持思考模式" and "支持推理强度/思考
等级". The missing piece was the top-level reasoning_effort string
(low/high/max), the only reasoning control the K3 family supports.

Open Platform preset (api.moonshot.cn/v1):
- supportsEffort:true + effortParam reasoning_effort; effortValueMode
  stays unset (passthrough - the deepseek map would crush low to high)
- kimi-k3: low/high/max. No explicit default: the template default
  medium is outside the subset so the backend falls back to the highest
  tier, max, which is exactly the vendor default
- kimi-k2.7-code: single-tier ["high"] (always-thinking, effort
  documented as unsupported - single tier avoids the template's fake
  differentiated tiers, LongCat precedent)

Kimi For Coding preset (api.kimi.com/coding/v1):
- same declaration change; catalog extended with the full official
  model table: kimi-for-coding-highspeed (262144), k3 (1048576),
  k3-256k (262144)
- k3/k3-256k: low/high/max with explicit defaultReasoningLevel high -
  first use of an explicit default: the vendor default (high) differs
  from the fallback (max), and max would silently burn more tokens
- no none tier anywhere: k2.7/k3 cannot disable thinking, and on the
  Kimi Code gateway disabling reroutes requests to K2.6 (different
  model, different billing). Gateway effort whitelist rejects unknown
  values with 400 (minimal is not in it); the declared subsets keep the
  picker inside the whitelist

Known doc conflict noted inline: the parameter reference says K3 should
not receive the thinking param while the integration guide enables
thinking mode; production shows no failures, so we follow the guide -
first thing to check if users report Kimi 400s.

Test tuple gains an optional expected-default column.
2026-08-16 10:51:29 +08:00
Jason 9dcd3486f7 feat(presets): real thinking switches for Qianfan and BytePlus Codex
2026-08-15 vendor audit, official-switch group:

- Baidu Qianfan Coding Plan: the v2 Chat API documents top-level
  thinking:{type:enabled/disabled} (same shape as Zhipu) across the
  plan's six main models, and Baidu's own OpenCode integration guide
  sends it on the /v2/coding endpoint. Declaration added (with the
  supportsThinking:true flag that gates the whole injection path) plus
  none/high levels. Known alias caveat noted inline: if the console
  resolves qianfan-code-latest to a non-thinking model the field is
  ignored, not rejected (platform documents unsupported params as
  ignore-not-error).
- BytePlus (ModelArk intl): the "not verified for the intl site"
  comment is obsolete - BytePlus' own Codex guide configures this exact
  coding/v3 endpoint with wire_api="responses". Switched apiFormat to
  openai_responses (aligned with the domestic Volcengine Plan presets,
  one less conversion layer) and pre-filled low/medium/high per the
  official Codex doc, with the glm-5-2 tier-collapse caveat noted.

Test moves BytePlus from the Chat-route list to the native Responses
list; reasoning-level expectations extended for both presets.
2026-08-16 10:51:29 +08:00
Jason e12fc62366 fix(presets): correct thinking-switch dialects for aggregator platforms
2026-08-15 vendor audit, aggregator group. All three presets declared
the Zhipu-style top-level thinking:{type} object, which is a model
vendor dialect their platforms never documented:

- ModelScope: platform switch is the top-level enable_thinking bool
  (official model-page extra_body samples + Bailian first-party GLM
  docs). thinkingParam fixed; levels stay unset until field passthrough
  to the upstream is verified.
- Novita: same fix - the Create-chat-completion parameter enum has no
  thinking object; enable_thinking is documented platform-wide. GLM-5.1
  catalog row gains none/high (two-hop inference, noted inline).
- Nvidia NIM: fake switch withdrawn. The per-model official OpenAPI
  (additionalProperties:false) has no top-level thinking field; the
  real control chat_template_kwargs:{thinking:bool} is outside our
  thinkingParam value range, so the declaration becomes an explicit
  no-injection block (supportsThinking:false, thinkingParam:none).

All three keep their codexChatReasoning block on purpose: deleting it
would fall through to the backend name/model inference, which matches
"glm"/"kimi" in the model id and would resurrect the wrong dialect.
A new modelscope branch in infer_aggregator_platform_config covers
hand-created ModelScope providers the same way the siliconflow branch
does (platform identity beats model-vendor hints), with a unit test.
2026-08-16 10:51:29 +08:00
Jason 3f75bbdf37 feat(proxy): extend StepFun effort inference to step-3.7-flash
The StepFun inference block predated step-3.7-flash and only granted
reasoning_effort to models containing "2603". Per the official
reasoning guide and model pages (both .com and .ai sites, 2026-08-15
audit), step-3.7-flash supports low/medium/high (default medium) while
step-3.5-flash-2603 supports low/high; the suffix-less step-3.5-flash
exposes no effort control.

- supports_effort now also matches step-3.7-flash
- effort_value_mode is split per model: 2603 keeps the low_high
  collapsing map; 3.7-flash uses passthrough - reusing low_high would
  collapse medium into high, creating tiers with no wire difference
- the fix stays in the inference table rather than a preset-level
  codexChatReasoning declaration, which is provider-wide and would lose
  the per-model gating (suffix-less step-3.5-flash must not receive
  reasoning_effort - its behavior is undocumented)
- StepFun preset catalogs pre-fill the vendor-documented tiers
  (3.7-flash low/medium/high, 2603 low/high, suffix-less unset); no
  none tier anywhere - StepFun documents no way to disable thinking
- new unit test locks the three per-model inference outcomes
2026-08-16 10:51:29 +08:00
Jason 1435223bd8 fix(presets): replace unavailable SiliconFlow/ModelScope catalog models
2026-08-15 vendor audit (official catalogs, cross-checked live):

- SiliconFlow: MiniMax-M2.7 was never listed on either site - users got
  400 "Model does not exist" out of the box. The two sites carry
  different MiniMax lineups and must not mirror each other:
  - .cn -> Pro/MiniMaxAI/MiniMax-M2.5 (catalog contextLen 196608);
    reasoning levels left unset (no official evidence M2.5 thinking can
    be disabled via enable_thinking)
  - .com -> MiniMaxAI/MiniMax-M3 (official 1M window = 1048576);
    reasoningLevels none/high (platform enable_thinking switch is real
    and M3 thinking is documented as disableable)
- ModelScope: bare ZhipuAI/GLM-5.1 id is not in the free API-Inference
  service list (only the BYOK :DashScope variant exists) - replaced
  with ZhipuAI/GLM-5.2 which is on the free community route. Levels
  left unset until field passthrough to the upstream is verified.

Applied across all seven apps carrying these presets (claude,
claude-desktop, codex, hermes, openclaw, opencode, pi), plus the
hardcoded model id in the SiliconFlow platform-inference Rust test and
the context-window test assertions. Bare MiniMax-M2.7 ids (MiniMax's
own official endpoint) are a different platform and intentionally
untouched. Pi catalog key moved to the existing zai/glm-5.2 entry.

Known follow-up: openclaw SiliconFlow cost figures still reflect the
old M2.7 pricing and need a separate re-audit.
2026-08-16 10:51:29 +08:00
Jason c6247d1358 feat(presets): fill remaining Codex reasoning levels for form visibility
Second round of the #6228 preset pre-fill, reversing the round-1
"deliberately unfilled" list per product ruling: an "unset" reasoning
levels field in the provider form is more misleading than a redundant
or snapshot-style declaration.

- DeepSeek direct (flash + pro): low/high/max, copied from the official
  catalog mirror. Per-row values override the mirror, so the preset must
  be kept in sync if DeepSeek's catalog changes (noted inline).
- MiniMax x2 and Xiaomi MiMo x2 (both models): none/high, equal to the
  template default - zero behavior change, declared only so the form
  shows the real tiers.
- Zhipu GLM x2 (Chat route): none/high two-state. Also fixes a real
  gap: the gpt5_5 template default tiers (low/medium/high/xhigh) had no
  none, so users could not disable thinking from Codex's picker even
  though GLM's thinking:{type:"disabled"} switch is real; the other
  template tiers were fake differentiation (supportsEffort: false).

Still unfilled: Bailian qwen3-coder-plus (no per-model evidence) and
OpenCode Go (multi-vendor Chat gateway without a codexChatReasoning
declaration - the thinking toggle is inert there, so a none tier would
be a fake switch).

Test file extended to 20 assertions covering the new fills and the
updated unfilled list.
2026-08-16 10:51:29 +08:00
Jason e163a671ed feat(presets): pre-fill vendor-documented Codex reasoning levels
Follow-up to #6228 per-model reasoning levels: pass reasoningLevels /
defaultReasoningLevel through the modelCatalog() preset helper and
pre-fill the enums documented by each vendor for native Responses
presets, so known models ship with their real effort tiers out of the
box while remaining user-editable per provider.

Filled (official-doc evidence cited inline):
- Volcengine Agent/Coding Plan ark-code-latest: low/medium/high
- DouBaoSeed doubao-seed-2-1-pro-260628: minimal/low/medium/high
- Tencent Hunyuan hy3 & hy3-preview: low/high
- Longcat LongCat-2.0: high (single tier)
- xAI Grok (API & OAuth) grok-4.5: low/medium/high

Deliberately left unfilled (comments guard against "completing" them):
DeepSeek direct (official catalog mirror already declares low/high/max),
MiniMax & Xiaomi MiMo (official catalog equals template default,
zero-effect fill), Bailian qwen3-coder-plus (no per-model evidence).

defaultReasoningLevel is never declared: the backend fallback lands on
high for every filled entry. Chat-route presets are out of scope since
effort only toggles thinking there (supportsEffort: false).

Adds tests/config/codexReasoningLevelPresets.test.ts locking the
expected enums, the unfilled list, and a canonical-effort whitelist
over all presets (unknown values are silently dropped downstream).
2026-08-16 10:51:29 +08:00
a2e22f3302 Add managed OAuth account selection for providers (#3879)
* Add managed ChatGPT account binding for Codex

* Consolidate managed account entry points

* Clarify unmanaged Codex login option

* fix(provider-form): show Codex FAST mode toggle in account-select mode

The FAST mode switch was gated on mode === "manage", but the Claude and
Claude Desktop Codex OAuth forms render CodexOAuthSection in select mode
while still passing onFastModeChange. The toggle was therefore hidden:
new providers couldn't enable FAST mode and existing ones couldn't turn
it off, even though the backend still honors meta.codexFastMode. Gate the
toggle on onFastModeChange presence instead, restoring the pre-refactor
behavior without affecting the manage panel or native Codex form (which
do not pass the handler).

* fix(i18n): localize Codex managed-account none option label

ProviderForm passed a hardcoded Chinese string as codexOauthNoneOptionLabel,
so en/ja/zh-TW users saw Chinese text in the Codex account selector's
"none" option. Add codexOauth.noneOptionLabel to all four locales and
resolve it via t().

* feat(codex): write managed ChatGPT id_token into live auth + reauth prompt

Bind the selected ChatGPT account's id_token into the Codex official
managed auth.json so it matches a native browser login for the fields
that drive behavior (auth_mode, account/plan/email via id_token claims).

- Persist id_token on CodexAccountData; capture at login and on refresh
  (empty string treated as missing). Add get_valid_token_and_id_token_for_account.
- codex_managed_oauth_live_auth now writes tokens.id_token when available.
- Keep the managed-vs-native safety marker intact: extract_codex_managed_oauth_auth
  tolerates id_token but still rejects native logins (which carry refresh_token /
  top-level last_refresh), so cc-switch never clears a real browser login.
  refresh_token and last_refresh are intentionally NOT written for this reason.
- Surface reauth_required (account has no stored id_token) through
  GitHubAccount -> ManagedAuthAccount -> TS. Legacy accounts get a styled
  amber prompt + one-click re-login (device flow) in CodexOAuthSection,
  flagged in both the selector dropdown and the select-mode hint.
- i18n: reauth strings added for en / ja / zh / zh-TW.

Verified: pnpm typecheck + build:renderer green; cross-model review of Rust
correctness, the managed-vs-native safety invariant, and the id_token lifecycle.

* style(codex): satisfy prettier format check for reauth UI

* fix(i18n): add missing managed-account selector keys

The managed OAuth account selector referenced codexOauth.chatgptAccount,
codexOauth.manageAccounts, copilot.githubAccount, copilot.manageAccounts and
providerForm.providerKeyStatusLoading with Chinese defaultValue fallbacks, so
the en/ja/zh-TW UIs rendered Chinese text. Add the translations across all four
locales.

Addresses review feedback on #3879.

* fix(providers): don't clear managed OAuth binding on status-query failure

useManagedAuth now exposes isStatusSuccess. The account-clear effect in the
Codex/Copilot selector sections only unbinds when the status query has
*successfully* loaded and the bound account is genuinely gone. Previously a
failed or still-pending query yielded an empty accounts array, which silently
cleared the selection; the subsequent save then dropped providerType/authBinding
and turned a managed provider into a broken unbound config.

Addresses review feedback on #3879.

* fix(codex-oauth): make managed accounts safe & usable with the bare CLI

Addresses review feedback on #3879. These backend changes are deeply
intertwined across shared files, so they are committed together.

Refreshable managed auth (bare `codex` support):
- Write a full, native-shaped auth.json bundle (tokens.refresh_token + top-level
  last_refresh) instead of an access-only token, so the Codex CLI can self-refresh
  and the managed account keeps working past ~1h without a proxy.
- last_refresh reflects the access token's real obtained-at time (not write time),
  so the CLI doesn't treat a cached token as freshly refreshed.
- Read back the CLI-rotated refresh_token from ~/.codex/auth.json before writing
  (account_id-matched, chatgpt-mode guarded) so re-switching doesn't clobber the
  CLI's valid login with a stale refresh_token.

Never persist managed tokens at rest:
- Backfill of a managed provider always replaces live auth with the stored
  placeholder (even on marker mismatch), so native tokens can't leak into the
  provider's DB config.
- Sanitize managed auth out of Live backups on the initial/strict snapshot paths
  and in update_live_backup_from_provider_inner before serialization.

Concurrency / blocking:
- Drop the redundant outer Arc<RwLock<CodexOAuthManager>> (all methods are &self)
  so token refresh no longer holds a coarse lock across the network; give OAuth
  token/device requests a 30s timeout instead of the shared 600s client default.
- Add a persistence lock and linearize the access-token cache under a consistent
  accounts -> access_tokens order (existence-checked reads/writes; remove/clear
  clear the cache atomically) to prevent stale or resurrected cache entries.

Switch ordering:
- Preflight the managed token before committing the current provider on
  switch/add/update, so a failed token fetch can't leave DB/UI pointing at a
  provider whose live config was never written.

Cleanup:
- Remove the now-dead content-fingerprint marker machinery; managed writes are
  now shape-identical to a native login, so ownership is judged by account_id.

Known, documented limitations (B-scheme, narrow & recoverable): a remove+re-login
of the same account within an in-flight refresh window (ABA), a login authorized
after logout, and switch-away cleanup being unable to distinguish our write from a
user's native login of the same account.

* fix(codex-oauth): keep managed token in restore backup; fix failing tests

CI caught three test failures from the previous commit. Root cause: the Live
backup (proxy_live_backup) is local restore state that is replayed to
~/.codex/auth.json when proxy takeover ends, so it must contain the real auth to
restore a working login. Stripping it (the earlier "don't leak into backup"
change) broke restore and over-stripped a user's native login.

- Revert the backup auth stripping: remove sanitize_codex_backup_auth from the
  initial/strict snapshot paths and the forced auth={} in
  update_live_backup_from_provider_inner. The managed token belongs in the
  restore backup (the refresh_token is already persisted by CodexOAuthManager, so
  this is not a new exposure).
- Restore the ownership marker (account_id + access_token fingerprint) so backup
  cleanup can tell our managed write from a user's native `codex login` of the
  same account. extract now also tolerates the full-bundle shape (refresh_token +
  last_refresh) so it fingerprints ①'s refreshable writes. clear_codex_auth_in_backup
  and clear_codex_live_auth_for_managed_account use the marker again; the
  account_id-only helper is dropped.
- Fix the adopt unit test: adopt now invalidates the cached access token, so the
  test asserts the stored refresh_token/id_token were updated and the cache was
  cleared instead of reading it back through get_valid_token_bundle (which would
  trigger a network refresh).

Token stays out of the exported provider settings_config (backfill strip) — only
the local restore backup keeps it, matching pre-existing behavior.

* fix(codex): harden managed OAuth credential lifecycle

* fix: preserve Codex restore auth state

* feat(codex): support multiple official accounts

* feat(codex): refine official account login selection

Keep native Codex login separate from managed ChatGPT accounts, migrate provider identity safely when switching modes, and cover the account-selection states with regression tests.

* style(codex): satisfy clippy for login guard

---------

Co-authored-by: Jason <farion1231@gmail.com>
Co-authored-by: YUZHEthefool <2804776511@qq.com>
2026-08-16 10:45:41 +08:00
40cac1a68e feat(codex): support per-model reasoning levels in model catalog (#6228)
* feat(codex): support per-model reasoning levels in model catalog

The generated Codex model catalog hardcodes supported_reasoning_levels to
none/high from the native template, so users of gateways that accept more
effort levels (e.g. LiteLLM serving deepseek-v4-flash with
low/medium/high/xhigh/max) cannot select anything above high in the Codex
UI.

Add optional per-model reasoningLevels / defaultReasoningLevel fields to the
model mapping. The backend applies them on top of the native template and the
official vendor catalog (unknown efforts are dropped, and the default falls
back to the template/vendor default when still in the list, otherwise the
highest declared level). The model mapping rows now expose a reasoning-level
multi-select plus a default-level picker.

Fixes #6181

* fix(codex): validate reasoning default against canonical supported set

Address bot review feedback:

- Validate every default candidate (explicit value, template default,
  fallback) against the canonical filtered efforts so a typo'd level can
  never become default_reasoning_level while missing from
  supported_reasoning_levels.
- The fallback now picks the highest supported level in canonical order
  instead of the last declared entry, and supported_reasoning_levels
  always emits canonical order regardless of declaration order.
- Drop the misleading "Auto (highest selected)" placeholder: the backend
  prefers the template default while it stays supported, so the label is
  now just "Auto" in all four locales.

* fix(proxy): map ultra reasoning effort instead of dropping it in codex transforms

The catalog UI now offers all eight canonical levels, but the proxy
transform layer predates ultra and silently dropped it:

- Chat transform: passthrough mode now forwards ultra verbatim (the
  per-model reasoningLevels declaration vouches for upstream support,
  same as the existing max/xhigh handling); deepseek and openrouter
  modes clamp it to their highest legal tier (max / xhigh) instead of
  dropping the effort parameter entirely.
- Anthropic transform: ultra now maps to the max thinking budget;
  previously it fell through to None, so picking the deepest level
  disabled extended thinking altogether.

* fix(ui): keep codex reasoning levels in canonical order and allow resetting default to Auto

- The reasoning-levels editor now stores selections in canonical
  ascending-depth order instead of click order, matching the order the
  generated catalog and the Codex picker use.
- The default-level select gains an explicit Auto item (Radix Select
  forbids empty item values, so a sentinel maps back to undefined);
  previously a chosen default could not be reverted without unchecking
  and rechecking the level.
- Tests: cover duplicate level declarations in the canonical
  normalization test.

* fix(ui): raise nested default-level menu above the reasoning popover

The enclosing reasoning-levels popover uses z-[1000] while SelectContent
defaults to z-[100], so the default-level menu rendered behind the panel
when it flipped upward near the viewport bottom. Raise it to z-[1100],
matching the existing nested-layer convention (usage panels use z-[120]
above z-[110] dialogs).

---------

Co-authored-by: Kaihang An <ztmdsbt@gmail.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-08-15 12:37:39 +08:00
SaladDay 40d747c009 feat(pi): add session usage statistics (#6463) 2026-08-14 22:31:18 +08:00
SaladDayandJason 84e75ad24a feat(pi): add native coding agent support (#6064)
* feat(pi): add native coding agent support

* refactor(pi): align native provider management

* fix(pi): allow removing global default provider

* feat(pi): refine provider creation experience

* refactor(pi): align prompt management UI

* feat(pi): refine native prompt and provider UX

* fix(pi): size config preview to content

* feat(pi): refine native provider management

* refactor(pi): remove unused integration paths

* fix(pi): address review feedback

* test(pi): align model picker assertions

* fix(pi): preserve AGENTS.md during restore sync

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-14 17:57:45 +08:00
Thefool f748f3ac4a refactor(grokbuild): align provider form with Codex (#6427) 2026-08-14 12:58:17 +08:00
yovinchen d9d4a66048 fix(provider): prevent macOS IME input corruption (#6308) (#6333)
Fixes #6308
2026-08-14 11:35:55 +08:00
SaladDay 6a7da87cbc fix(grokbuild): include required input token details (#6423) 2026-08-14 10:53:23 +08:00
Jason eb69e4922e feat(presets): add XycAi partner preset across all seven apps
- Gateway: apicdn.xycai.us primary, apicdn.xyc.ai fallback
- Claude auth uses ANTHROPIC_API_KEY per official docs
- Claude Desktop connects direct with native Anthropic format
- In-app partner promotion only (no README entry), four locales
- Register xycai icon (PNG via iconUrls) with metadata
2026-08-13 17:53:33 +08:00
Jason 5b8bf1fe4f feat(presets): split Volcengine into Agent Plan and Coding Plan presets
The former 火山Agentplan preset actually pointed at Coding Plan
endpoints (/api/coding[/v3]). Split it into two presets across all six
app preset files:

- 火山 Agent Plan: /api/plan (Anthropic) and /api/plan/v3 (OpenAI),
  with its own activity/agentplan invite link
- 火山 Coding Plan: keeps /api/coding[/v3] and the original
  activity/codingplan invite link

Both plans' OpenAI endpoints are covered by the official Codex docs
(wire_api=responses), so the Coding Plan Codex preset also uses native
Responses. Widen the Volcengine usage detection to
volces.com/api/(plan|coding) in both the frontend pattern and the
backend detect_provider mirror; the quota query already auto-probes
both plans (GetAFPUsage then GetCodingPlanUsage). Split the partner
promo copy into volcengine_agentplan / volcengine_codingplan i18n keys
in all four locales, and pin both presets in the codex native
Responses preset test.
2026-08-13 17:53:01 +08:00
Jason a7f073e95d docs(partner): update FennoAI offer to $1.99 trial plan with $50 credits
FennoAI changed its CC Switch benefit: the previous ¥9.9/month Coding
Plan worth $150 in credits is replaced by a $1.99 Trial Plan worth
$50 in credits, valid for 7 days. Update the in-app promo line in all
four locales and the partner sections of the four READMEs. The 20%
referral reward and the registration link stay unchanged.
2026-08-13 17:53:01 +08:00
Jason c99550e087 chore(presets): migrate RunAPI domain to runapi.host, keep runapi.co as fallback endpoint
Switch RunAPI website, registration and request URLs to runapi.host
across all seven app presets and the four README partner sections.
The previous runapi.co endpoints are retained as endpointCandidates
fallbacks where the preset type supports the field (claude,
claude-desktop, codex, grok-build).
2026-08-13 17:53:01 +08:00
Jason 5f6072ce46 fix(ui): remove partner star badge from main panel provider cards
The star was legacy display logic gated on meta.isPartner, which the
generic provider form almost never persisted. The standalone Grok Build
form unconditionally saves meta.isPartner, resurrecting the dead code
path. Partner stars belong only in the preset selector, so drop the
card-level badge and the now-unused officialPartner i18n key from all
four locales.
2026-08-13 17:53:01 +08:00
Jason 5602324b28 fix(codex): restore angle-bracket text lost in DeepSeek catalog mirror extraction
The official catalog mirror template was extracted from DeepSeek's docs
page with HTML unescaping applied before tag stripping, so literal
angle-bracket text inside the JSON (e.g. "<this good thing>" and the
spaced-path markdown link example) was swallowed as if it were HTML
tags — 8 spots across base_instructions and model_messages for both
models, 86 bytes missing per harness copy. Restore them; the template
is now structurally identical to the current official models.json.

Also refresh the preset comment: deepseek-v4-pro's Codex integration
is live as of 2026-08 (its catalog entry differs from flash only by
priority), so the "switching early errors upstream" warning is gone.
2026-08-13 17:53:01 +08:00
Jason 7dc0a725ee fix(pricing): correct Grok 4.5 cached rate, seed Grok 4.6 and a DeepSeek alias
Findings from a models.dev audit of the seeded pricing table:

- Correct grok-4.5 cached input 0.50 -> 0.30 (seed + repair with an
  old-value guard). The current xAI list table, models.dev and the billing
  observed for grok-4.5-build all state 0.30; 0.50 is grok-4.6's rate.
- Seed grok-4.6 (2 / 6 / 0.50, released 2026-08-12). Both 4.5 and 4.6 double
  their rates above a 200K prompt, but the table has no tier column, so the
  base tier is stored, consistent with other tiered vendors.
- Seed a deepseek-v4-flash-0731 alias at DeepSeek's official price.
  strip_model_date_suffix only strips ISO, 8-digit YYYYMMDD and 6-digit
  YYMMDD suffixes, and the prefix fallback only matches longer rows, so this
  id resolved to no pricing row and was silently billed at zero.

The GrokBuild backfill test expectations follow the corrected cache-read
price; its cache-inclusive input assertion (450 fresh tokens) is unchanged.
2026-08-13 17:53:00 +08:00
Jason c82624761c fix(proxy): stop thinking/reasoning_content injection for Kimi upstreams
Moonshot/Kimi asked to exit the reasoning-vendor workaround: their
endpoints no longer require thinking replay on tool-call turns, and the
injected placeholders disrupt the model's chain of thought.

- Remove moonshot/kimi from REASONING_VENDOR_HINTS; Kimi now gets clean
  passthrough on the anthropic path (no placeholder thinking blocks, no
  signature stripping) and no reasoning_content on the openai_chat path.
- DeepSeek/MiMo keep the behavior (documented server-side requirement).
- Flip the two Kimi gating tests into negative regressions and update
  stale comments/test model names that still referenced Kimi.
2026-08-13 17:53:00 +08:00
Jason d2b070c965 fix(proxy): never clobber Codex official ChatGPT login on takeover restore
The restore backup is a snapshot taken when takeover starts and is never
refreshed from live afterwards. If the user logged into official ChatGPT
while takeover was active, exit/crash-recovery restored the stale
third-party API-key snapshot verbatim over auth.json, wiping the login on
every restart (and the auto re-takeover on startup looped the clobber).

Restore now arbitrates before writing: whenever live auth.json holds real
login credentials (codex_auth_has_credential_login_material, and not the
proxy placeholder), live wins — the backup's API key is demoted into
config.toml as experimental_bearer_token and the backup auth slot is
dropped, so auth.json is left untouched. Live credentials are always newer
than the snapshot because only Codex itself (login / token self-refresh)
advances them, so even an official-shape backup must not roll live tokens
back. Metadata residue (last_refresh / tokens.account_id) counts neither
as a live login to protect nor as backup material to restore. Both restore
entry points — the with-fallback path (exit / crash recovery / takeover
disable) and the simple path (takeover rebuild and failure rollback) —
share the same protection.

Fixes #6277
2026-08-13 17:53:00 +08:00
Thefool c9fe340be0 fix(sync): harden sync and restore consistency (#6147)
Closes #6129
2026-08-13 16:09:08 +08:00
Thefool dfb2e5235b fix(backup): preserve SQL fidelity and recovery safety (#6146)
* fix(backup): preserve incremental auto-vacuum on import

* fix(backup): preserve SQLite scalar values in SQL dumps

* fix(backup): preserve autoincrement high-water marks

* fix(backup): restore valid empty SQL exports

* fix(backup): make restores atomic under retention

* fix(backup): publish safety snapshots atomically

* fix(backup): serialize backup file operations
2026-08-13 15:50:07 +08:00
Thefool 1f38c83826 fix(zhipu): accept CREDIT_LIMIT quota entries (#6160)
Zhipu renamed the quota entry type field from TOKENS_LIMIT to CREDIT_LIMIT on the mainland endpoint, causing all quota tiers to be skipped and the usage panel to show empty. Accept both values (case-insensitive) so old plans and the international endpoint keep working.

Fixes #6153
2026-08-12 22:09:45 +08:00
SaladDayandJason 7e5007d5bc fix(claude-desktop): clarify model configuration modes (#6208)
* fix(ui): unify checkbox styles

* fix(claude-desktop): align provider form frame

* fix(claude-desktop): clarify model configuration modes

* fix(claude-desktop): preserve direct preset models

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-08-12 21:49:16 +08:00
SaladDay 580a4d7bbd refactor(hermes): align provider form hierarchy (#6207)
* refactor(hermes): align provider form hierarchy

* fix(hermes): match model detail label typography

* fix(hermes): mute context length label

* fix(hermes): align model detail field width

* fix(hermes): expose model detail state
2026-08-12 21:43:34 +08:00
SaladDayandallenxu09 ccc8629810 feat(proxy): animate routing activation (#6209)
* feat(proxy): animate routing activation

* fix(proxy): gate routing activation animation

* fix(proxy): wait for initial status before takeover

---------

Co-authored-by: allenxu09 <s23372.xu@stu.scie.com.cn>
2026-08-12 21:38:50 +08:00
SaladDay ec84215614 refactor(opencode): clarify provider form hierarchy (#6206) 2026-08-12 21:31:43 +08:00
jiekouaiandjiekouai 58d92e5616 feat(provider): add JieKou AI presets (#6356)
* feat(provider): add JieKou AI presets

* feat(provider): use Claude Fable 5 for JieKou AI

---------

Co-authored-by: jiekouai <231459779+jiekouai@users.noreply.github.com>
2026-08-12 20:49:00 +08:00
SaladDay c005062319 fix(ui): unify checkbox styles (#6203) 2026-08-11 23:23:26 +08:00
SaladDay 5b77da2b60 style(openclaw): clarify User-Agent section hierarchy (#6204)
* refactor(openclaw): align provider model editor

* style(openclaw): clarify user agent section hierarchy
2026-08-11 23:21:04 +08:00
SaladDay 619a592c38 fix(claude-desktop): align provider form frame (#6205) 2026-08-11 23:20:33 +08:00
SaladDayandJason 95b95da6ab refactor(openclaw): align provider model editor (#6201)
Co-authored-by: Jason <farion1231@gmail.com>
2026-08-11 23:20:06 +08:00
Thefool 076c2744ce fix(provider): finish model dropdown consolidation (#6353) 2026-08-11 18:05:09 +08:00
Thefool 7e152d758b feat(provider): add fuzzy search to model mapping dropdown (#6285)
The model mapping dropdown (used by Claude Desktop, Codex, and OpenCode
provider forms) lists every fetched model grouped by vendor with no way
to filter. Providers with hundreds of models make the right model hard
to find, as requested in #6275.

Convert ModelDropdown from a plain DropdownMenu to a Popover + Command
combobox (the existing OmoFormFields pattern), adding a fuzzy search
input powered by cmdk:
- non-matching groups auto-hide; an empty state shows when nothing matches
- vendor name is indexed as a keyword, so models can be matched by vendor
  as well as by model id
- the { models, onSelect } API is unchanged, so all 5 call sites work as-is

Consolidate two near-identical inline copies of the same grouped
dropdown (ModelInputWithFetch and the Copilot branch in ClaudeFormFields)
onto ModelDropdown so every model picker gains the search and the
duplication is removed.

Add searchModelPlaceholder / searchModelEmpty / searchModelAriaLabel i18n
keys for en, zh, zh-TW, ja.
2026-08-11 16:13:40 +08:00
Hu Miao 3711e1a046 feat(provider): add PPIO support (#6239)
* feat(provider): add PPIO support

Refs #6226

* test(provider): avoid pinning PPIO preset order
2026-08-11 15:50:11 +08:00
SaladDay 8673e9d8d8 fix(claude): align advanced options with Codex (#6200) 2026-08-11 11:24:24 +08:00
SaladDay bc7f5f413a fix(ui): reduce provider editor empty space (#6199) 2026-08-11 11:22:36 +08:00
SaladDay 7de63227d4 fix(grokbuild): add glass form container to provider form (#6198)
Apply the shared glass card styles (background, border, radius, padding) used by the generic provider form to the Grok Build provider form.
2026-08-11 11:20:19 +08:00
Jason 967daa1a06 fix(skills): report missing SSOT directory as update in check_updates
check_updates trusted the DB-cached content_hash before ever looking at
disk, so a skill whose SSOT directory is gone (e.g. after restoring a DB
backup on another machine) showed "no update" and the missing files were
permanently masked; the only recovery was uninstall + reinstall.

Extract the local-hash decision into local_hash_for_update_check with
the order inverted: validate the untrusted directory name, check that
the SSOT directory actually exists, and only then trust the cached
hash (computing and backfilling it when absent). A missing directory
now yields None, which never equals the remote hash, so the skill
surfaces as "update available" and the existing update_skill flow
rebuilds it — no new download logic.

Invalid directory values keep the pre-fix behavior (fall back to the
cached hash) instead of being reported as updatable, because
update_skill would hard-fail on the same validation gate.

Covered by four unit tests on the extracted helper.
2026-08-10 23:55:00 +08:00
Jason 3c592d93e6 fix(windows): escape backslashes before Handlebars vars in WiX registry key
The single backslash in Software\{{manufacturer}}\{{product_name}} was
consumed by Handlebars as a mustache escape, so the MSI wrote a literal
key named Software{{manufacturer}}{{product_name}} directly under HKCU.
Double the backslashes to match every other registry key in the template.

Fixes #6283
2026-08-10 23:07:51 +08:00
Jason bef46cd5de chore(grokBuild): correct OpenCode Go exclusion rationale
Upstream has had grok-4.5 since 2026-08, so 'no Grok models upstream' is no longer accurate.
Exclusion is now a deliberate product decision; enrollment requires separate review.
2026-08-10 22:56:51 +08:00
Jason 16cc0d7fea feat(claude): route OpenCode Go preset directly to /messages
/v1/messages only accepts x-api-key: switch env from ANTHROPIC_AUTH_TOKEN to ANTHROPIC_API_KEY and add top-level apiKeyField.
Drop apiFormat so Claude Code connects directly (providerNeedsRouting no longer triggers) instead of through the proxy.
Desktop keeps mode: proxy (it cannot rename models itself) but switches to anthropic passthrough.
2026-08-10 22:56:51 +08:00
Jason 390102a23b fix(codex): fill DeepSeek contextWindow in OpenCode Go catalog
Both deepseek-v4-pro/flash lacked contextWindow; codex_config.rs falls back to 128k for catalog entries without it, forcing premature compaction.
2026-08-10 22:56:51 +08:00
Jason c98cc3a9e9 ci: skip frontend/backend checks when a PR touches neither area
Add a changes-detection job (dorny/paths-filter, SHA-pinned) and gate
the frontend job, the 3-OS backend matrix, and the WSL2 contract gate
on whether the PR actually touches their inputs. About two thirds of
merged PRs only touch one side, and docs-only PRs now skip CI entirely.

Pushes to main still run everything unconditionally so the caches that
PRs restore from stay warm. Path groups mirror .github/labeler.yml,
plus rust-toolchain.toml which pins the compiler used by the backend
jobs.
2026-08-10 17:06:52 +08:00
Jason 36ed280d32 ci: fix i18n labeler glob to match actual locales path
The i18n label never fired because the glob pointed at src/locales/**
while the locale files live under src/i18n/locales/.
2026-08-10 17:06:52 +08:00