predikit 0.4.3__tar.gz → 0.4.5__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 (122) hide show
  1. {predikit-0.4.3 → predikit-0.4.5}/CHANGELOG.md +23 -1
  2. {predikit-0.4.3 → predikit-0.4.5}/PKG-INFO +91 -24
  3. {predikit-0.4.3 → predikit-0.4.5}/README.md +85 -21
  4. {predikit-0.4.3 → predikit-0.4.5}/examples/01_basic_sklearn.py +4 -1
  5. {predikit-0.4.3 → predikit-0.4.5}/examples/02_xgboost_regression.py +12 -9
  6. {predikit-0.4.3 → predikit-0.4.5}/examples/03_orlando_real_estate.py +31 -26
  7. {predikit-0.4.3 → predikit-0.4.5}/examples/04_confidence_routing.py +6 -3
  8. {predikit-0.4.3 → predikit-0.4.5}/examples/05_multi_model_ensemble.py +58 -31
  9. {predikit-0.4.3 → predikit-0.4.5}/examples/06_mlflow_loader.py +3 -4
  10. {predikit-0.4.3 → predikit-0.4.5}/examples/07_snowflake_loader.py +5 -3
  11. {predikit-0.4.3 → predikit-0.4.5}/pyproject.toml +17 -5
  12. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/__init__.py +1 -1
  13. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/ensemble.py +19 -0
  14. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/registry.py +13 -4
  15. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/tool.py +4 -0
  16. {predikit-0.4.3 → predikit-0.4.5}/tests/test_confidence.py +11 -6
  17. {predikit-0.4.3 → predikit-0.4.5}/tests/test_ensemble.py +28 -0
  18. {predikit-0.4.3 → predikit-0.4.5}/tests/test_loaders_mlflow.py +1 -0
  19. predikit-0.4.5/tests/test_registry.py +89 -0
  20. {predikit-0.4.3 → predikit-0.4.5}/tests/test_weighted_ensemble.py +22 -0
  21. {predikit-0.4.3 → predikit-0.4.5}/uv.lock +1 -1
  22. predikit-0.4.3/tests/test_registry.py +0 -45
  23. {predikit-0.4.3 → predikit-0.4.5}/.claude/settings.local.json +0 -0
  24. {predikit-0.4.3 → predikit-0.4.5}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  25. {predikit-0.4.3 → predikit-0.4.5}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  26. {predikit-0.4.3 → predikit-0.4.5}/.github/workflows/publish.yml +0 -0
  27. {predikit-0.4.3 → predikit-0.4.5}/.github/workflows/test.yml +0 -0
  28. {predikit-0.4.3 → predikit-0.4.5}/.gitignore +0 -0
  29. {predikit-0.4.3 → predikit-0.4.5}/.pre-commit-config.yaml +0 -0
  30. {predikit-0.4.3 → predikit-0.4.5}/CLAUDE.md +0 -0
  31. {predikit-0.4.3 → predikit-0.4.5}/CONTRIBUTING.md +0 -0
  32. {predikit-0.4.3 → predikit-0.4.5}/LICENSE +0 -0
  33. {predikit-0.4.3 → predikit-0.4.5}/docs/logo.gif +0 -0
  34. {predikit-0.4.3 → predikit-0.4.5}/docs/logo.png +0 -0
  35. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-27a74bc0ab2f40e09dc3d6c4f026cc1e/artifacts/MLmodel +0 -0
  36. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-27a74bc0ab2f40e09dc3d6c4f026cc1e/artifacts/conda.yaml +0 -0
  37. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-27a74bc0ab2f40e09dc3d6c4f026cc1e/artifacts/model.skops +0 -0
  38. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-27a74bc0ab2f40e09dc3d6c4f026cc1e/artifacts/python_env.yaml +0 -0
  39. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-27a74bc0ab2f40e09dc3d6c4f026cc1e/artifacts/requirements.txt +0 -0
  40. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-28173468f0874040a705d2d3820a4f5c/artifacts/MLmodel +0 -0
  41. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-28173468f0874040a705d2d3820a4f5c/artifacts/conda.yaml +0 -0
  42. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-28173468f0874040a705d2d3820a4f5c/artifacts/model.skops +0 -0
  43. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-28173468f0874040a705d2d3820a4f5c/artifacts/python_env.yaml +0 -0
  44. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-28173468f0874040a705d2d3820a4f5c/artifacts/requirements.txt +0 -0
  45. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-3eabd93b6ac447808321a1d58fef2b9b/artifacts/MLmodel +0 -0
  46. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-3eabd93b6ac447808321a1d58fef2b9b/artifacts/conda.yaml +0 -0
  47. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-3eabd93b6ac447808321a1d58fef2b9b/artifacts/model.skops +0 -0
  48. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-3eabd93b6ac447808321a1d58fef2b9b/artifacts/python_env.yaml +0 -0
  49. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-3eabd93b6ac447808321a1d58fef2b9b/artifacts/requirements.txt +0 -0
  50. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4816da14ba9c47c2b69d7d959f186d4e/artifacts/MLmodel +0 -0
  51. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4816da14ba9c47c2b69d7d959f186d4e/artifacts/conda.yaml +0 -0
  52. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4816da14ba9c47c2b69d7d959f186d4e/artifacts/model.skops +0 -0
  53. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4816da14ba9c47c2b69d7d959f186d4e/artifacts/python_env.yaml +0 -0
  54. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4816da14ba9c47c2b69d7d959f186d4e/artifacts/requirements.txt +0 -0
  55. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4deda032d5434d74888edc6f4df2e642/artifacts/MLmodel +0 -0
  56. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4deda032d5434d74888edc6f4df2e642/artifacts/conda.yaml +0 -0
  57. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4deda032d5434d74888edc6f4df2e642/artifacts/model.skops +0 -0
  58. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4deda032d5434d74888edc6f4df2e642/artifacts/python_env.yaml +0 -0
  59. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-4deda032d5434d74888edc6f4df2e642/artifacts/requirements.txt +0 -0
  60. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-6988b8fc759d4a6d9ba42b3ef9c5bbad/artifacts/MLmodel +0 -0
  61. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-6988b8fc759d4a6d9ba42b3ef9c5bbad/artifacts/conda.yaml +0 -0
  62. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-6988b8fc759d4a6d9ba42b3ef9c5bbad/artifacts/model.skops +0 -0
  63. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-6988b8fc759d4a6d9ba42b3ef9c5bbad/artifacts/python_env.yaml +0 -0
  64. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-6988b8fc759d4a6d9ba42b3ef9c5bbad/artifacts/requirements.txt +0 -0
  65. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-885ed3e972dd4583aa9b4c518b369316/artifacts/MLmodel +0 -0
  66. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-885ed3e972dd4583aa9b4c518b369316/artifacts/conda.yaml +0 -0
  67. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-885ed3e972dd4583aa9b4c518b369316/artifacts/model.skops +0 -0
  68. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-885ed3e972dd4583aa9b4c518b369316/artifacts/python_env.yaml +0 -0
  69. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-885ed3e972dd4583aa9b4c518b369316/artifacts/requirements.txt +0 -0
  70. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-936aa30d653c4e79920e98dd23b2e352/artifacts/MLmodel +0 -0
  71. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-936aa30d653c4e79920e98dd23b2e352/artifacts/conda.yaml +0 -0
  72. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-936aa30d653c4e79920e98dd23b2e352/artifacts/model.skops +0 -0
  73. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-936aa30d653c4e79920e98dd23b2e352/artifacts/python_env.yaml +0 -0
  74. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-936aa30d653c4e79920e98dd23b2e352/artifacts/requirements.txt +0 -0
  75. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-9c8120122eb744128b3c91e724536d7e/artifacts/MLmodel +0 -0
  76. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-9c8120122eb744128b3c91e724536d7e/artifacts/conda.yaml +0 -0
  77. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-9c8120122eb744128b3c91e724536d7e/artifacts/model.skops +0 -0
  78. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-9c8120122eb744128b3c91e724536d7e/artifacts/python_env.yaml +0 -0
  79. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-9c8120122eb744128b3c91e724536d7e/artifacts/requirements.txt +0 -0
  80. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-bc53e68577e64ed5b64b173ae23eb99d/artifacts/MLmodel +0 -0
  81. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-bc53e68577e64ed5b64b173ae23eb99d/artifacts/conda.yaml +0 -0
  82. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-bc53e68577e64ed5b64b173ae23eb99d/artifacts/model.skops +0 -0
  83. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-bc53e68577e64ed5b64b173ae23eb99d/artifacts/python_env.yaml +0 -0
  84. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-bc53e68577e64ed5b64b173ae23eb99d/artifacts/requirements.txt +0 -0
  85. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-d5e1b20e8a9a4414b74b95d613362ae0/artifacts/MLmodel +0 -0
  86. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-d5e1b20e8a9a4414b74b95d613362ae0/artifacts/conda.yaml +0 -0
  87. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-d5e1b20e8a9a4414b74b95d613362ae0/artifacts/model.skops +0 -0
  88. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-d5e1b20e8a9a4414b74b95d613362ae0/artifacts/python_env.yaml +0 -0
  89. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-d5e1b20e8a9a4414b74b95d613362ae0/artifacts/requirements.txt +0 -0
  90. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e368d86129cb416cbdc24ce1f4d4062b/artifacts/MLmodel +0 -0
  91. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e368d86129cb416cbdc24ce1f4d4062b/artifacts/conda.yaml +0 -0
  92. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e368d86129cb416cbdc24ce1f4d4062b/artifacts/model.skops +0 -0
  93. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e368d86129cb416cbdc24ce1f4d4062b/artifacts/python_env.yaml +0 -0
  94. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e368d86129cb416cbdc24ce1f4d4062b/artifacts/requirements.txt +0 -0
  95. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e71aea9d1d2646f0970b78d821200719/artifacts/MLmodel +0 -0
  96. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e71aea9d1d2646f0970b78d821200719/artifacts/conda.yaml +0 -0
  97. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e71aea9d1d2646f0970b78d821200719/artifacts/model.skops +0 -0
  98. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e71aea9d1d2646f0970b78d821200719/artifacts/python_env.yaml +0 -0
  99. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-e71aea9d1d2646f0970b78d821200719/artifacts/requirements.txt +0 -0
  100. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-f374e93dce4f4be498ccf04e1fb1ac9e/artifacts/MLmodel +0 -0
  101. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-f374e93dce4f4be498ccf04e1fb1ac9e/artifacts/conda.yaml +0 -0
  102. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-f374e93dce4f4be498ccf04e1fb1ac9e/artifacts/model.skops +0 -0
  103. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-f374e93dce4f4be498ccf04e1fb1ac9e/artifacts/python_env.yaml +0 -0
  104. {predikit-0.4.3 → predikit-0.4.5}/mlruns/1/models/m-f374e93dce4f4be498ccf04e1fb1ac9e/artifacts/requirements.txt +0 -0
  105. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/cli.py +0 -0
  106. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/coerce.py +0 -0
  107. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/exceptions.py +0 -0
  108. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/exporters/__init__.py +0 -0
  109. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/exporters/langchain.py +0 -0
  110. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/exporters/openai.py +0 -0
  111. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/introspect.py +0 -0
  112. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/loaders/__init__.py +0 -0
  113. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/loaders/mlflow.py +0 -0
  114. {predikit-0.4.3 → predikit-0.4.5}/src/predikit/loaders/snowflake.py +0 -0
  115. {predikit-0.4.3 → predikit-0.4.5}/tests/__init__.py +0 -0
  116. {predikit-0.4.3 → predikit-0.4.5}/tests/test_cli.py +0 -0
  117. {predikit-0.4.3 → predikit-0.4.5}/tests/test_coerce.py +0 -0
  118. {predikit-0.4.3 → predikit-0.4.5}/tests/test_exporters_openai.py +0 -0
  119. {predikit-0.4.3 → predikit-0.4.5}/tests/test_introspect.py +0 -0
  120. {predikit-0.4.3 → predikit-0.4.5}/tests/test_loaders_snowflake.py +0 -0
  121. {predikit-0.4.3 → predikit-0.4.5}/tests/test_logging.py +0 -0
  122. {predikit-0.4.3 → predikit-0.4.5}/tests/test_tool.py +0 -0
