pyinferencemanager 1.0.0__tar.gz → 1.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.
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/Cargo.lock +87 -2
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/Cargo.toml +1 -1
- pyinferencemanager-1.3.0/LICENSE +22 -0
- pyinferencemanager-1.3.0/PKG-INFO +162 -0
- pyinferencemanager-1.3.0/README.md +127 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/Cargo.toml +2 -0
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/backends/gemini_backend.rs +86 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/backends/mod.rs +12 -1
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/backends/stub_backend.rs +9 -19
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/backends/vllm_backend.rs +155 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/engines/cloud_client.rs +84 -8
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/engines/gemini_client.rs +250 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/engines/mod.rs +4 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/engines/ollama_client.rs +87 -1
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/engines/openai_client.rs +83 -8
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/engines/provider_health.rs +483 -0
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/engines/vllm_client.rs +347 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/error.rs +3 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/optimizer/budget_enforcer.rs +56 -10
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/optimizer/dynamic_router.rs +57 -6
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/optimizer/retry_strategy.rs +26 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/orchestrator/api_executor.rs +9 -7
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/orchestrator/mod.rs +841 -0
- pyinferencemanager-1.3.0/crates/pyinferencemanager-core/src/orchestrator/provider_executor.rs +267 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/orchestrator/provider_load_test.rs +1 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/orchestrator/real_load_tester.rs +1 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/router/multi_provider.rs +4 -1
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/config.rs +5 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/dag.rs +64 -2
- pyinferencemanager-1.3.0/crates/pyinferencemanager-py/src/lib.rs +566 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/pyproject.toml +16 -2
- pyinferencemanager-1.3.0/src/pyinferencemanager/__init__.py +172 -0
- pyinferencemanager-1.3.0/src/pyinferencemanager/_mcp_connector.py +189 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0/src}/pyinferencemanager/_mcp_tools.py +216 -57
- pyinferencemanager-1.3.0/src/pyinferencemanager/py.typed +0 -0
- pyinferencemanager-1.0.0/PKG-INFO +0 -178
- pyinferencemanager-1.0.0/README.md +0 -142
- pyinferencemanager-1.0.0/crates/pyinferencemanager-core/src/engines/provider_health.rs +0 -303
- pyinferencemanager-1.0.0/crates/pyinferencemanager-core/src/orchestrator/mod.rs +0 -433
- pyinferencemanager-1.0.0/crates/pyinferencemanager-core/src/orchestrator/provider_executor.rs +0 -135
- pyinferencemanager-1.0.0/crates/pyinferencemanager-py/src/lib.rs +0 -381
- pyinferencemanager-1.0.0/pyinferencemanager/_mcp_connector.py +0 -105
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/analyzer/classifier.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/analyzer/complexity.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/analyzer/embedding_complexity.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/analyzer/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/backends/anthropic_backend.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/backends/colibri_backend.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/backends/ollama_backend.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/backends/openai_backend.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/cache/embedding_key.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/cache/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/cache/semantic_cache.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/cache/sqlite_store.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/error_classifier.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/hardware/memory_map.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/hardware/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/hardware/ollama_probe.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/hardware/profiler.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/lib.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/memory/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/memory/resource_monitor.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/exporters/jaeger_exporter.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/exporters/logging_exporter.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/exporters/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/exporters/prometheus_exporter.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/logging.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/metrics.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/observability/tracer.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/optimizer/cost_estimator.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/optimizer/cost_tracker.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/optimizer/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/orchestrator/executor.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/orchestrator/load_tester.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/orchestrator/scenarios.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/planner/dag_builder.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/planner/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/planner/parallel.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/planner/templates.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/router/execution_router.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/router/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/cache.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/hardware.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/mod.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/plan.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-core/src/types/task.rs +0 -0
- {pyinferencemanager-1.0.0 → pyinferencemanager-1.3.0}/crates/pyinferencemanager-py/Cargo.toml +0 -0
|
@@ -26,6 +26,16 @@ version = "1.0.104"
|
|
|
26
26
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
27
27
|
checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470"
|
|
28
28
|
|
|
29
|
+
[[package]]
|
|
30
|
+
name = "assert-json-diff"
|
|
31
|
+
version = "2.0.2"
|
|
32
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
33
|
+
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
|
|
34
|
+
dependencies = [
|
|
35
|
+
"serde",
|
|
36
|
+
"serde_json",
|
|
37
|
+
]
|
|
38
|
+
|
|
29
39
|
[[package]]
|
|
30
40
|
name = "async-trait"
|
|
31
41
|
version = "0.1.91"
|
|
@@ -233,6 +243,24 @@ dependencies = [
|
|
|
233
243
|
"typenum",
|
|
234
244
|
]
|
|
235
245
|
|
|
246
|
+
[[package]]
|
|
247
|
+
name = "deadpool"
|
|
248
|
+
version = "0.12.3"
|
|
249
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
250
|
+
checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b"
|
|
251
|
+
dependencies = [
|
|
252
|
+
"deadpool-runtime",
|
|
253
|
+
"lazy_static",
|
|
254
|
+
"num_cpus",
|
|
255
|
+
"tokio",
|
|
256
|
+
]
|
|
257
|
+
|
|
258
|
+
[[package]]
|
|
259
|
+
name = "deadpool-runtime"
|
|
260
|
+
version = "0.1.4"
|
|
261
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
262
|
+
checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b"
|
|
263
|
+
|
|
236
264
|
[[package]]
|
|
237
265
|
name = "deranged"
|
|
238
266
|
version = "0.5.8"
|
|
@@ -576,6 +604,12 @@ version = "1.10.1"
|
|
|
576
604
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
577
605
|
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
|
578
606
|
|
|
607
|
+
[[package]]
|
|
608
|
+
name = "httpdate"
|
|
609
|
+
version = "1.0.3"
|
|
610
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
611
|
+
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
|
612
|
+
|
|
579
613
|
[[package]]
|
|
580
614
|
name = "hyper"
|
|
581
615
|
version = "1.11.0"
|
|
@@ -590,6 +624,7 @@ dependencies = [
|
|
|
590
624
|
"http",
|
|
591
625
|
"http-body",
|
|
592
626
|
"httparse",
|
|
627
|
+
"httpdate",
|
|
593
628
|
"itoa",
|
|
594
629
|
"pin-project-lite",
|
|
595
630
|
"smallvec",
|
|
@@ -1304,7 +1339,7 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
|
|
|
1304
1339
|
|
|
1305
1340
|
[[package]]
|
|
1306
1341
|
name = "pyinferencemanager"
|
|
1307
|
-
version = "1.
|
|
1342
|
+
version = "1.3.0"
|
|
1308
1343
|
dependencies = [
|
|
1309
1344
|
"chrono",
|
|
1310
1345
|
"pyinferencemanager-core",
|
|
@@ -1315,7 +1350,7 @@ dependencies = [
|
|
|
1315
1350
|
|
|
1316
1351
|
[[package]]
|
|
1317
1352
|
name = "pyinferencemanager-core"
|
|
1318
|
-
version = "1.
|
|
1353
|
+
version = "1.3.0"
|
|
1319
1354
|
dependencies = [
|
|
1320
1355
|
"anyhow",
|
|
1321
1356
|
"async-trait",
|
|
@@ -1330,6 +1365,7 @@ dependencies = [
|
|
|
1330
1365
|
"rusqlite",
|
|
1331
1366
|
"serde",
|
|
1332
1367
|
"serde_json",
|
|
1368
|
+
"serial_test",
|
|
1333
1369
|
"sha2",
|
|
1334
1370
|
"sqlite-vec",
|
|
1335
1371
|
"tempfile",
|
|
@@ -1339,6 +1375,7 @@ dependencies = [
|
|
|
1339
1375
|
"tracing-opentelemetry",
|
|
1340
1376
|
"tracing-subscriber",
|
|
1341
1377
|
"uuid",
|
|
1378
|
+
"wiremock",
|
|
1342
1379
|
]
|
|
1343
1380
|
|
|
1344
1381
|
[[package]]
|
|
@@ -1856,6 +1893,31 @@ dependencies = [
|
|
|
1856
1893
|
"zmij",
|
|
1857
1894
|
]
|
|
1858
1895
|
|
|
1896
|
+
[[package]]
|
|
1897
|
+
name = "serial_test"
|
|
1898
|
+
version = "3.5.0"
|
|
1899
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1900
|
+
checksum = "699f4197115b8a7e7ff19c9a315a4bd6fffec26cc4626ef45ecaea389e081c6d"
|
|
1901
|
+
dependencies = [
|
|
1902
|
+
"futures-executor",
|
|
1903
|
+
"futures-util",
|
|
1904
|
+
"log",
|
|
1905
|
+
"once_cell",
|
|
1906
|
+
"parking_lot",
|
|
1907
|
+
"serial_test_derive",
|
|
1908
|
+
]
|
|
1909
|
+
|
|
1910
|
+
[[package]]
|
|
1911
|
+
name = "serial_test_derive"
|
|
1912
|
+
version = "3.5.0"
|
|
1913
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1914
|
+
checksum = "94e153fc76e1c6a068703d6d29c508a0b15c061c4b7e43da59cc097bc342673c"
|
|
1915
|
+
dependencies = [
|
|
1916
|
+
"proc-macro2",
|
|
1917
|
+
"quote",
|
|
1918
|
+
"syn 2.0.119",
|
|
1919
|
+
]
|
|
1920
|
+
|
|
1859
1921
|
[[package]]
|
|
1860
1922
|
name = "sha2"
|
|
1861
1923
|
version = "0.10.9"
|
|
@@ -2726,6 +2788,29 @@ version = "0.52.6"
|
|
|
2726
2788
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2727
2789
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
|
2728
2790
|
|
|
2791
|
+
[[package]]
|
|
2792
|
+
name = "wiremock"
|
|
2793
|
+
version = "0.6.5"
|
|
2794
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2795
|
+
checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031"
|
|
2796
|
+
dependencies = [
|
|
2797
|
+
"assert-json-diff",
|
|
2798
|
+
"base64",
|
|
2799
|
+
"deadpool",
|
|
2800
|
+
"futures",
|
|
2801
|
+
"http",
|
|
2802
|
+
"http-body-util",
|
|
2803
|
+
"hyper",
|
|
2804
|
+
"hyper-util",
|
|
2805
|
+
"log",
|
|
2806
|
+
"once_cell",
|
|
2807
|
+
"regex",
|
|
2808
|
+
"serde",
|
|
2809
|
+
"serde_json",
|
|
2810
|
+
"tokio",
|
|
2811
|
+
"url",
|
|
2812
|
+
]
|
|
2813
|
+
|
|
2729
2814
|
[[package]]
|
|
2730
2815
|
name = "writeable"
|
|
2731
2816
|
version = "0.6.3"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Proprietary License — Free to use with explicit attribution
|
|
2
|
+
|
|
3
|
+
Copyright © 2026 Georgi Mammen Mullassery
|
|
4
|
+
|
|
5
|
+
Permission is granted to any person obtaining a copy of this software to use,
|
|
6
|
+
copy, modify, and distribute this software and its documentation, provided that:
|
|
7
|
+
|
|
8
|
+
1. The above copyright notice and this permission notice appear in all copies
|
|
9
|
+
or substantial portions of the software.
|
|
10
|
+
|
|
11
|
+
2. Explicit attribution to the original author (Georgi Mammen Mullassery) is
|
|
12
|
+
provided in any project documentation and significant code comments where
|
|
13
|
+
this software is used.
|
|
14
|
+
|
|
15
|
+
3. 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, or non-infringement.
|
|
18
|
+
|
|
19
|
+
4. In no event shall the author be liable for any claim, damages, or other
|
|
20
|
+
liability arising from the use of this software.
|
|
21
|
+
|
|
22
|
+
For more information, visit: https://github.com/Mullassery
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyinferencemanager
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Classifier: Development Status :: 4 - Beta
|
|
5
|
+
Classifier: Environment :: Console
|
|
6
|
+
Classifier: Intended Audience :: Developers
|
|
7
|
+
Classifier: Intended Audience :: Science/Research
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Rust
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
17
|
+
Classifier: Typing :: Typed
|
|
18
|
+
Requires-Dist: pytest>=7.0 ; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-asyncio>=0.21 ; extra == 'dev'
|
|
20
|
+
Requires-Dist: maturin>=1.0 ; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff>=0.5.0 ; extra == 'dev'
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Summary: Intelligent AI workload orchestrator. Multi-provider routing, cost optimization, semantic caching, dynamic routing with budget enforcement. Production observability included.
|
|
25
|
+
Keywords: ai,orchestrator,llm,ollama,anthropic,openai,local-first,cost-optimization,caching,multi-provider,routing,inference,workload-orchestration,hardware-aware,semantic-caching,distributed-tracing,observability,budget-enforcement
|
|
26
|
+
Author-email: Georgi Mammen Mullassery <mullassery@gmail.com>
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
29
|
+
Project-URL: Changelog, https://github.com/Mullassery/pyinferencemanager/releases
|
|
30
|
+
Project-URL: Documentation, https://github.com/Mullassery/pyinferencemanager/blob/main/README.md
|
|
31
|
+
Project-URL: Homepage, https://github.com/Mullassery/pyinferencemanager
|
|
32
|
+
Project-URL: Issues, https://github.com/Mullassery/pyinferencemanager/issues
|
|
33
|
+
Project-URL: Repository, https://github.com/Mullassery/pyinferencemanager.git
|
|
34
|
+
|
|
35
|
+
# PyInferenceManager
|
|
36
|
+
|
|
37
|
+
**A multi-provider LLM inference orchestrator with cost/latency-aware routing, real retry + budget guardrails, and local-first execution.**
|
|
38
|
+
|
|
39
|
+
Routes requests to Anthropic Claude, OpenAI GPT, Google Gemini, or a local Ollama model based on task complexity, privacy, and observed provider health — with real retry/backoff on failures and a real spend cap you configure.
|
|
40
|
+
|
|
41
|
+
[](https://pypi.org/project/pyinferencemanager)
|
|
42
|
+
[](https://www.python.org)
|
|
43
|
+
[](https://github.com/Mullassery/PyInferenceManager/actions)
|
|
44
|
+
[](./LICENSE)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## What this actually is
|
|
49
|
+
|
|
50
|
+
The core (Rust, ~11k lines, PyO3 bindings) is a workload orchestrator: it builds a small execution DAG for a task, profiles your local hardware, picks an engine (local Ollama model vs. a cloud provider) based on complexity/privacy/cost, executes with real retry and budget enforcement, and semantically caches results.
|
|
51
|
+
|
|
52
|
+
The Python API surface is a single `Orchestrator` class. There is no `Manager.chat()`, no streaming API, and no 11-provider marketplace — see [Providers](#providers) for the honest list.
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install pyinferencemanager
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires Python 3.10+.
|
|
61
|
+
|
|
62
|
+
Set whichever provider keys you plan to use (none are required for local-only Ollama use):
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
66
|
+
export OPENAI_API_KEY=sk-...
|
|
67
|
+
export GEMINI_API_KEY=... # or GOOGLE_API_KEY
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See [`.env.example`](.env.example).
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from pyinferencemanager import Orchestrator
|
|
76
|
+
|
|
77
|
+
orchestrator = Orchestrator(mode="local_first") # or "cloud_first"
|
|
78
|
+
|
|
79
|
+
result = orchestrator.run(task="question_answering", message="What is the capital of France?")
|
|
80
|
+
print(result.output)
|
|
81
|
+
print(f"Engines used: {result.engines_used}")
|
|
82
|
+
print(f"Cost: ${result.total_cost_usd:.4f} | Latency: {result.total_latency_ms}ms | Tokens: {result.total_tokens}")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`mode="local_first"` runs on your local Ollama model when it's adequate for the task's complexity and escalates to a cloud provider otherwise. `mode="cloud_first"` prefers a cloud provider, falling back to local only for very low-complexity tasks. `privacy="high"` on any call always forces local execution regardless of mode.
|
|
86
|
+
|
|
87
|
+
If the selected backend is unreachable or unauthenticated, `run()` doesn't raise — it returns a result whose `output` says so (e.g. `"[cloud inference unavailable: ...]"`), so a single bad provider doesn't crash your pipeline.
|
|
88
|
+
|
|
89
|
+
## Core API
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
orchestrator = Orchestrator(mode="local_first")
|
|
93
|
+
|
|
94
|
+
# Execute a task — real inference against Ollama or a cloud provider.
|
|
95
|
+
result = orchestrator.run(task="...", file=None, message=None, privacy="low")
|
|
96
|
+
# result.output, .total_tokens, .total_cost_usd, .total_latency_ms, .engines_used, .cache_hits
|
|
97
|
+
|
|
98
|
+
# Estimate cost/latency without executing anything.
|
|
99
|
+
plan = orchestrator.plan("Summarize this document")
|
|
100
|
+
# plan.stages, .estimated_cost_usd, .estimated_latency_ms, .local_first
|
|
101
|
+
|
|
102
|
+
# Real-time provider health, from actually completed cloud calls.
|
|
103
|
+
orchestrator.provider_ranking() # [(provider_key, health_score), ...]
|
|
104
|
+
orchestrator.provider_performance() # {provider_key: {success_rate, avg_latency_ms, ...}}
|
|
105
|
+
|
|
106
|
+
# Cost guardrails, enforced on every real cloud call.
|
|
107
|
+
orchestrator.configure_budget(max_cost_usd=10.0, max_requests=1000,
|
|
108
|
+
alert_threshold_percent=80.0, enforce_hard_limit=True)
|
|
109
|
+
orchestrator.budget_status()
|
|
110
|
+
|
|
111
|
+
# Retry/backoff policy for retryable errors (HTTP 429/408/5xx).
|
|
112
|
+
orchestrator.configure_retry(max_attempts=3, backoff="exponential",
|
|
113
|
+
initial_ms=100, max_ms=5000)
|
|
114
|
+
|
|
115
|
+
# Synthetic load test exercising the same budget + dynamic-routing logic
|
|
116
|
+
# run() uses, at a volume impractical against live APIs. Latencies/costs
|
|
117
|
+
# here are simulated, not real network calls.
|
|
118
|
+
orchestrator.run_load_test(num_requests=200, budget_usd=5.0)
|
|
119
|
+
|
|
120
|
+
# Local hardware profile (memory tier, Apple Silicon/Metal, Ollama models).
|
|
121
|
+
orchestrator.profile_hardware()
|
|
122
|
+
orchestrator.available_backends()
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
See [`examples/`](examples/) for runnable scripts covering each of these.
|
|
126
|
+
|
|
127
|
+
## Providers
|
|
128
|
+
|
|
129
|
+
Real HTTP calls, with retry/backoff and cost tracking:
|
|
130
|
+
|
|
131
|
+
| Provider | Env var | Notes |
|
|
132
|
+
|---|---|---|
|
|
133
|
+
| Anthropic Claude | `ANTHROPIC_API_KEY` | `claude-haiku-4-5`, `claude-opus-4-1` |
|
|
134
|
+
| OpenAI | `OPENAI_API_KEY` | `gpt-4o-mini` |
|
|
135
|
+
| Google Gemini | `GEMINI_API_KEY` / `GOOGLE_API_KEY` | `gemini-1.5-flash` |
|
|
136
|
+
| Ollama (local) | — | whatever models you've pulled locally |
|
|
137
|
+
| vLLM (local) | — | OpenAI-compatible endpoint, default `localhost:8000` |
|
|
138
|
+
|
|
139
|
+
Additionally, `tensorrt_llm`, `mlc_llm`, and `colibri` exist as **cost-estimator-only stubs** (`BackendKind`/`RuntimeBackend` trait implementations with real cost/latency estimation logic, but no live inference) — they're placeholders for self-hosted inference servers, not currently wired to make real calls. `orchestrator.available_backends()` lists all of these honestly, including the stubs.
|
|
140
|
+
|
|
141
|
+
Cloud execution dispatches through `BackendRegistry`/`RuntimeBackend` (not a hand-matched provider enum): `ProviderExecutor::execute` maps a `CloudProvider` to its `BackendKind`, registers the one backend it needs (reading the API key from the env vars above), and calls it through the same `RuntimeBackend::infer` trait object every backend implements — so adding a new cloud provider is a new `BackendKind`/backend + one dispatch arm, not edits scattered across every call site that used to match the old enum.
|
|
142
|
+
|
|
143
|
+
## MCP tools
|
|
144
|
+
|
|
145
|
+
`pyinferencemanager._mcp_tools.PyInferenceManagerMCPHandler` exposes 13 MCP-style tools (`list_available_models`, `execute_inference`, `estimate_inference_cost`, `get_provider_status`, etc.), all backed by a real `Orchestrator` instance — no hardcoded responses. See [`examples/mcp_pyinferencemanager.py`](examples/mcp_pyinferencemanager.py).
|
|
146
|
+
|
|
147
|
+
The network connector (`_mcp_connector.InferenceManager.start_mcp_connector()`) binds to `127.0.0.1` by default with scoped CORS and permissions; binding elsewhere requires passing `allow_remote=True` explicitly.
|
|
148
|
+
|
|
149
|
+
## Testing
|
|
150
|
+
|
|
151
|
+
- Rust core: `cargo test --workspace` (350+ tests, including HTTP-mocked request/response tests for every cloud client via [`wiremock`](https://docs.rs/wiremock)).
|
|
152
|
+
- Python: `pytest tests/` — covers `Orchestrator.run/plan/provider_ranking`, the MCP tool handlers, budget/retry configuration, load testing, and MCP connector security defaults, all without requiring live API keys.
|
|
153
|
+
|
|
154
|
+
## Known issues
|
|
155
|
+
|
|
156
|
+
- `tensorrt_llm`, `mlc_llm`, and `colibri` backends are cost-estimator-only stubs (see [Providers](#providers)) — they do not make live inference calls yet. `vllm` was a stub too as of 1.2.0 but is now a real backend.
|
|
157
|
+
- No open GitHub issues and no `TODO`/`FIXME` markers in the codebase at the time of this writing.
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
Proprietary License — free to use with explicit attribution. See [LICENSE](LICENSE).
|
|
162
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# PyInferenceManager
|
|
2
|
+
|
|
3
|
+
**A multi-provider LLM inference orchestrator with cost/latency-aware routing, real retry + budget guardrails, and local-first execution.**
|
|
4
|
+
|
|
5
|
+
Routes requests to Anthropic Claude, OpenAI GPT, Google Gemini, or a local Ollama model based on task complexity, privacy, and observed provider health — with real retry/backoff on failures and a real spend cap you configure.
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/pyinferencemanager)
|
|
8
|
+
[](https://www.python.org)
|
|
9
|
+
[](https://github.com/Mullassery/PyInferenceManager/actions)
|
|
10
|
+
[](./LICENSE)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What this actually is
|
|
15
|
+
|
|
16
|
+
The core (Rust, ~11k lines, PyO3 bindings) is a workload orchestrator: it builds a small execution DAG for a task, profiles your local hardware, picks an engine (local Ollama model vs. a cloud provider) based on complexity/privacy/cost, executes with real retry and budget enforcement, and semantically caches results.
|
|
17
|
+
|
|
18
|
+
The Python API surface is a single `Orchestrator` class. There is no `Manager.chat()`, no streaming API, and no 11-provider marketplace — see [Providers](#providers) for the honest list.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install pyinferencemanager
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Requires Python 3.10+.
|
|
27
|
+
|
|
28
|
+
Set whichever provider keys you plan to use (none are required for local-only Ollama use):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
32
|
+
export OPENAI_API_KEY=sk-...
|
|
33
|
+
export GEMINI_API_KEY=... # or GOOGLE_API_KEY
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
See [`.env.example`](.env.example).
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from pyinferencemanager import Orchestrator
|
|
42
|
+
|
|
43
|
+
orchestrator = Orchestrator(mode="local_first") # or "cloud_first"
|
|
44
|
+
|
|
45
|
+
result = orchestrator.run(task="question_answering", message="What is the capital of France?")
|
|
46
|
+
print(result.output)
|
|
47
|
+
print(f"Engines used: {result.engines_used}")
|
|
48
|
+
print(f"Cost: ${result.total_cost_usd:.4f} | Latency: {result.total_latency_ms}ms | Tokens: {result.total_tokens}")
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`mode="local_first"` runs on your local Ollama model when it's adequate for the task's complexity and escalates to a cloud provider otherwise. `mode="cloud_first"` prefers a cloud provider, falling back to local only for very low-complexity tasks. `privacy="high"` on any call always forces local execution regardless of mode.
|
|
52
|
+
|
|
53
|
+
If the selected backend is unreachable or unauthenticated, `run()` doesn't raise — it returns a result whose `output` says so (e.g. `"[cloud inference unavailable: ...]"`), so a single bad provider doesn't crash your pipeline.
|
|
54
|
+
|
|
55
|
+
## Core API
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
orchestrator = Orchestrator(mode="local_first")
|
|
59
|
+
|
|
60
|
+
# Execute a task — real inference against Ollama or a cloud provider.
|
|
61
|
+
result = orchestrator.run(task="...", file=None, message=None, privacy="low")
|
|
62
|
+
# result.output, .total_tokens, .total_cost_usd, .total_latency_ms, .engines_used, .cache_hits
|
|
63
|
+
|
|
64
|
+
# Estimate cost/latency without executing anything.
|
|
65
|
+
plan = orchestrator.plan("Summarize this document")
|
|
66
|
+
# plan.stages, .estimated_cost_usd, .estimated_latency_ms, .local_first
|
|
67
|
+
|
|
68
|
+
# Real-time provider health, from actually completed cloud calls.
|
|
69
|
+
orchestrator.provider_ranking() # [(provider_key, health_score), ...]
|
|
70
|
+
orchestrator.provider_performance() # {provider_key: {success_rate, avg_latency_ms, ...}}
|
|
71
|
+
|
|
72
|
+
# Cost guardrails, enforced on every real cloud call.
|
|
73
|
+
orchestrator.configure_budget(max_cost_usd=10.0, max_requests=1000,
|
|
74
|
+
alert_threshold_percent=80.0, enforce_hard_limit=True)
|
|
75
|
+
orchestrator.budget_status()
|
|
76
|
+
|
|
77
|
+
# Retry/backoff policy for retryable errors (HTTP 429/408/5xx).
|
|
78
|
+
orchestrator.configure_retry(max_attempts=3, backoff="exponential",
|
|
79
|
+
initial_ms=100, max_ms=5000)
|
|
80
|
+
|
|
81
|
+
# Synthetic load test exercising the same budget + dynamic-routing logic
|
|
82
|
+
# run() uses, at a volume impractical against live APIs. Latencies/costs
|
|
83
|
+
# here are simulated, not real network calls.
|
|
84
|
+
orchestrator.run_load_test(num_requests=200, budget_usd=5.0)
|
|
85
|
+
|
|
86
|
+
# Local hardware profile (memory tier, Apple Silicon/Metal, Ollama models).
|
|
87
|
+
orchestrator.profile_hardware()
|
|
88
|
+
orchestrator.available_backends()
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
See [`examples/`](examples/) for runnable scripts covering each of these.
|
|
92
|
+
|
|
93
|
+
## Providers
|
|
94
|
+
|
|
95
|
+
Real HTTP calls, with retry/backoff and cost tracking:
|
|
96
|
+
|
|
97
|
+
| Provider | Env var | Notes |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| Anthropic Claude | `ANTHROPIC_API_KEY` | `claude-haiku-4-5`, `claude-opus-4-1` |
|
|
100
|
+
| OpenAI | `OPENAI_API_KEY` | `gpt-4o-mini` |
|
|
101
|
+
| Google Gemini | `GEMINI_API_KEY` / `GOOGLE_API_KEY` | `gemini-1.5-flash` |
|
|
102
|
+
| Ollama (local) | — | whatever models you've pulled locally |
|
|
103
|
+
| vLLM (local) | — | OpenAI-compatible endpoint, default `localhost:8000` |
|
|
104
|
+
|
|
105
|
+
Additionally, `tensorrt_llm`, `mlc_llm`, and `colibri` exist as **cost-estimator-only stubs** (`BackendKind`/`RuntimeBackend` trait implementations with real cost/latency estimation logic, but no live inference) — they're placeholders for self-hosted inference servers, not currently wired to make real calls. `orchestrator.available_backends()` lists all of these honestly, including the stubs.
|
|
106
|
+
|
|
107
|
+
Cloud execution dispatches through `BackendRegistry`/`RuntimeBackend` (not a hand-matched provider enum): `ProviderExecutor::execute` maps a `CloudProvider` to its `BackendKind`, registers the one backend it needs (reading the API key from the env vars above), and calls it through the same `RuntimeBackend::infer` trait object every backend implements — so adding a new cloud provider is a new `BackendKind`/backend + one dispatch arm, not edits scattered across every call site that used to match the old enum.
|
|
108
|
+
|
|
109
|
+
## MCP tools
|
|
110
|
+
|
|
111
|
+
`pyinferencemanager._mcp_tools.PyInferenceManagerMCPHandler` exposes 13 MCP-style tools (`list_available_models`, `execute_inference`, `estimate_inference_cost`, `get_provider_status`, etc.), all backed by a real `Orchestrator` instance — no hardcoded responses. See [`examples/mcp_pyinferencemanager.py`](examples/mcp_pyinferencemanager.py).
|
|
112
|
+
|
|
113
|
+
The network connector (`_mcp_connector.InferenceManager.start_mcp_connector()`) binds to `127.0.0.1` by default with scoped CORS and permissions; binding elsewhere requires passing `allow_remote=True` explicitly.
|
|
114
|
+
|
|
115
|
+
## Testing
|
|
116
|
+
|
|
117
|
+
- Rust core: `cargo test --workspace` (350+ tests, including HTTP-mocked request/response tests for every cloud client via [`wiremock`](https://docs.rs/wiremock)).
|
|
118
|
+
- Python: `pytest tests/` — covers `Orchestrator.run/plan/provider_ranking`, the MCP tool handlers, budget/retry configuration, load testing, and MCP connector security defaults, all without requiring live API keys.
|
|
119
|
+
|
|
120
|
+
## Known issues
|
|
121
|
+
|
|
122
|
+
- `tensorrt_llm`, `mlc_llm`, and `colibri` backends are cost-estimator-only stubs (see [Providers](#providers)) — they do not make live inference calls yet. `vllm` was a stub too as of 1.2.0 but is now a real backend.
|
|
123
|
+
- No open GitHub issues and no `TODO`/`FIXME` markers in the codebase at the time of this writing.
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
Proprietary License — free to use with explicit attribution. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
use super::{BackendKind, InferenceRequest, InferenceResult, ModelProfile, RuntimeBackend};
|
|
2
|
+
use crate::engines::GeminiClient;
|
|
3
|
+
|
|
4
|
+
pub struct GeminiBackend {
|
|
5
|
+
api_key: String,
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
impl GeminiBackend {
|
|
9
|
+
pub fn new(api_key: String) -> Self {
|
|
10
|
+
GeminiBackend { api_key }
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#[async_trait::async_trait]
|
|
15
|
+
impl RuntimeBackend for GeminiBackend {
|
|
16
|
+
async fn infer(&self, request: InferenceRequest) -> crate::Result<InferenceResult> {
|
|
17
|
+
let start = std::time::Instant::now();
|
|
18
|
+
let client = GeminiClient::new(self.api_key.clone(), request.model.clone());
|
|
19
|
+
|
|
20
|
+
let response = client.complete(&request.prompt, request.max_tokens).await?;
|
|
21
|
+
|
|
22
|
+
let latency_ms = start.elapsed().as_millis() as u64;
|
|
23
|
+
|
|
24
|
+
Ok(InferenceResult {
|
|
25
|
+
output: response.text,
|
|
26
|
+
tokens_used: response.tokens_used,
|
|
27
|
+
latency_ms,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
fn estimate_cost(&self, profile: &ModelProfile) -> f32 {
|
|
32
|
+
// Gemini Flash-tier pricing is roughly in the same band as
|
|
33
|
+
// OpenAI's smaller models.
|
|
34
|
+
let size_gb = profile.size_gb();
|
|
35
|
+
if size_gb < 10.0 {
|
|
36
|
+
0.0001
|
|
37
|
+
} else if size_gb < 30.0 {
|
|
38
|
+
0.00025
|
|
39
|
+
} else {
|
|
40
|
+
0.0005
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fn estimate_latency(&self, profile: &ModelProfile) -> u64 {
|
|
45
|
+
let size_gb = profile.size_gb();
|
|
46
|
+
let base = (size_gb * 8.0) as u64;
|
|
47
|
+
base.clamp(80, 4000)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
fn kind(&self) -> BackendKind {
|
|
51
|
+
BackendKind::Gemini
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#[cfg(test)]
|
|
56
|
+
mod tests {
|
|
57
|
+
use super::*;
|
|
58
|
+
|
|
59
|
+
#[test]
|
|
60
|
+
fn test_gemini_backend_kind() {
|
|
61
|
+
let backend = GeminiBackend::new("test-key".to_string());
|
|
62
|
+
assert_eq!(backend.kind(), BackendKind::Gemini);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[test]
|
|
66
|
+
fn test_gemini_estimate_cost() {
|
|
67
|
+
let backend = GeminiBackend::new("test-key".to_string());
|
|
68
|
+
let small_profile = ModelProfile::new(4 * 1_073_741_824, "gemini".to_string());
|
|
69
|
+
let large_profile = ModelProfile::new(50 * 1_073_741_824, "gemini".to_string());
|
|
70
|
+
|
|
71
|
+
let small_cost = backend.estimate_cost(&small_profile);
|
|
72
|
+
let large_cost = backend.estimate_cost(&large_profile);
|
|
73
|
+
|
|
74
|
+
assert!(small_cost < large_cost);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
#[test]
|
|
78
|
+
fn test_gemini_estimate_latency() {
|
|
79
|
+
let backend = GeminiBackend::new("test-key".to_string());
|
|
80
|
+
let profile = ModelProfile::new(8 * 1_073_741_824, "gemini".to_string());
|
|
81
|
+
let latency = backend.estimate_latency(&profile);
|
|
82
|
+
|
|
83
|
+
assert!(latency >= 80);
|
|
84
|
+
assert!(latency <= 4000);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -3,20 +3,25 @@ use std::collections::HashMap;
|
|
|
3
3
|
|
|
4
4
|
pub mod anthropic_backend;
|
|
5
5
|
pub mod colibri_backend;
|
|
6
|
+
pub mod gemini_backend;
|
|
6
7
|
pub mod ollama_backend;
|
|
7
8
|
pub mod openai_backend;
|
|
8
9
|
pub mod stub_backend;
|
|
10
|
+
pub mod vllm_backend;
|
|
9
11
|
|
|
10
12
|
pub use anthropic_backend::AnthropicBackend;
|
|
11
13
|
pub use colibri_backend::ColibriBackend;
|
|
14
|
+
pub use gemini_backend::GeminiBackend;
|
|
12
15
|
pub use ollama_backend::OllamaBackend;
|
|
13
16
|
pub use openai_backend::OpenAiBackend;
|
|
14
17
|
pub use stub_backend::StubBackend;
|
|
18
|
+
pub use vllm_backend::VLlmBackend;
|
|
15
19
|
|
|
16
20
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
|
17
21
|
pub enum BackendKind {
|
|
18
22
|
Anthropic,
|
|
19
23
|
OpenAi,
|
|
24
|
+
Gemini,
|
|
20
25
|
Ollama,
|
|
21
26
|
VLlm,
|
|
22
27
|
TensorRtLlm,
|
|
@@ -29,6 +34,7 @@ impl BackendKind {
|
|
|
29
34
|
match self {
|
|
30
35
|
BackendKind::Anthropic => "anthropic",
|
|
31
36
|
BackendKind::OpenAi => "openai",
|
|
37
|
+
BackendKind::Gemini => "gemini",
|
|
32
38
|
BackendKind::Ollama => "ollama",
|
|
33
39
|
BackendKind::VLlm => "vllm",
|
|
34
40
|
BackendKind::TensorRtLlm => "tensorrt_llm",
|
|
@@ -99,8 +105,9 @@ pub trait RuntimeBackend: Send + Sync {
|
|
|
99
105
|
pub enum AnyBackend {
|
|
100
106
|
Anthropic(AnthropicBackend),
|
|
101
107
|
OpenAi(OpenAiBackend),
|
|
108
|
+
Gemini(GeminiBackend),
|
|
102
109
|
Ollama(OllamaBackend),
|
|
103
|
-
VLlm(
|
|
110
|
+
VLlm(VLlmBackend),
|
|
104
111
|
TensorRtLlm(StubBackend),
|
|
105
112
|
MlcLlm(StubBackend),
|
|
106
113
|
Colibri(ColibriBackend),
|
|
@@ -111,6 +118,7 @@ impl AnyBackend {
|
|
|
111
118
|
match self {
|
|
112
119
|
AnyBackend::Anthropic(b) => b.infer(request).await,
|
|
113
120
|
AnyBackend::OpenAi(b) => b.infer(request).await,
|
|
121
|
+
AnyBackend::Gemini(b) => b.infer(request).await,
|
|
114
122
|
AnyBackend::Ollama(b) => b.infer(request).await,
|
|
115
123
|
AnyBackend::VLlm(b) => b.infer(request).await,
|
|
116
124
|
AnyBackend::TensorRtLlm(b) => b.infer(request).await,
|
|
@@ -123,6 +131,7 @@ impl AnyBackend {
|
|
|
123
131
|
match self {
|
|
124
132
|
AnyBackend::Anthropic(b) => b.estimate_cost(profile),
|
|
125
133
|
AnyBackend::OpenAi(b) => b.estimate_cost(profile),
|
|
134
|
+
AnyBackend::Gemini(b) => b.estimate_cost(profile),
|
|
126
135
|
AnyBackend::Ollama(b) => b.estimate_cost(profile),
|
|
127
136
|
AnyBackend::VLlm(b) => b.estimate_cost(profile),
|
|
128
137
|
AnyBackend::TensorRtLlm(b) => b.estimate_cost(profile),
|
|
@@ -135,6 +144,7 @@ impl AnyBackend {
|
|
|
135
144
|
match self {
|
|
136
145
|
AnyBackend::Anthropic(b) => b.estimate_latency(profile),
|
|
137
146
|
AnyBackend::OpenAi(b) => b.estimate_latency(profile),
|
|
147
|
+
AnyBackend::Gemini(b) => b.estimate_latency(profile),
|
|
138
148
|
AnyBackend::Ollama(b) => b.estimate_latency(profile),
|
|
139
149
|
AnyBackend::VLlm(b) => b.estimate_latency(profile),
|
|
140
150
|
AnyBackend::TensorRtLlm(b) => b.estimate_latency(profile),
|
|
@@ -147,6 +157,7 @@ impl AnyBackend {
|
|
|
147
157
|
match self {
|
|
148
158
|
AnyBackend::Anthropic(b) => b.kind(),
|
|
149
159
|
AnyBackend::OpenAi(b) => b.kind(),
|
|
160
|
+
AnyBackend::Gemini(b) => b.kind(),
|
|
150
161
|
AnyBackend::Ollama(b) => b.kind(),
|
|
151
162
|
AnyBackend::VLlm(b) => b.kind(),
|
|
152
163
|
AnyBackend::TensorRtLlm(b) => b.kind(),
|