Commit Graph

2143 Commits

Author SHA1 Message Date
Jason a35209a6e7 feat(xai): add Grok OAuth device-flow backend and proxy routing
Add an xAI OAuth manager using the OAuth 2.0 Device Authorization Grant
with endpoints resolved from xAI's OIDC discovery document. All HTTP goes
through the app-managed proxy client.

- Managed provider kind xai_oauth: forced openai_responses wire format,
  pinned api.x.ai base URL, bearer injection gated to the xAI origin,
  tokens registered for log redaction, single-auth-key takeover policy.
- Token cache cannot bypass account state: cache hits re-validate account
  usability, refresh commits run under the mutation lock with a
  refresh-token CAS check, and pending logins are re-checked before an
  account is persisted.
- Refresh classification: 401/403 with any body and 400 with a non-JSON
  body mark the account for re-auth; 429/5xx stay transient.
- Shared auth_* commands dispatch to xAI with guard types mirroring the
  Copilot/Codex branches.
2026-07-21 16:39:33 +08:00
Jason c4795e98ff fix(codex): backfill parser-required catalog fields from static template
Codex >= 0.144.5 requires supports_reasoning_summaries in every external
model catalog entry and rejects the whole file at startup when it is
missing, which bricks both the CLI and the desktop app.

The ProxyChat catalog template is cloned from dynamic sources first
(models_cache.json, then `codex debug models --bundled`). models_cache.json
is shared by every Codex install on the machine and each version serializes
its own ModelInfo shape, so the cache's field set follows whichever process
wrote it last and cannot be assumed to satisfy the current external-catalog
schema. Deleting the generated catalog never helped: any provider save or
switch regenerated it from the same stale template.

Backfill parser-required fields (explicit whitelist, currently only
supports_reasoning_summaries) from the bundled static template when the
dynamic template lacks them. Optional capability fields are deliberately
NOT backfilled so their missing-means-parser-default semantics survive,
and existing values always win.
2026-07-21 16:39:33 +08:00
Jason 6fddcaa97c feat(pricing): add bare k3 alias for Kimi For Coding plan
The Kimi For Coding subscription reports its K3 model under the short
id `k3` (no `kimi-` prefix), whereas the regular Moonshot API still uses
the full `kimi-k3`. Seed a `k3` alias row right after `kimi-k3` at the
same official list price ($3/M in, $15/M out, $0.30/M cache read) so
coding-plan usage is priced correctly. Mirrors the existing
hunyuan-hy3/hy3 bare-alias precedent.

Pricing is matched by exact model id, so this does not touch the
`kimi-for-coding` endpoint alias (intentionally unpriced, subscription
semantics) nor risk prefix mismatches. Seed-only, no schema bump.
2026-07-21 16:39:33 +08:00
Jason aa0e441d07 docs: add Claude Code Codex routing guide
Document API key and ChatGPT OAuth routing flows for using Codex models in Claude Code, including configuration screenshots and troubleshooting guidance.
2026-07-21 16:39:33 +08:00
Jason 17b053ed94 fix(updater): resolve Node for anchored npm commands
Prefix anchored npm invocations with their sibling bin directory so env-based Node shebangs work under a minimal GUI PATH. Cover Codex repair commands and add a regression test.
2026-07-21 16:39:33 +08:00
Jason e356fc6efc fix(openclaw): price preset models at official list prices in $/M
The cost field on OpenClaw preset models is denominated in USD per
million tokens (as the Claude entries already were), but 15 entries
carried $/1K-style decimals or stale values. Reprice everything at the
model's official list price, mirroring the built-in pricing table, so
usage is always valued at standard rates regardless of channel:

- glm-5.1 (Zhipu CN/EN, ModelScope): 1.4/4.4, cache read 0.26
- qwen3.5-plus: 0.26/1.56, cache read 0.052
- kimi-k2.7-code and the kimi-for-coding alias (K2.7 Code per official
  docs): 0.95/4, cache read 0.19
- MiniMax-M2.7 (official + SiliconFlow): 0.3/1.2, cache read 0.06,
  cache write 0.375
- KAT-Coder-Pro: 0.3/1.2, cache read 0.06
- LongCat-2.0: 0.75/2.95, cache read 0.015
- Ling-2.5-1T: 0.56/2.24 (official CNY 4/16 at ~7.14)
- deepseek-v4-pro: 0.435/0.87 (old 1.68/3.36 was CNY 12/24 left
  unconverted), cache read 0.003625