@@ -4,7 +4,29 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased]
7
+ ## [Unreleased]
8
+
9
+ ## [0.4.5] - 2026-07-01
10
+
11
+ ### Fixed
12
+ - Added validation for `confidence_threshold` so values outside `0.0` to `1.0` fail at construction time
13
+ - Added `ModelEnsemble` validation for duplicate `collect` outputs, mismatched aggregate output names, negative weights, and zero-total weighted strategies
14
+ - Added `ToolRegistry` duplicate-name validation across tools and ensembles
15
+ - Updated `ToolRegistry.get()` to retrieve both tools and ensembles with clearer missing-name errors
16
+ - Cleaned up example lint issues and corrected stale `modelbridge[xgboost]` install text
17
+
18
+ ### Changed
19
+ - Marked MLflow loader tests as opt-in integration tests so the default pytest suite stays fast and deterministic
20
+
21
+ ## [0.4.4] - 2026-06-24
22
+
23
+ ### Changed
24
+ - README overhauled: added "Why predikit?" comparison table, "Works with" ecosystem section, GitHub star/fork badges, and a shipped-vs-planned roadmap
25
+ - Quick start section replaces "30-second example" heading; `---` dividers added between major sections for better scanability
26
+ - PyPI package description updated to a more descriptive one-liner
27
+ - Keywords expanded: added `scikit-learn`, `tool-use`, `openai`, `langchain`, `mlops`, `ai-agents`, `pydantic`, `model-serving`
28
+ - Added `Documentation` URL to `[project.urls]` in `pyproject.toml`
29
+ - Added `Topic :: Software Development :: Libraries :: Python Modules` and `Typing :: Typed` classifiers
8
30
 
