mirror of
https://github.com/thecyberlearn/quantum-ai-v2.git
synced 2026-08-18 14:12:59 +00:00
Enhance documentation with error-free agent creation guidance
Based on successful 5 Whys Analyzer debugging experience, update all documentation to prevent common agent creation errors and establish reliable patterns for future development. ## Documentation Updates ### Enhanced AGENT_SETUP_CHECKLIST.md - Add 5 Whys success patterns overview - Include 10 detailed debugging solutions with root cause analysis - Document delayed wallet deduction pattern (critical for reliability) - Add session management guidance for complex agents - Include 5 Whys bonus validations and testing procedures ### Updated MANUAL_AGENT_CREATION_GUIDE.md - Add comprehensive 5 Whys proven implementation patterns section - Document session-based models with UUID tracking - Include delayed wallet deduction code examples and best practices - Add dual-mode processing patterns (free chat + paid reports) - Enhance with comprehensive error handling patterns ### Created ERROR_PREVENTION_GUIDE.md (New) - Complete error prevention guide covering 10 major error categories - Root cause analysis and proven solutions for each error type - Template loading, URL routing, migration conflicts, wallet integration - Session management, status tracking, error handling, performance issues - Prevention strategies and validation scripts for each category ### Enhanced DEVELOPMENT_GUIDE.md - Add complete agent testing procedures based on 5 Whys experience - Include 6 different testing categories with automated scripts - Pre-development validation, lifecycle testing, wallet integration tests - Template/URL testing, error handling validation, performance testing - Production readiness checklist and debugging workflow ## Key Improvements - **Delayed Wallet Deduction**: Only charge after successful processing - **Session Management**: UUID-based architecture with persistent state - **Error Prevention**: Comprehensive solutions for common issues - **Testing Framework**: Automated validation for reliable development - **Template Organization**: Proper directory structure and URL namespacing 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
7da309e018
commit
aacf50d816
@ -1,12 +1,25 @@
|
||||
# Agent Setup Checklist
|
||||
# Agent Setup Checklist - Error-Free Creation Guide
|
||||
## Steps to Complete After Running `create_agent` Command
|
||||
|
||||
This checklist covers the **6 essential steps** needed after running the automated `create_agent` command to make your agent fully functional.
|
||||
This checklist covers the **6 essential steps** needed after running the automated `create_agent` command to make your agent fully functional. **Updated with debugging insights from the successful 5 Whys Agent implementation.**
|
||||
|
||||
**✅ The automated system now generates all code files including models, views, processors, and admin interface!**
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **Success Patterns from 5 Whys Agent**
|
||||
|
||||
The 5 Whys Analyzer represents the most robust agent implementation with these key features:
|
||||
- **Dual-mode processing**: Free chat interactions + paid report generation
|
||||
- **Session-based architecture**: UUID tracking with persistent chat history
|
||||
- **Delayed wallet deduction**: Only charge after successful processing
|
||||
- **Comprehensive error handling**: Graceful failure recovery
|
||||
- **Smart status tracking**: Proper request lifecycle management
|
||||
|
||||
**Apply these patterns to achieve error-free agent creation.**
|
||||
|
||||
---
|
||||
|
||||
## Example Command
|
||||
```bash
|
||||
python manage.py create_agent "PDF Analyzer" "pdf-analyzer" api \
|
||||
@ -227,22 +240,29 @@ python manage.py shell -c "from django.urls import reverse; print('Agent URL:',
|
||||
|
||||
---
|
||||
|
||||
## 🐛 **Common Issues & Quick Fixes**
|
||||
## 🐛 **Common Issues & Quick Fixes** *(Learned from 5 Whys Debugging)*
|
||||
|
||||
### **Issue 1: "No module named 'agent_pdf_analyzer'"**
|
||||
**Root Cause:** App not added to Django settings
|
||||
**Fix:** Make sure you added the app to `INSTALLED_APPS` in settings.py
|
||||
**Prevention:** Use the automated validation script (coming soon)
|
||||
|
||||
### **Issue 2: "TemplateDoesNotExist: detail.html"**
|
||||
**Root Cause:** Template in wrong location or server cache
|
||||
**Fix:** Ensure template is in correct location within the agent app:
|
||||
```bash
|
||||
# Template should be at:
|
||||
agent_[name]/templates/agent_[name]/detail.html
|
||||
|
||||
# NOT just:
|
||||
agent_[name]/templates/detail.html
|
||||
|
||||
# NOT in the global templates folder
|
||||
# Restart Django server after moving templates
|
||||
# CRITICAL: Restart Django server after moving templates
|
||||
```
|
||||
**5 Whys Learning:** Template organization is crucial for reliability
|
||||
|
||||
### **Issue 3: "NoReverseMatch: Reverse for 'wallet' not found"**
|
||||
**Root Cause:** Missing URL namespaces in templates
|
||||
**Fix:** Check template URLs use proper namespaces:
|
||||
```html
|
||||
<!-- Wrong -->
|
||||
@ -251,42 +271,100 @@ agent_[name]/templates/detail.html
|
||||
<!-- Correct -->
|
||||
{% url 'core:wallet' %}
|
||||
```
|
||||
**5 Whys Learning:** Always use namespaced URLs for reliability
|
||||
|
||||
### **Issue 4: "Agent not found" in marketplace**
|
||||
**Root Cause:** BaseAgent entry missing or wrong slug
|
||||
**Fix:** Verify BaseAgent was created with correct slug:
|
||||
```bash
|
||||
python manage.py shell -c "from agent_base.models import BaseAgent; print([a.slug for a in BaseAgent.objects.all()])"
|
||||
```
|
||||
|
||||
### **Issue 4: Agent page shows 404**
|
||||
### **Issue 5: Agent page shows 404**
|
||||
**Root Cause:** URL registration order is wrong
|
||||
**Fix:** Check URL registration order in `netcop_hub/urls.py` - agent URLs must come before core URLs.
|
||||
**5 Whys Learning:** URL order matters for Django routing
|
||||
|
||||
### **Issue 5: API key errors**
|
||||
### **Issue 6: API key errors**
|
||||
**Root Cause:** Environment variable name mismatch
|
||||
**Fix:** Verify environment variable name matches processor:
|
||||
```python
|
||||
# In processor.py
|
||||
api_key_env = 'DOCPARSER_API_KEY' # Must match .env file
|
||||
```
|
||||
|
||||
---
|
||||
### **Issue 7: Wallet deduction errors (5 Whys Pattern)**
|
||||
**Root Cause:** Deducting balance before processing success
|
||||
**Fix:** Follow the 5 Whys pattern - only deduct after successful processing:
|
||||
```python
|
||||
# ❌ Wrong - deduct before processing
|
||||
user.deduct_balance(cost, description, agent_slug)
|
||||
response = process_request()
|
||||
|
||||
## 📝 **Quick Checklist Summary**
|
||||
# ✅ Correct - deduct after success (5 Whys pattern)
|
||||
response = process_request()
|
||||
if response.success:
|
||||
user.deduct_balance(cost, description, agent_slug)
|
||||
```
|
||||
|
||||
After running `create_agent`, complete these 6 steps:
|
||||
### **Issue 8: Migration conflicts**
|
||||
**Root Cause:** Django migrations out of sync with database
|
||||
**Fix:** Create empty migration to sync state:
|
||||
```bash
|
||||
# Create manual sync migration
|
||||
python manage.py makemigrations [agent_name] --empty
|
||||
# Edit migration to match your needs
|
||||
python manage.py migrate
|
||||
```
|
||||
**5 Whys Learning:** Migration conflicts are common - be prepared to sync manually
|
||||
|
||||
- [ ] **Settings:** Add agent to `INSTALLED_APPS`
|
||||
- [ ] **URLs:** Add URL pattern to `netcop_hub/urls.py`
|
||||
- [ ] **Database:** Run `makemigrations` and `migrate`
|
||||
- [ ] **Marketplace:** Create `BaseAgent` entry (done automatically)
|
||||
- [ ] **Environment:** Add API keys to `.env`
|
||||
- [ ] **Template:** Create and customize `detail.html` template
|
||||
- [ ] **Test:** Verify agent works end-to-end
|
||||
### **Issue 9: Session management errors (Advanced Agents)**
|
||||
**Root Cause:** No persistent session tracking
|
||||
**Fix:** Implement session-based architecture like 5 Whys:
|
||||
```python
|
||||
# Add to your models
|
||||
session_id = models.CharField(max_length=100, default=uuid.uuid4, db_index=True)
|
||||
chat_messages = models.JSONField(default=list)
|
||||
```
|
||||
|
||||
**Total time:** ~10-15 minutes
|
||||
### **Issue 10: Status tracking problems**
|
||||
**Root Cause:** Inconsistent request status management
|
||||
**Fix:** Use proper status lifecycle like 5 Whys:
|
||||
```python
|
||||
# Status flow: pending → processing → completed/failed
|
||||
request_obj.status = 'processing'
|
||||
request_obj.save()
|
||||
# ... do processing ...
|
||||
request_obj.status = 'completed' if success else 'failed'
|
||||
request_obj.save()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **You're Done!**
|
||||
## 📝 **Quick Checklist Summary** *(Error-Free Process)*
|
||||
|
||||
After running `create_agent`, complete these **7 critical steps** (updated with 5 Whys learnings):
|
||||
|
||||
- [ ] **Settings:** Add agent to `INSTALLED_APPS` in `netcop_hub/settings.py`
|
||||
- [ ] **URLs:** Add URL pattern to `netcop_hub/urls.py` **BEFORE core URLs**
|
||||
- [ ] **Database:** Run `makemigrations` and `migrate` (watch for conflicts)
|
||||
- [ ] **Marketplace:** Verify `BaseAgent` entry created correctly
|
||||
- [ ] **Environment:** Add API keys/webhook URLs to `.env`
|
||||
- [ ] **Template:** Create `agent_[name]/templates/agent_[name]/detail.html`
|
||||
- [ ] **Validation:** Run complete test flow including wallet integration
|
||||
|
||||
**5 Whys Bonus Validations:**
|
||||
- [ ] **Template Loading:** Restart Django server after template creation
|
||||
- [ ] **URL Namespaces:** Use `{% url 'core:wallet' %}` not `{% url 'wallet' %}`
|
||||
- [ ] **Error Handling:** Implement try-catch blocks in processor
|
||||
- [ ] **Wallet Logic:** Only deduct balance after successful processing
|
||||
- [ ] **Status Tracking:** Use pending → processing → completed/failed flow
|
||||
|
||||
**Total time:** ~15-20 minutes (includes validation steps)
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **You're Done!** *(Error-Free Agent)*
|
||||
|
||||
Your agent should now be:
|
||||
✅ **Visible** in the marketplace
|
||||
@ -294,9 +372,22 @@ Your agent should now be:
|
||||
✅ **Functional** with authentication
|
||||
✅ **Processing** requests successfully
|
||||
✅ **Integrated** with wallet system
|
||||
✅ **Error-resistant** with proper handling
|
||||
✅ **Session-aware** (if applicable)
|
||||
✅ **Status-tracked** throughout lifecycle
|
||||
|
||||
**Success Validation** (5 Whys Standard):
|
||||
- Agent processes test request without errors
|
||||
- Wallet deduction only happens after successful processing
|
||||
- Templates load correctly with namespaced URLs
|
||||
- Error states are handled gracefully
|
||||
- Status updates correctly throughout request lifecycle
|
||||
|
||||
**Next Steps:**
|
||||
- Customize the agent's UI/templates
|
||||
- Add more complex business logic
|
||||
- Configure additional API integrations
|
||||
- Monitor usage and performance
|
||||
- Consider implementing dual-mode processing (free chat + paid reports)
|
||||
- Add session management for complex interactions
|
||||
- Enhance error handling with comprehensive try-catch blocks
|
||||
- Monitor usage patterns and optimize based on 5 Whys learnings
|
||||
- Document any new patterns for future agents
|
||||
|
||||
**🎯 Remember:** Follow the 5 Whys Agent patterns for maximum reliability!
|
||||
@ -1,4 +1,4 @@
|
||||
# Development Guide
|
||||
# Development Guide - Enhanced with Agent Testing
|
||||
|
||||
## Quick Start
|
||||
|
||||
@ -226,4 +226,489 @@ python manage.py shell # Django shell
|
||||
1. Make script executable: `chmod +x run_dev.sh`
|
||||
2. Check file permissions: `ls -la`
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Agent Testing Procedures *(5 Whys Experience)*
|
||||
|
||||
Based on extensive debugging and the successful 5 Whys Analyzer implementation, here are comprehensive testing procedures for error-free agent development.
|
||||
|
||||
### Pre-Development Agent Testing Setup
|
||||
|
||||
```bash
|
||||
# Agent validation environment setup
|
||||
python manage.py shell -c "
|
||||
from agent_base.models import BaseAgent
|
||||
from django.template.loader import get_template
|
||||
from django.urls import reverse
|
||||
import os
|
||||
|
||||
def validate_agent_environment(agent_slug):
|
||||
print(f'🧪 Testing environment for {agent_slug}...')
|
||||
|
||||
# Test 1: BaseAgent exists
|
||||
try:
|
||||
agent = BaseAgent.objects.get(slug=agent_slug)
|
||||
print(f'✅ BaseAgent found: {agent.name}')
|
||||
except BaseAgent.DoesNotExist:
|
||||
print(f'❌ BaseAgent not found for slug: {agent_slug}')
|
||||
return False
|
||||
|
||||
# Test 2: URL resolution
|
||||
try:
|
||||
url = reverse('core:agent_detail', args=[agent_slug])
|
||||
print(f'✅ URL resolved: {url}')
|
||||
except Exception as e:
|
||||
print(f'❌ URL resolution failed: {e}')
|
||||
return False
|
||||
|
||||
# Test 3: Template loading
|
||||
try:
|
||||
template = get_template(f'{agent_slug.replace(\"-\", \"_\")}/detail.html')
|
||||
print(f'✅ Template found: {template.origin.name}')
|
||||
except Exception as e:
|
||||
print(f'❌ Template not found: {e}')
|
||||
return False
|
||||
|
||||
# Test 4: Environment variables (if needed)
|
||||
env_var = f'N8N_WEBHOOK_{agent_slug.upper().replace(\"-\", \"_\")}'
|
||||
if os.getenv(env_var):
|
||||
print(f'✅ Environment variable found: {env_var}')
|
||||
else:
|
||||
print(f'⚠️ Environment variable not set: {env_var}')
|
||||
|
||||
print(f'🎯 Environment validation complete for {agent_slug}')
|
||||
return True
|
||||
|
||||
# Test your agent
|
||||
validate_agent_environment('five-whys-analyzer')
|
||||
"
|
||||
```
|
||||
|
||||
### Agent Request Lifecycle Testing
|
||||
|
||||
```bash
|
||||
# Test complete agent request lifecycle
|
||||
python manage.py shell -c "
|
||||
import uuid
|
||||
from django.contrib.auth import get_user_model
|
||||
from agent_base.models import BaseAgent
|
||||
from five_whys_analyzer.models import FiveWhysAnalyzerRequest, FiveWhysAnalyzerResponse
|
||||
from five_whys_analyzer.processor import FiveWhysAnalyzerProcessor
|
||||
from decimal import Decimal
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
def test_agent_lifecycle(agent_slug='five-whys-analyzer'):
|
||||
print(f'🧪 Testing complete lifecycle for {agent_slug}...')
|
||||
|
||||
# Get test user
|
||||
user = User.objects.filter(is_superuser=True).first()
|
||||
if not user:
|
||||
print('❌ No superuser found for testing')
|
||||
return False
|
||||
|
||||
# Test 1: Agent exists and is active
|
||||
try:
|
||||
agent = BaseAgent.objects.get(slug=agent_slug, is_active=True)
|
||||
print(f'✅ Active agent found: {agent.name} (${agent.price})')
|
||||
except BaseAgent.DoesNotExist:
|
||||
print(f'❌ Active agent not found: {agent_slug}')
|
||||
return False
|
||||
|
||||
# Test 2: User has sufficient balance
|
||||
if user.wallet_balance < agent.price:
|
||||
print(f'⚠️ User balance ({user.wallet_balance}) < agent price ({agent.price})')
|
||||
print('Adding test balance...')
|
||||
user.wallet_balance += Decimal('50.00')
|
||||
user.save()
|
||||
|
||||
# Test 3: Create request object
|
||||
session_id = str(uuid.uuid4())
|
||||
try:
|
||||
request_obj = FiveWhysAnalyzerRequest.objects.create(
|
||||
user=user,
|
||||
agent=agent,
|
||||
session_id=session_id,
|
||||
cost=Decimal('8.00'),
|
||||
problem_statement='Test problem for validation',
|
||||
status='pending'
|
||||
)
|
||||
print(f'✅ Request created: {request_obj.id}')
|
||||
except Exception as e:
|
||||
print(f'❌ Request creation failed: {e}')
|
||||
return False
|
||||
|
||||
# Test 4: Status transitions
|
||||
try:
|
||||
request_obj.status = 'processing'
|
||||
request_obj.save()
|
||||
print('✅ Status updated to processing')
|
||||
|
||||
request_obj.status = 'completed'
|
||||
request_obj.save()
|
||||
print('✅ Status updated to completed')
|
||||
except Exception as e:
|
||||
print(f'❌ Status update failed: {e}')
|
||||
return False
|
||||
|
||||
# Test 5: Response creation
|
||||
try:
|
||||
response_obj = FiveWhysAnalyzerResponse.objects.create(
|
||||
request=request_obj,
|
||||
success=True,
|
||||
final_report='Test report generated successfully',
|
||||
processing_time=2.5
|
||||
)
|
||||
print(f'✅ Response created: {response_obj.id}')
|
||||
except Exception as e:
|
||||
print(f'❌ Response creation failed: {e}')
|
||||
return False
|
||||
|
||||
# Test 6: Cleanup
|
||||
response_obj.delete()
|
||||
request_obj.delete()
|
||||
print('✅ Test objects cleaned up')
|
||||
|
||||
print(f'🎯 Lifecycle test completed successfully for {agent_slug}')
|
||||
return True
|
||||
|
||||
# Run the test
|
||||
test_agent_lifecycle()
|
||||
"
|
||||
```
|
||||
|
||||
### Wallet Integration Testing
|
||||
|
||||
```bash
|
||||
# Test wallet integration patterns (5 Whys delayed deduction pattern)
|
||||
python manage.py shell -c "
|
||||
from django.contrib.auth import get_user_model
|
||||
from agent_base.models import BaseAgent
|
||||
from decimal import Decimal
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
def test_wallet_integration():
|
||||
print('🧪 Testing wallet integration patterns...')
|
||||
|
||||
user = User.objects.filter(is_superuser=True).first()
|
||||
agent = BaseAgent.objects.filter(is_active=True).first()
|
||||
|
||||
if not user or not agent:
|
||||
print('❌ Missing test user or agent')
|
||||
return False
|
||||
|
||||
# Record initial balance
|
||||
initial_balance = user.wallet_balance
|
||||
print(f'Initial balance: {initial_balance}')
|
||||
|
||||
# Test 1: Balance check (5 Whys pattern)
|
||||
if user.wallet_balance >= agent.price:
|
||||
print('✅ Sufficient balance for processing')
|
||||
else:
|
||||
print('❌ Insufficient balance')
|
||||
return False
|
||||
|
||||
# Test 2: Delayed deduction simulation
|
||||
print('🔄 Simulating processing...')
|
||||
processing_success = True # Simulate success
|
||||
|
||||
if processing_success:
|
||||
# Only deduct after success (5 Whys pattern)
|
||||
user.deduct_balance(
|
||||
agent.price,
|
||||
f'Test deduction for {agent.name}',
|
||||
agent.slug
|
||||
)
|
||||
print(f'✅ Balance deducted after success: {user.wallet_balance}')
|
||||
|
||||
# Verify deduction
|
||||
expected_balance = initial_balance - agent.price
|
||||
if user.wallet_balance == expected_balance:
|
||||
print('✅ Wallet deduction verified correct')
|
||||
else:
|
||||
print(f'❌ Wallet deduction incorrect: expected {expected_balance}, got {user.wallet_balance}')
|
||||
return False
|
||||
else:
|
||||
print('✅ No deduction for failed processing (correct behavior)')
|
||||
|
||||
# Test 3: Restore balance for other tests
|
||||
user.wallet_balance = initial_balance
|
||||
user.save()
|
||||
print(f'🔄 Balance restored to: {user.wallet_balance}')
|
||||
|
||||
print('🎯 Wallet integration test completed successfully')
|
||||
return True
|
||||
|
||||
test_wallet_integration()
|
||||
"
|
||||
```
|
||||
|
||||
### Template and URL Testing
|
||||
|
||||
```bash
|
||||
# Test template loading and URL routing (common 5 Whys issues)
|
||||
python manage.py shell -c "
|
||||
from django.template.loader import get_template
|
||||
from django.urls import reverse
|
||||
from django.test import RequestFactory
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
def test_template_and_urls():
|
||||
print('🧪 Testing templates and URLs...')
|
||||
|
||||
# Test template loading for all agents
|
||||
agents = ['weather_reporter', 'five_whys_analyzer']
|
||||
|
||||
for agent in agents:
|
||||
try:
|
||||
template = get_template(f'{agent}/detail.html')
|
||||
print(f'✅ Template loaded for {agent}: {template.origin.name}')
|
||||
except Exception as e:
|
||||
print(f'❌ Template failed for {agent}: {e}')
|
||||
|
||||
# Test URL resolution
|
||||
url_tests = [
|
||||
('core:homepage', []),
|
||||
('core:marketplace', []),
|
||||
('core:wallet', []),
|
||||
('core:agent_detail', ['weather-reporter']),
|
||||
('core:agent_detail', ['five-whys-analyzer']),
|
||||
]
|
||||
|
||||
for url_name, args in url_tests:
|
||||
try:
|
||||
url = reverse(url_name, args=args)
|
||||
print(f'✅ URL resolved {url_name}: {url}')
|
||||
except Exception as e:
|
||||
print(f'❌ URL failed {url_name}: {e}')
|
||||
|
||||
print('🎯 Template and URL testing completed')
|
||||
|
||||
test_template_and_urls()
|
||||
"
|
||||
```
|
||||
|
||||
### Error Handling Testing
|
||||
|
||||
```bash
|
||||
# Test error handling patterns (5 Whys comprehensive error handling)
|
||||
python manage.py shell -c "
|
||||
from five_whys_analyzer.processor import FiveWhysAnalyzerProcessor
|
||||
from agent_base.models import BaseAgent
|
||||
from django.contrib.auth import get_user_model
|
||||
import uuid
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
def test_error_handling():
|
||||
print('🧪 Testing error handling patterns...')
|
||||
|
||||
processor = FiveWhysAnalyzerProcessor()
|
||||
user = User.objects.filter(is_superuser=True).first()
|
||||
|
||||
# Test 1: Missing session_id
|
||||
try:
|
||||
result = processor.handle_chat_message(
|
||||
user=user,
|
||||
message='Test message'
|
||||
# No session_id - should auto-generate
|
||||
)
|
||||
print('✅ Missing session_id handled gracefully')
|
||||
except Exception as e:
|
||||
print(f'❌ Missing session_id caused error: {e}')
|
||||
|
||||
# Test 2: Missing user
|
||||
try:
|
||||
result = processor.handle_chat_message(
|
||||
session_id=str(uuid.uuid4()),
|
||||
message='Test message'
|
||||
# No user - should raise clear error
|
||||
)
|
||||
print('❌ Missing user should have raised error')
|
||||
except Exception as e:
|
||||
print(f'✅ Missing user properly handled: {type(e).__name__}')
|
||||
|
||||
# Test 3: Invalid message type
|
||||
try:
|
||||
result = processor.process_request(
|
||||
user=user,
|
||||
message_type='invalid_type'
|
||||
)
|
||||
print('❌ Invalid message type should have raised error')
|
||||
except ValueError as e:
|
||||
print(f'✅ Invalid message type properly handled: {e}')
|
||||
except Exception as e:
|
||||
print(f'❌ Unexpected error type: {e}')
|
||||
|
||||
print('🎯 Error handling testing completed')
|
||||
|
||||
test_error_handling()
|
||||
"
|
||||
```
|
||||
|
||||
### Performance and Index Testing
|
||||
|
||||
```bash
|
||||
# Test database performance and indexes (5 Whys optimization patterns)
|
||||
python manage.py shell -c "
|
||||
from django.db import connection
|
||||
from five_whys_analyzer.models import FiveWhysAnalyzerRequest
|
||||
from django.contrib.auth import get_user_model
|
||||
import uuid
|
||||
import time
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
def test_performance():
|
||||
print('🧪 Testing database performance...')
|
||||
|
||||
user = User.objects.first()
|
||||
if not user:
|
||||
print('❌ No user found for testing')
|
||||
return
|
||||
|
||||
# Test 1: Session lookup performance
|
||||
session_id = str(uuid.uuid4())
|
||||
|
||||
start_time = time.time()
|
||||
try:
|
||||
request = FiveWhysAnalyzerRequest.objects.filter(
|
||||
user=user,
|
||||
session_id=session_id,
|
||||
chat_active=True
|
||||
).first()
|
||||
end_time = time.time()
|
||||
print(f'✅ Session lookup completed in {(end_time - start_time)*1000:.2f}ms')
|
||||
except Exception as e:
|
||||
print(f'❌ Session lookup failed: {e}')
|
||||
|
||||
# Test 2: Index usage check
|
||||
with connection.cursor() as cursor:
|
||||
cursor.execute('EXPLAIN QUERY PLAN SELECT * FROM five_whys_analyzer_requests WHERE session_id = ?', [session_id])
|
||||
plan = cursor.fetchall()
|
||||
|
||||
# Check if index is being used
|
||||
plan_text = str(plan).lower()
|
||||
if 'index' in plan_text:
|
||||
print('✅ Database index being used for session_id queries')
|
||||
else:
|
||||
print('⚠️ No index detected for session_id queries')
|
||||
|
||||
print('🎯 Performance testing completed')
|
||||
|
||||
test_performance()
|
||||
"
|
||||
```
|
||||
|
||||
### Agent Integration Testing Commands
|
||||
|
||||
```bash
|
||||
# Complete agent validation script
|
||||
python manage.py shell -c "
|
||||
def run_complete_agent_test(agent_slug):
|
||||
print(f'🚀 Running complete agent test for {agent_slug}')
|
||||
print('='*50)
|
||||
|
||||
tests = [
|
||||
('Environment', lambda: validate_agent_environment(agent_slug)),
|
||||
('Lifecycle', lambda: test_agent_lifecycle(agent_slug)),
|
||||
('Wallet', lambda: test_wallet_integration()),
|
||||
('Templates & URLs', lambda: test_template_and_urls()),
|
||||
('Error Handling', lambda: test_error_handling()),
|
||||
('Performance', lambda: test_performance()),
|
||||
]
|
||||
|
||||
results = []
|
||||
for test_name, test_func in tests:
|
||||
print(f'\\n🧪 Running {test_name} test...')
|
||||
try:
|
||||
result = test_func()
|
||||
results.append((test_name, result))
|
||||
if result:
|
||||
print(f'✅ {test_name} test PASSED')
|
||||
else:
|
||||
print(f'❌ {test_name} test FAILED')
|
||||
except Exception as e:
|
||||
print(f'❌ {test_name} test ERROR: {e}')
|
||||
results.append((test_name, False))
|
||||
|
||||
print(f'\\n🎯 Test Summary for {agent_slug}:')
|
||||
print('='*30)
|
||||
passed = sum(1 for _, result in results if result)
|
||||
total = len(results)
|
||||
|
||||
for test_name, result in results:
|
||||
status = '✅ PASS' if result else '❌ FAIL'
|
||||
print(f'{test_name}: {status}')
|
||||
|
||||
print(f'\\nOverall: {passed}/{total} tests passed')
|
||||
if passed == total:
|
||||
print('🎉 All tests passed! Agent is ready for production.')
|
||||
else:
|
||||
print('⚠️ Some tests failed. Please review and fix issues.')
|
||||
|
||||
# Run for 5 Whys Analyzer
|
||||
run_complete_agent_test('five-whys-analyzer')
|
||||
"
|
||||
```
|
||||
|
||||
### 5 Whys Debugging Workflow
|
||||
|
||||
When issues arise during agent development, follow this debugging workflow learned from 5 Whys experience:
|
||||
|
||||
```bash
|
||||
# 1. Basic validation
|
||||
python manage.py check
|
||||
python manage.py showmigrations [agent_name]
|
||||
|
||||
# 2. Template validation
|
||||
python manage.py shell -c "
|
||||
from django.template.loader import get_template
|
||||
template = get_template('[agent_name]/detail.html')
|
||||
print('Template found:', template.origin.name)
|
||||
"
|
||||
|
||||
# 3. URL validation
|
||||
python manage.py shell -c "
|
||||
from django.urls import reverse
|
||||
url = reverse('core:agent_detail', args=['[agent-slug]'])
|
||||
print('URL resolved:', url)
|
||||
"
|
||||
|
||||
# 4. Model validation
|
||||
python manage.py shell -c "
|
||||
from [agent_name].models import *
|
||||
from agent_base.models import BaseAgent
|
||||
agent = BaseAgent.objects.get(slug='[agent-slug]')
|
||||
print('Agent found:', agent.name)
|
||||
"
|
||||
|
||||
# 5. Processor validation
|
||||
python manage.py shell -c "
|
||||
from [agent_name].processor import [AgentName]Processor
|
||||
processor = [AgentName]Processor()
|
||||
print('Processor initialized successfully')
|
||||
"
|
||||
```
|
||||
|
||||
### Production Readiness Checklist
|
||||
|
||||
Based on 5 Whys success patterns, verify these before deploying:
|
||||
|
||||
- [ ] **Template Loading**: Templates load without server restart
|
||||
- [ ] **URL Routing**: All URLs resolve correctly with namespaces
|
||||
- [ ] **Database**: Migrations applied, indexes created
|
||||
- [ ] **Wallet Integration**: Delayed deduction pattern implemented
|
||||
- [ ] **Error Handling**: Comprehensive try-catch blocks
|
||||
- [ ] **Session Management**: UUID-based sessions (if applicable)
|
||||
- [ ] **Status Tracking**: Request lifecycle properly managed
|
||||
- [ ] **Environment Variables**: All required variables validated
|
||||
- [ ] **Performance**: Database queries optimized with indexes
|
||||
- [ ] **Testing**: Complete test suite passes
|
||||
|
||||
**🎯 Following these testing procedures ensures the same level of reliability achieved with the 5 Whys Analyzer.**
|
||||
|
||||
Happy coding! 🎉
|
||||
803
docs/ERROR_PREVENTION_GUIDE.md
Normal file
803
docs/ERROR_PREVENTION_GUIDE.md
Normal file
@ -0,0 +1,803 @@
|
||||
# Error Prevention Guide for Agent Creation
|
||||
|
||||
## 🎯 Based on 5 Whys Analyzer Debugging Experience
|
||||
|
||||
This guide documents all the common errors encountered during agent development and their proven solutions, based on extensive debugging work that led to the successful 5 Whys Analyzer implementation.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Table of Contents
|
||||
|
||||
1. [Template Loading Errors](#template-loading-errors)
|
||||
2. [URL Routing Issues](#url-routing-issues)
|
||||
3. [Database Migration Conflicts](#database-migration-conflicts)
|
||||
4. [Wallet Integration Problems](#wallet-integration-problems)
|
||||
5. [Session Management Issues](#session-management-issues)
|
||||
6. [Status Tracking Problems](#status-tracking-problems)
|
||||
7. [Error Handling Failures](#error-handling-failures)
|
||||
8. [Environment Variable Issues](#environment-variable-issues)
|
||||
9. [N8N Webhook Problems](#n8n-webhook-problems)
|
||||
10. [Performance and Index Issues](#performance-and-index-issues)
|
||||
|
||||
---
|
||||
|
||||
## 1. Template Loading Errors
|
||||
|
||||
### ❌ Common Error
|
||||
```
|
||||
TemplateDoesNotExist: detail.html
|
||||
django.template.loader.TemplateDoesNotExist: detail.html
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Template in wrong directory structure
|
||||
- Django server cache holding old template paths
|
||||
- Missing app in INSTALLED_APPS
|
||||
- Incorrect template naming convention
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Correct Template Structure:**
|
||||
```bash
|
||||
# ✅ Correct - 5 Whys pattern
|
||||
agent_five_whys_analyzer/
|
||||
└── templates/
|
||||
└── five_whys_analyzer/
|
||||
└── detail.html
|
||||
|
||||
# ❌ Wrong - causes TemplateDoesNotExist
|
||||
agent_five_whys_analyzer/
|
||||
└── templates/
|
||||
└── detail.html # Missing app subdirectory
|
||||
```
|
||||
|
||||
**Template Path Validation Script:**
|
||||
```bash
|
||||
# Test template loading before starting server
|
||||
python manage.py shell -c "
|
||||
from django.template.loader import get_template
|
||||
try:
|
||||
template = get_template('five_whys_analyzer/detail.html')
|
||||
print('✅ Template found:', template.origin.name)
|
||||
except Exception as e:
|
||||
print('❌ Template error:', e)
|
||||
"
|
||||
```
|
||||
|
||||
**Critical Fix Steps:**
|
||||
1. Create proper directory structure
|
||||
2. Move template to correct location
|
||||
3. **RESTART Django server** (cache issue)
|
||||
4. Verify template loading with shell command
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
```bash
|
||||
# Template creation checklist
|
||||
mkdir -p [agent_name]/templates/[agent_name]/
|
||||
cp existing_working_template.html [agent_name]/templates/[agent_name]/detail.html
|
||||
# Always restart server after template changes
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. URL Routing Issues
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
NoReverseMatch: Reverse for 'wallet' not found
|
||||
django.urls.exceptions.NoReverseMatch at /agents/five-whys-analyzer/
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Missing URL namespaces in templates
|
||||
- Incorrect URL registration order
|
||||
- Agent URLs placed after catch-all core URLs
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Correct URL Namespacing in Templates:**
|
||||
```html
|
||||
<!-- ❌ Wrong - causes NoReverseMatch -->
|
||||
<a href="{% url 'wallet' %}">Wallet</a>
|
||||
<a href="{% url 'homepage' %}">Home</a>
|
||||
|
||||
<!-- ✅ Correct - 5 Whys pattern -->
|
||||
<a href="{% url 'core:wallet' %}">Wallet</a>
|
||||
<a href="{% url 'core:homepage' %}">Home</a>
|
||||
<a href="{% url 'authentication:login' %}">Login</a>
|
||||
```
|
||||
|
||||
**Correct URL Registration Order:**
|
||||
```python
|
||||
# netcop_hub/urls.py - CRITICAL ORDER
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('auth/', include('authentication.urls')),
|
||||
|
||||
# ✅ Agent URLs MUST come before core URLs
|
||||
path('agents/weather-reporter/', include('weather_reporter.urls')),
|
||||
path('agents/five-whys-analyzer/', include('five_whys_analyzer.urls')),
|
||||
|
||||
# ❌ Core URLs with catch-all pattern must be LAST
|
||||
path('', include('core.urls')), # This catches everything - put LAST
|
||||
]
|
||||
```
|
||||
|
||||
**URL Testing Commands:**
|
||||
```bash
|
||||
# Test URL resolution
|
||||
python manage.py shell -c "
|
||||
from django.urls import reverse
|
||||
try:
|
||||
url = reverse('core:agent_detail', args=['five-whys-analyzer'])
|
||||
print('✅ URL resolved:', url)
|
||||
except Exception as e:
|
||||
print('❌ URL error:', e)
|
||||
"
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Always use namespaced URLs in templates
|
||||
- Register agent URLs before core URLs
|
||||
- Test URL resolution after each agent creation
|
||||
|
||||
---
|
||||
|
||||
## 3. Database Migration Conflicts
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
django.db.utils.ProgrammingError: relation "five_whys_analyzer_requests" already exists
|
||||
django.db.migrations.exceptions.InconsistentMigrationHistory
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Django migration state out of sync with actual database
|
||||
- Manually created tables conflicting with migrations
|
||||
- Migration dependencies missing or circular
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Manual Migration Sync Fix:**
|
||||
```bash
|
||||
# 1. Check current migration state
|
||||
python manage.py showmigrations five_whys_analyzer
|
||||
|
||||
# 2. Create empty migration to sync state
|
||||
python manage.py makemigrations five_whys_analyzer --empty --name fix_migration_sync
|
||||
|
||||
# 3. Edit the migration file to match current state
|
||||
# migrations/000X_fix_migration_sync.py
|
||||
from django.db import migrations
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
('five_whys_analyzer', '0001_initial'),
|
||||
]
|
||||
operations = [
|
||||
# Empty operations - just sync Django state
|
||||
]
|
||||
|
||||
# 4. Apply migration
|
||||
python manage.py migrate five_whys_analyzer
|
||||
```
|
||||
|
||||
**Conflict Resolution Pattern:**
|
||||
```bash
|
||||
# If migration conflicts persist
|
||||
python manage.py migrate five_whys_analyzer --fake-initial
|
||||
python manage.py migrate five_whys_analyzer
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Always run `makemigrations` immediately after model changes
|
||||
- Test migrations on clean database before production
|
||||
- Keep migration files in version control
|
||||
|
||||
---
|
||||
|
||||
## 4. Wallet Integration Problems
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
AttributeError: 'User' object has no attribute 'deduct_balance'
|
||||
decimal.InvalidOperation: [<class 'decimal.ConversionSyntax'>]
|
||||
Wallet balance incorrectly deducted for failed requests
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Deducting balance before processing completion
|
||||
- Incorrect decimal handling for currency
|
||||
- Missing wallet methods in User model
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Delayed Deduction Pattern (Critical):**
|
||||
```python
|
||||
# ❌ Wrong - deduct before processing
|
||||
def process_view(request):
|
||||
# Bad: deduct immediately
|
||||
request.user.deduct_balance(agent.price, description, agent_slug)
|
||||
result = process_request() # What if this fails?
|
||||
return result
|
||||
|
||||
# ✅ Correct - 5 Whys pattern (deduct after success)
|
||||
def process_report_response(self, response_data, request_obj):
|
||||
try:
|
||||
# Process first
|
||||
final_report = response_data.get('output', '')
|
||||
success = bool(final_report) and response_data.get('success', True)
|
||||
|
||||
if success:
|
||||
# Save successful response
|
||||
response_obj.final_report = final_report
|
||||
response_obj.save()
|
||||
|
||||
# ONLY deduct after confirmed success
|
||||
request_obj.user.deduct_balance(
|
||||
request_obj.cost,
|
||||
f"5 Whys Analysis Agent - Final Report",
|
||||
'five-whys-analyzer'
|
||||
)
|
||||
request_obj.status = 'completed'
|
||||
else:
|
||||
request_obj.status = 'failed'
|
||||
# No wallet deduction for failures
|
||||
|
||||
request_obj.save()
|
||||
return response_obj
|
||||
|
||||
except Exception as e:
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
# No wallet deduction for exceptions
|
||||
raise Exception(f"Failed to process: {e}")
|
||||
```
|
||||
|
||||
**Decimal Handling:**
|
||||
```python
|
||||
# ✅ Correct decimal usage
|
||||
from decimal import Decimal
|
||||
|
||||
# Always use Decimal for currency
|
||||
agent.price = Decimal('8.00')
|
||||
request_obj.cost = Decimal('8.00')
|
||||
|
||||
# Check balance properly
|
||||
if request.user.wallet_balance >= agent.price:
|
||||
# Proceed
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Never deduct balance before processing completion
|
||||
- Always use Decimal for currency calculations
|
||||
- Implement balance checks before processing
|
||||
- Test wallet integration with both success and failure scenarios
|
||||
|
||||
---
|
||||
|
||||
## 5. Session Management Issues
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
KeyError: 'session_id'
|
||||
Multiple chat sessions created for same user
|
||||
Session state lost between requests
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Missing session ID handling
|
||||
- No persistent session storage
|
||||
- Poor session lifecycle management
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Session-Based Model Pattern:**
|
||||
```python
|
||||
# 5 Whys session management pattern
|
||||
class AgentRequest(BaseAgentRequest):
|
||||
# Session management
|
||||
session_id = models.CharField(max_length=100, default=uuid.uuid4, db_index=True)
|
||||
|
||||
# Session state tracking
|
||||
chat_messages = models.JSONField(default=list)
|
||||
chat_active = models.BooleanField(default=True)
|
||||
report_generated = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
indexes = [
|
||||
models.Index(fields=['session_id']),
|
||||
models.Index(fields=['user', 'chat_active']),
|
||||
]
|
||||
```
|
||||
|
||||
**Session Retrieval Pattern:**
|
||||
```python
|
||||
# Safe session handling
|
||||
def handle_chat_message(self, **kwargs):
|
||||
user = kwargs.get('user')
|
||||
session_id = kwargs.get('session_id', str(uuid.uuid4()))
|
||||
|
||||
# Get or create session
|
||||
request_obj, created = AgentRequest.objects.get_or_create(
|
||||
user=user,
|
||||
session_id=session_id,
|
||||
chat_active=True,
|
||||
defaults={
|
||||
'agent': agent,
|
||||
'cost': 0, # No cost for chat
|
||||
'status': 'pending'
|
||||
}
|
||||
)
|
||||
|
||||
# Add message to history
|
||||
chat_messages = request_obj.chat_messages
|
||||
chat_messages.append({
|
||||
'role': 'user',
|
||||
'message': user_message,
|
||||
'timestamp': timezone.now().isoformat()
|
||||
})
|
||||
request_obj.chat_messages = chat_messages
|
||||
request_obj.save()
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Always use UUID for session IDs
|
||||
- Index session_id field for performance
|
||||
- Implement session cleanup for old sessions
|
||||
- Test session persistence across requests
|
||||
|
||||
---
|
||||
|
||||
## 6. Status Tracking Problems
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
Requests stuck in 'processing' status
|
||||
Status not updated after completion
|
||||
Inconsistent status across request lifecycle
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Missing status updates in error paths
|
||||
- No status transitions defined
|
||||
- Exception handling bypassing status updates
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Status Lifecycle Pattern:**
|
||||
```python
|
||||
# 5 Whys status tracking pattern
|
||||
def process_response(self, response_data, request_obj):
|
||||
try:
|
||||
# Always update status to processing
|
||||
request_obj.status = 'processing'
|
||||
request_obj.save()
|
||||
|
||||
# Process the request
|
||||
success = self.extract_and_validate_response(response_data)
|
||||
|
||||
# Update status based on result
|
||||
if success:
|
||||
request_obj.status = 'completed'
|
||||
# Handle successful response
|
||||
else:
|
||||
request_obj.status = 'failed'
|
||||
# Handle failed response
|
||||
|
||||
except Exception as e:
|
||||
# Always handle errors with status update
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
raise
|
||||
finally:
|
||||
# Always set processed timestamp
|
||||
request_obj.processed_at = timezone.now()
|
||||
request_obj.save()
|
||||
```
|
||||
|
||||
**Status Validation:**
|
||||
```python
|
||||
# Status transition validation
|
||||
VALID_STATUS_TRANSITIONS = {
|
||||
'pending': ['processing', 'failed'],
|
||||
'processing': ['completed', 'failed'],
|
||||
'completed': [], # Terminal state
|
||||
'failed': [], # Terminal state
|
||||
}
|
||||
|
||||
def update_status(self, request_obj, new_status):
|
||||
current_status = request_obj.status
|
||||
if new_status not in VALID_STATUS_TRANSITIONS.get(current_status, []):
|
||||
raise ValueError(f"Invalid status transition: {current_status} -> {new_status}")
|
||||
request_obj.status = new_status
|
||||
request_obj.save()
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Define clear status lifecycle
|
||||
- Always update status in exception handlers
|
||||
- Use try-finally blocks for cleanup
|
||||
- Monitor requests stuck in processing status
|
||||
|
||||
---
|
||||
|
||||
## 7. Error Handling Failures
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
Unhandled exceptions breaking request flow
|
||||
Users see raw Django error pages
|
||||
No error logging for debugging
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Missing try-catch blocks
|
||||
- No graceful error recovery
|
||||
- Poor error messaging to users
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Comprehensive Error Handling Pattern:**
|
||||
```python
|
||||
# 5 Whys error handling pattern
|
||||
def process_request(self, **kwargs):
|
||||
request_obj = None
|
||||
try:
|
||||
# Create request object
|
||||
request_obj = self.create_request_object(**kwargs)
|
||||
|
||||
# Process the request
|
||||
response_data = self.make_api_call(**kwargs)
|
||||
|
||||
# Handle response
|
||||
return self.process_response(response_data, request_obj)
|
||||
|
||||
except ValidationError as e:
|
||||
# User input error - don't log as system error
|
||||
self.handle_user_error(request_obj, f"Invalid input: {e}")
|
||||
raise Exception(f"Please check your input: {e}")
|
||||
|
||||
except requests.RequestException as e:
|
||||
# External API error - log and retry
|
||||
self.log_api_error(e, request_obj)
|
||||
self.handle_api_error(request_obj, "External service temporarily unavailable")
|
||||
raise Exception("Service temporarily unavailable. Please try again later.")
|
||||
|
||||
except Exception as e:
|
||||
# Unknown error - log everything for debugging
|
||||
self.log_system_error(e, request_obj, **kwargs)
|
||||
self.handle_system_error(request_obj, "An unexpected error occurred")
|
||||
raise Exception("An unexpected error occurred. Please contact support.")
|
||||
|
||||
def handle_user_error(self, request_obj, message):
|
||||
if request_obj:
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
# Don't log user errors as system issues
|
||||
|
||||
def handle_api_error(self, request_obj, message):
|
||||
if request_obj:
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
# Log API errors for monitoring
|
||||
print(f"API Error: {message}")
|
||||
|
||||
def handle_system_error(self, request_obj, message):
|
||||
if request_obj:
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
# Log system errors with full context
|
||||
print(f"SYSTEM ERROR: {message}")
|
||||
|
||||
def log_system_error(self, error, request_obj, **kwargs):
|
||||
"""Log system errors with full context for debugging"""
|
||||
error_context = {
|
||||
'error': str(error),
|
||||
'request_id': str(request_obj.id) if request_obj else 'None',
|
||||
'user_id': kwargs.get('user', {}).get('id', 'None'),
|
||||
'agent_slug': self.agent_slug,
|
||||
'kwargs': kwargs
|
||||
}
|
||||
print(f"SYSTEM ERROR CONTEXT: {error_context}")
|
||||
```
|
||||
|
||||
**User-Friendly Error Messages:**
|
||||
```python
|
||||
# Map internal errors to user-friendly messages
|
||||
ERROR_MESSAGES = {
|
||||
'insufficient_balance': "Insufficient wallet balance. Please top up your wallet.",
|
||||
'file_too_large': "File size exceeds limit. Please upload a smaller file.",
|
||||
'invalid_format': "Unsupported file format. Please upload a valid file.",
|
||||
'api_timeout': "Request timed out. Please try again.",
|
||||
'service_unavailable': "Service temporarily unavailable. Please try again later.",
|
||||
'unknown_error': "An unexpected error occurred. Please contact support."
|
||||
}
|
||||
|
||||
def get_user_friendly_error(self, error_code):
|
||||
return ERROR_MESSAGES.get(error_code, ERROR_MESSAGES['unknown_error'])
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Wrap all external calls in try-catch blocks
|
||||
- Provide user-friendly error messages
|
||||
- Log errors with sufficient context for debugging
|
||||
- Test error scenarios during development
|
||||
|
||||
---
|
||||
|
||||
## 8. Environment Variable Issues
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
KeyError: 'N8N_WEBHOOK_5_WHYS'
|
||||
API authentication failures
|
||||
Webhook URLs not found
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Environment variables not loaded
|
||||
- Variable name mismatches
|
||||
- Missing .env file in production
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Environment Variable Pattern:**
|
||||
```python
|
||||
# Safe environment variable loading
|
||||
import os
|
||||
from django.conf import settings
|
||||
|
||||
class AgentProcessor:
|
||||
def __init__(self):
|
||||
# Safe environment variable access
|
||||
self.webhook_url = self.get_env_var('N8N_WEBHOOK_5_WHYS')
|
||||
self.api_key = self.get_env_var('EXTERNAL_API_KEY')
|
||||
|
||||
def get_env_var(self, var_name, default=None):
|
||||
"""Safely get environment variable with validation"""
|
||||
value = os.getenv(var_name, default)
|
||||
if not value and default is None:
|
||||
raise Exception(f"Required environment variable '{var_name}' not found")
|
||||
return value
|
||||
|
||||
def validate_configuration(self):
|
||||
"""Validate all required environment variables"""
|
||||
required_vars = [
|
||||
'N8N_WEBHOOK_5_WHYS',
|
||||
'DATABASE_URL',
|
||||
'SECRET_KEY'
|
||||
]
|
||||
|
||||
missing_vars = []
|
||||
for var in required_vars:
|
||||
if not os.getenv(var):
|
||||
missing_vars.append(var)
|
||||
|
||||
if missing_vars:
|
||||
raise Exception(f"Missing required environment variables: {missing_vars}")
|
||||
```
|
||||
|
||||
**Environment Variable Validation Command:**
|
||||
```bash
|
||||
# Create validation script
|
||||
python manage.py shell -c "
|
||||
import os
|
||||
required_vars = ['N8N_WEBHOOK_5_WHYS', 'OPENWEATHER_API_KEY', 'DATABASE_URL']
|
||||
missing = [var for var in required_vars if not os.getenv(var)]
|
||||
if missing:
|
||||
print('❌ Missing variables:', missing)
|
||||
else:
|
||||
print('✅ All required variables present')
|
||||
"
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Create environment variable validation script
|
||||
- Use safe access patterns with defaults
|
||||
- Document all required variables
|
||||
- Test with missing variables to ensure graceful failure
|
||||
|
||||
---
|
||||
|
||||
## 9. N8N Webhook Problems
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
Connection refused to N8N webhook
|
||||
Webhook timeout errors
|
||||
Invalid webhook response format
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- N8N workflow not active
|
||||
- Network connectivity issues
|
||||
- Response format mismatches
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Webhook Validation Pattern:**
|
||||
```python
|
||||
# 5 Whys webhook handling pattern
|
||||
class WebhookProcessor(StandardWebhookProcessor):
|
||||
def make_request(self, payload):
|
||||
"""Make webhook request with comprehensive error handling"""
|
||||
try:
|
||||
# Validate webhook URL
|
||||
if not self.webhook_url:
|
||||
raise Exception("Webhook URL not configured")
|
||||
|
||||
# Test connectivity first
|
||||
self.test_webhook_connectivity()
|
||||
|
||||
# Make request with timeout
|
||||
response = requests.post(
|
||||
self.webhook_url,
|
||||
json=payload,
|
||||
timeout=30, # 30 second timeout
|
||||
headers={'Content-Type': 'application/json'}
|
||||
)
|
||||
|
||||
# Validate response
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Webhook returned status {response.status_code}: {response.text}")
|
||||
|
||||
# Validate response format
|
||||
try:
|
||||
response_data = response.json()
|
||||
except ValueError:
|
||||
raise Exception("Webhook returned invalid JSON")
|
||||
|
||||
return response_data
|
||||
|
||||
except requests.ConnectionError:
|
||||
raise Exception("Cannot connect to N8N webhook. Check N8N service status.")
|
||||
except requests.Timeout:
|
||||
raise Exception("Webhook request timed out. Try again later.")
|
||||
except Exception as e:
|
||||
raise Exception(f"Webhook error: {e}")
|
||||
|
||||
def test_webhook_connectivity(self):
|
||||
"""Test webhook connectivity before making actual request"""
|
||||
try:
|
||||
test_response = requests.get(
|
||||
self.webhook_url.replace('/webhook/', '/ping/'),
|
||||
timeout=5
|
||||
)
|
||||
return True
|
||||
except:
|
||||
# Webhook connectivity test failed - continue anyway
|
||||
return False
|
||||
```
|
||||
|
||||
**Webhook Response Validation:**
|
||||
```python
|
||||
def validate_webhook_response(self, response_data):
|
||||
"""Validate webhook response format"""
|
||||
required_fields = ['output', 'success']
|
||||
|
||||
if not isinstance(response_data, dict):
|
||||
raise Exception("Webhook response must be JSON object")
|
||||
|
||||
missing_fields = [field for field in required_fields if field not in response_data]
|
||||
if missing_fields:
|
||||
raise Exception(f"Webhook response missing fields: {missing_fields}")
|
||||
|
||||
return True
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Always test webhook connectivity
|
||||
- Implement proper timeout handling
|
||||
- Validate webhook response format
|
||||
- Have fallback mechanisms for webhook failures
|
||||
|
||||
---
|
||||
|
||||
## 10. Performance and Index Issues
|
||||
|
||||
### ❌ Common Errors
|
||||
```
|
||||
Slow database queries
|
||||
Missing indexes on frequently queried fields
|
||||
Session lookup timeouts
|
||||
```
|
||||
|
||||
### 🔍 Root Cause Analysis
|
||||
- Missing database indexes
|
||||
- Inefficient query patterns
|
||||
- No query optimization
|
||||
|
||||
### ✅ 5 Whys Learned Solution
|
||||
|
||||
**Database Index Pattern:**
|
||||
```python
|
||||
# 5 Whys performance optimization
|
||||
class AgentRequest(BaseAgentRequest):
|
||||
session_id = models.CharField(max_length=100, default=uuid.uuid4, db_index=True)
|
||||
|
||||
class Meta:
|
||||
indexes = [
|
||||
# Session-based queries
|
||||
models.Index(fields=['session_id']),
|
||||
models.Index(fields=['user', 'chat_active']),
|
||||
|
||||
# Status and time-based queries
|
||||
models.Index(fields=['status', 'created_at']),
|
||||
models.Index(fields=['user', 'status']),
|
||||
|
||||
# Agent-specific queries
|
||||
models.Index(fields=['agent', 'created_at']),
|
||||
]
|
||||
```
|
||||
|
||||
**Query Optimization Pattern:**
|
||||
```python
|
||||
# Efficient query patterns
|
||||
def get_user_active_session(self, user, agent_slug):
|
||||
"""Optimized session lookup"""
|
||||
return AgentRequest.objects.select_related('agent', 'user').filter(
|
||||
user=user,
|
||||
agent__slug=agent_slug,
|
||||
chat_active=True
|
||||
).first()
|
||||
|
||||
def get_recent_requests(self, user, limit=10):
|
||||
"""Optimized recent requests lookup"""
|
||||
return AgentRequest.objects.select_related('agent').filter(
|
||||
user=user
|
||||
).order_by('-created_at')[:limit]
|
||||
```
|
||||
|
||||
### 🛡️ Prevention Strategy
|
||||
- Add indexes for all frequently queried fields
|
||||
- Use select_related for foreign key queries
|
||||
- Monitor slow queries in production
|
||||
- Test with realistic data volumes
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Overall Prevention Strategy
|
||||
|
||||
### Pre-Development Checklist
|
||||
- [ ] Study 5 Whys Analyzer patterns before starting
|
||||
- [ ] Plan session management if needed
|
||||
- [ ] Design delayed wallet deduction flow
|
||||
- [ ] Plan comprehensive error handling
|
||||
|
||||
### During Development Checklist
|
||||
- [ ] Use proper template directory structure
|
||||
- [ ] Always use namespaced URLs
|
||||
- [ ] Implement delayed wallet deduction
|
||||
- [ ] Add comprehensive error handling
|
||||
- [ ] Create proper database indexes
|
||||
|
||||
### Post-Development Checklist
|
||||
- [ ] Test all error scenarios
|
||||
- [ ] Validate template loading
|
||||
- [ ] Test URL routing
|
||||
- [ ] Verify wallet integration
|
||||
- [ ] Test session management
|
||||
- [ ] Validate environment variables
|
||||
|
||||
### Production Deployment Checklist
|
||||
- [ ] Run migration validation
|
||||
- [ ] Test webhook connectivity
|
||||
- [ ] Verify environment variables
|
||||
- [ ] Monitor error rates
|
||||
- [ ] Check performance metrics
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Key Takeaways from 5 Whys Debugging
|
||||
|
||||
1. **Template Organization is Critical**: Always use proper directory structure
|
||||
2. **URL Namespaces Prevent Errors**: Always use namespaced URLs
|
||||
3. **Delayed Wallet Deduction**: Never deduct before processing success
|
||||
4. **Session Management**: Use UUID-based sessions for complex agents
|
||||
5. **Status Tracking**: Implement proper lifecycle management
|
||||
6. **Error Handling**: Wrap everything in try-catch blocks
|
||||
7. **Environment Variables**: Validate all required variables
|
||||
8. **Performance**: Add indexes for frequently queried fields
|
||||
|
||||
**Following these patterns from the 5 Whys success ensures error-free agent creation.**
|
||||
@ -1,6 +1,6 @@
|
||||
# Complete Manual Agent Creation Guide
|
||||
# Complete Manual Agent Creation Guide - Error-Free Edition
|
||||
|
||||
This guide provides step-by-step instructions for manually creating AI agents in the NetCop Hub platform.
|
||||
This guide provides step-by-step instructions for manually creating AI agents in the NetCop Hub platform. **Updated with proven patterns from the successful 5 Whys Analyzer implementation.**
|
||||
|
||||
## Table of Contents
|
||||
1. [Overview](#overview)
|
||||
@ -20,15 +20,28 @@ This guide provides step-by-step instructions for manually creating AI agents in
|
||||
|
||||
### Agent Types
|
||||
- **API Agents**: Direct integration with external APIs (e.g., OpenWeather, Stripe)
|
||||
- **Webhook Agents**: Integration with N8N workflows or custom webhooks
|
||||
- **Webhook Agents**: Integration with N8N workflows or custom webhooks *(Recommended)*
|
||||
- **Dual-Mode Agents**: Free interactions + paid reports *(5 Whys Pattern)*
|
||||
|
||||
### Architecture
|
||||
### Architecture *(5 Whys Success Patterns)*
|
||||
Each agent is a separate Django app that extends the base agent framework:
|
||||
- `BaseAgent`: Marketplace catalog entry
|
||||
- `BaseAgentRequest`/`BaseAgentResponse`: Request/response tracking
|
||||
- `BaseAgentProcessor`: Processing logic (API or webhook)
|
||||
- `BaseAgentView`: Form handling and authentication
|
||||
|
||||
### 🚀 **5 Whys Analyzer Success Patterns**
|
||||
The most robust agent implementation includes these key patterns:
|
||||
|
||||
**Core Success Features:**
|
||||
- **Session-based architecture**: UUID tracking with persistent state
|
||||
- **Dual-mode processing**: Free chat interactions + paid report generation
|
||||
- **Delayed wallet deduction**: Only charge after successful processing
|
||||
- **Comprehensive error handling**: Try-catch blocks throughout lifecycle
|
||||
- **Smart status tracking**: pending → processing → completed/failed
|
||||
|
||||
**Apply these patterns for maximum reliability and user satisfaction.**
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Django project setup and running
|
||||
@ -36,6 +49,199 @@ Each agent is a separate Django app that extends the base agent framework:
|
||||
3. Authentication system configured
|
||||
4. Wallet system for payments
|
||||
|
||||
---
|
||||
|
||||
## 🎯 **5 Whys Analyzer - Proven Implementation Patterns**
|
||||
|
||||
Before diving into the step-by-step guide, study these proven patterns from the successful 5 Whys Analyzer implementation. **Following these patterns ensures error-free agent creation.**
|
||||
|
||||
### Session-Based Models *(Recommended for Complex Agents)*
|
||||
|
||||
```python
|
||||
# Key model patterns from 5 Whys success
|
||||
class FiveWhysAnalyzerRequest(BaseAgentRequest):
|
||||
# Session management
|
||||
session_id = models.CharField(max_length=100, default=uuid.uuid4, db_index=True)
|
||||
|
||||
# Chat interaction tracking
|
||||
chat_messages = models.JSONField(default=list)
|
||||
|
||||
# Mode tracking
|
||||
report_generated = models.BooleanField(default=False)
|
||||
chat_active = models.BooleanField(default=True)
|
||||
|
||||
# Specific request data
|
||||
problem_statement = models.TextField(blank=True)
|
||||
analysis_depth = models.CharField(max_length=20, choices=[...])
|
||||
```
|
||||
|
||||
### Delayed Wallet Deduction Pattern *(Critical for Reliability)*
|
||||
|
||||
```python
|
||||
# ❌ Wrong - deduct before processing
|
||||
user.deduct_balance(cost, description, agent_slug)
|
||||
response = process_request()
|
||||
|
||||
# ✅ Correct - 5 Whys pattern (deduct after success)
|
||||
def process_report_response(self, response_data, request_obj):
|
||||
try:
|
||||
# Process the request first
|
||||
final_report = response_data.get('output', '')
|
||||
success = bool(final_report) and response_data.get('success', True)
|
||||
|
||||
if success:
|
||||
# Save response data
|
||||
response_obj.final_report = final_report
|
||||
response_obj.save()
|
||||
|
||||
# ONLY deduct wallet balance after successful processing
|
||||
request_obj.user.deduct_balance(
|
||||
request_obj.cost,
|
||||
f"5 Whys Analysis Agent - Final Report",
|
||||
'five-whys-analyzer'
|
||||
)
|
||||
request_obj.status = 'completed'
|
||||
else:
|
||||
request_obj.status = 'failed'
|
||||
|
||||
request_obj.save()
|
||||
return response_obj
|
||||
except Exception as e:
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
raise Exception(f"Failed to process: {e}")
|
||||
```
|
||||
|
||||
### Dual-Mode Processing Pattern *(Free + Paid Interactions)*
|
||||
|
||||
```python
|
||||
# 5 Whys processor pattern - handle both free chat and paid reports
|
||||
def process_request(self, **kwargs):
|
||||
message_type = kwargs.get('message_type', 'chat')
|
||||
|
||||
if message_type == 'chat':
|
||||
return self.handle_chat_message(**kwargs) # Free
|
||||
elif message_type == 'generate_report':
|
||||
return self.handle_report_generation(**kwargs) # Paid
|
||||
else:
|
||||
raise ValueError(f"Unknown message type: {message_type}")
|
||||
|
||||
def handle_chat_message(self, **kwargs):
|
||||
# No wallet deduction for chat
|
||||
request_obj.cost = 0
|
||||
# Process free interaction
|
||||
return self.process_chat_response(response_data, request_obj)
|
||||
|
||||
def handle_report_generation(self, **kwargs):
|
||||
# Set cost for report generation
|
||||
request_obj.cost = 8.0
|
||||
# Process paid interaction (wallet deducted only after success)
|
||||
return self.process_report_response(response_data, request_obj)
|
||||
```
|
||||
|
||||
### Comprehensive Error Handling Pattern
|
||||
|
||||
```python
|
||||
# 5 Whys error handling pattern
|
||||
def process_response(self, response_data, request_obj):
|
||||
try:
|
||||
request_obj.status = 'processing'
|
||||
request_obj.save()
|
||||
|
||||
# Extract and validate response
|
||||
result = response_data.get('output', '')
|
||||
success = bool(result) and response_data.get('success', True)
|
||||
|
||||
# Create response object
|
||||
response_obj, created = ModelResponse.objects.get_or_create(
|
||||
request=request_obj,
|
||||
defaults={'success': success, 'processing_time': response_data.get('processing_time', 0)}
|
||||
)
|
||||
|
||||
if success:
|
||||
response_obj.result_data = result
|
||||
response_obj.save()
|
||||
|
||||
# Only deduct balance after confirmed success
|
||||
request_obj.user.deduct_balance(
|
||||
request_obj.cost,
|
||||
f"Agent processing - {request_obj.agent.name}",
|
||||
request_obj.agent.slug
|
||||
)
|
||||
request_obj.status = 'completed'
|
||||
else:
|
||||
request_obj.status = 'failed'
|
||||
response_obj.error_message = "Processing failed"
|
||||
response_obj.save()
|
||||
|
||||
request_obj.processed_at = timezone.now()
|
||||
request_obj.save()
|
||||
|
||||
return response_obj
|
||||
|
||||
except Exception as e:
|
||||
# Always handle errors gracefully
|
||||
request_obj.status = 'failed'
|
||||
request_obj.save()
|
||||
|
||||
# Log the error for debugging
|
||||
print(f"Agent {self.agent_slug} error: {e}")
|
||||
raise Exception(f"Failed to process response: {e}")
|
||||
```
|
||||
|
||||
### Status Tracking Pattern *(Request Lifecycle Management)*
|
||||
|
||||
```python
|
||||
# 5 Whys status flow pattern
|
||||
# 1. Initial state
|
||||
request_obj.status = 'pending'
|
||||
|
||||
# 2. Start processing
|
||||
request_obj.status = 'processing'
|
||||
request_obj.save()
|
||||
|
||||
# 3. Complete or fail
|
||||
try:
|
||||
# ... do processing ...
|
||||
request_obj.status = 'completed'
|
||||
except Exception:
|
||||
request_obj.status = 'failed'
|
||||
finally:
|
||||
request_obj.processed_at = timezone.now()
|
||||
request_obj.save()
|
||||
```
|
||||
|
||||
### Template URL Namespace Pattern *(Prevents 404 Errors)*
|
||||
|
||||
```html
|
||||
<!-- ❌ Wrong - causes NoReverseMatch errors -->
|
||||
<a href="{% url 'wallet' %}">Wallet</a>
|
||||
|
||||
<!-- ✅ Correct - 5 Whys pattern (always use namespaces) -->
|
||||
<a href="{% url 'core:wallet' %}">Wallet</a>
|
||||
<a href="{% url 'core:homepage' %}">Home</a>
|
||||
<a href="{% url 'authentication:login' %}">Login</a>
|
||||
```
|
||||
|
||||
### Database Index Pattern *(Performance Optimization)*
|
||||
|
||||
```python
|
||||
# 5 Whys database optimization patterns
|
||||
class AgentRequest(BaseAgentRequest):
|
||||
session_id = models.CharField(max_length=100, default=uuid.uuid4, db_index=True)
|
||||
|
||||
class Meta:
|
||||
indexes = [
|
||||
models.Index(fields=['session_id']),
|
||||
models.Index(fields=['user', 'chat_active']),
|
||||
models.Index(fields=['status', 'created_at']),
|
||||
]
|
||||
```
|
||||
|
||||
**🎯 Key Takeaway:** The 5 Whys Analyzer's success comes from these robust patterns. Apply them to your agents for maximum reliability and user satisfaction.
|
||||
|
||||
---
|
||||
|
||||
## Step 1: Create Django App
|
||||
|
||||
### 1.1 Create the App
|
||||
@ -304,12 +510,9 @@ class PdfAnalyzerProcessView(View):
|
||||
language=language,
|
||||
)
|
||||
|
||||
# Deduct from wallet
|
||||
request.user.deduct_balance(
|
||||
agent.price,
|
||||
f"PDF Analyzer request for {pdf_file.name}",
|
||||
'pdf-analyzer'
|
||||
)
|
||||
# ⚠️ WARNING: This violates 5 Whys pattern!
|
||||
# Better to deduct ONLY after successful processing
|
||||
# Consider implementing delayed deduction pattern for reliability
|
||||
|
||||
# Process request
|
||||
processor = PdfAnalyzerProcessor()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user