Commit Graph

27 Commits

  • Feat/usage model extraction (#455)
    * 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.
  • Feat/auto failover switch (#440)
    * feat(failover): add auto-failover master switch with proxy integration
    
    - Add persistent auto_failover_enabled setting in database
    - Add get/set_auto_failover_enabled commands
    - Provider router respects master switch state
    - Proxy shutdown automatically disables failover
    - Enabling failover auto-starts proxy server
    - Optimistic updates for failover queue toggle
    
    * feat(proxy): persist proxy takeover state across app restarts
    
    - Add proxy_takeover_{app_type} settings for per-app state tracking
    - Restore proxy takeover state automatically on app startup
    - Preserve state on normal exit, clear on manual stop
    - Add stop_with_restore_keep_state method for graceful shutdown
    
    * fix(proxy): set takeover state for all apps in start_with_takeover
    
    * fix(windows): hide console window when checking CLI versions
    
    Add CREATE_NO_WINDOW flag to prevent command prompt from flashing
    when detecting claude/codex/gemini CLI versions on Windows.
    
    * refactor(failover): make auto-failover toggle per-app independent
    
    - Change setting key from 'auto_failover_enabled' to 'auto_failover_enabled_{app_type}'
    - Update provider_router to check per-app failover setting
    - When failover disabled, use current provider only; when enabled, use queue order
    - Add unit tests for failover enabled/disabled behavior
    
    * feat(failover): auto-switch to higher priority provider on recovery
    
    - After circuit breaker reset, check if recovered provider has higher priority
    - Automatically switch back if queue_order is lower (higher priority)
    - Stream health check now resets circuit breaker on success/degraded
    
    * chore: remove unused start_proxy_with_takeover command
    
    - Remove command registration from lib.rs
    - Add comment clarifying failover queue is preserved on proxy stop
    
    * feat(ui): integrate failover controls into provider cards
    
    - Add failover toggle button to provider card actions
    - Show priority badge (P1, P2, ...) for queued providers
    - Highlight active provider with green border in failover mode
    - Sync drag-drop order with failover queue
    - Move per-app failover toggle to FailoverQueueManager
    - Simplify SettingsPage failover section
    
    * test(providers): add mocks for failover hooks in ProviderList tests
    
    * refactor(failover): merge failover_queue table into providers
    
    - Add in_failover_queue field to providers table
    - Remove standalone failover_queue table and related indexes
    - Simplify queue ordering by reusing sort_index field
    - Remove reorder_failover_queue and set_failover_item_enabled commands
    - Update frontend to use simplified FailoverQueueItem type
    
    * fix(database): ensure in_failover_queue column exists for v2 databases
    
    Add column check in create_tables to handle existing v2 databases
    that were created before the failover queue refactor.
    
    * fix(ui): differentiate active provider border color by proxy mode
    
    - Use green border/gradient when proxy takeover is active
    - Use blue border/gradient in normal mode (no proxy)
    - Improves visual distinction between proxy and non-proxy states
    
    * fix(database): clear provider health record when removing from failover queue
    
    When a provider is removed from the failover queue, its health monitoring
    is no longer needed. This change ensures the health record is also deleted
    from the database to prevent stale data.
    
    * fix(failover): improve cache cleanup for provider health and circuit breaker
    
    - Use removeQueries instead of invalidateQueries when stopping proxy to
      completely clear health and circuit breaker caches
    - Clear provider health and circuit breaker caches when removing from
      failover queue
    - Refresh failover queue after drag-sort since queue order depends on
      sort_index
    - Only show health badge when provider is in failover queue
    
    * style: apply prettier formatting to App.tsx and ProviderList.tsx
    
    * fix(proxy): handle missing health records and clear health on proxy stop
    
    - Return default healthy state when provider health record not found
    - Add clear_provider_health_for_app to clear health for specific app
    - Clear app health records when stopping proxy takeover
    
    * fix(proxy): track actual provider used in forwarding for accurate logging
    
    Introduce ForwardResult and ForwardError structs to return the actual
    provider that handled the request. This ensures usage statistics and
    error logs reflect the correct provider after failover.
  • feat(failover): add auto-failover master switch with proxy integration (#427)
    * feat(failover): add auto-failover master switch with proxy integration
    
    - Add persistent auto_failover_enabled setting in database
    - Add get/set_auto_failover_enabled commands
    - Provider router respects master switch state
    - Proxy shutdown automatically disables failover
    - Enabling failover auto-starts proxy server
    - Optimistic updates for failover queue toggle
    
    * feat(proxy): persist proxy takeover state across app restarts
    
    - Add proxy_takeover_{app_type} settings for per-app state tracking
    - Restore proxy takeover state automatically on app startup
    - Preserve state on normal exit, clear on manual stop
    - Add stop_with_restore_keep_state method for graceful shutdown
    
    * fix(proxy): set takeover state for all apps in start_with_takeover
  • chore: bump version to 3.9.0-2 for second test release
    - Update version in package.json, Cargo.toml, tauri.conf.json
    - Fix clippy too_many_arguments warning in forwarder.rs
  • refactor(proxy): switch OpenRouter to passthrough mode for native Claude API
    OpenRouter now supports Claude Code compatible endpoint (/v1/messages),
    eliminating the need for Anthropic ↔ OpenAI format conversion.
    
    - Disable format transformation for OpenRouter (keep old logic as fallback)
    - Pass through original endpoint instead of redirecting to /v1/chat/completions
    - Add anthropic-version header for ClaudeAuth and Bearer strategies
    - Update tests to reflect new passthrough behavior
  • fix(proxy): respect existing token field when syncing Claude config
    - Add support for ANTHROPIC_API_KEY in Claude auth extraction
    - Only update existing token fields during sync, avoid adding fields
      that weren't originally configured by the user
    - Add tests for both scenarios
  • refactor(proxy): remove global auto-start flag
    - Remove global proxy auto-start flag from config and UI.
    - Simplify per-app takeover start/stop and stop server when the last takeover is disabled.
    - Restore live takeover detection used for crash recovery.
    - Keep proxy_config.enabled column but always write 0 for compatibility.
    - Tests: not run (not requested).
  • feat(proxy): implement per-app takeover mode
    Replace global live takeover with granular per-app control:
    - Add start_proxy_server command (start without takeover)
    - Add get_proxy_takeover_status to query each app's state
    - Add set_proxy_takeover_for_app for individual app control
    - Use live backup existence as SSOT for takeover state
    - Refactor sync_live_to_provider to eliminate code duplication
    - Update ProxyToggle to show status per active app
  • fix(proxy): takeover Codex base_url via model_provider
    - Update Codex `model_providers.<model_provider>.base_url` to the proxy origin with `/v1`
    - Add route fallbacks for `/responses` and `/chat/completions` (plus double-`/v1` safeguard)
    - Add unit tests for the TOML base_url takeover logic
  • fix(proxy): sync UI when active provider differs from current setting
    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.
  • fix(proxy): resolve circuit breaker race condition and error classification
    This commit addresses two critical issues in the proxy failover logic:
    
    1. Circuit Breaker HalfOpen Concurrency Bug:
       - Introduced `AllowResult` struct to track half-open permit usage
       - Added state guard in `transition_to_half_open()` to prevent duplicate resets
       - Replaced `fetch_sub` with CAS loop in `release_half_open_permit()` to prevent underflow
       - Separated `is_available()` (routing) from `allow_request()` (permit acquisition)
    
    2. Error Classification Conflation:
       - Split retry logic into `should_retry_same_provider()` and `categorize_proxy_error()`
       - Same-provider retry: only for transient errors (timeout, 429, 5xx)
       - Cross-provider failover: now includes ConfigError, TransformError, AuthError
       - 4xx errors (401/403) no longer waste retries on the same provider
  • Feature/error request logging (#401)
    * feat(proxy): add error mapper for HTTP status code mapping
    
    - Add error_mapper.rs module to map ProxyError to HTTP status codes
    - Implement map_proxy_error_to_status() for error classification
    - Implement get_error_message() for user-friendly error messages
    - Support all error types: upstream, timeout, connection, provider failures
    - Include comprehensive unit tests for all mappings
    
    * feat(proxy): enhance error logging with context support
    
    - Add log_error_with_context() method for detailed error recording
    - Support streaming flag, session_id, and provider_type fields
    - Remove dead_code warning from log_error() method
    - Enable comprehensive error request tracking in database
    
    * feat(proxy): implement error capture and logging in all handlers
    
    - Capture and log all failed requests in handle_messages (Claude)
    - Capture and log all failed requests in handle_gemini (Gemini)
    - Capture and log all failed requests in handle_responses (Codex)
    - Capture and log all failed requests in handle_chat_completions (Codex)
    - Record error status codes, messages, and latency for all failures
    - Generate unique session_id for each request
    - Support both streaming and non-streaming error scenarios
    
    * style: fix clippy warnings and typescript errors
    
    - Add allow(dead_code) for CircuitBreaker::get_state (reserved for future)
    - Fix all uninlined format string warnings (27 instances)
    - Use inline format syntax for better readability
    - Fix unused import and parameter warnings in ProviderActions.tsx
    - Achieve zero warnings in both Rust and TypeScript
    
    * style: apply code formatting
    
    - Remove trailing whitespace in misc.rs
    - Add trailing comma in App.tsx
    - Format multi-line className in ProviderCard.tsx
    
    * feat(proxy): add settings button to proxy panel
    
    Add configuration buttons in both running and stopped states to
    provide easy access to proxy settings dialog.
    
    * fix(speedtest): skip client build for invalid inputs
    
    * chore(clippy): fix uninlined format args
    
    * Merge branch 'main' into feature/error-request-logging
  • refactor(proxy): remove is_proxy_target in favor of failover_queue
    - Remove `is_proxy_target` field from Provider struct (Rust & TypeScript)
    - Remove related DAO methods: get_proxy_target_provider, set_proxy_target
    - Remove deprecated Tauri commands: get_proxy_targets, set_proxy_target
    - Add `is_available()` method to CircuitBreaker for availability checks
      without consuming HalfOpen probe permits (used in select_providers)
    - Keep `allow_request()` for actual request gating with permit tracking
    - Update stream_check to use failover_queue instead of is_proxy_target
    - Clean up commented-out reset circuit breaker button in ProviderActions
    - Remove unused useProxyTargets and useSetProxyTarget hooks
  • fix(proxy): retry failover for all HTTP errors including 4xx
    Previously, only 429, 408, and 5xx errors triggered failover to the next
    provider. Other 4xx errors (like 400) were considered non-retryable and
    caused immediate disconnection.
    
    This was problematic because different providers have different restrictions
    (e.g., "Do not use this API outside Claude Code CLI"), and a 400 error from
    one provider doesn't mean other providers will fail.
    
    Now all upstream HTTP errors trigger failover, allowing the system to try
    all configured providers before giving up.
  • feat(proxy): sync UI when failover succeeds
    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.
  • fix(proxy): resolve HalfOpen counter underflow and config field inconsistencies
    - Fix HalfOpen counter underflow: increment half_open_requests when
      transitioning from Open to HalfOpen to prevent underflow in
      record_success/record_failure
    
    - Fix Gemini config field names: unify to GEMINI_API_KEY and
      GOOGLE_GEMINI_BASE_URL (removed GOOGLE_API_KEY and GEMINI_API_BASE)
    
    - Fix Codex proxy takeover: write base_url to config.toml instead of
      OPENAI_BASE_URL in auth.json (Codex CLI reads from config.toml)
  • fix(proxy): resolve circuit breaker state persistence and HalfOpen deadlock
    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.
  • feat(proxy): implement independent failover queue management
    Add a new failover queue system that operates independently from provider
    sortIndex, allowing users to configure failover order per app type.
    
    Backend changes:
    - Add failover_queue table to schema.rs for persistent storage
    - Create dao/failover.rs with CRUD operations for queue management
    - Add Tauri commands for queue operations (get, add, remove, reorder, toggle)
    - Refactor provider_router.rs select_providers() to use failover queue:
      - Current provider always takes first priority
      - Queue providers ordered by queue_order as fallback
      - Only providers with open circuit breakers are included
    
    Frontend changes:
    - Add FailoverQueueItem type to proxy.ts
    - Extend failover.ts API with queue management methods
    - Add React Query hooks for queue data fetching and mutations
    - Create FailoverQueueManager component with drag-and-drop reordering
    - Integrate queue management into SettingsPage under "Auto Failover"
    - Add i18n translations for zh and en locales
  • refactor(proxy): modularize handlers.rs to reduce code duplication
    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).
  • fix(proxy): wait for server shutdown before exiting app
    The previous cleanup logic only sent a shutdown signal but didn't wait
    for the proxy server to actually stop. This caused a race condition
    where the app would exit before cleanup completed, leaving Live configs
    in an inconsistent state.
    
    Changes:
    - Add `server_handle` field to ProxyServer to track the spawned task
    - Modify `stop()` to wait for server task completion (5s timeout)
    - Add 100ms delay before process exit to ensure I/O flush
    - Export ProxyService and fix test files that were missing proxy_service field
  • Feat/provider icon color (#385)
    * feat(ui): add color prop support to ProviderIcon component
    
    * feat(health): add stream check core functionality
    
    Add new stream-based health check module to replace model_test:
    - Add stream_check command layer with single and batch provider checks
    - Add stream_check DAO layer for config and log persistence
    - Add stream_check service layer with retry mechanism and health status evaluation
    - Add frontend HealthStatusIndicator component
    - Add frontend useStreamCheck hook
    
    This provides more comprehensive health checking capabilities.
    
    * refactor(health): replace model_test with stream_check
    
    Replace model_test module with stream_check across the codebase:
    - Remove model_test command and service modules
    - Update command registry in lib.rs to use stream_check commands
    - Update module exports in commands/mod.rs and services/mod.rs
    - Remove frontend useModelTest hook
    - Update stream_check command implementation
    
    This refactoring provides clearer naming and better separation of concerns.
    
    * refactor(db): clean up unused database tables and optimize schema
    
    Remove deprecated and unused database tables:
    - Remove proxy_usage table (replaced by proxy_request_logs)
    - Remove usage_daily_stats table (aggregation done on-the-fly)
    - Rename model_test_logs to stream_check_logs with updated schema
    - Remove related DAO methods for proxy_usage
    - Update usage_stats service to use proxy_request_logs only
    - Refactor usage_script to work with new schema
    
    This simplifies the database schema and removes redundant data storage.
    
    * refactor(ui): update frontend components for stream check
    
    Update frontend components to use stream check API:
    - Refactor ModelTestConfigPanel to use stream check config
    - Update API layer to use stream_check commands
    - Add HealthStatus type and StreamCheckResult interface
    - Update ProviderList to use new health check integration
    - Update AutoFailoverConfigPanel with stream check references
    - Improve UI layout and configuration options
    
    This completes the frontend migration from model_test to stream_check.
    
    * feat(health): add configurable test models and reasoning effort support
    
    Enhance stream check service with configurable test models:
    - Add claude_model, codex_model, gemini_model to StreamCheckConfig
    - Support reasoning effort syntax (model@level or model#level)
    - Parse and apply reasoning_effort for OpenAI-compatible models
    - Remove hardcoded model names from check functions
    - Add unit tests for model parsing logic
    - Remove obsolete model_test source files
    
    This allows users to customize which models are used for health checks.
  • refactor(proxy): simplify provider selection to use is_current directly
    Changes:
    - Modify provider_router to select provider based on is_current flag
      instead of is_proxy_target queue
    - Remove proxy target toggle UI from ProviderCard
    - Remove proxyPriority and allProviders props from ProviderList
    - Remove isProxyTarget prop from ProviderHealthBadge
    - Use start_with_takeover() for auto-start to ensure proper setup
    
    This simplifies the proxy architecture by directly using the current
    provider for proxying, eliminating the need for separate proxy target
    management. Switching providers now immediately takes effect in proxy
    mode.
  • fix(proxy): resolve 404 error and auto-setup proxy targets
    Issues fixed:
    1. Route prefix mismatch - Live config was set to use /claude, /codex,
       /gemini prefixes but server only had routes without prefixes
    2. Proxy targets not auto-configured - start_with_takeover only modified
       Live config but didn't set is_proxy_target=true for current providers
    
    Changes:
    - Add prefixed routes (/claude/v1/messages, /codex/v1/*, /gemini/v1beta/*)
      to server.rs for backward compatibility
    - Remove URL prefixes from takeover_live_configs() - server can route
      by API endpoint path alone (/v1/messages=Claude, /v1/chat/completions=Codex)
    - Add setup_proxy_targets() method that automatically sets current providers
      as proxy targets when starting proxy with takeover
    - Unify proxy toggle in SettingsPage to use takeover mode (same as main UI)
    - Fix error message extraction in useProxyStatus hooks
    - Fix provider switch logic to check both takeover flag AND proxy running state
  • Security fixes javascript executor and usage script (#151)
    * dependencies: url
    
    * fix: comprehensive security improvements for usage script execution
    
    🛡️ Security Fixes:
    - Implement robust SSRF protection with same-origin URL validation
    - Add precise IP address validation for IPv4/IPv6 private networks
    - Fix port comparison to handle default ports correctly (443/80)
    - Remove hardcoded domain whitelist, support custom domains flexibly
    - Add comprehensive input validation and hostname security checks
    
    🔧 Technical Improvements:
    - Replace string-based IP checks with proper IpAddr parsing
    - Use port_or_known_default() for accurate port validation
    - Add comprehensive unit tests covering edge cases
    - Implement CIDR-compliant private IP detection (RFC1918)
    - Fix IPv6 address validation to prevent false positives
    
    📊 Fixed Issues:
    - Prevent access to private IP addresses while allowing public services
    - Support Cloudflare (172.67.x.x) and other public 172.x.x.x ranges
    - Fix port matching between explicit (e.g., :443) and implicit (default) ports
    - Resolve IPv6 false positives for addresses containing ::1 substrings
    - Maintain backward compatibility with existing script usage patterns
    
     Testing:
    - Add comprehensive test suite for IP validation (IPv4/IPv6)
    - Add port comparison tests for various scenarios
    - Add edge case tests for CIDR boundaries
    - All tests passing, ensuring no regressions
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude <noreply@anthropic.com>
    
    * fix: add is_loopback_host for proper localhost validation
    
    * fix: use Database::memory() in tests
    
    ---------
    
    Co-authored-by: Claude <noreply@anthropic.com>
  • Feat/auto failover (#367)
    * feat(db): add circuit breaker config table and provider proxy target APIs
    
    Add database support for auto-failover feature:
    
    - Add circuit_breaker_config table for storing failover thresholds
    - Add get/update_circuit_breaker_config methods in proxy DAO
    - Add reset_provider_health method for manual recovery
    - Add set_proxy_target and get_proxy_targets methods in providers DAO
      for managing multi-provider failover configuration
    
    * feat(proxy): implement circuit breaker and provider router for auto-failover
    
    Add core failover logic:
    
    - CircuitBreaker: Tracks provider health with three states:
      - Closed: Normal operation, requests pass through
      - Open: Circuit broken after consecutive failures, skip provider
      - HalfOpen: Testing recovery with limited requests
    - ProviderRouter: Routes requests across multiple providers with:
      - Health tracking and automatic failover
      - Configurable failure/success thresholds
      - Auto-disable proxy target after reaching failure threshold
      - Support for manual circuit breaker reset
    - Export new types in proxy module
    
    * feat(proxy): add failover Tauri commands and integrate with forwarder
    
    Expose failover functionality to frontend:
    
    - Add Tauri commands: get_proxy_targets, set_proxy_target,
      get_provider_health, reset_circuit_breaker,
      get/update_circuit_breaker_config, get_circuit_breaker_stats
    - Register all new commands in lib.rs invoke handler
    - Update forwarder with improved error handling and logging
    - Integrate ProviderRouter with proxy server startup
    - Add provider health tracking in request handlers
    
    * feat(frontend): add failover API layer and TanStack Query hooks
    
    Add frontend data layer for failover management:
    
    - Add failover.ts API: Tauri invoke wrappers for all failover commands
    - Add failover.ts query hooks: TanStack Query mutations and queries
      - useProxyTargets, useProviderHealth queries
      - useSetProxyTarget, useResetCircuitBreaker mutations
      - useCircuitBreakerConfig query and mutation
    - Update queries.ts with provider health query key
    - Update mutations.ts to invalidate health on provider changes
    - Add CircuitBreakerConfig and ProviderHealth types
    
    * feat(ui): add auto-failover configuration UI and provider health display
    
    Add comprehensive UI for failover management:
    
    Components:
    - ProviderHealthBadge: Display provider health status with color coding
    - CircuitBreakerConfigPanel: Configure failure/success thresholds,
      timeout duration, and error rate limits
    - AutoFailoverConfigPanel: Manage proxy targets with drag-and-drop
      priority ordering and individual enable/disable controls
    - ProxyPanel: Integrate failover tabs for unified proxy management
    
    Provider enhancements:
    - ProviderCard: Show health badge and proxy target indicator
    - ProviderActions: Add "Set as Proxy Target" action
    - EditProviderDialog: Add is_proxy_target toggle
    - ProviderList: Support proxy target filtering mode
    
    Other:
    - Update App.tsx routing for settings integration
    - Update useProviderActions hook with proxy target mutation
    - Fix ProviderList tests for updated component API
    
    * fix(usage): stabilize date range to prevent infinite re-renders
    
    * feat(backend): add tool version check command
    
    Add get_tool_versions command to check local and latest versions of
    Claude, Codex, and Gemini CLI tools:
    
    - Detect local installed versions via command line execution
    - Fetch latest versions from npm registry (Claude, Gemini)
      and GitHub releases API (Codex)
    - Return comprehensive version info including error details
      for uninstalled tools
    - Register command in Tauri invoke handler
    
    * style(ui): format accordion component code style
    
    Apply consistent code formatting to accordion component:
    - Convert double quotes to semicolons at line endings
    - Adjust indentation to 2-space standard
    - Align with project code style conventions
    
    * refactor(providers): update provider card styling to use theme tokens
    
    Replace hardcoded color classes with semantic design tokens:
    - Use bg-card, border-border, text-card-foreground instead of glass-card
    - Replace gray/white color literals with muted/foreground tokens
    - Change proxy target indicator color from purple to green
    - Improve hover states with border-border-active
    - Ensure consistent dark mode support via CSS variables
    
    * refactor(proxy): simplify auto-failover config panel structure
    
    Restructure AutoFailoverConfigPanel for better integration:
    - Remove internal Card wrapper and expansion toggle (now handled by parent)
    - Extract enabled state to props for external control
    - Simplify loading state display
    - Clean up redundant CardHeader/CardContent wrappers
    - ProxyPanel: reduce complexity by delegating to parent components
    
    * feat(settings): enhance settings page with accordion layout and tool versions
    
    Major settings page improvements:
    
    AboutSection:
    - Add local tool version detection (Claude, Codex, Gemini)
    - Display installed vs latest version comparison with visual indicators
    - Show update availability badges and environment check cards
    
    SettingsPage:
    - Reorganize advanced settings into collapsible accordion sections
    - Add proxy control panel with inline status toggle
    - Integrate auto-failover configuration with accordion UI
    - Add database and cost calculation config sections
    
    DirectorySettings & WindowSettings:
    - Minor styling adjustments for consistency
    
    settings.ts API:
    - Add getToolVersions() wrapper for new backend command
    
    * refactor(usage): restructure usage dashboard components
    
    Comprehensive usage statistics panel refactoring:
    
    UsageDashboard:
    - Reorganize layout with improved section headers
    - Add better loading states and empty state handling
    
    ModelStatsTable & ProviderStatsTable:
    - Minor styling updates for consistency
    
    ModelTestConfigPanel & PricingConfigPanel:
    - Simplify component structure
    - Remove redundant Card wrappers
    - Improve form field organization
    
    RequestLogTable:
    - Enhance table layout with better column sizing
    - Improve pagination controls
    
    UsageSummaryCards:
    - Update card styling with semantic tokens
    - Better responsive grid layout
    
    UsageTrendChart:
    - Refine chart container styling
    - Improve legend and tooltip display
    
    * chore(deps): add accordion and animation dependencies
    
    Package updates:
    - Add @radix-ui/react-accordion for collapsible sections
    - Add cmdk for command palette support
    - Add framer-motion for enhanced animations
    
    Tailwind config:
    - Add accordion-up/accordion-down animations
    - Update darkMode config to support both selector and class
    - Reorganize color and keyframe definitions for clarity
    
    * style(app): update header and app switcher styling
    
    App.tsx:
    - Replace glass-header with explicit bg-background/80 backdrop-blur
    - Update navigation button container to use bg-muted
    
    AppSwitcher:
    - Replace hardcoded gray colors with semantic muted/foreground tokens
    - Ensure consistent dark mode support via CSS variables
    - Add group class for better hover state transitions
  • Feat/proxy server (#355)
    * feat(proxy): implement local HTTP proxy server with multi-provider failover
    
    Add a complete HTTP proxy server implementation built on Axum framework,
    enabling local API request forwarding with automatic provider failover
    and load balancing capabilities.
    
    Backend Implementation (Rust):
    - Add proxy server module with 7 core components:
      * server.rs: Axum HTTP server lifecycle management (start/stop/status)
      * router.rs: API routing configuration for Claude/OpenAI/Gemini endpoints
      * handlers.rs: Request/response handling and transformation
      * forwarder.rs: Upstream forwarding logic with retry mechanism (652 lines)
      * error.rs: Comprehensive error handling and HTTP status mapping
      * types.rs: Shared types (ProxyConfig, ProxyStatus, ProxyServerInfo)
      * health.rs: Provider health check infrastructure
    
    Service Layer:
    - Add ProxyService (services/proxy.rs, 157 lines):
      * Manage proxy server lifecycle
      * Handle configuration updates
      * Track runtime status and metrics
    
    Database Layer:
    - Add proxy configuration DAO (dao/proxy.rs, 242 lines):
      * Persist proxy settings (listen address, port, timeout)
      * Store provider priority and availability flags
    - Update schema with proxy_config table (schema.rs):
      * Support runtime configuration persistence
    
    Tauri Commands:
    - Add 6 command endpoints (commands/proxy.rs):
      * start_proxy_server: Launch proxy server
      * stop_proxy_server: Gracefully shutdown server
      * get_proxy_status: Query runtime status
      * get_proxy_config: Retrieve current configuration
      * update_proxy_config: Modify settings without restart
      * is_proxy_running: Check server state
    
    Frontend Implementation (React + TypeScript):
    - Add ProxyPanel component (222 lines):
      * Real-time server status display
      * Start/stop controls
      * Provider availability monitoring
    - Add ProxySettingsDialog component (420 lines):
      * Configuration editor (address, port, timeout)
      * Provider priority management
      * Settings validation
    - Add React hooks:
      * useProxyConfig: Manage proxy configuration state
      * useProxyStatus: Poll and display server status
    - Add TypeScript types (types/proxy.ts):
      * Define ProxyConfig, ProxyStatus interfaces
    
    Provider Integration:
    - Extend Provider model with availability field (providers.rs):
      * Track provider health for failover logic
    - Update ProviderCard UI to display proxy status
    - Integrate proxy controls in Settings page
    
    Dependencies:
    - Add Axum 0.7 (async web framework)
    - Add Tower 0.4 (middleware and service abstractions)
    - Add Tower-HTTP (CORS layer)
    - Add Tokio sync primitives (oneshot, RwLock)
    
    Technical Details:
    - Graceful shutdown via oneshot channel
    - Shared state with Arc<RwLock<T>> for thread-safe config updates
    - CORS enabled for cross-origin frontend access
    - Request/response streaming support
    - Automatic retry with exponential backoff (forwarder)
    - API key extraction from multiple config formats (Claude/Codex/Gemini)
    
    File Statistics:
    - 41 files changed
    - 3491 insertions(+), 41 deletions(-)
    - Core modules: 1393 lines (server + forwarder + handlers)
    - Frontend UI: 642 lines (ProxyPanel + ProxySettingsDialog)
    - Database/DAO: 326 lines
    
    This implementation provides the foundation for advanced features like:
    - Multi-provider load balancing
    - Automatic failover on provider errors
    - Request logging and analytics
    - Usage tracking and cost monitoring
    
    * fix(proxy): resolve UI/UX issues and database constraint error
    
    Simplify proxy control interface and fix database persistence issues:
    
    Backend Fixes:
    - Fix NOT NULL constraint error in proxy_config.created_at field
      * Use COALESCE to preserve created_at on updates
      * Ensure proper INSERT OR REPLACE behavior
    - Remove redundant enabled field validation on startup
      * Auto-enable when user clicks start button
      * Persist enabled state after successful start
    - Preserve enabled state during config updates
      * Prevent accidental service shutdown on config save
    
    Frontend Improvements:
    - Remove duplicate proxy enable switch from settings dialog
      * Keep only runtime toggle in ProxyPanel
      * Simplify user experience with single control point
    - Hide proxy target button when proxy service is stopped
      * Add isProxyRunning prop to ProviderCard
      * Conditionally render proxy controls based on service status
    - Update form schema to omit enabled field
      * Managed automatically by backend
    
    Files: 5 changed, 81 insertions(+), 94 deletions(-)
    
    * fix(proxy): improve URL building and Gemini request handling
    
    - Refactor URL construction with version path deduplication (/v1, /v1beta)
    - Preserve query parameters for Gemini API requests
    - Support GOOGLE_GEMINI_API_KEY field name (with fallback)
    - Change default proxy port from 5000 to 15721
    - Fix test: use Option type for is_proxy_target field
    
    * refactor(proxy): remove unused request handlers and routes
    
    - Remove unused GET/DELETE request forwarding methods
    - Remove count_tokens, get/delete response handlers
    - Simplify router by removing unused endpoints
    - Keep only essential routes: /v1/messages, /v1/responses, /v1beta/*
    
    * Merge branch 'main' into feat/proxy-server
    
    * fix(proxy): resolve clippy warnings for dead code and uninlined format args
    
    - Add #[allow(dead_code)] to unused ProviderUnhealthy variant
    - Inline format string arguments in handlers.rs and codex.rs log macros
    - Refactor error response handling to properly pass through upstream errors
    - Add URL deduplication logic for /v1/v1 paths in CodexAdapter
    
    * feat(proxy): implement provider adapter pattern with OpenRouter support
    
    This major refactoring introduces a modular provider adapter architecture
    to support format transformation between different AI API formats.
    
    New features:
    - Add ProviderAdapter trait for unified provider abstraction
    - Implement Claude, Codex, and Gemini adapters with specific logic
    - Add Anthropic ↔ OpenAI format transformation for OpenRouter compatibility
    - Support model mapping from provider configuration (ANTHROPIC_MODEL, etc.)
    - Add OpenRouter preset to Claude provider presets
    
    Refactoring:
    - Extract authentication logic into auth.rs with AuthInfo and AuthStrategy
    - Move URL building and request transformation to individual adapters
    - Simplify ProviderRouter to only use proxy target providers
    - Refactor RequestForwarder to use adapter-based request/response handling
    - Use whitelist mode for header forwarding (only pass necessary headers)
    
    Architecture:
    - providers/adapter.rs: ProviderAdapter trait definition
    - providers/auth.rs: AuthInfo, AuthStrategy types
    - providers/claude.rs: Claude adapter with OpenRouter detection
    - providers/codex.rs: Codex (OpenAI) adapter
    - providers/gemini.rs: Gemini (Google) adapter
    - providers/models/: Anthropic and OpenAI API data models
    - providers/transform.rs: Bidirectional format transformation
    
    * feat(proxy): add streaming SSE transform and thinking parameter support
    
    New features:
    - Add OpenAI → Anthropic SSE streaming response transformation
    - Support thinking parameter detection for reasoning model selection
    - Add ANTHROPIC_REASONING_MODEL config option for extended thinking
    
    Changes:
    - streaming.rs: Implement SSE event parsing and Anthropic format conversion
    - transform.rs: Add thinking detection logic and reasoning model mapping
    - handlers.rs: Integrate streaming transform for OpenRouter compatibility
    - Cargo.toml: Add async-stream and bytes dependencies
    
    * feat(db): add usage tracking schema and types
    
    Add database tables for proxy request logs and model pricing.
    Extend Provider and error types to support usage statistics.
    
    * feat(proxy): implement usage tracking subsystem
    
    Add request logger with automatic cost calculation.
    Implement token parser for Claude/OpenAI/Gemini responses.
    Add cost calculator based on model pricing configuration.
    
    * feat(proxy): integrate usage logging into request handlers
    
    Add usage logging to forwarder and streaming handlers.
    Track token usage and costs for each proxy request.
    
    * feat(commands): add usage statistics Tauri commands
    
    Register usage commands for summary, trends, logs, and pricing.
    Expose usage stats service through Tauri command layer.
    
    * feat(api): add frontend usage API and query hooks
    
    Add TypeScript types for usage statistics.
    Implement usage API with Tauri invoke calls.
    Add TanStack Query hooks for usage data fetching.
    
    * feat(ui): add usage dashboard components
    
    Add UsageDashboard with summary cards, trend chart, and data tables.
    Implement model pricing configuration panel.
    Add request log viewer with filtering and detail panel.
    
    * fix(ui): integrate usage dashboard and fix type errors
    
    Add usage dashboard tab to settings page.
    Fix UsageScriptModal TypeScript type annotations.
    
    * deps: add recharts for charts and rust_decimal/uuid for usage tracking
    
    - recharts: Chart visualization for usage trends
    - rust_decimal: Precise cost calculations
    - uuid: Request ID generation
    
    * feat(proxy): add ProviderType enum for fine-grained provider detection
    
    Introduce ProviderType enum to distinguish between different provider
    implementations (Claude, ClaudeAuth, Codex, Gemini, GeminiCli, OpenRouter).
    This enables proper authentication handling and request transformation
    based on the actual provider type rather than just AppType.
    
    - Add ProviderType enum with detection logic from config
    - Enhance Claude adapter with OpenRouter detection
    - Enhance Gemini adapter with CLI mode detection
    - Add helper methods for provider type inference
    
    * feat(database): extend schema with streaming and timing fields
    
    Add new columns to proxy_request_logs table for enhanced usage tracking:
    - first_token_ms and duration_ms for performance metrics
    - provider_type and is_streaming for request classification
    - cost_multiplier for flexible pricing
    
    Update model pricing with accurate rates for Claude/GPT/Gemini models.
    Add ensure_model_pricing_seeded() call on database initialization.
    Add test for model pricing auto-seeding verification.
    
    * feat(proxy/usage): enhance token parser and logger for multi-format support
    
    Parser enhancements:
    - Add OpenAI Chat Completions format parsing (prompt_tokens/completion_tokens)
    - Add model field to TokenUsage for actual model name extraction
    - Add from_codex_response_adjusted() for proper cache token handling
    - Add debug logging for better stream event tracing
    
    Logger enhancements:
    - Add first_token_ms, provider_type, is_streaming, cost_multiplier fields
    - Extend RequestLog struct with full metadata tracking
    - Update log_with_calculation() signature for new fields
    
    Calculator: Update tests with model field in TokenUsage.
    
    * feat(proxy): enhance proxy server with session tracking and OpenAI route
    
    Error handling:
    - Add StreamIdleTimeout and AuthError variants for better error classification
    
    Module exports:
    - Export ResponseType, StreamHandler, NonStreamHandler from response_handler
    - Export ProxySession, ClientFormat from session module
    
    Server routing:
    - Add /v1/chat/completions route for OpenAI Chat Completions API
    
    Handlers:
    - Add log_usage_with_session() for enhanced usage tracking with session context
    - Add first_token_ms timing measurement for streaming responses
    - Use SseUsageCollector with start_time for accurate latency calculation
    - Track is_streaming flag in usage logs
    
    * feat(services): add pagination and enhanced filtering for request logs
    
    Usage stats service:
    - Change get_request_logs() from limit/offset to page/page_size pagination
    - Return PaginatedLogs with total count, page, and page_size
    - Add appType and providerName filters with LIKE search
    - Add is_streaming, first_token_ms, duration_ms to RequestLogDetail
    - Join with providers table for provider name lookup
    
    Commands:
    - Update get_request_logs command signature for pagination params
    
    Module exports:
    - Export PaginatedLogs struct
    
    * feat(frontend): update usage types and API for pagination support
    
    Types (usage.ts):
    - Add isStreaming, firstTokenMs, durationMs to RequestLog
    - Add PaginatedLogs interface with data, total, page, pageSize
    - Change LogFilters: providerId -> appType + providerName
    
    API (usage.ts):
    - Change getRequestLogs params from limit/offset to page/pageSize
    - Return PaginatedLogs instead of RequestLog[]
    - Pass filters object directly to backend
    
    Query (usage.ts):
    - Update usageKeys.logs key generation for pagination
    - Update useRequestLogs hook signature
    
    * refactor(ui): enhance RequestLogTable with filtering and pagination
    
    UI improvements:
    - Add filter bar with app type, provider name, model, status selectors
    - Add date range picker (startDate/endDate)
    - Add search/reset/refresh buttons
    
    Pagination:
    - Implement proper page-based pagination with page info display
    - Show total count and current page range
    - Add prev/next navigation buttons
    
    Features:
    - Default to last 24 hours filter
    - Streamlined table columns layout
    - Query invalidation on refresh
    
    * style(config): format mcpPresets code style
    
    Apply consistent formatting to createNpxCommand function and
    sequential-thinking server configuration.
    
    * fix(ui): update SettingsPage tab styles for improved appearance (#342)
    
    * feat(model-test): add provider model availability testing
    
    Implement standalone model testing feature to verify provider API connectivity:
    - Add ModelTestService for Claude/Codex/Gemini endpoint testing
    - Create model_test_logs table for test result persistence
    - Add test button to ProviderCard with loading state
    - Include ModelTestConfigPanel for customizing test parameters
    
    * fix(proxy): resolve token parsing for OpenRouter streaming responses
    
    Problem:
    - OpenRouter and similar third-party services return streaming responses
      where input_tokens appear in message_delta instead of message_start
    - The previous implementation only extracted input_tokens from message_start,
      causing input_tokens to be recorded as 0 for these providers
    
    Changes:
    - streaming.rs: Add prompt_tokens field to Usage struct and include
      input_tokens in the transformed message_delta event when converting
      OpenAI format to Anthropic format
    - parser.rs: Update from_claude_stream_events() to handle input_tokens
      from both message_start (native Claude API) and message_delta (OpenRouter)
      - Use if-let pattern instead of direct unwrap for safer parsing
      - Only update input_tokens from message_delta if not already set
    - logger.rs: Adjust test parameters to match updated function signature
    
    Tests:
    - Add test_openrouter_stream_parsing() for OpenRouter format validation
    - Add test_native_claude_stream_parsing() for native Claude API validation
    
    * fix(pricing): standardize model ID format for pricing lookup
    
    Normalize model IDs by removing vendor prefixes and converting dots to hyphens to ensure consistent pricing lookups across different API response formats.
    
    Changes:
    - Update seed data to use hyphen format (e.g., gpt-5-1, gemini-2-5-pro)
    - Add normalize_model_id() function to strip vendor prefixes (anthropic/, openai/)
    - Convert dots to hyphens in model IDs (claude-haiku-4.5 → claude-haiku-4-5)
    - Try both original and normalized IDs for exact matching
    - Use normalized ID for suffix-based fallback matching
    - Add comprehensive test cases for prefix and dot handling
    - Add warning log when no pricing found
    
    This ensures pricing lookups work correctly for:
    - Models with vendor prefixes: anthropic/claude-haiku-4.5
    - Models with dots in version: claude-sonnet-4.5
    - Models with date suffixes: claude-haiku-4-5-20240229
    
    * style(rust): apply clippy formatting suggestions
    
    Apply automatic clippy fixes for uninlined_format_args warnings across Rust codebase. Replace format string placeholders with inline variable syntax for improved readability.
    
    Changes:
    - Convert format!("{}", var) to format!("{var}")
    - Apply to model_test.rs, parser.rs, and usage_stats.rs
    - Fix line length issues by breaking long function calls
    - Improve code formatting consistency
    
    All changes are automatic formatting with no functional impact.
    
    * fix(ui): restore card borders in usage statistics panels
    
    Restore proper card styling for ModelTestConfigPanel and PricingConfigPanel by adding back border and rounded-lg classes. The transparent background styling was causing visual inconsistency.
    
    Changes:
    - Replace border-none bg-transparent shadow-none with border rounded-lg
    - Apply to both loading and error states for consistency
    - Format TypeScript code for better readability
    - Break long function signatures across multiple lines
    
    This ensures the usage statistics panels have consistent visual appearance with proper borders and rounded corners.
    
    * feat(pricing): add GPT-5 Codex model pricing presets
    
    Add pricing configuration for GPT-5 Codex variants to support cost tracking for Codex-specific models.
    
    Changes:
    - Add gpt-5-codex model with standard GPT-5 pricing
    - Add gpt-5-1-codex model with standard GPT-5.1 pricing
    - Input: $1.25/M tokens, Output: $10/M tokens
    - Cache read: $0.125/M tokens, Cache creation: $0
    
    This ensures accurate cost calculation for Codex API requests using GPT-5 Codex models.