9
31
  ## [0.4.2] - 2026-06-13
10
32
 
@@ -1,15 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: predikit
3
- Version: 0.4.3
4
- Summary: Turn any trained sklearn/XGBoost model into an LLM-callable tool with auto-generated schemas and typed I/O.
3
+ Version: 0.4.5
4
+ Summary: Wrap any trained sklearn/XGBoost model as an LLM-callable tool auto-generated JSON schemas, Pydantic I/O, OpenAI & LangChain ready, zero boilerplate.
5
5
  Project-URL: Homepage, https://github.com/Tejas-TA/predikit
6
6
  Project-URL: Repository, https://github.com/Tejas-TA/predikit
7
+ Project-URL: Documentation, https://github.com/Tejas-TA/predikit#readme
7
8
  Project-URL: Bug Tracker, https://github.com/Tejas-TA/predikit/issues
8
9
  Project-URL: Changelog, https://github.com/Tejas-TA/predikit/releases
9
10
  Author-email: Tejas Tumakuru Ashok <tejasta@gmail.com>
10
11
  License: MIT
11
12
  License-File: LICENSE
12
- Keywords: agents,function-calling,llm,ml-tools,sklearn,xgboost
13
+ Keywords: agents,ai-agents,function-calling,langchain,llm,machine-learning,ml-tools,mlops,model-serving,openai,pydantic,scikit-learn,sklearn,tool-use,xgboost
13
14
  Classifier: Development Status :: 4 - Beta
14
15
  Classifier: Intended Audience :: Developers
15
16
  Classifier: Intended Audience :: Science/Research
@@ -19,6 +20,8 @@ Classifier: Programming Language :: Python :: 3.10
19
20
  Classifier: Programming Language :: Python :: 3.11
20
21
  Classifier: Programming Language :: Python :: 3.12
21
22
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
23
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
24
+ Classifier: Typing :: Typed
22
25
  Requires-Python: >=3.10
23
26
  Requires-Dist: numpy>=1.24
24
27
  Requires-Dist: pydantic>=2.0
@@ -56,7 +59,8 @@ Description-Content-Type: text/markdown
56
59
  </p>
57
60
 
58
61
  <p align="center">
