# Model Selector A FastAPI dashboard for browsing and editing the model/provider configuration in `~/.openclaw/openclaw.json`. ![Dashboard](https://img.shields.io/badge/FastAPI-0.115+-green) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-MIT-lightgray) ## Features - **Live provider discovery** — Pull available models from OpenAI, Groq, and OpenRouter APIs - **Smart caching** — Provider snapshots saved locally to `.cache/` for offline browsing - **Alias management** — Give your models friendly names (e.g., `gpt-4o` → "osiris") - **Config sync** — All changes written atomically to your central `openclaw.json` - **Auto-refresh** — Periodic provider updates (default: every 30 minutes) - **Zero-build UI** — Single-page vanilla JS, no frontend build step ## Quick Start ```bash # Copy env template and add your API keys cp .env.example .env # Edit .env with your OPENAI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY # Start the server (defaults to port 3300) ./run.sh # Or with custom port MODEL_SELECTOR_PORT=8080 ./run.sh ``` Open in your browser. ## Configuration ### Environment Variables | Variable | Default | Description | |----------|---------|-------------| | `OPENAI_API_KEY` | — | OpenAI API token | | `GROQ_API_KEY` | — | Groq API token | | `OPENROUTER_API_KEY` | — | OpenRouter API token | | `OPENCLAW_CONFIG_PATH` | `~/.openclaw/openclaw.json` | Path to your OpenClaw config | | `MODEL_SELECTOR_PORT` | `3300` | Dashboard server port | | `MODEL_SELECTOR_REFRESH_INTERVAL` | `1800` | Provider refresh interval (seconds) | | `MODEL_SELECTOR_CACHE_DIR` | `data/model-cache` | Cache directory for provider snapshots | ### Canonical Config Path The dashboard reads from `/home/lucky/.openclaw/openclaw.json` by default. This file uses the OpenClaw schema: ```json { "models": { "providers": { "openai": { "models": [ {"id": "gpt-4o", "name": "GPT-4o", "reasoning": false, "input": ["text"], "contextWindow": 128000, "maxTokens": 16000} ] } } }, "agents": { "defaults": { "models": { "openai/gpt-4o": {"alias": "my-favorite"} } } } } ``` ## API Endpoints | Endpoint | Method | Description | |----------|--------|-------------| | `/` | GET | Dashboard UI | | `/api/state` | GET | Full dashboard state (configured + providers) | | `/api/config` | GET | Config path and configured models | | `/api/alias` | POST | Update model alias (`{full_key, alias}`) | | `/api/config/models/add` | POST | Add model to config (`{provider_key, model_id}`) | | `/api/config/models/delete` | POST | Remove model from config (`{full_key}`) | | `/api/refresh` | POST | Force provider refresh | ## Development ### Running Tests ```bash # Uses temp config fixtures; never touches the live file python -m pytest tests/ -v ``` ### Project Structure ``` . ├── model_selector/ │ ├── main.py # FastAPI app, routes │ ├── config.py # OpenClawConfigRepository │ ├── providers.py # ProviderAdapter, feature detection │ ├── service.py # ModelDashboardService │ ├── cache.py # SnapshotCache │ ├── settings.py # AppSettings from env │ └── ui.py # Jinja2-style HTML rendering ├── data/model-cache/ # Provider snapshots (gitignored) ├── tests/ ├── run.sh # Start server ├── restart.sh # Kill + start └── killserver.sh # Clear port 3300 ``` ## Provider Support | Provider | Key | Features | |----------|-----|----------| | OpenAI | `openai` | reasoning, context_window, max_tokens | | Groq | `groq-cloud` | reasoning, context_window, active status | | OpenRouter | `openrouter` | pricing (prompt/completion/request), full metadata | Missing capabilities display as "—" rather than being invented. ## License MIT