Files
triqura-ecd/docs/swift/implementation-e5-s1-action-routing.md
colinislit 14a9d34337 feat(swift): voeg chat orchestration toe (E5)
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>
2025-12-27 22:44:18 +01:00

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_query
  • create_appointment
  • cancel_appointment
  • reschedule_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:

  1. Import routeIntentToArtifact from action-parser
  2. Add openArtifact to store hooks
  3. Replace legacy openBlock logic 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

  1. E5.S2: Update chat API prompt to include agenda intent examples
  2. E5.S3: Add error state handling with fallback links
  3. E6: Manual QA testing of complete agenda flow

💡 Lessons Learned

  1. Artifact System: Modern approach using openArtifact() is cleaner than legacy openBlock()
  2. Centralized Routing: Single function makes intent mapping maintainable and testable
  3. Validation Early: Checking required entities in routing prevents incomplete forms
  4. Confidence Thresholds: 0.7 threshold balances automation with user control
  5. 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)