59
- Turn any trained scikit-learn or XGBoost model into an LLM-callable tool —<br/>
62
+ <strong>The bridge between your ML models and LLM agents.</strong><br/>
63
+ Wrap any trained scikit-learn or XGBoost model as an LLM-callable tool —<br/>
60
64
  auto-generated JSON schemas, typed I/O, zero boilerplate.
61
65
  </p>
62
66
 
@@ -68,6 +72,8 @@ Description-Content-Type: text/markdown
68
72
  </p>
69
73
 
70
74
  <p align="center">
75
+ <a href="https://github.com/Tejas-TA/predikit/stargazers"><img src="https://img.shields.io/github/stars/Tejas-TA/predikit?style=social" alt="GitHub Stars"/></a>
76
+ <a href="https://github.com/Tejas-TA/predikit/network/members"><img src="https://img.shields.io/github/forks/Tejas-TA/predikit?style=social" alt="GitHub Forks"/></a>
71
77
  <a href="https://pepy.tech/project/predikit"><img src="https://static.pepy.tech/personalized-badge/predikit?period=week&units=international_system&left_color=grey&right_color=blue&left_text=weekly+downloads" alt="Weekly Downloads"/></a>
72
78
  <a href="https://pepy.tech/project/predikit"><img src="https://static.pepy.tech/personalized-badge/predikit?period=month&units=international_system&left_color=grey&right_color=blue&left_text=monthly+downloads" alt="Monthly Downloads"/></a>
73
79
  <a href="https://pepy.tech/project/predikit"><img src="https://static.pepy.tech/personalized-badge/predikit?period=total&units=international_system&left_color=grey&right_color=blue&left_text=total+downloads" alt="Total Downloads"/></a>
@@ -79,34 +85,71 @@ tool.to_openai() # OpenAI function schema, ready to pass to the API
79
85
  tool.invoke({"sqft": 2200}) # → {"price_usd": 370730}
80
86
  ```
81
87
 
88
+ ---
89
+
82
90
  ## Table of Contents
91
+ - [Why predikit?](#why-predikit)
92
+ - [Works with](#works-with)
83
93
  - [Install](#install)
84
- - [30-second example](#30-second-example)
94
+ - [Quick start](#quick-start)
85
95
  - [Core API](#core-api)
86
96
  - [Field naming rule](#field-naming-rule)
87
97
  - [Cookbook](#cookbook)
98
+ - [Roadmap](#roadmap)
88
99
  - [Contributing](#contributing)
89
100
  - [License](#license)
90
101
 
91
- ## Install
102
+ ---
92
103
 
93
- ```bash
94
- pip install predikit
104
+ ## Why predikit?
105
+
106
+ Most ML pipelines stop at `.predict()`. Getting that prediction callable by an LLM agent — with validated inputs, correct types, and a schema the model can reason about — requires glue code that's tedious to write and easy to get wrong.
107
+
108
+ predikit handles that layer for you:
109
+
110
+ | | Without predikit | With predikit |
111
+ |--|------------------|---------------|
112
+ | **Schema** | Hand-write JSON Schema for every model | Auto-generated from your Pydantic `BaseModel` |
113
+ | **Type safety** | Manual casting, silent failures | Pydantic v2 validation with clear error messages |
114
+ | **LLM integration** | OpenAI / LangChain boilerplate per model | `.to_openai()` / `.to_langchain()` in one line |
115
+ | **Ensemble routing** | Custom aggregation logic per project | `ModelEnsemble` with 5 built-in strategies |
116
+ | **Confidence handling** | Write your own threshold checks | `confidence_threshold` + `on_low_confidence` |
117
+ | **Model registries** | Manual MLflow / Snowflake registry calls | `from_mlflow()` / `from_snowflake()` loaders |
118
+ | **Async** | `asyncio.get_event_loop().run_in_executor(...)` | `await tool.ainvoke(inputs)` |
119
+
120
+ ---
121
+
122
+ ## Works with
123
+
124
+ predikit is designed to plug into the tools your team already uses:
125
+
126
+ **Models** — scikit-learn · XGBoost
127
+
128
+ **LLM frameworks** — OpenAI function calling · LangChain · any tool-calling API that accepts JSON Schema
129
+
130
+ **Model registries** — MLflow Model Registry · Snowflake Model Registry
131
+
132
+ **Validation** — Pydantic v2
95
133
 
96
- # With XGBoost support
97
- pip install predikit[xgboost]
134
+ **Async** `asyncio`-compatible via `ainvoke()`
98
135
 
99
- # With LangChain support
100
- pip install predikit[langchain]
136
+ ---
101
137
 
102
- # With MLflow Model Registry support
103
- pip install predikit[mlflow]
138
+ ## Install
139
+
140
+ ```bash
141
+ pip install predikit
104
142
 
105
- # With Snowflake Model Registry support
106
- pip install predikit[snowflake]
143
+ # Optional extras
144
+ pip install predikit[xgboost] # XGBoost support
145
+ pip install predikit[langchain] # LangChain StructuredTool export
146
+ pip install predikit[mlflow] # MLflow Model Registry loader
147
+ pip install predikit[snowflake] # Snowflake Model Registry loader
107
148
  ```
108
149
 
109
- ## 30-second example
150
+ ---
151
+
152
+ ## Quick start
110
153
 
111
154
  ```python
112
155
  from pydantic import BaseModel, Field
@@ -147,6 +190,8 @@ tool.invoke({
147
190
  # → {"species": 0}
148
191
  ```
