A library for building reliable, state-driven LLM workflows using the State+CRUD pattern
Project description
stateagent
A lightweight Python framework to structure LLM conversations using a validated state model and a tool-based interaction design.
Table of Contents
- Installation
- Quick Start
- 🏗️ Core Concepts
- 🎨 Advanced Features
- 🧪 Built-in Validators
- 📚 Examples
- 🔧 Configuration
- 🧪 Testing
- 📖 API Reference
- 📄 License
- 📊 Roadmap
Installation
pip install stateagent
Quick Start
Here's a simple example to get you up and running:
Example Conversation
🤖 Hi! I need to collect some contact information from you.
👤 My name is John Smith
🤖 Great! I've recorded your name as John Smith.
Now, could you please provide your email address?
👤 john@company.com
🤖 Perfect! I've saved your email.
Finally, what message would you like to send?
👤 I'm interested in learning more about your services.
🤖 Excellent! I have all the information I need:
✓ Name: John Smith
✓ Email: john@company.com
✓ Message: I'm interested in learning more about your services.
Thank you for your submission!
🏗️ Core Concepts
StateModel
Define your data structure with validation:
from dataclasses import dataclass, field
from llm_structured_agent import StateModel, Field, create_range_validator
@dataclass
class UserProfile(StateModel):
name: str = field(default=None)
age: int = field(default=None)
email: str = field(default=None)
_field_info = {
'name': Field(
required=True,
description="User's full name",
validator=create_length_validator(min_length=2)
),
'age': Field(
required=True,
description="User's age",
validator=create_range_validator(min_val=13, max_val=120)
),
'email': Field(
required=True,
description="Email address",
validator=create_email_validator()
)
}
CRUD Tools
The LLM automatically gets these tools to interact with state:
set_field(field_name, value)- Update a field with validationvalidate_state()- Check if all required fields are completeget_state()- View current state snapshotclear_state()- Reset all fields to defaults
Structured Agent
The main orchestrator that manages the conversation:
agent = StructuredAgent(
state_cls=UserProfile,
llm=OpenAIAdapter(model="gpt-4o-mini"),
hooks={
"on_field_set": lambda state, field: print(f"Updated {field}"),
"on_submit": lambda state: save_to_database(state.snapshot())
},
max_turns=20
)
🎨 Advanced Features
Custom Validation
import re
from llm_structured_agent import ValidationError
def validate_phone_number(value: str):
if not re.match(r'^\+?[\d\s\-]+$', value):
raise ValidationError("Invalid phone format")
return value.strip()
@dataclass
class ContactInfo(StateModel):
phone: str = field(default=None)
_field_info = {
'phone': Field(
required=True,
description="Phone number with country code",
validator=validate_phone_number
)
}
Conditional Logic
@dataclass
class OrderForm(StateModel):
item_type: str = field(default=None)
shipping_address: str = field(default=None)
gift_message: str = field(default=None)
def validate(self) -> List[str]:
missing = super().validate()
# Gift message required for gift items
if (self.item_type == "gift" and
not self.gift_message):
missing.append("gift_message")
return missing
Lifecycle Hooks
def on_field_updated(state, field_name):
print(f"📝 {field_name} updated to: {getattr(state, field_name)}")
def on_form_complete(state):
# Save to database
save_to_database(state.snapshot())
# Send notification
send_notification(state.email, "Form completed!")
# Log completion
logger.info(f"Form completed for {state.name}")
agent = StructuredAgent(
state_cls=MyForm,
llm=OpenAIAdapter(),
hooks={
"on_field_set": on_field_updated,
"on_submit": on_form_complete
}
)
Multiple LLM Providers
# OpenAI (default)
agent = StructuredAgent(
state_cls=MyState,
llm=OpenAIAdapter(model="gpt-4o-mini")
)
# Custom LLM provider
class CustomLLMAdapter(LLMAdapter):
def chat(self, messages, tools=None):
# Your implementation
pass
def extract_function_calls(self, response):
# Your implementation
pass
agent = StructuredAgent(
state_cls=MyState,
llm=CustomLLMAdapter()
)
Non-Interactive Usage
# For API endpoints or batch processing
agent = StructuredAgent(state_cls=ContactForm, llm=OpenAIAdapter())
# Process single message
result = agent.process_single_turn("My name is John and email is john@example.com")
if result["complete"]:
print("Form completed:", result["state"])
else:
print("Next response:", result["message"])
print("Still missing:", result["missing_fields"])
🧪 Built-in Validators
The library includes common validators:
from llm_structured_agent import (
create_email_validator,
create_range_validator,
create_length_validator,
create_regex_validator,
create_choice_validator
)
# Email validation
email_validator = create_email_validator()
# Numeric range
age_validator = create_range_validator(min_val=18, max_val=100)
# String length
name_validator = create_length_validator(min_length=2, max_length=50)
# Regex pattern
phone_validator = create_regex_validator(
pattern=r'^\+?[\d\s\-]+$',
error_message="Invalid phone number format"
)
# Choice validation
department_validator = create_choice_validator([
"Engineering", "Sales", "Marketing", "HR"
])
📚 Examples
The library includes complete examples:
Customer Onboarding (KYC)
# Run the KYC example
python -m llm_structured_agent.examples.kyc_example
# Or if installed via pip
kyc-agent
Employee Onboarding
# Run the employee onboarding example
python -m llm_structured_agent.examples.onboarding_example
# Or if installed via pip
onboarding-agent
🔧 Configuration
Environment Variables
# Required for OpenAI
export OPENAI_API_KEY="your-openai-api-key"
# Optional: Custom model
export OPENAI_MODEL="gpt-4o-mini"
Custom System Prompts
custom_prompt = """You are a helpful assistant collecting user information.
Be conversational and friendly while systematically gathering:
- Name (required)
- Email (required)
- Phone (optional)
Use the provided tools to store information and check completeness."""
agent = StructuredAgent(
state_cls=ContactForm,
llm=OpenAIAdapter(),
system_prompt=custom_prompt
)
🧪 Testing
# Install with dev dependencies
pip install stateagent[dev]
# Run tests
pytest
# Run with coverage
pytest --cov=llm_structured_agent
# Run specific test
pytest tests/test_state.py -v
📖 API Reference
StateModel
Base class for defining structured state:
class StateModel:
def set_field(self, name: str, value: Any) -> None
def validate(self) -> List[str]
def snapshot(self) -> Dict[str, Any]
def clear(self) -> None
def get_field_info(self, name: str) -> Optional[Field]
Field
Field definition with validation:
class Field:
def __init__(
self,
required: bool = False,
description: str = "",
validator: Optional[Callable] = None,
default: Any = None
)
StructuredAgent
Main orchestration class:
class StructuredAgent:
def __init__(
self,
state_cls: type,
llm: LLMAdapter,
hooks: Optional[Dict[str, Callable]] = None,
max_turns: int = 20,
system_prompt: Optional[str] = None
)
def run_chat(self) -> None
def process_single_turn(self, user_input: str) -> Dict[str, Any]
def reset(self) -> None
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
📊 Roadmap
- More LLM provider integrations
- FastAPI integration
- Streamlit demo interface
- Database persistence layer
- MCP Server
Built with ❤️ for the AI community
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 stateagent-0.1.0.tar.gz.
File metadata
- Download URL: stateagent-0.1.0.tar.gz
- Upload date:
- Size: 20.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3f6a45b2cffacb4f1cca69a4a11f018e03974e78a3b8d21f729b9322e7085304
|
|
| MD5 |
a36508b697a0bbd653926269d45c9758
|
|
| BLAKE2b-256 |
0fc5fa7ddaca27983612aea29d1252e013390a707c194429903f5a4edc845c6d
|
File details
Details for the file stateagent-0.1.0-py3-none-any.whl.
File metadata
- Download URL: stateagent-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa19e829a747cb15ebb4edbb8099d339e37f7c944372b18beea6e0a7792a16b9
|
|
| MD5 |
3af4a0956237b64ff345bb11048812eb
|
|
| BLAKE2b-256 |
3e6ebc61a023941c07d32d961a67bce2d83cd6b2bc5f673926d3239eaa26ea51
|