Production-ready prompt management system with versioning, validation, and framework integrations for OpenAI, Anthropic, LangChain, and LiteLLM
Project description
Prompt Manager
A modern, production-ready Python 3.11+ prompt management system with Pydantic v2 validation, YAML schema support, Handlebars templating, plugin architecture, and comprehensive observability.
Features
- Type-Safe Models: Pydantic v2 with strict validation and serialization
- YAML Schema Support: Define prompts in YAML with automatic validation
- Handlebars Templating: Powerful templating with partials and helpers
- Plugin Architecture: Extensible framework integrations (OpenAI, Anthropic, LangChain, etc.)
- Versioning: Full version history with semantic versioning and changelogs
- Observability: Structured logging, metrics collection, and OpenTelemetry integration
- Async/Await: Full async support for high-performance operations
- Storage Backends: File system and in-memory storage with pluggable interface
- Caching: Optional caching layer for rendered prompts
- Protocol-Based Design: Structural subtyping for flexible integration
Framework Integrations
Seamlessly integrate with popular LLM frameworks:
- OpenAI SDK: Convert prompts to OpenAI message format for GPT models
- Anthropic SDK: Convert prompts to Claude-compatible message format
- LangChain: Convert to
PromptTemplateandChatPromptTemplatefor chain composition - LiteLLM: Multi-provider support with unified interface (100+ LLM providers)
All integrations support:
- Automatic template rendering with variables
- Framework-specific format conversion
- Role mapping and message structure validation
- Type-safe outputs with full IDE support
See Framework Integration Examples below for usage patterns.
Installation
# Core package only
pip install agentic-prompt-manager
# With specific framework integration
pip install agentic-prompt-manager[openai] # OpenAI SDK support
pip install agentic-prompt-manager[anthropic] # Anthropic SDK (Claude) support
pip install agentic-prompt-manager[langchain] # LangChain support
pip install agentic-prompt-manager[litellm] # LiteLLM multi-provider support
# With all framework integrations
pip install agentic-prompt-manager[all]
# Development installation with Poetry
poetry install --with dev -E all
Quick Start
Basic Usage
from prompt_manager import PromptManager, Prompt, PromptMetadata
from prompt_manager.core.models import PromptFormat, PromptTemplate, PromptStatus
from prompt_manager.core.registry import PromptRegistry
from prompt_manager.storage import InMemoryStorage
# Create components
storage = InMemoryStorage()
registry = PromptRegistry(storage=storage)
manager = PromptManager(registry=registry)
# Create a prompt
prompt = Prompt(
id="greeting",
version="1.0.0",
format=PromptFormat.TEXT,
status=PromptStatus.ACTIVE,
template=PromptTemplate(
content="Hello {{name}}! Welcome to {{service}}.",
variables=["name", "service"],
),
metadata=PromptMetadata(
author="System",
description="Simple greeting prompt",
tags=["greeting", "welcome"],
),
)
# Register prompt
await manager.create_prompt(prompt)
# Render prompt
result = await manager.render(
"greeting",
{"name": "Alice", "service": "Prompt Manager"},
)
print(result) # "Hello Alice! Welcome to Prompt Manager."
Chat Prompts
from prompt_manager.core.models import ChatPromptTemplate, Message, Role
chat_prompt = Prompt(
id="customer_support",
version="1.0.0",
format=PromptFormat.CHAT,
status=PromptStatus.ACTIVE,
chat_template=ChatPromptTemplate(
messages=[
Message(
role=Role.SYSTEM,
content="You are a helpful assistant for {{company}}.",
),
Message(
role=Role.USER,
content="{{user_query}}",
),
],
variables=["company", "user_query"],
),
)
await manager.create_prompt(chat_prompt)
Loading from YAML
Individual Files (Recommended):
Each prompt and schema in its own file for better organization:
project/
├── prompts/ # One YAML file per prompt
│ ├── greeting.yaml
│ ├── customer_support.yaml
│ └── code_review.yaml
└── schemas/ # One YAML file per schema
├── user_profile.yaml
├── code_review_input.yaml
└── text_summarization_output.yaml
from prompt_manager import PromptManager
from prompt_manager.storage import YAMLLoader
from pathlib import Path
# Load prompts from directory
loader = YAMLLoader(registry)
await loader.import_directory_to_registry(Path("prompts/"))
# Load schemas for validation
manager = PromptManager(registry=registry)
await manager.load_schemas(Path("schemas/"))
Single File Format:
# prompts/greeting.yaml
version: "1.0.0"
prompts:
- id: greeting
version: "1.0.0"
format: text
status: active
template:
content: "Hello {{name}}! Welcome to {{service}}."
variables:
- name
- service
metadata:
author: System
tags:
- greeting
input_schema: "user_input" # Optional validation
Versioning
# Create initial version
prompt = Prompt(id="feature", version="1.0.0", ...)
await manager.create_prompt(prompt, changelog="Initial version")
# Update and bump version
prompt.template.content = "Updated content"
await manager.update_prompt(
prompt,
bump_version=True,
changelog="Updated greeting message",
)
# Get version history
history = await manager.get_history("feature")
for version in history:
print(f"{version.version}: {version.changelog}")
Schema Validation
Validate input and output data with YAML-defined schemas. Schemas are automatically injected into prompts during rendering.
Individual Schema Files (Recommended):
# schemas/user_input.yaml
version: "1.0.0"
metadata:
description: "User input validation schema"
author: "Team"
schemas:
- name: "user_input"
version: "1.0.0"
description: "Validation for user input variables"
strict: true
fields:
- name: "username"
type: "string"
required: true
validators:
- type: "min_length"
min_value: 3
- type: "regex"
pattern: "^[a-zA-Z0-9_]+$"
error_message: "Username must be alphanumeric"
- name: "email"
type: "string"
required: true
validators:
- type: "email"
- name: "age"
type: "integer"
required: false
validators:
- type: "range"
min_value: 13
max_value: 120
Auto-Injection with Prompts:
from prompt_manager import PromptManager
# Load schemas (loads all YAML files in directory)
manager = PromptManager(registry=registry)
await manager.load_schemas(Path("schemas/"))
# Create prompt with schema reference
prompt = Prompt(
id="user_onboarding",
format=PromptFormat.TEXT,
template=PromptTemplate(content="Welcome {{username}}!"),
input_schema="user_input", # Auto-injected during render
output_schema="user_profile" # Auto-injected during render
)
# Render - schema descriptions automatically added
result = await manager.render("user_onboarding", {"username": "john_doe"})
# Result includes:
# 1. Input schema description (intro)
# 2. Main prompt content
# 3. Output schema description (ending)
Validating LLM Output:
# After getting LLM response, validate it
llm_response = {
"summary": "Brief summary of the content",
"key_points": ["Point 1", "Point 2"],
"word_count": 25
}
try:
# Validate against output schema
validated = await manager.validate_output(
"text_summarization_output",
llm_response
)
# Use validated data safely
print(f"Summary: {validated['summary']}")
except SchemaValidationError as e:
print(f"LLM returned invalid format: {e}")
# Handle validation error (retry, log, etc.)
Complete Automatic Workflow (Recommended):
# ═══════════════════════════════════════════════════════════
# ONE-TIME SETUP
# ═══════════════════════════════════════════════════════════
# Load schemas once at startup
manager = PromptManager(registry=registry)
await manager.load_schemas(Path("schemas/"))
# Define prompt in YAML with schemas
# prompts/summarizer.yaml:
# input_schema: "text_summarization_input" # Auto-validates input
# output_schema: "text_summarization_output" # Auto-validates output
# ═══════════════════════════════════════════════════════════
# PER-REQUEST FLOW (Automatic Validation!)
# ═══════════════════════════════════════════════════════════
# 1. Render prompt (INPUT AUTO-VALIDATED)
prompt_text = await manager.render("summarizer", {
"content_type": "article",
"text": "Your content here..."
})
# ✅ Input validated automatically
# ✅ Output schema injected as JSON format instructions
# 2. Send to LLM
llm_response = await openai_client.generate(prompt_text)
# 3. Parse and validate output (OUTPUT AUTO-VALIDATED)
try:
validated = await manager.render_and_parse(
"summarizer",
input_vars,
llm_response # Can be dict or JSON string
)
# ✅ Output validated automatically
# Use validated data with confidence!
except SchemaValidationError as e:
# Handle validation errors gracefully
logger.error(f"Validation failed: {e}")
What Happens Automatically:
- Input Validation:
render()validates input againstinput_schemabefore rendering - Schema Injection: Output schema is injected with JSON format instructions
- Output Validation:
render_and_parse()validates LLM response againstoutput_schema - Type Safety: All data is validated against your schemas
Supported Field Types:
string,integer,float,booleanlist(withitem_typeoritem_schema)dict(withnested_schema)enum(withallowed_values)any(no type checking)
Supported Validators:
min_length,max_length- String/list lengthrange- Numeric min/maxregex- Pattern matchingenum- Choice validationemail,url,uuid- Format validationdate,datetime- Date/time parsingcustom- Custom validator functions
Schema Features:
- Required/optional fields with
required: true/false - Default values with
default: value - Nullable fields with
nullable: true - Nested schemas for complex objects
- List validation with item types
- Custom error messages per validator
See validation README for complete documentation.
Observability
from prompt_manager.observability import (
LoggingObserver,
MetricsCollector,
OpenTelemetryObserver,
)
# Add observers
logging_observer = LoggingObserver()
metrics_collector = MetricsCollector()
otel_observer = OpenTelemetryObserver()
manager.add_observer(logging_observer)
manager.add_observer(otel_observer)
# Create manager with metrics
manager = PromptManager(
registry=registry,
metrics=metrics_collector,
)
# Get metrics
metrics = await manager.get_metrics()
print(metrics)
Framework Integration Examples
OpenAI SDK
Convert prompts to OpenAI message format for use with GPT models:
from prompt_manager import PromptManager
from prompt_manager.integrations import OpenAIIntegration
import openai
# Setup
manager = PromptManager(registry=registry)
integration = OpenAIIntegration(manager.template_engine)
# Get prompt
prompt = await manager.get_prompt("customer_support")
# Convert to OpenAI format
messages = await integration.convert(prompt, {
"company": "Acme Corp",
"user_query": "How do I reset my password?"
})
# Use with OpenAI SDK
client = openai.AsyncOpenAI()
response = await client.chat.completions.create(
model="gpt-4",
messages=messages
)
print(response.choices[0].message.content)
Anthropic SDK (Claude)
Convert prompts to Anthropic's Claude format:
from prompt_manager.integrations import AnthropicIntegration
import anthropic
# Setup integration
integration = AnthropicIntegration(manager.template_engine)
# Convert prompt (returns dict with 'system' and 'messages' keys)
claude_format = await integration.convert(prompt, {
"company": "Acme Corp",
"user_query": "Explain quantum computing"
})
# Use with Anthropic SDK
client = anthropic.AsyncAnthropic()
response = await client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=1024,
system=claude_format.get("system"), # System message (if present)
messages=claude_format["messages"] # User/assistant messages
)
print(response.content[0].text)
LangChain
Convert prompts to LangChain templates for chain composition:
from prompt_manager.integrations import LangChainIntegration
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
# Setup integration
integration = LangChainIntegration(manager.template_engine)
# Convert to LangChain ChatPromptTemplate
chat_template = await integration.convert(prompt, {})
# Use in LCEL chain
chain = chat_template | ChatOpenAI(model="gpt-4") | StrOutputParser()
# Invoke chain
result = await chain.ainvoke({
"company": "Acme Corp",
"user_query": "What are your pricing plans?"
})
print(result)
LiteLLM
Use with LiteLLM for multi-provider support:
from prompt_manager.integrations import LiteLLMIntegration
import litellm
# Setup integration
integration = LiteLLMIntegration(manager.template_engine)
# Convert to LiteLLM format (OpenAI-compatible)
messages = await integration.convert(prompt, {
"company": "Acme Corp",
"user_query": "Compare your plans"
})
# Use with any LLM provider via LiteLLM
response = await litellm.acompletion(
model="gpt-4", # or "claude-3", "gemini-pro", etc.
messages=messages
)
print(response.choices[0].message.content)
Error Handling
All integrations provide clear error messages:
from prompt_manager.exceptions import (
IntegrationError,
IntegrationNotAvailableError,
ConversionError,
IncompatibleFormatError,
)
try:
messages = await integration.convert(prompt, variables)
except IntegrationNotAvailableError as e:
# Framework not installed
print(e) # "OpenAI integration not available. Install with: pip install agentic-prompt-manager[openai]"
except IncompatibleFormatError as e:
# Prompt format not supported by framework
print(e) # "Anthropic requires CHAT format"
except ConversionError as e:
# Conversion failed (missing variable, template error, etc.)
print(e) # "Missing required variable 'company'"
For complete examples, see examples/integrations/ directory.
For creating custom integrations, see Integration Guide.
Architecture
Core Components
-
Models (
core/models.py): Pydantic v2 models with validationPrompt: Main prompt model with versioningPromptTemplate: Text template configurationChatPromptTemplate: Chat message templatesPromptVersion: Version trackingPromptExecution: Execution records
-
Protocols (
core/protocols.py): Protocol-based interfacesTemplateEngineProtocol: Template renderingStorageBackendProtocol: Storage operationsVersionStoreProtocol: Version managementObserverProtocol: Lifecycle hooksPluginProtocol: Framework integrationsCacheProtocol: Caching layerMetricsCollectorProtocol: Metrics collection
-
Registry (
core/registry.py): In-memory prompt registry- Fast access with optional persistence
- Filtering by tags, status, category
- Version management
-
Manager (
core/manager.py): Main orchestrator- High-level API
- Rendering with caching
- Version management
- Plugin integration
- Observability hooks
-
Template Engine (
core/template.py): Handlebars rendering- Variable extraction
- Partial templates
- Chat message rendering
Storage Backends
- InMemoryStorage: Fast in-memory storage for testing
- FileSystemStorage: JSON file-based persistence
- YAMLLoader: Load prompts from YAML schemas
Plugin System
Plugins enable framework-specific rendering:
from prompt_manager.plugins import BasePlugin
class OpenAIPlugin(BasePlugin):
def __init__(self):
super().__init__(name="openai", version="1.0.0")
async def render_for_framework(self, prompt, variables):
# Convert to OpenAI format
...
Observability
Three observer implementations:
- LoggingObserver: Structured logging with structlog
- MetricsCollector: In-memory metrics aggregation
- OpenTelemetryObserver: Distributed tracing
Type Safety
Full mypy strict mode compliance:
mypy src/prompt_manager
All public APIs have complete type annotations using:
- Generic types with
TypeVar - Protocol definitions for duck typing
- Pydantic v2 models for runtime validation
Literaltypes for constantsTypedDictfor structured dictionaries
Testing
# Run tests with coverage
pytest
# Run specific test types
pytest -m unit
pytest -m integration
pytest -m benchmark
# Check coverage
pytest --cov=prompt_manager --cov-report=html
Performance
- Async operations: All I/O operations are async
- Caching layer: Optional caching for rendered prompts
- Memory efficient: Generator-based iteration
- Type checking: Zero runtime overhead with proper annotations
Development
# Install dependencies
poetry install
# Run linters
ruff check src/
black --check src/
mypy src/
# Format code
black src/
ruff check --fix src/
# Security scan
bandit -r src/
# Pre-commit hooks
pre-commit install
pre-commit run --all-files
Project Structure
prompt-manager/
├── src/
│ └── prompt_manager/
│ ├── __init__.py
│ ├── exceptions.py
│ ├── core/
│ │ ├── __init__.py
│ │ ├── models.py # Pydantic models
│ │ ├── protocols.py # Protocol definitions
│ │ ├── registry.py # Prompt registry
│ │ ├── manager.py # Main manager
│ │ └── template.py # Template engine
│ ├── storage/
│ │ ├── __init__.py
│ │ ├── memory.py # In-memory storage
│ │ ├── file.py # File system storage
│ │ └── yaml_loader.py # YAML import
│ ├── versioning/
│ │ ├── __init__.py
│ │ └── store.py # Version store
│ ├── plugins/
│ │ ├── __init__.py
│ │ ├── base.py # Base plugin
│ │ └── registry.py # Plugin registry
│ └── observability/
│ ├── __init__.py
│ ├── logging.py # Structured logging
│ ├── metrics.py # Metrics collector
│ └── telemetry.py # OpenTelemetry
├── tests/ # Test suite
├── pyproject.toml # Project configuration
└── README.md
License
MIT License
Contributing
Contributions welcome! Please ensure:
- Type hints on all functions
- Docstrings in Google style
- Test coverage > 90%
- Mypy strict mode passes
- Black formatting applied
- Security scans pass
Roadmap
- Additional plugin implementations (OpenAI, Anthropic, LangChain)
- Redis cache backend
- PostgreSQL storage backend
- A/B testing framework
- Prompt analytics dashboard
- CLI tool for management
- REST API server
- Performance optimizations
- Advanced templating features
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 agentic_prompt_manager-0.1.0.tar.gz.
File metadata
- Download URL: agentic_prompt_manager-0.1.0.tar.gz
- Upload date:
- Size: 59.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e2f92debb386f841455bc9636441b28471c89d9c922db2682543acbebadfd13
|
|
| MD5 |
8f650d014ea1c3480797896385c31947
|
|
| BLAKE2b-256 |
8f715cd2e990ad164e4548989817ba91b87ddb0666128ddbb5e1b24c83ba8ca4
|
File details
Details for the file agentic_prompt_manager-0.1.0-py3-none-any.whl.
File metadata
- Download URL: agentic_prompt_manager-0.1.0-py3-none-any.whl
- Upload date:
- Size: 72.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5537763eb3f26c91fe270ae8c283bc4be92cafcf85539e6f71c7d36e2816e55
|
|
| MD5 |
36ec88274c8ec7fb0ccf6443935952c1
|
|
| BLAKE2b-256 |
f31e2dff8626c95f787a0d7526a495597246a60b10509017d37590e4a28b3fcf
|