🌟 LLMRepo - Structured Tool Integration for Large Language Models
LLMRepo.tools is your swiss army knife 🛠️ for building structured, type-safe tool integrations with Large Language Models (LLMs). Designed specifically for modern AI workflows, it provides seamless integration with platforms like OpenAI while offering enterprise-grade validation and monitoring capabilities.
🚀 Features
- Type-Safe Tools 🔒 - Pydantic-powered parameter validation
- Observability 📊 - Built-in event system for monitoring
- Async First ⚡ - Native support for asynchronous operations
- Context Management 🧠 - Shared state across tool executions
- OpenAI Ready 🤖 - Automatic format conversion for function calling
- Modular Design 🧱 - Toolbox system for organizing tool collections
📦 Installation
pip install llmrepo
🎯 Quick Start
Create Your First Tool
from llmrepo.tools import BaseTool, ToolParameter
class WeatherTool(BaseTool):
"""Get current weather conditions"""
name = "get_weather"
description = "Fetch current weather data for any location"
parameters = {
"location": ToolParameter(
name="location",
type="string",
description="City and country (e.g., 'London, UK')",
required=True
),
"units": ToolParameter(
name="units",
type="string",
description="Temperature units system",
enum=["celsius", "fahrenheit"],
default="celsius"
)
}
def invoke(self, location: str, units: str = "celsius") -> str:
"""Actual implementation would call weather API here"""
return f"Weather in {location}: 22°{units[0].upper()}"
Execute and Monitor
tool = WeatherTool()
# Attach event listeners
tool.on("invoke:before", lambda: print("🌤️ Checking weather..."))
tool.on("invoke:after", lambda result: print(f"Result: {result}"))
# Call your tool
print(tool.invoke("Paris, France")) # Output: Weather in Paris: 22°C
🧠 Core Concepts
🔧 Tools Architecture
Define atomic operations with strict input validation:
class CalculatorTool(BaseTool):
name = "calculator"
description = "Perform mathematical operations"
parameters = {
"numbers": ToolParameter(
type="array",
description="List of operands",
required=True
),
"operation": ToolParameter(
type="string",
enum=["add", "subtract", "multiply"],
required=True
)
}
def invoke(self, numbers: list[float], operation: str) -> float:
match operation:
case 'add': return sum(numbers)
case 'multiply': return math.prod(numbers)
case _: raise ValueError("Invalid operation")
🧰 Toolbox Orchestration
Group related tools and share context:
from llmrepo.tools import BaseToolbox
class PhysicsToolbox(BaseToolbox):
weather = WeatherTool()
calc = CalculatorTool()
def init(self, api_key: str):
super().__init__()
self.context["api_key"] = api_key # Shared across tools
# Usage
toolbox = PhysicsToolbox(api_key="my-secret-key")
toolbox.weather.invoke("Berlin, DE")
Tools can still have their own context, and this context will be merged with the toolbox's context.
# only updates the weather tool's context
toolbox.weather.context["api_key"] = "my-secret-key"
# only updates the calc tool's context
toolbox.calc.context["api_key"] = "my-secret-key"
# updates both contexts
toolbox.context["api_key"] = "my-secret-key"
toolbox.context["api_key"] = "my-secret-key"
If toolbox is initialized with a context, this context can be changed by setting the context on the toolbox or the tool (since it was already defined).
toolbox = PhysicsToolbox(context={"api_key": "my-secret-key"})
# this updates the context of api_key for all tools
toolbox.weather.context["api_key"] = "my-secret-key"
🔔 Event System
Monitor tool lifecycle events:
def log_usage(tool_name: str):
print(f"📡 {tool_name} triggered!")
toolbox.on("invoke:before", lambda tool: log_usage(tool.name))
Available Events
| Event | Description |
|---|---|
invoke:before |
Pre-sync execution hook |
invoke:after |
Post-sync execution hook |
ainvoke:before |
Pre-async execution hook |
ainvoke:after |
Post-async execution hook |
validation_error |
Parameter validation failure |
runtime_error |
Unhandled exception during execution |
⚡ Advanced Patterns
Async Superpowers
class AsyncSearchTool(BaseTool):
async def ainvoke(self, query: str) -> dict:
async with aiohttp.ClientSession() as session:
async with session.get(f"https://api.com/search?q={query}") as response:
return await response.json()
OpenAI Integration
# Convert toolbox to OpenAI-compatible format
functions = PhysicsToolbox().as_openai_tools()
response = openai.ChatCompletion.create(
model="gpt-4",
messages=[{"role": "user", "content": "What's 18°C in Fahrenheit?"}],
functions=functions,
function_call={"name": "temperature_converter"}
)
Context-Aware Execution
class PersonalizedGreeter(BaseTool):
def invoke(self) -> str:
user = self.context.get("user")
return f"Hello {user['name']}! You have {user['messages']} unread messages."
toolbox = PhysicsToolbox(context={"user": {"name": "Alice", "messages": 3}})
print(toolbox.personalized_greeter.invoke()) # Hello Alice! You have 3 unread messages.
🤝 Contributing
We welcome contributions! Please follow these steps:
- Fork the repository 🍴
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request 🌟
Please ensure tests pass using pytest tests/ and update documentation accordingly.
Running Tests
# if you are developing locally
pip install -e .
# run tests
pytest tests/
📜 License
MIT License - See LICENSE for details.
Built with ❤️ by AI enthusiasts | Documentation improvements welcome!
Metadata
Release files for llmrepo 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| llmrepo-0.1.0.tar.gz | 11.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| llmrepo-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 20.3 kB
Release files / llmrepo-0.1.0.tar.gz
| Download URL | llmrepo-0.1.0.tar.gz |
|---|---|
| Size | 11.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e42e398cd5a71d65303ac4bdbc412d680a78ebe23fa3d3e95e016c05c00fe7e7
|
|
BLAKE2b-256 checksum How to use checksums |
705fe91c365255edd882375c003b226b4ba6f1036f5918ec1e388185d0681541
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.10.13
|
Release files / llmrepo-0.1.0-py3-none-any.whl
| Download URL | llmrepo-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
966ce488c4ccc86a57c2b4688ca2f85def917b40306e0339be9d92df6440fc71
|
|
BLAKE2b-256 checksum How to use checksums |
832cbefa7e775638d44c3526376bad0aff17b6b29b19a9531a4088232c9d1c0a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.10.13
|
Security for llmrepo 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.