149
192
 
193
+ ---
194
+
150
195
  ## Core API
151
196
 
152
197
  ### `ModelTool`
@@ -205,6 +250,8 @@ ModelEnsemble(
205
250
 
206
251
  `ModelEnsemble` exposes the same `.invoke()`, `.ainvoke()`, `.to_openai()`, and `.to_langchain()` interface as `ModelTool`.
207
252
 
253
+ ---
254
+
208
255
  ## Field naming rule
209
256
 
210
257
  **Your Pydantic schema field names must exactly match the column names the model was trained on.**
@@ -234,6 +281,8 @@ Schema has: ['square_footage', 'beds', 'bathrooms'], model expects: ['sqft', 'be
234
281
 
235
282
  > **Tip:** If you trained with a numpy array (no DataFrame), predikit has no feature names to check — it uses your schema's field definition order instead.
236
283
 
284
+ ---
285
+
237
286
  ## Cookbook
238
287
 
239
288
  ### XGBoost regression
@@ -389,23 +438,41 @@ tool = from_snowflake(
389
438
 
390
439
  Pass `output_method="predict_proba"` or any other method your Snowflake model exposes. The returned `ModelTool` is identical to one built directly — all exporters, confidence routing, and ensemble strategies work as-is. Requires `pip install predikit[snowflake]`.
391
440
 
392
- ### Orlando real estate demo
441
+ ### End-to-end demo
442
+
443
+ See [`examples/03_orlando_real_estate.py`](examples/03_orlando_real_estate.py) for a full walkthrough: synthetic dataset → XGBoost training → `ModelTool` → registry → OpenAI schema → prediction.
393
444
 
394
- See [`examples/03_orlando_real_estate.py`](examples/03_orlando_real_estate.py) for a full end-to-end walkthrough: synthetic dataset → XGBoost training → `ModelTool` → registry → OpenAI schema → prediction.
445
+ ---
395
446
 
396
447
  ## Roadmap
397
448
 
398
- Planned for later releases:
449
+ ### Shipped
450
+
451
+ - [x] OpenAI function-calling schema export
452
+ - [x] LangChain `StructuredTool` export
453
+ - [x] Pydantic v2 typed I/O validation
454
+ - [x] Multi-model `ModelEnsemble` — collect / mean / vote / weighted variants
455
+ - [x] Confidence routing — `warn` / `raise` / `fallback`
456
+ - [x] Async `ainvoke()` via thread pool executor
457
+ - [x] MLflow Model Registry loader
458
+ - [x] Snowflake Model Registry loader
459
+ - [x] `predikit inspect` CLI
460
+
461
+ ### Planned
399
462
 
400
- - HuggingFace / PyTorch / TensorFlow model support
401
- - Streaming inference support
402
- - OpenAI Assistants API integration
463
+ - [ ] HuggingFace / PyTorch / TensorFlow model support
464
+ - [ ] Streaming inference support
465
+ - [ ] OpenAI Assistants API integration
466
+ - [ ] MCP server mode
467
+
468
+ ---
403
469
 
404
470
  ## Contributing
405
471
 
406
472
  See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code style, and PR guidelines. The [CHANGELOG](CHANGELOG.md) tracks notable changes per release.
407
473
 
474
+ Issues and PRs are welcome — if you're wrapping a model type or registry that predikit doesn't support yet, open a discussion.
475
+
408
476
  ## License
409
477
 
410
478
  MIT © Tejas Tumakuru Ashok
411
-
@@ -6,7 +6,8 @@
6
6
  </p>
7
7
 
8
8
  <p align="center">
9
- Turn any trained scikit-learn or XGBoost model into an LLM-callable tool —<br/>
9
+ <strong>The bridge between your ML models and LLM agents.</strong><br/>
10
+ Wrap any trained scikit-learn or XGBoost model as an LLM-callable tool —<br/>
10
11
  auto-generated JSON schemas, typed I/O, zero boilerplate.
11
12
  </p>
12
13
 
@@ -18,6 +19,8 @@
18
19
  </p>
19
20
 
20
21
  <p align="center">
22
+ <a href="https://github.com/Tejas-TA/predikit/stargazers"><img src="https://img.shields.io/github/stars/Tejas-TA/predikit?style=social" alt="GitHub Stars"/></a>
23
+ <a href="https://github.com/Tejas-TA/predikit/network/members"><img src="https://img.shields.io/github/forks/Tejas-TA/predikit?style=social" alt="GitHub Forks"/></a>
21
24
  <a href="https://pepy.tech/project/predikit"><img src="https://static.pepy.tech/personalized-badge/predikit?period=week&units=international_system&left_color=grey&right_color=blue&left_text=weekly+downloads" alt="Weekly Downloads"/></a>
22
25
  <a href="https://pepy.tech/project/predikit"><img src="https://static.pepy.tech/personalized-badge/predikit?period=month&units=international_system&left_color=grey&right_color=blue&left_text=monthly+downloads" alt="Monthly Downloads"/></a>
23
26
  <a href="https://pepy.tech/project/predikit"><img src="https://static.pepy.tech/personalized-badge/predikit?period=total&units=international_system&left_color=grey&right_color=blue&left_text=total+downloads" alt="Total Downloads"/></a>
@@ -29,34 +32,71 @@ tool.to_openai() # OpenAI function schema, ready to pass to the API
29
32
  tool.invoke({"sqft": 2200}) # → {"price_usd": 370730}
30
33
  ```
31
34
 
35
+ ---
36
+
32
37
  ## Table of Contents
38
+ - [Why predikit?](#why-predikit)
39
+ - [Works with](#works-with)
33
40
  - [Install](#install)
34
- - [30-second example](#30-second-example)
41
+ - [Quick start](#quick-start)
35
42
  - [Core API](#core-api)
36
43
  - [Field naming rule](#field-naming-rule)
37
44
  - [Cookbook](#cookbook)
45
+ - [Roadmap](#roadmap)
38
46
  - [Contributing](#contributing)
39
47
  - [License](#license)
40
48
 
41
- ## Install
49
+ ---
42
50
 
43
- ```bash
44
- pip install predikit
51
+ ## Why predikit?
52
+
53
+ Most ML pipelines stop at `.predict()`. Getting that prediction callable by an LLM agent — with validated inputs, correct types, and a schema the model can reason about — requires glue code that's tedious to write and easy to get wrong.
54
+
55
+ predikit handles that layer for you:
56
+
57
+ | | Without predikit | With predikit |
58
+ |--|------------------|---------------|
59
+ | **Schema** | Hand-write JSON Schema for every model | Auto-generated from your Pydantic `BaseModel` |
60
+ | **Type safety** | Manual casting, silent failures | Pydantic v2 validation with clear error messages |
61
+ | **LLM integration** | OpenAI / LangChain boilerplate per model | `.to_openai()` / `.to_langchain()` in one line |
62
+ | **Ensemble routing** | Custom aggregation logic per project | `ModelEnsemble` with 5 built-in strategies |
63
+ | **Confidence handling** | Write your own threshold checks | `confidence_threshold` + `on_low_confidence` |
64
+ | **Model registries** | Manual MLflow / Snowflake registry calls | `from_mlflow()` / `from_snowflake()` loaders |
65
+ | **Async** | `asyncio.get_event_loop().run_in_executor(...)` | `await tool.ainvoke(inputs)` |
66
+
67
+ ---
68
+
69
+ ## Works with
70
+
71
+ predikit is designed to plug into the tools your team already uses:
72
+
73
+ **Models** — scikit-learn · XGBoost
74
+
75
+ **LLM frameworks** — OpenAI function calling · LangChain · any tool-calling API that accepts JSON Schema
76
+
77
+ **Model registries** — MLflow Model Registry · Snowflake Model Registry
78
+
79
+ **Validation** — Pydantic v2
45
80
 
46
- # With XGBoost support
47
- pip install predikit[xgboost]
81
+ **Async** `asyncio`-compatible via `ainvoke()`
48
82
 
49
- # With LangChain support
50
- pip install predikit[langchain]
83
+ ---
51
84
 
52
- # With MLflow Model Registry support
53
- pip install predikit[mlflow]
85
+ ## Install
86
+
87
+ ```bash
88
+ pip install predikit
54
89
 
55
- # With Snowflake Model Registry support
56
- pip install predikit[snowflake]
90
+ # Optional extras
91
+ pip install predikit[xgboost] # XGBoost support
92
+ pip install predikit[langchain] # LangChain StructuredTool export
93
+ pip install predikit[mlflow] # MLflow Model Registry loader
94
+ pip install predikit[snowflake] # Snowflake Model Registry loader
57
95
  ```
58
96
 
59
- ## 30-second example
97
+ ---
98
+
99
+ ## Quick start
60
100
 
61
101
  ```python
62
102
  from pydantic import BaseModel, Field
@@ -97,6 +137,8 @@ tool.invoke({
97
137
  # → {"species": 0}
98
138
  ```
99
139
 
140
+ ---
141
+
100
142
  ## Core API
101
143
 
102
144
  ### `ModelTool`
@@ -155,6 +197,8 @@ ModelEnsemble(
155
197
 
156
198
  `ModelEnsemble` exposes the same `.invoke()`, `.ainvoke()`, `.to_openai()`, and `.to_langchain()` interface as `ModelTool`.
157
199
 
200
+ ---
201
+
158
202
  ## Field naming rule
159
203
 
160
204
  **Your Pydantic schema field names must exactly match the column names the model was trained on.**
@@ -184,6 +228,8 @@ Schema has: ['square_footage', 'beds', 'bathrooms'], model expects: ['sqft', 'be
184
228
 
185
229
  > **Tip:** If you trained with a numpy array (no DataFrame), predikit has no feature names to check — it uses your schema's field definition order instead.
186
230
 
231
+ ---
232
+
187
233
  ## Cookbook
188
234
 
189
235
  ### XGBoost regression
@@ -339,23 +385,41 @@ tool = from_snowflake(
339
385
 
340
386
  Pass `output_method="predict_proba"` or any other method your Snowflake model exposes. The returned `ModelTool` is identical to one built directly — all exporters, confidence routing, and ensemble strategies work as-is. Requires `pip install predikit[snowflake]`.
341
387
 
342
- ### Orlando real estate demo
388
+ ### End-to-end demo
389
+
390
+ See [`examples/03_orlando_real_estate.py`](examples/03_orlando_real_estate.py) for a full walkthrough: synthetic dataset → XGBoost training → `ModelTool` → registry → OpenAI schema → prediction.
343
391
 
344
- See [`examples/03_orlando_real_estate.py`](examples/03_orlando_real_estate.py) for a full end-to-end walkthrough: synthetic dataset → XGBoost training → `ModelTool` → registry → OpenAI schema → prediction.
392
+ ---
345
393
 
346
394
  ## Roadmap
347
395
 
348
- Planned for later releases:
396
+ ### Shipped
397
+
398
+ - [x] OpenAI function-calling schema export
399
+ - [x] LangChain `StructuredTool` export
400
+ - [x] Pydantic v2 typed I/O validation
401
+ - [x] Multi-model `ModelEnsemble` — collect / mean / vote / weighted variants
402
+ - [x] Confidence routing — `warn` / `raise` / `fallback`
403
+ - [x] Async `ainvoke()` via thread pool executor
404
+ - [x] MLflow Model Registry loader
405
+ - [x] Snowflake Model Registry loader
406
+ - [x] `predikit inspect` CLI
407
+
408
+ ### Planned
349
409
 
350
- - HuggingFace / PyTorch / TensorFlow model support
351
- - Streaming inference support
352
- - OpenAI Assistants API integration
410
+ - [ ] HuggingFace / PyTorch / TensorFlow model support
411
+ - [ ] Streaming inference support
412
+ - [ ] OpenAI Assistants API integration
413
+ - [ ] MCP server mode
414
+
415
+ ---
353
416
 
354
417
  ## Contributing
355
418
 
356
419
  See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, code style, and PR guidelines. The [CHANGELOG](CHANGELOG.md) tracks notable changes per release.
357
420
 
421
+ Issues and PRs are welcome — if you're wrapping a model type or registry that predikit doesn't support yet, open a discussion.
422
+
358
423
  ## License
359
424
 
360
425
  MIT © Tejas Tumakuru Ashok
361
-
@@ -1,4 +1,5 @@
1
1
  """Example 01 — Basic sklearn classifier wrapped as an OpenAI tool."""
2
+
2
3
  import json
3
4
 
4
5
  from pydantic import BaseModel, Field
@@ -36,7 +37,9 @@ print(json.dumps(tool.to_openai(), indent=2))
36
37
 
37
38
  # 5. Direct invocation
38
39
  print("\n=== Direct Invocation ===")
39
- result = tool.invoke({"sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2})
40
+ result = tool.invoke(
41
+ {"sepal_length": 5.1, "sepal_width": 3.5, "petal_length": 1.4, "petal_width": 0.2}
42
+ )
40
43
  print(f"Result: {result}")
41
44
 
42
45
  # 6. Plain callable
@@ -1,7 +1,8 @@
1
1
  """
2
2
  Example 02 — XGBoost regression model wrapped as a tool.
3
- Requires: pip install modelbridge[xgboost]
3
+ Requires: pip install predikit[xgboost]
4
4
  """
5
+
5
6
  import json
6
7
 
7
8
  from pydantic import BaseModel, Field
@@ -10,8 +11,8 @@ from sklearn.model_selection import train_test_split
10
11
 
11
12
  try:
12
13
  from xgboost import XGBRegressor
13
- except ImportError:
14
- raise SystemExit("XGBoost not installed. Run: pip install modelbridge[xgboost]")
14
+ except ImportError as err:
15
+ raise SystemExit("XGBoost not installed. Run: pip install predikit[xgboost]") from err
15
16
 
16
17
  from predikit import ModelTool
17
18
 
@@ -44,11 +45,13 @@ print("=== OpenAI Tool Schema ===")
44
45
  print(json.dumps(tool.to_openai(), indent=2))
45
46
 
46
47
  print("\n=== Invoke ===")
47
- result = tool.invoke({
48
- "feature_1": float(X_test[0, 0]),
49
- "feature_2": float(X_test[0, 1]),
50
- "feature_3": float(X_test[0, 2]),
51
- "feature_4": float(X_test[0, 3]),
52
- })
48
+ result = tool.invoke(
49
+ {
50
+ "feature_1": float(X_test[0, 0]),
51
+ "feature_2": float(X_test[0, 1]),
52
+ "feature_3": float(X_test[0, 2]),
53
+ "feature_4": float(X_test[0, 3]),
54
+ }
55
+ )
53
56
  print(f"Prediction: {result}")
54
57
  print(f"Actual: {y_test[0]:.2f}")
@@ -7,6 +7,7 @@ schema generation → registry export → direct invocation → callable.
7
7
 
8
8
  Requires: pip install xgboost
9
9
  """
10
+
10
11
  import json
11
12
 
12
13
  import numpy as np
@@ -16,8 +17,8 @@ from sklearn.model_selection import train_test_split
16
17
 
17
18
  try:
18
19
  from xgboost import XGBRegressor
19
- except ImportError:
20
- raise SystemExit("XGBoost not installed. Run: pip install xgboost")
20
+ except ImportError as err:
21
+ raise SystemExit("XGBoost not installed. Run: pip install xgboost") from err
21
22
 
22
23
  from predikit import ModelTool, ToolRegistry
23
24
 
@@ -27,31 +28,33 @@ from predikit import ModelTool, ToolRegistry
27
28
  rng = np.random.default_rng(42)
28
29
  n = 1_000
29
30
 
30
- sqft = rng.integers(800, 4_000, n).astype(float)
31
- bedrooms = rng.integers(1, 6, n).astype(float)
32
- bathrooms = rng.choice([1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0], n)
33
- year_built = rng.integers(1960, 2024, n).astype(float)
34
- has_pool = rng.integers(0, 2, n).astype(float)
31
+ sqft = rng.integers(800, 4_000, n).astype(float)
32
+ bedrooms = rng.integers(1, 6, n).astype(float)
33
+ bathrooms = rng.choice([1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0], n)
34
+ year_built = rng.integers(1960, 2024, n).astype(float)
35
+ has_pool = rng.integers(0, 2, n).astype(float)
35
36
  zip_code_group = rng.integers(0, 5, n).astype(float) # 0=rural … 4=prime
36
37
 
37
38
  price = (
38
39
  80 * sqft
39
40
  + 15_000 * bedrooms
40
41
  + 10_000 * bathrooms
41
- + 500 * (year_built - 1960)
42
+ + 500 * (year_built - 1960)
42
43
  + 20_000 * has_pool
43
44
  + 30_000 * zip_code_group
44
45
  + rng.normal(0, 15_000, n)
45
46
  ).clip(50_000, 1_500_000)
46
47
 
47
- df = pd.DataFrame({
48
- "sqft": sqft,
49
- "bedrooms": bedrooms,
50
- "bathrooms": bathrooms,
51
- "year_built": year_built,
52
- "has_pool": has_pool,
53
- "zip_code_group": zip_code_group,
54
- })
48
+ df = pd.DataFrame(
49
+ {
50
+ "sqft": sqft,
51
+ "bedrooms": bedrooms,
52
+ "bathrooms": bathrooms,
53
+ "year_built": year_built,
54
+ "has_pool": has_pool,
55
+ "zip_code_group": zip_code_group,
56
+ }
57
+ )
55
58
 
56
59
  X_train, X_test, y_train, y_test = train_test_split(df, price, test_size=0.2, random_state=42)
57
60
 
@@ -61,17 +64,19 @@ X_train, X_test, y_train, y_test = train_test_split(df, price, test_size=0.2, ra
61
64
  model = XGBRegressor(n_estimators=200, learning_rate=0.05, random_state=42)
62
65
  model.fit(X_train, y_train)
63
66
 
67
+
64
68
  # ---------------------------------------------------------------------------
65
69
  # 3. Input schema — field names must match DataFrame columns exactly
66
70
  # ---------------------------------------------------------------------------
67
71
  class OrlandoHouseInput(BaseModel):
68
- sqft: float = Field(description="Total square footage of the home")
69
- bedrooms: float = Field(description="Number of bedrooms")
70
- bathrooms: float = Field(description="Number of bathrooms (0.5 increments)")
71
- year_built: float = Field(description="Year the home was built")
72
- has_pool: float = Field(description="1 if the home has a pool, else 0")
72
+ sqft: float = Field(description="Total square footage of the home")
73
+ bedrooms: float = Field(description="Number of bedrooms")
74
+ bathrooms: float = Field(description="Number of bathrooms (0.5 increments)")
75
+ year_built: float = Field(description="Year the home was built")
76
+ has_pool: float = Field(description="1 if the home has a pool, else 0")
73
77
  zip_code_group: float = Field(description="Area cluster 0–4 (0=rural, 4=prime location)")
74
78
 
79
+
75
80
  # ---------------------------------------------------------------------------
76
81
  # 4. Wrap as ModelTool and register
77
82
  # ---------------------------------------------------------------------------
@@ -99,11 +104,11 @@ print(json.dumps(registry.to_openai(), indent=2))
99
104
  # 6. Run a prediction
100
105
  # ---------------------------------------------------------------------------
101
106
  sample = {
102
- "sqft": 2_200.0,
103
- "bedrooms": 3.0,
104
- "bathrooms": 2.0,
105
- "year_built": 2005.0,
106
- "has_pool": 1.0,
107
+ "sqft": 2_200.0,
108
+ "bedrooms": 3.0,
109
+ "bathrooms": 2.0,
110
+ "year_built": 2005.0,
111
+ "has_pool": 1.0,
107
112
  "zip_code_group": 3.0,
108
113
  }
109
114
 
@@ -9,6 +9,7 @@ Demonstrates the three on_low_confidence modes:
9
9
  threshold=0.999 guarantees the low-confidence path fires for illustration.
10
10
  In production, set this between 0.75 and 0.95.
11
11
  """
12
+
12
13
  from pydantic import BaseModel, Field
13
14
  from sklearn.datasets import load_iris
14
15
  from sklearn.linear_model import LogisticRegression
@@ -26,9 +27,9 @@ fallback_clf = GaussianNB().fit(X, y)
26
27
 
27
28
  class IrisInput(BaseModel):
28
29
  sepal_length: float = Field(description="Sepal length in cm")
29
- sepal_width: float = Field(description="Sepal width in cm")
30
+ sepal_width: float = Field(description="Sepal width in cm")
30
31
  petal_length: float = Field(description="Petal length in cm")
31
- petal_width: float = Field(description="Petal width in cm")
32
+ petal_width: float = Field(description="Petal width in cm")
32
33
 
33
34
 
34
35
  fallback_tool = ModelTool(
@@ -61,7 +62,9 @@ print("=== Mode: warn ===")
61
62
  result = warn_tool.invoke(sample)
62
63
  print(result)
63
64
  if result.get("_low_confidence"):
64
- print(f" → confidence {result['_confidence']:.3f} below threshold; agent should seek clarification")
65
+ print(
66
+ f" → confidence {result['_confidence']:.3f} below threshold; agent should seek clarification"
67
+ )
65
68
 
66
69
  # ---------------------------------------------------------------------------
67
70
  # Mode 2: raise — lets the calling agent handle uncertainty explicitly