Epic 5 compleet: Chat orchestration voor Swift Agenda Planning. Alle agenda intents worden nu correct gerouteerd naar AgendaBlock met user-friendly error handling en fallback opties. E5.S1 - Action Routing (2 SP) - routeIntentToArtifact() functie in action-parser - Maps agenda intents naar juiste AgendaBlock mode - Confidence threshold enforcement (< 0.7 → fallback) - Required entity validation (patient voor create, identifier voor reschedule) - Command-input gebruikt nieuwe routing ipv legacy openBlock - Migratie naar modern artifact systeem (openArtifact) E5.S2 - Chat Prompt Update (2 SP) - 4 agenda intents toegevoegd aan Swift chat system prompt - agenda_query: afspraken opvragen op datumrange - create_appointment: nieuwe afspraak maken (required: patient, datetime) - cancel_appointment: afspraak annuleren (disambiguation support) - reschedule_appointment: afspraak verzetten (required: identifier) - Entity extraction rules gedocumenteerd (dateRange, datetime, identifier) - 4 complete voorbeelden met JSON action format - Clarification questions voor incomplete data - Prompt size: ~325 → ~525 regels (+60%) E5.S3 - Error States (2 SP) - AgendaErrorState component voor full-page errors - AgendaErrorAlert component voor inline form errors - getUserFriendlyMessage() vertaalt technical → user-friendly Dutch - Auto-redirect bij auth errors (401 → /login) - Fallback link naar /epd/agenda in alle error states - Context-aware messaging (query/create/cancel/reschedule) - Retry functionaliteit voor recoverable errors - Dev-only technical details collapsible Error message mapping: - 401 → "Je sessie is verlopen. Log opnieuw in." + auto-redirect - 403 → "Je hebt geen toegang tot deze afspraak." - 404 → "De gevraagde afspraak kon niet worden gevonden." - 500 → "Er ging iets mis op de server. Probeer het opnieuw." - Network → "Geen internetverbinding. Controleer je netwerkverbinding." - Timeout → "De aanvraag duurde te lang. Probeer het opnieuw." Components updated: - command-input: gebruikt routeIntentToArtifact + openArtifact - agenda-create-form: gebruikt AgendaErrorAlert met fallback link - chat/route: uitgebreide system prompt met agenda sectie Nieuwe files: - lib/swift/action-parser.ts: routeIntentToArtifact() functie - components/swift/artifacts/blocks/agenda-error-state.tsx (225 regels) - docs/swift/implementation-e5-s1-action-routing.md - docs/swift/implementation-e5-s2-chat-prompt.md - docs/swift/implementation-e5-s3-error-states.md Documentatie: - Bouwplan bijgewerkt: Epic 5 → Done - 3 implementation docs met API specs en testing scenarios - Error handling best practices gedocumenteerd Progress: 48 SP / 51 SP (94%) - Epic 6 (QA) remaining 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.5 KiB
Epic 5.S1 Implementation: Action Routing
Story: E5.S1 - Action routing Date: 2025-12-27 Status: ✅ Complete Story Points: 2 SP
🎯 Objective
Implement intent routing logic that maps agenda intents to the AgendaBlock artifact with the appropriate mode and prefill data.
📝 Implementation Summary
1. Updated Action Parser Schemas
File: lib/swift/action-parser.ts
Added agenda intents to validation schemas:
agenda_querycreate_appointmentcancel_appointmentreschedule_appointment
2. Created Intent Routing Function
Function: routeIntentToArtifact(intent, entities, confidence)
Purpose: Maps intents to artifact configurations with:
- Artifact type
- Title
- Prefill data
Logic:
if (confidence < 0.7) return null; // Trigger fallback
switch (intent) {
case 'agenda_query':
return { type: 'agenda_query', title: 'Agenda', prefill: { dateRange } };
case 'create_appointment':
if (!patientName && !patientId) return null; // Missing required entity
return { type: 'create_appointment', title: 'Nieuwe afspraak', prefill: {...} };
case 'cancel_appointment':
return { type: 'cancel_appointment', title: 'Afspraak annuleren', prefill: {...} };
case 'reschedule_appointment':
if (!identifier) return null; // Need to know which appointment
return { type: 'reschedule_appointment', title: 'Afspraak verzetten', prefill: {...} };
// ... other intents (dagnotitie, zoeken, overdracht)
}
Key Features:
- ✅ Confidence threshold (0.7) enforcement
- ✅ Required entity validation (patient for create, identifier for reschedule)
- ✅ Returns null to trigger clarification when needed
- ✅ Proper prefill data extraction for each intent
3. Updated Command Input
File: components/swift/command-center/command-input.tsx
Changes:
- Import
routeIntentToArtifactfrom action-parser - Add
openArtifactto store hooks - Replace legacy
openBlocklogic with routing:
// OLD (direct block opening):
if (intent !== 'unknown' && confidence >= 0.5) {
openBlock(intent as BlockType, entities);
}
// NEW (routing with artifact system):
const artifactConfig = routeIntentToArtifact(intent, entities, confidence);
if (artifactConfig) {
openArtifact({
type: artifactConfig.type,
title: artifactConfig.title,
prefill: artifactConfig.prefill,
});
}
🔑 Key Routing Rules
| Intent | Artifact Type | Required Entities | Mode |
|---|---|---|---|
agenda_query |
agenda_query |
None | List view with date filter |
create_appointment |
create_appointment |
patientName OR patientId |
Create form |
cancel_appointment |
cancel_appointment |
None | Cancel view (may need disambiguation) |
reschedule_appointment |
reschedule_appointment |
identifier |
Reschedule form |
📊 Confidence Thresholds
| Confidence | Action | Example |
|---|---|---|
| ≥ 0.7 | Open artifact directly | "afspraken vandaag" → AgendaBlock opens |
| < 0.7 | Show fallback picker | Low confidence → User chooses intent manually |
| Missing required entity | Show fallback picker | "maak afspraak" (no patient) → Clarification needed |
🔄 Data Flow
User Input
↓
Intent Classification API (/api/intent/classify)
↓
{ intent, entities, confidence }
↓
routeIntentToArtifact()
↓
Artifact Config { type, title, prefill } OR null
↓
openArtifact() OR openBlock('fallback')
↓
AgendaBlock renders with prefilled data
📁 Files Modified
lib/swift/action-parser.ts
├── Updated ActionSchema with agenda intents
├── Updated artifact type enum
├── Added routeIntentToArtifact() function
└── Updated validateArtifactType() for agenda intents
components/swift/command-center/command-input.tsx
├── Import routeIntentToArtifact
├── Use openArtifact from store
└── Replace direct block opening with routing logic
✅ Acceptance Criteria
| Criterion | Status | Notes |
|---|---|---|
| Agenda intents open AgendaBlock | ✅ | Via routing function |
| Correct mode selected | ✅ | Based on intent type |
| Prefill data passed correctly | ✅ | Mapped from entities |
| Confidence threshold enforced | ✅ | < 0.7 shows fallback |
| Required entities validated | ✅ | Returns null when missing |
| TypeScript type safety | ✅ | No compilation errors |
🧪 Testing Scenarios
Scenario 1: High Confidence Agenda Query
Input: "afspraken vandaag" Expected:
- Intent:
agenda_query - Confidence: ~0.95
- Result: AgendaBlock opens in list mode with today's date range
Scenario 2: Create Appointment with Patient
Input: "maak afspraak jan morgen 14:00" Expected:
- Intent:
create_appointment - Entities:
{ patientName: "jan", datetime: {...} } - Result: AgendaBlock opens in create mode with prefilled patient and time
Scenario 3: Create Appointment without Patient (Missing Entity)
Input: "maak afspraak morgen 14:00" Expected:
- Intent:
create_appointment - Entities:
{ datetime: {...} }(no patient) - Result: FallbackPicker opens (routing returns null due to missing required entity)
Scenario 4: Low Confidence
Input: "agenda ding morgen" Expected:
- Intent:
agenda_query(maybe) - Confidence: < 0.7
- Result: FallbackPicker opens (routing returns null due to low confidence)
Scenario 5: Reschedule with Identifier
Input: "verzet 14:00 naar 15:00" Expected:
- Intent:
reschedule_appointment - Entities:
{ identifier: {...}, newDatetime: {...} } - Result: AgendaBlock opens in reschedule mode
🚀 Next Steps
- E5.S2: Update chat API prompt to include agenda intent examples
- E5.S3: Add error state handling with fallback links
- E6: Manual QA testing of complete agenda flow
💡 Lessons Learned
- Artifact System: Modern approach using
openArtifact()is cleaner than legacyopenBlock() - Centralized Routing: Single function makes intent mapping maintainable and testable
- Validation Early: Checking required entities in routing prevents incomplete forms
- Confidence Thresholds: 0.7 threshold balances automation with user control
- Type Safety: TypeScript schemas ensure consistency across intent types
Implementation Status: ✅ Complete Ready for: E5.S2 (Chat prompt update) Estimated Testing Time: 15-20 minutes (manual testing with various inputs)