API endpoints return valid data via curl but browser JS shows 'Failed to load'.
Added verbose logging and a fixed-position debug panel to api.js that displays
the exact error type (JSON parse, API error, or network exception) on-page.
Bumped cache-bust to ?v=4.
- Add in-memory ModelConfigCache (30s refresh, explicit invalidation)
replacing 2 SQLite queries per request (model lookup + cost override)
- Configure all 5 provider HTTP clients with proper timeouts (300s),
connection pooling (4 idle/host, 90s idle timeout), and TCP keepalive
- Move client_usage update to tokio::spawn in non-streaming path
- Use fast chars/4 heuristic for token estimation on large inputs (>1KB)
- Generate single UUID/timestamp per SSE stream instead of per chunk
- Add shared LazyLock<Client> for image fetching in multimodal module
- Add proxy overhead timing instrumentation for both request paths
- Fix test helper to include new model_config_cache field
Backend: wrap SUM() queries with COALESCE in handle_time_series,
handle_clients_usage, and handle_detailed_usage to prevent NULL-induced
panics when no data exists for a time window.
Frontend: add showEmptyChart() empty-state messages and error feedback
across overview, analytics, costs, and clients pages. Rewrite analytics
loadCharts() to use Promise.allSettled() so each chart renders
independently on partial API failures.
messages_to_openai_json_text_only() was missing tool-calling support,
causing DeepSeek 400 errors when conversations included tool turns.
Now mirrors messages_to_openai_json() logic for tool-role messages
(tool_call_id, name) and assistant tool_calls, with images replaced
by "[Image]" text.
- Add /api/system/metrics endpoint reading real data from /proc (CPU, memory, disk, network, load avg, uptime, connections)
- Replace hardcoded fake monitoring metrics with live API data
- Replace random chart data with real latency/error-rate/client-request charts from DB logs
- Fix light-mode colors leaking into dark theme (monitoring stream bg, settings tokens, warning card)
- Add 'models' to page title map, fix System Health card structure
- Move inline styles to CSS classes (monitoring-layout, monitoring-stream, token-item, warning-card)
- Prevent duplicate style injection in monitoring page
INSERT into llm_requests was failing with FOREIGN KEY constraint (code 787)
because client_id (e.g. 'client_sk-hobok') didn't exist in the clients table.
Add INSERT OR IGNORE for the client row within the same transaction.
- overview.js: fix time-series chart crash (data is {series:[...]}, not array; field is 'time' not 'hour')
- monitoring.js: use fallback field names (total_tokens/tokens, duration_ms/duration) for WebSocket vs API compat
- monitoring.js: disable localhost demo data injection that mixed fake data with real
- websocket.js: fix duplicate condition and field name mismatches in dead-code handlers
- logging/mod.rs: add info! logs for successful DB insert and broadcast count for diagnostics
Implement full OpenAI-compatible tool-calling support across the proxy,
enabling OpenCode to use llm-proxy as its sole LLM backend.
- Add 9 tool-calling types (Tool, FunctionDef, ToolChoice, ToolCall, etc.)
- Update ChatCompletionRequest/ChatMessage/ChatStreamDelta with tool fields
- Update UnifiedRequest/UnifiedMessage to carry tool data through the pipeline
- Shared helpers: messages_to_openai_json handles tool messages, build_openai_body
includes tools/tool_choice, parse/stream extract tool_calls from responses
- Gemini: full OpenAI<->Gemini format translation (functionDeclarations,
functionCall/functionResponse, synthetic call IDs, tool_config mapping)
- Gemini: extract duplicated message-conversion into shared convert_messages()
- Server: SSE streams include tool_calls deltas, finish_reason='tool_calls'
- AggregatingStream: accumulate tool call deltas across stream chunks
- OpenAI provider: add o4- prefix to supports_model()
- Added 'users' table to database with bcrypt hashing.
- Refactored login to verify against the database.
- Implemented 'Security' section in settings to allow changing the admin password.
- Initialized system with default user 'admin' and password 'admin'.
- Added 'credit_balance' and 'low_credit_threshold' to 'provider_configs' table.
- Updated dashboard backend to support reading and updating provider credits.
- Implemented real-time credit deduction from provider balances on successful requests.
- Added visual balance indicators and configuration modal to the 'Providers' dashboard tab.
- Added 'provider_configs' and 'model_configs' tables to database.
- Refactored ProviderManager to support thread-safe dynamic updates and database overrides.
- Implemented 'Models' tab in dashboard to manage model visibility, mapping, and pricing.
- Added provider configuration modal to 'Providers' tab.
- Integrated database overrides into chat completion logic (enabled state, mapping, and cost).
- Set Grok to enabled: true by default.
- Updated AppState to include raw AppConfig.
- Refactored dashboard to show all supported providers, including their configuration and initialization status (online, disabled, or error).
- Added global loading spinner and page transitions.
- Improved sidebar with tooltips and persistent collapsed state.
- Fixed chart memory leaks by properly destroying instances on page change.
- Unified WebSocket event handling and status indicators.
- Refined stat cards, tables, and modal interactions.
- Added real backend integration for logout and session management.
- Switched from mock data to real backend APIs.
- Implemented unified ApiClient for consistent frontend data fetching.
- Refactored dashboard structure and styles for a modern SaaS aesthetic.
- Fixed Axum 0.8+ routing and parameter syntax issues.
- Implemented real client creation/deletion and provider health monitoring.
- Synchronized WebSocket event structures between backend and frontend.
- Added strict token validation against LLM_PROXY__SERVER__AUTH_TOKENS.
- Integrated 'reasoning_content' support into providers and server responses.
- Updated AppState to carry valid auth tokens for request-time validation.