# LLMUtils A Python utility library for managing LLM prompts with Jinja2 template support and JSON schemas. ## Installation ### Install using uv ```bash uv add git+https://git.project-insanity.de/gmarth/LLMUtils.git ``` ### Install using pip ```bash pip install git+https://git.project-insanity.de/gmarth/LLMUtils.git ``` ## Features - **Jinja2 Template Engine**: Full support for loops, conditionals, filters, and complex data structures - **Smart Prompt Management**: Load and manage prompt templates with variable substitution - **On-demand Loading**: Prompts are loaded lazily at runtime for better performance - **Caching Support**: Optional caching to avoid repeated disk reads - **JSON Schema Support**: Associate structured output schemas with prompts - **Variable Validation**: Automatic validation of required template variables - **Flexible API**: Fill variables at retrieval or on-demand ## Quick Start ### Basic Usage ```python from llmutils.prompt_manager import PromptManager # Get a prompt template result = PromptManager.get_prompt('greeting') print(result.variables) # See required variables: {'name', 'age'} print(result.template) # View the template: "Hello {{name}}, you are {{age}} years old" # Fill the template filled = result.fill(name='Alice', age=30) print(filled) # "Hello Alice, you are 30 years old" ``` ### Pre-filling Variables ```python # Fill variables during retrieval result = PromptManager.get_prompt('greeting', name='Alice', age=30) print(result.prompt) # Already filled: "Hello Alice, you are 30 years old" ``` ### Validation ```python result = PromptManager.get_prompt('greeting') # Check if variables are valid if not result.validate(name='Alice'): missing = result.get_missing_variables(name='Alice') print(f"Missing variables: {missing}") # {'age'} # Fill with all required variables filled = result.fill(name='Alice', age=30) ``` ### Advanced Jinja2 Features ```python # Using lists and loops result = PromptManager.get_prompt('task_list') filled = result.fill( tasks=['Write code', 'Review PR', 'Deploy'], priority='high' ) # Using conditionals result = PromptManager.get_prompt('status_report') filled = result.fill( error='Connection timeout', # Will show error message items=[] # Will show "No items" ) # Using complex nested data result = PromptManager.get_prompt('user_profile') filled = result.fill( user={ 'name': 'Alice', 'roles': ['admin', 'developer'], 'projects': [ {'name': 'Project A', 'status': 'active'}, {'name': 'Project B', 'status': 'completed'} ] } ) ``` ### JSON Schema Support ```python # Get prompt with associated schema result = PromptManager.get_prompt('task_prompt') if result.schema: print("This prompt has a structured output schema") print(result.schema) # The JSON schema dictionary ``` ## Configuration ```python from pathlib import Path from llmutils.prompt_manager import PromptManager # Configure custom prompts directory (default: ./prompts) PromptManager.configure(path=Path('/custom/prompts/location')) # Disable caching for development PromptManager.configure(caching=False) # Clear cache to force reload PromptManager.reload_prompts() ``` ## Prompt Files Place your prompt templates in the `prompts/` directory: - `prompts/greeting.md` - Markdown file with template - `prompts/greeting.json` - Optional JSON schema for structured output ### Simple Template Example (`greeting.md`): ```markdown Hello {{name}}, You are {{age}} years old. ``` ### Jinja2 Template Examples #### Lists and Loops (`task_list.md`): ```markdown Priority: {{ priority }} Tasks to complete: {% for task in tasks %} - {{ task }} {% endfor %} Total: {{ tasks | length }} tasks ``` #### Conditionals (`status_report.md`): ```markdown {% if error %} ⚠️ ERROR: {{ error }} {% else %} ✅ All systems operational {% endif %} {% if items %} Items ({{ items | length }}): {% for item in items %} {{ loop.index }}. {{ item }} {% endfor %} {% else %} No items to process. {% endif %} ``` #### Complex Data (`user_profile.md`): ```markdown # User: {{ user.name }} ## Roles {{ user.roles | join(', ') }} ## Projects {% for project in user.projects %} - {{ project.name }} [{{ project.status | upper }}] {% endfor %} ``` ### JSON Schema Example (`greeting.json`): ```json { "type": "object", "properties": { "response": { "type": "string" } } } ``` ## API Reference ### ManagedPrompt Class The `ManagedPrompt` dataclass returned by `get_prompt()`: - `template: str` - The original Jinja2 template string - `name: str` - The prompt name - `variables: Set[str]` - Required template variables (auto-extracted from Jinja2) - `schema: Optional[Dict]` - Associated JSON schema - `prompt: str` - Property that returns filled prompt or template - `fill(**kwargs) -> str` - Fill template with variables using Jinja2 - `validate(**kwargs) -> bool` - Check if all variables provided - `get_missing_variables(**kwargs) -> Set[str]` - Get missing variables ### PromptManager Methods - `get_prompt(prompt_name, **kwargs) -> ManagedPrompt` - Get a prompt template - `get_schema(prompt_name) -> Optional[Dict]` - Get just the schema - `has_schema(prompt_name) -> bool` - Check if prompt has schema - `list_prompts() -> Dict` - List all available prompts - `get_prompt_info(prompt_name) -> Dict` - Get detailed prompt information - `configure(path=None, caching=None)` - Configure settings - `reload_prompts()` - Clear the cache ### Jinja2 Template Features The library supports all standard Jinja2 features: #### Filters - `{{ items | length }}` - Get length of list - `{{ name | upper }}` - Convert to uppercase - `{{ name | lower }}` - Convert to lowercase - `{{ skills | join(', ') }}` - Join list items - `{{ data | tojson }}` - Convert to JSON - `{{ price | round(2) }}` - Round numbers #### Loops - `{% for item in items %}...{% endfor %}` - Iterate over lists - `{{ loop.index }}` - Current iteration (1-indexed) - `{{ loop.index0 }}` - Current iteration (0-indexed) - `{% for key, value in dict.items() %}...{% endfor %}` - Iterate over dictionaries #### Conditionals - `{% if condition %}...{% endif %}` - Simple conditional - `{% if condition %}...{% else %}...{% endif %}` - If/else - `{% if condition %}...{% elif other %}...{% else %}...{% endif %}` - Multiple conditions ## License MIT