A library for validating agent outputs against schemas
Project description
๐ Agent Validator
A simple drop-in tool to validate LLM/agent outputs against schemas with automatic retries, logging, and optional cloud monitoring.
โจ Features
- ๐ Schema Validation: Validate JSON outputs against Python dict schemas
- ๐ Automatic Retries: Retry failed validations with exponential backoff
- ๐ง Type Coercion: Optional safe type coercion (e.g.,
"42"โ42) - ๐ Local Logging: JSON Lines logging with automatic redaction
- โ๏ธ Cloud Monitoring: Optional cloud logging with secure authentication
- ๐ ๏ธ CLI Tools: Command-line interface for testing and log management
- ๐ก๏ธ Size Limits: Configurable limits to prevent abuse
๐ Quick Start
๐ฆ Installation
pip install agent-validator
๐ป Basic Usage
from agent_validator import validate, Schema, ValidationMode
# Define your schema
schema = Schema({
"name": str,
"age": int,
"email": str,
"tags": [str]
})
# Validate agent output
try:
result = validate(
agent_output, # Your agent's output (string or dict)
schema,
retry_fn=call_agent, # Function to retry if validation fails
retries=2,
mode=ValidationMode.COERCE, # Allow type coercion
context={"correlation_id": "abc123"} # Optional correlation ID for tracking
)
print("โ
Validation successful!")
print(result)
except ValidationError as e:
print(f"โ Validation failed: {e}")
print(f"Correlation ID: {e.correlation_id}") # For debugging
๐ฅ๏ธ CLI Usage
# Test validation with files
agent-validator test schema.json input.json --mode COERCE
# View recent logs
agent-validator logs -n 20
# View cloud logs
agent-validator cloud-logs -n 20
# Open web dashboard (secure proxy)
agent-validator dashboard
# Generate correlation ID
agent-validator id
# Configure cloud logging
agent-validator config --set-license-key YOUR_LICENSE_KEY
agent-validator config --set-log-to-cloud true
๐ Schema Definition
Schemas are defined using Python dictionaries with type annotations:
schema = Schema({
"name": str, # Required string field
"age": int, # Required integer field
"email": str, # Required string field
"is_active": bool, # Required boolean field
"score": float, # Required float field
"tags": [str], # List of strings
"metadata": None, # Optional field (can be omitted)
"address": { # Nested object
"street": str,
"city": str,
"zip": str
},
"scores": [int] # List of integers
})
๐ฏ Supported Types
- Primitives:
str,int,float,bool - Lists:
[type]for lists of that type - Objects:
dictfor nested objects - Optional:
Nonefor optional fields
๐ Schema File Formats
When using the CLI with JSON files, you can use either format:
Direct Schema Format (Recommended)
{
"name": "string",
"age": "integer",
"email": "string",
"is_active": "boolean",
"tags": ["string"],
"metadata": {
"source": "string",
"version": "string"
}
}
Wrapped Schema Format
{
"schema": {
"name": "string",
"age": "integer",
"email": "string",
"is_active": "boolean"
}
}
Supported string types: string, integer, int, float, number, boolean, bool, list, array, dict, object
๐ Validation Modes
๐ซ Strict Mode (Default)
No type coercion allowed. Input must match schema exactly.
schema = Schema({"age": int})
data = {"age": "30"} # String instead of int
# This will fail
validate(data, schema, mode=ValidationMode.STRICT)
๐ง Coerce Mode
Safe type coercion is performed:
schema = Schema({"age": int, "is_active": bool})
data = {"age": "30", "is_active": "true"}
# This will succeed and coerce types
result = validate(data, schema, mode=ValidationMode.COERCE)
# result = {"age": 30, "is_active": True}
๐ Coercion Rules
| Input Type | Target Type | Coercion |
|---|---|---|
"42" |
int |
42 |
"42.5" |
float |
42.5 |
"true" |
bool |
True |
"false" |
bool |
False |
"1" |
bool |
True |
"0" |
bool |
False |
"yes" |
bool |
True |
"no" |
bool |
False |
"on" |
bool |
True |
"off" |
bool |
False |
๐ Retry Logic
When validation fails and a retry_fn is provided, the system will automatically retry:
def call_agent(prompt: str, context: dict) -> str:
"""Your agent function that returns JSON string."""
# Call your LLM/agent here
return json.dumps({"name": "John", "age": 30})
result = validate(
malformed_output,
schema,
retry_fn=call_agent,
retries=2, # Retry up to 2 times
timeout_s=20 # 20 second timeout per attempt
)
โก Retry Behavior
- Exponential Backoff: Delays increase with each retry (0.5s, 1s, 2s)
- Jitter: Random variation to prevent thundering herd
- Timeout: Per-attempt timeout to prevent hanging
- Context Preservation: Original context is passed to retry function
๐ Logging
๐พ Local Logging
All validation attempts are logged to ~/.agent_validator/logs/YYYY-MM-DD.jsonl:
{
"ts": "2023-12-01T10:30:00Z",
"correlation_id": "abc123-def456",
"valid": true,
"errors": [],
"attempts": 1,
"duration_ms": 150,
"mode": "coerce",
"limits": {
"max_output_bytes": 131072,
"max_str_len": 8192,
"max_list_len": 2048,
"max_dict_keys": 512
},
"context": { "correlation_id": "abc123" },
"output_sample": "{\"name\": \"John\", \"age\": 30}"
}
Correlation IDs are automatically generated for each validation attempt and help you:
- ๐ Track specific validations across logs and error messages
- ๐ Debug issues by correlating errors with specific validation attempts
- ๐ Monitor performance by tracking validation duration and retry attempts
- ๐ Link related operations when using retry functions
When viewing logs with agent-validator logs, logs are displayed in a clear table format:
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโ
โ Timestamp โ Status โ Correlation โ Mode โ Attempts โ Duration โ Errors โ Size โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโค
โ 2025-08-30 18:40:00 โ โ โ none โ strict โ 1 โ 0ms โ 2 โ 45B โ
โ 2025-08-30 18:40:00 โ โ โ none โ coerce โ 1 โ 0ms โ 0 โ 45B โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโ
Correlation IDs are truncated for readability and show [none] when not set.
โ๏ธ Cloud Logging
Enable cloud logging for monitoring and recovery:
from agent_validator import Config
config = Config(
log_to_cloud=True,
license_key="your-license-key",
cloud_endpoint="https://api.agentvalidator.dev"
)
result = validate(
agent_output,
schema,
log_to_cloud=True,
config=config
)
๐ Webhook Secret Management
For enhanced security, generate a webhook secret for HMAC signature validation:
# Generate a new webhook secret
agent-validator webhook --generate
# Check webhook status
agent-validator webhook --status
# Show current webhook secret
agent-validator webhook --show
# Revoke webhook secret
agent-validator webhook --revoke
Security Features:
- โ One-time display: Webhook secrets are only shown once when generated
- โ Secure storage: Secrets are stored encrypted in the database
- โ User isolation: Each license key has its own webhook secret
- โ Revocation: Users can revoke and regenerate secrets as needed
Using HMAC Signatures
Once you have a webhook secret, requests can include an HMAC signature:
import hmac
import hashlib
# Create signature
signature = hmac.new(
webhook_secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
# Include in request headers
headers = {
"license-key": "your-license-key",
"x-signature": signature
}
Security Notes
- One-time display: Webhook secrets are only shown once when generated
- Secure storage: Secrets are stored encrypted in the database
- User isolation: Each license key has its own webhook secret
- Revocation: Users can revoke and regenerate secrets as needed
๐ Web Dashboard
Access your validation logs through a secure web dashboard:
# Configure your license key
agent-validator config --set-license-key your-license-key
# Open dashboard with secure local proxy
agent-validator dashboard
This opens a local proxy server at http://localhost:8080 that securely forwards requests to the cloud API with proper authentication headers. The dashboard shows:
- Recent validation attempts
- Success/failure rates
- Performance metrics
- Error details
- Correlation IDs for debugging
Security Features:
- โ No credentials in URLs
- โ Secure header authentication
- โ User data isolation
- โ Local proxy prevents credential exposure
โ๏ธ Configuration
๐ Environment Variables
export AGENT_VALIDATOR_LICENSE_KEY="your-license-key"
export AGENT_VALIDATOR_WEBHOOK_SECRET="your-webhook-secret"
export AGENT_VALIDATOR_LOG_TO_CLOUD="1"
export AGENT_VALIDATOR_ENDPOINT="https://api.agentvalidator.dev"
export AGENT_VALIDATOR_MAX_OUTPUT_BYTES="131072"
export AGENT_VALIDATOR_MAX_STR_LEN="8192"
export AGENT_VALIDATOR_MAX_LIST_LEN="2048"
export AGENT_VALIDATOR_MAX_DICT_KEYS="512"
export AGENT_VALIDATOR_TIMEOUT_S="20"
export AGENT_VALIDATOR_RETRIES="2"
๐ Configuration File
Configuration is stored in ~/.agent_validator/config.toml:
max_output_bytes = 131072
max_str_len = 8192
max_list_len = 2048
max_dict_keys = 512
log_to_cloud = false
cloud_endpoint = "https://api.agentvalidator.dev"
timeout_s = 20
retries = 2
license_key = "your-license-key"
webhook_secret = "your-webhook-secret"
๐ Configuration Precedence
Configuration values are loaded in the following order (highest to lowest priority):
-
CLI Arguments (highest priority)
agent-validator test schema.json input.json --mode COERCE --timeout-s 30
-
Environment Variables
export AGENT_VALIDATOR_MODE="COERCE" export AGENT_VALIDATOR_TIMEOUT_S="30"
-
Configuration File (lowest priority)
# ~/.agent_validator/config.toml mode = "STRICT" timeout_s = 20
Example: If you have timeout_s = 20 in your config file, but set export AGENT_VALIDATOR_TIMEOUT_S="30", the environment variable (30 seconds) will take precedence.
Note: CLI arguments always override environment variables and config file settings.
๐ Security & Privacy
๐ซ Redaction
Sensitive data is automatically redacted before logging:
- API Keys:
sk-1234567890abcdefโ[REDACTED] - JWT Tokens:
Bearer eyJ...โ[REDACTED] - Emails:
john@example.comโj***n@example.com - Phone Numbers:
+1-555-123-4567โ***-***-4567 - SSNs:
123-45-6789โ***-**-6789 - Credit Cards:
1234-5678-9012-3456โ************3456 - Passwords:
secret123โ[REDACTED]
๐ง Custom Redaction Patterns
from agent_validator.redact import add_redaction_pattern
# Add custom pattern
add_redaction_pattern("custom_token", r"custom-[a-zA-Z0-9]{20,}")
๐ Size Limits
Default limits to prevent abuse:
| Limit | Default | Description |
|---|---|---|
max_output_bytes |
131,072 | Total JSON size in bytes |
max_str_len |
8,192 | Maximum string length |
max_list_len |
2,048 | Maximum list length |
max_dict_keys |
512 | Maximum dictionary keys |
โ ๏ธ Error Handling
๐จ ValidationError
Raised when validation fails after all retries:
from agent_validator import ValidationError
try:
result = validate(data, schema)
except ValidationError as e:
print(f"Path: {e.path}")
print(f"Reason: {e.reason}")
print(f"Attempt: {e.attempt}")
print(f"Correlation ID: {e.correlation_id}")
๐ SchemaError
Raised when schema definition is invalid:
from agent_validator import SchemaError
try:
schema = Schema({"name": bytes}) # Unsupported type
except SchemaError as e:
print(f"Schema error: {e}")
โ๏ธ CloudLogError
Raised when cloud logging fails (non-fatal):
from agent_validator import CloudLogError
try:
result = validate(data, schema, log_to_cloud=True)
except CloudLogError as e:
print(f"Cloud logging failed: {e}")
# Validation still succeeds
๐ก Examples
๐ฏ Basic Example
from agent_validator import validate, Schema, ValidationMode
def call_agent(prompt: str, context: dict) -> str:
"""Mock agent function."""
import random
if random.random() < 0.3:
return "This is not valid JSON"
return '{"name": "John", "age": 30, "email": "john@example.com"}'
schema = Schema({
"name": str,
"age": int,
"email": str
})
result = validate(
call_agent("", {}),
schema,
retry_fn=call_agent,
retries=2,
mode=ValidationMode.COERCE
)
โ๏ธ With Cloud Logging
from agent_validator import validate, Schema, Config
config = Config(
log_to_cloud=True,
license_key=os.getenv("AGENT_VALIDATOR_LICENSE_KEY")
)
schema = Schema({
"user": {
"name": str,
"age": int,
"preferences": {
"theme": str,
"notifications": bool
}
}
})
result = validate(
agent_output,
schema,
log_to_cloud=True,
config=config,
context={"user_id": "123", "environment": "production"}
)
๐ฅ๏ธ CLI Reference
๐ ๏ธ Commands
# Test validation
agent-validator test <schema.json> <input.json> [--mode STRICT|COERCE]
# View local logs
agent-validator logs [-n <number>] [--clear]
# View cloud logs
agent-validator cloud-logs [-n <number>]
# Open web dashboard
agent-validator dashboard [--port <port>] [--url] [--open]
# Generate correlation ID
agent-validator id
# Manage configuration
agent-validator config [--show] [--show-secrets] [--set-license-key <key>] [--set-endpoint <url>] [--set-webhook-secret <secret>] [--set-log-to-cloud <true|false>]
# Manage webhook secrets
agent-validator webhook [--generate] [--status] [--show] [--revoke] [--force]
๐ Exit Codes
0: Success1: General error2: Validation failed
๐ Security Notes
-
Configuration Display: By default, sensitive values (license key, webhook secret) are masked as
***when showing configuration -
Show Secrets: Use
--show-secretsflag to display actual values for debugging/verification -
Example:
# Default (masked) agent-validator config --show # Output: license_key: *** # With secrets visible agent-validator config --show --show-secrets # Output: license_key: my-actual-key
๐ ๏ธ Development
๐ฆ Installation
git clone https://github.com/agent-validator/agent-validator.git
cd agent-validator
pip install -e ".[dev]"
Note: The [dev] extras include build tools (build, twine) needed for creating releases.
๐งช Running Tests
# Run all tests
python -m pytest tests/ -v
# Run with coverage
pytest --cov=agent_validator
# Run property-based tests
python -m pytest tests/property/ -v
# Run type checking
mypy agent_validator cli
# Run linting
ruff check .
black --check .
isort --check-only .
# Run smoke tests (isolated environment)
python smoke_tests/smoke_tests.py
๐ง Pre-commit Hooks
pre-commit install
pre-commit run --all-files
๐ Smoke Tests
Smoke tests verify the complete user experience in an isolated environment:
# Run comprehensive smoke tests
python smoke_tests/smoke_tests.py
# With backend URL for cloud testing
python smoke_tests/smoke_tests.py --backend-url http://localhost:9090
What gets tested:
- โ Package installation in isolated environment
- โ CLI command availability and functionality
- โ Library imports and basic operations
- โ Configuration management
- โ Log generation and retrieval
- โ Schema validation (strict and coerce modes)
- โ Error handling and edge cases
Benefits:
- ๐ก๏ธ No pollution to your development environment
- ๐ Clean testing environment every time
- ๐งช Tests real installation and usage scenarios
- ๐ Perfect for CI/CD integration
๐ฆ Releasing New Versions
The project uses automated CI/CD for releases. When you push a version tag, the CI automatically builds and publishes to PyPI.
1. Update Version
Update the version in agent_validator/version.py:
__version__ = "1.0.1" # Increment version number
2. Update CHANGELOG
Add a new entry to CHANGELOG.md following the Keep a Changelog format:
## [1.0.1] - 2025-01-01
### Added
- New feature description
### Changed
- Breaking change description
### Fixed
- Bug fix description
3. Run Pre-release Checks
# Install build dependencies (if not already installed)
pip install -e ".[dev]"
# Run all tests
python -m pytest tests/ -v
# Run smoke tests
python smoke_tests/smoke_tests.py
# Check code quality (matches CI)
ruff check .
mypy agent_validator cli
# Verify package builds
python -m build
4. Commit and Push Changes
# Commit version and changelog updates
git add agent_validator/version.py CHANGELOG.md
git commit -m "Release v1.0.1"
git push origin master
5. Create and Push Git Tag
# Create version tag
git tag v1.0.1
# Push tag to trigger automated release
git push origin v1.0.1
That's it! ๐ The CI/CD pipeline will automatically:
- โ Run tests across Python 3.9, 3.10, 3.11, and 3.12
- โ Run linting and type checking
- โ Build the package
- โ
Publish to PyPI (if tag starts with
v)
6. Verify Release
After the CI completes (usually 2-3 minutes):
# Test installation from PyPI
pip install agent-validator==1.0.1 --force-reinstall
# Verify functionality
agent-validator --help
python -c "import agent_validator; print(agent_validator.__version__)"
7. Create GitHub Release
- Go to GitHub Releases
- Click "Create a new release"
- Select the tag you just pushed
- Copy the changelog content
- Publish the release
Release Checklist:
- Version updated in
agent_validator/version.py - CHANGELOG.md updated
- All tests pass locally
- Smoke tests pass
- Code quality checks pass
- Package builds successfully
- Changes committed and pushed to master
- Git tag created and pushed
- CI/CD pipeline completes successfully
- Installation from PyPI verified
- GitHub release created with changelog
CI/CD Pipeline Details:
The .github/workflows/ci.yml workflow automatically:
- Tests: Runs on Python 3.9, 3.10, 3.11, 3.12
- Quality: Runs
ruff checkandmypy - Coverage: Generates and uploads coverage reports
- Publishing: Automatically publishes to PyPI when a tag starting with
vis pushed - Security: Uses GitHub secrets for PyPI authentication
๐ค Contributing
- ๐ด Fork the repository
- ๐ฟ Create a feature branch
- โ๏ธ Make your changes
- ๐งช Add tests
- โ Run the test suite
- ๐ค Submit a pull request
๐ License
MIT License - see LICENSE file for details.
โ FAQ
Q: Can I use this with any LLM/agent?
A: Yes! The library is framework-agnostic. Just pass your agent's output to the validate function.
Q: What happens if my agent returns malformed JSON?
A: In strict mode, it will fail immediately. In coerce mode, it will try to parse as JSON first, then fall back to treating it as a plain string.
Q: How do I handle sensitive data in logs?
A: Sensitive data is automatically redacted before logging. You can also add custom redaction patterns.
Q: Can I use this in production?
A: Yes! The library is designed for production use with proper error handling, logging, and monitoring capabilities.
Q: How do I access the web dashboard securely?
A: Use agent-validator dashboard which creates a secure local proxy server. Never put your license key in URLs - the CLI handles authentication securely via headers.
Q: How do I verify my license key is set correctly?
A: Use agent-validator config --show --show-secrets to display the actual license key value. By default, sensitive values are masked as *** for security.
Q: What's the performance impact?
A: Minimal. Validation is fast, and logging is asynchronous. The main overhead comes from retry attempts when validation fails.
Q: Can I use my own schema format?
A: Currently only Python dict schemas are supported. JSONSchema support is planned for v0.1.
๐บ๏ธ Roadmap
- JSONSchema import/export
- Pydantic model support
- Custom validators per field
- Schema composition and inheritance
- Web dashboard for monitoring
- Alerting and notifications
- Schema versioning
- Performance metrics
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 agent_validator-1.0.0.tar.gz.
File metadata
- Download URL: agent_validator-1.0.0.tar.gz
- Upload date:
- Size: 40.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
44b5b049bec31378077ddc4b1dffc72266aab1e9a86ba75d052aed969064d33b
|
|
| MD5 |
95a403e44e7ed347c6be0119b04ea942
|
|
| BLAKE2b-256 |
ee03ea266c20d611b7994ddb82ebe3fe9fcb8dec1d5c3527ddd40354c11c2789
|
File details
Details for the file agent_validator-1.0.0-py3-none-any.whl.
File metadata
- Download URL: agent_validator-1.0.0-py3-none-any.whl
- Upload date:
- Size: 29.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acf1085c636a5652ab0d945997a1e581f2d9e83be3ea762444fc9762d14df83d
|
|
| MD5 |
916e058612de6dd3ec3ab97250a6533b
|
|
| BLAKE2b-256 |
12da80be98ee20855f87aeadda095cb98ff25747566f050c1b15332e438369c0
|