router-maestro 0.1.2__tar.gz → 0.1.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- router_maestro-0.1.4/.markdownlint.json +4 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/PKG-INFO +71 -33
- {router_maestro-0.1.2 → router_maestro-0.1.4}/README.md +70 -32
- {router_maestro-0.1.2 → router_maestro-0.1.4}/pyproject.toml +1 -1
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/__init__.py +1 -1
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/client.py +0 -32
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/config.py +36 -1
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/main.py +1 -2
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/server.py +1 -1
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/__init__.py +0 -2
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/paths.py +0 -1
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/routing/router.py +2 -2
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/admin.py +1 -73
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/__init__.py +0 -4
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/admin.py +0 -19
- {router_maestro-0.1.2 → router_maestro-0.1.4}/uv.lock +1 -1
- router_maestro-0.1.2/src/router_maestro/cli/stats.py +0 -76
- router_maestro-0.1.2/src/router_maestro/stats/__init__.py +0 -14
- router_maestro-0.1.2/src/router_maestro/stats/heatmap.py +0 -154
- router_maestro-0.1.2/src/router_maestro/stats/storage.py +0 -228
- router_maestro-0.1.2/src/router_maestro/stats/tracker.py +0 -73
- router_maestro-0.1.2/tests/test_stats.py +0 -78
- {router_maestro-0.1.2 → router_maestro-0.1.4}/.env.example +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/.gitignore +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/CLAUDE.md +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/Dockerfile +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/LICENSE +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/Makefile +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/docker-compose.yml +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/docs/deployment.md +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/__main__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/github_oauth.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/manager.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/storage.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/auth.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/context.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/model.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/contexts.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/priorities.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/providers.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/server.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/settings.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/anthropic.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/base.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/copilot.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/openai.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/openai_compat.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/routing/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/app.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/middleware/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/middleware/auth.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/oauth_sessions.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/anthropic.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/chat.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/models.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/anthropic.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/openai.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/translation.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/utils/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/utils/logging.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/utils/tokens.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/__init__.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_auth.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_config.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_providers.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_router.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_translation.py +0 -0
- {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: router-maestro
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Multi-model routing and load balancing system with OpenAI-compatible API
|
|
5
5
|
Author-email: Kanwen Li <likanwen@icloud.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -52,7 +52,6 @@ Router-Maestro acts as a proxy that gives you access to models from multiple pro
|
|
|
52
52
|
- **Dual API compatibility**: Both OpenAI (`/v1/...`) and Anthropic (`/v1/messages`) API formats
|
|
53
53
|
- **Cross-provider translation**: Seamlessly route OpenAI requests to Anthropic providers and vice versa
|
|
54
54
|
- **Configuration hot-reload**: Auto-reload config files every 5 minutes without server restart
|
|
55
|
-
- **Usage tracking**: Token usage statistics with heatmap visualization
|
|
56
55
|
- **CLI management**: Full command-line interface for configuration and server control
|
|
57
56
|
- **Docker ready**: Production-ready Docker images with Traefik integration
|
|
58
57
|
|
|
@@ -60,6 +59,11 @@ Router-Maestro acts as a proxy that gives you access to models from multiple pro
|
|
|
60
59
|
|
|
61
60
|
- [Quick Start](#quick-start)
|
|
62
61
|
- [Core Concepts](#core-concepts)
|
|
62
|
+
- [Model Identification](#model-identification)
|
|
63
|
+
- [Auto-Routing](#auto-routing)
|
|
64
|
+
- [Priority & Fallback](#priority--fallback)
|
|
65
|
+
- [Cross-Provider Translation](#cross-provider-translation)
|
|
66
|
+
- [Contexts](#contexts)
|
|
63
67
|
- [CLI Reference](#cli-reference)
|
|
64
68
|
- [API Reference](#api-reference)
|
|
65
69
|
- [Configuration](#configuration)
|
|
@@ -70,20 +74,36 @@ Router-Maestro acts as a proxy that gives you access to models from multiple pro
|
|
|
70
74
|
|
|
71
75
|
Get up and running in 4 steps:
|
|
72
76
|
|
|
73
|
-
### 1.
|
|
77
|
+
### 1. Start the Server
|
|
78
|
+
|
|
79
|
+
#### Docker (recommended)
|
|
74
80
|
|
|
75
81
|
```bash
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
82
|
+
docker run -d -p 8080:8080 \
|
|
83
|
+
-v ~/.local/share/router-maestro:/home/maestro/.local/share/router-maestro \
|
|
84
|
+
-v ~/.config/router-maestro:/home/maestro/.config/router-maestro \
|
|
85
|
+
likanwen/router-maestro:latest
|
|
79
86
|
```
|
|
80
87
|
|
|
81
|
-
|
|
88
|
+
#### Install locally
|
|
82
89
|
|
|
83
90
|
```bash
|
|
91
|
+
pip install router-maestro
|
|
84
92
|
router-maestro server start --port 8080
|
|
85
93
|
```
|
|
86
94
|
|
|
95
|
+
### 2. Set Context (for Docker or Remote)
|
|
96
|
+
|
|
97
|
+
When running via Docker in remote VPS, set up a context to communicate with the containerized server:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install router-maestro # Install CLI locally
|
|
101
|
+
router-maestro context add docker --endpoint http://localhost:8080
|
|
102
|
+
router-maestro context set docker
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
> **What's a context?** A context is a named connection profile (endpoint + API key) that lets you manage local or remote Router-Maestro servers. See [Contexts](#contexts) for details.
|
|
106
|
+
|
|
87
107
|
### 3. Authenticate with GitHub Copilot
|
|
88
108
|
|
|
89
109
|
```bash
|
|
@@ -112,8 +132,8 @@ router-maestro config claude-code
|
|
|
112
132
|
|
|
113
133
|
Models are identified using the format `{provider}/{model-id}`:
|
|
114
134
|
|
|
115
|
-
| Example
|
|
116
|
-
|
|
135
|
+
| Example | Description |
|
|
136
|
+
| --------------------------------- | ----------------------------------- |
|
|
117
137
|
| `github-copilot/gpt-4o` | GPT-4o via GitHub Copilot |
|
|
118
138
|
| `github-copilot/claude-sonnet-4` | Claude Sonnet 4 via GitHub Copilot |
|
|
119
139
|
| `openai/gpt-4-turbo` | GPT-4 Turbo via OpenAI |
|
|
@@ -144,8 +164,8 @@ router-maestro model priority list
|
|
|
144
164
|
|
|
145
165
|
**Fallback** triggers when a request fails with a retryable error (429, 5xx):
|
|
146
166
|
|
|
147
|
-
| Strategy
|
|
148
|
-
|
|
167
|
+
| Strategy | Behavior |
|
|
168
|
+
| ------------ | ------------------------------------ |
|
|
149
169
|
| `priority` | Try next model in priorities list |
|
|
150
170
|
| `same-model` | Try same model on different provider |
|
|
151
171
|
| `none` | Fail immediately |
|
|
@@ -171,29 +191,50 @@ POST /v1/messages {"model": "openai/gpt-4o", ...}
|
|
|
171
191
|
POST /v1/chat/completions {"model": "anthropic/claude-3-5-sonnet", ...}
|
|
172
192
|
```
|
|
173
193
|
|
|
194
|
+
### Contexts
|
|
195
|
+
|
|
196
|
+
A **context** is a named connection profile that stores an endpoint URL and API key. Contexts let you manage multiple Router-Maestro deployments from a single CLI.
|
|
197
|
+
|
|
198
|
+
| Context | Use Case |
|
|
199
|
+
| -------- | ------------------------------------------ |
|
|
200
|
+
| `local` | Default context for `router-maestro server start` |
|
|
201
|
+
| `docker` | Connect to a local Docker container |
|
|
202
|
+
| `my-vps` | Connect to a remote VPS deployment |
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Add a context
|
|
206
|
+
router-maestro context add my-vps --endpoint https://api.example.com --api-key xxx
|
|
207
|
+
|
|
208
|
+
# Switch contexts
|
|
209
|
+
router-maestro context set my-vps
|
|
210
|
+
|
|
211
|
+
# All CLI commands now target the remote server
|
|
212
|
+
router-maestro model list
|
|
213
|
+
```
|
|
214
|
+
|
|
174
215
|
## CLI Reference
|
|
175
216
|
|
|
176
217
|
### Server
|
|
177
218
|
|
|
178
|
-
| Command
|
|
179
|
-
|
|
180
|
-
| `server start --port 8080` | Start the server
|
|
219
|
+
| Command | Description |
|
|
220
|
+
| -------------------------- | ------------------ |
|
|
221
|
+
| `server start --port 8080` | Start the server |
|
|
181
222
|
| `server stop` | Stop the server |
|
|
182
223
|
| `server info` | Show server status |
|
|
183
224
|
|
|
184
225
|
### Authentication
|
|
185
226
|
|
|
186
|
-
| Command
|
|
187
|
-
|
|
188
|
-
| `auth login [provider]` | Authenticate with a provider
|
|
227
|
+
| Command | Description |
|
|
228
|
+
| ----------------------- | ------------------------------ |
|
|
229
|
+
| `auth login [provider]` | Authenticate with a provider |
|
|
189
230
|
| `auth logout <provider>` | Remove authentication |
|
|
190
231
|
| `auth list` | List authenticated providers |
|
|
191
232
|
|
|
192
233
|
### Models
|
|
193
234
|
|
|
194
|
-
| Command
|
|
195
|
-
|
|
196
|
-
| `model list`
|
|
235
|
+
| Command | Description |
|
|
236
|
+
| ---------------------------------- | ---------------------- |
|
|
237
|
+
| `model list` | List available models |
|
|
197
238
|
| `model refresh` | Refresh models cache |
|
|
198
239
|
| `model priority list` | Show priorities |
|
|
199
240
|
| `model priority <model> --position <n>` | Set priority |
|
|
@@ -201,9 +242,9 @@ POST /v1/chat/completions {"model": "anthropic/claude-3-5-sonnet", ...}
|
|
|
201
242
|
|
|
202
243
|
### Contexts (Remote Management)
|
|
203
244
|
|
|
204
|
-
| Command
|
|
205
|
-
|
|
206
|
-
| `context show`
|
|
245
|
+
| Command | Description |
|
|
246
|
+
| ---------------------------------------------------- | -------------------- |
|
|
247
|
+
| `context show` | Show current context |
|
|
207
248
|
| `context list` | List all contexts |
|
|
208
249
|
| `context set <name>` | Switch context |
|
|
209
250
|
| `context add <name> --endpoint <url> --api-key <key>` | Add remote context |
|
|
@@ -211,11 +252,9 @@ POST /v1/chat/completions {"model": "anthropic/claude-3-5-sonnet", ...}
|
|
|
211
252
|
|
|
212
253
|
### Other
|
|
213
254
|
|
|
214
|
-
| Command
|
|
215
|
-
|
|
255
|
+
| Command | Description |
|
|
256
|
+
| -------------------- | ----------------------------- |
|
|
216
257
|
| `config claude-code` | Generate Claude Code settings |
|
|
217
|
-
| `stats --days 7` | Show usage statistics |
|
|
218
|
-
| `stats --days 30 --heatmap` | Show heatmap visualization |
|
|
219
258
|
|
|
220
259
|
## API Reference
|
|
221
260
|
|
|
@@ -262,8 +301,8 @@ POST /api/admin/models/refresh # Refresh model cache
|
|
|
262
301
|
|
|
263
302
|
Following XDG Base Directory specification:
|
|
264
303
|
|
|
265
|
-
| Type
|
|
266
|
-
|
|
304
|
+
| Type | Path | Contents |
|
|
305
|
+
| ---------- | ---------------------------------- | ---------------------------- |
|
|
267
306
|
| **Config** | `~/.config/router-maestro/` | |
|
|
268
307
|
| | `providers.json` | Custom provider definitions |
|
|
269
308
|
| | `priorities.json` | Model priorities and fallback |
|
|
@@ -271,7 +310,6 @@ Following XDG Base Directory specification:
|
|
|
271
310
|
| **Data** | `~/.local/share/router-maestro/` | |
|
|
272
311
|
| | `auth.json` | OAuth tokens |
|
|
273
312
|
| | `server.json` | Server state |
|
|
274
|
-
| | `stats.db` | Usage statistics |
|
|
275
313
|
|
|
276
314
|
### Custom Providers
|
|
277
315
|
|
|
@@ -302,8 +340,8 @@ export OLLAMA_API_KEY="sk-..."
|
|
|
302
340
|
|
|
303
341
|
Configuration files are automatically reloaded every 5 minutes:
|
|
304
342
|
|
|
305
|
-
| File
|
|
306
|
-
|
|
343
|
+
| File | Auto-Reload |
|
|
344
|
+
| ------------------ | ---------------- |
|
|
307
345
|
| `priorities.json` | ✓ (5 min) |
|
|
308
346
|
| `providers.json` | ✓ (5 min) |
|
|
309
347
|
| `auth.json` | Requires restart |
|
|
@@ -360,7 +398,6 @@ router-maestro context set my-vps
|
|
|
360
398
|
|
|
361
399
|
# Now all commands target the VPS
|
|
362
400
|
router-maestro model list
|
|
363
|
-
router-maestro stats --days 7
|
|
364
401
|
```
|
|
365
402
|
|
|
366
403
|
### HTTPS with Traefik
|
|
@@ -368,6 +405,7 @@ router-maestro stats --days 7
|
|
|
368
405
|
The Docker Compose setup includes Traefik for automatic HTTPS via Let's Encrypt with DNS challenge.
|
|
369
406
|
|
|
370
407
|
For detailed configuration options including:
|
|
408
|
+
|
|
371
409
|
- Other DNS providers (Route53, DigitalOcean, etc.)
|
|
372
410
|
- HTTP challenge setup
|
|
373
411
|
- Traefik dashboard configuration
|
|
@@ -15,7 +15,6 @@ Router-Maestro acts as a proxy that gives you access to models from multiple pro
|
|
|
15
15
|
- **Dual API compatibility**: Both OpenAI (`/v1/...`) and Anthropic (`/v1/messages`) API formats
|
|
16
16
|
- **Cross-provider translation**: Seamlessly route OpenAI requests to Anthropic providers and vice versa
|
|
17
17
|
- **Configuration hot-reload**: Auto-reload config files every 5 minutes without server restart
|
|
18
|
-
- **Usage tracking**: Token usage statistics with heatmap visualization
|
|
19
18
|
- **CLI management**: Full command-line interface for configuration and server control
|
|
20
19
|
- **Docker ready**: Production-ready Docker images with Traefik integration
|
|
21
20
|
|
|
@@ -23,6 +22,11 @@ Router-Maestro acts as a proxy that gives you access to models from multiple pro
|
|
|
23
22
|
|
|
24
23
|
- [Quick Start](#quick-start)
|
|
25
24
|
- [Core Concepts](#core-concepts)
|
|
25
|
+
- [Model Identification](#model-identification)
|
|
26
|
+
- [Auto-Routing](#auto-routing)
|
|
27
|
+
- [Priority & Fallback](#priority--fallback)
|
|
28
|
+
- [Cross-Provider Translation](#cross-provider-translation)
|
|
29
|
+
- [Contexts](#contexts)
|
|
26
30
|
- [CLI Reference](#cli-reference)
|
|
27
31
|
- [API Reference](#api-reference)
|
|
28
32
|
- [Configuration](#configuration)
|
|
@@ -33,20 +37,36 @@ Router-Maestro acts as a proxy that gives you access to models from multiple pro
|
|
|
33
37
|
|
|
34
38
|
Get up and running in 4 steps:
|
|
35
39
|
|
|
36
|
-
### 1.
|
|
40
|
+
### 1. Start the Server
|
|
41
|
+
|
|
42
|
+
#### Docker (recommended)
|
|
37
43
|
|
|
38
44
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
docker run -d -p 8080:8080 \
|
|
46
|
+
-v ~/.local/share/router-maestro:/home/maestro/.local/share/router-maestro \
|
|
47
|
+
-v ~/.config/router-maestro:/home/maestro/.config/router-maestro \
|
|
48
|
+
likanwen/router-maestro:latest
|
|
42
49
|
```
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
#### Install locally
|
|
45
52
|
|
|
46
53
|
```bash
|
|
54
|
+
pip install router-maestro
|
|
47
55
|
router-maestro server start --port 8080
|
|
48
56
|
```
|
|
49
57
|
|
|
58
|
+
### 2. Set Context (for Docker or Remote)
|
|
59
|
+
|
|
60
|
+
When running via Docker in remote VPS, set up a context to communicate with the containerized server:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install router-maestro # Install CLI locally
|
|
64
|
+
router-maestro context add docker --endpoint http://localhost:8080
|
|
65
|
+
router-maestro context set docker
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
> **What's a context?** A context is a named connection profile (endpoint + API key) that lets you manage local or remote Router-Maestro servers. See [Contexts](#contexts) for details.
|
|
69
|
+
|
|
50
70
|
### 3. Authenticate with GitHub Copilot
|
|
51
71
|
|
|
52
72
|
```bash
|
|
@@ -75,8 +95,8 @@ router-maestro config claude-code
|
|
|
75
95
|
|
|
76
96
|
Models are identified using the format `{provider}/{model-id}`:
|
|
77
97
|
|
|
78
|
-
| Example
|
|
79
|
-
|
|
98
|
+
| Example | Description |
|
|
99
|
+
| --------------------------------- | ----------------------------------- |
|
|
80
100
|
| `github-copilot/gpt-4o` | GPT-4o via GitHub Copilot |
|
|
81
101
|
| `github-copilot/claude-sonnet-4` | Claude Sonnet 4 via GitHub Copilot |
|
|
82
102
|
| `openai/gpt-4-turbo` | GPT-4 Turbo via OpenAI |
|
|
@@ -107,8 +127,8 @@ router-maestro model priority list
|
|
|
107
127
|
|
|
108
128
|
**Fallback** triggers when a request fails with a retryable error (429, 5xx):
|
|
109
129
|
|
|
110
|
-
| Strategy
|
|
111
|
-
|
|
130
|
+
| Strategy | Behavior |
|
|
131
|
+
| ------------ | ------------------------------------ |
|
|
112
132
|
| `priority` | Try next model in priorities list |
|
|
113
133
|
| `same-model` | Try same model on different provider |
|
|
114
134
|
| `none` | Fail immediately |
|
|
@@ -134,29 +154,50 @@ POST /v1/messages {"model": "openai/gpt-4o", ...}
|
|
|
134
154
|
POST /v1/chat/completions {"model": "anthropic/claude-3-5-sonnet", ...}
|
|
135
155
|
```
|
|
136
156
|
|
|
157
|
+
### Contexts
|
|
158
|
+
|
|
159
|
+
A **context** is a named connection profile that stores an endpoint URL and API key. Contexts let you manage multiple Router-Maestro deployments from a single CLI.
|
|
160
|
+
|
|
161
|
+
| Context | Use Case |
|
|
162
|
+
| -------- | ------------------------------------------ |
|
|
163
|
+
| `local` | Default context for `router-maestro server start` |
|
|
164
|
+
| `docker` | Connect to a local Docker container |
|
|
165
|
+
| `my-vps` | Connect to a remote VPS deployment |
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
# Add a context
|
|
169
|
+
router-maestro context add my-vps --endpoint https://api.example.com --api-key xxx
|
|
170
|
+
|
|
171
|
+
# Switch contexts
|
|
172
|
+
router-maestro context set my-vps
|
|
173
|
+
|
|
174
|
+
# All CLI commands now target the remote server
|
|
175
|
+
router-maestro model list
|
|
176
|
+
```
|
|
177
|
+
|
|
137
178
|
## CLI Reference
|
|
138
179
|
|
|
139
180
|
### Server
|
|
140
181
|
|
|
141
|
-
| Command
|
|
142
|
-
|
|
143
|
-
| `server start --port 8080` | Start the server
|
|
182
|
+
| Command | Description |
|
|
183
|
+
| -------------------------- | ------------------ |
|
|
184
|
+
| `server start --port 8080` | Start the server |
|
|
144
185
|
| `server stop` | Stop the server |
|
|
145
186
|
| `server info` | Show server status |
|
|
146
187
|
|
|
147
188
|
### Authentication
|
|
148
189
|
|
|
149
|
-
| Command
|
|
150
|
-
|
|
151
|
-
| `auth login [provider]` | Authenticate with a provider
|
|
190
|
+
| Command | Description |
|
|
191
|
+
| ----------------------- | ------------------------------ |
|
|
192
|
+
| `auth login [provider]` | Authenticate with a provider |
|
|
152
193
|
| `auth logout <provider>` | Remove authentication |
|
|
153
194
|
| `auth list` | List authenticated providers |
|
|
154
195
|
|
|
155
196
|
### Models
|
|
156
197
|
|
|
157
|
-
| Command
|
|
158
|
-
|
|
159
|
-
| `model list`
|
|
198
|
+
| Command | Description |
|
|
199
|
+
| ---------------------------------- | ---------------------- |
|
|
200
|
+
| `model list` | List available models |
|
|
160
201
|
| `model refresh` | Refresh models cache |
|
|
161
202
|
| `model priority list` | Show priorities |
|
|
162
203
|
| `model priority <model> --position <n>` | Set priority |
|
|
@@ -164,9 +205,9 @@ POST /v1/chat/completions {"model": "anthropic/claude-3-5-sonnet", ...}
|
|
|
164
205
|
|
|
165
206
|
### Contexts (Remote Management)
|
|
166
207
|
|
|
167
|
-
| Command
|
|
168
|
-
|
|
169
|
-
| `context show`
|
|
208
|
+
| Command | Description |
|
|
209
|
+
| ---------------------------------------------------- | -------------------- |
|
|
210
|
+
| `context show` | Show current context |
|
|
170
211
|
| `context list` | List all contexts |
|
|
171
212
|
| `context set <name>` | Switch context |
|
|
172
213
|
| `context add <name> --endpoint <url> --api-key <key>` | Add remote context |
|
|
@@ -174,11 +215,9 @@ POST /v1/chat/completions {"model": "anthropic/claude-3-5-sonnet", ...}
|
|
|
174
215
|
|
|
175
216
|
### Other
|
|
176
217
|
|
|
177
|
-
| Command
|
|
178
|
-
|
|
218
|
+
| Command | Description |
|
|
219
|
+
| -------------------- | ----------------------------- |
|
|
179
220
|
| `config claude-code` | Generate Claude Code settings |
|
|
180
|
-
| `stats --days 7` | Show usage statistics |
|
|
181
|
-
| `stats --days 30 --heatmap` | Show heatmap visualization |
|
|
182
221
|
|
|
183
222
|
## API Reference
|
|
184
223
|
|
|
@@ -225,8 +264,8 @@ POST /api/admin/models/refresh # Refresh model cache
|
|
|
225
264
|
|
|
226
265
|
Following XDG Base Directory specification:
|
|
227
266
|
|
|
228
|
-
| Type
|
|
229
|
-
|
|
267
|
+
| Type | Path | Contents |
|
|
268
|
+
| ---------- | ---------------------------------- | ---------------------------- |
|
|
230
269
|
| **Config** | `~/.config/router-maestro/` | |
|
|
231
270
|
| | `providers.json` | Custom provider definitions |
|
|
232
271
|
| | `priorities.json` | Model priorities and fallback |
|
|
@@ -234,7 +273,6 @@ Following XDG Base Directory specification:
|
|
|
234
273
|
| **Data** | `~/.local/share/router-maestro/` | |
|
|
235
274
|
| | `auth.json` | OAuth tokens |
|
|
236
275
|
| | `server.json` | Server state |
|
|
237
|
-
| | `stats.db` | Usage statistics |
|
|
238
276
|
|
|
239
277
|
### Custom Providers
|
|
240
278
|
|
|
@@ -265,8 +303,8 @@ export OLLAMA_API_KEY="sk-..."
|
|
|
265
303
|
|
|
266
304
|
Configuration files are automatically reloaded every 5 minutes:
|
|
267
305
|
|
|
268
|
-
| File
|
|
269
|
-
|
|
306
|
+
| File | Auto-Reload |
|
|
307
|
+
| ------------------ | ---------------- |
|
|
270
308
|
| `priorities.json` | ✓ (5 min) |
|
|
271
309
|
| `providers.json` | ✓ (5 min) |
|
|
272
310
|
| `auth.json` | Requires restart |
|
|
@@ -323,7 +361,6 @@ router-maestro context set my-vps
|
|
|
323
361
|
|
|
324
362
|
# Now all commands target the VPS
|
|
325
363
|
router-maestro model list
|
|
326
|
-
router-maestro stats --days 7
|
|
327
364
|
```
|
|
328
365
|
|
|
329
366
|
### HTTPS with Traefik
|
|
@@ -331,6 +368,7 @@ router-maestro stats --days 7
|
|
|
331
368
|
The Docker Compose setup includes Traefik for automatic HTTPS via Let's Encrypt with DNS challenge.
|
|
332
369
|
|
|
333
370
|
For detailed configuration options including:
|
|
371
|
+
|
|
334
372
|
- Other DNS providers (Route53, DigitalOcean, etc.)
|
|
335
373
|
- HTTP challenge setup
|
|
336
374
|
- Traefik dashboard configuration
|
|
@@ -241,38 +241,6 @@ class AdminClient:
|
|
|
241
241
|
self._handle_connection_error(e)
|
|
242
242
|
return False
|
|
243
243
|
|
|
244
|
-
async def get_stats(
|
|
245
|
-
self, days: int = 7, provider: str | None = None, model: str | None = None
|
|
246
|
-
) -> dict:
|
|
247
|
-
"""Get usage statistics.
|
|
248
|
-
|
|
249
|
-
Args:
|
|
250
|
-
days: Number of days to query
|
|
251
|
-
provider: Optional provider filter
|
|
252
|
-
model: Optional model filter
|
|
253
|
-
|
|
254
|
-
Returns:
|
|
255
|
-
Stats dict with total_requests, total_tokens, by_provider, by_model
|
|
256
|
-
"""
|
|
257
|
-
try:
|
|
258
|
-
async with httpx.AsyncClient() as client:
|
|
259
|
-
params: dict = {"days": days}
|
|
260
|
-
if provider:
|
|
261
|
-
params["provider"] = provider
|
|
262
|
-
if model:
|
|
263
|
-
params["model"] = model
|
|
264
|
-
|
|
265
|
-
response = await client.get(
|
|
266
|
-
f"{self.endpoint}/api/admin/stats",
|
|
267
|
-
headers=self._get_headers(),
|
|
268
|
-
params=params,
|
|
269
|
-
)
|
|
270
|
-
response.raise_for_status()
|
|
271
|
-
return response.json()
|
|
272
|
-
except httpx.HTTPError as e:
|
|
273
|
-
self._handle_connection_error(e)
|
|
274
|
-
return {}
|
|
275
|
-
|
|
276
244
|
async def test_connection(self) -> dict:
|
|
277
245
|
"""Test connection to the server.
|
|
278
246
|
|
|
@@ -15,9 +15,17 @@ from rich.table import Table
|
|
|
15
15
|
from router_maestro.cli.client import ServerNotRunningError, get_admin_client
|
|
16
16
|
from router_maestro.config.server import get_current_context_api_key
|
|
17
17
|
|
|
18
|
-
app = typer.Typer(
|
|
18
|
+
app = typer.Typer(invoke_without_command=True)
|
|
19
19
|
console = Console()
|
|
20
20
|
|
|
21
|
+
# Available CLI tools for configuration
|
|
22
|
+
CLI_TOOLS = {
|
|
23
|
+
"claude-code": {
|
|
24
|
+
"name": "Claude Code",
|
|
25
|
+
"description": "Generate settings.json for Claude Code CLI",
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
|
|
22
30
|
def get_claude_code_paths() -> dict[str, Path]:
|
|
23
31
|
"""Get Claude Code settings paths."""
|
|
@@ -27,6 +35,33 @@ def get_claude_code_paths() -> dict[str, Path]:
|
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
|
|
38
|
+
@app.callback(invoke_without_command=True)
|
|
39
|
+
def config_callback(ctx: typer.Context) -> None:
|
|
40
|
+
"""Generate configuration for CLI tools (interactive selection if not specified)."""
|
|
41
|
+
if ctx.invoked_subcommand is not None:
|
|
42
|
+
return
|
|
43
|
+
|
|
44
|
+
# Interactive selection
|
|
45
|
+
console.print("\n[bold]Available CLI tools:[/bold]")
|
|
46
|
+
tools = list(CLI_TOOLS.items())
|
|
47
|
+
for i, (key, info) in enumerate(tools, 1):
|
|
48
|
+
console.print(f" {i}. {info['name']} - {info['description']}")
|
|
49
|
+
|
|
50
|
+
console.print()
|
|
51
|
+
choice = Prompt.ask(
|
|
52
|
+
"Select tool to configure",
|
|
53
|
+
choices=[str(i) for i in range(1, len(tools) + 1)],
|
|
54
|
+
default="1",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
idx = int(choice) - 1
|
|
58
|
+
tool_key = tools[idx][0]
|
|
59
|
+
|
|
60
|
+
# Dispatch to the appropriate command
|
|
61
|
+
if tool_key == "claude-code":
|
|
62
|
+
claude_code_config()
|
|
63
|
+
|
|
64
|
+
|
|
30
65
|
@app.command(name="claude-code")
|
|
31
66
|
def claude_code_config() -> None:
|
|
32
67
|
"""Generate Claude Code CLI settings.json for router-maestro."""
|
|
@@ -14,14 +14,13 @@ app = typer.Typer(
|
|
|
14
14
|
console = Console()
|
|
15
15
|
|
|
16
16
|
# Import and register sub-commands
|
|
17
|
-
from router_maestro.cli import auth, config, context, model, server
|
|
17
|
+
from router_maestro.cli import auth, config, context, model, server # noqa: E402
|
|
18
18
|
|
|
19
19
|
app.add_typer(server.app, name="server", help="Manage the API server")
|
|
20
20
|
app.add_typer(auth.app, name="auth", help="Manage authentication for providers")
|
|
21
21
|
app.add_typer(model.app, name="model", help="Manage models and priorities")
|
|
22
22
|
app.add_typer(context.app, name="context", help="Manage deployment contexts")
|
|
23
23
|
app.add_typer(config.app, name="config", help="Manage configuration")
|
|
24
|
-
app.command(name="stats")(stats.stats)
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
@app.callback(invoke_without_command=True)
|
|
@@ -98,7 +98,7 @@ def status() -> None:
|
|
|
98
98
|
|
|
99
99
|
try:
|
|
100
100
|
data = asyncio.run(client.test_connection())
|
|
101
|
-
console.print(
|
|
101
|
+
console.print("[green]Server is running[/green]")
|
|
102
102
|
console.print(f" Version: {data.get('version', 'unknown')}")
|
|
103
103
|
console.print(f" Status: {data.get('status', 'unknown')}")
|
|
104
104
|
except Exception as e:
|
|
@@ -8,7 +8,6 @@ from router_maestro.config.paths import (
|
|
|
8
8
|
PRIORITIES_FILE,
|
|
9
9
|
PROVIDERS_FILE,
|
|
10
10
|
SERVER_CONFIG_FILE,
|
|
11
|
-
STATS_DB_FILE,
|
|
12
11
|
get_config_dir,
|
|
13
12
|
get_data_dir,
|
|
14
13
|
)
|
|
@@ -45,7 +44,6 @@ __all__ = [
|
|
|
45
44
|
"PROVIDERS_FILE",
|
|
46
45
|
"PRIORITIES_FILE",
|
|
47
46
|
"CONTEXTS_FILE",
|
|
48
|
-
"STATS_DB_FILE",
|
|
49
47
|
"LOG_FILE",
|
|
50
48
|
# Provider models
|
|
51
49
|
"ModelConfig",
|
|
@@ -46,5 +46,4 @@ SERVER_CONFIG_FILE = get_data_dir() / "server.json"
|
|
|
46
46
|
PROVIDERS_FILE = get_config_dir() / "providers.json"
|
|
47
47
|
PRIORITIES_FILE = get_config_dir() / "priorities.json"
|
|
48
48
|
CONTEXTS_FILE = get_config_dir() / "contexts.json"
|
|
49
|
-
STATS_DB_FILE = get_data_dir() / "stats.db"
|
|
50
49
|
LOG_FILE = get_data_dir() / "router-maestro.log"
|
|
@@ -382,7 +382,7 @@ class Router:
|
|
|
382
382
|
try:
|
|
383
383
|
await provider.ensure_token()
|
|
384
384
|
if is_stream:
|
|
385
|
-
stream = provider.chat_completion_stream(actual_request)
|
|
385
|
+
stream = await provider.chat_completion_stream(actual_request)
|
|
386
386
|
logger.info("Stream request routed to %s", provider_name)
|
|
387
387
|
return stream, provider_name
|
|
388
388
|
else:
|
|
@@ -417,7 +417,7 @@ class Router:
|
|
|
417
417
|
try:
|
|
418
418
|
await other_provider.ensure_token()
|
|
419
419
|
if is_stream:
|
|
420
|
-
stream = other_provider.chat_completion_stream(fallback_request)
|
|
420
|
+
stream = await other_provider.chat_completion_stream(fallback_request)
|
|
421
421
|
logger.info("Stream fallback succeeded via %s", other_name)
|
|
422
422
|
return stream, other_name
|
|
423
423
|
else:
|