python-rerouting-library 0.2.1__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 (25) hide show
  1. python_rerouting_library-0.2.1/LICENSE +21 -0
  2. python_rerouting_library-0.2.1/PKG-INFO +624 -0
  3. python_rerouting_library-0.2.1/README.md +590 -0
  4. python_rerouting_library-0.2.1/pyproject.toml +80 -0
  5. python_rerouting_library-0.2.1/setup.cfg +4 -0
  6. python_rerouting_library-0.2.1/src/python_rerouting_library/__init__.py +25 -0
  7. python_rerouting_library-0.2.1/src/python_rerouting_library/backends/__init__.py +30 -0
  8. python_rerouting_library-0.2.1/src/python_rerouting_library/backends/cloud.py +58 -0
  9. python_rerouting_library-0.2.1/src/python_rerouting_library/backends/local_llama.py +74 -0
  10. python_rerouting_library-0.2.1/src/python_rerouting_library/config.py +128 -0
  11. python_rerouting_library-0.2.1/src/python_rerouting_library/dispatcher.py +200 -0
  12. python_rerouting_library-0.2.1/src/python_rerouting_library/exceptions.py +18 -0
  13. python_rerouting_library-0.2.1/src/python_rerouting_library/privacy.py +171 -0
  14. python_rerouting_library-0.2.1/src/python_rerouting_library/router.py +227 -0
  15. python_rerouting_library-0.2.1/src/python_rerouting_library/training.py +177 -0
  16. python_rerouting_library-0.2.1/src/python_rerouting_library.egg-info/PKG-INFO +624 -0
  17. python_rerouting_library-0.2.1/src/python_rerouting_library.egg-info/SOURCES.txt +23 -0
  18. python_rerouting_library-0.2.1/src/python_rerouting_library.egg-info/dependency_links.txt +1 -0
  19. python_rerouting_library-0.2.1/src/python_rerouting_library.egg-info/requires.txt +13 -0
  20. python_rerouting_library-0.2.1/src/python_rerouting_library.egg-info/top_level.txt +1 -0
  21. python_rerouting_library-0.2.1/tests/test_classifier_artifact.py +99 -0
  22. python_rerouting_library-0.2.1/tests/test_dispatcher.py +354 -0
  23. python_rerouting_library-0.2.1/tests/test_privacy.py +134 -0
  24. python_rerouting_library-0.2.1/tests/test_router_decision.py +56 -0
  25. python_rerouting_library-0.2.1/tests/test_router_thresholds.py +88 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Deepa Patil
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,624 @@
1
+ Metadata-Version: 2.4
2
+ Name: python-rerouting-library
3
+ Version: 0.2.1
4
+ Summary: Privacy-aware semantic routing between local and cloud LLM backends
5
+ Author: Deepa793
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Deepa793/python-rerouting-library
8
+ Project-URL: Repository, https://github.com/Deepa793/python-rerouting-library
9
+ Project-URL: Issues, https://github.com/Deepa793/python-rerouting-library/issues
10
+ Keywords: llm,routing,semantic-routing,local-llm,privacy,llama,openai,machine-learning,generative-ai
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: numpy>=1.24
23
+ Requires-Dist: scikit-learn>=1.1
24
+ Requires-Dist: sentence-transformers>=3.0
25
+ Requires-Dist: joblib>=1.4
26
+ Requires-Dist: openai>=1.0
27
+ Provides-Extra: local-llama
28
+ Requires-Dist: llama-cpp-python>=0.3; extra == "local-llama"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=8; extra == "dev"
31
+ Requires-Dist: build>=1.2; extra == "dev"
32
+ Requires-Dist: twine>=6; extra == "dev"
33
+ Dynamic: license-file
34
+
35
+ # Python Rerouting Library
36
+
37
+ A lightweight Python library that routes user queries between a local Llama model and a cloud LLM using privacy rules and semantic complexity classification.
38
+
39
+ ## What Changed in v0.2.0
40
+
41
+ Version 0.2 adds a **privacy-first routing layer** in front of the semantic complexity router.
42
+
43
+ The key rule is:
44
+
45
+ > Privacy policy takes precedence over complexity routing.
46
+
47
+ If a query contains detected sensitive information, the query is routed directly to the local model and is never sent to the cloud.
48
+
49
+ ---
50
+
51
+ ## Routing Architecture
52
+
53
+ ```text
54
+ Query
55
+
56
+ Privacy Detector
57
+
58
+ Sensitive data detected?
59
+
60
+ ├── YES
61
+ │ ↓
62
+ │ privacy_override
63
+ │ ↓
64
+ │ Local Llama only
65
+ │ ↓
66
+ │ if local fails → DispatchError
67
+
68
+ │ NEVER cloud
69
+
70
+ └── NO
71
+
72
+ MiniLM Semantic Router
73
+
74
+ Logistic Regression
75
+
76
+ simple / uncertain / complex
77
+ ```
78
+
79
+ For clean queries, normal routing continues:
80
+
81
+ ```text
82
+ simple
83
+
84
+ Local Llama
85
+
86
+ if local fails → Cloud fallback
87
+
88
+ uncertain
89
+
90
+ Cloud
91
+
92
+ complex
93
+
94
+ Cloud
95
+ ```
96
+
97
+ ---
98
+
99
+ ## Privacy-First Routing
100
+
101
+ Before complexity scoring, every query is checked by `PrivacyDetector`.
102
+
103
+ The current detector looks for common patterns including:
104
+
105
+ * Email addresses
106
+ * US-style phone numbers
107
+ * Social Security numbers
108
+ * Common API-key formats
109
+ * Credit-card numbers
110
+
111
+ Credit-card candidates are additionally validated using the **Luhn checksum** to reduce false positives.
112
+
113
+ If sensitive information is detected:
114
+
115
+ ```text
116
+ Query
117
+
118
+ PrivacyDetector
119
+
120
+ privacy_override
121
+
122
+ Local Llama
123
+ ```
124
+
125
+ The MiniLM semantic router is not called.
126
+
127
+ The cloud backend is not called.
128
+
129
+ If the local backend fails:
130
+
131
+ ```text
132
+ privacy_override
133
+
134
+ Local backend failure
135
+
136
+ DispatchError
137
+ ```
138
+
139
+ There is intentionally **no cloud fallback** for privacy-sensitive queries.
140
+
141
+ The detector reports only privacy categories such as:
142
+
143
+ ```text
144
+ email
145
+ phone
146
+ ssn
147
+ api_key
148
+ credit_card
149
+ ```
150
+
151
+ It does not return the matched sensitive value.
152
+
153
+ > The privacy detector is a lightweight policy layer based on known patterns. It is not intended to replace a full Data Loss Prevention, compliance, or enterprise sensitive-data classification system.
154
+
155
+ ---
156
+
157
+ ## Semantic Router
158
+
159
+ Queries that pass the privacy check continue to the semantic router.
160
+
161
+ The router uses:
162
+
163
+ * `sentence-transformers/all-MiniLM-L6-v2`
164
+ * 384-dimensional semantic embeddings
165
+ * Logistic Regression
166
+ * Configurable uncertainty thresholds
167
+
168
+ The query is converted into an embedding and passed to the trained classifier.
169
+
170
+ The classifier produces:
171
+
172
+ ```text
173
+ P(complex)
174
+ ```
175
+
176
+ This probability is then used by the routing policy.
177
+
178
+ ---
179
+
180
+ ## Default Complexity Routing Policy
181
+
182
+ ```text
183
+ P(complex) < 0.40
184
+ → simple
185
+ → local Llama
186
+
187
+ 0.40 ≤ P(complex) ≤ 0.60
188
+ → uncertain
189
+ → cloud
190
+
191
+ P(complex) > 0.60
192
+ → complex
193
+ → cloud
194
+ ```
195
+
196
+ The thresholds are configurable.
197
+
198
+ ---
199
+
200
+ ## Routing Priority
201
+
202
+ The system now contains two routing layers:
203
+
204
+ ```text
205
+ 1. Privacy policy
206
+
207
+ 2. Complexity policy
208
+ ```
209
+
210
+ Privacy always wins.
211
+
212
+ For example, a query such as:
213
+
214
+ ```text
215
+ Design a multi-region database architecture
216
+ for alice@example.com with automatic failover.
217
+ ```
218
+
219
+ looks like a complex query.
220
+
221
+ In v0.1 it would likely be routed to the cloud.
222
+
223
+ In v0.2:
224
+
225
+ ```text
226
+ email detected
227
+
228
+ privacy_override
229
+
230
+ local only
231
+ ```
232
+
233
+ The semantic complexity classifier is not called.
234
+
235
+ ---
236
+
237
+ ## Failure Policy
238
+
239
+ ### Privacy-sensitive query
240
+
241
+ ```text
242
+ Local Llama
243
+ ↓ failure
244
+ DispatchError
245
+ ```
246
+
247
+ Cloud fallback is prohibited.
248
+
249
+ ### Clean simple query
250
+
251
+ ```text
252
+ Local Llama
253
+ ↓ failure
254
+ Cloud fallback
255
+ ```
256
+
257
+ ### Clean uncertain query
258
+
259
+ ```text
260
+ Cloud
261
+ ↓ failure
262
+ DispatchError
263
+ ```
264
+
265
+ ### Clean complex query
266
+
267
+ ```text
268
+ Cloud
269
+ ↓ failure
270
+ DispatchError
271
+ ```
272
+
273
+ Complex and uncertain queries are not silently downgraded to the local model.
274
+
275
+ ---
276
+
277
+ ## Project Structure
278
+
279
+ ```text
280
+ python-rerouting-library/
281
+ ├── src/
282
+ │ └── python_rerouting_library/
283
+ │ ├── __init__.py
284
+ │ ├── router.py
285
+ │ ├── privacy.py
286
+ │ ├── dispatcher.py
287
+ │ ├── training.py
288
+ │ ├── config.py
289
+ │ ├── exceptions.py
290
+ │ └── backends/
291
+ │ ├── __init__.py
292
+ │ ├── local_llama.py
293
+ │ └── cloud.py
294
+ ├── tests/
295
+ │ ├── test_dispatcher.py
296
+ │ ├── test_privacy.py
297
+ │ ├── test_router_decision.py
298
+ │ └── test_router_thresholds.py
299
+ ├── examples/
300
+ ├── benchmarks/
301
+ ├── pyproject.toml
302
+ ├── .env.example
303
+ ├── .gitignore
304
+ ├── LICENSE
305
+ └── README.md
306
+ ```
307
+
308
+ The generated router classifier is stored under:
309
+
310
+ ```text
311
+ artifacts/
312
+ ```
313
+
314
+ and is intentionally excluded from Git.
315
+
316
+ ---
317
+
318
+ ## Requirements
319
+
320
+ * Python 3.10+
321
+ * Router classifier artifact
322
+ * Local GGUF model for local Llama inference
323
+ * OpenAI-compatible cloud API for cloud routing
324
+
325
+ ---
326
+
327
+ ## Installation
328
+
329
+ From the project folder:
330
+
331
+ ```powershell
332
+ python -m pip install -e ".[dev]"
333
+ ```
334
+
335
+ If using the local Llama backend:
336
+
337
+ ```powershell
338
+ python -m pip install -e ".[local-llama]"
339
+ ```
340
+
341
+ `llama-cpp-python` is an optional dependency.
342
+
343
+ Cloud-only users do not need to install it.
344
+
345
+ ---
346
+
347
+ ## Configuration
348
+
349
+ The library reads runtime settings from environment variables.
350
+
351
+ Example:
352
+
353
+ ```powershell
354
+ $env:LLAMA_MODEL_PATH="C:\models\llama3.2\model.gguf"
355
+
356
+ $env:ROUTER_CLASSIFIER_PATH="artifacts\router_classifier.joblib"
357
+
358
+ $env:CLOUD_BASE_URL="https://api.openai.com/v1"
359
+ $env:CLOUD_MODEL="gpt-5.4-nano"
360
+ $env:CLOUD_API_KEY="YOUR_API_KEY"
361
+
362
+ $env:LOCAL_MAX_TOKENS="128"
363
+ $env:CLOUD_MAX_TOKENS="256"
364
+
365
+ $env:ROUTER_SIMPLE_THRESHOLD="0.40"
366
+ $env:ROUTER_COMPLEX_THRESHOLD="0.60"
367
+ ```
368
+
369
+ See `.env.example` for the available settings.
370
+
371
+ Never commit real API keys or credentials.
372
+
373
+ ---
374
+
375
+ ## Classifier Artifact
376
+
377
+ The package does not ship with a default production complexity classifier.
378
+
379
+ Complexity classification is workload-dependent. What should be considered a simple or complex query can vary depending on:
380
+
381
+ - the local model being used
382
+ - the cloud model being used
383
+ - application domain
384
+ - latency requirements
385
+ - cost policy
386
+ - desired routing behavior
387
+
388
+ Users should therefore train or provide a compatible classifier artifact.
389
+
390
+ When using `Router` directly:
391
+
392
+ ```python
393
+ from python_rerouting_library import Router
394
+
395
+ router = Router(
396
+ classifier_path="path/to/router_classifier.joblib"
397
+ )
398
+
399
+ ## Train the Router
400
+
401
+ The current example training dataset is:
402
+
403
+ ```text
404
+ benchmarks/router_queries_50.csv
405
+ ```
406
+
407
+ Train and save the classifier with:
408
+
409
+ ```powershell
410
+ python -m python_rerouting_library.training `
411
+ --csv benchmarks\router_queries_50.csv `
412
+ --output artifacts\router_classifier.joblib
413
+ ```
414
+
415
+ The training pipeline uses MiniLM embeddings and Logistic Regression.
416
+
417
+ The router thresholds are runtime routing policy and are not stored as a training-time decision threshold.
418
+
419
+ ---
420
+
421
+ ## Run the Full Example
422
+
423
+ After configuring the environment and training the router:
424
+
425
+ ```powershell
426
+ python .\examples\test_full_dispatcher.py
427
+ ```
428
+
429
+ A clean simple query should normally route to:
430
+
431
+ ```text
432
+ Backend: local-llama
433
+ ```
434
+
435
+ A clean complex query should normally route to:
436
+
437
+ ```text
438
+ Backend: cloud-api
439
+ ```
440
+
441
+ A detected privacy-sensitive query should route to:
442
+
443
+ ```text
444
+ Route: privacy_override
445
+ Backend: local-llama
446
+ ```
447
+
448
+ ---
449
+
450
+ ## Run Tests
451
+
452
+ ```powershell
453
+ python -m pytest -v
454
+ ```
455
+
456
+ Current v0.2 regression suite:
457
+
458
+ ```text
459
+ 26 passed
460
+ ```
461
+
462
+ The tests cover:
463
+
464
+ * simple → local
465
+ * complex → cloud
466
+ * uncertain → cloud
467
+ * clean simple local failure → cloud fallback
468
+ * cloud failure handling
469
+ * uncertainty threshold boundaries
470
+ * structured route decisions
471
+ * email detection
472
+ * phone-number detection
473
+ * SSN detection
474
+ * API-key detection
475
+ * credit-card detection
476
+ * Luhn validation
477
+ * multiple privacy categories
478
+ * privacy override before semantic routing
479
+ * verification that privacy queries do not call the router
480
+ * verification that privacy queries do not fall back to cloud
481
+
482
+ The automated unit tests do not call the OpenAI API.
483
+
484
+ ---
485
+
486
+ ## Route Decision Behavior
487
+
488
+ Normal semantic routes contain complexity information:
489
+
490
+ ```text
491
+ label
492
+ confidence
493
+ complex_probability
494
+ latency_ms
495
+ ```
496
+
497
+ For a privacy override:
498
+
499
+ ```text
500
+ label = privacy_override
501
+ confidence = None
502
+ complex_probability = None
503
+ ```
504
+
505
+ This is intentional.
506
+
507
+ The complexity classifier never ran, so the library does not invent a complexity probability.
508
+
509
+ ---
510
+
511
+ ## Privacy Override Example
512
+
513
+ Conceptually:
514
+
515
+ ```python
516
+ result = dispatcher.run(
517
+ "Please review account details for alice@example.com"
518
+ )
519
+
520
+ print(result.route.label)
521
+ print(result.backend_name)
522
+ print(result.privacy_categories)
523
+ ```
524
+
525
+ Expected behavior:
526
+
527
+ ```text
528
+ privacy_override
529
+ local-llama
530
+ ('email',)
531
+ ```
532
+
533
+ The query is not sent to the cloud.
534
+
535
+ ---
536
+
537
+ ## Version History
538
+
539
+ ### v0.2.0
540
+
541
+ Adds:
542
+
543
+ * Privacy-first routing
544
+ * `PrivacyDetector`
545
+ * `PrivacyDecision`
546
+ * `privacy_override`
547
+ * Local-only processing for detected sensitive data
548
+ * No cloud fallback for privacy-sensitive queries
549
+ * Email detection
550
+ * Phone-number detection
551
+ * SSN detection
552
+ * API-key pattern detection
553
+ * Credit-card detection with Luhn validation
554
+ * Privacy-category observability
555
+ * Expanded regression tests
556
+
557
+ ### v0.1.0
558
+
559
+ Introduced:
560
+
561
+ * MiniLM semantic query embeddings
562
+ * Logistic Regression complexity classifier
563
+ * Simple / uncertain / complex routing
564
+ * Local Llama backend
565
+ * Cloud LLM backend
566
+ * Local-to-cloud fallback for simple queries
567
+ * Custom backend exceptions
568
+ * Centralized configuration
569
+ * Automated regression tests
570
+
571
+ ---
572
+
573
+ ## Design Principle
574
+
575
+ The library separates three concerns:
576
+
577
+ ```text
578
+ Policy
579
+
580
+ Routing
581
+
582
+ Execution
583
+ ```
584
+
585
+ In v0.2:
586
+
587
+ ```text
588
+ Privacy Detector
589
+
590
+ Semantic Router
591
+
592
+ Dispatcher
593
+
594
+ Local / Cloud Backend
595
+ ```
596
+
597
+ This means model-selection optimization happens only after the privacy policy allows the query to continue through the normal routing pipeline.
598
+
599
+ ---
600
+
601
+ ## Current Limitations
602
+
603
+ The current privacy detector is intentionally lightweight.
604
+
605
+ It does not yet provide:
606
+
607
+ * Named-entity recognition
608
+ * Address detection
609
+ * Medical-record detection
610
+ * International identity-number detection
611
+ * Context-aware secret detection
612
+ * Configurable privacy policies
613
+ * User-defined sensitive-data patterns
614
+ * Enterprise DLP integration
615
+
616
+ These are possible future extensions.
617
+
618
+ ---
619
+
620
+ ## License
621
+
622
+ This project is licensed under the MIT License.
623
+
624
+ See the `LICENSE` file for details.