* feat(proxy): extract model name from API response for accurate usage tracking
- Add model field extraction in TokenUsage parsing for Claude, OpenAI, and Codex
- Prioritize response model over request model in usage logging
- Update model extractors to use parsed usage.model first
- Add tests for model extraction in stream and non-stream responses
* feat(proxy): implement streaming timeout control with validation
- Add first byte timeout (0 or 1-180s) for streaming requests
- Add idle timeout (0 or 60-600s) for streaming data gaps
- Add non-streaming timeout (0 or 60-1800s) for total request
- Implement timeout logic in response processor
- Add 1800s global timeout fallback when disabled
- Add database schema migration for timeout fields
- Add i18n translations for timeout settings
* feat(proxy): add model mapping module for provider-based model substitution
- Add model_mapper.rs with ModelMapping struct to extract model configs from Provider
- Support ANTHROPIC_MODEL, ANTHROPIC_REASONING_MODEL, and default models for haiku/sonnet/opus
- Implement thinking mode detection for reasoning model priority
- Include comprehensive unit tests for all mapping scenarios
* fix(proxy): bypass circuit breaker for single provider scenario
When failover is disabled (single provider), circuit breaker open state
would block all requests causing poor UX. Now bypasses circuit breaker
check in this scenario. Also integrates model mapping into request flow.
* feat(ui): add reasoning model field to Claude provider form
Add ANTHROPIC_REASONING_MODEL configuration field for Claude providers,
allowing users to specify a dedicated model for thinking/reasoning tasks.
* feat(proxy): add openrouter_compat_mode for optional format conversion
Add configurable OpenRouter compatibility mode that enables Anthropic to
OpenAI format conversion. When enabled, rewrites endpoint to /v1/chat/completions
and transforms request/response formats. Defaults to enabled for OpenRouter.
* feat(ui): add OpenRouter compatibility mode toggle
Add UI toggle for OpenRouter providers to enable/disable compatibility
mode which uses OpenAI Chat Completions format with SSE conversion.
* feat(stream-check): use provider-configured model for health checks
Extract model from provider's settings_config (ANTHROPIC_MODEL, GEMINI_MODEL,
or Codex config.toml) instead of always using default test models.
* refactor(ui): remove timeout settings from AutoFailoverConfigPanel
Remove streaming/non-streaming timeout configuration from failover panel
as these settings have been moved to a dedicated location.
* refactor(database): migrate proxy_config to per-app three-row structure
Replace singleton proxy_config table with app_type primary key structure,
allowing independent proxy settings for Claude, Codex, and Gemini.
Add GlobalProxyConfig queries and per-app config management in DAO layer.
* feat(proxy): add GlobalProxyConfig and AppProxyConfig types
Add new type definitions for the refactored proxy configuration:
- GlobalProxyConfig: shared settings (enabled, address, port, logging)
- AppProxyConfig: per-app settings (failover, timeouts, circuit breaker)
* refactor(proxy): update service layer for per-app config structure
Adapt proxy service, handler context, and provider router to use
the new per-app configuration model. Read enabled/timeout settings
from proxy_config table instead of settings table.
* feat(commands): add global and per-app proxy config commands
Add new Tauri commands for the refactored proxy configuration:
- get_global_proxy_config / update_global_proxy_config
- get_proxy_config_for_app / update_proxy_config_for_app
Update startup restore logic to read from proxy_config table.
* feat(api): add frontend API and Query hooks for proxy config
Add TypeScript wrappers and TanStack Query hooks for:
- Global proxy config (address, port, logging)
- Per-app proxy config (failover, timeouts, circuit breaker)
- Proxy takeover status management
* refactor(ui): redesign proxy panel with inline config controls
Replace ProxySettingsDialog with inline controls in ProxyPanel.
Add per-app takeover switches and global address/port settings.
Simplify AutoFailoverConfigPanel by removing timeout settings.
* feat(i18n): add proxy takeover translations and update types
Add i18n strings for proxy takeover status in zh/en/ja.
Update TypeScript types for GlobalProxyConfig and AppProxyConfig.
* refactor(proxy): load circuit breaker config per-app instead of globally
Extract app_type from router key and read circuit breaker settings
from the corresponding proxy_config row for each application.
Previously, UI sync was triggered only when failover happened (retry count > 1).
This missed cases where the first provider in the failover queue succeeded but
was different from the user's selected provider in settings.
Now we capture the current provider ID at request start and compare it with
the actually used provider. This ensures UI/tray always reflects the real
provider handling requests.
Add FailoverSwitchManager to handle provider switching after successful
failover. This ensures the UI reflects the actual provider in use:
- Create failover_switch.rs with deduplication and async switching logic
- Pass AppHandle through ProxyService -> ProxyServer -> RequestForwarder
- Update is_current in database when failover succeeds
- Emit provider-switched event for frontend refresh
- Update tray menu and live backup synchronously
The switching runs asynchronously via tokio::spawn to avoid blocking
API responses while still providing immediate UI feedback.
This commit addresses several critical issues in the failover system:
**Circuit breaker state persistence (previous fix)**
- Promote ProviderRouter to ProxyState for cross-request state sharing
- Remove redundant router.rs module
- Fix 429 errors to be retryable (rate limiting should try other providers)
**Hot-update circuit breaker config**
- Add update_circuit_breaker_configs() to ProxyServer and ProxyService
- Connect update_circuit_breaker_config command to running circuit breakers
- Add reset_provider_circuit_breaker() for manual breaker reset
**Fix HalfOpen deadlock bug**
- Change half_open_requests from cumulative count to in-flight count
- Release quota in record_success()/record_failure() when in HalfOpen state
- Prevents permanent deadlock when success_threshold > 1
**Fix duplicate select_providers() call**
- Store providers list in RequestContext, pass to forward_with_retry()
- Avoid consuming HalfOpen quota twice per request
- Single call to select_providers() per request lifecycle
**Add per-provider retry with exponential backoff**
- Implement forward_with_provider_retry() with configurable max_retries
- Backoff delays: 100ms, 200ms, 400ms, etc.
Extract common request handling logic into dedicated modules:
- handler_config.rs: Usage parser configurations for each API type
- handler_context.rs: Request lifecycle context management
- response_processor.rs: Unified streaming/non-streaming response handling
Reduces handlers.rs from ~1130 lines to ~418 lines (-63%), eliminating
repeated initialization and response processing patterns across the
four API handlers (Claude, Codex Chat, Codex Responses, Gemini).