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.
Files changed (73) hide show
  1. router_maestro-0.1.4/.markdownlint.json +4 -0
  2. {router_maestro-0.1.2 → router_maestro-0.1.4}/PKG-INFO +71 -33
  3. {router_maestro-0.1.2 → router_maestro-0.1.4}/README.md +70 -32
  4. {router_maestro-0.1.2 → router_maestro-0.1.4}/pyproject.toml +1 -1
  5. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/__init__.py +1 -1
  6. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/client.py +0 -32
  7. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/config.py +36 -1
  8. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/main.py +1 -2
  9. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/server.py +1 -1
  10. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/__init__.py +0 -2
  11. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/paths.py +0 -1
  12. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/routing/router.py +2 -2
  13. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/admin.py +1 -73
  14. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/__init__.py +0 -4
  15. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/admin.py +0 -19
  16. {router_maestro-0.1.2 → router_maestro-0.1.4}/uv.lock +1 -1
  17. router_maestro-0.1.2/src/router_maestro/cli/stats.py +0 -76
  18. router_maestro-0.1.2/src/router_maestro/stats/__init__.py +0 -14
  19. router_maestro-0.1.2/src/router_maestro/stats/heatmap.py +0 -154
  20. router_maestro-0.1.2/src/router_maestro/stats/storage.py +0 -228
  21. router_maestro-0.1.2/src/router_maestro/stats/tracker.py +0 -73
  22. router_maestro-0.1.2/tests/test_stats.py +0 -78
  23. {router_maestro-0.1.2 → router_maestro-0.1.4}/.env.example +0 -0
  24. {router_maestro-0.1.2 → router_maestro-0.1.4}/.gitignore +0 -0
  25. {router_maestro-0.1.2 → router_maestro-0.1.4}/CLAUDE.md +0 -0
  26. {router_maestro-0.1.2 → router_maestro-0.1.4}/Dockerfile +0 -0
  27. {router_maestro-0.1.2 → router_maestro-0.1.4}/LICENSE +0 -0
  28. {router_maestro-0.1.2 → router_maestro-0.1.4}/Makefile +0 -0
  29. {router_maestro-0.1.2 → router_maestro-0.1.4}/docker-compose.yml +0 -0
  30. {router_maestro-0.1.2 → router_maestro-0.1.4}/docs/deployment.md +0 -0
  31. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/__main__.py +0 -0
  32. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/__init__.py +0 -0
  33. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/github_oauth.py +0 -0
  34. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/manager.py +0 -0
  35. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/auth/storage.py +0 -0
  36. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/__init__.py +0 -0
  37. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/auth.py +0 -0
  38. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/context.py +0 -0
  39. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/cli/model.py +0 -0
  40. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/contexts.py +0 -0
  41. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/priorities.py +0 -0
  42. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/providers.py +0 -0
  43. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/server.py +0 -0
  44. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/config/settings.py +0 -0
  45. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/__init__.py +0 -0
  46. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/anthropic.py +0 -0
  47. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/base.py +0 -0
  48. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/copilot.py +0 -0
  49. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/openai.py +0 -0
  50. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/providers/openai_compat.py +0 -0
  51. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/routing/__init__.py +0 -0
  52. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/__init__.py +0 -0
  53. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/app.py +0 -0
  54. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/middleware/__init__.py +0 -0
  55. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/middleware/auth.py +0 -0
  56. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/oauth_sessions.py +0 -0
  57. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/__init__.py +0 -0
  58. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/anthropic.py +0 -0
  59. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/chat.py +0 -0
  60. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/routes/models.py +0 -0
  61. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/anthropic.py +0 -0
  62. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/schemas/openai.py +0 -0
  63. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/server/translation.py +0 -0
  64. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/utils/__init__.py +0 -0
  65. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/utils/logging.py +0 -0
  66. {router_maestro-0.1.2 → router_maestro-0.1.4}/src/router_maestro/utils/tokens.py +0 -0
  67. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/__init__.py +0 -0
  68. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_auth.py +0 -0
  69. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_config.py +0 -0
  70. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_providers.py +0 -0
  71. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_router.py +0 -0
  72. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_translation.py +0 -0
  73. {router_maestro-0.1.2 → router_maestro-0.1.4}/tests/test_utils.py +0 -0
@@ -0,0 +1,4 @@
1
+ {
2
+ "MD013": false,
3
+ "MD060": false
4
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: router-maestro
3
- Version: 0.1.2
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. Install
77
+ ### 1. Start the Server
78
+
79
+ #### Docker (recommended)
74
80
 
75
81
  ```bash
76
- pip install router-maestro
77
- # or
78
- uv pip install router-maestro
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
- ### 2. Start the Server
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 | Description |
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 | Behavior |
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 | Description |
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 | Description |
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 | Description |
195
- |---------|-------------|
196
- | `model list` | List available models |
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 | Description |
205
- |---------|-------------|
206
- | `context show` | Show current context |
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 | Description |
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 | Path | Contents |
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 | Auto-Reload |
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. Install
40
+ ### 1. Start the Server
41
+
42
+ #### Docker (recommended)
37
43
 
38
44
  ```bash
39
- pip install router-maestro
40
- # or
41
- uv pip install router-maestro
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
- ### 2. Start the Server
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 | Description |
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 | Behavior |
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 | Description |
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 | Description |
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 | Description |
158
- |---------|-------------|
159
- | `model list` | List available models |
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 | Description |
168
- |---------|-------------|
169
- | `context show` | Show current context |
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 | Description |
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 | Path | Contents |
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 | Auto-Reload |
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "router-maestro"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  description = "Multi-model routing and load balancing system with OpenAI-compatible API"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """Router-Maestro: Multi-model routing and load balancing system."""
2
2
 
3
- __version__ = "0.1.2"
3
+ __version__ = "0.1.4"
@@ -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(no_args_is_help=True)
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, stats # noqa: E402
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(f"[green]Server is running[/green]")
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: