|
|
@@ -1,53 +1,66 @@
|
|
|
# Model Selector
|
|
|
|
|
|
-A FastAPI dashboard for browsing and editing the model/provider configuration in `~/.openclaw/openclaw.json`.
|
|
|
+FastAPI dashboard for browsing and editing the model/provider config in `~/.openclaw/openclaw.json`.
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+It is intentionally small:
|
|
|
|
|
|
-## Features
|
|
|
+- canonical config stays in `/home/lucky/.openclaw/openclaw.json`
|
|
|
+- provider snapshots are cached locally under `data/model-cache/`
|
|
|
+- alias edits land in `agents.defaults.models.<provider/model>.alias`
|
|
|
+- the server runs on port `3300`
|
|
|
|
|
|
-- **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
|
|
|
+## What it shows
|
|
|
+
|
|
|
+- configured models from the canonical OpenClaw config
|
|
|
+- live provider catalogs from OpenAI, Groq, and OpenRouter
|
|
|
+- aliases, reasoning flags, context window, max tokens, and provider metadata when present
|
|
|
+- missing capabilities as `—`, rather than guessing
|
|
|
+
|
|
|
+## Files That Matter
|
|
|
+
|
|
|
+- [`model_selector/main.py`](model_selector/main.py) - FastAPI app and API routes
|
|
|
+- [`model_selector/config.py`](model_selector/config.py) - canonical config read/write logic
|
|
|
+- [`model_selector/providers.py`](model_selector/providers.py) - provider adapters and config serialization
|
|
|
+- [`model_selector/service.py`](model_selector/service.py) - dashboard state assembly
|
|
|
+- [`model_selector/cache.py`](model_selector/cache.py) - local JSON snapshot cache
|
|
|
+- [`run.sh`](run.sh) - start the app
|
|
|
+- [`killserver.sh`](killserver.sh) - clear stale listeners on port `3300`
|
|
|
+- [`restart.sh`](restart.sh) - kill then start
|
|
|
+- [`tests.sh`](tests.sh) - run the test suite
|
|
|
|
|
|
## Quick Start
|
|
|
|
|
|
```bash
|
|
|
-# Copy env template and add your API keys
|
|
|
+# Create a local virtualenv and install dependencies
|
|
|
+python3 -m venv .venv
|
|
|
+source .venv/bin/activate
|
|
|
+pip install -r requirements.txt
|
|
|
+
|
|
|
+# Configure API keys if you want live provider catalogs
|
|
|
cp .env.example .env
|
|
|
-# Edit .env with your OPENAI_API_KEY, GROQ_API_KEY, OPENROUTER_API_KEY
|
|
|
|
|
|
-# Start the server (defaults to port 3300)
|
|
|
+# Start the dashboard
|
|
|
./run.sh
|
|
|
-
|
|
|
-# Or with custom port
|
|
|
-MODEL_SELECTOR_PORT=8080 ./run.sh
|
|
|
```
|
|
|
|
|
|
-Open <http://localhost:3300> in your browser.
|
|
|
+Open `http://localhost:3300`.
|
|
|
|
|
|
## 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 |
|
|
|
+The app reads these environment variables:
|
|
|
|
|
|
-### Canonical Config Path
|
|
|
+| Variable | Default | Purpose |
|
|
|
+| --- | --- | --- |
|
|
|
+| `OPENCLAW_CONFIG_PATH` | `/home/lucky/.openclaw/openclaw.json` | Canonical config file |
|
|
|
+| `MODEL_SELECTOR_PORT` | `3300` | Web server port |
|
|
|
+| `MODEL_SELECTOR_HOST` | `0.0.0.0` | Bind host |
|
|
|
+| `MODEL_SELECTOR_REFRESH_INTERVAL` | `1800` | Live provider refresh interval, in seconds |
|
|
|
+| `MODEL_SELECTOR_CACHE_DIR` | `data/model-cache` | Local JSON snapshot directory |
|
|
|
+| `OPENAI_API_KEY` | unset | OpenAI live catalog access |
|
|
|
+| `GROQ_API_KEY` | unset | Groq live catalog access |
|
|
|
+| `OPENROUTER_API_KEY` | unset | OpenRouter live catalog access |
|
|
|
|
|
|
-The dashboard reads from `/home/lucky/.openclaw/openclaw.json` by default. This file uses the OpenClaw schema:
|
|
|
+The config schema is intentionally narrow:
|
|
|
|
|
|
```json
|
|
|
{
|
|
|
@@ -55,7 +68,14 @@ The dashboard reads from `/home/lucky/.openclaw/openclaw.json` by default. This
|
|
|
"providers": {
|
|
|
"openai": {
|
|
|
"models": [
|
|
|
- {"id": "gpt-4o", "name": "GPT-4o", "reasoning": false, "input": ["text"], "contextWindow": 128000, "maxTokens": 16000}
|
|
|
+ {
|
|
|
+ "id": "gpt-4o",
|
|
|
+ "name": "GPT-4o",
|
|
|
+ "reasoning": false,
|
|
|
+ "input": ["text"],
|
|
|
+ "contextWindow": 128000,
|
|
|
+ "maxTokens": 16000
|
|
|
+ }
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
@@ -63,63 +83,39 @@ The dashboard reads from `/home/lucky/.openclaw/openclaw.json` by default. This
|
|
|
"agents": {
|
|
|
"defaults": {
|
|
|
"models": {
|
|
|
- "openai/gpt-4o": {"alias": "my-favorite"}
|
|
|
+ "openai/gpt-4o": {
|
|
|
+ "alias": "my-favorite"
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
-## API Endpoints
|
|
|
+## API
|
|
|
|
|
|
-| 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 |
|
|
|
+- `GET /` - dashboard UI
|
|
|
+- `GET /api/state` - full dashboard state
|
|
|
+- `GET /api/config` - config path and configured models
|
|
|
+- `POST /api/alias` - update alias for a configured model
|
|
|
+- `POST /api/config/models/add` - add a provider model to config
|
|
|
+- `POST /api/config/models/delete` - remove a configured model
|
|
|
+- `POST /api/refresh` - force a live provider refresh
|
|
|
|
|
|
-## Development
|
|
|
+## Testing
|
|
|
|
|
|
-### Running Tests
|
|
|
+Use the repo-local test runner:
|
|
|
|
|
|
```bash
|
|
|
-# Uses temp config fixtures; never touches the live file
|
|
|
-python -m pytest tests/ -v
|
|
|
+bash tests.sh
|
|
|
```
|
|
|
|
|
|
-### 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 |
|
|
|
+That script uses `.venv` when present and falls back to `python3 -m pytest -q` if not.
|
|
|
|
|
|
-Missing capabilities display as "—" rather than being invented.
|
|
|
+The tests use temporary config fixtures and do not touch the live `~/.openclaw/openclaw.json`.
|
|
|
|
|
|
-## License
|
|
|
+## Notes
|
|
|
|
|
|
-MIT
|
|
|
+- Runtime cache files under `data/model-cache/` are local-only and ignored by git.
|
|
|
+- The dashboard keeps the configured-model view separate from provider catalogs on purpose.
|
|
|
+- OpenRouter config writes only include parameters that the dashboard knows are valid.
|