A package for building and managing tools for Large Language Models
Project description
🌟 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!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file llmrepo-0.1.0.tar.gz.
File metadata
- Download URL: llmrepo-0.1.0.tar.gz
- Upload date:
- Size: 11.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e42e398cd5a71d65303ac4bdbc412d680a78ebe23fa3d3e95e016c05c00fe7e7
|
|
| MD5 |
ccff41bf34c7b2e89aee5efb07d8d5f8
|
|
| BLAKE2b-256 |
705fe91c365255edd882375c003b226b4ba6f1036f5918ec1e388185d0681541
|
File details
Details for the file llmrepo-0.1.0-py3-none-any.whl.
File metadata
- Download URL: llmrepo-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
966ce488c4ccc86a57c2b4688ca2f85def917b40306e0339be9d92df6440fc71
|
|
| MD5 |
d6bfabae0a43cf0a2457291c0dab55fc
|
|
| BLAKE2b-256 |
832cbefa7e775638d44c3526376bad0aff17b6b29b19a9531a4088232c9d1c0a
|