- kimi-k2.5 (Nvidia NIM): 0.6/3, cache read 0.1

Subscription-plan endpoints and free-tier hosts intentionally show
list prices too, so plan users can see the standard value of their
usage.
2026-07-21 16:39:33 +08:00
Jason f20458229d feat(presets): add Kimi K3 to Kimi open-platform presets
Add kimi-k3 (1M context, 131K max output) to the Kimi provider preset
model lists for Codex, Hermes, OpenClaw, and OpenCode, appended after
kimi-k2.7-code so the catalog-first-row default backfill is unchanged.
The Kimi For Coding plan presets keep the kimi-for-coding endpoint
alias and are intentionally untouched.
2026-07-21 16:39:33 +08:00
Jason 2bfecead4f feat(pricing): add Kimi K3 to built-in model pricing table
Seed kimi-k3 at the official list price ($3/M input, $15/M output,
$0.30/M cache read; released 2026-07-16 with a 1M context window).
Cross-checked against the Moonshot pricing docs, OpenRouter, and
models.dev. Seed-only change: ensure_model_pricing_seeded picks it up
on next launch, no schema version bump needed.
2026-07-21 16:39:33 +08:00
Jason 6274705848 feat(logging): capture frontend errors to disk with structured redaction
Frontend half of the logging overhaul.

Capture:
- Add a global error boundary plus window error/unhandledrejection
  handlers that persist renderer errors via tauri-plugin-log (new
  @tauri-apps/plugin-log dependency + log:default capability), so a
  white-screen crash leaves a trace.

Redaction (two layers over every logged value):
- Structured serializer: redact by sensitive property name (arrays and
  nested values included) and by opaque value shape.
- Text layer, the universal final pass: redact URL credentials/query,
  auth schemes, known secret shapes, and named-key array/object values.
  The container rule closes prefix+JSON, double-encoded, and POJO-error
  bypasses regardless of which entrypoint the structured data came from.
- Render Errors as redacted message + native stack across V8 and WebKit
  (macOS/Linux) without depending on a single stack format.
- Bound all inputs and drop oversized JSON to keep the UI responsive.

i18n:
- zh / en / ja / zh-TW for the new log settings and error text.
2026-07-21 16:39:33 +08:00
Jason 22d2872c33 feat(logging): persist diagnostics across restarts and redact secrets
Backend half of the logging overhaul.

Retention:
- Keep the last 4 rotated files at 20MB each and stop deleting logs on
  startup, so a crash's prior-run logs survive a restart.
- Apply the persisted log level right after plugin registration instead
  of at the end of setup.
- Bound crash.log with size-based rotation (5MB x 2).

Secret redaction on every log path:
- Proxy: strip userinfo/query from upstream URLs (keep path for
  diagnostics), exact-match redact known auth.api_key/access_token,
  classify request/response bodies instead of logging them, header
  allowlist.
- Redact the Gemini `?key=` in cache-trace endpoints.
- Omit MCP custom-field values (headers may carry tokens).
- Redact deeplink and model-fetch URLs before logging.

Docs:
- FAQ points users to the persistent crash.log for support workflows.
2026-07-21 16:39:33 +08:00
Jason 7f028632b5 feat(presets): restore SudoCode.us to coexist with SudoCode.chat sponsor
The legacy sudocode.us provider was replaced in place by the sudocode.chat
sponsor (618723b4) because the two unrelated companies share the SudoCode
name. Bring the legacy provider back and distinguish the two by their
domain suffix.

- Rename the sponsor preset to "SudoCode.chat" across its six clients;
  partner status, promotion copy (key "sudocode"), and icon unchanged
- Re-add "SudoCode.us" across all seven clients (including the previously
  removed Gemini entry) with its pre-replacement config: gpt-5.5,
  sudocode.us endpoints, sudocode.run fallback candidates
- Mark SudoCode.us as partner (isPartner) without a partnerPromotionKey:
  promo copy is pending, and the promo box only renders when a key exists
- Give the SudoCode.us Hermes entry a distinct slug (sudocode_us) so both
  providers can coexist in the additive ~/.hermes/config.yaml
- Restore the legacy logo from git history as sudocode-us.png and register
  it in the hand-maintained icon index and metadata
2026-07-21 16:39:33 +08:00
Jason 3bc828aecc fix(windows): eliminate console flash and UI freeze on provider switch
Switching providers or toggling proxy takeover on Windows flashed a
transient cmd window and froze the UI for up to a couple of seconds.
Three fixes:

