diff --git a/use-cases/mcp-server/README.md b/use-cases/mcp-server/README.md index 4ef7aaf..378a63c 100644 --- a/use-cases/mcp-server/README.md +++ b/use-cases/mcp-server/README.md @@ -4,6 +4,44 @@ This use case demonstrates how to use **Context Engineering** and the **PRP (Pro > A PRP is PRD + curated codebase intelligence + agent/runbookβ€”the minimum viable packet an AI needs to plausibly ship production-ready code on the first pass. +## πŸš€ Quick Start + +### Prerequisites + +- Node.js and npm installed +- Cloudflare account (free tier works) +- GitHub account for OAuth +- PostgreSQL database (local or hosted) + +### Step 1: Setup Your Project + +```bash +# Clone the context engineering repository +git clone https://github.com/coleam00/Context-Engineering-Intro.git +cd Context-Engineering-Intro/use-cases/mcp-server + +# Copy template to your new project directory +python copy_template.py my-mcp-server-project + +# Navigate to your new project +cd my-mcp-server-project + +# Install dependencies +npm install + +# Install Wrangler CLI globally +npm install -g wrangler + +# Authenticate with Cloudflare +wrangler login +``` + +**What copy_template.py does:** +- Copies all template files except build artifacts (respects .gitignore) +- Renames README.md to README_TEMPLATE.md (so you can create your own README) +- Includes all source code, examples, tests, and configuration files +- Preserves the complete context engineering setup + ## 🎯 What You'll Learn This use case teaches you how to: @@ -16,9 +54,11 @@ This use case teaches you how to: ## πŸ“‹ How It Works - The PRP Process for MCP Servers -### 1. Define Your MCP Server (initial.md) +> **Step 1 is the Quick Start setup above** - clone repo, copy template, install dependencies, setup Wrangler -Start by describing the exact MCP server you want to build in `PRPs/INITIAL.md`: +### Step 2: Define Your MCP Server + +Edit `PRPs/INITIAL.md` to describe your specific MCP server requirements: ```markdown ## FEATURE: @@ -38,7 +78,7 @@ with caching and rate limiting. - Coordinate validation for location queries ``` -### 2. Generate Your PRP +### Step 3: Generate Your PRP Use the specialized MCP PRP command to create a comprehensive implementation plan: @@ -55,7 +95,7 @@ Use the specialized MCP PRP command to create a comprehensive implementation pla > It's important after your PRP is generated to validate everything! With the PRP framework, you are meant to be a part of the process to ensure the quality of all context! An execution is only as good as your PRP. Use /prp-mcp-create as a solid starting point. -### 3. Execute Your PRP +### Step 4: Execute Your PRP Use the specialized MCP execution command to build your server: @@ -70,6 +110,32 @@ Use the specialized MCP execution command to build your server: - Runs comprehensive validation (TypeScript, tests, deployment) - Ensures your MCP server works end-to-end +### Step 5: Configure Environment + +```bash +# Create environment file +cp .dev.vars.example .dev.vars + +# Edit .dev.vars with your credentials +# - GitHub OAuth app credentials +# - Database connection string +# - Cookie encryption key +``` + +### Step 6: Test and Deploy + +```bash +# Test locally +wrangler dev --config + +# Test with MCP Inspector +npx @modelcontextprotocol/inspector@latest +# Connect to: http://localhost:8792/mcp + +# Deploy to production +wrangler deploy +``` + ## πŸ—οΈ MCP-Specific Context Engineering This use case includes specialized context engineering components designed specifically for MCP server development: @@ -135,89 +201,6 @@ The `examples/` folder shows how to create MCP tools: - **πŸ“Š Monitoring** - Optional Sentry integration for production - **πŸ§ͺ Testing** - Comprehensive validation from TypeScript to deployment -## πŸš€ Quick Start - -### Prerequisites - -- Node.js and npm installed -- Cloudflare account (free tier works) -- GitHub account for OAuth -- PostgreSQL database (local or hosted) - -### Step 1: Clone and Setup - -```bash -# Clone the context engineering template -git clone https://github.com/coleam00/Context-Engineering-Intro.git -cd Context-Engineering-Intro/use-cases/mcp-server - -# Install dependencies -npm install - -# Install Wrangler CLI globally -npm install -g wrangler - -# Authenticate with Cloudflare -wrangler login -``` - -### Step 2: Configure Environment - -```bash -# Create environment file -cp .dev.vars.example .dev.vars - -# Edit .dev.vars with your credentials -# - GitHub OAuth app credentials -# - Database connection string -# - Cookie encryption key -``` - -### Step 3: Define Your MCP Server - -Edit `PRPs/INITIAL.md` to describe your specific MCP server requirements: - -```markdown -## FEATURE: -Describe exactly what your MCP server should do - be specific about -functionality, data sources, and user interactions. - -## ADDITIONAL FEATURES: -- List specific features beyond basic CRUD operations -- Include integrations with external APIs -- Mention any special requirements - -## OTHER CONSIDERATIONS: -- Authentication requirements -- Performance considerations -- Security requirements -- Rate limiting needs -``` - -### Step 4: Generate and Execute PRP - -```bash -# Generate comprehensive PRP -/prp-mcp-create INITIAL.md - -# Execute the PRP to build your server -/prp-mcp-execute PRPs/your-server-name.md -``` - -### Step 5: Test and Deploy - -```bash -# Test locally -wrangler dev - -# Test with MCP Inspector -npx @modelcontextprotocol/inspector@latest -# Connect to: http://localhost:8792/mcp - -# Deploy to production -wrangler deploy -``` - ## πŸ” Key Files to Understand To fully understand this use case, examine these files: @@ -262,4 +245,4 @@ The goal is to make MCP server development predictable and successful through co --- -**Ready to build your MCP server?** Start by editing `PRPs/INITIAL.md` and run `/prp-mcp-create INITIAL.md` to generate your comprehensive implementation plan. \ No newline at end of file +**Ready to build your MCP server?** Follow the complete process above: setup your project with the copy template, configure your environment, define your requirements in `PRPs/INITIAL.md`, then generate and execute your PRP to build your production-ready MCP server. \ No newline at end of file diff --git a/use-cases/mcp-server/copy_template.py b/use-cases/mcp-server/copy_template.py new file mode 100644 index 0000000..12bc4bd --- /dev/null +++ b/use-cases/mcp-server/copy_template.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python3 +""" +MCP Server Template Copy Script + +Copies the complete MCP server context engineering template to a target directory +for starting new MCP server development projects. Uses gitignore-aware copying +to avoid copying build artifacts and dependencies. + +Usage: + python copy_template.py + +Example: + python copy_template.py my-mcp-server + python copy_template.py /path/to/my-new-server +""" + +import os +import sys +import shutil +import argparse +from pathlib import Path +from typing import List, Tuple, Set +import fnmatch + + +def parse_gitignore(gitignore_path: Path) -> Set[str]: + """ + Parse .gitignore file and return set of patterns to ignore. + + Args: + gitignore_path: Path to .gitignore file + + Returns: + Set of gitignore patterns + """ + ignore_patterns = set() + + if not gitignore_path.exists(): + return ignore_patterns + + try: + with open(gitignore_path, 'r', encoding='utf-8') as f: + for line in f: + line = line.strip() + # Skip empty lines and comments + if line and not line.startswith('#'): + # Remove leading slash for consistency + pattern = line.lstrip('/') + ignore_patterns.add(pattern) + except Exception as e: + print(f"Warning: Could not read .gitignore: {e}") + + return ignore_patterns + + +def should_ignore_path(path: Path, template_root: Path, ignore_patterns: Set[str]) -> bool: + """ + Check if a path should be ignored based on gitignore patterns. + + Args: + path: Path to check + template_root: Root directory of template + ignore_patterns: Set of gitignore patterns + + Returns: + True if path should be ignored, False otherwise + """ + # Get relative path from template root + try: + rel_path = path.relative_to(template_root) + except ValueError: + return False + + # Convert to string with forward slashes + rel_path_str = str(rel_path).replace('\\', '/') + + # Check against each ignore pattern + for pattern in ignore_patterns: + # Handle directory patterns (ending with /) + if pattern.endswith('/'): + pattern = pattern.rstrip('/') + if rel_path_str.startswith(pattern + '/') or rel_path_str == pattern: + return True + # Handle glob patterns + elif fnmatch.fnmatch(rel_path_str, pattern): + return True + # Handle exact matches and prefix matches + elif rel_path_str == pattern or rel_path_str.startswith(pattern + '/'): + return True + + return False + + +def get_template_files() -> List[Tuple[str, str]]: + """ + Get list of template files to copy with their relative paths. + Uses gitignore-aware filtering to exclude build artifacts and dependencies. + + Returns: + List of (source_path, relative_path) tuples + """ + template_root = Path(__file__).parent + files_to_copy = [] + + # Parse .gitignore patterns + gitignore_path = template_root / '.gitignore' + ignore_patterns = parse_gitignore(gitignore_path) + + # Add the copy_template.py script itself to ignore patterns + ignore_patterns.add('copy_template.py') + + # Walk through all files in template directory + for root, dirs, files in os.walk(template_root): + root_path = Path(root) + + # Filter out ignored directories + dirs[:] = [d for d in dirs if not should_ignore_path(root_path / d, template_root, ignore_patterns)] + + for file in files: + file_path = root_path / file + + # Skip if file should be ignored + if should_ignore_path(file_path, template_root, ignore_patterns): + continue + + # Get relative path for target + rel_path = file_path.relative_to(template_root) + + # Rename README.md to README_TEMPLATE.md + if rel_path.name == 'README.md': + target_rel_path = rel_path.parent / 'README_TEMPLATE.md' + else: + target_rel_path = rel_path + + files_to_copy.append((str(file_path), str(target_rel_path))) + + return files_to_copy + + +def create_directory_structure(target_dir: Path, files: List[Tuple[str, str]]) -> None: + """ + Create directory structure for all files. + + Args: + target_dir: Target directory path + files: List of (source_path, relative_path) tuples + """ + directories = set() + + for _, rel_path in files: + dir_path = target_dir / Path(rel_path).parent + if str(dir_path) != str(target_dir): # Don't add root directory + directories.add(dir_path) + + for directory in directories: + directory.mkdir(parents=True, exist_ok=True) + + +def copy_template_files(target_dir: Path, files: List[Tuple[str, str]]) -> int: + """ + Copy all template files to target directory. + + Args: + target_dir: Target directory path + files: List of (source_path, relative_path) tuples + + Returns: + Number of files copied successfully + """ + copied_count = 0 + + for source_path, rel_path in files: + target_path = target_dir / rel_path + + try: + shutil.copy2(source_path, target_path) + copied_count += 1 + print(f" βœ“ {rel_path}") + except Exception as e: + print(f" βœ— {rel_path} - Error: {e}") + + return copied_count + + +def validate_template_integrity(target_dir: Path) -> bool: + """ + Validate that essential template files were copied correctly. + + Args: + target_dir: Target directory path + + Returns: + True if template appears complete, False otherwise + """ + essential_files = [ + "CLAUDE.md", + "README_TEMPLATE.md", + ".claude/commands/prp-mcp-create.md", + ".claude/commands/prp-mcp-execute.md", + "PRPs/templates/prp_mcp_base.md", + "PRPs/INITIAL.md", + "package.json", + "tsconfig.json", + "src/index.ts", + "src/types.ts" + ] + + missing_files = [] + for file_path in essential_files: + if not (target_dir / file_path).exists(): + missing_files.append(file_path) + + if missing_files: + print(f"\n⚠️ Warning: Some essential files are missing:") + for file in missing_files: + print(f" - {file}") + return False + + return True + + +def print_next_steps(target_dir: Path) -> None: + """ + Print helpful next steps for using the template. + + Args: + target_dir: Target directory path + """ + print(f""" +πŸŽ‰ MCP Server template successfully copied to: {target_dir} + +πŸ“‹ Next Steps: + +1. Navigate to your new project: + cd {target_dir} + +2. Install dependencies: + npm install + +3. Set up your environment: + # Copy environment template (if needed) + cp .env.example .env + # Edit .env with your configuration + +4. Start building your MCP server: + # 1. Edit PRPs/INITIAL.md with your server requirements + # 2. Generate PRP: /prp-mcp-create PRPs/INITIAL.md + # 3. Execute PRP: /prp-mcp-execute PRPs/generated_prp.md + +5. Development workflow: + # Run tests + npm test + + # Start development server + npm run dev + + # Build for production + npm run build + +6. Read the documentation: + # Check README_TEMPLATE.md for complete usage guide + # Check CLAUDE.md for MCP development rules + +πŸ”— Useful Resources: + - MCP Specification: https://spec.modelcontextprotocol.io/ + - Examples: See examples/ directory + - Testing: See tests/ directory + +Happy MCP server building! πŸ€– +""") + + +def main(): + """Main function for the copy template script.""" + parser = argparse.ArgumentParser( + description="Copy MCP Server context engineering template to a new project directory", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python copy_template.py my-mcp-server + python copy_template.py /path/to/my-new-server + python copy_template.py ../customer-support-mcp + """ + ) + + parser.add_argument( + "target_directory", + help="Target directory for the new MCP server project" + ) + + parser.add_argument( + "--force", + action="store_true", + help="Overwrite target directory if it exists" + ) + + parser.add_argument( + "--dry-run", + action="store_true", + help="Show what would be copied without actually copying" + ) + + if len(sys.argv) == 1: + parser.print_help() + return + + args = parser.parse_args() + + # Convert target directory to Path object + target_dir = Path(args.target_directory).resolve() + + # Check if target directory exists + if target_dir.exists(): + if target_dir.is_file(): + print(f"❌ Error: {target_dir} is a file, not a directory") + return + + if list(target_dir.iterdir()) and not args.force: + print(f"❌ Error: {target_dir} is not empty") + print("Use --force to overwrite existing directory") + return + + if args.force and not args.dry_run: + print(f"⚠️ Overwriting existing directory: {target_dir}") + + # Get list of files to copy + print("πŸ“‚ Scanning MCP server template files...") + files_to_copy = get_template_files() + + if not files_to_copy: + print("❌ Error: No template files found. Make sure you're running this from the template directory.") + return + + print(f"Found {len(files_to_copy)} files to copy") + + if args.dry_run: + print(f"\nπŸ” Dry run - would copy to: {target_dir}") + for _, rel_path in files_to_copy: + print(f" β†’ {rel_path}") + return + + # Create target directory and structure + print(f"\nπŸ“ Creating directory structure in: {target_dir}") + target_dir.mkdir(parents=True, exist_ok=True) + create_directory_structure(target_dir, files_to_copy) + + # Copy files + print(f"\nπŸ“‹ Copying template files:") + copied_count = copy_template_files(target_dir, files_to_copy) + + # Validate template integrity + print(f"\nβœ… Copied {copied_count}/{len(files_to_copy)} files successfully") + + if validate_template_integrity(target_dir): + print("βœ… Template integrity check passed") + print_next_steps(target_dir) + else: + print("⚠️ Template may be incomplete. Check for missing files.") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/use-cases/pydantic-ai/.claude/commands/execute-pydantic-ai-prp.md b/use-cases/pydantic-ai/.claude/commands/execute-pydantic-ai-prp.md new file mode 100644 index 0000000..a3c1ec8 --- /dev/null +++ b/use-cases/pydantic-ai/.claude/commands/execute-pydantic-ai-prp.md @@ -0,0 +1,55 @@ +# Execute Pydantic AI Agent PRP + +Implement a Pydantic AI agent using the PRP file. + +## PRP File: $ARGUMENTS + +## Execution Process + +1. **Load PRP** + - Read the specified Pydantic AI PRP file + - Understand all agent requirements and research findings + - Follow all instructions in the PRP and extend research if needed + - Review main_agent_reference patterns for implementation guidance + - Do more web searches and Pydantic AI documentation review as needed + +2. **ULTRATHINK** + - Think hard before executing the agent implementation plan + - Break down agent development into smaller steps using your todos tools + - Use the TodoWrite tool to create and track your agent implementation plan + - Follow main_agent_reference patterns for configuration and structure + - Plan agent.py, tools.py, dependencies.py, and testing approach + +3. **Execute the plan** + - Implement the Pydantic AI agent following the PRP + - Create agent with environment-based configuration (settings.py, providers.py) + - Use string output by default (no result_type unless structured output needed) + - Implement tools with @agent.tool decorators and proper error handling + - Add comprehensive testing with TestModel and FunctionModel + +4. **Validate** + - Test agent import and instantiation + - Run TestModel validation for rapid development testing + - Test tool registration and functionality + - Run pytest test suite if created + - Verify agent follows main_agent_reference patterns + +5. **Complete** + - Ensure all PRP checklist items done + - Test agent with example queries + - Verify security patterns (environment variables, error handling) + - Report completion status + - Read the PRP again to ensure complete implementation + +6. **Reference the PRP** + - You can always reference the PRP again if needed + +## Pydantic AI-Specific Patterns to Follow + +- **Configuration**: Use environment-based setup like main_agent_reference +- **Output**: Default to string output, only use result_type when validation needed +- **Tools**: Use @agent.tool with RunContext for dependency injection +- **Testing**: Include TestModel validation for development +- **Security**: Environment variables for API keys, proper error handling + +Note: If validation fails, use error patterns in PRP to fix and retry. Follow main_agent_reference for proven Pydantic AI implementation patterns. \ No newline at end of file diff --git a/use-cases/pydantic-ai/.claude/commands/generate-pydantic-ai-prp.md b/use-cases/pydantic-ai/.claude/commands/generate-pydantic-ai-prp.md new file mode 100644 index 0000000..5c72bec --- /dev/null +++ b/use-cases/pydantic-ai/.claude/commands/generate-pydantic-ai-prp.md @@ -0,0 +1,94 @@ +# Create PRP + +## Feature file: $ARGUMENTS + +Generate a complete PRP for general feature implementation with thorough research. Ensure context is passed to the AI agent to enable self-validation and iterative refinement. Read the feature file first to understand what needs to be created, how the examples provided help, and any other considerations. + +The AI agent only gets the context you are appending to the PRP and training data. Assuma the AI agent has access to the codebase and the same knowledge cutoff as you, so its important that your research findings are included or referenced in the PRP. The Agent has Websearch capabilities, so pass urls to documentation and examples. + +## Research Process + +1. **Codebase Analysis** + - Search for similar features/patterns in the codebase + - Identify files to reference in PRP + - Note existing conventions to follow + - Check test patterns for validation approach + +2. **External Research** + - Search for similar features/patterns online + - Library documentation (include specific URLs) + - Implementation examples (GitHub/StackOverflow/blogs) + - Best practices and common pitfalls + - Use Archon MCP server to gather latest Pydantic AI documentation + - Web search for specific patterns and best practices relevant to the agent type + - Research model provider capabilities and limitations + - Investigate tool integration patterns and security considerations + - Document async/sync patterns and testing strategies + +3. **User Clarification** (if needed) + - Specific patterns to mirror and where to find them? + - Integration requirements and where to find them? + +4. **Analyzing Initial Requirements** + - Read and understand the agent feature requirements + - Identify the type of agent needed (chat, tool-enabled, workflow, structured output) + - Determine required model providers and external integrations + - Assess complexity and scope of the agent implementation + +5. **Agent Architecture Planning** + - Design agent structure (agent.py, tools.py, models.py, dependencies.py) + - Plan dependency injection patterns and external service integrations + - Design structured output models using Pydantic validation + - Plan tool registration and parameter validation strategies + - Design testing approach with TestModel/FunctionModel patterns + +6. **Implementation Blueprint Creation** + - Create detailed agent implementation steps + - Plan model provider configuration and fallback strategies + - Design tool error handling and retry mechanisms + - Plan security implementation (API keys, input validation, rate limiting) + - Design validation loops with agent behavior testing + +## PRP Generation + +Using PRPs/templates/prp_pydantic_aibase.md as template: + +### Critical Context to Include and pass to the AI agent as part of the PRP +- **Documentation**: URLs with specific sections +- **Code Examples**: Real snippets from codebase +- **Gotchas**: Library quirks, version issues +- **Patterns**: Existing approaches to follow + +### Implementation Blueprint +- Start with pseudocode showing approach +- Reference real files for patterns +- Include error handling strategy +- list tasks to be completed to fullfill the PRP in the order they should be completed + +### Validation Gates (Must be Executable) eg for python +```bash +# Syntax/Style +ruff check --fix && mypy . + +# Unit Tests +uv run pytest tests/ -v + +``` + +*** CRITICAL AFTER YOU ARE DONE RESEARCHING AND EXPLORING THE CODEBASE BEFORE YOU START WRITING THE PRP *** + +*** ULTRATHINK ABOUT THE PRP AND PLAN YOUR APPROACH THEN START WRITING THE PRP *** + +## Output +Save as: `PRPs/{feature-name}.md` + +## Quality Checklist +- [ ] All necessary context included +- [ ] Validation gates are executable by AI +- [ ] References existing patterns +- [ ] Clear implementation path +- [ ] Error handling documented + +Score the PRP on a scale of 1-10 (confidence level to succeed in one-pass implementation using claude codes) + +Remember: The goal is one-pass implementation success through comprehensive context. diff --git a/use-cases/pydantic-ai/CLAUDE.md b/use-cases/pydantic-ai/CLAUDE.md new file mode 100644 index 0000000..2ad0c68 --- /dev/null +++ b/use-cases/pydantic-ai/CLAUDE.md @@ -0,0 +1,176 @@ +# PydanticAI Context Engineering - Global Rules for AI Agent Development + +This file contains the global rules and principles that apply to ALL PydanticAI agent development work. These rules are specialized for building production-grade AI agents with tools, memory, and structured outputs. + +## πŸ”„ PydanticAI Core Principles + +**IMPORTANT: These principles apply to ALL PydanticAI agent development:** + +### Agent Development Workflow +- **Always start with INITIAL.md** - Define agent requirements before generating PRPs +- **Use the PRP pattern**: INITIAL.md β†’ `/generate-pydantic-ai-prp INITIAL.md` β†’ `/execute-pydantic-ai-prp PRPs/filename.md` +- **Follow validation loops** - Each PRP must include agent testing with TestModel/FunctionModel +- **Context is King** - Include ALL necessary PydanticAI patterns, examples, and documentation + +### Research Methodology for AI Agents +- **Web search extensively** - Always research PydanticAI patterns and best practices +- **Study official documentation** - ai.pydantic.dev is the authoritative source +- **Pattern extraction** - Identify reusable agent architectures and tool patterns +- **Gotcha documentation** - Document async patterns, model limits, and context management issues + +## πŸ“š Project Awareness & Context + +- **Use consistent PydanticAI naming conventions** and agent structure patterns +- **Follow established agent directory organization** patterns (agent.py, tools.py, models.py) +- **Leverage PydanticAI examples extensively** - Study existing patterns before creating new agents + +## 🧱 Agent Structure & Modularity + +- **Never create files longer than 500 lines** - Split into modules when approaching limit +- **Organize agent code into clearly separated modules** grouped by responsibility: + - `agent.py` - Main agent definition and execution logic + - `tools.py` - Tool functions used by the agent + - `models.py` - Pydantic output models and dependency classes + - `dependencies.py` - Context dependencies and external service integrations +- **Use clear, consistent imports** - Import from pydantic_ai package appropriately +- **Use environment variables for API keys** - Never hardcode sensitive information + +## πŸ€– PydanticAI Development Standards + +### Agent Creation Patterns +- **Use model-agnostic design** - Support multiple providers (OpenAI, Anthropic, Gemini) +- **Implement dependency injection** - Use deps_type for external services and context +- **Define structured outputs** - Use Pydantic models for result validation +- **Include comprehensive system prompts** - Both static and dynamic instructions + +### Tool Integration Standards +- **Use @agent.tool decorator** for context-aware tools with RunContext[DepsType] +- **Use @agent.tool_plain decorator** for simple tools without context dependencies +- **Implement proper parameter validation** - Use Pydantic models for tool parameters +- **Handle tool errors gracefully** - Implement retry mechanisms and error recovery + +### Model Provider Configuration +```python +# Use environment-based configuration, never hardcode model strings +from pydantic_settings import BaseSettings +from pydantic_ai.providers.openai import OpenAIProvider +from pydantic_ai.models.openai import OpenAIModel + +class Settings(BaseSettings): + # LLM Configuration + llm_provider: str = "openai" + llm_api_key: str + llm_model: str = "gpt-4" + llm_base_url: str = "https://api.openai.com/v1" + + class Config: + env_file = ".env" + +def get_llm_model(): + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key=settings.llm_api_key + ) + return OpenAIModel(settings.llm_model, provider=provider) +``` + +### Testing Standards for AI Agents +- **Use TestModel for development** - Fast validation without API calls +- **Use FunctionModel for custom behavior** - Control agent responses in tests +- **Use Agent.override() for testing** - Replace models in test contexts +- **Test both sync and async patterns** - Ensure compatibility with different execution modes +- **Test tool validation** - Verify tool parameter schemas and error handling + +## βœ… Task Management for AI Development + +- **Break agent development into clear steps** with specific completion criteria +- **Mark tasks complete immediately** after finishing agent implementations +- **Update task status in real-time** as agent development progresses +- **Test agent behavior** before marking implementation tasks complete + +## πŸ“Ž PydanticAI Coding Standards + +### Agent Architecture +```python +# Follow main_agent_reference patterns - no result_type unless structured output needed +from pydantic_ai import Agent, RunContext +from dataclasses import dataclass + +@dataclass +class AgentDependencies: + """Dependencies for agent execution""" + api_key: str + session_id: str = None + +# Simple agent with string output (default) +agent = Agent( + get_llm_model(), # Use environment-based configuration + deps_type=AgentDependencies, + system_prompt="You are a helpful assistant..." +) + +@agent.tool +async def example_tool( + ctx: RunContext[AgentDependencies], + query: str +) -> str: + """Tool with proper context access""" + return await external_api_call(ctx.deps.api_key, query) +``` + +### Security Best Practices +- **API key management** - Use environment variables, never commit keys +- **Input validation** - Use Pydantic models for all tool parameters +- **Rate limiting** - Implement proper request throttling for external APIs +- **Prompt injection prevention** - Validate and sanitize user inputs +- **Error handling** - Never expose sensitive information in error messages + +### Common PydanticAI Gotchas +- **Async/sync mixing issues** - Be consistent with async/await patterns throughout +- **Model token limits** - Different models have different context limits, plan accordingly +- **Dependency injection complexity** - Keep dependency graphs simple and well-typed +- **Tool error handling failures** - Always implement proper retry and fallback mechanisms +- **Context state management** - Design stateless tools when possible for reliability + +## πŸ” Research Standards for AI Agents + +- **Use Archon MCP server** - Leverage available PydanticAI documentation via RAG +- **Study official examples** - ai.pydantic.dev/examples has working implementations +- **Research model capabilities** - Understand provider-specific features and limitations +- **Document integration patterns** - Include external service integration examples + +## 🎯 Implementation Standards for AI Agents + +- **Follow the PRP workflow religiously** - Don't skip agent validation steps +- **Always test with TestModel first** - Validate agent logic before using real models +- **Use existing agent patterns** rather than creating from scratch +- **Include comprehensive error handling** for tool failures and model errors +- **Test streaming patterns** when implementing real-time agent interactions + +## 🚫 Anti-Patterns to Always Avoid + +- ❌ Don't skip agent testing - Always use TestModel/FunctionModel for validation +- ❌ Don't hardcode model strings - Use environment-based configuration like main_agent_reference +- ❌ Don't use result_type unless structured output is specifically needed - default to string +- ❌ Don't ignore async patterns - PydanticAI has specific async/sync considerations +- ❌ Don't create complex dependency graphs - Keep dependencies simple and testable +- ❌ Don't forget tool error handling - Implement proper retry and graceful degradation +- ❌ Don't skip input validation - Use Pydantic models for all external inputs + +## πŸ”§ Tool Usage Standards for AI Development + +- **Use web search extensively** for PydanticAI research and documentation +- **Follow PydanticAI command patterns** for slash commands and agent workflows +- **Use agent validation loops** to ensure quality at each development step +- **Test with multiple model providers** to ensure agent compatibility + +## πŸ§ͺ Testing & Reliability for AI Agents + +- **Always create comprehensive agent tests** for tools, outputs, and error handling +- **Test agent behavior with TestModel** before using real model providers +- **Include edge case testing** for tool failures and model provider issues +- **Test both structured and unstructured outputs** to ensure agent flexibility +- **Validate dependency injection** works correctly in test environments + +These global rules apply specifically to PydanticAI agent development and ensure production-ready AI applications with proper error handling, testing, and security practices. \ No newline at end of file diff --git a/use-cases/pydantic-ai/PRPs/INITIAL.md b/use-cases/pydantic-ai/PRPs/INITIAL.md new file mode 100644 index 0000000..b97be80 --- /dev/null +++ b/use-cases/pydantic-ai/PRPs/INITIAL.md @@ -0,0 +1,25 @@ +## FEATURE: + +Build a simple customer support chatbot using PydanticAI that can answer basic questions and escalate complex issues to human agents. + +## EXAMPLES: + +- Basic chat agent with conversation memory +- Tool-enabled agent with web search capabilities +- Structured output agent for data validation +- Testing examples with TestModel and FunctionModel + +## DOCUMENTATION: + +- PydanticAI Official Documentation: https://ai.pydantic.dev/ +- Agent Creation Guide: https://ai.pydantic.dev/agents/ +- Tool Integration: https://ai.pydantic.dev/tools/ +- Testing Patterns: https://ai.pydantic.dev/testing/ +- Model Providers: https://ai.pydantic.dev/models/ + +## OTHER CONSIDERATIONS: + +- Use environment variables for API key configuration instead of hardcoded model strings +- Keep agents simple - default to string output unless structured output is specifically needed +- Follow the main_agent_reference patterns for configuration and providers +- Always include comprehensive testing with TestModel for development \ No newline at end of file diff --git a/use-cases/pydantic-ai/PRPs/templates/prp_pydantic_ai_base.md b/use-cases/pydantic-ai/PRPs/templates/prp_pydantic_ai_base.md new file mode 100644 index 0000000..64892d2 --- /dev/null +++ b/use-cases/pydantic-ai/PRPs/templates/prp_pydantic_ai_base.md @@ -0,0 +1,410 @@ +--- +name: "PydanticAI Agent PRP Template" +description: "Template for generating comprehensive PRPs for PydanticAI agent development projects" +--- + +## Purpose + +[Brief description of the PydanticAI agent to be built and its main purpose] + +## Core Principles + +1. **PydanticAI Best Practices**: Deep integration with PydanticAI patterns for agent creation, tools, and structured outputs +2. **Production Ready**: Include security, testing, and monitoring for production deployments +3. **Type Safety First**: Leverage PydanticAI's type-safe design and Pydantic validation throughout +4. **Context Engineering Integration**: Apply proven context engineering workflows to AI agent development +5. **Comprehensive Testing**: Use TestModel and FunctionModel for thorough agent validation + +## ⚠️ Implementation Guidelines: Don't Over-Engineer + +**IMPORTANT**: Keep your agent implementation focused and practical. Don't build unnecessary complexity. + +### What NOT to do: +- ❌ **Don't create dozens of tools** - Build only the tools your agent actually needs +- ❌ **Don't over-complicate dependencies** - Keep dependency injection simple and focused +- ❌ **Don't add unnecessary abstractions** - Follow main_agent_reference patterns directly +- ❌ **Don't build complex workflows** unless specifically required +- ❌ **Don't add structured output** unless validation is specifically needed (default to string) + +### What TO do: +- βœ… **Start simple** - Build the minimum viable agent that meets requirements +- βœ… **Add tools incrementally** - Implement only what the agent needs to function +- βœ… **Follow main_agent_reference** - Use proven patterns, don't reinvent +- βœ… **Use string output by default** - Only add result_type when validation is required +- βœ… **Test early and often** - Use TestModel to validate as you build + +### Key Question: +**"Does this agent really need this feature to accomplish its core purpose?"** + +If the answer is no, don't build it. Keep it simple, focused, and functional. + +--- + +## Goal + +[Detailed description of what the agent should accomplish] + +## Why + +[Explanation of why this agent is needed and what problem it solves] + +## What + +### Agent Type Classification +- [ ] **Chat Agent**: Conversational interface with memory and context +- [ ] **Tool-Enabled Agent**: Agent with external tool integration capabilities +- [ ] **Workflow Agent**: Multi-step task processing and orchestration +- [ ] **Structured Output Agent**: Complex data validation and formatting + +### Model Provider Requirements +- [ ] **OpenAI**: `openai:gpt-4o` or `openai:gpt-4o-mini` +- [ ] **Anthropic**: `anthropic:claude-3-5-sonnet-20241022` or `anthropic:claude-3-5-haiku-20241022` +- [ ] **Google**: `gemini-1.5-flash` or `gemini-1.5-pro` +- [ ] **Fallback Strategy**: Multiple provider support with automatic failover + +### External Integrations +- [ ] Database connections (specify type: PostgreSQL, MongoDB, etc.) +- [ ] REST API integrations (list required services) +- [ ] File system operations +- [ ] Web scraping or search capabilities +- [ ] Real-time data sources + +### Success Criteria +- [ ] Agent successfully handles specified use cases +- [ ] All tools work correctly with proper error handling +- [ ] Structured outputs validate according to Pydantic models +- [ ] Comprehensive test coverage with TestModel and FunctionModel +- [ ] Security measures implemented (API keys, input validation, rate limiting) +- [ ] Performance meets requirements (response time, throughput) + +## All Needed Context + +### PydanticAI Documentation & Research + +```yaml +# MCP servers +- mcp: Archon + query: "PydanticAI agent creation model providers tools dependencies" + why: Core framework understanding and latest patterns + +# ESSENTIAL PYDANTIC AI DOCUMENTATION - Must be researched +- url: https://ai.pydantic.dev/ + why: Official PydanticAI documentation with getting started guide + content: Agent creation, model providers, dependency injection patterns + +- url: https://ai.pydantic.dev/agents/ + why: Comprehensive agent architecture and configuration patterns + content: System prompts, output types, execution methods, agent composition + +- url: https://ai.pydantic.dev/tools/ + why: Tool integration patterns and function registration + content: @agent.tool decorators, RunContext usage, parameter validation + +- url: https://ai.pydantic.dev/testing/ + why: Testing strategies specific to PydanticAI agents + content: TestModel, FunctionModel, Agent.override(), pytest patterns + +- url: https://ai.pydantic.dev/models/ + why: Model provider configuration and authentication + content: OpenAI, Anthropic, Gemini setup, API key management, fallback models + +# Prebuilt examples +- path: examples/ + why: Reference implementations for Pydantic AI agents + content: A bunch of already built simple Pydantic AI examples to reference including how to set up models and providers + +- path: examples/cli.py + why: Shows real-world interaction with Pydantic AI agents + content: Conversational CLI with streaming, tool call visibility, and conversation handling - demonstrates how users actually interact with agents +``` + +### Agent Architecture Research + +```yaml +# PydanticAI Architecture Patterns (follow main_agent_reference) +agent_structure: + configuration: + - settings.py: Environment-based configuration with pydantic-settings + - providers.py: Model provider abstraction with get_llm_model() + - Environment variables for API keys and model selection + - Never hardcode model strings like "openai:gpt-4o" + + agent_definition: + - Default to string output (no result_type unless structured output needed) + - Use get_llm_model() from providers.py for model configuration + - System prompts as string constants or functions + - Dataclass dependencies for external services + + tool_integration: + - @agent.tool for context-aware tools with RunContext[DepsType] + - Tool functions as pure functions that can be called independently + - Proper error handling and logging in tool implementations + - Dependency injection through RunContext.deps + + testing_strategy: + - TestModel for rapid development validation + - FunctionModel for custom behavior testing + - Agent.override() for test isolation + - Comprehensive tool testing with mocks +``` + +### Security and Production Considerations + +```yaml +# PydanticAI Security Patterns (research required) +security_requirements: + api_management: + environment_variables: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY"] + secure_storage: "Never commit API keys to version control" + rotation_strategy: "Plan for key rotation and management" + + input_validation: + sanitization: "Validate all user inputs with Pydantic models" + prompt_injection: "Implement prompt injection prevention strategies" + rate_limiting: "Prevent abuse with proper throttling" + + output_security: + data_filtering: "Ensure no sensitive data in agent responses" + content_validation: "Validate output structure and content" + logging_safety: "Safe logging without exposing secrets" +``` + +### Common PydanticAI Gotchas (research and document) + +```yaml +# Agent-specific gotchas to research and address +implementation_gotchas: + async_patterns: + issue: "Mixing sync and async agent calls inconsistently" + research: "PydanticAI async/await best practices" + solution: "[To be documented based on research]" + + model_limits: + issue: "Different models have different capabilities and token limits" + research: "Model provider comparison and capabilities" + solution: "[To be documented based on research]" + + dependency_complexity: + issue: "Complex dependency graphs can be hard to debug" + research: "Dependency injection best practices in PydanticAI" + solution: "[To be documented based on research]" + + tool_error_handling: + issue: "Tool failures can crash entire agent runs" + research: "Error handling and retry patterns for tools" + solution: "[To be documented based on research]" +``` + +## Implementation Blueprint + +### Technology Research Phase + +**RESEARCH REQUIRED - Complete before implementation:** + +βœ… **PydanticAI Framework Deep Dive:** +- [ ] Agent creation patterns and best practices +- [ ] Model provider configuration and fallback strategies +- [ ] Tool integration patterns (@agent.tool vs @agent.tool_plain) +- [ ] Dependency injection system and type safety +- [ ] Testing strategies with TestModel and FunctionModel + +βœ… **Agent Architecture Investigation:** +- [ ] Project structure conventions (agent.py, tools.py, models.py, dependencies.py) +- [ ] System prompt design (static vs dynamic) +- [ ] Structured output validation with Pydantic models +- [ ] Async/sync patterns and streaming support +- [ ] Error handling and retry mechanisms + +βœ… **Security and Production Patterns:** +- [ ] API key management and secure configuration +- [ ] Input validation and prompt injection prevention +- [ ] Rate limiting and monitoring strategies +- [ ] Logging and observability patterns +- [ ] Deployment and scaling considerations + +### Agent Implementation Plan + +```yaml +Implementation Task 1 - Agent Architecture Setup (Follow main_agent_reference): + CREATE agent project structure: + - settings.py: Environment-based configuration with pydantic-settings + - providers.py: Model provider abstraction with get_llm_model() + - agent.py: Main agent definition (default string output) + - tools.py: Tool functions with proper decorators + - dependencies.py: External service integrations (dataclasses) + - tests/: Comprehensive test suite + +Implementation Task 2 - Core Agent Development: + IMPLEMENT agent.py following main_agent_reference patterns: + - Use get_llm_model() from providers.py for model configuration + - System prompt as string constant or function + - Dependency injection with dataclass + - NO result_type unless structured output specifically needed + - Error handling and logging + +Implementation Task 3 - Tool Integration: + DEVELOP tools.py: + - Tool functions with @agent.tool decorators + - RunContext[DepsType] integration for dependency access + - Parameter validation with proper type hints + - Error handling and retry mechanisms + - Tool documentation and schema generation + +Implementation Task 4 - Data Models and Dependencies: + CREATE models.py and dependencies.py: + - Pydantic models for structured outputs + - Dependency classes for external services + - Input validation models for tools + - Custom validators and constraints + +Implementation Task 5 - Comprehensive Testing: + IMPLEMENT testing suite: + - TestModel integration for rapid development + - FunctionModel tests for custom behavior + - Agent.override() patterns for isolation + - Integration tests with real providers + - Tool validation and error scenario testing + +Implementation Task 6 - Security and Configuration: + SETUP security patterns: + - Environment variable management for API keys + - Input sanitization and validation + - Rate limiting implementation + - Secure logging and monitoring + - Production deployment configuration +``` + +## Validation Loop + +### Level 1: Agent Structure Validation + +```bash +# Verify complete agent project structure +find agent_project -name "*.py" | sort +test -f agent_project/agent.py && echo "Agent definition present" +test -f agent_project/tools.py && echo "Tools module present" +test -f agent_project/models.py && echo "Models module present" +test -f agent_project/dependencies.py && echo "Dependencies module present" + +# Verify proper PydanticAI imports +grep -q "from pydantic_ai import Agent" agent_project/agent.py +grep -q "@agent.tool" agent_project/tools.py +grep -q "from pydantic import BaseModel" agent_project/models.py + +# Expected: All required files with proper PydanticAI patterns +# If missing: Generate missing components with correct patterns +``` + +### Level 2: Agent Functionality Validation + +```bash +# Test agent can be imported and instantiated +python -c " +from agent_project.agent import agent +print('Agent created successfully') +print(f'Model: {agent.model}') +print(f'Tools: {len(agent.tools)}') +" + +# Test with TestModel for validation +python -c " +from pydantic_ai.models.test import TestModel +from agent_project.agent import agent +test_model = TestModel() +with agent.override(model=test_model): + result = agent.run_sync('Test message') + print(f'Agent response: {result.output}') +" + +# Expected: Agent instantiation works, tools registered, TestModel validation passes +# If failing: Debug agent configuration and tool registration +``` + +### Level 3: Comprehensive Testing Validation + +```bash +# Run complete test suite +cd agent_project +python -m pytest tests/ -v + +# Test specific agent behavior +python -m pytest tests/test_agent.py::test_agent_response -v +python -m pytest tests/test_tools.py::test_tool_validation -v +python -m pytest tests/test_models.py::test_output_validation -v + +# Expected: All tests pass, comprehensive coverage achieved +# If failing: Fix implementation based on test failures +``` + +### Level 4: Production Readiness Validation + +```bash +# Verify security patterns +grep -r "API_KEY" agent_project/ | grep -v ".py:" # Should not expose keys +test -f agent_project/.env.example && echo "Environment template present" + +# Check error handling +grep -r "try:" agent_project/ | wc -l # Should have error handling +grep -r "except" agent_project/ | wc -l # Should have exception handling + +# Verify logging setup +grep -r "logging\|logger" agent_project/ | wc -l # Should have logging + +# Expected: Security measures in place, error handling comprehensive, logging configured +# If issues: Implement missing security and production patterns +``` + +## Final Validation Checklist + +### Agent Implementation Completeness + +- [ ] Complete agent project structure: `agent.py`, `tools.py`, `models.py`, `dependencies.py` +- [ ] Agent instantiation with proper model provider configuration +- [ ] Tool registration with @agent.tool decorators and RunContext integration +- [ ] Structured outputs with Pydantic model validation +- [ ] Dependency injection properly configured and tested +- [ ] Comprehensive test suite with TestModel and FunctionModel + +### PydanticAI Best Practices + +- [ ] Type safety throughout with proper type hints and validation +- [ ] Security patterns implemented (API keys, input validation, rate limiting) +- [ ] Error handling and retry mechanisms for robust operation +- [ ] Async/sync patterns consistent and appropriate +- [ ] Documentation and code comments for maintainability + +### Production Readiness + +- [ ] Environment configuration with .env files and validation +- [ ] Logging and monitoring setup for observability +- [ ] Performance optimization and resource management +- [ ] Deployment readiness with proper configuration management +- [ ] Maintenance and update strategies documented + +--- + +## Anti-Patterns to Avoid + +### PydanticAI Agent Development + +- ❌ Don't skip TestModel validation - always test with TestModel during development +- ❌ Don't hardcode API keys - use environment variables for all credentials +- ❌ Don't ignore async patterns - PydanticAI has specific async/sync requirements +- ❌ Don't create complex tool chains - keep tools focused and composable +- ❌ Don't skip error handling - implement comprehensive retry and fallback mechanisms + +### Agent Architecture + +- ❌ Don't mix agent types - clearly separate chat, tool, workflow, and structured output patterns +- ❌ Don't ignore dependency injection - use proper type-safe dependency management +- ❌ Don't skip output validation - always use Pydantic models for structured responses +- ❌ Don't forget tool documentation - ensure all tools have proper descriptions and schemas + +### Security and Production + +- ❌ Don't expose sensitive data - validate all outputs and logs for security +- ❌ Don't skip input validation - sanitize and validate all user inputs +- ❌ Don't ignore rate limiting - implement proper throttling for external services +- ❌ Don't deploy without monitoring - include proper observability from the start + +**RESEARCH STATUS: [TO BE COMPLETED]** - Complete comprehensive PydanticAI research before implementation begins. \ No newline at end of file diff --git a/use-cases/pydantic-ai/README.md b/use-cases/pydantic-ai/README.md new file mode 100644 index 0000000..a14c66e --- /dev/null +++ b/use-cases/pydantic-ai/README.md @@ -0,0 +1,532 @@ +# Pydantic AI Context Engineering Template + +A comprehensive template for building production-grade AI agents using Pydantic AI with context engineering best practices, tools integration, structured outputs, and comprehensive testing patterns. + +## πŸš€ Quick Start - Copy Template + +**Get started in 2 minutes:** + +```bash +# Clone the context engineering repository +git clone https://github.com/coleam00/Context-Engineering-Intro.git +cd Context-Engineering-Intro/use-cases/pydantic-ai + +# 1. Copy this template to your new project +python copy_template.py /path/to/my-agent-project + +# 2. Navigate to your project +cd /path/to/my-agent-project + +# 3. Set up environment +python -m venv venv +source venv/bin/activate # On Windows: venv\Scripts\activate + +# 4. Start building with the PRP workflow +# Edit PRPs/INITIAL.md with your requirements, then: +/generate-pydantic-ai-prp PRPs/INITIAL.md +/execute-pydantic-ai-prp PRPs/generated_prp.md +``` + +## πŸ“– What is This Template? + +This template provides everything you need to build sophisticated Pydantic AI agents using proven context engineering workflows. It combines: + +- **Pydantic AI Best Practices**: Type-safe agents with tools, structured outputs, and dependency injection +- **Context Engineering Workflows**: Proven PRP (Problem Requirements Planning) methodology +- **Production Patterns**: Security, testing, monitoring, and deployment-ready code +- **Working Examples**: Complete agent implementations you can learn from and extend + +## 🎯 PRP Framework Workflow + +This template uses a 3-step context engineering workflow for building AI agents: + +### 1. **Define Requirements** (`PRPs/INITIAL.md`) +Start by clearly defining what your agent needs to do: +```markdown +# Customer Support Agent - Initial Requirements + +## Overview +Build an intelligent customer support agent that can handle inquiries, +access customer data, and escalate issues appropriately. + +## Core Requirements +- Multi-turn conversations with context and memory +- Customer authentication and account access +- Account balance and transaction queries +- Payment processing and refund handling +... +``` + +### 2. **Generate Implementation Plan** +```bash +/generate-pydantic-ai-prp PRPs/INITIAL.md +``` +This creates a comprehensive Problem Requirements Planning document that includes: +- Pydantic AI technology research and best practices +- Agent architecture design with tools and dependencies +- Implementation roadmap with validation loops +- Security patterns and production considerations + +### 3. **Execute Implementation** +```bash +/execute-pydantic-ai-prp PRPs/your_agent.md +``` +This implements the complete agent based on the PRP, including: +- Agent creation with proper model provider configuration +- Tool integration with error handling and validation +- Structured output models with Pydantic validation +- Comprehensive testing with TestModel and FunctionModel +- Security patterns and production deployment setup + +## πŸ“‚ Template Structure + +``` +pydantic-ai/ +β”œβ”€β”€ CLAUDE.md # Pydantic AI global development rules +β”œβ”€β”€ copy_template.py # Template deployment script +β”œβ”€β”€ .claude/commands/ +β”‚ β”œβ”€β”€ generate-pydantic-ai-prp.md # PRP generation for agents +β”‚ └── execute-pydantic-ai-prp.md # PRP execution for agents +β”œβ”€β”€ PRPs/ +β”‚ β”œβ”€β”€ templates/ +β”‚ β”‚ └── prp_pydantic_ai_base.md # Base PRP template for agents +β”‚ └── INITIAL.md # Example agent requirements +β”œβ”€β”€ examples/ +β”‚ β”œβ”€β”€ basic_chat_agent/ # Simple conversational agent +β”‚ β”‚ β”œβ”€β”€ agent.py # Agent with memory and context +β”‚ β”‚ └── README.md # Usage guide +β”‚ β”œβ”€β”€ tool_enabled_agent/ # Agent with external tools +β”‚ β”‚ β”œβ”€β”€ agent.py # Web search + calculator tools +β”‚ β”‚ └── requirements.txt # Dependencies +β”‚ └── testing_examples/ # Comprehensive testing patterns +β”‚ β”œβ”€β”€ test_agent_patterns.py # TestModel, FunctionModel examples +β”‚ └── pytest.ini # Test configuration +└── README.md # This file +``` + +## πŸ€– Agent Examples Included + +### 1. Main Agent Reference (`examples/main_agent_reference/`) +**The canonical reference implementation** showing proper Pydantic AI patterns: +- Environment-based configuration with `settings.py` and `providers.py` +- Clean separation of concerns between email and research agents +- Tool integration with external APIs (Gmail, Brave Search) +- Production-ready error handling and logging + +**Key Files:** +- `settings.py`: Environment configuration with pydantic-settings +- `providers.py`: Model provider abstraction with `get_llm_model()` +- `research_agent.py`: Multi-tool agent with web search and email integration +- `email_agent.py`: Specialized agent for Gmail draft creation + +### 2. Basic Chat Agent (`examples/basic_chat_agent/`) +A simple conversational agent demonstrating core patterns: +- **Environment-based model configuration** (follows main_agent_reference) +- **String output by default** (no `result_type` unless needed) +- System prompts (static and dynamic) +- Conversation memory with dependency injection + +**Key Features:** +- Simple string responses (not structured output) +- Settings-based configuration pattern +- Conversation context tracking +- Clean, minimal implementation + +### 3. Tool-Enabled Agent (`examples/tool_enabled_agent/`) +An agent with tool integration capabilities: +- **Environment-based configuration** (follows main_agent_reference) +- **String output by default** (no unnecessary structure) +- Web search and calculation tools +- Error handling and retry mechanisms + +**Key Features:** +- `@agent.tool` decorator patterns +- RunContext for dependency injection +- Tool error handling and recovery +- Simple string responses from tools + +### 4. Structured Output Agent (`examples/structured_output_agent/`) +**NEW**: Shows when to use `result_type` for data validation: +- **Environment-based configuration** (follows main_agent_reference) +- **Structured output with Pydantic validation** (when specifically needed) +- Data analysis with statistical tools +- Professional report generation + +**Key Features:** +- Demonstrates proper use of `result_type` +- Pydantic validation for business reports +- Data analysis tools with numerical statistics +- Clear documentation on when to use structured vs string output + +### 5. Testing Examples (`examples/testing_examples/`) +Comprehensive testing patterns for Pydantic AI agents: +- TestModel for rapid development validation +- FunctionModel for custom behavior testing +- Agent.override() for test isolation +- Pytest fixtures and async testing + +**Key Features:** +- Unit testing without API costs +- Mock dependency injection +- Tool validation and error scenario testing +- Integration testing patterns + +## πŸ› οΈ Core Pydantic AI Patterns + +### Environment-Based Configuration (from main_agent_reference) +```python +# settings.py - Environment configuration +from pydantic_settings import BaseSettings +from pydantic import Field + +class Settings(BaseSettings): + llm_provider: str = Field(default="openai") + llm_api_key: str = Field(...) + llm_model: str = Field(default="gpt-4") + llm_base_url: str = Field(default="https://api.openai.com/v1") + + class Config: + env_file = ".env" + +# providers.py - Model provider abstraction +from pydantic_ai.providers.openai import OpenAIProvider +from pydantic_ai.models.openai import OpenAIModel + +def get_llm_model() -> OpenAIModel: + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key=settings.llm_api_key + ) + return OpenAIModel(settings.llm_model, provider=provider) +``` + +### Simple Agent (String Output - Default) +```python +from pydantic_ai import Agent, RunContext +from dataclasses import dataclass + +@dataclass +class AgentDependencies: + """Dependencies for agent execution""" + api_key: str + session_id: str = None + +# Simple agent - no result_type, defaults to string +agent = Agent( + get_llm_model(), # Environment-based configuration + deps_type=AgentDependencies, + system_prompt="You are a helpful assistant..." +) +``` + +### Structured Output Agent (When Validation Needed) +```python +from pydantic import BaseModel, Field + +class AnalysisReport(BaseModel): + """Use result_type ONLY when you need validation""" + summary: str + confidence: float = Field(ge=0.0, le=1.0) + insights: list[str] = Field(min_items=1) + +# Structured agent - result_type specified for validation +structured_agent = Agent( + get_llm_model(), + deps_type=AgentDependencies, + result_type=AnalysisReport, # Only when structure is required + system_prompt="You are a data analyst..." +) +``` + +### Tool Integration +```python +@agent.tool +async def example_tool( + ctx: RunContext[AgentDependencies], + query: str +) -> str: + """Tool with proper error handling - returns string.""" + try: + result = await external_api_call(ctx.deps.api_key, query) + return f"API result: {result}" + except Exception as e: + logger.error(f"Tool error: {e}") + return f"Tool temporarily unavailable: {str(e)}" +``` + +### Testing with TestModel +```python +from pydantic_ai.models.test import TestModel + +def test_simple_agent(): + """Test simple agent with string output.""" + test_model = TestModel() + with agent.override(model=test_model): + result = agent.run_sync("Test message") + assert isinstance(result.data, str) # String output + +def test_structured_agent(): + """Test structured agent with validation.""" + test_model = TestModel( + custom_output_text='{"summary": "Test", "confidence": 0.8, "insights": ["insight1"]}' + ) + with structured_agent.override(model=test_model): + result = structured_agent.run_sync("Analyze this data") + assert isinstance(result.data, AnalysisReport) # Validated object + assert 0.0 <= result.data.confidence <= 1.0 +``` + +## 🎯 When to Use String vs Structured Output + +### Use String Output (Default) βœ… +**Most agents should use string output** - don't specify `result_type`: + +```python +# βœ… Simple chat agent +chat_agent = Agent(get_llm_model(), system_prompt="You are helpful...") + +# βœ… Tool-enabled agent +tool_agent = Agent(get_llm_model(), tools=[search_tool], system_prompt="...") + +# Result: agent.run() returns string +result = agent.run_sync("Hello") +print(result.data) # "Hello! How can I help you today?" +``` + +**When to use string output:** +- Conversational agents +- Creative writing +- Flexible responses +- Human-readable output +- Simple tool responses + +### Use Structured Output (Specific Cases) 🎯 +**Only use `result_type` when you need validation:** + +```python +# βœ… Data analysis requiring validation +analysis_agent = Agent( + get_llm_model(), + result_type=AnalysisReport, # Pydantic model with validation + system_prompt="You are a data analyst..." +) + +# Result: agent.run() returns validated Pydantic object +result = analysis_agent.run_sync("Analyze sales data") +print(result.data.confidence) # 0.85 (validated 0.0-1.0) +``` + +**When to use structured output:** +- Data validation required +- API integrations needing specific schemas +- Business reports with consistent formatting +- Downstream processing requiring type safety +- Database insertion with validated fields + +### Key Rule πŸ“ +**Start with string output. Only add `result_type` when you specifically need validation or structure.** + +## πŸ”’ Security Best Practices + +This template includes production-ready security patterns: + +### API Key Management +```bash +# Environment variables (never commit to code) +export LLM_API_KEY="your-api-key-here" +export LLM_MODEL="gpt-4" +export LLM_BASE_URL="https://api.openai.com/v1" + +# Or use .env file (git-ignored) +echo "LLM_API_KEY=your-api-key-here" > .env +echo "LLM_MODEL=gpt-4" >> .env +``` + +### Input Validation +```python +from pydantic import BaseModel, Field + +class ToolInput(BaseModel): + query: str = Field(max_length=1000, description="Search query") + max_results: int = Field(ge=1, le=10, default=5) +``` + +### Error Handling +```python +@agent.tool +async def secure_tool(ctx: RunContext[Deps], input_data: str) -> str: + try: + # Validate and sanitize input + cleaned_input = sanitize_input(input_data) + result = await process_safely(cleaned_input) + return result + except Exception as e: + # Log error without exposing sensitive data + logger.error(f"Tool error: {type(e).__name__}") + return "An error occurred. Please try again." +``` + +## πŸ§ͺ Testing Your Agents + +### Development Testing (Fast, No API Costs) +```python +from pydantic_ai.models.test import TestModel + +# Test with TestModel for rapid iteration +test_model = TestModel() +with agent.override(model=test_model): + result = agent.run_sync("Test input") + print(result.data) +``` + +### Custom Behavior Testing +```python +from pydantic_ai.models.test import FunctionModel + +def custom_response(messages, tools): + """Custom function to control agent responses.""" + return '{"response": "Custom test response", "confidence": 0.9}' + +function_model = FunctionModel(function=custom_response) +with agent.override(model=function_model): + result = agent.run_sync("Test input") +``` + +### Integration Testing +```python +# Test with real models (use sparingly due to costs) +@pytest.mark.integration +async def test_agent_integration(): + result = await agent.run("Real test message") + assert result.data.confidence > 0.5 +``` + +## πŸš€ Deployment Patterns + +### Environment Configuration +```python +# settings.py - Production configuration +from pydantic_settings import BaseSettings + +class Settings(BaseSettings): + # LLM Configuration + llm_api_key: str + llm_model: str = "gpt-4" + llm_base_url: str = "https://api.openai.com/v1" + + # Production settings + app_env: str = "production" + log_level: str = "INFO" + retries: int = 3 + + class Config: + env_file = ".env" + +# agent.py - Use environment settings +agent = Agent( + get_llm_model(), # From providers.py + retries=settings.retries, + system_prompt="Production agent..." +) +``` + +### Docker Deployment +```dockerfile +FROM python:3.11-slim + +WORKDIR /app +COPY requirements.txt . +RUN pip install -r requirements.txt + +COPY . . +EXPOSE 8000 + +CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] +``` + +## πŸŽ“ Learning Path + +### 1. Start with Examples +- Run `examples/basic_chat_agent/agent.py` to see a simple agent +- Explore `examples/tool_enabled_agent/` for tool integration +- Study `examples/testing_examples/` for testing patterns + +### 2. Use the PRP Workflow +- Edit `PRPs/INITIAL.md` with your agent requirements +- Generate a PRP: `/generate-pydantic-ai-prp PRPs/INITIAL.md` +- Execute the PRP: `/execute-pydantic-ai-prp PRPs/generated_file.md` + +### 3. Build Your Own Agent +- Start with the basic chat agent pattern +- Add tools for external capabilities +- Implement structured outputs for your use case +- Add comprehensive testing and error handling + +### 4. Production Deployment +- Implement security patterns from `CLAUDE.md` +- Add monitoring and logging +- Set up CI/CD with automated testing +- Deploy with proper scaling and availability + +## 🀝 Common Gotchas & Solutions + +Based on extensive Pydantic AI research, here are common issues and solutions: + +### Async/Sync Patterns +```python +# ❌ Don't mix sync and async inconsistently +def bad_tool(ctx): + return asyncio.run(some_async_function()) # Anti-pattern + +# βœ… Be consistent with async patterns +@agent.tool +async def good_tool(ctx: RunContext[Deps]) -> str: + result = await some_async_function() + return result +``` + +### Model Token Limits +```python +# βœ… Handle different model capabilities +from pydantic_ai.models import FallbackModel + +model = FallbackModel([ + "openai:gpt-4o", # High capability, higher cost + "openai:gpt-4o-mini", # Fallback option +]) +``` + +### Tool Error Handling +```python +# βœ… Implement proper retry and fallback +@agent.tool +async def resilient_tool(ctx: RunContext[Deps], query: str) -> str: + for attempt in range(3): + try: + return await external_api_call(query) + except TemporaryError: + if attempt == 2: + return "Service temporarily unavailable" + await asyncio.sleep(2 ** attempt) +``` + +## πŸ“š Additional Resources + +- **Official Pydantic AI Documentation**: https://ai.pydantic.dev/ +- **Model Provider Guides**: https://ai.pydantic.dev/models/ +- **Tool Integration Patterns**: https://ai.pydantic.dev/tools/ +- **Testing Strategies**: https://ai.pydantic.dev/testing/ +- **Context Engineering Methodology**: See main repository README + +## πŸ†˜ Support & Contributing + +- **Issues**: Report problems with the template or examples +- **Improvements**: Contribute additional examples or patterns +- **Questions**: Ask about Pydantic AI integration or context engineering + +This template is part of the larger Context Engineering framework. See the main repository for more context engineering templates and methodologies. + +--- + +**Ready to build production-grade AI agents?** Start with `python copy_template.py my-agent-project` and follow the PRP workflow! πŸš€ \ No newline at end of file diff --git a/use-cases/pydantic-ai/copy_template.py b/use-cases/pydantic-ai/copy_template.py new file mode 100644 index 0000000..58ed07a --- /dev/null +++ b/use-cases/pydantic-ai/copy_template.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python3 +""" +PydanticAI Template Copy Script + +Copies the complete PydanticAI context engineering template to a target directory +for starting new PydanticAI agent development projects. + +Usage: + python copy_template.py + +Example: + python copy_template.py my-agent-project + python copy_template.py /path/to/my-new-agent +""" + +import os +import sys +import shutil +import argparse +from pathlib import Path +from typing import List, Tuple + + +def get_template_files() -> List[Tuple[str, str]]: + """ + Get list of template files to copy with their relative paths. + + Returns: + List of (source_path, relative_path) tuples + """ + template_root = Path(__file__).parent + files_to_copy = [] + + # Core template files + core_files = [ + "CLAUDE.md", + "README.md", + ] + + for file in core_files: + source_path = template_root / file + if source_path.exists(): + # Rename README.md to readme_template.md in target + target_name = "README_TEMPLATE.md" if file == "README.md" else file + files_to_copy.append((str(source_path), target_name)) + + # Claude commands directory + commands_dir = template_root / ".claude" / "commands" + if commands_dir.exists(): + for file in commands_dir.glob("*.md"): + rel_path = f".claude/commands/{file.name}" + files_to_copy.append((str(file), rel_path)) + + # PRPs directory + prps_dir = template_root / "PRPs" + if prps_dir.exists(): + # Copy templates subdirectory + templates_dir = prps_dir / "templates" + if templates_dir.exists(): + for file in templates_dir.glob("*.md"): + rel_path = f"PRPs/templates/{file.name}" + files_to_copy.append((str(file), rel_path)) + + # Copy INITIAL.md example + initial_file = prps_dir / "INITIAL.md" + if initial_file.exists(): + files_to_copy.append((str(initial_file), "PRPs/INITIAL.md")) + + # Examples directory - copy all examples + examples_dir = template_root / "examples" + if examples_dir.exists(): + for example_dir in examples_dir.iterdir(): + if example_dir.is_dir(): + # Copy all files in each example directory + for file in example_dir.rglob("*"): + if file.is_file(): + rel_path = file.relative_to(template_root) + files_to_copy.append((str(file), str(rel_path))) + + return files_to_copy + + +def create_directory_structure(target_dir: Path, files: List[Tuple[str, str]]) -> None: + """ + Create directory structure for all files. + + Args: + target_dir: Target directory path + files: List of (source_path, relative_path) tuples + """ + directories = set() + + for _, rel_path in files: + dir_path = target_dir / Path(rel_path).parent + directories.add(dir_path) + + for directory in directories: + directory.mkdir(parents=True, exist_ok=True) + + +def copy_template_files(target_dir: Path, files: List[Tuple[str, str]]) -> int: + """ + Copy all template files to target directory. + + Args: + target_dir: Target directory path + files: List of (source_path, relative_path) tuples + + Returns: + Number of files copied successfully + """ + copied_count = 0 + + for source_path, rel_path in files: + target_path = target_dir / rel_path + + try: + shutil.copy2(source_path, target_path) + copied_count += 1 + print(f" βœ“ {rel_path}") + except Exception as e: + print(f" βœ— {rel_path} - Error: {e}") + + return copied_count + + +def validate_template_integrity(target_dir: Path) -> bool: + """ + Validate that essential template files were copied correctly. + + Args: + target_dir: Target directory path + + Returns: + True if template appears complete, False otherwise + """ + essential_files = [ + "CLAUDE.md", + "README_TEMPLATE.md", + ".claude/commands/generate-pydantic-ai-prp.md", + ".claude/commands/execute-pydantic-ai-prp.md", + "PRPs/templates/prp_pydantic_ai_base.md", + "PRPs/INITIAL.md", + "examples/basic_chat_agent/agent.py", + "examples/testing_examples/test_agent_patterns.py" + ] + + missing_files = [] + for file_path in essential_files: + if not (target_dir / file_path).exists(): + missing_files.append(file_path) + + if missing_files: + print(f"\n⚠️ Warning: Some essential files are missing:") + for file in missing_files: + print(f" - {file}") + return False + + return True + + +def print_next_steps(target_dir: Path) -> None: + """ + Print helpful next steps for using the template. + + Args: + target_dir: Target directory path + """ + print(f""" +πŸŽ‰ PydanticAI template successfully copied to: {target_dir} + +πŸ“‹ Next Steps: + +1. Navigate to your new project: + cd {target_dir} + +2. Set up your environment: + # Create virtual environment + python -m venv venv + source venv/bin/activate # On Windows: venv\\Scripts\\activate + + # Install packages ahead of time or let your AI coding assistant handle taht + +3. Start building your agent: + # 1. Edit PRPs/INITIAL.md with your agent requirements + # 2. Generate PRP: /generate-pydantic-ai-prp PRPs/INITIAL.md + # 3. Execute PRP: /execute-pydantic-ai-prp PRPs/generated_prp.md + +5. Read the documentation: + # Check README.md for complete usage guide + # Check CLAUDE.md for PydanticAI development rules + +πŸ”— Useful Resources: + - PydanticAI Docs: https://ai.pydantic.dev/ + - Examples: See examples/ directory + - Testing: See examples/testing_examples/ + +Happy agent building! πŸ€– +""") + + +def main(): + """Main function for the copy template script.""" + parser = argparse.ArgumentParser( + description="Copy PydanticAI context engineering template to a new project directory", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + python copy_template.py my-agent-project + python copy_template.py /path/to/my-new-agent + python copy_template.py ../customer-support-agent + """ + ) + + parser.add_argument( + "target_directory", + help="Target directory for the new PydanticAI project" + ) + + parser.add_argument( + "--force", + action="store_true", + help="Overwrite target directory if it exists" + ) + + parser.add_argument( + "--dry-run", + action="store_true", + help="Show what would be copied without actually copying" + ) + + if len(sys.argv) == 1: + parser.print_help() + return + + args = parser.parse_args() + + # Convert target directory to Path object + target_dir = Path(args.target_directory).resolve() + + # Check if target directory exists + if target_dir.exists(): + if target_dir.is_file(): + print(f"❌ Error: {target_dir} is a file, not a directory") + return + + if list(target_dir.iterdir()) and not args.force: + print(f"❌ Error: {target_dir} is not empty") + print("Use --force to overwrite existing directory") + return + + if args.force and not args.dry_run: + print(f"⚠️ Overwriting existing directory: {target_dir}") + + # Get list of files to copy + print("πŸ“‚ Scanning PydanticAI template files...") + files_to_copy = get_template_files() + + if not files_to_copy: + print("❌ Error: No template files found. Make sure you're running this from the template directory.") + return + + print(f"Found {len(files_to_copy)} files to copy") + + if args.dry_run: + print(f"\nπŸ” Dry run - would copy to: {target_dir}") + for _, rel_path in files_to_copy: + print(f" β†’ {rel_path}") + return + + # Create target directory and structure + print(f"\nπŸ“ Creating directory structure in: {target_dir}") + target_dir.mkdir(parents=True, exist_ok=True) + create_directory_structure(target_dir, files_to_copy) + + # Copy files + print(f"\nπŸ“‹ Copying template files:") + copied_count = copy_template_files(target_dir, files_to_copy) + + # Validate template integrity + print(f"\nβœ… Copied {copied_count}/{len(files_to_copy)} files successfully") + + if validate_template_integrity(target_dir): + print("βœ… Template integrity check passed") + print_next_steps(target_dir) + else: + print("⚠️ Template may be incomplete. Check for missing files.") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/basic_chat_agent/agent.py b/use-cases/pydantic-ai/examples/basic_chat_agent/agent.py new file mode 100644 index 0000000..b69dad5 --- /dev/null +++ b/use-cases/pydantic-ai/examples/basic_chat_agent/agent.py @@ -0,0 +1,191 @@ +""" +Basic Chat Agent with Memory and Context + +A simple conversational agent that demonstrates core PydanticAI patterns: +- Environment-based model configuration +- System prompts for personality and behavior +- Basic conversation handling with memory +- String output (default, no result_type needed) +""" + +import logging +from dataclasses import dataclass +from typing import Optional +from pydantic_settings import BaseSettings +from pydantic import Field +from pydantic_ai import Agent, RunContext +from pydantic_ai.providers.openai import OpenAIProvider +from pydantic_ai.models.openai import OpenAIModel +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +logger = logging.getLogger(__name__) + + +class Settings(BaseSettings): + """Configuration settings for the chat agent.""" + + # LLM Configuration + llm_provider: str = Field(default="openai") + llm_api_key: str = Field(...) + llm_model: str = Field(default="gpt-4") + llm_base_url: str = Field(default="https://api.openai.com/v1") + + class Config: + env_file = ".env" + case_sensitive = False + + +def get_llm_model() -> OpenAIModel: + """Get configured LLM model from environment settings.""" + try: + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key=settings.llm_api_key + ) + return OpenAIModel(settings.llm_model, provider=provider) + except Exception: + # For testing without env vars + import os + os.environ.setdefault("LLM_API_KEY", "test-key") + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key="test-key" + ) + return OpenAIModel(settings.llm_model, provider=provider) + + +@dataclass +class ConversationContext: + """Simple context for conversation state management.""" + user_name: Optional[str] = None + conversation_count: int = 0 + preferred_language: str = "English" + session_id: Optional[str] = None + + +SYSTEM_PROMPT = """ +You are a friendly and helpful AI assistant. + +Your personality: +- Warm and approachable +- Knowledgeable but humble +- Patient and understanding +- Encouraging and supportive + +Guidelines: +- Keep responses conversational and natural +- Be helpful without being overwhelming +- Ask follow-up questions when appropriate +- Remember context from the conversation +- Adapt your tone to match the user's needs +""" + + +# Create the basic chat agent - note: no result_type, defaults to string +chat_agent = Agent( + get_llm_model(), + deps_type=ConversationContext, + system_prompt=SYSTEM_PROMPT +) + + +@chat_agent.system_prompt +def dynamic_context_prompt(ctx) -> str: + """Dynamic system prompt that includes conversation context.""" + prompt_parts = [] + + if ctx.deps.user_name: + prompt_parts.append(f"The user's name is {ctx.deps.user_name}.") + + if ctx.deps.conversation_count > 0: + prompt_parts.append(f"This is message #{ctx.deps.conversation_count + 1} in your conversation.") + + if ctx.deps.preferred_language != "English": + prompt_parts.append(f"The user prefers to communicate in {ctx.deps.preferred_language}.") + + return " ".join(prompt_parts) if prompt_parts else "" + + +async def chat_with_agent(message: str, context: Optional[ConversationContext] = None) -> str: + """ + Main function to chat with the agent. + + Args: + message: User's message to the agent + context: Optional conversation context for memory + + Returns: + String response from the agent + """ + if context is None: + context = ConversationContext() + + # Increment conversation count + context.conversation_count += 1 + + # Run the agent with the message and context + result = await chat_agent.run(message, deps=context) + + return result.data + + +def chat_with_agent_sync(message: str, context: Optional[ConversationContext] = None) -> str: + """ + Synchronous version of chat_with_agent for simple use cases. + + Args: + message: User's message to the agent + context: Optional conversation context for memory + + Returns: + String response from the agent + """ + if context is None: + context = ConversationContext() + + # Increment conversation count + context.conversation_count += 1 + + # Run the agent synchronously + result = chat_agent.run_sync(message, deps=context) + + return result.data + + +# Example usage and demonstration +if __name__ == "__main__": + import asyncio + + async def demo_conversation(): + """Demonstrate the basic chat agent with a simple conversation.""" + print("=== Basic Chat Agent Demo ===\n") + + # Create conversation context + context = ConversationContext( + user_name="Alex", + preferred_language="English" + ) + + # Sample conversation + messages = [ + "Hello! My name is Alex, nice to meet you.", + "Can you help me understand what PydanticAI is?", + "That's interesting! What makes it different from other AI frameworks?", + "Thanks for the explanation. Can you recommend some good resources to learn more?" + ] + + for message in messages: + print(f"User: {message}") + + response = await chat_with_agent(message, context) + + print(f"Agent: {response}") + print("-" * 50) + + # Run the demo + asyncio.run(demo_conversation()) \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/cli.py b/use-cases/pydantic-ai/examples/cli.py new file mode 100644 index 0000000..6480555 --- /dev/null +++ b/use-cases/pydantic-ai/examples/cli.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python3 +"""Conversational CLI with real-time streaming and tool call visibility for Pydantic AI agents.""" + +import asyncio +import sys +import os +from typing import List + +# Add parent directory to Python path for imports +sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) + +from rich.console import Console +from rich.panel import Panel +from rich.prompt import Prompt +from rich.live import Live +from rich.text import Text + +from pydantic_ai import Agent +from agents.research_agent import research_agent +from agents.dependencies import ResearchAgentDependencies +from agents.settings import settings + +console = Console() + + +async def stream_agent_interaction(user_input: str, conversation_history: List[str]) -> tuple[str, str]: + """Stream agent interaction with real-time tool call display.""" + + try: + # Set up dependencies + research_deps = ResearchAgentDependencies(brave_api_key=settings.brave_api_key) + + # Build context with conversation history + context = "\n".join(conversation_history[-6:]) if conversation_history else "" + + prompt = f"""Previous conversation: +{context} + +User: {user_input} + +Respond naturally and helpfully.""" + + # Stream the agent execution + async with research_agent.iter(prompt, deps=research_deps) as run: + + async for node in run: + + # Handle user prompt node + if Agent.is_user_prompt_node(node): + pass # Clean start - no processing messages + + # Handle model request node - stream the thinking process + elif Agent.is_model_request_node(node): + # Show assistant prefix at the start + console.print("[bold blue]Assistant:[/bold blue] ", end="") + + # Stream model request events for real-time text + response_text = "" + async with node.stream(run.ctx) as request_stream: + async for event in request_stream: + # Handle different event types based on their type + event_type = type(event).__name__ + + if event_type == "PartDeltaEvent": + # Extract content from delta + if hasattr(event, 'delta') and hasattr(event.delta, 'content_delta'): + delta_text = event.delta.content_delta + if delta_text: + console.print(delta_text, end="") + response_text += delta_text + elif event_type == "FinalResultEvent": + console.print() # New line after streaming + + # Handle tool calls - this is the key part + elif Agent.is_call_tools_node(node): + # Stream tool execution events + async with node.stream(run.ctx) as tool_stream: + async for event in tool_stream: + event_type = type(event).__name__ + + if event_type == "FunctionToolCallEvent": + # Extract tool name from the part attribute + tool_name = "Unknown Tool" + args = None + + # Check if the part attribute contains the tool call + if hasattr(event, 'part'): + part = event.part + + # Check if part has tool_name directly + if hasattr(part, 'tool_name'): + tool_name = part.tool_name + elif hasattr(part, 'function_name'): + tool_name = part.function_name + elif hasattr(part, 'name'): + tool_name = part.name + + # Check for arguments in part + if hasattr(part, 'args'): + args = part.args + elif hasattr(part, 'arguments'): + args = part.arguments + + # Debug: print part attributes to understand structure + if tool_name == "Unknown Tool" and hasattr(event, 'part'): + part_attrs = [attr for attr in dir(event.part) if not attr.startswith('_')] + console.print(f" [dim red]Debug - Part attributes: {part_attrs}[/dim red]") + + # Try to get more details about the part + if hasattr(event.part, '__dict__'): + console.print(f" [dim red]Part dict: {event.part.__dict__}[/dim red]") + + console.print(f" πŸ”Ή [cyan]Calling tool:[/cyan] [bold]{tool_name}[/bold]") + + # Show tool args if available + if args and isinstance(args, dict): + # Show first few characters of each arg + arg_preview = [] + for key, value in list(args.items())[:3]: + val_str = str(value) + if len(val_str) > 50: + val_str = val_str[:47] + "..." + arg_preview.append(f"{key}={val_str}") + console.print(f" [dim]Args: {', '.join(arg_preview)}[/dim]") + elif args: + args_str = str(args) + if len(args_str) > 100: + args_str = args_str[:97] + "..." + console.print(f" [dim]Args: {args_str}[/dim]") + + elif event_type == "FunctionToolResultEvent": + # Display tool result + result = str(event.tool_return) if hasattr(event, 'tool_return') else "No result" + if len(result) > 100: + result = result[:97] + "..." + console.print(f" βœ… [green]Tool result:[/green] [dim]{result}[/dim]") + + # Handle end node + elif Agent.is_end_node(node): + # Don't show "Processing complete" - keep it clean + pass + + # Get final result + final_result = run.result + final_output = final_result.output if hasattr(final_result, 'output') else str(final_result) + + # Return both streamed and final content + return (response_text.strip(), final_output) + + except Exception as e: + console.print(f"[red]❌ Error: {e}[/red]") + return ("", f"Error: {e}") + + +async def main(): + """Main conversation loop.""" + + # Show welcome + welcome = Panel( + "[bold blue]πŸ€– Pydantic AI Research Assistant[/bold blue]\n\n" + "[green]Real-time tool execution visibility[/green]\n" + "[dim]Type 'exit' to quit[/dim]", + style="blue", + padding=(1, 2) + ) + console.print(welcome) + console.print() + + conversation_history = [] + + while True: + try: + # Get user input + user_input = Prompt.ask("[bold green]You").strip() + + # Handle exit + if user_input.lower() in ['exit', 'quit']: + console.print("\n[yellow]πŸ‘‹ Goodbye![/yellow]") + break + + if not user_input: + continue + + # Add to history + conversation_history.append(f"User: {user_input}") + + # Stream the interaction and get response + streamed_text, final_response = await stream_agent_interaction(user_input, conversation_history) + + # Handle the response display + if streamed_text: + # Response was streamed, just add spacing + console.print() + conversation_history.append(f"Assistant: {streamed_text}") + elif final_response and final_response.strip(): + # Response wasn't streamed, display with proper formatting + console.print(f"[bold blue]Assistant:[/bold blue] {final_response}") + console.print() + conversation_history.append(f"Assistant: {final_response}") + else: + # No response + console.print() + + except KeyboardInterrupt: + console.print("\n[yellow]Use 'exit' to quit[/yellow]") + continue + + except Exception as e: + console.print(f"[red]Error: {e}[/red]") + continue + + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/main_agent_reference/.env.example b/use-cases/pydantic-ai/examples/main_agent_reference/.env.example new file mode 100644 index 0000000..9e4011b --- /dev/null +++ b/use-cases/pydantic-ai/examples/main_agent_reference/.env.example @@ -0,0 +1,9 @@ +# ===== LLM Configuration ===== +# Provider: openai, anthropic, gemini, ollama, etc. +LLM_PROVIDER=openai +# Your LLM API key +LLM_API_KEY=sk-your-openai-api-key-here +# LLM to use for the agents (e.g., gpt-4.1-mini, gpt-4.1, claude-4-sonnet) +LLM_CHOICE=gpt-4.1-mini +# Base URL for the LLM API (change for Ollama or other providers) +LLM_BASE_URL=https://api.openai.com/v1 \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/main_agent_reference/models.py b/use-cases/pydantic-ai/examples/main_agent_reference/models.py new file mode 100644 index 0000000..f7505e8 --- /dev/null +++ b/use-cases/pydantic-ai/examples/main_agent_reference/models.py @@ -0,0 +1,103 @@ +""" +Core data models for the multi-agent system. +""" + +from pydantic import BaseModel, Field +from typing import List, Optional, Dict, Any +from datetime import datetime + + +class ResearchQuery(BaseModel): + """Model for research query requests.""" + query: str = Field(..., description="Research topic to investigate") + max_results: int = Field(10, ge=1, le=50, description="Maximum number of results to return") + include_summary: bool = Field(True, description="Whether to include AI-generated summary") + + +class BraveSearchResult(BaseModel): + """Model for individual Brave search results.""" + title: str = Field(..., description="Title of the search result") + url: str = Field(..., description="URL of the search result") + description: str = Field(..., description="Description/snippet from the search result") + score: float = Field(0.0, ge=0.0, le=1.0, description="Relevance score") + + class Config: + """Pydantic configuration.""" + json_schema_extra = { + "example": { + "title": "Understanding AI Safety", + "url": "https://example.com/ai-safety", + "description": "A comprehensive guide to AI safety principles...", + "score": 0.95 + } + } + + +class EmailDraft(BaseModel): + """Model for email draft creation.""" + to: List[str] = Field(..., min_length=1, description="List of recipient email addresses") + subject: str = Field(..., min_length=1, description="Email subject line") + body: str = Field(..., min_length=1, description="Email body content") + cc: Optional[List[str]] = Field(None, description="List of CC recipients") + bcc: Optional[List[str]] = Field(None, description="List of BCC recipients") + + class Config: + """Pydantic configuration.""" + json_schema_extra = { + "example": { + "to": ["john@example.com"], + "subject": "AI Research Summary", + "body": "Dear John,\n\nHere's the latest research on AI safety...", + "cc": ["team@example.com"] + } + } + + +class EmailDraftResponse(BaseModel): + """Response model for email draft creation.""" + draft_id: str = Field(..., description="Gmail draft ID") + message_id: str = Field(..., description="Message ID") + thread_id: Optional[str] = Field(None, description="Thread ID if part of a thread") + created_at: datetime = Field(default_factory=datetime.now, description="Draft creation timestamp") + + +class ResearchEmailRequest(BaseModel): + """Model for research + email draft request.""" + research_query: str = Field(..., description="Topic to research") + email_context: str = Field(..., description="Context for email generation") + recipient_email: str = Field(..., description="Email recipient") + email_subject: Optional[str] = Field(None, description="Optional email subject") + + +class ResearchResponse(BaseModel): + """Response model for research queries.""" + query: str = Field(..., description="Original research query") + results: List[BraveSearchResult] = Field(..., description="Search results") + summary: Optional[str] = Field(None, description="AI-generated summary of results") + total_results: int = Field(..., description="Total number of results found") + timestamp: datetime = Field(default_factory=datetime.now, description="Query timestamp") + + +class AgentResponse(BaseModel): + """Generic agent response model.""" + success: bool = Field(..., description="Whether the operation was successful") + data: Optional[Dict[str, Any]] = Field(None, description="Response data") + error: Optional[str] = Field(None, description="Error message if failed") + tools_used: List[str] = Field(default_factory=list, description="List of tools used") + + +class ChatMessage(BaseModel): + """Model for chat messages in the CLI.""" + role: str = Field(..., description="Message role (user/assistant)") + content: str = Field(..., description="Message content") + timestamp: datetime = Field(default_factory=datetime.now, description="Message timestamp") + tools_used: Optional[List[Dict[str, Any]]] = Field(None, description="Tools used in response") + + +class SessionState(BaseModel): + """Model for maintaining session state.""" + session_id: str = Field(..., description="Unique session identifier") + user_id: Optional[str] = Field(None, description="User identifier") + messages: List[ChatMessage] = Field(default_factory=list, description="Conversation history") + created_at: datetime = Field(default_factory=datetime.now, description="Session creation time") + last_activity: datetime = Field(default_factory=datetime.now, description="Last activity timestamp") \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/main_agent_reference/providers.py b/use-cases/pydantic-ai/examples/main_agent_reference/providers.py new file mode 100644 index 0000000..08e0cce --- /dev/null +++ b/use-cases/pydantic-ai/examples/main_agent_reference/providers.py @@ -0,0 +1,61 @@ +""" +Flexible provider configuration for LLM models. +Based on examples/agent/providers.py pattern. +""" + +from typing import Optional +from pydantic_ai.providers.openai import OpenAIProvider +from pydantic_ai.models.openai import OpenAIModel +from .settings import settings + + +def get_llm_model(model_choice: Optional[str] = None) -> OpenAIModel: + """ + Get LLM model configuration based on environment variables. + + Args: + model_choice: Optional override for model choice + + Returns: + Configured OpenAI-compatible model + """ + llm_choice = model_choice or settings.llm_model + base_url = settings.llm_base_url + api_key = settings.llm_api_key + + # Create provider based on configuration + provider = OpenAIProvider(base_url=base_url, api_key=api_key) + + return OpenAIModel(llm_choice, provider=provider) + + +def get_model_info() -> dict: + """ + Get information about current model configuration. + + Returns: + Dictionary with model configuration info + """ + return { + "llm_provider": settings.llm_provider, + "llm_model": settings.llm_model, + "llm_base_url": settings.llm_base_url, + "app_env": settings.app_env, + "debug": settings.debug, + } + + +def validate_llm_configuration() -> bool: + """ + Validate that LLM configuration is properly set. + + Returns: + True if configuration is valid + """ + try: + # Check if we can create a model instance + get_llm_model() + return True + except Exception as e: + print(f"LLM configuration validation failed: {e}") + return False \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/main_agent_reference/research_agent.py b/use-cases/pydantic-ai/examples/main_agent_reference/research_agent.py new file mode 100644 index 0000000..c566001 --- /dev/null +++ b/use-cases/pydantic-ai/examples/main_agent_reference/research_agent.py @@ -0,0 +1,263 @@ +""" +Research Agent that uses Brave Search and can invoke Email Agent. +""" + +import logging +from typing import Dict, Any, List, Optional +from dataclasses import dataclass + +from pydantic_ai import Agent, RunContext + +from .providers import get_llm_model +from .email_agent import email_agent, EmailAgentDependencies +from .tools import search_web_tool + +logger = logging.getLogger(__name__) + + +SYSTEM_PROMPT = """ +You are an expert research assistant with the ability to search the web and create email drafts. Your primary goal is to help users find relevant information and communicate findings effectively. + +Your capabilities: +1. **Web Search**: Use Brave Search to find current, relevant information on any topic +2. **Email Creation**: Create professional email drafts through Gmail when requested + +When conducting research: +- Use specific, targeted search queries +- Analyze search results for relevance and credibility +- Synthesize information from multiple sources +- Provide clear, well-organized summaries +- Include source URLs for reference + +When creating emails: +- Use research findings to create informed, professional content +- Adapt tone and detail level to the intended recipient +- Include relevant sources and citations when appropriate +- Ensure emails are clear, concise, and actionable + +Always strive to provide accurate, helpful, and actionable information. +""" + + +@dataclass +class ResearchAgentDependencies: + """Dependencies for the research agent - only configuration, no tool instances.""" + brave_api_key: str + gmail_credentials_path: str + gmail_token_path: str + session_id: Optional[str] = None + + +# Initialize the research agent +research_agent = Agent( + get_llm_model(), + deps_type=ResearchAgentDependencies, + system_prompt=SYSTEM_PROMPT +) + + +@research_agent.tool +async def search_web( + ctx: RunContext[ResearchAgentDependencies], + query: str, + max_results: int = 10 +) -> List[Dict[str, Any]]: + """ + Search the web using Brave Search API. + + Args: + query: Search query + max_results: Maximum number of results to return (1-20) + + Returns: + List of search results with title, URL, description, and score + """ + try: + # Ensure max_results is within valid range + max_results = min(max(max_results, 1), 20) + + results = await search_web_tool( + api_key=ctx.deps.brave_api_key, + query=query, + count=max_results + ) + + logger.info(f"Found {len(results)} results for query: {query}") + return results + + except Exception as e: + logger.error(f"Web search failed: {e}") + return [{"error": f"Search failed: {str(e)}"}] + + +@research_agent.tool +async def create_email_draft( + ctx: RunContext[ResearchAgentDependencies], + recipient_email: str, + subject: str, + context: str, + research_summary: Optional[str] = None +) -> Dict[str, Any]: + """ + Create an email draft based on research context using the Email Agent. + + Args: + recipient_email: Email address of the recipient + subject: Email subject line + context: Context or purpose for the email + research_summary: Optional research findings to include + + Returns: + Dictionary with draft creation results + """ + try: + # Prepare the email content prompt + if research_summary: + email_prompt = f""" +Create a professional email to {recipient_email} with the subject "{subject}". + +Context: {context} + +Research Summary: +{research_summary} + +Please create a well-structured email that: +1. Has an appropriate greeting +2. Provides clear context +3. Summarizes the key research findings professionally +4. Includes actionable next steps if appropriate +5. Ends with a professional closing + +The email should be informative but concise, and maintain a professional yet friendly tone. +""" + else: + email_prompt = f""" +Create a professional email to {recipient_email} with the subject "{subject}". + +Context: {context} + +Please create a well-structured email that addresses the context provided. +""" + + # Create dependencies for email agent + email_deps = EmailAgentDependencies( + gmail_credentials_path=ctx.deps.gmail_credentials_path, + gmail_token_path=ctx.deps.gmail_token_path, + session_id=ctx.deps.session_id + ) + + # Run the email agent + result = await email_agent.run( + email_prompt, + deps=email_deps, + usage=ctx.usage # Pass usage for token tracking + ) + + logger.info(f"Email agent invoked for recipient: {recipient_email}") + + return { + "success": True, + "agent_response": result.data, + "recipient": recipient_email, + "subject": subject, + "context": context + } + + except Exception as e: + logger.error(f"Failed to create email draft via Email Agent: {e}") + return { + "success": False, + "error": str(e), + "recipient": recipient_email, + "subject": subject + } + + +@research_agent.tool +async def summarize_research( + ctx: RunContext[ResearchAgentDependencies], + search_results: List[Dict[str, Any]], + topic: str, + focus_areas: Optional[str] = None +) -> Dict[str, Any]: + """ + Create a comprehensive summary of research findings. + + Args: + search_results: List of search result dictionaries + topic: Main research topic + focus_areas: Optional specific areas to focus on + + Returns: + Dictionary with research summary + """ + try: + if not search_results: + return { + "summary": "No search results provided for summarization.", + "key_points": [], + "sources": [] + } + + # Extract key information + sources = [] + descriptions = [] + + for result in search_results: + if "title" in result and "url" in result: + sources.append(f"- {result['title']}: {result['url']}") + if "description" in result: + descriptions.append(result["description"]) + + # Create summary content + content_summary = "\n".join(descriptions[:5]) # Limit to top 5 descriptions + sources_list = "\n".join(sources[:10]) # Limit to top 10 sources + + focus_text = f"\nSpecific focus areas: {focus_areas}" if focus_areas else "" + + summary = f""" +Research Summary: {topic}{focus_text} + +Key Findings: +{content_summary} + +Sources: +{sources_list} +""" + + return { + "summary": summary, + "topic": topic, + "sources_count": len(sources), + "key_points": descriptions[:5] + } + + except Exception as e: + logger.error(f"Failed to summarize research: {e}") + return { + "summary": f"Failed to summarize research: {str(e)}", + "key_points": [], + "sources": [] + } + + +# Convenience function to create research agent with dependencies +def create_research_agent( + brave_api_key: str, + gmail_credentials_path: str, + gmail_token_path: str, + session_id: Optional[str] = None +) -> Agent: + """ + Create a research agent with specified dependencies. + + Args: + brave_api_key: Brave Search API key + gmail_credentials_path: Path to Gmail credentials.json + gmail_token_path: Path to Gmail token.json + session_id: Optional session identifier + + Returns: + Configured research agent + """ + return research_agent \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/main_agent_reference/settings.py b/use-cases/pydantic-ai/examples/main_agent_reference/settings.py new file mode 100644 index 0000000..6e5cee7 --- /dev/null +++ b/use-cases/pydantic-ai/examples/main_agent_reference/settings.py @@ -0,0 +1,58 @@ +""" +Configuration management using pydantic-settings. +""" + +import os +from typing import Optional +from pydantic_settings import BaseSettings +from pydantic import Field, field_validator, ConfigDict +from dotenv import load_dotenv + +# Load environment variables from .env file +load_dotenv() + + +class Settings(BaseSettings): + """Application settings with environment variable support.""" + + model_config = ConfigDict( + env_file=".env", + env_file_encoding="utf-8", + case_sensitive=False + ) + + # LLM Configuration + llm_provider: str = Field(default="openai") + llm_api_key: str = Field(...) + llm_model: str = Field(default="gpt-4") + llm_base_url: Optional[str] = Field(default="https://api.openai.com/v1") + + # Brave Search Configuration + brave_api_key: str = Field(...) + brave_search_url: str = Field( + default="https://api.search.brave.com/res/v1/web/search" + ) + + # Application Configuration + app_env: str = Field(default="development") + log_level: str = Field(default="INFO") + debug: bool = Field(default=False) + + @field_validator("llm_api_key", "brave_api_key") + @classmethod + def validate_api_keys(cls, v): + """Ensure API keys are not empty.""" + if not v or v.strip() == "": + raise ValueError("API key cannot be empty") + return v + + +# Global settings instance +try: + settings = Settings() +except Exception: + # For testing, create settings with dummy values + import os + os.environ.setdefault("LLM_API_KEY", "test_key") + os.environ.setdefault("BRAVE_API_KEY", "test_key") + settings = Settings() \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/main_agent_reference/tools.py b/use-cases/pydantic-ai/examples/main_agent_reference/tools.py new file mode 100644 index 0000000..a1f28f6 --- /dev/null +++ b/use-cases/pydantic-ai/examples/main_agent_reference/tools.py @@ -0,0 +1,120 @@ +""" +Pure tool functions for multi-agent system. +These are standalone functions that can be imported and used by any agent. +""" + +import os +import base64 +import logging +import httpx +from typing import List, Dict, Any, Optional +from datetime import datetime + +from agents.models import BraveSearchResult + +logger = logging.getLogger(__name__) + + +# Brave Search Tool Function +async def search_web_tool( + api_key: str, + query: str, + count: int = 10, + offset: int = 0, + country: Optional[str] = None, + lang: Optional[str] = None +) -> List[Dict[str, Any]]: + """ + Pure function to search the web using Brave Search API. + + Args: + api_key: Brave Search API key + query: Search query + count: Number of results to return (1-20) + offset: Offset for pagination + country: Country code for localized results + lang: Language code for results + + Returns: + List of search results as dictionaries + + Raises: + ValueError: If query is empty or API key missing + Exception: If API request fails + """ + if not api_key or not api_key.strip(): + raise ValueError("Brave API key is required") + + if not query or not query.strip(): + raise ValueError("Query cannot be empty") + + # Ensure count is within valid range + count = min(max(count, 1), 20) + + headers = { + "X-Subscription-Token": api_key, + "Accept": "application/json" + } + + params = { + "q": query, + "count": count, + "offset": offset + } + + if country: + params["country"] = country + if lang: + params["lang"] = lang + + logger.info(f"Searching Brave for: {query}") + + async with httpx.AsyncClient() as client: + try: + response = await client.get( + "https://api.search.brave.com/res/v1/web/search", + headers=headers, + params=params, + timeout=30.0 + ) + + # Handle rate limiting + if response.status_code == 429: + raise Exception("Rate limit exceeded. Check your Brave API quota.") + + # Handle authentication errors + if response.status_code == 401: + raise Exception("Invalid Brave API key") + + # Handle other errors + if response.status_code != 200: + raise Exception(f"Brave API returned {response.status_code}: {response.text}") + + data = response.json() + + # Extract web results + web_results = data.get("web", {}).get("results", []) + + # Convert to our format + results = [] + for idx, result in enumerate(web_results): + # Calculate a simple relevance score based on position + score = 1.0 - (idx * 0.05) # Decrease by 0.05 for each position + score = max(score, 0.1) # Minimum score of 0.1 + + results.append({ + "title": result.get("title", ""), + "url": result.get("url", ""), + "description": result.get("description", ""), + "score": score + }) + + logger.info(f"Found {len(results)} results for query: {query}") + return results + + except httpx.RequestError as e: + logger.error(f"Request error during Brave search: {e}") + raise Exception(f"Request failed: {str(e)}") + except Exception as e: + logger.error(f"Error during Brave search: {e}") + raise diff --git a/use-cases/pydantic-ai/examples/structured_output_agent/agent.py b/use-cases/pydantic-ai/examples/structured_output_agent/agent.py new file mode 100644 index 0000000..c47d742 --- /dev/null +++ b/use-cases/pydantic-ai/examples/structured_output_agent/agent.py @@ -0,0 +1,303 @@ +""" +Structured Output Agent for Data Validation + +Demonstrates when to use structured outputs with PydanticAI: +- Environment-based model configuration (following main_agent_reference) +- Structured output validation with Pydantic models (result_type specified) +- Data extraction and validation use case +- Professional report generation with consistent formatting +""" + +import logging +from dataclasses import dataclass +from typing import Optional, List +from pydantic_settings import BaseSettings +from pydantic import BaseModel, Field +from pydantic_ai import Agent, RunContext +from pydantic_ai.providers.openai import OpenAIProvider +from pydantic_ai.models.openai import OpenAIModel +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +logger = logging.getLogger(__name__) + + +class Settings(BaseSettings): + """Configuration settings for the structured output agent.""" + + # LLM Configuration + llm_provider: str = Field(default="openai") + llm_api_key: str = Field(...) + llm_model: str = Field(default="gpt-4") + llm_base_url: str = Field(default="https://api.openai.com/v1") + + class Config: + env_file = ".env" + case_sensitive = False + + +def get_llm_model() -> OpenAIModel: + """Get configured LLM model from environment settings.""" + try: + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key=settings.llm_api_key + ) + return OpenAIModel(settings.llm_model, provider=provider) + except Exception: + # For testing without env vars + import os + os.environ.setdefault("LLM_API_KEY", "test-key") + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key="test-key" + ) + return OpenAIModel(settings.llm_model, provider=provider) + + +@dataclass +class AnalysisDependencies: + """Dependencies for the analysis agent.""" + report_format: str = "business" # business, technical, academic + include_recommendations: bool = True + session_id: Optional[str] = None + + +class DataInsight(BaseModel): + """Individual insight extracted from data.""" + insight: str = Field(description="The key insight or finding") + confidence: float = Field(ge=0.0, le=1.0, description="Confidence level in this insight") + data_points: List[str] = Field(description="Supporting data points") + + +class DataAnalysisReport(BaseModel): + """Structured output for data analysis with validation.""" + + # Required fields + summary: str = Field(description="Executive summary of the analysis") + key_insights: List[DataInsight] = Field( + min_items=1, + max_items=10, + description="Key insights discovered in the data" + ) + + # Validated fields + confidence_score: float = Field( + ge=0.0, le=1.0, + description="Overall confidence in the analysis" + ) + data_quality: str = Field( + pattern="^(excellent|good|fair|poor)$", + description="Assessment of data quality" + ) + + # Optional structured fields + recommendations: Optional[List[str]] = Field( + default=None, + description="Actionable recommendations based on findings" + ) + limitations: Optional[List[str]] = Field( + default=None, + description="Limitations or caveats in the analysis" + ) + + # Metadata + analysis_type: str = Field(description="Type of analysis performed") + data_sources: List[str] = Field(description="Sources of data analyzed") + + +SYSTEM_PROMPT = """ +You are an expert data analyst specializing in extracting structured insights from various data sources. + +Your role: +- Analyze provided data with statistical rigor +- Extract meaningful insights and patterns +- Assess data quality and reliability +- Provide actionable recommendations +- Structure findings in a consistent, professional format + +Guidelines: +- Be objective and evidence-based in your analysis +- Clearly distinguish between facts and interpretations +- Provide confidence levels for your insights +- Highlight both strengths and limitations of the data +- Ensure all outputs follow the required structured format +""" + + +# Create structured output agent - NOTE: result_type specified for data validation +structured_agent = Agent( + get_llm_model(), + deps_type=AnalysisDependencies, + result_type=DataAnalysisReport, # This is when we DO want structured output + system_prompt=SYSTEM_PROMPT +) + + +@structured_agent.tool +def analyze_numerical_data( + ctx: RunContext[AnalysisDependencies], + data_description: str, + numbers: List[float] +) -> str: + """ + Analyze numerical data and provide statistical insights. + + Args: + data_description: Description of what the numbers represent + numbers: List of numerical values to analyze + + Returns: + Statistical analysis summary + """ + try: + if not numbers: + return "No numerical data provided for analysis." + + # Basic statistical calculations + count = len(numbers) + total = sum(numbers) + average = total / count + minimum = min(numbers) + maximum = max(numbers) + + # Calculate variance and standard deviation + variance = sum((x - average) ** 2 for x in numbers) / count + std_dev = variance ** 0.5 + + # Simple trend analysis + if count > 1: + trend = "increasing" if numbers[-1] > numbers[0] else "decreasing" + else: + trend = "insufficient data" + + analysis = f""" +Statistical Analysis of {data_description}: +- Count: {count} data points +- Average: {average:.2f} +- Range: {minimum:.2f} to {maximum:.2f} +- Standard Deviation: {std_dev:.2f} +- Overall Trend: {trend} +- Data Quality: {'good' if std_dev < average * 0.5 else 'variable'} +""" + + logger.info(f"Analyzed {count} data points for: {data_description}") + return analysis.strip() + + except Exception as e: + logger.error(f"Error in numerical analysis: {e}") + return f"Error analyzing numerical data: {str(e)}" + + +async def analyze_data( + data_input: str, + dependencies: Optional[AnalysisDependencies] = None +) -> DataAnalysisReport: + """ + Analyze data and return structured report. + + Args: + data_input: Raw data or description to analyze + dependencies: Optional analysis configuration + + Returns: + Structured DataAnalysisReport with validation + """ + if dependencies is None: + dependencies = AnalysisDependencies() + + result = await structured_agent.run(data_input, deps=dependencies) + return result.data + + +def analyze_data_sync( + data_input: str, + dependencies: Optional[AnalysisDependencies] = None +) -> DataAnalysisReport: + """ + Synchronous version of analyze_data. + + Args: + data_input: Raw data or description to analyze + dependencies: Optional analysis configuration + + Returns: + Structured DataAnalysisReport with validation + """ + import asyncio + return asyncio.run(analyze_data(data_input, dependencies)) + + +# Example usage and demonstration +if __name__ == "__main__": + import asyncio + + async def demo_structured_output(): + """Demonstrate structured output validation.""" + print("=== Structured Output Agent Demo ===\n") + + # Sample data scenarios + scenarios = [ + { + "title": "Sales Performance Data", + "data": """ + Monthly sales data for Q4 2024: + October: $125,000 + November: $142,000 + December: $158,000 + + Customer satisfaction scores: 4.2, 4.5, 4.1, 4.6, 4.3 + Return rate: 3.2% + """ + }, + { + "title": "Website Analytics", + "data": """ + Website traffic analysis: + - Daily visitors: 5,200 average + - Bounce rate: 35% + - Page load time: 2.1 seconds + - Conversion rate: 3.8% + - Mobile traffic: 68% + """ + } + ] + + for scenario in scenarios: + print(f"Analysis: {scenario['title']}") + print(f"Input Data: {scenario['data'][:100]}...") + + # Configure for business report + deps = AnalysisDependencies( + report_format="business", + include_recommendations=True + ) + + try: + report = await analyze_data(scenario['data'], deps) + + print(f"Summary: {report.summary}") + print(f"Confidence: {report.confidence_score}") + print(f"Data Quality: {report.data_quality}") + print(f"Key Insights: {len(report.key_insights)} found") + + for i, insight in enumerate(report.key_insights, 1): + print(f" {i}. {insight.insight} (confidence: {insight.confidence})") + + if report.recommendations: + print(f"Recommendations: {len(report.recommendations)}") + for i, rec in enumerate(report.recommendations, 1): + print(f" {i}. {rec}") + + print("=" * 60) + + except Exception as e: + print(f"Analysis failed: {e}") + print("=" * 60) + + # Run the demo + asyncio.run(demo_structured_output()) \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/testing_examples/pytest.ini b/use-cases/pydantic-ai/examples/testing_examples/pytest.ini new file mode 100644 index 0000000..d3715c5 --- /dev/null +++ b/use-cases/pydantic-ai/examples/testing_examples/pytest.ini @@ -0,0 +1,18 @@ +[tool:pytest] +testpaths = . +python_files = test_*.py +python_classes = Test* +python_functions = test_* +addopts = + -v + --tb=short + --strict-markers + --disable-warnings +markers = + integration: Integration tests + slow: Slow running tests + asyncio: Async tests +filterwarnings = + ignore::DeprecationWarning + ignore::PendingDeprecationWarning +asyncio_mode = auto \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/testing_examples/test_agent_patterns.py b/use-cases/pydantic-ai/examples/testing_examples/test_agent_patterns.py new file mode 100644 index 0000000..0a2b0bb --- /dev/null +++ b/use-cases/pydantic-ai/examples/testing_examples/test_agent_patterns.py @@ -0,0 +1,399 @@ +""" +Comprehensive PydanticAI Testing Examples + +Demonstrates testing patterns and best practices for PydanticAI agents: +- TestModel for fast development validation +- FunctionModel for custom behavior testing +- Agent.override() for test isolation +- Pytest fixtures and async testing +- Tool validation and error handling tests +""" + +import pytest +import asyncio +from unittest.mock import Mock, AsyncMock +from dataclasses import dataclass +from typing import Optional, List +from pydantic import BaseModel +from pydantic_ai import Agent, RunContext +from pydantic_ai.models.test import TestModel, FunctionModel + + +@dataclass +class TestDependencies: + """Test dependencies for agent testing.""" + database: Mock + api_client: Mock + user_id: str = "test_user_123" + + +class TestResponse(BaseModel): + """Test response model for validation.""" + message: str + confidence: float = 0.8 + actions: List[str] = [] + + +# Create test agent for demonstrations +test_agent = Agent( + model="openai:gpt-4o-mini", # Will be overridden in tests + deps_type=TestDependencies, + result_type=TestResponse, + system_prompt="You are a helpful test assistant." +) + + +@test_agent.tool +async def mock_database_query( + ctx: RunContext[TestDependencies], + query: str +) -> str: + """Mock database query tool for testing.""" + try: + # Simulate database call + result = await ctx.deps.database.execute_query(query) + return f"Database result: {result}" + except Exception as e: + return f"Database error: {str(e)}" + + +@test_agent.tool +def mock_api_call( + ctx: RunContext[TestDependencies], + endpoint: str, + data: Optional[dict] = None +) -> str: + """Mock API call tool for testing.""" + try: + # Simulate API call + response = ctx.deps.api_client.post(endpoint, json=data) + return f"API response: {response}" + except Exception as e: + return f"API error: {str(e)}" + + +class TestAgentBasics: + """Test basic agent functionality with TestModel.""" + + @pytest.fixture + def test_dependencies(self): + """Create mock dependencies for testing.""" + return TestDependencies( + database=AsyncMock(), + api_client=Mock(), + user_id="test_user_123" + ) + + def test_agent_with_test_model(self, test_dependencies): + """Test agent behavior with TestModel.""" + test_model = TestModel() + + with test_agent.override(model=test_model): + result = test_agent.run_sync( + "Hello, please help me with a simple task.", + deps=test_dependencies + ) + + # TestModel returns a JSON summary by default + assert result.data.message is not None + assert isinstance(result.data.confidence, float) + assert isinstance(result.data.actions, list) + + def test_agent_custom_test_model_output(self, test_dependencies): + """Test agent with custom TestModel output.""" + test_model = TestModel( + custom_output_text='{"message": "Custom test response", "confidence": 0.9, "actions": ["test_action"]}' + ) + + with test_agent.override(model=test_model): + result = test_agent.run_sync( + "Test message", + deps=test_dependencies + ) + + assert result.data.message == "Custom test response" + assert result.data.confidence == 0.9 + assert result.data.actions == ["test_action"] + + @pytest.mark.asyncio + async def test_agent_async_with_test_model(self, test_dependencies): + """Test async agent behavior with TestModel.""" + test_model = TestModel() + + with test_agent.override(model=test_model): + result = await test_agent.run( + "Async test message", + deps=test_dependencies + ) + + assert result.data.message is not None + assert result.data.confidence >= 0.0 + + +class TestAgentTools: + """Test agent tool functionality.""" + + @pytest.fixture + def mock_dependencies(self): + """Create mock dependencies with configured responses.""" + database_mock = AsyncMock() + database_mock.execute_query.return_value = "Test data from database" + + api_mock = Mock() + api_mock.post.return_value = {"status": "success", "data": "test_data"} + + return TestDependencies( + database=database_mock, + api_client=api_mock, + user_id="test_user_456" + ) + + @pytest.mark.asyncio + async def test_database_tool_success(self, mock_dependencies): + """Test database tool with successful response.""" + test_model = TestModel(call_tools=['mock_database_query']) + + with test_agent.override(model=test_model): + result = await test_agent.run( + "Please query the database for user data", + deps=mock_dependencies + ) + + # Verify database was called + mock_dependencies.database.execute_query.assert_called() + + # TestModel should include tool results + assert "mock_database_query" in result.data.message + + @pytest.mark.asyncio + async def test_database_tool_error(self, mock_dependencies): + """Test database tool with error handling.""" + # Configure mock to raise exception + mock_dependencies.database.execute_query.side_effect = Exception("Connection failed") + + test_model = TestModel(call_tools=['mock_database_query']) + + with test_agent.override(model=test_model): + result = await test_agent.run( + "Query the database", + deps=mock_dependencies + ) + + # Tool should handle the error gracefully + assert "mock_database_query" in result.data.message + + def test_api_tool_with_data(self, mock_dependencies): + """Test API tool with POST data.""" + test_model = TestModel(call_tools=['mock_api_call']) + + with test_agent.override(model=test_model): + result = test_agent.run_sync( + "Make an API call to create a new record", + deps=mock_dependencies + ) + + # Verify API was called + mock_dependencies.api_client.post.assert_called() + + # Check tool execution in response + assert "mock_api_call" in result.data.message + + +class TestAgentWithFunctionModel: + """Test agent behavior with FunctionModel for custom responses.""" + + @pytest.fixture + def test_dependencies(self): + """Create basic test dependencies.""" + return TestDependencies( + database=AsyncMock(), + api_client=Mock() + ) + + def test_function_model_custom_behavior(self, test_dependencies): + """Test agent with FunctionModel for custom behavior.""" + def custom_response_func(messages, tools): + """Custom function to generate specific responses.""" + last_message = messages[-1].content if messages else "" + + if "error" in last_message.lower(): + return '{"message": "Error detected and handled", "confidence": 0.6, "actions": ["error_handling"]}' + else: + return '{"message": "Normal operation", "confidence": 0.9, "actions": ["standard_response"]}' + + function_model = FunctionModel(function=custom_response_func) + + with test_agent.override(model=function_model): + # Test normal case + result1 = test_agent.run_sync( + "Please help me with a normal request", + deps=test_dependencies + ) + assert result1.data.message == "Normal operation" + assert result1.data.confidence == 0.9 + + # Test error case + result2 = test_agent.run_sync( + "There's an error in the system", + deps=test_dependencies + ) + assert result2.data.message == "Error detected and handled" + assert result2.data.confidence == 0.6 + assert "error_handling" in result2.data.actions + + +class TestAgentValidation: + """Test agent output validation and error scenarios.""" + + @pytest.fixture + def test_dependencies(self): + """Create test dependencies.""" + return TestDependencies( + database=AsyncMock(), + api_client=Mock() + ) + + def test_invalid_output_handling(self, test_dependencies): + """Test how agent handles invalid output format.""" + # TestModel with invalid JSON output + test_model = TestModel( + custom_output_text='{"message": "test", "invalid_field": "should_not_exist"}' + ) + + with test_agent.override(model=test_model): + # This should either succeed with validation or raise appropriate error + try: + result = test_agent.run_sync( + "Test invalid output", + deps=test_dependencies + ) + # If it succeeds, Pydantic should filter out invalid fields + assert hasattr(result.data, 'message') + assert not hasattr(result.data, 'invalid_field') + except Exception as e: + # Or it might raise a validation error, which is also acceptable + assert "validation" in str(e).lower() or "error" in str(e).lower() + + def test_missing_required_fields(self, test_dependencies): + """Test handling of missing required fields in output.""" + # TestModel with missing required message field + test_model = TestModel( + custom_output_text='{"confidence": 0.8}' + ) + + with test_agent.override(model=test_model): + try: + result = test_agent.run_sync( + "Test missing fields", + deps=test_dependencies + ) + # Should either provide default or raise validation error + if hasattr(result.data, 'message'): + assert result.data.message is not None + except Exception as e: + # Validation error is expected for missing required fields + assert any(keyword in str(e).lower() for keyword in ['validation', 'required', 'missing']) + + +class TestAgentIntegration: + """Integration tests for complete agent workflows.""" + + @pytest.fixture + def full_mock_dependencies(self): + """Create fully configured mock dependencies.""" + database_mock = AsyncMock() + database_mock.execute_query.return_value = { + "user_id": "123", + "name": "Test User", + "status": "active" + } + + api_mock = Mock() + api_mock.post.return_value = { + "status": "success", + "transaction_id": "txn_123456" + } + + return TestDependencies( + database=database_mock, + api_client=api_mock, + user_id="test_integration_user" + ) + + @pytest.mark.asyncio + async def test_complete_workflow(self, full_mock_dependencies): + """Test complete agent workflow with multiple tools.""" + test_model = TestModel(call_tools='all') # Call all available tools + + with test_agent.override(model=test_model): + result = await test_agent.run( + "Please look up user information and create a new transaction", + deps=full_mock_dependencies + ) + + # Verify both tools were potentially called + assert result.data.message is not None + assert isinstance(result.data.actions, list) + + # Verify mocks were called + full_mock_dependencies.database.execute_query.assert_called() + full_mock_dependencies.api_client.post.assert_called() + + +class TestAgentErrorRecovery: + """Test agent error handling and recovery patterns.""" + + @pytest.fixture + def failing_dependencies(self): + """Create dependencies that will fail for testing error handling.""" + database_mock = AsyncMock() + database_mock.execute_query.side_effect = Exception("Database connection failed") + + api_mock = Mock() + api_mock.post.side_effect = Exception("API service unavailable") + + return TestDependencies( + database=database_mock, + api_client=api_mock, + user_id="failing_test_user" + ) + + @pytest.mark.asyncio + async def test_tool_error_recovery(self, failing_dependencies): + """Test agent behavior when tools fail.""" + test_model = TestModel(call_tools='all') + + with test_agent.override(model=test_model): + # Agent should handle tool failures gracefully + result = await test_agent.run( + "Try to access database and API", + deps=failing_dependencies + ) + + # Even with tool failures, agent should return a valid response + assert result.data.message is not None + assert isinstance(result.data.confidence, float) + + +# Pytest configuration and utilities +@pytest.fixture(scope="session") +def event_loop(): + """Create an instance of the default event loop for the test session.""" + loop = asyncio.get_event_loop_policy().new_event_loop() + yield loop + loop.close() + + +def pytest_configure(config): + """Configure pytest with custom markers.""" + config.addinivalue_line( + "markers", "integration: mark test as integration test" + ) + config.addinivalue_line( + "markers", "slow: mark test as slow running" + ) + + +if __name__ == "__main__": + # Run tests directly + pytest.main([__file__, "-v"]) \ No newline at end of file diff --git a/use-cases/pydantic-ai/examples/tool_enabled_agent/agent.py b/use-cases/pydantic-ai/examples/tool_enabled_agent/agent.py new file mode 100644 index 0000000..3366790 --- /dev/null +++ b/use-cases/pydantic-ai/examples/tool_enabled_agent/agent.py @@ -0,0 +1,374 @@ +""" +Tool-Enabled Agent with Web Search and Calculator + +Demonstrates PydanticAI tool integration patterns: +- Environment-based model configuration +- Tool registration with @agent.tool decorator +- RunContext for dependency injection +- Parameter validation with type hints +- Error handling and retry mechanisms +- String output (default, no result_type needed) +""" + +import logging +import math +import json +import asyncio +from dataclasses import dataclass +from typing import Optional, List, Dict, Any +from datetime import datetime +import aiohttp +from pydantic_settings import BaseSettings +from pydantic import Field +from pydantic_ai import Agent, RunContext +from pydantic_ai.providers.openai import OpenAIProvider +from pydantic_ai.models.openai import OpenAIModel +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +logger = logging.getLogger(__name__) + + +class Settings(BaseSettings): + """Configuration settings for the tool-enabled agent.""" + + # LLM Configuration + llm_provider: str = Field(default="openai") + llm_api_key: str = Field(...) + llm_model: str = Field(default="gpt-4") + llm_base_url: str = Field(default="https://api.openai.com/v1") + + class Config: + env_file = ".env" + case_sensitive = False + + +def get_llm_model() -> OpenAIModel: + """Get configured LLM model from environment settings.""" + try: + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key=settings.llm_api_key + ) + return OpenAIModel(settings.llm_model, provider=provider) + except Exception: + # For testing without env vars + import os + os.environ.setdefault("LLM_API_KEY", "test-key") + settings = Settings() + provider = OpenAIProvider( + base_url=settings.llm_base_url, + api_key="test-key" + ) + return OpenAIModel(settings.llm_model, provider=provider) + + +@dataclass +class ToolDependencies: + """Dependencies for tool-enabled agent.""" + session: Optional[aiohttp.ClientSession] = None + api_timeout: int = 10 + max_search_results: int = 5 + calculation_precision: int = 6 + session_id: Optional[str] = None + + +SYSTEM_PROMPT = """ +You are a helpful research assistant with access to web search and calculation tools. + +Your capabilities: +- Web search for current information and facts +- Mathematical calculations and data analysis +- Data processing and formatting +- Source verification and citation + +Guidelines: +- Always use tools when you need current information or calculations +- Cite sources when providing factual information +- Show your work for mathematical calculations +- Be precise and accurate in your responses +- If tools fail, explain the limitation and provide what you can +""" + + +# Create the tool-enabled agent - note: no result_type, defaults to string +tool_agent = Agent( + get_llm_model(), + deps_type=ToolDependencies, + system_prompt=SYSTEM_PROMPT +) + + +@tool_agent.tool +async def web_search( + ctx: RunContext[ToolDependencies], + query: str, + max_results: Optional[int] = None +) -> str: + """ + Search the web for current information. + + Args: + query: Search query string + max_results: Maximum number of results to return (default: 5) + + Returns: + Formatted search results with titles, snippets, and URLs + """ + if not ctx.deps.session: + return "Web search unavailable: No HTTP session configured" + + max_results = max_results or ctx.deps.max_search_results + + try: + # Using DuckDuckGo Instant Answer API as a simple example + # In production, use proper search APIs like Google, Bing, or DuckDuckGo + search_url = "https://api.duckduckgo.com/" + params = { + "q": query, + "format": "json", + "pretty": "1", + "no_redirect": "1" + } + + async with ctx.deps.session.get( + search_url, + params=params, + timeout=ctx.deps.api_timeout + ) as response: + if response.status == 200: + data = await response.json() + + results = [] + + # Process instant answer if available + if data.get("AbstractText"): + results.append({ + "title": "Instant Answer", + "snippet": data["AbstractText"], + "url": data.get("AbstractURL", "") + }) + + # Process related topics + for topic in data.get("RelatedTopics", [])[:max_results-len(results)]: + if isinstance(topic, dict) and "Text" in topic: + results.append({ + "title": topic.get("FirstURL", "").split("/")[-1].replace("_", " "), + "snippet": topic["Text"], + "url": topic.get("FirstURL", "") + }) + + if not results: + return f"No results found for query: {query}" + + # Format results + formatted_results = [] + for i, result in enumerate(results, 1): + formatted_results.append( + f"{i}. **{result['title']}**\n" + f" {result['snippet']}\n" + f" Source: {result['url']}" + ) + + return "\n\n".join(formatted_results) + else: + return f"Search failed with status: {response.status}" + + except asyncio.TimeoutError: + return f"Search timed out after {ctx.deps.api_timeout} seconds" + except Exception as e: + return f"Search error: {str(e)}" + + +@tool_agent.tool +def calculate( + ctx: RunContext[ToolDependencies], + expression: str, + description: Optional[str] = None +) -> str: + """ + Perform mathematical calculations safely. + + Args: + expression: Mathematical expression to evaluate + description: Optional description of what's being calculated + + Returns: + Calculation result with formatted output + """ + try: + # Safe evaluation - only allow mathematical operations + allowed_names = { + "abs": abs, "round": round, "min": min, "max": max, + "sum": sum, "pow": pow, "sqrt": math.sqrt, + "sin": math.sin, "cos": math.cos, "tan": math.tan, + "log": math.log, "log10": math.log10, "exp": math.exp, + "pi": math.pi, "e": math.e + } + + # Remove any potentially dangerous operations + safe_expression = expression.replace("__", "").replace("import", "") + + # Evaluate the expression + result = eval(safe_expression, {"__builtins__": {}}, allowed_names) + + # Format result with appropriate precision + if isinstance(result, float): + result = round(result, ctx.deps.calculation_precision) + + output = f"Calculation: {expression} = {result}" + if description: + output = f"{description}\n{output}" + + return output + + except Exception as e: + return f"Calculation error: {str(e)}\nExpression: {expression}" + + +@tool_agent.tool +def format_data( + ctx: RunContext[ToolDependencies], + data: str, + format_type: str = "table" +) -> str: + """ + Format data into structured output. + + Args: + data: Raw data to format + format_type: Type of formatting (table, list, json) + + Returns: + Formatted data string + """ + try: + lines = data.strip().split('\n') + + if format_type == "table": + # Simple table formatting + if len(lines) > 1: + header = lines[0] + rows = lines[1:] + + # Basic table formatting + formatted = f"| {header} |\n" + formatted += f"|{'-' * (len(header) + 2)}|\n" + for row in rows[:10]: # Limit to 10 rows + formatted += f"| {row} |\n" + + return formatted + else: + return data + + elif format_type == "list": + # Bullet point list + formatted_lines = [f"β€’ {line.strip()}" for line in lines if line.strip()] + return "\n".join(formatted_lines) + + elif format_type == "json": + # Try to parse and format as JSON + try: + parsed = json.loads(data) + return json.dumps(parsed, indent=2) + except json.JSONDecodeError: + # If not valid JSON, create simple key-value structure + items = {} + for i, line in enumerate(lines): + items[f"item_{i+1}"] = line.strip() + return json.dumps(items, indent=2) + + return data + + except Exception as e: + return f"Formatting error: {str(e)}" + + +@tool_agent.tool +def get_current_time(ctx: RunContext[ToolDependencies]) -> str: + """ + Get the current date and time. + + Returns: + Current timestamp in a readable format + """ + now = datetime.now() + return now.strftime("%Y-%m-%d %H:%M:%S UTC") + + +async def ask_agent( + question: str, + dependencies: Optional[ToolDependencies] = None +) -> str: + """ + Ask the tool-enabled agent a question. + + Args: + question: Question or request for the agent + dependencies: Optional tool dependencies + + Returns: + String response from the agent + """ + if dependencies is None: + # Create HTTP session for web search + session = aiohttp.ClientSession() + dependencies = ToolDependencies(session=session) + + try: + result = await tool_agent.run(question, deps=dependencies) + return result.data + finally: + # Clean up session if we created it + if dependencies.session and not dependencies.session.closed: + await dependencies.session.close() + + +def ask_agent_sync(question: str) -> str: + """ + Synchronous version of ask_agent. + + Args: + question: Question or request for the agent + + Returns: + String response from the agent + """ + return asyncio.run(ask_agent(question)) + + +# Example usage and demonstration +if __name__ == "__main__": + async def demo_tools(): + """Demonstrate the tool-enabled agent capabilities.""" + print("=== Tool-Enabled Agent Demo ===\n") + + # Create dependencies with HTTP session + session = aiohttp.ClientSession() + dependencies = ToolDependencies(session=session) + + try: + # Sample questions that exercise different tools + questions = [ + "What's the current time?", + "Calculate the square root of 144 plus 25% of 200", + "Search for recent news about artificial intelligence", + "Format this data as a table: Name,Age\nAlice,25\nBob,30\nCharlie,35" + ] + + for question in questions: + print(f"Question: {question}") + + response = await ask_agent(question, dependencies) + + print(f"Answer: {response}") + print("-" * 60) + + finally: + await session.close() + + # Run the demo + asyncio.run(demo_tools()) \ No newline at end of file diff --git a/use-cases/template-generator/.claude/commands/execute-template-prp.md b/use-cases/template-generator/.claude/commands/execute-template-prp.md new file mode 100644 index 0000000..f4c064b --- /dev/null +++ b/use-cases/template-generator/.claude/commands/execute-template-prp.md @@ -0,0 +1,165 @@ +# Execute Template Generation PRP + +Execute a comprehensive template generation PRP to create a complete context engineering template package for a specific technology/framework. + +## PRP File: $ARGUMENTS + +## Execution Process + +1. **Load Template Generation PRP** + - Read the specified template generation PRP file completely + - Understand the target technology and all requirements + - Review all web research findings documented in the PRP + - Follow all instructions for template package creation + +2. **ULTRATHINK - Template Package Design** + - Create comprehensive implementation plan + - Plan the complete template package structure based on PRP research + - Design domain-specific context engineering adaptations + - Map technology patterns to context engineering principles + - Plan all required files and their relationships + +3. **Generate Complete Template Package** + - Create complete directory structure for the technology use case + - Generate domain-specific CLAUDE.md with global rules + - Create specialized template PRP generation and execution commands + - Develop domain-specific base PRP template with research findings + - Include comprehensive examples and documentation from web research + +4. **Validate Template Package** + - Run all validation commands specified in the PRP + - Verify all required files are created and properly formatted + - Test template structure completeness and accuracy + - Check integration with base context engineering framework + +5. **Quality Assurance** + - Ensure template follows all context engineering principles + - Verify domain-specific patterns are accurately represented + - Check validation loops are appropriate and executable for the technology + - Confirm template is immediately usable for the target technology + +6. **Complete Implementation** + - Review template package against all PRP requirements + - Ensure all success criteria from the PRP are met + - Validate template is production-ready + +## Template Package Requirements + +Create a complete use case template with this exact structure: + +### Required Directory Structure +``` +use-cases/{technology-name}/ +β”œβ”€β”€ CLAUDE.md # Domain global rules +β”œβ”€β”€ .claude/commands/ +β”‚ β”œβ”€β”€ generate-{technology}-prp.md # Domain PRP generation +β”‚ └── execute-{technology}-prp.md # Domain PRP execution +β”œβ”€β”€ PRPs/ +β”‚ β”œβ”€β”€ templates/ +β”‚ β”‚ └── prp_{technology}_base.md # Domain base PRP template +β”‚ β”œβ”€β”€ ai_docs/ # Domain documentation (optional) +β”‚ └── INITIAL.md # Example feature request +β”œβ”€β”€ examples/ # Domain code examples +β”œβ”€β”€ copy_template.py # Template deployment script +└── README.md # Comprehensive usage guide +``` + +### Content Requirements Based on PRP Research + +**CLAUDE.md** must include (global rules for the domain): +- Technology-specific tooling and package management commands +- Domain architectural patterns and conventions +- Framework-specific development workflow procedures +- Security and best practices specific to the technology +- Common gotchas and integration points + +**Domain PRP Commands** must include: +- Technology-specific research processes and web search strategies +- Domain documentation gathering approaches based on PRP findings +- Framework-appropriate validation loops and testing patterns +- Specialized implementation blueprints for the technology + +**Base PRP Template** must include: +- Pre-filled domain context from web research conducted in PRP +- Technology-specific success criteria and validation gates +- Framework-appropriate implementation patterns and examples +- Domain-specialized documentation references and gotchas + +**Copy Script (copy_template.py)** must include: +- Accept target directory as command line argument +- Copy entire template directory structure to target location +- Include ALL files: CLAUDE.md, .claude/, PRPs/, examples/, README.md +- Handle directory creation and error handling gracefully +- Provide clear success feedback with next steps + +**README.md** must include: +- Clear description of template purpose and capabilities +- Copy script usage instructions (prominently placed near top) +- Complete PRP framework workflow explanation (3-step process) +- Template structure overview with file explanations +- Technology-specific examples and capabilities +- Common gotchas and troubleshooting guidance + +## Validation Requirements + +### Structure Validation +```bash +# Verify complete structure exists +find use-cases/{technology-name} -type f -name "*.md" | sort +ls -la use-cases/{technology-name}/.claude/commands/ +ls -la use-cases/{technology-name}/PRPs/templates/ + +# Check required files exist +test -f use-cases/{technology-name}/CLAUDE.md +test -f use-cases/{technology-name}/README.md +test -f use-cases/{technology-name}/PRPs/INITIAL.md +test -f use-cases/{technology-name}/copy_template.py + +# Test copy script functionality +python use-cases/{technology-name}/copy_template.py 2>&1 | grep -q "Usage:" || echo "Copy script needs proper usage message" +``` + +### Content Validation +```bash +# Check for incomplete content +grep -r "TODO\|PLACEHOLDER\|WEBSEARCH_NEEDED" use-cases/{technology-name}/ +grep -r "{technology}" use-cases/{technology-name}/ | wc -l # Should be 0 + +# Verify domain-specific content exists +grep -r "framework\|library\|technology" use-cases/{technology-name}/CLAUDE.md +grep -r "WebSearch\|web search" use-cases/{technology-name}/.claude/commands/ + +# Verify README has required sections +grep -q "Quick Start.*Copy Template" use-cases/{technology-name}/README.md +grep -q "PRP Framework Workflow" use-cases/{technology-name}/README.md +grep -q "python copy_template.py" use-cases/{technology-name}/README.md +``` + +### Functionality Testing +```bash +# Test template functionality +cd use-cases/{technology-name} + +# Verify commands are properly named +ls .claude/commands/ | grep "{technology}" + +# Test INITIAL.md example exists and is comprehensive +wc -l PRPs/INITIAL.md # Should be substantial, not just a few lines +``` + +## Success Criteria + +- [ ] Complete template package structure created exactly as specified +- [ ] All required files present and properly formatted +- [ ] Domain-specific content accurately represents technology based on PRP research +- [ ] Context engineering principles properly adapted for the technology +- [ ] Validation loops appropriate and executable for the framework +- [ ] Template package immediately usable for building projects in the domain +- [ ] Integration with base context engineering framework maintained +- [ ] All web research findings from PRP properly integrated into template +- [ ] Examples and documentation comprehensive and technology-specific +- [ ] Copy script (copy_template.py) functional and properly documented +- [ ] README includes copy script instructions prominently at top +- [ ] README explains complete PRP framework workflow with concrete examples + +Note: If any validation fails, analyze the error, fix the template package components, and re-validate until all criteria pass. The template must be production-ready and immediately usable for developers working with the target technology. \ No newline at end of file diff --git a/use-cases/template-generator/.claude/commands/generate-template-prp.md b/use-cases/template-generator/.claude/commands/generate-template-prp.md new file mode 100644 index 0000000..d8909f0 --- /dev/null +++ b/use-cases/template-generator/.claude/commands/generate-template-prp.md @@ -0,0 +1,105 @@ +# Generate Template PRP + +## Feature file: $ARGUMENTS + +Generate a comprehensive PRP for creating context engineering templates for specific technology domains based on the detailed requirements in the INITIAL.md file. This follows the standard PRP framework workflow: INITIAL.md β†’ generate-template-prp β†’ execute-template-prp. + +**CRITICAL: Web search and documentation research is your best friend. Use it extensively throughout this process.** + +## Research Process + +1. **Read and Understand Requirements** + - Read the specified INITIAL.md file thoroughly + - Understand the target technology and specific template requirements + - Note any specific features, examples, or documentation mentioned + - Identify the scope and complexity of the template needed + +2. **Extensive Web Research (CRITICAL)** + - **Web search the target technology extensively** - this is essential + - Study official documentation, APIs, and getting started guides + - Research best practices and common architectural patterns + - Find real-world implementation examples and tutorials + - Identify common gotchas, pitfalls, and edge cases + - Look for established project structure conventions + +3. **Technology Pattern Analysis** + - Examine successful implementations found through web research + - Identify project structure and file organization patterns + - Extract reusable code patterns and configuration templates + - Document framework-specific development workflows + - Note testing frameworks and validation approaches + +4. **Context Engineering Adaptation** + - Map discovered technology patterns to context engineering principles + - Plan how to adapt the PRP framework for this specific technology + - Design domain-specific validation requirements + - Plan template package structure and components + +## PRP Generation + +Using PRPs/templates/prp_template_base.md as the foundation: + +### Critical Context to Include from Web Research + +**Technology Documentation (from web search)**: +- Official framework documentation URLs with specific sections +- Getting started guides and tutorials +- API references and best practices guides +- Community resources and example repositories + +**Implementation Patterns (from research)**: +- Framework-specific project structures and conventions +- Configuration management approaches +- Development workflow patterns +- Testing and validation approaches + +**Real-World Examples**: +- Links to successful implementations found online +- Code snippets and configuration examples +- Common integration patterns +- Deployment and setup procedures + +### Implementation Blueprint + +Based on web research findings: +- **Technology Analysis**: Document framework characteristics and patterns +- **Template Structure**: Plan complete template package components +- **Specialization Strategy**: How to adapt context engineering for this technology +- **Validation Design**: Technology-appropriate testing and validation loops + +### Validation Gates (Must be Executable) + +```bash +# Template Structure Validation +ls -la use-cases/{technology-name}/ +find use-cases/{technology-name}/ -name "*.md" | wc -l # Should have all required files + +# Template Content Validation +grep -r "TODO\|PLACEHOLDER" use-cases/{technology-name}/ # Should be empty +grep -r "WEBSEARCH_NEEDED" use-cases/{technology-name}/ # Should be empty + +# Template Functionality Testing +cd use-cases/{technology-name} +/generate-{technology}-prp INITIAL.md # Test domain-specific PRP generation +``` + +*** CRITICAL: Do extensive web research before writing the PRP *** +*** Use WebSearch tool extensively to understand the technology deeply *** + +## Output + +Save as: `PRPs/template-{technology-name}.md` + +## Quality Checklist + +- [ ] Extensive web research completed on target technology +- [ ] Official documentation thoroughly reviewed +- [ ] Real-world examples and patterns identified +- [ ] Complete template package structure planned +- [ ] Domain-specific validation designed +- [ ] All web research findings documented in PRP +- [ ] Technology-specific gotchas and patterns captured + +Score the PRP on a scale of 1-10 (confidence level for creating comprehensive, immediately usable templates based on thorough technology research). + +Remember: The goal is creating complete, specialized template packages that make context engineering trivial to apply to any technology domain through comprehensive research and documentation. \ No newline at end of file diff --git a/use-cases/template-generator/.claude/settings.local.json b/use-cases/template-generator/.claude/settings.local.json new file mode 100644 index 0000000..d08d7ec --- /dev/null +++ b/use-cases/template-generator/.claude/settings.local.json @@ -0,0 +1,17 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:ai.pydantic.dev)", + "mcp__archon__get_available_sources", + "Bash(mkdir:*)", + "Bash(ls:*)", + "mcp__archon__perform_rag_query", + "mcp__archon__search_code_examples", + "Bash(find:*)", + "Bash(test:*)", + "Bash(grep:*)", + "Bash(python:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/use-cases/template-generator/CLAUDE.md b/use-cases/template-generator/CLAUDE.md new file mode 100644 index 0000000..ebd5fe9 --- /dev/null +++ b/use-cases/template-generator/CLAUDE.md @@ -0,0 +1,76 @@ +# Template Generator - Global Rules for Context Engineering + +This file contains the global rules and principles that apply to ALL context engineering work, regardless of what template or project you're building. These rules never change and should be followed consistently. + +## πŸ”„ Context Engineering Core Principles + +**IMPORTANT: These principles apply to ALL context engineering work:** + +### PRP Framework Workflow +- **Always start with INITIAL.md** - Define requirements before generating PRPs +- **Use the PRP pattern**: INITIAL.md β†’ `/generate-template-prp INITIAL.md` β†’ `/execute-template-prp PRPs/filename.md` +- **Follow validation loops** - Each PRP must include executable validation steps +- **Context is King** - Include ALL necessary documentation, examples, and patterns + +### Research Methodology +- **Web search first** - Always do extensive web research before implementation +- **Documentation deep dive** - Study official docs, best practices, and common patterns +- **Pattern extraction** - Identify reusable patterns and architectural conventions +- **Gotcha documentation** - Document common pitfalls and edge cases + +## πŸ“š Project Awareness & Context + +- **Use consistent naming conventions** and file structure patterns +- **Follow established directory organization** patterns +- **Leverage examples extensively** - Study existing patterns before creating new ones + +## 🧱 Code Structure & Modularity + +- **Never create files longer than 500 lines** - Split into modules when approaching limit +- **Organize code into clearly separated modules** grouped by feature or responsibility +- **Use clear, consistent imports** (prefer relative imports within packages) +- **Follow established coding standards** and conventions + +## βœ… Task Management + +- **Break complex tasks into smaller steps** with clear completion criteria +- **Mark tasks complete immediately** after finishing them +- **Update task status in real-time** as work progresses + +## πŸ“Ž Documentation Standards + +- **Write comprehensive documentation** for every component +- **Include clear usage examples** with working code +- **Document all gotchas and edge cases** to prevent common errors +- **Maintain up-to-date references** to external documentation + +## πŸ” Research Standards + +- **Web search is your best friend** - Use it extensively for technology research +- **Study official documentation thoroughly** before implementation +- **Research established patterns** and best practices for the technology +- **Document all findings comprehensively** in PRPs and implementation guides + +## 🎯 Implementation Standards + +- **Follow the PRP workflow religiously** - Don't skip steps +- **Always validate before proceeding** to the next step +- **Use existing patterns as templates** rather than creating from scratch +- **Include comprehensive error handling** in all implementations + +## 🚫 Anti-Patterns to Always Avoid + +- ❌ Don't skip research - Always understand the technology deeply first +- ❌ Don't create generic solutions - Always specialize for the specific use case +- ❌ Don't ignore validation - Every step must include verification +- ❌ Don't assume knowledge - Document everything explicitly +- ❌ Don't skip examples - Always include working code examples +- ❌ Don't forget edge cases - Include error handling and gotchas + +## πŸ”§ Tool Usage Standards + +- **Use web search extensively** for research and documentation +- **Follow established command patterns** for slash commands +- **Use validation loops** to ensure quality at each step + +These global rules apply regardless of whether you're generating templates, implementing features, or doing research. They form the foundation of effective context engineering work. \ No newline at end of file diff --git a/use-cases/template-generator/PRPs/INITIAL.md b/use-cases/template-generator/PRPs/INITIAL.md new file mode 100644 index 0000000..a7ac907 --- /dev/null +++ b/use-cases/template-generator/PRPs/INITIAL.md @@ -0,0 +1,228 @@ +# Template Generation Request + +## TECHNOLOGY/FRAMEWORK: + +**Example:** Pydantic AI agents +**Example:** Supabase frontend applications +**Example:** CrewAI multi-agent systems + +**Your technology:** [Specify the exact framework, library, or technology you want to create a context engineering template for] + +--- + +## TEMPLATE PURPOSE: + +**What specific use case should this template be optimized for?** + +**Example for Pydantic AI:** "Building intelligent AI agents with tool integration, conversation handling, and structured data validation using Pydantic AI framework" + +**Example for Supabase:** "Creating full-stack web applications with real-time data, authentication, and serverless functions using Supabase as the backend" + +**Your purpose:** [Be very specific about what developers should be able to build easily with this template] + +--- + +## CORE FEATURES: + +**What are the essential features this template should help developers implement?** + +**Example for Pydantic AI:** +- Agent creation with different model providers (OpenAI, Anthropic, Gemini) +- Tool integration patterns (web search, file operations, API calls) +- Conversation memory and context management +- Structured output validation with Pydantic models +- Error handling and retry mechanisms +- Testing patterns for AI agent behavior + +**Example for Supabase:** +- Database schema design and migrations +- Real-time subscriptions and live data updates +- Row Level Security (RLS) policy implementation +- Authentication flows (email, OAuth, magic links) +- Serverless edge functions for backend logic +- File storage and CDN integration + +**Your core features:** [List the specific capabilities developers should be able to implement easily] + +--- + +## EXAMPLES TO INCLUDE: + +**What working examples should be provided in the template?** + +**Example for Pydantic AI:** +- Basic chat agent with memory +- Tool-enabled agent (web search + calculator) +- Multi-step workflow agent +- Agent with custom Pydantic models for structured outputs +- Testing examples for agent responses and tool usage + +**Example for Supabase:** +- User authentication and profile management +- Real-time chat or messaging system +- File upload and sharing functionality +- Multi-tenant application patterns +- Database triggers and functions + +**Your examples:** [Specify concrete, working examples that should be included] + +--- + +## DOCUMENTATION TO RESEARCH: + +**What specific documentation should be thoroughly researched and referenced?** + +**Example for Pydantic AI:** +- https://ai.pydantic.dev/ - Official Pydantic AI documentation +- https://docs.pydantic.dev/ - Pydantic data validation library +- Model provider APIs (OpenAI, Anthropic) for integration patterns +- Tool integration best practices and examples +- Testing frameworks for AI applications + +**Example for Supabase:** +- https://supabase.com/docs - Complete Supabase documentation +- https://supabase.com/docs/guides/auth - Authentication guide +- https://supabase.com/docs/guides/realtime - Real-time features +- Database design patterns and RLS policies +- Edge functions development and deployment + +**Your documentation:** [List specific URLs and documentation sections to research deeply] + +--- + +## DEVELOPMENT PATTERNS: + +**What specific development patterns, project structures, or workflows should be researched and included?** + +**Example for Pydantic AI:** +- How to structure agent modules and tool definitions +- Configuration management for different model providers +- Environment setup for development vs production +- Logging and monitoring patterns for AI agents +- Version control patterns for prompts and agent configurations + +**Example for Supabase:** +- Frontend + Supabase project structure patterns +- Local development workflow with Supabase CLI +- Database migration and versioning strategies +- Environment management (local, staging, production) +- Testing strategies for full-stack Supabase applications + +**Your development patterns:** [Specify the workflow and organizational patterns to research] + +--- + +## SECURITY & BEST PRACTICES: + +**What security considerations and best practices are critical for this technology?** + +**Example for Pydantic AI:** +- API key management and rotation +- Input validation and sanitization for agent inputs +- Rate limiting and usage monitoring +- Prompt injection prevention +- Cost control and monitoring for model usage + +**Example for Supabase:** +- Row Level Security (RLS) policy design +- API key vs JWT authentication patterns +- Database security and access control +- File upload security and virus scanning +- Rate limiting and abuse prevention + +**Your security considerations:** [List technology-specific security patterns to research and document] + +--- + +## COMMON GOTCHAS: + +**What are the typical pitfalls, edge cases, or complex issues developers face with this technology?** + +**Example for Pydantic AI:** +- Model context length limitations and management +- Handling model provider rate limits and errors +- Token counting and cost optimization +- Managing conversation state across requests +- Tool execution error handling and retries + +**Example for Supabase:** +- RLS policy debugging and testing +- Real-time subscription performance with large datasets +- Edge function cold starts and optimization +- Database connection pooling in serverless environments +- CORS configuration for different domains + +**Your gotchas:** [Identify the specific challenges developers commonly face] + +--- + +## VALIDATION REQUIREMENTS: + +**What specific validation, testing, or quality checks should be included in the template?** + +**Example for Pydantic AI:** +- Agent response quality testing +- Tool integration testing +- Model provider fallback testing +- Cost and performance benchmarking +- Conversation flow validation + +**Example for Supabase:** +- Database migration testing +- RLS policy validation +- Real-time functionality testing +- Authentication flow testing +- Edge function integration testing + +**Your validation requirements:** [Specify the testing and validation patterns needed] + +--- + +## INTEGRATION FOCUS: + +**What specific integrations or third-party services are commonly used with this technology?** + +**Example for Pydantic AI:** +- Integration with vector databases (Pinecone, Weaviate) +- Web scraping tools and APIs +- External API integrations for tools +- Monitoring services (Weights & Biases, LangSmith) +- Deployment platforms (Modal, Replicate) + +**Example for Supabase:** +- Frontend frameworks (Next.js, React, Vue) +- Payment processing (Stripe) +- Email services (SendGrid, Resend) +- File processing (image optimization, document parsing) +- Analytics and monitoring tools + +**Your integration focus:** [List the key integrations to research and include] + +--- + +## ADDITIONAL NOTES: + +**Any other specific requirements, constraints, or considerations for this template?** + +**Example:** "Focus on TypeScript patterns and include comprehensive type definitions" +**Example:** "Emphasize serverless deployment patterns and cost optimization" +**Example:** "Include patterns for both beginner and advanced use cases" + +**Your additional notes:** [Any other important considerations] + +--- + +## TEMPLATE COMPLEXITY LEVEL: + +**What level of complexity should this template target?** + +- [ ] **Beginner-friendly** - Simple getting started patterns +- [ ] **Intermediate** - Production-ready patterns with common features +- [ ] **Advanced** - Comprehensive patterns including complex scenarios +- [ ] **Enterprise** - Full enterprise patterns with monitoring, scaling, security + +**Your choice:** [Select the appropriate complexity level and explain why] + +--- + +**REMINDER: Be as specific as possible in each section. The more detailed you are here, the better the generated template will be. This INITIAL.md file is where you should put all your requirements, not just basic information.** \ No newline at end of file diff --git a/use-cases/template-generator/PRPs/INITIAL_PYDANTIC_AI.md b/use-cases/template-generator/PRPs/INITIAL_PYDANTIC_AI.md new file mode 100644 index 0000000..f854b8e --- /dev/null +++ b/use-cases/template-generator/PRPs/INITIAL_PYDANTIC_AI.md @@ -0,0 +1,101 @@ +# Template Generation Request + +## TECHNOLOGY/FRAMEWORK: + +**Example:** CrewAI multi-agent systems + +**Your technology:** Pydantic AI agents + +--- + +## TEMPLATE PURPOSE: + +**What specific use case should this template be optimized for?** + +**Your purpose:** Building intelligent AI agents with tool integration, conversation handling, and structured data validation using Pydantic AI framework + +--- + +## CORE FEATURES: + +**What are the essential features this template should help developers implement?** + +**Your core features:** + +- Agent creation with different model providers (OpenAI, Anthropic, Gemini) +- Tool integration patterns (web search, file operations, API calls) +- Conversation memory and context management +- Structured output validation with Pydantic models +- Error handling and retry mechanisms +- Testing patterns for AI agent behavior + +--- + +## EXAMPLES TO INCLUDE: + +**What working examples should be provided in the template?** + +**Your examples:** + +- Basic chat agent with memory +- Tool-enabled agent (web search + calculator) +- Multi-step workflow agent +- Agent with custom Pydantic models for structured outputs +- Testing examples for agent responses and tool usage + +--- + +## DOCUMENTATION TO RESEARCH: + +**What specific documentation should be thoroughly researched and referenced?** + +**Your documentation:** +- https://ai.pydantic.dev/ - Official Pydantic AI documentation +- Model provider APIs (OpenAI, Anthropic) for integration patterns +- Tool integration best practices and examples + +--- + +## DEVELOPMENT PATTERNS: + +**What specific development patterns, project structures, or workflows should be researched and included?** + +**Your development patterns:** +- How to structure agent modules and tool definitions +- Configuration management for different model providers +- Environment setup for development vs production +- Logging and monitoring patterns for AI agents + +--- + +## SECURITY & BEST PRACTICES: + +**What security considerations and best practices are critical for this technology?** + +**Your security considerations:** +- API key management +- Input validation and sanitization for agent inputs +- Rate limiting and usage monitoring +- Prompt injection prevention +- Cost control and monitoring for model usage + +--- + +## COMMON GOTCHAS: + +**What are the typical pitfalls, edge cases, or complex issues developers face with this technology?** + +**Your gotchas:** +- Handling model provider rate limits and errors +- Managing conversation state across requests +- Tool execution error handling and retries + +--- + +## VALIDATION REQUIREMENTS: + +**What specific validation, testing, or quality checks should be included in the template?** + +**Your validation requirements:** +- Tool unit testing testing +- Agent unit testing diff --git a/use-cases/template-generator/PRPs/template-pydantic-ai.md b/use-cases/template-generator/PRPs/template-pydantic-ai.md new file mode 100644 index 0000000..39c8d9b --- /dev/null +++ b/use-cases/template-generator/PRPs/template-pydantic-ai.md @@ -0,0 +1,604 @@ +--- +name: "PydanticAI Template Generator PRP" +description: "Generate comprehensive context engineering template for PydanticAI agent development with tools, memory, and structured outputs" +--- + +## Purpose + +Generate a complete context engineering template package for **PydanticAI** that enables developers to rapidly build intelligent AI agents with tool integration, conversation handling, and structured data validation using the PydanticAI framework. + +## Core Principles + +1. **PydanticAI Specialization**: Deep integration with PydanticAI patterns for agent creation, tools, and structured outputs +2. **Complete Package Generation**: Create entire template ecosystem with working examples and validation +3. **Type Safety First**: Leverage PydanticAI's type-safe design and Pydantic validation throughout +4. **Production Ready**: Include security, testing, and best practices for production deployments +5. **Context Engineering Integration**: Apply proven context engineering workflows to AI agent development + +--- + +## Goal + +Generate a complete context engineering template package for **PydanticAI** that includes: + +- PydanticAI-specific CLAUDE.md implementation guide with agent patterns +- Specialized PRP generation and execution commands for AI agents +- Domain-specific base PRP template with agent architecture patterns +- Comprehensive working examples (chat agents, tool integration, multi-step workflows) +- PydanticAI-specific validation loops and testing patterns + +## Why + +- **AI Development Acceleration**: Enable rapid development of production-grade PydanticAI agents +- **Pattern Consistency**: Maintain established AI agent architecture patterns and best practices +- **Quality Assurance**: Ensure comprehensive testing for agent behavior, tools, and outputs +- **Knowledge Capture**: Document PydanticAI-specific patterns, gotchas, and integration strategies +- **Scalable AI Framework**: Create reusable templates for various AI agent use cases + +## What + +### Template Package Components + +**Complete Directory Structure:** +``` +use-cases/pydantic-ai/ +β”œβ”€β”€ CLAUDE.md # PydanticAI implementation guide +β”œβ”€β”€ .claude/commands/ +β”‚ β”œβ”€β”€ generate-pydantic-ai-prp.md # Agent PRP generation +β”‚ └── execute-pydantic-ai-prp.md # Agent PRP execution +β”œβ”€β”€ PRPs/ +β”‚ β”œβ”€β”€ templates/ +β”‚ β”‚ └── prp_pydantic_ai_base.md # PydanticAI base PRP template +β”‚ β”œβ”€β”€ ai_docs/ # PydanticAI documentation +β”‚ └── INITIAL.md # Example agent feature request +β”œβ”€β”€ examples/ +β”‚ β”œβ”€β”€ basic_chat_agent/ # Simple chat agent with memory +β”‚ β”œβ”€β”€ tool_enabled_agent/ # Web search + calculator tools +β”‚ β”œβ”€β”€ workflow_agent/ # Multi-step workflow processing +β”‚ β”œβ”€β”€ structured_output_agent/ # Custom Pydantic models +β”‚ └── testing_examples/ # Agent testing patterns +β”œβ”€β”€ copy_template.py # Template deployment script +└── README.md # Comprehensive usage guide +``` + +**PydanticAI Integration:** +- Agent creation with multiple model providers (OpenAI, Anthropic, Gemini) +- Tool integration patterns and function registration +- Conversation memory and context management using dependencies +- Structured output validation with Pydantic models +- Testing patterns using TestModel and FunctionModel +- Security patterns for API key management and input validation + +**Context Engineering Adaptation:** +- PydanticAI-specific research processes and documentation references +- Agent-appropriate validation loops and testing strategies +- AI framework-specialized implementation blueprints +- Integration with base context engineering principles for AI development + +### Success Criteria + +- [ ] Complete PydanticAI template package structure generated +- [ ] All required files present with PydanticAI-specific content +- [ ] Agent patterns accurately represent PydanticAI best practices +- [ ] Context engineering principles adapted for AI agent development +- [ ] Validation loops appropriate for testing AI agents and tools +- [ ] Template immediately usable for creating PydanticAI projects +- [ ] Integration with base context engineering framework maintained +- [ ] Comprehensive examples and testing documentation included + +## All Needed Context + +### Documentation & References (RESEARCHED) + +```yaml +# IMPORTANT - use the Archon MCP server to get more Pydantic AI documentation! +- mcp: Archon + why: Official Pydantic AI documentation ready for RAG lookup + content: All Pydantic AI documentation +# PYDANTIC AI CORE DOCUMENTATION - Essential framework understanding +- url: https://ai.pydantic.dev/ + why: Official PydanticAI documentation with core concepts and getting started + content: Agent creation, model providers, type safety, dependency injection + +- url: https://ai.pydantic.dev/agents/ + why: Comprehensive agent architecture, system prompts, tools, structured outputs + content: Agent components, execution methods, configuration options + +- url: https://ai.pydantic.dev/models/ + why: Model provider configuration, API key management, fallback models + content: OpenAI, Anthropic, Gemini integration patterns and authentication + +- url: https://ai.pydantic.dev/tools/ + why: Function tool registration, context usage, rich returns, dynamic tools + content: Tool decorators, parameter validation, documentation patterns + +- url: https://ai.pydantic.dev/testing/ + why: Testing strategies, TestModel, FunctionModel, pytest patterns + content: Unit testing, agent behavior validation, mock model usage + +- url: https://ai.pydantic.dev/examples/ + why: Working examples for various PydanticAI use cases + content: Chat apps, RAG systems, SQL generation, FastAPI integration + +# CONTEXT ENGINEERING FOUNDATION - Base framework to adapt +- file: ../../../README.md + why: Core context engineering principles and workflow to adapt for AI agents + +- file: ../../../.claude/commands/generate-prp.md + why: Base PRP generation patterns to specialize for PydanticAI development + +- file: ../../../.claude/commands/execute-prp.md + why: Base PRP execution patterns to adapt for AI agent validation + +- file: ../../../PRPs/templates/prp_base.md + why: Base PRP template structure to specialize for PydanticAI domain + +# MCP SERVER EXAMPLE - Reference implementation +- file: ../mcp-server/CLAUDE.md + why: Example of domain-specific implementation guide patterns + +- file: ../mcp-server/.claude/commands/prp-mcp-create.md + why: Example of specialized PRP generation command structure +``` + +### PydanticAI Framework Analysis (FROM RESEARCH) + +```typescript +// PydanticAI Architecture Patterns (from official docs) +interface PydanticAIPatterns { + // Core agent patterns + agent_creation: { + model_providers: ["openai:gpt-4o", "anthropic:claude-3-sonnet", "google:gemini-1.5-flash"]; + configuration: ["system_prompt", "deps_type", "output_type", "instructions"]; + execution_methods: ["run()", "run_sync()", "run_stream()", "iter()"]; + }; + + // Tool integration patterns + tool_system: { + registration: ["@agent.tool", "@agent.tool_plain", "tools=[]"]; + context_access: ["RunContext[DepsType]", "ctx.deps", "dependency_injection"]; + return_types: ["str", "ToolReturn", "structured_data", "rich_content"]; + validation: ["parameter_schemas", "docstring_extraction", "type_hints"]; + }; + + // Testing and validation + testing_patterns: { + unit_testing: ["TestModel", "FunctionModel", "Agent.override()"]; + validation: ["capture_run_messages()", "pytest_fixtures", "mock_dependencies"]; + evals: ["model_performance", "agent_behavior", "production_monitoring"]; + }; + + // Production considerations + security: { + api_keys: ["environment_variables", "secure_storage", "key_rotation"]; + input_validation: ["pydantic_models", "parameter_validation", "sanitization"]; + monitoring: ["logfire_integration", "usage_tracking", "error_handling"]; + }; +} +``` + +### Development Workflow Analysis (FROM RESEARCH) + +```yaml +# PydanticAI Development Patterns (researched from docs and examples) +project_structure: + basic_pattern: | + my_agent/ + β”œβ”€β”€ agent.py # Main agent definition + β”œβ”€β”€ tools.py # Tool functions + β”œβ”€β”€ models.py # Pydantic output models + β”œβ”€β”€ dependencies.py # Context dependencies + └── tests/ + β”œβ”€β”€ test_agent.py + └── test_tools.py + + advanced_pattern: | + agents_project/ + β”œβ”€β”€ agents/ + β”‚ β”œβ”€β”€ __init__.py + β”‚ β”œβ”€β”€ chat_agent.py + β”‚ └── workflow_agent.py + β”œβ”€β”€ tools/ + β”‚ β”œβ”€β”€ __init__.py + β”‚ β”œβ”€β”€ web_search.py + β”‚ └── calculator.py + β”œβ”€β”€ models/ + β”‚ β”œβ”€β”€ __init__.py + β”‚ └── outputs.py + β”œβ”€β”€ dependencies/ + β”‚ β”œβ”€β”€ __init__.py + β”‚ └── database.py + β”œβ”€β”€ tests/ + └── examples/ + +package_management: + installation: "pip install pydantic-ai" + optional_deps: "pip install 'pydantic-ai[examples]'" + dev_deps: "pip install pytest pytest-asyncio inline-snapshot dirty-equals" + +testing_workflow: + unit_tests: "pytest tests/ -v" + agent_testing: "Use TestModel for fast validation" + integration_tests: "Use real models with rate limiting" + evals: "Run performance benchmarks separately" + +environment_setup: + api_keys: ["OPENAI_API_KEY", "ANTHROPIC_API_KEY", "GEMINI_API_KEY"] + development: "Set ALLOW_MODEL_REQUESTS=False for testing" + production: "Configure proper logging and monitoring" +``` + +### Security and Best Practices (FROM RESEARCH) + +```typescript +// Security patterns specific to PydanticAI (from research) +interface PydanticAISecurity { + // API key management + api_security: { + storage: "environment_variables_only"; + access_control: "minimal_required_permissions"; + monitoring: "usage_tracking_and_alerts"; + }; + + // Input validation and sanitization + input_security: { + validation: "pydantic_models_for_all_inputs"; + sanitization: "escape_user_content"; + rate_limiting: "prevent_abuse_patterns"; + content_filtering: "block_malicious_prompts"; + }; + + // Prompt injection prevention + prompt_security: { + system_prompts: "clear_instruction_boundaries"; + user_input: "validate_and_sanitize"; + tool_calls: "parameter_validation"; + output_filtering: "structured_response_validation"; + }; + + // Production considerations + production_security: { + monitoring: "logfire_integration_recommended"; + error_handling: "no_sensitive_data_in_logs"; + dependency_injection: "secure_context_management"; + testing: "security_focused_unit_tests"; + }; +} +``` + +### Common Gotchas and Edge Cases (FROM RESEARCH) + +```yaml +# PydanticAI-specific gotchas discovered through research +agent_gotchas: + model_limits: + issue: "Different models have different token limits and capabilities" + solution: "Use FallbackModel for automatic model switching" + validation: "Test with multiple model providers" + + async_patterns: + issue: "Mixing sync and async agent calls can cause issues" + solution: "Consistent async/await patterns throughout" + validation: "Test both sync and async execution paths" + + dependency_injection: + issue: "Complex dependency graphs can be hard to debug" + solution: "Keep dependencies simple and well-typed" + validation: "Unit test dependencies in isolation" + +tool_integration_gotchas: + parameter_validation: + issue: "Tools may receive unexpected parameter types" + solution: "Use strict Pydantic models for tool parameters" + validation: "Test tools with invalid inputs" + + context_management: + issue: "RunContext state can become inconsistent" + solution: "Design stateless tools when possible" + validation: "Test context isolation between runs" + + error_handling: + issue: "Tool errors can crash entire agent runs" + solution: "Implement retry mechanisms and graceful degradation" + validation: "Test error scenarios and recovery" + +testing_gotchas: + model_costs: + issue: "Real model testing can be expensive" + solution: "Use TestModel and FunctionModel for development" + validation: "Separate unit tests from expensive eval runs" + + async_testing: + issue: "Async agent testing requires special setup" + solution: "Use pytest-asyncio and proper fixtures" + validation: "Test both sync and async code paths" + + deterministic_behavior: + issue: "AI responses are inherently non-deterministic" + solution: "Focus on testing tool calls and structured outputs" + validation: "Use inline-snapshot for complex assertions" +``` + +## Implementation Blueprint + +### Technology Research Phase (COMPLETED) + +**Comprehensive PydanticAI Analysis Complete:** + +βœ… **Core Framework Analysis:** +- PydanticAI architecture, agent creation patterns, model provider integration +- Project structure conventions from official docs and examples +- Dependency injection system and type-safe design principles +- Development workflow with async/sync patterns and streaming support + +βœ… **Tool System Investigation:** +- Function tool registration patterns (@agent.tool vs @agent.tool_plain) +- Context management with RunContext and dependency injection +- Parameter validation, docstring extraction, and schema generation +- Rich return types and multi-modal content support + +βœ… **Testing Framework Analysis:** +- TestModel and FunctionModel for unit testing without API calls +- Agent.override() patterns for test isolation +- Pytest integration with async testing and fixtures +- Evaluation strategies for model performance vs unit testing + +βœ… **Security and Production Patterns:** +- API key management with environment variables and secure storage +- Input validation using Pydantic models and parameter schemas +- Rate limiting, monitoring, and Logfire integration +- Common security vulnerabilities and prevention strategies + +### Template Package Generation + +Create complete PydanticAI context engineering template based on research findings: + +```yaml +Generation Task 1 - Create PydanticAI Template Directory Structure: + CREATE complete use case directory structure: + - use-cases/pydantic-ai/ + - .claude/commands/ with PydanticAI-specific slash commands + - PRPs/templates/ with agent-focused base template + - examples/ with working agent implementations + - All subdirectories per template package requirements + +Generation Task 2 - Generate PydanticAI-Specific CLAUDE.md: + CREATE PydanticAI global rules file including: + - PydanticAI agent creation and tool integration patterns + - Model provider configuration and API key management + - Agent architecture patterns (chat, workflow, tool-enabled) + - Testing strategies with TestModel/FunctionModel + - Security best practices for AI agents and tool integration + - Common gotchas: async patterns, context management, model limits + +Generation Task 3 - Create PydanticAI PRP Commands: + GENERATE domain-specific slash commands: + - generate-pydantic-ai-prp.md with agent research patterns + - execute-pydantic-ai-prp.md with AI agent validation loops + - Include PydanticAI documentation references and research strategies + - Agent-specific success criteria and testing requirements + +Generation Task 4 - Develop PydanticAI Base PRP Template: + CREATE specialized prp_pydantic_ai_base.md template: + - Pre-filled with agent architecture patterns from research + - PydanticAI-specific success criteria and validation gates + - Official documentation references and model provider guides + - Agent testing patterns with TestModel and validation strategies + +Generation Task 5 - Create Working PydanticAI Examples: + GENERATE comprehensive example agents: + - basic_chat_agent: Simple conversation with memory + - tool_enabled_agent: Web search and calculator integration + - workflow_agent: Multi-step task processing + - structured_output_agent: Custom Pydantic models + - testing_examples: Unit tests and validation patterns + - Include configuration files and environment setup + +Generation Task 6 - Create Template Copy Script: + CREATE Python script for template deployment: + - copy_template.py with command-line interface + - Copies entire PydanticAI template structure to target location + - Handles all files: CLAUDE.md, commands, PRPs, examples, etc. + - Error handling and success feedback with next steps + +Generation Task 7 - Generate Comprehensive README: + CREATE PydanticAI-specific README.md: + - Clear description: "PydanticAI Context Engineering Template" + - Template copy script usage (prominently at top) + - PRP framework workflow for AI agent development + - Template structure with PydanticAI-specific explanations + - Quick start guide with agent creation examples + - Working examples overview and testing patterns +``` + +### PydanticAI Specialization Details + +```typescript +// Template specialization for PydanticAI +const pydantic_ai_specialization = { + agent_patterns: [ + "chat_agent_with_memory", + "tool_integrated_agent", + "workflow_processing_agent", + "structured_output_agent" + ], + + validation: [ + "agent_behavior_testing", + "tool_function_validation", + "output_schema_verification", + "model_provider_compatibility" + ], + + examples: [ + "basic_conversation_agent", + "web_search_calculator_tools", + "multi_step_workflow_processing", + "custom_pydantic_output_models", + "comprehensive_testing_suite" + ], + + gotchas: [ + "async_sync_mixing_issues", + "model_token_limits", + "dependency_injection_complexity", + "tool_error_handling_failures", + "context_state_management" + ], + + security: [ + "api_key_environment_management", + "input_validation_pydantic_models", + "prompt_injection_prevention", + "rate_limiting_implementation", + "secure_tool_parameter_handling" + ] +}; +``` + +### Integration Points + +```yaml +CONTEXT_ENGINEERING_FRAMEWORK: + - base_workflow: Inherit PRP generation/execution, adapt for AI agent development + - validation_principles: Extend with AI-specific testing (agent behavior, tool validation) + - documentation_standards: Maintain consistency while specializing for PydanticAI + +PYDANTIC_AI_INTEGRATION: + - agent_architecture: Include chat, tool-enabled, and workflow agent patterns + - model_providers: Support OpenAI, Anthropic, Gemini configuration patterns + - testing_framework: Use TestModel/FunctionModel for development validation + - production_patterns: Include security, monitoring, and deployment considerations + +TEMPLATE_STRUCTURE: + - directory_organization: Follow use case template patterns with AI-specific examples + - file_naming: generate-pydantic-ai-prp.md, prp_pydantic_ai_base.md + - content_format: Markdown with agent code examples and configuration + - command_patterns: Extend slash commands for AI agent development workflows +``` + +## Validation Loop + +### Level 1: PydanticAI Template Structure Validation + +```bash +# Verify complete PydanticAI template package structure +find use-cases/pydantic-ai -type f | sort +ls -la use-cases/pydantic-ai/.claude/commands/ +ls -la use-cases/pydantic-ai/PRPs/templates/ +ls -la use-cases/pydantic-ai/examples/ + +# Verify copy script and agent examples +test -f use-cases/pydantic-ai/copy_template.py +ls use-cases/pydantic-ai/examples/*/agent.py 2>/dev/null | wc -l # Should have agent files +python use-cases/pydantic-ai/copy_template.py --help 2>/dev/null || echo "Copy script needs help" + +# Expected: All required files including working agent examples +# If missing: Generate missing components with PydanticAI patterns +``` + +### Level 2: PydanticAI Content Quality Validation + +```bash +# Verify PydanticAI-specific content accuracy +grep -r "from pydantic_ai import Agent" use-cases/pydantic-ai/examples/ +grep -r "@agent.tool" use-cases/pydantic-ai/examples/ +grep -r "TestModel\|FunctionModel" use-cases/pydantic-ai/ + +# Check for PydanticAI patterns and avoid generic content +grep -r "TODO\|PLACEHOLDER" use-cases/pydantic-ai/ +grep -r "openai:gpt-4o\|anthropic:" use-cases/pydantic-ai/ +grep -r "RunContext\|deps_type" use-cases/pydantic-ai/ + +# Expected: Real PydanticAI code, no placeholders, agent patterns present +# If issues: Add proper PydanticAI-specific patterns and examples +``` + +### Level 3: PydanticAI Functional Validation + +```bash +# Test PydanticAI template functionality +cd use-cases/pydantic-ai + +# Test PRP generation with agent focus +/generate-pydantic-ai-prp INITIAL.md +ls PRPs/*.md | grep -v templates | head -1 # Should generate agent PRP + +# Verify agent examples can be parsed (syntax check) +python -m py_compile examples/basic_chat_agent/agent.py 2>/dev/null && echo "Basic agent syntax OK" +python -m py_compile examples/tool_enabled_agent/agent.py 2>/dev/null && echo "Tool agent syntax OK" + +# Expected: PRP generation works, agent examples have valid syntax +# If failing: Debug PydanticAI command patterns and fix agent code +``` + +### Level 4: PydanticAI Integration Testing + +```bash +# Verify PydanticAI specialization maintains base framework compatibility +diff -r ../../.claude/commands/ .claude/commands/ | head -10 +grep -r "Context is King" . | wc -l # Should inherit base principles +grep -r "pydantic.ai.dev\|PydanticAI" . | wc -l # Should have specializations + +# Test agent examples have proper dependencies +grep -r "pydantic_ai" examples/ | wc -l # Should import PydanticAI +grep -r "pytest" examples/testing_examples/ | wc -l # Should have tests + +# Expected: Proper specialization, working agent patterns, testing included +# If issues: Adjust to maintain compatibility while adding PydanticAI features +``` + +## Final Validation Checklist + +### PydanticAI Template Package Completeness + +- [ ] Complete directory structure: `tree use-cases/pydantic-ai` +- [ ] PydanticAI-specific files: CLAUDE.md with agent patterns, specialized commands +- [ ] Copy script present: `copy_template.py` with proper PydanticAI functionality +- [ ] README comprehensive: Includes agent development workflow and copy instructions +- [ ] Agent examples working: All examples use real PydanticAI code patterns +- [ ] Testing patterns included: TestModel/FunctionModel examples and validation +- [ ] Documentation complete: PydanticAI-specific patterns and gotchas documented + +### Quality and Usability for PydanticAI + +- [ ] No placeholder content: `grep -r "TODO\|PLACEHOLDER"` returns empty +- [ ] PydanticAI specialization: Agent patterns, tools, testing properly documented +- [ ] Validation loops work: All commands executable with agent-specific functionality +- [ ] Framework integration: Works with base context engineering for AI development +- [ ] Ready for AI development: Developers can immediately create PydanticAI agents + +### PydanticAI Framework Integration + +- [ ] Inherits base principles: Context engineering workflow preserved for AI agents +- [ ] Proper AI specialization: PydanticAI patterns, security, testing included +- [ ] Command compatibility: Slash commands work for agent development workflows +- [ ] Documentation consistency: Follows patterns while specializing for AI development +- [ ] Maintainable structure: Easy to update as PydanticAI framework evolves + +--- + +## Anti-Patterns to Avoid + +### PydanticAI Template Generation + +- ❌ Don't create generic AI templates - research PydanticAI specifics thoroughly +- ❌ Don't skip agent architecture research - understand tools, memory, validation +- ❌ Don't use placeholder agent code - include real, working PydanticAI examples +- ❌ Don't ignore testing patterns - TestModel/FunctionModel are critical for AI + +### PydanticAI Content Quality + +- ❌ Don't assume AI patterns - document PydanticAI-specific gotchas explicitly +- ❌ Don't skip security research - API keys, input validation, prompt injection critical +- ❌ Don't ignore model providers - include OpenAI, Anthropic, Gemini patterns +- ❌ Don't forget async patterns - PydanticAI has specific async/sync considerations + +### PydanticAI Framework Integration + +- ❌ Don't break context engineering - maintain PRP workflow for AI development +- ❌ Don't duplicate base functionality - extend and specialize appropriately +- ❌ Don't ignore AI-specific validation - agent behavior testing is unique requirement +- ❌ Don't skip real examples - include working agents with tools and validation + +**CONFIDENCE SCORE: 9/10** - Comprehensive PydanticAI research completed, framework patterns understood, ready to generate specialized context engineering template for AI agent development. \ No newline at end of file diff --git a/use-cases/template-generator/PRPs/templates/prp_template_base.md b/use-cases/template-generator/PRPs/templates/prp_template_base.md new file mode 100644 index 0000000..cbcf7fe --- /dev/null +++ b/use-cases/template-generator/PRPs/templates/prp_template_base.md @@ -0,0 +1,525 @@ +--- +name: "Template Generator PRP Base" +description: "Meta-template for generating context engineering templates for specific technology domains and use cases" +--- + +## Purpose + +Template optimized for AI agents to generate complete context engineering template packages for specific technology domains (AI frameworks, frontend stacks, backend technologies, etc.) with comprehensive domain specialization and validation. + +## Core Principles + +1. **Meta-Context Engineering**: Apply context engineering principles to generate domain-specific templates +2. **Technology Specialization**: Deep integration with target framework patterns and conventions +3. **Complete Package Generation**: Create entire template ecosystems, not just individual files +4. **Validation-Driven**: Include comprehensive domain-appropriate testing and validation loops +5. **Usability First**: Generate templates that are immediately usable by developers + +--- + +## Goal + +Generate a complete context engineering template package for **[TARGET_TECHNOLOGY]** that includes: + +- Domain-specific CLAUDE.md implementation guide +- Specialized PRP generation and execution commands +- Technology-appropriate base PRP template +- Comprehensive examples and documentation +- Domain-specific validation loops and success criteria + +## Why + +- **Developer Acceleration**: Enable rapid application of context engineering to any technology +- **Pattern Consistency**: Maintain context engineering principles across all domains +- **Quality Assurance**: Ensure comprehensive validation and testing for each technology +- **Knowledge Capture**: Document best practices and patterns for specific technologies +- **Scalable Framework**: Create reusable templates that evolve with technology changes + +## What + +### Template Package Components + +**Complete Directory Structure:** +``` +use-cases/{technology-name}/ +β”œβ”€β”€ CLAUDE.md # Domain implementation guide +β”œβ”€β”€ .claude/commands/ +β”‚ β”œβ”€β”€ generate-{technology}-prp.md # Domain PRP generation +β”‚ └── execute-{technology}-prp.md # Domain PRP execution +β”œβ”€β”€ PRPs/ +β”‚ β”œβ”€β”€ templates/ +β”‚ β”‚ └── prp_{technology}_base.md # Domain base PRP template +β”‚ β”œβ”€β”€ ai_docs/ # Domain documentation (optional) +β”‚ └── INITIAL.md # Example feature request +β”œβ”€β”€ examples/ # Domain code examples +β”œβ”€β”€ copy_template.py # Template deployment script +└── README.md # Comprehensive usage guide +``` + +**Technology Integration:** +- Framework-specific tooling and commands +- Architecture patterns and conventions +- Development workflow integration +- Testing and validation approaches +- Security and performance considerations + +**Context Engineering Adaptation:** +- Domain-specific research processes +- Technology-appropriate validation loops +- Framework-specialized implementation blueprints +- Integration with base context engineering principles + +### Success Criteria + +- [ ] Complete template package structure generated +- [ ] All required files present and properly formatted +- [ ] Domain-specific content accurately represents technology patterns +- [ ] Context engineering principles properly adapted to the technology +- [ ] Validation loops appropriate and executable for the framework +- [ ] Template immediately usable for creating projects in the domain +- [ ] Integration with base context engineering framework maintained +- [ ] Comprehensive documentation and examples included + +## All Needed Context + +### Documentation & References (MUST READ) + +```yaml +# CONTEXT ENGINEERING FOUNDATION - Understand the base framework +- file: ../../../README.md + why: Core context engineering principles and workflow to adapt + +- file: ../../../.claude/commands/generate-prp.md + why: Base PRP generation patterns to specialize for domain + +- file: ../../../.claude/commands/execute-prp.md + why: Base PRP execution patterns to adapt for technology + +- file: ../../../PRPs/templates/prp_base.md + why: Base PRP template structure to specialize for domain + +# MCP SERVER EXAMPLE - Reference implementation of domain specialization +- file: ../mcp-server/CLAUDE.md + why: Example of domain-specific implementation guide patterns + +- file: ../mcp-server/.claude/commands/prp-mcp-create.md + why: Example of specialized PRP generation command + +- file: ../mcp-server/PRPs/templates/prp_mcp_base.md + why: Example of domain-specialized base PRP template + +# TARGET TECHNOLOGY RESEARCH - Add domain-specific documentation +- url: [OFFICIAL_FRAMEWORK_DOCS] + why: Core framework concepts, APIs, and architectural patterns + +- url: [BEST_PRACTICES_GUIDE] + why: Established patterns and conventions for the technology + +- url: [SECURITY_CONSIDERATIONS] + why: Security best practices and common vulnerabilities + +- url: [TESTING_FRAMEWORKS] + why: Testing approaches and validation patterns for the technology + +- url: [DEPLOYMENT_PATTERNS] + why: Production deployment and monitoring considerations +``` + +### Current Context Engineering Structure + +```bash +# Base framework structure to extend +context-engineering-intro/ +β”œβ”€β”€ README.md # Core principles to adapt +β”œβ”€β”€ .claude/commands/ # Base commands to specialize +β”œβ”€β”€ PRPs/templates/prp_base.md # Base template to extend +β”œβ”€β”€ CLAUDE.md # Base rules to inherit +└── use-cases/ + β”œβ”€β”€ mcp-server/ # Reference specialization example + └── template-generator/ # This meta-template system +``` + +### Target Technology Analysis Requirements + +```typescript +// Research areas for technology specialization +interface TechnologyAnalysis { + // Core framework patterns + architecture: { + project_structure: string[]; + configuration_files: string[]; + dependency_management: string; + module_organization: string[]; + }; + + // Development workflow + development: { + package_manager: string; + dev_server_commands: string[]; + build_process: string[]; + testing_frameworks: string[]; + }; + + // Best practices + patterns: { + code_organization: string[]; + state_management: string[]; + error_handling: string[]; + performance_optimization: string[]; + }; + + // Integration points + ecosystem: { + common_libraries: string[]; + deployment_platforms: string[]; + monitoring_tools: string[]; + CI_CD_patterns: string[]; + }; +} +``` + +### Known Template Generation Patterns + +```typescript +// CRITICAL: Template generation must follow these patterns + +// 1. ALWAYS inherit from base context engineering principles +const basePatterns = { + prp_workflow: "INITIAL.md β†’ generate-prp β†’ execute-prp", + validation_loops: "syntax β†’ unit β†’ integration β†’ deployment", + context_richness: "documentation + examples + patterns + gotchas" +}; + +// 2. ALWAYS specialize for the target technology +const specialization = { + tooling: "Replace generic commands with framework-specific ones", + patterns: "Include framework architectural conventions", + validation: "Use technology-appropriate testing and linting", + examples: "Provide real, working code examples for the domain" +}; + +// 3. ALWAYS maintain usability and completeness +const quality_gates = { + immediate_usability: "Template works out of the box", + comprehensive_docs: "All patterns and gotchas documented", + working_examples: "Examples compile and run successfully", + validation_loops: "All validation commands are executable" +}; + +// 4. Common pitfalls to avoid +const anti_patterns = { + generic_content: "Don't use placeholder text - research actual patterns", + incomplete_research: "Don't skip technology-specific documentation", + broken_examples: "Don't include non-working code examples", + missing_validation: "Don't skip domain-appropriate testing patterns" +}; +``` + +## Implementation Blueprint + +### Technology Research Phase + +**CRITICAL: Web search extensively before any template generation. This is essential for success.** + +Conduct comprehensive analysis of the target technology using web research: + +```yaml +Research Task 1 - Core Framework Analysis (WEB SEARCH REQUIRED): + WEB SEARCH and STUDY official documentation thoroughly: + - Framework architecture and design patterns + - Project structure conventions and best practices + - Configuration file patterns and management approaches + - Package/dependency management for the technology + - Getting started guides and setup procedures + +Research Task 2 - Development Workflow Analysis (WEB SEARCH REQUIRED): + WEB SEARCH and ANALYZE development patterns: + - Local development setup and tooling + - Build processes and compilation steps + - Testing frameworks commonly used with this technology + - Debugging tools and development environments + - CLI commands and package management workflows + +Research Task 3 - Best Practices Investigation (WEB SEARCH REQUIRED): + WEB SEARCH and RESEARCH established patterns: + - Code organization and file structure conventions + - Security best practices specific to this technology + - Common gotchas, pitfalls, and edge cases + - Error handling patterns and strategies + - Performance considerations and optimization techniques + +Research Task 4 - Template Package Structure Planning: + PLAN how to create context engineering template for this technology: + - How to adapt PRP framework for this specific technology + - What domain-specific CLAUDE.md rules are needed + - What validation loops are appropriate for this framework + - What examples and documentation should be included +``` + +### Template Package Generation + +Create complete context engineering template package based on web research findings: + +```yaml +Generation Task 1 - Create Template Directory Structure: + CREATE complete use case directory structure: + - use-cases/{technology-name}/ + - .claude/commands/ subdirectory + - PRPs/templates/ subdirectory + - examples/ subdirectory + - All other required subdirectories per template package requirements + +Generation Task 2 - Generate Domain-Specific CLAUDE.md: + CREATE technology-specific global rules file: + - Technology-specific tooling and package management commands + - Framework architectural patterns and conventions from web research + - Development workflow procedures specific to this technology + - Security and best practices discovered through research + - Common gotchas and integration points found in documentation + +Generation Task 3 - Create Specialized Template PRP Commands: + GENERATE domain-specific slash commands: + - generate-{technology}-prp.md with technology research patterns + - execute-{technology}-prp.md with framework validation loops + - Commands should reference technology-specific patterns from research + - Include web search strategies specific to this technology domain + +Generation Task 4 - Develop Domain-Specific Base PRP Template: + CREATE specialized prp_{technology}_base.md template: + - Pre-filled with technology context from web research + - Technology-specific success criteria and validation gates + - Framework documentation references found through research + - Domain-appropriate implementation patterns and validation loops + +Generation Task 5 - Create Examples and INITIAL.md Template: + GENERATE comprehensive template package content: + - INITIAL.md example showing how to request features for this technology + - Working code examples relevant to the technology (from research) + - Configuration file templates and patterns + +Generation Task 6 - Create Template Copy Script: + CREATE Python script for template deployment: + - copy_template.py script that accepts target directory argument + - Copies entire template directory structure to specified location + - Includes all files: CLAUDE.md, commands, PRPs, examples, etc. + - Handles directory creation and file copying with error handling + - Simple command-line interface for easy usage + +Generation Task 7 - Generate Comprehensive README: + CREATE comprehensive but concise README.md: + - Clear description of what this template is for and its purpose + - Explanation of the PRP framework workflow (3-step process) + - Template copy script usage instructions (prominently placed near top) + - Quick start guide with concrete examples + - Template structure overview showing all generated files + - Usage examples specific to this technology domain +``` + +### Implementation Details for Copy Script and README + +**Copy Script (copy_template.py) Requirements:** +```python +# Essential copy script functionality: +# 1. Accept target directory as command line argument +# 2. Copy entire template directory structure to target location +# 3. Include ALL files: CLAUDE.md, .claude/, PRPs/, examples/, README.md +# 4. Handle directory creation and error handling +# 5. Provide clear success feedback with next steps +# 6. Simple usage: python copy_template.py /path/to/target +``` + +**README Structure Requirements:** +```markdown +# Must include these sections in this order: +# 1. Title and brief description of template purpose +# 2. πŸš€ Quick Start - Copy Template First (prominently at top) +# 3. πŸ“‹ PRP Framework Workflow (3-step process explanation) +# 4. πŸ“ Template Structure (directory tree with explanations) +# 5. 🎯 What You Can Build (technology-specific examples) +# 6. πŸ“š Key Features (framework capabilities) +# 7. πŸ” Examples Included (working examples provided) +# 8. πŸ“– Documentation References (research sources) +# 9. 🚫 Common Gotchas (technology-specific pitfalls) + +# Copy script usage must be prominently featured near the top +# PRP workflow must clearly show the 3 steps with actual commands +# Everything should be technology-specific, not generic +``` + +### Domain Specialization Details + +```typescript +// Template specialization patterns for specific domains + +// For AI/ML Frameworks (Pydantic AI, CrewAI, etc.) +const ai_specialization = { + patterns: ["agent_architecture", "tool_integration", "model_configuration"], + validation: ["model_response_testing", "agent_behavior_validation"], + examples: ["basic_agent", "multi_agent_system", "tool_integration"], + gotchas: ["token_limits", "model_compatibility", "async_patterns"] +}; + +// For Frontend Frameworks (React, Vue, Svelte, etc.) +const frontend_specialization = { + patterns: ["component_architecture", "state_management", "routing"], + validation: ["component_testing", "e2e_testing", "accessibility"], + examples: ["basic_app", "state_integration", "api_consumption"], + gotchas: ["bundle_size", "ssr_considerations", "performance"] +}; + +// For Backend Frameworks (FastAPI, Express, Django, etc.) +const backend_specialization = { + patterns: ["api_design", "database_integration", "authentication"], + validation: ["api_testing", "database_testing", "security_testing"], + examples: ["rest_api", "auth_system", "database_models"], + gotchas: ["security_vulnerabilities", "performance_bottlenecks", "scalability"] +}; + +// For Database/Data Frameworks (SQLModel, Prisma, etc.) +const data_specialization = { + patterns: ["schema_design", "migration_management", "query_optimization"], + validation: ["schema_testing", "migration_testing", "query_performance"], + examples: ["basic_models", "relationships", "complex_queries"], + gotchas: ["migration_conflicts", "n+1_queries", "index_optimization"] +}; +``` + +### Integration Points + +```yaml +CONTEXT_ENGINEERING_FRAMEWORK: + - base_workflow: Inherit core PRP generation and execution patterns from base framework + - validation_principles: Extend base validation with domain-specific checks for the technology + - documentation_standards: Maintain consistency with base context engineering documentation patterns + +TECHNOLOGY_INTEGRATION: + - package_management: Include framework-specific package managers and tooling + - development_tools: Include technology-specific development and testing tools + - framework_patterns: Use technology-appropriate architectural and code patterns + - validation_approaches: Include framework-specific testing and validation methods + +TEMPLATE_STRUCTURE: + - directory_structure: Follow established use case template patterns from base framework + - file_naming: Maintain consistent naming conventions (generate-{tech}-prp.md, etc.) + - content_format: Use established markdown and documentation formats + - command_patterns: Extend base slash command functionality for the specific technology +``` + +## Validation Loop + +### Level 1: Template Structure Validation + +```bash +# CRITICAL: Verify complete template package structure +find use-cases/{technology-name} -type f | sort +ls -la use-cases/{technology-name}/.claude/commands/ +ls -la use-cases/{technology-name}/PRPs/templates/ + +# Verify copy script exists and is functional +test -f use-cases/{technology-name}/copy_template.py +python use-cases/{technology-name}/copy_template.py --help 2>/dev/null || echo "Copy script needs help option" + +# Expected: All required files present including copy_template.py +# If missing: Generate missing files following established patterns +``` + +### Level 2: Content Quality Validation + +```bash +# Verify domain-specific content accuracy +grep -r "TODO\|PLACEHOLDER\|{domain}" use-cases/{technology-name}/ +grep -r "{technology}" use-cases/{technology-name}/ | wc -l + +# Check for technology-specific patterns +grep -r "framework-specific-pattern" use-cases/{technology-name}/ +grep -r "validation" use-cases/{technology-name}/.claude/commands/ + +# Expected: No placeholder content, technology patterns present +# If issues: Research and add proper domain-specific content +``` + +### Level 3: Functional Validation + +```bash +# Test template functionality +cd use-cases/{technology-name} + +# Test PRP generation command +/generate-prp INITIAL.md +ls PRPs/*.md | grep -v templates + +# Test template completeness +grep -r "Context is King" . | wc -l # Should inherit principles +grep -r "{technology-specific}" . | wc -l # Should have specializations + +# Expected: PRP generation works, content is specialized +# If failing: Debug command patterns and template structure +``` + +### Level 4: Integration Testing + +```bash +# Verify integration with base context engineering framework +diff -r ../../.claude/commands/ .claude/commands/ | head -20 +diff ../../CLAUDE.md CLAUDE.md | head -20 + +# Test template produces working results +cd examples/ +# Run any example validation commands specific to the technology + +# Expected: Proper specialization without breaking base patterns +# If issues: Adjust specialization to maintain compatibility +``` + +## Final Validation Checklist + +### Template Package Completeness + +- [ ] Complete directory structure: `tree use-cases/{technology-name}` +- [ ] All required files present: CLAUDE.md, commands, base PRP, examples +- [ ] Copy script present: `copy_template.py` with proper functionality +- [ ] README comprehensive: Includes copy script instructions and PRP workflow +- [ ] Domain-specific content: Technology patterns accurately represented +- [ ] Working examples: All examples compile/run successfully +- [ ] Documentation complete: README and usage instructions clear + +### Quality and Usability + +- [ ] No placeholder content: `grep -r "TODO\|PLACEHOLDER"` +- [ ] Technology specialization: Framework patterns properly documented +- [ ] Validation loops work: All commands executable and functional +- [ ] Integration maintained: Works with base context engineering framework +- [ ] Ready for use: Developer can immediately start using template + +### Framework Integration + +- [ ] Inherits base principles: Context engineering workflow preserved +- [ ] Proper specialization: Technology-specific patterns included +- [ ] Command compatibility: Slash commands work as expected +- [ ] Documentation consistency: Follows established documentation patterns +- [ ] Maintainable structure: Easy to update as technology evolves + +--- + +## Anti-Patterns to Avoid + +### Template Generation + +- ❌ Don't create generic templates - always research and specialize deeply +- ❌ Don't skip comprehensive technology research - understand frameworks thoroughly +- ❌ Don't use placeholder content - always include real, researched information +- ❌ Don't ignore validation loops - include comprehensive testing for the technology + +### Content Quality + +- ❌ Don't assume knowledge - document everything explicitly for the domain +- ❌ Don't skip edge cases - include common gotchas and error handling +- ❌ Don't ignore security - always include security considerations for the technology +- ❌ Don't forget maintenance - ensure templates can evolve with technology changes + +### Framework Integration + +- ❌ Don't break base patterns - maintain compatibility with context engineering principles +- ❌ Don't duplicate effort - reuse and extend base framework components +- ❌ Don't ignore consistency - follow established naming and structure conventions +- ❌ Don't skip validation - ensure templates actually work before completion \ No newline at end of file diff --git a/use-cases/template-generator/README.md b/use-cases/template-generator/README.md new file mode 100644 index 0000000..4b47fd7 --- /dev/null +++ b/use-cases/template-generator/README.md @@ -0,0 +1,184 @@ +# Template Generator - Meta-Framework for Context Engineering + +This template generator creates complete context engineering template packages for any technology domain. It's a meta-template that generates specialized templates for frameworks like Pydantic AI, Supabase, CrewAI, etc. + +## πŸš€ Quick Start + +```bash +# 1. Define your template requirements in detail +# Edit PRPs/INITIAL.md with specific technology and requirements + +# 2. Generate comprehensive template PRP +/generate-template-prp PRPs/INITIAL.md + +# 3. Execute the PRP to create complete template package +/execute-template-prp PRPs/template-{technology-name}.md +``` + +## πŸ“š What This Creates + +This meta-template generates complete context engineering template packages with: + +### Generated Template Structure +``` +use-cases/{technology-name}/ +β”œβ”€β”€ CLAUDE.md # Technology-specific global rules +β”œβ”€β”€ .claude/commands/ +β”‚ β”œβ”€β”€ generate-{tech}-prp.md # Domain PRP generation +β”‚ └── execute-{tech}-prp.md # Domain PRP execution +β”œβ”€β”€ PRPs/ +β”‚ β”œβ”€β”€ templates/ +β”‚ β”‚ └── prp_{tech}_base.md # Technology-specific base PRP +β”‚ β”œβ”€β”€ ai_docs/ # Domain documentation +β”‚ └── INITIAL.md # Example feature request +β”œβ”€β”€ examples/ # Technology-specific examples +└── README.md # Usage guide +``` + +### Template Features + +**Technology Specialization:** +- Framework-specific global rules and patterns +- Technology-appropriate validation loops +- Domain-specific research methodologies +- Framework-specialized documentation references + +**Web Research Integration:** +- Extensive web search requirements for technology research +- Official documentation gathering and analysis +- Real-world pattern identification and extraction +- Best practices and gotcha documentation + +**Context Engineering Adaptation:** +- PRP framework adapted for specific technologies +- Domain-appropriate success criteria +- Technology-specific implementation blueprints +- Framework-specialized validation gates + +## πŸ” Research-Driven Approach + +This meta-template emphasizes **extensive web research** as the foundation for creating high-quality templates: + +1. **Technology Deep Dive** - Comprehensive research of official docs, patterns, and best practices +2. **Pattern Extraction** - Identification of real-world implementation patterns +3. **Context Integration** - Adaptation of context engineering principles for the technology +4. **Validation Design** - Creation of technology-appropriate testing and validation loops + +## πŸ“‹ Usage Process + +### 1. Define Requirements (PRPs/INITIAL.md) + +Be extremely specific about: +- **Target technology/framework** +- **Core features to support** +- **Examples to include** +- **Documentation to research** +- **Development patterns** +- **Security considerations** +- **Common gotchas** +- **Validation requirements** + +### 2. Generate Template PRP + +```bash +/generate-template-prp PRPs/INITIAL.md +``` + +This will: +- Conduct extensive web research on your specified technology +- Analyze official documentation and best practices +- Create comprehensive implementation blueprint +- Design technology-specific validation loops + +### 3. Execute Template Generation + +```bash +/execute-template-prp PRPs/template-{technology-name}.md +``` + +This will: +- Create complete template package directory structure +- Generate technology-specific CLAUDE.md with global rules +- Create specialized PRP commands for the technology +- Develop domain-specific base PRP template +- Include working examples and comprehensive documentation + +## 🎯 Template Quality Standards + +Generated templates include: + +**Comprehensive Research Foundation:** +- Extensive web research on target technology +- Official documentation analysis and integration +- Real-world pattern identification +- Best practices and gotcha documentation + +**Technology Specialization:** +- Framework-specific patterns and conventions +- Domain-appropriate architectural guidance +- Technology-specific validation and testing approaches +- Integration patterns for common use cases + +**Context Engineering Integration:** +- Proper adaptation of PRP framework principles +- Technology-appropriate success criteria +- Domain-specific research methodologies +- Specialized validation loops and quality gates + +## πŸ”§ Key Features + +### Web Research Emphasis +- **Web search is your best friend** throughout the process +- Comprehensive technology documentation analysis +- Real-world implementation pattern identification +- Community best practices research and integration + +### Template Package Completeness +- Complete directory structure with all required files +- Technology-specific global rules and patterns +- Specialized PRP generation and execution commands +- Domain-appropriate base PRP templates +- Working examples and comprehensive documentation + +### Quality Validation +- Multiple validation levels for template structure and content +- Technology-specific testing and validation approaches +- Integration testing with base context engineering framework +- Usability validation for immediate developer productivity + +## πŸ“š Examples of Templates You Can Generate + +- **Pydantic AI Agents** - AI agent development with tool integration +- **Supabase Applications** - Full-stack apps with real-time features +- **CrewAI Multi-Agents** - Complex multi-agent system development +- **FastAPI Services** - High-performance API development +- **React Applications** - Modern frontend development patterns +- **Any Technology** - The system adapts to any framework or library + +## 🚫 Anti-Patterns Avoided + +- ❌ Generic templates without technology specialization +- ❌ Shallow research leading to incomplete patterns +- ❌ Missing validation loops and quality gates +- ❌ Ignoring framework-specific best practices +- ❌ Incomplete documentation and examples + +## πŸ”„ Continuous Improvement + +Templates generated with this system: +- Are based on comprehensive, current research +- Include real-world patterns and best practices +- Provide immediate developer productivity +- Can be updated as technologies evolve +- Maintain consistency with context engineering principles + +## πŸŽ“ Philosophy + +This meta-template embodies the principle that **context engineering can be applied to any technology domain** through: + +1. **Deep Research** - Understanding the technology thoroughly +2. **Pattern Extraction** - Identifying reusable implementation patterns +3. **Context Integration** - Adapting context engineering principles +4. **Quality Validation** - Ensuring templates work immediately and effectively + +The result is a systematic approach to creating high-quality, immediately usable context engineering templates for any technology domain. \ No newline at end of file