Canonical Handlers Architecture

Last Updated: October 6, 2025 Epic: GREAT-4C - Remove Hardcoded User Context Status: Production Ready


Overview

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.


Handler Capabilities

1. Identity Handler (_handle_identity_query)

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:

2. Temporal Handler (_handle_temporal_query)

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."

3. Status Handler (_handle_status_query)

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"
    }

4. Priority Handler (_handle_priority_query)

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"
    }

5. Guidance Handler (_handle_guidance_query)

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"

Multi-User Architecture

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"

Spatial Intelligence

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:


Error Handling

All handlers gracefully degrade with three main patterns:

1. Service Failures

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

2. Missing Data

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"
    }

3. Context Unavailable

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:


Caching

Two-layer cache reduces file I/O and improves performance:

1. File-level (PiperConfigLoader)

2. Session-level (UserContextService)

Performance Impact:

Cache Monitoring:

# Check cache performance
curl http://localhost:8001/api/admin/piper-config-cache-metrics

Testing

Comprehensive test coverage across all dimensions:

Spatial Intelligence Tests

Error Handling Tests

Multi-User Tests

Cache Performance Tests

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

Implementation Details

Handler Registration

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

Response Format

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.)
}

Performance Characteristics



Future Enhancements

Potential Improvements

  1. Enhanced PIPER.md Parsing: Structured parsing with schema validation
  2. Dynamic Handler Registration: Plugin-based handler system
  3. Advanced Spatial Patterns: More granular response control
  4. Predictive Caching: Pre-load likely queries based on patterns

Monitoring Recommendations

  1. Handler Performance: Track response times by handler
  2. Error Rates: Monitor failure scenarios and recovery
  3. Cache Effectiveness: Optimize cache policies based on usage
  4. User Satisfaction: Gather feedback on response quality

Status: ✅ Production ready - All handlers validated and tested

Last Updated: October 6, 2025 (GREAT-4C completion)