- Spawn `codex debug models --bundled` with CREATE_NO_WINDOW so the
  console child of the GUI-subsystem app (npm's codex.cmd runs via
  cmd.exe) no longer opens a visible window.
- Cache the ProxyChat model catalog template in a process-wide OnceCell:
  only successful loads are cached, failures stay retryable, so the
  Codex CLI starts at most once per app run instead of on every switch.
- Run switch_provider via spawn_blocking: sync Tauri commands execute on
  the main thread, so the blocking catalog generation (and the
  block_on'd per-app switch lock) froze the UI. Concurrency is already
  serialized by ProxyService::lock_switch_for_app.
2026-07-21 16:39:33 +08:00
Komi 08710d51fc fix(proxy): default Codex tool parameters to object schema (#5315)
Normalize function tool parameters on the Codex Responses -> Chat Completions bridge: default null/missing parameters (direct and nested function forms) to {"type":"object","properties":{}}, coerce explicit type:null, and add a root type for top-level oneOf schemas so strict OpenAI-compatible upstreams (DeepSeek etc.) no longer reject built-in Codex tools like codex_app__automation_update. Also hardens the Codex -> Anthropic tool path with the same object-type guarantee and adds regression coverage for all reported shapes.
2026-07-21 10:13:00 +08:00
ka79376046 613fef70bc fix(codex-chat): attach reasoning forward for responses bridge (#5508)
* fix(codex-chat): attach reasoning forward for responses bridge

* fix(codex-chat): preserve tail reasoning after embedded reasoning

* docs(codex-chat): align trailing reasoning comments
2026-07-19 11:39:29 +08:00
滅ü 997be22bfa fix(tray): detect system locale for first-run language instead of hardcoding zh (#4355)
The tray menu used a hardcoded zh (Simplified Chinese) fallback whenever
settings.language was unset (i.e. first install). On systems whose UI language
resolves to Traditional Chinese / Japanese / English via the frontend's
navigator-based detection, the tray therefore showed Simplified Chinese until
the user manually switched language once.

Detect the OS locale via the sys-locale crate and map it to a supported tray
language, mirroring the frontend getInitialLanguage precedence
(zh-TW/HK/MO/Hant -> zh-TW, other zh -> zh, ja -> ja, en -> en, otherwise zh).
This keeps the tray consistent with the UI from the first launch with no timing
window. An explicitly stored settings.language still takes precedence, so user
choices are never overridden. Adds unit tests for the locale mapping.

Co-authored-by: LaiYueTing <LaiYueTing@users.noreply.github.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-07-17 21:35:10 +08:00
Allen Xu edea624a27 fix(skills): preserve deleted default repositories (#5356)
* fix(skills): preserve deleted default repositories

* fix(skills): persist default repo initialization state
2026-07-17 15:51:29 +08:00
Thefool 1c0ee0c58a feat(grokbuild): add first-class Grok Build support (#5453)
* feat(grokbuild): add backend integration

* feat(grokbuild): add provider and management UI

* test(grokbuild): cover configuration and integrations

* fix(grokbuild): address backend review feedback

* fix(grokbuild): complete UI review feedback

* feat(grokbuild): add CLI lifecycle management

* fix(grokbuild): align provider icon fallback

* test(grokbuild): cover provider icon persistence
2026-07-17 15:50:50 +08:00
zayoka f6e37ed994 fix(ci): run backend checks on Windows/macOS and repair platform-gated tests (#5138)
* fix(ci): run backend checks on Windows/macOS and repair platform-gated tests

The backend CI job ran only on ubuntu-22.04, so every #[cfg(target_os =
"windows")] / macOS path — tests and clippy lints alike — was never
compiled or run. As a result main shipped 8 failing Windows unit tests and
a hard `cargo clippy -- -D warnings` failure on Windows, all invisible to
CI because it only builds and tests Linux.

Changes:

- ci: run the backend job on a {ubuntu-22.04, windows-latest, macos-latest}
  matrix (fail-fast: false); gate the apt install step on runner.os ==
  'Linux' and use `shell: bash` for the dist placeholder so it works on all
  three runners.

- misc.rs: fix 6 stale `anchored_upgrade_windows` tests. Commit 5092fe51
  removed codex from `prefers_official_update`, so codex now anchors to the
  package manager with no `codex update ||` prefix; update the five
  package-manager expectations accordingly, and retarget the no-sibling
  "official-update-without-fallback" test to `claude` (still in the list) so
  that branch stays covered instead of being silently dropped.

- codex_state_db.rs / codex_history_migration.rs: the two sqlite_home tests
  built TOML basic strings from Windows paths, whose backslashes are invalid
  escape sequences and made the override fail to parse; switch to TOML
  literal (single-quoted) strings so the path is taken verbatim.

- clippy (13 Windows-only warnings): move `use std::io::Write` into the
  #[cfg(unix)] block that actually uses it; convert 3 unneeded `return`s in
  Windows-gated tail positions to expressions; mark 9 POSIX-shell helpers
  #[cfg_attr(windows, allow(dead_code))] since they are used only by the
  macOS/Linux terminal launchers.

Verified locally (Windows 11, Rust 1.95.0):
  cargo test --lib                        → 1748 passed; 0 failed (was 1740/8)
  cargo clippy -- -D warnings             → clean (was 13 errors)
  cargo fmt --check                       → clean

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

* fix(skills): resolve home via get_home_dir so tests isolate on Windows

services/skill.rs called dirs::home_dir() directly in five places. On
Windows dirs::home_dir() resolves through the Known Folder API and
ignores HOME/USERPROFILE, so the CC_SWITCH_TEST_HOME override set by the
test harness never applied: the skill_sync integration tests scanned the
runner's real user profile, found no skills, and failed (the first panic
then poisoned the shared test mutex, cascading to all seven). On Unix
the harness also sets HOME, which dirs::home_dir() honors, so the suite
passed there by accident.

Route all five call sites through crate::config::get_home_dir(), the
crate-wide home resolver that prefers CC_SWITCH_TEST_HOME. The three
now-unreachable GET_HOME_DIR_FAILED error branches are dropped:
get_home_dir() is infallible, matching every other config-dir resolver.
Production behavior is unchanged (CC_SWITCH_TEST_HOME is unset outside
tests, so get_home_dir falls through to dirs::home_dir).

Add a regression test that discriminates on every platform by pointing
CC_SWITCH_TEST_HOME at a temp dir different from $HOME; it is marked
#[serial_test::serial] to stay mutually exclusive with the other tests
mutating the same process-global variable. Verified the test fails
against the old code on macOS with the same failure mode as Windows CI.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
2026-07-15 10:33:22 +08:00
Jason 1cc52c7e73 docs(readme): add SubRouter sponsor entry across four locales 2026-07-14 22:46:19 +08:00
SaladDay 6d316c0bda fix(codex): preserve streamed tool call identity and order (#5310)
Keep non-empty call IDs across continuation deltas and release parallel tool calls in Chat index order when identity fields arrive late. Preserve valid sparse and later calls during finalization.
2026-07-14 20:01:10 +08:00
Ryan2128 9ca1a41f58 fix: normalize function parameters type to "object" for strict OpenAI-compatible providers (#4706)
* fix: normalize function parameters type to "object" for strict OpenAI-compatible providers

Some Responses tools carry parameters with `type: null` (e.g.
codex_app__automation_update), causing HTTP 400 from strict
OpenAI-compatible providers like DeepSeek that require
`{"type": "object", "properties": {...}}`.

This adds normalize_function_parameters() to ensure the type
field is always "object" in both branches of
responses_function_tool_to_chat_tool.

Closes #4705

* style: fix cargo fmt issues

* fix: handle null function parameters
2026-07-14 19:23:41 +08:00
Jason c8b0d60c2d docs(guides): add Codex + Claude local routing guide in three languages
Step-by-step guide for the v3.17.0 native Anthropic Messages upstream:
add a custom Codex provider pointed at a Claude-family /v1/messages
gateway, pick the anthropic upstream format, enable local routing, and
verify the chain. Covers the auth-field choice (Bearer vs x-api-key),
the Claude Code impersonation toggle, the 8192 max-output fallback, and
a FAQ entry for gateways that restrict keys to Claude Code only.

Includes four UI screenshots captured from the real 3.17.0 app with
sample data, and links the guide from the v3.17.0 release notes in all
three languages.
2026-07-14 11:53:55 +08:00
Jason 7e73a1ffb2 fix(i18n): add missing proxyReasonAnthropicMessages key across locales
The routing-required toast for Anthropic-format Codex providers only had
a Chinese defaultValue in code; non-Chinese locales showed a mixed-language
message. Add the reason string to zh/en/ja/zh-TW following the phrasing of
the sibling proxyReason* keys.
2026-07-14 11:53:39 +08:00
Jason 3d176b98cc docs(release): add v3.17.0 release notes v3.17.0 2026-07-13 23:41:54 +08:00
Jason c154d30b7a chore(release): v3.17.0 2026-07-13 21:24:58 +08:00
Jason 6eb217b242 revert(proxy): drop the 1-hour cache TTL option and TTL-bucketed write accounting
The forced 1-hour cache_control TTL (schema v14) was a mistake. Injected
breakpoints return to Anthropic's standard 5-minute TTL, caller-owned
markers are preserved verbatim instead of having their TTLs rewritten,
and the 5m/1h cache-write buckets are removed from usage parsing and
pricing (back to the single aggregate cache-creation rate). The cache
TTL selector is removed from the rectifier settings panel along with its
i18n keys in all four locales.

SCHEMA_VERSION returns to 13: the unreleased cache_creation_1h_tokens
column and the v13->v14 migration are removed. The feature never shipped
in a release and the introducing commit was never pushed, so no
databases were stamped v14 outside this machine (local DB verified at
user_version 13).
2026-07-13 17:55:33 +08:00
Jason ac52c851bf fix(codex): infer image capability for generated catalogs and resync takeover live on save
Mapped GPT models were rejected by Codex clients with "model does not
support image inputs". Two root causes:

- Catalog entries for native-Responses/Anthropic providers cloned a
  template whose input_modalities defaulted to ["text"], so every mapped
  model was advertised text-only. model_catalog_json replaces Codex's
  built-in model table wholesale, and both the TUI and the IDE extension
  block images pre-send when the current model is found without "image".
- Editing the current Codex provider during proxy takeover only refreshed
  the DB backup, so removing the mapping left a stale model_catalog_json
  pointer (and its text-only catalog file) active in live config.

Changes:

- New shared model_capabilities module: explicit row declaration first,
  then a confirmed text-only registry (exact tail match only — prefix
  matching removed, variants enumerated so future -vl/-vision models fail
  open), everything else unknown.
- Catalog generation writes input_modalities from that inference for all
  tool profiles: unknown models fail open to ["text","image"]; only
  confirmed text-only models are advertised as ["text"], giving users a
  clear client-side prompt instead of silent image stripping.
- Live catalog reverse-import collapses modalities that match current
  inference, so registry corrections are not frozen into hidden row
  overrides and the rectifier's heuristic opt-out keeps working.
- Saving the current Codex provider while takeover owns live now
  re-projects the live config (mirrors the hot-switch path), so mapping
  edits and removals take effect immediately.
- Media rectifier delegates to the shared module; its preflight toggle is
  documented (4 locales) as proxy-request-only, never affecting catalog
  capability declarations.
2026-07-13 16:48:22 +08:00
Jason 618723b42f feat(presets): promote SudoCode to paid sponsor across six clients
Replace the legacy sudocode.us provider (a name collision) with the new
paid sponsor SudoCode on sudocode.chat, updated in place across six
clients: Claude Code, Codex, Claude Desktop, OpenCode, OpenClaw, Hermes.

- Switch endpoints to api.sudocode.chat, add isPartner +
  partnerPromotionKey, and add four-locale partnerPromotion copy
- Claude Code / Desktop use direct passthrough (no model mapping)
- Codex / OpenCode / OpenClaw / Hermes use gpt-5.6-sol
- Remove the Gemini entry (outside sponsor scope)
- Replace the provider icon with the new brand PNG
2026-07-13 16:48:22 +08:00
Jason af58740bcd fix(proxy): align Codex OAuth client identity
ChatGPT's Codex backend routes model availability by the originator and version header pair. Requests identifying as cc-switch without a version were assigned to a cohort where gpt-5.6-luna resolved to an unavailable internal engine, resulting in a misleading 404 Model not found response.

Identify takeover requests as codex_cli_rs and send version 0.144.1, satisfying luna's minimal_client_version requirement of 0.144.0. A direct HTTP A/B test confirmed the existing headers returned 404 while the aligned identity completed successfully, so no WebSocket transport workaround is required.
2026-07-13 16:48:22 +08:00
Jason 99573d2242 refactor(presets): pin context window values instead of form fields
Drop the Max Context Tokens / Auto Compact Window template inputs from
the Codex and Kimi For Coding presets and hardcode the values in the
preset env (372000 / 262144). The rare user who wants different numbers
can edit them directly in the JSON editor.

Both keys stay on purpose: the compact window resolves as
min(model window, value), so matching the window is behavior-neutral
today, but the explicit env pins compaction locally against
remote-config experiments dialing it down.
2026-07-13 16:48:21 +08:00
Jason 940ddd332b feat(kimi): declare the 256K context window for Kimi For Coding
Claude Code caps unknown model ids at 200K, so the preset's standalone
CLAUDE_CODE_AUTO_COMPACT_WINDOW=262144 was clamped by min(window, value)
and never took effect. Pair it with CLAUDE_CODE_MAX_CONTEXT_TOKENS and
route the endpoint's kimi-for-coding alias on every tier, since both
context envs are ignored for claude-* prefixed model ids.

Saved providers get the same context defaults injected into effective
live settings at switch time, with a mirror-inverse strip on backfill so
injected values never harden into provider config. Explicit user values
always win over the injected defaults.
2026-07-13 16:48:21 +08:00
Jason 31ee42854a feat(pricing): seed gpt-5.6 alias rows and 1.25x cache-write rates
- Add the bare gpt-5.6 row (official Sol alias) plus effort-suffix variants
  mirroring the gpt-5.5 accounting shape, priced at Sol rates
- The GPT-5.6 family charges cache writes at 1.25x the uncached input rate
  (new for OpenAI; earlier GPT models keep their correct zero): set
  6.25 / 3.125 / 1.25 for Sol / Terra / Luna across seed rows
- Repair earlier zero-value gpt-5.6 tier seeds in existing databases,
  matching only untouched rows so user-customized prices survive
2026-07-13 16:48:21 +08:00
Jason 5c39dfbfbe feat(codex): declare gpt-5.6 context window for Claude Code takeover
- Update Codex OAuth presets to the gpt-5.6 family (haiku -> gpt-5.6-luna)
  and bump the custom Codex template default model
- Inject CLAUDE_CODE_MAX_CONTEXT_TOKENS / CLAUDE_CODE_AUTO_COMPACT_WINDOW
  (372000, the ChatGPT Codex catalog window with a ~353K effective budget,
  openai/codex#31860) into effective live settings so Claude Code stops
  assuming a 200K window and compacts before the upstream rejects the prompt
- Gate the injected defaults on every configured model being gpt-5.6*:
  gpt-5.5's upstream catalog oscillates between 272K and 372K and must not
  inherit them; explicit user values always win
- Strip the injected values on switch-away backfill (mirror-inverse of the
  injection conditions) so program defaults never harden into per-provider
  explicit values, and keep both keys out of the shared common-config snippet
2026-07-13 16:48:21 +08:00
Jason f15184edb0 feat(codex): expose official routing and restore the built-in provider
Let users switch between the built-in OpenAI provider and third-party Codex providers directly from the provider panel while takeover mode remains active.

Centralize the frontend capability predicate so only the fixed codex-official seed receives native-login routing support, and keep copied UUID-based official entries clearly marked as unsupported.

Add an idempotent backend command that recreates the deleted official seed, wire it into the add-provider flow, refresh localized guidance, and add mutation and provider-action regression coverage.
2026-07-13 16:48:21 +08:00
Jason f2c6d48e19 fix(providers): skip reachability probes for official OAuth entries
Do not derive unauthenticated health-check targets from runtime adapter defaults for official providers. Batch checks now skip official entries, and direct base-URL resolution fails explicitly instead of probing first-party endpoints without credentials.

Cover the Codex official provider in the stream-check regression tests so future adapter changes cannot silently reintroduce these probes.
2026-07-13 16:48:21 +08:00
Jason 51d6c458ff feat(codex): route native ChatGPT sessions through proxy takeover
Allow the built-in Codex official provider to participate in takeover mode while preserving Codex's native OAuth or API-key credentials instead of persisting them into provider records.

Project official routing into a dedicated TOML provider, normalize inline tables, clean stale managed placeholders, and fail closed when the live configuration cannot be transformed safely.

Validate forwarded authorization, make official 401/403 responses non-retryable, avoid circuit-breaker pollution, and share the first-party ChatGPT endpoint across the Codex and Claude adapters.
2026-07-13 16:48:21 +08:00
Jason 13e7c1fcc4 fix(usage): account for Anthropic cache write TTLs
Parse and retain Anthropic's ephemeral 5-minute and 1-hour cache-creation token buckets while preserving the existing aggregate cache-write metric for compatibility.

Price 1-hour writes at the documented premium relative to the configured 5-minute write rate, clamp inconsistent provider details safely, and include TTL buckets in usage diagnostics.

Persist 1-hour cache-write tokens with schema version 14 so zero-cost backfills and later pricing updates retain the original TTL semantics. Keep session import paths compatible through zero-valued detail fields.
2026-07-13 16:48:21 +08:00
Jason b9263a8040 fix(cache): strengthen prompt cache breakpoint injection
Honor both the optimizer master switch and the cache-injection sub-switch before mutating native optimizer requests.

Use the available four-breakpoint budget across tools, system content, the latest cacheable message, and an older user anchor for long tool-heavy conversations.

Preserve caller-owned breakpoint limits, avoid thinking blocks as cache targets, normalize configured TTLs, and add regression coverage for disabled optimization and long histories.
2026-07-13 16:48:21 +08:00
Jason 650905af2c fix(proxy): harden Responses and Anthropic protocol bridges
Fail closed on HTTP 2xx failure envelopes and pre-output SSE failures so semantic upstream errors can trigger failover instead of becoming empty successful replies.

Finalize incomplete and truncated streams explicitly, handle clean EOF and whole JSON responses, and keep tool-call stop reasons and terminal event ordering consistent.

Preserve structured tool results, URL images, documents, system roles, and signed thinking across both conversion directions. Drop incomplete historical tool calls safely and classify malformed completed arguments as non-retryable client requests.

Keep Codex-to-Anthropic prompt caching enabled by default while honoring the dedicated cache-injection switch.
2026-07-13 16:48:21 +08:00
Jason a078b4b207 feat(proxy): session-based prompt_cache_key routing for Codex Chat bridge
Codex always sends prompt_cache_key in its Responses requests, but the
Responses -> Chat Completions conversion dropped it, breaking session
cache affinity on upstreams that route by key (e.g. Kimi Coding).

- Re-inject prompt_cache_key after conversion in the forwarder: an
  explicit client key wins, otherwise a client-provided session ID;
  generated per-request UUIDs are never sent upstream.
- Provider-aware gating: "auto" enables only known-compatible upstreams
  (api.openai.com, api.kimi.com/coding) because strict gateways reject
  unknown fields with HTTP 400 (e.g. Fireworks); an advanced
  Auto/Enabled/Disabled override is available on the Codex form in all
  four locales.
- Kimi For Coding preset opts in explicitly.
2026-07-13 16:48:21 +08:00
Jason 0e563b50c5 fix(cache): surface unsupported breakpoint counts
Warn when caller-provided cache breakpoints already exceed the supported total of four while preserving the original markers and upgrading their TTLs.

Clarify that automatic injection is governed by the remaining breakpoint budget, and add regression coverage proving excess caller markers are never deleted or reordered.
2026-07-13 16:48:21 +08:00
Jason 27ce0a519c fix(proxy): harden Responses reasoning and tool-call conversion
Round-trip encrypted Responses reasoning items through bridge-owned Anthropic thinking blocks, discard orphaned reasoning-only history, and consume the official reasoning text event vocabulary.

Track concurrent streaming items by stable IDs and output indexes, reuse a dedicated fallback block for keyless legacy reasoning, recover tool arguments from done events, and close blocks in protocol order.

Normalize empty or incomplete non-streaming tool arguments, reject malformed completed calls, and persist upstream usage before returning terminal conversion errors.
2026-07-13 16:48:21 +08:00
Jason f991726ff0 fix(usage): account for cache-write tokens across schema versions
Parse cache_write_tokens from OpenAI usage details and preserve cache creation data across Chat, Responses, and Anthropic conversion paths.

Add explicit input-token semantics to request logs and rollups so legacy rows subtract cache reads only while new total-inclusive rows subtract both cache reads and writes. Migrate v12 databases, normalize rollups to fresh input, and cover historical backfill behavior with regression tests.
2026-07-13 16:48:21 +08:00
Jason 06039540ff refactor(health-check): remove per-provider test config 2026-07-13 16:48:21 +08:00
Jason 442799879d feat(profiles): add setting to toggle project switcher on main page
Add a show/hide toggle for the header project profile switcher under
the Homepage Display section in settings. Defaults to visible so
existing users keep the current behavior.
2026-07-13 16:48:21 +08:00
Jason 7479d10db7 feat(codex): add default model field to provider form
Expose the top-level `model` key of config.toml as an editable field in
the Codex provider form, so users can switch to newly released models
(e.g. gpt-5.6) without waiting for a preset update — preset updates only
affect newly added providers, existing ones keep their saved TOML.

The field syncs bidirectionally with the TOML editor (mirroring the
base-URL pattern), suggests models from the mapping catalog plus the
provider's /models endpoint, and offers a one-click "add to mapping"
action when the value is outside a non-empty catalog. Hidden for
official providers.

Details:

- Save-time catalog sync now only backfills the first mapping row into
  the top-level model when the field was left empty, so the explicit
  field wins over the implicit row-0 sync
- Escape model names (and base_url) with TOML basic-string escaping and
  strip control characters from field input: /models ids are remote
  data and unescaped interpolation could inject config.toml lines
  (e.g. a forged [mcp_servers.*] command)
- The strict model-line matcher now recognizes escaped output, empty
  strings and single-quoted literals, keeping extract/set round-trips
  stable; deliberately no key-only loose matching (it would misfire on
  assignment-looking text inside multiline strings)
- Invalidate the fetched model list whenever the request identity
  changes (base URL, full-URL toggle, API key, custom UA) and discard
  in-flight responses via a sequence guard, so the dropdown never shows
  a previous provider's models
- i18n for zh/en/ja/zh-TW
2026-07-13 16:48:21 +08:00
Jason 62e44c4838 feat(pricing): seed Tencent Hunyuan Hy3 pricing
Add Hunyuan Hy3 (released 2026-07-06, 256K context) to seed_model_pricing
under both the hunyuan-hy3 and hy3 ids, since the upstream billing id isn't
yet confirmed and one of the two should match logged usage.

Prices come from Tencent's launch-day list price (CNY 1 / 4 / 0.25 per 1M
input / output / cache-hit), converted at 1 USD ~= 7.14: 0.14 / 0.56 / 0.035.
cache_write is "0" (no published write rate). Hy3 actually uses input-length
tiered billing (<16K / 16-32K / >=32K); the single-price table holds the
lowest tier, so long-context requests are under-billed until this is revisited
against the official billing page. New model, so seed only.
2026-07-13 16:48:21 +08:00
Jason a7b4dd9405 feat(pricing): seed GPT-5.6 Sol/Terra/Luna pricing
Add the three GPT-5.6 tiers to seed_model_pricing, cross-checked against
OpenAI's official pricing page and OpenRouter:

  gpt-5.6-sol    5 / 30 / 0.50 (cache read)
  gpt-5.6-terra  2.50 / 15 / 0.25
  gpt-5.6-luna   1 / 6 / 0.10

cache_write is "0": OpenAI publishes only a cached-input (read) rate and no
separate cache-write price, matching the gpt-5.x family convention. Base ids
only for now — effort-suffix variants are deferred until the upstream logging
suffix set for 5.6 is confirmed. New model, so seed only (no repair branch,
no SCHEMA_VERSION bump).
2026-07-13 16:48:21 +08:00
风少1227 c6197ae324 fix(proxy): inject a single auth placeholder on managed Claude takeover (#5095)
Switching the Claude provider from a third-party (DeepSeek/MiMo/...) to a
managed Codex provider wrote both ANTHROPIC_API_KEY and
ANTHROPIC_AUTH_TOKEN as PROXY_MANAGED into ~/.claude/settings.json,
making Claude Code warn "Both ANTHROPIC_AUTH_TOKEN and ANTHROPIC_API_KEY
set - auth may not work as expected" on every run.

The double key is an accretion artifact: the ManagedAccount takeover
policy originally injected only ANTHROPIC_API_KEY (Copilot, #1049), and
the Codex fix that preserved ANTHROPIC_AUTH_TOKEN to avoid the login
prompt (#3784 / PR #3789) added the token on top without removing the
API key insert.

Inject exactly one placeholder instead: AUTH_TOKEN for Codex-managed
providers (keeps the #3784 fix), API_KEY for Copilot (keeps the #1049
behavior). Local-proxy auth is unaffected - the forwarder resolves the
PROXY_MANAGED placeholder from either header.

Updates the three Codex takeover tests to assert API_KEY is absent and
adds a regression test for the exact third-party -> Codex switch from
the report.

Fixes #4919
2026-07-12 21:47:45 +08:00
白喵喵喵喵 f39d463c44 fix(usage): 修复 Codex 子代理使用量未计入统计 (#5187)
* fix(usage): count Codex subagent session tokens

* fix(usage): address Codex subagent review feedback

* fix(usage): preserve Codex migration history

* fix(usage): harden Codex subagent migration

* fix(usage): reimport late Codex subagents

* fix(usage): guard late Codex rollup reimport

* refactor(usage): simplify Codex subagent accounting fix
2026-07-11 20:11:14 +08:00