A meta-framework for building agentic workflows with Pydantic AI.
β οΈ Early Alpha: This library is in active development. The API is subject to change as we refine the framework based on feedback and real-world usage.
pip install pygentic-aiOr with uv:
uv add pygentic-aiBuild your first agentic workflow in 4 steps:
from dataclasses import dataclass
@dataclass
class AppConfig:
api_key: str
model: str = "gpt-4o-mini"
language: str = "english"Create a factory to configure your agents:
from pydantic_ai import UsageLimits
from pygentic_ai import AgentManager
from pygentic_ai.engines import ReasoningAgent, GuardrailsAgent, SimpleTranslatorWorker
class AgentFactory:
@staticmethod
async def create_manager(config: AppConfig) -> AgentManager:
manager = AgentManager()
# Configure usage limits
usage_limits = UsageLimits(output_tokens_limit=2000)
# Register agents
manager.register(
"agent",
ReasoningAgent,
api_key=config.api_key,
llm_model=config.model,
language=config.language,
usage_limits=usage_limits,
)
manager.register(
"guardrails",
GuardrailsAgent,
api_key=config.api_key,
llm_model=config.model,
)
manager.register(
"translator",
SimpleTranslatorWorker,
api_key=config.api_key,
target_language=config.language,
)
# Initialize all agents
await manager.initialize()
return managerUse the pre-built workflow:
from pygentic_ai import user_assistant_graph
# Run workflow - manager.to_deps() automatically includes all registered agents
result = await user_assistant_graph.run(
{"message": "Hello!"},
manager.to_deps(chat_history=[])
)
print(result)Complete application:
import asyncio
from dataclasses import dataclass
from pydantic_ai import UsageLimits
from pygentic_ai import AgentManager, user_assistant_graph
from pygentic_ai.engines import ReasoningAgent, GuardrailsAgent, SimpleTranslatorWorker
@dataclass
class AppConfig:
api_key: str
model: str = "gpt-4o-mini"
language: str = "english"
class AgentFactory:
@staticmethod
async def create_manager(config: AppConfig) -> AgentManager:
manager = AgentManager()
usage_limits = UsageLimits(output_tokens_limit=2000)
manager.register("agent", ReasoningAgent, api_key=config.api_key,
llm_model=config.model, usage_limits=usage_limits)
manager.register("guardrails", GuardrailsAgent, api_key=config.api_key)
manager.register("translator", SimpleTranslatorWorker, api_key=config.api_key)
await manager.initialize()
return manager
async def main():
config = AppConfig(api_key="sk-...")
manager = await AgentFactory.create_manager(config)
# Use workflow
result = await user_assistant_graph.run(
{"message": "Hello!"},
manager.to_deps(chat_history=[])
)
print(result)
# Or use agent directly
agent = manager.get("agent")
result = await agent.generate_response("What's the weather?", [])
print(result.output)
if __name__ == "__main__":
asyncio.run(main())Complete working example: examples/simple-chat
from pygentic_ai import BaseAgent
class MyCustomAgent(BaseAgent):
def __init__(self, **kwargs):
super().__init__(
llm_vendor="openai",
llm_model="gpt-4o",
instructions="You are a helpful assistant.",
**kwargs
)Build your own workflow by composing nodes:
from pydantic_graph import Graph
from pygentic_ai.workflows.nodes import StartNode, GenerateNode, GuardrailsNode
# Define custom workflow
my_workflow = Graph(
nodes=(StartNode, GenerateNode, GuardrailsNode),
name="MyWorkflow"
)
# Execute with manager.to_deps()
result = await my_workflow.run(
{"message": "Hello"},
manager.to_deps(chat_history=[])
)from pygentic_ai.tools import tool_manager, Toolpacks
# Get tools for your agent
tools = tool_manager.get_toolpack(AgentMode.GENERAL)
# Register agent with tools
manager.register(
"agent",
ReasoningAgent,
api_key=config.api_key,
tool_list=tools,
)- BaseAgent: Foundation for custom agents
- ReasoningAgent: General-purpose agent with reasoning capabilities
- GuardrailsAgent: Agent with content safety checks
- GenericRouter: Routes messages to appropriate handlers
- SimpleTranslatorWorker: Translates responses to different languages
- AgentManager: Registry for managing multiple agents
- user_assistant_graph: Pre-built workflow with routing, generation, guardrails, and translation
- StartNode: Entry point for workflows
- GenerateNode: Generates responses using an agent
- GuardrailsNode: Applies safety checks
- ClassifyNode: Routes based on message classification
- TranslateNode: Translates output
- RefuseNode: Handles refused/blocked content
- WorkflowState: Maintains conversation state and metadata
- RefusalInfo: Tracks content refusal details
- dateutils: Date utility functions (get_today_date, get_current_week, get_weekday_from_date)
- tool_registry: ToolManager for organizing tools by agent mode
- π Built on Pydantic AI for type safety
- π§ Extensible agent system
- π Workflow composition with pydantic-graph
- π‘οΈ Built-in guardrails
- π Multi-language support
- π MCP (Model Context Protocol) support
- π Token usage tracking
- Simple Chat: Basic chat application showing complete workflow setup
See examples/ for more.
Recommended structure for your application:
your-app/
βββ config.py # Configuration (API keys, models)
βββ factories/
β βββ agent_factory.py # Agent initialization
βββ engines/ # Custom agents (optional)
β βββ my_custom_agent.py
βββ workflows/ # Custom workflows (optional)
β βββ my_workflow.py
βββ nodes/ # Custom workflow nodes (optional)
β βββ my_custom_node.py
βββ tools/ # Custom tools (optional)
β βββ my_tools.py
βββ main.py # Application entry point
βββ .env # Environment variables
# engines/my_custom_agent.py
from pygentic_ai import BaseAgent
class MyCustomAgent(BaseAgent):
def __init__(self, **kwargs):
super().__init__(
llm_vendor="openai",
llm_model="gpt-4o",
instructions="You are a specialized assistant.",
**kwargs
)# nodes/my_custom_node.py
from dataclasses import dataclass
from pydantic_graph import BaseNode, GraphRunContext
from pygentic_ai.workflows.state import WorkflowState
@dataclass
class MyCustomNode(BaseNode[WorkflowState, dict, str]):
async def run(self, ctx: GraphRunContext[WorkflowState, dict]):
# Your custom logic
return NextNode()# tools/my_tools.py
def my_custom_tool(query: str) -> str:
"""Custom tool for your agent."""
return f"Processed: {query}"
MY_TOOLS = [my_custom_tool]
# In factory:
manager.register(
"agent",
ReasoningAgent,
tool_list=MY_TOOLS,
)- π Built on Pydantic AI for type safety
- π§ Extensible agent system
- π Workflow composition with pydantic-graph
- π‘οΈ Built-in guardrails
- π Multi-language support
- π MCP (Model Context Protocol) support
- π Token usage tracking