Last Updated: October 6, 2025 Epic: GREAT-4C - Remove Hardcoded User Context Status: Production Ready
The 5 canonical handlers provide natural language query responses for standup/basic queries with multi-user support, spatial intelligence, and robust error handling. They form the core of Piper Morgan’s conversational interface for common user queries.
Purpose: “Who are you?” queries Spatial patterns: EMBEDDED (brief) to GRANULAR (full capabilities) Data source: Static identity info Error handling: Always available (no external dependencies)
Response Examples:
Purpose: “What day is it?” / time queries Spatial patterns: Date only (EMBEDDED) to full calendar (GRANULAR) Data sources: System time + calendar integration Error handling: Works without calendar service
Response Examples:
Error Handling:
try:
calendar_data = await calendar_adapter.get_temporal_summary()
# Process calendar data
except Exception as e:
logger.warning(f"Calendar service unavailable: {e}")
if spatial_pattern != "EMBEDDED":
message += "\n\nNote: I couldn't access your calendar right now."
Purpose: “What am I working on?” queries Spatial patterns: Brief list (EMBEDDED) to detailed status (GRANULAR) Data source: User’s PIPER.md projects Error handling: Graceful fallback if PIPER.md missing
Response Examples:
Error Handling:
try:
user_context = await user_context_service.get_user_context(session_id)
except Exception as e:
return {
"message": "I'm having trouble accessing your configuration right now. "
"Your PIPER.md file may be missing or unreadable. "
"Would you like help setting it up?",
"error": "config_unavailable",
"action_required": "setup_piper_config"
}
Purpose: “What’s my top priority?” queries Spatial patterns: Single priority (EMBEDDED) to full breakdown (GRANULAR) Data source: User’s PIPER.md priorities Error handling: Offers to help configure if empty
Response Examples:
Empty Data Handling:
if not priorities:
return {
"message": "You don't have any priorities configured in your PIPER.md yet. "
"Would you like me to help you set up your priority list?",
"action_required": "configure_priorities"
}
Purpose: “What should I focus on?” queries Spatial patterns: Brief (EMBEDDED) to comprehensive guidance (GRANULAR) Data sources: Time of day + user context Error handling: Falls back to generic time-based guidance
Response Examples:
Fallback Pattern:
user_context = None
try:
user_context = await user_context_service.get_user_context(session_id)
except Exception as e:
logger.warning(f"Using generic guidance, user context unavailable: {e}")
# Provide time-based guidance with or without user context
if user_context and user_context.organization:
focus = f"Morning work - focus on {user_context.organization} priorities"
else:
focus = "Morning work - perfect time for deep focus and complex problem-solving"
Each handler uses UserContextService to load user-specific data:
user_context = await user_context_service.get_user_context(session_id)
# Returns: organization, projects, priorities for this user
Key Principles:
Before GREAT-4C (WRONG):
# This broke multi-user support!
if config and "VA" in str(config.values()):
focus = "VA Q4 onramp implementation"
After GREAT-4C (CORRECT):
# This works for any user!
if user_context and user_context.organization:
focus = f"Focus on {user_context.organization} priorities"
Handlers adjust response detail based on spatial pattern:
spatial_pattern = intent.spatial_context.get('pattern') if hasattr(intent, 'spatial_context') else None
if spatial_pattern == "GRANULAR":
return detailed_response # 450-550 chars
elif spatial_pattern == "EMBEDDED":
return brief_response # 15-30 chars
else:
return standard_response # 100-350 chars
Use Cases:
Performance Impact:
All handlers gracefully degrade with three main patterns:
Continue with fallback data when external services fail:
try:
external_data = await external_service.call()
# Use external data
except Exception as e:
logger.warning(f"Service unavailable: {e}")
# Continue with basic response
Offer to help configure when user data is missing:
if not user_data:
return {
"message": "You don't have X configured. Would you like help setting it up?",
"action_required": "configure_X"
}
Provide generic responses when user context fails:
user_context = None
try:
user_context = await get_context()
except Exception:
pass # Continue with generic response
# Adapt response based on context availability
if user_context:
return personalized_response()
else:
return generic_response()
User Experience Benefits:
Two-layer cache reduces file I/O and improves performance:
Performance Impact:
Cache Monitoring:
# Check cache performance
curl http://localhost:8001/api/admin/piper-config-cache-metrics
Comprehensive test coverage across all dimensions:
Test Execution:
# Run all handler tests
pytest tests/intent/test_handler_error_handling.py -v
python3 dev/2025/10/06/test_all_handlers_spatial.py
Handlers are registered in the CanonicalHandlers class:
async def handle(self, intent: Intent, session_id: str) -> Dict:
"""Route to appropriate canonical handler"""
if intent.category == IntentCategoryEnum.IDENTITY:
return await self._handle_identity_query(intent, session_id)
elif intent.category == IntentCategoryEnum.TEMPORAL:
return await self._handle_temporal_query(intent, session_id)
# ... etc
All handlers return consistent response structure:
{
"message": "User-facing response text",
"intent": {
"category": "handler_category",
"action": "handler_action",
"confidence": 1.0,
"context": {
# Handler-specific context data
}
},
"spatial_pattern": "GRANULAR|EMBEDDED|None",
"requires_clarification": False,
# Handler-specific fields (error, action_required, etc.)
}
dev/2025/10/06/ - Implementation detailstests/intent/ - Comprehensive test coverageStatus: ✅ Production ready - All handlers validated and tested
Last Updated: October 6, 2025 (GREAT-4C completion)