query-oracle 0.3.0__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.
- query_oracle-0.3.0/LICENSE +21 -0
- query_oracle-0.3.0/PKG-INFO +299 -0
- query_oracle-0.3.0/README.md +253 -0
- query_oracle-0.3.0/pyproject.toml +55 -0
- query_oracle-0.3.0/setup.cfg +4 -0
- query_oracle-0.3.0/src/llm_router/__init__.py +14 -0
- query_oracle-0.3.0/src/llm_router/classifier.py +301 -0
- query_oracle-0.3.0/src/llm_router/mcp_server.py +103 -0
- query_oracle-0.3.0/src/llm_router/models.py +159 -0
- query_oracle-0.3.0/src/llm_router/providers/__init__.py +9 -0
- query_oracle-0.3.0/src/llm_router/providers/anthropic_provider.py +50 -0
- query_oracle-0.3.0/src/llm_router/providers/base.py +24 -0
- query_oracle-0.3.0/src/llm_router/providers/gemini_provider.py +53 -0
- query_oracle-0.3.0/src/llm_router/providers/openai_provider.py +55 -0
- query_oracle-0.3.0/src/llm_router/router.py +77 -0
- query_oracle-0.3.0/src/query_oracle.egg-info/PKG-INFO +299 -0
- query_oracle-0.3.0/src/query_oracle.egg-info/SOURCES.txt +21 -0
- query_oracle-0.3.0/src/query_oracle.egg-info/dependency_links.txt +1 -0
- query_oracle-0.3.0/src/query_oracle.egg-info/entry_points.txt +2 -0
- query_oracle-0.3.0/src/query_oracle.egg-info/requires.txt +26 -0
- query_oracle-0.3.0/src/query_oracle.egg-info/top_level.txt +1 -0
- query_oracle-0.3.0/tests/test_classifier.py +147 -0
- query_oracle-0.3.0/tests/test_router.py +134 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Heman Phadvas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: query-oracle
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Automatic LLM model and effort-level routing based on query classification.
|
|
5
|
+
Author-email: Heman Phadvas <tailung.hp@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hemanpadvas2002/query-oracle
|
|
8
|
+
Project-URL: Repository, https://github.com/hemanpadvas2002/query-oracle
|
|
9
|
+
Project-URL: Issues, https://github.com/hemanpadvas2002/query-oracle/issues
|
|
10
|
+
Project-URL: Live API, https://query-oracle-production.up.railway.app
|
|
11
|
+
Keywords: llm,routing,anthropic,openai,gemini,claude,mcp,model-selection,cost-optimization
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Operating System :: OS Independent
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: anthropic>=0.40.0
|
|
26
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
27
|
+
Provides-Extra: server
|
|
28
|
+
Requires-Dist: fastapi>=0.110.0; extra == "server"
|
|
29
|
+
Requires-Dist: uvicorn[standard]>=0.27.0; extra == "server"
|
|
30
|
+
Provides-Extra: mcp
|
|
31
|
+
Requires-Dist: mcp<2.0.0,>=1.0.0; extra == "mcp"
|
|
32
|
+
Provides-Extra: openai
|
|
33
|
+
Requires-Dist: openai>=1.30.0; extra == "openai"
|
|
34
|
+
Provides-Extra: gemini
|
|
35
|
+
Requires-Dist: google-generativeai>=0.7.0; extra == "gemini"
|
|
36
|
+
Provides-Extra: train
|
|
37
|
+
Requires-Dist: transformers>=4.40.0; extra == "train"
|
|
38
|
+
Requires-Dist: datasets>=2.19.0; extra == "train"
|
|
39
|
+
Requires-Dist: torch>=2.2.0; extra == "train"
|
|
40
|
+
Requires-Dist: scikit-learn>=1.4.0; extra == "train"
|
|
41
|
+
Requires-Dist: optimum>=1.19.0; extra == "train"
|
|
42
|
+
Requires-Dist: onnxruntime>=1.17.0; extra == "train"
|
|
43
|
+
Provides-Extra: all
|
|
44
|
+
Requires-Dist: query-oracle[gemini,mcp,openai,server]; extra == "all"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# query-oracle
|
|
48
|
+
|
|
49
|
+
> Automatic LLM routing — the right model, the right effort, zero manual selection.
|
|
50
|
+
|
|
51
|
+
[](https://github.com/hemanpadvas2002/query-oracle/actions/workflows/ci.yml)
|
|
52
|
+
[](https://query-oracle-production.up.railway.app/health)
|
|
53
|
+
[](https://www.python.org/)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Live demo
|
|
58
|
+
|
|
59
|
+
> **Illustrative** — actual output will vary by provider, model, and query.
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
from llm_router import QueryRouter
|
|
63
|
+
|
|
64
|
+
r = QueryRouter().route("Design a fault-tolerant event streaming architecture.")
|
|
65
|
+
print(f"tier={r.tier.value} model={r.model_used} thinking={r.extended_thinking_used}")
|
|
66
|
+
print(f"cost=${r.cost_usd:.5f} total=${r.total_cost_usd:.5f} latency={r.latency_ms:.0f}ms")
|
|
67
|
+
print(r.classification.reasoning)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## What it does
|
|
73
|
+
|
|
74
|
+
query-oracle sits in front of your LLM calls and automatically decides which model deserves the query. Factual lookups go to Haiku or GPT-4o-mini in under a second; open-ended design problems get routed to Opus with extended thinking or o1 with high reasoning effort. The classification itself costs a fraction of a cent and the routing decision is logged so you can fine-tune a local DistilBERT classifier later — eventually dropping the classification API cost to zero.
|
|
75
|
+
|
|
76
|
+
It ships as a Python library, a live REST API, a Claude Code MCP plugin, a VS Code / Cursor extension, an OpenAI Custom GPT Action, and a reusable GitHub Actions workflow. Pick whichever integration fits your stack.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Quick install — pick your platform
|
|
81
|
+
|
|
82
|
+
### Python library
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install "query-oracle"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
With optional extras:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install "query-oracle[server]" # FastAPI REST server
|
|
92
|
+
pip install "query-oracle[mcp]" # Claude Code / Desktop MCP plugin
|
|
93
|
+
pip install "query-oracle[openai]" # OpenAI provider
|
|
94
|
+
pip install "query-oracle[gemini]" # Gemini provider
|
|
95
|
+
pip install "query-oracle[all]" # everything
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Claude Code / Claude Desktop (MCP)
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install "query-oracle[mcp]"
|
|
102
|
+
claude mcp add query-oracle -- query-oracle-mcp
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Then in any Claude conversation:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
route "Design a real-time fraud detection pipeline."
|
|
109
|
+
classify "What is the capital of France?"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Or add to `~/.claude/claude_desktop_config.json` manually:
|
|
113
|
+
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"mcpServers": {
|
|
117
|
+
"query-oracle": {
|
|
118
|
+
"command": "query-oracle-mcp",
|
|
119
|
+
"env": { "ANTHROPIC_API_KEY": "sk-ant-..." }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### ChatGPT — Custom GPT Action
|
|
128
|
+
|
|
129
|
+
Paste this URL into **GPT builder → Configure → Actions → Import from URL**:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
https://query-oracle-production.up.railway.app/openapi.json
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The server is live — no setup required. See [`openai-plugin/README.md`](openai-plugin/README.md) for how to self-host and add authentication.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Cursor / VS Code Extension
|
|
140
|
+
|
|
141
|
+
The extension starts the REST server automatically — no manual uvicorn command.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cd vscode-extension
|
|
145
|
+
npm install
|
|
146
|
+
npm run package # → query-oracle-1.0.0.vsix
|
|
147
|
+
code --install-extension query-oracle-1.0.0.vsix
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Press `Cmd/Ctrl+Shift+L` to open the query input. Responses appear in the **LLM Query Router** output panel with tier, model, latency, and cost.
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
### GitHub Copilot / Codex
|
|
155
|
+
|
|
156
|
+
Copy `.github/copilot-instructions.md` into your own repo's `.github/` folder. Copilot will read it automatically in VS Code and JetBrains and stop suggesting hard-coded model names.
|
|
157
|
+
|
|
158
|
+
For GitHub Actions / Copilot Workspace tasks:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
jobs:
|
|
162
|
+
design:
|
|
163
|
+
uses: hemanpadvas2002/query-oracle/.github/workflows/copilot-router.yml@main
|
|
164
|
+
with:
|
|
165
|
+
query: "Design a zero-downtime database migration strategy."
|
|
166
|
+
secrets:
|
|
167
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
168
|
+
# outputs: response, tier, model_used, cost_usd
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## How routing works
|
|
174
|
+
|
|
175
|
+
| Tier | When | Anthropic | OpenAI | Gemini |
|
|
176
|
+
|---|---|---|---|---|
|
|
177
|
+
| `fast` | Factual lookups, maths, news, nutrition | claude-haiku-4-5 | gpt-4o-mini | gemini-1.5-flash |
|
|
178
|
+
| `balanced` | Analysis, explanations, moderate reasoning | claude-sonnet-4-5 | gpt-4o | gemini-1.5-pro |
|
|
179
|
+
| `deep` | Strategy, design, ethics, complex ideation | claude-opus-4-5 + thinking | o1 (high) | gemini-2.0-flash-thinking |
|
|
180
|
+
|
|
181
|
+
The classifier sends the query to a small model (Haiku by default) with a structured prompt that returns `tier`, `effort`, `facts_ratio`, `judgment_ratio`, `confidence`, and a one-sentence `reasoning`. Every result is logged to `logs/classifications.jsonl` — this passively builds the labelled dataset for local DistilBERT fine-tuning.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Response fields
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
RouterResponse(
|
|
189
|
+
content = "...",
|
|
190
|
+
tier = QueryTier.DEEP,
|
|
191
|
+
effort = EffortLevel.HIGH,
|
|
192
|
+
provider = ProviderType.ANTHROPIC,
|
|
193
|
+
model_used = "claude-opus-4-5",
|
|
194
|
+
extended_thinking_used = True,
|
|
195
|
+
input_tokens = 312,
|
|
196
|
+
output_tokens = 891,
|
|
197
|
+
latency_ms = 3241.4,
|
|
198
|
+
cost_usd = 0.02184, # completion cost only
|
|
199
|
+
total_cost_usd = 0.02188, # completion + classifier cost
|
|
200
|
+
classification = ClassificationResult(
|
|
201
|
+
tier = QueryTier.DEEP,
|
|
202
|
+
effort = EffortLevel.HIGH,
|
|
203
|
+
facts_ratio = 0.12,
|
|
204
|
+
judgment_ratio = 0.88,
|
|
205
|
+
confidence = 0.94,
|
|
206
|
+
reasoning = "Complex distributed systems design — strategy tier warranted",
|
|
207
|
+
classifier_input_tokens = 85,
|
|
208
|
+
classifier_output_tokens = 47,
|
|
209
|
+
classifier_cost_usd = 0.0000456,
|
|
210
|
+
),
|
|
211
|
+
)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Live REST API
|
|
217
|
+
|
|
218
|
+
**Base URL:** `https://query-oracle-production.up.railway.app`
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
# Health check (no auth required)
|
|
222
|
+
curl https://query-oracle-production.up.railway.app/health
|
|
223
|
+
# {"status":"ok"}
|
|
224
|
+
|
|
225
|
+
# Classify only (auth required when QUERY_ORACLE_API_KEY is set)
|
|
226
|
+
curl -s -X POST https://query-oracle-production.up.railway.app/classify \
|
|
227
|
+
-H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
|
|
228
|
+
-H "Content-Type: application/json" \
|
|
229
|
+
-d '{"query": "How many calories in a banana?"}' | jq .
|
|
230
|
+
|
|
231
|
+
# Route and get a full response
|
|
232
|
+
curl -s -X POST https://query-oracle-production.up.railway.app/route \
|
|
233
|
+
-H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
|
|
234
|
+
-H "Content-Type: application/json" \
|
|
235
|
+
-d '{"query": "Explain backpressure in reactive systems.", "provider": "anthropic"}' \
|
|
236
|
+
| jq '{tier, model_used, cost_usd, total_cost_usd, latency_ms}'
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Interactive docs: [`/docs`](https://query-oracle-production.up.railway.app/docs)
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Securing your deployment
|
|
244
|
+
|
|
245
|
+
By default the server runs in open mode (dev-only). Before exposing it publicly:
|
|
246
|
+
|
|
247
|
+
**1. Set an API key**
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
export QUERY_ORACLE_API_KEY="your-secret-key"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
All requests to `/route` and `/classify` then require:
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
Authorization: Bearer your-secret-key
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The `/health` endpoint stays open. The server logs a warning at startup if no key is set.
|
|
260
|
+
|
|
261
|
+
**2. Restrict CORS origins**
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
export CORS_ORIGINS="https://yourdomain.com,https://app.yourdomain.com"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
When unset, CORS defaults to `*` (any origin). Set it to your specific domains in production.
|
|
268
|
+
|
|
269
|
+
**3. Rate limiting**
|
|
270
|
+
|
|
271
|
+
The `/route` endpoint enforces 30 requests per minute per client IP in-process. For heavier traffic, put an API gateway (e.g. Nginx, Cloudflare, Railway gateway) in front.
|
|
272
|
+
|
|
273
|
+
**Railway environment variables:**
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
QUERY_ORACLE_API_KEY → your secret key
|
|
277
|
+
ANTHROPIC_API_KEY → sk-ant-...
|
|
278
|
+
OPENAI_API_KEY → sk-... (optional)
|
|
279
|
+
GEMINI_API_KEY → AIza... (optional)
|
|
280
|
+
CORS_ORIGINS → https://yourdomain.com
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Train your own classifier (coming soon)
|
|
286
|
+
|
|
287
|
+
Once `logs/classifications.jsonl` accumulates ~500 entries, run `python training/train.py --data training/data/queries.csv` to fine-tune a local DistilBERT model. Swap it in with `QueryRouter(classifier=DistilBERTClassifier("training/query-classifier-final"))` and classification drops to ~10 ms with zero API cost.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Contributing
|
|
292
|
+
|
|
293
|
+
Open an issue or PR — the codebase is intentionally small. Adding a new provider means subclassing `BaseProvider` and implementing one method; the routing logic, classifier, and all integrations stay unchanged.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Licence
|
|
298
|
+
|
|
299
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# query-oracle
|
|
2
|
+
|
|
3
|
+
> Automatic LLM routing — the right model, the right effort, zero manual selection.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/hemanpadvas2002/query-oracle/actions/workflows/ci.yml)
|
|
6
|
+
[](https://query-oracle-production.up.railway.app/health)
|
|
7
|
+
[](https://www.python.org/)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Live demo
|
|
12
|
+
|
|
13
|
+
> **Illustrative** — actual output will vary by provider, model, and query.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from llm_router import QueryRouter
|
|
17
|
+
|
|
18
|
+
r = QueryRouter().route("Design a fault-tolerant event streaming architecture.")
|
|
19
|
+
print(f"tier={r.tier.value} model={r.model_used} thinking={r.extended_thinking_used}")
|
|
20
|
+
print(f"cost=${r.cost_usd:.5f} total=${r.total_cost_usd:.5f} latency={r.latency_ms:.0f}ms")
|
|
21
|
+
print(r.classification.reasoning)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## What it does
|
|
27
|
+
|
|
28
|
+
query-oracle sits in front of your LLM calls and automatically decides which model deserves the query. Factual lookups go to Haiku or GPT-4o-mini in under a second; open-ended design problems get routed to Opus with extended thinking or o1 with high reasoning effort. The classification itself costs a fraction of a cent and the routing decision is logged so you can fine-tune a local DistilBERT classifier later — eventually dropping the classification API cost to zero.
|
|
29
|
+
|
|
30
|
+
It ships as a Python library, a live REST API, a Claude Code MCP plugin, a VS Code / Cursor extension, an OpenAI Custom GPT Action, and a reusable GitHub Actions workflow. Pick whichever integration fits your stack.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Quick install — pick your platform
|
|
35
|
+
|
|
36
|
+
### Python library
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install "query-oracle"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
With optional extras:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install "query-oracle[server]" # FastAPI REST server
|
|
46
|
+
pip install "query-oracle[mcp]" # Claude Code / Desktop MCP plugin
|
|
47
|
+
pip install "query-oracle[openai]" # OpenAI provider
|
|
48
|
+
pip install "query-oracle[gemini]" # Gemini provider
|
|
49
|
+
pip install "query-oracle[all]" # everything
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Claude Code / Claude Desktop (MCP)
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install "query-oracle[mcp]"
|
|
56
|
+
claude mcp add query-oracle -- query-oracle-mcp
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Then in any Claude conversation:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
route "Design a real-time fraud detection pipeline."
|
|
63
|
+
classify "What is the capital of France?"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Or add to `~/.claude/claude_desktop_config.json` manually:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"mcpServers": {
|
|
71
|
+
"query-oracle": {
|
|
72
|
+
"command": "query-oracle-mcp",
|
|
73
|
+
"env": { "ANTHROPIC_API_KEY": "sk-ant-..." }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### ChatGPT — Custom GPT Action
|
|
82
|
+
|
|
83
|
+
Paste this URL into **GPT builder → Configure → Actions → Import from URL**:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
https://query-oracle-production.up.railway.app/openapi.json
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The server is live — no setup required. See [`openai-plugin/README.md`](openai-plugin/README.md) for how to self-host and add authentication.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### Cursor / VS Code Extension
|
|
94
|
+
|
|
95
|
+
The extension starts the REST server automatically — no manual uvicorn command.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cd vscode-extension
|
|
99
|
+
npm install
|
|
100
|
+
npm run package # → query-oracle-1.0.0.vsix
|
|
101
|
+
code --install-extension query-oracle-1.0.0.vsix
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Press `Cmd/Ctrl+Shift+L` to open the query input. Responses appear in the **LLM Query Router** output panel with tier, model, latency, and cost.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### GitHub Copilot / Codex
|
|
109
|
+
|
|
110
|
+
Copy `.github/copilot-instructions.md` into your own repo's `.github/` folder. Copilot will read it automatically in VS Code and JetBrains and stop suggesting hard-coded model names.
|
|
111
|
+
|
|
112
|
+
For GitHub Actions / Copilot Workspace tasks:
|
|
113
|
+
|
|
114
|
+
```yaml
|
|
115
|
+
jobs:
|
|
116
|
+
design:
|
|
117
|
+
uses: hemanpadvas2002/query-oracle/.github/workflows/copilot-router.yml@main
|
|
118
|
+
with:
|
|
119
|
+
query: "Design a zero-downtime database migration strategy."
|
|
120
|
+
secrets:
|
|
121
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
122
|
+
# outputs: response, tier, model_used, cost_usd
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## How routing works
|
|
128
|
+
|
|
129
|
+
| Tier | When | Anthropic | OpenAI | Gemini |
|
|
130
|
+
|---|---|---|---|---|
|
|
131
|
+
| `fast` | Factual lookups, maths, news, nutrition | claude-haiku-4-5 | gpt-4o-mini | gemini-1.5-flash |
|
|
132
|
+
| `balanced` | Analysis, explanations, moderate reasoning | claude-sonnet-4-5 | gpt-4o | gemini-1.5-pro |
|
|
133
|
+
| `deep` | Strategy, design, ethics, complex ideation | claude-opus-4-5 + thinking | o1 (high) | gemini-2.0-flash-thinking |
|
|
134
|
+
|
|
135
|
+
The classifier sends the query to a small model (Haiku by default) with a structured prompt that returns `tier`, `effort`, `facts_ratio`, `judgment_ratio`, `confidence`, and a one-sentence `reasoning`. Every result is logged to `logs/classifications.jsonl` — this passively builds the labelled dataset for local DistilBERT fine-tuning.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Response fields
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
RouterResponse(
|
|
143
|
+
content = "...",
|
|
144
|
+
tier = QueryTier.DEEP,
|
|
145
|
+
effort = EffortLevel.HIGH,
|
|
146
|
+
provider = ProviderType.ANTHROPIC,
|
|
147
|
+
model_used = "claude-opus-4-5",
|
|
148
|
+
extended_thinking_used = True,
|
|
149
|
+
input_tokens = 312,
|
|
150
|
+
output_tokens = 891,
|
|
151
|
+
latency_ms = 3241.4,
|
|
152
|
+
cost_usd = 0.02184, # completion cost only
|
|
153
|
+
total_cost_usd = 0.02188, # completion + classifier cost
|
|
154
|
+
classification = ClassificationResult(
|
|
155
|
+
tier = QueryTier.DEEP,
|
|
156
|
+
effort = EffortLevel.HIGH,
|
|
157
|
+
facts_ratio = 0.12,
|
|
158
|
+
judgment_ratio = 0.88,
|
|
159
|
+
confidence = 0.94,
|
|
160
|
+
reasoning = "Complex distributed systems design — strategy tier warranted",
|
|
161
|
+
classifier_input_tokens = 85,
|
|
162
|
+
classifier_output_tokens = 47,
|
|
163
|
+
classifier_cost_usd = 0.0000456,
|
|
164
|
+
),
|
|
165
|
+
)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Live REST API
|
|
171
|
+
|
|
172
|
+
**Base URL:** `https://query-oracle-production.up.railway.app`
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
# Health check (no auth required)
|
|
176
|
+
curl https://query-oracle-production.up.railway.app/health
|
|
177
|
+
# {"status":"ok"}
|
|
178
|
+
|
|
179
|
+
# Classify only (auth required when QUERY_ORACLE_API_KEY is set)
|
|
180
|
+
curl -s -X POST https://query-oracle-production.up.railway.app/classify \
|
|
181
|
+
-H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
|
|
182
|
+
-H "Content-Type: application/json" \
|
|
183
|
+
-d '{"query": "How many calories in a banana?"}' | jq .
|
|
184
|
+
|
|
185
|
+
# Route and get a full response
|
|
186
|
+
curl -s -X POST https://query-oracle-production.up.railway.app/route \
|
|
187
|
+
-H "Authorization: Bearer $QUERY_ORACLE_API_KEY" \
|
|
188
|
+
-H "Content-Type: application/json" \
|
|
189
|
+
-d '{"query": "Explain backpressure in reactive systems.", "provider": "anthropic"}' \
|
|
190
|
+
| jq '{tier, model_used, cost_usd, total_cost_usd, latency_ms}'
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Interactive docs: [`/docs`](https://query-oracle-production.up.railway.app/docs)
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Securing your deployment
|
|
198
|
+
|
|
199
|
+
By default the server runs in open mode (dev-only). Before exposing it publicly:
|
|
200
|
+
|
|
201
|
+
**1. Set an API key**
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
export QUERY_ORACLE_API_KEY="your-secret-key"
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
All requests to `/route` and `/classify` then require:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
Authorization: Bearer your-secret-key
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The `/health` endpoint stays open. The server logs a warning at startup if no key is set.
|
|
214
|
+
|
|
215
|
+
**2. Restrict CORS origins**
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
export CORS_ORIGINS="https://yourdomain.com,https://app.yourdomain.com"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
When unset, CORS defaults to `*` (any origin). Set it to your specific domains in production.
|
|
222
|
+
|
|
223
|
+
**3. Rate limiting**
|
|
224
|
+
|
|
225
|
+
The `/route` endpoint enforces 30 requests per minute per client IP in-process. For heavier traffic, put an API gateway (e.g. Nginx, Cloudflare, Railway gateway) in front.
|
|
226
|
+
|
|
227
|
+
**Railway environment variables:**
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
QUERY_ORACLE_API_KEY → your secret key
|
|
231
|
+
ANTHROPIC_API_KEY → sk-ant-...
|
|
232
|
+
OPENAI_API_KEY → sk-... (optional)
|
|
233
|
+
GEMINI_API_KEY → AIza... (optional)
|
|
234
|
+
CORS_ORIGINS → https://yourdomain.com
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Train your own classifier (coming soon)
|
|
240
|
+
|
|
241
|
+
Once `logs/classifications.jsonl` accumulates ~500 entries, run `python training/train.py --data training/data/queries.csv` to fine-tune a local DistilBERT model. Swap it in with `QueryRouter(classifier=DistilBERTClassifier("training/query-classifier-final"))` and classification drops to ~10 ms with zero API cost.
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Contributing
|
|
246
|
+
|
|
247
|
+
Open an issue or PR — the codebase is intentionally small. Adding a new provider means subclassing `BaseProvider` and implementing one method; the routing logic, classifier, and all integrations stay unchanged.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Licence
|
|
252
|
+
|
|
253
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=45", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "query-oracle"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Automatic LLM model and effort-level routing based on query classification."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Heman Phadvas", email = "tailung.hp@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = [
|
|
16
|
+
"llm", "routing", "anthropic", "openai", "gemini", "claude",
|
|
17
|
+
"mcp", "model-selection", "cost-optimization",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
28
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
29
|
+
"Operating System :: OS Independent",
|
|
30
|
+
]
|
|
31
|
+
dependencies = [
|
|
32
|
+
"anthropic>=0.40.0",
|
|
33
|
+
"python-dotenv>=1.0.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/hemanpadvas2002/query-oracle"
|
|
38
|
+
Repository = "https://github.com/hemanpadvas2002/query-oracle"
|
|
39
|
+
Issues = "https://github.com/hemanpadvas2002/query-oracle/issues"
|
|
40
|
+
"Live API" = "https://query-oracle-production.up.railway.app"
|
|
41
|
+
|
|
42
|
+
[project.optional-dependencies]
|
|
43
|
+
server = ["fastapi>=0.110.0", "uvicorn[standard]>=0.27.0"]
|
|
44
|
+
mcp = ["mcp>=1.0.0,<2.0.0"]
|
|
45
|
+
openai = ["openai>=1.30.0"]
|
|
46
|
+
gemini = ["google-generativeai>=0.7.0"]
|
|
47
|
+
train = ["transformers>=4.40.0", "datasets>=2.19.0", "torch>=2.2.0",
|
|
48
|
+
"scikit-learn>=1.4.0", "optimum>=1.19.0", "onnxruntime>=1.17.0"]
|
|
49
|
+
all = ["query-oracle[server,mcp,openai,gemini]"]
|
|
50
|
+
|
|
51
|
+
[project.scripts]
|
|
52
|
+
query-oracle-mcp = "llm_router.mcp_server:main"
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.packages.find]
|
|
55
|
+
where = ["src"]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .models import (
|
|
2
|
+
ClassificationResult, EffortLevel, ProviderType,
|
|
3
|
+
QueryTier, RouterConfig, RouterResponse,
|
|
4
|
+
MODEL_PRICING, estimate_cost,
|
|
5
|
+
)
|
|
6
|
+
from .router import QueryRouter
|
|
7
|
+
from .classifier import PromptClassifier, DistilBERTClassifier
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"QueryRouter", "RouterConfig", "RouterResponse",
|
|
11
|
+
"ClassificationResult", "QueryTier", "EffortLevel", "ProviderType",
|
|
12
|
+
"PromptClassifier", "DistilBERTClassifier",
|
|
13
|
+
"MODEL_PRICING", "estimate_cost",
|
|
14
|
+
]
|