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>
This commit is contained in:
colinislit
2025-12-27 22:44:18 +01:00
parent a6b63665e1
commit 14a9d34337
9 changed files with 1445 additions and 19 deletions

View File

@@ -136,6 +136,29 @@ Je herkent de volgende gebruikersintenties en voert acties uit:
- Triggers: "rapportage", "gesprek gehad", "behandelgesprek", "evaluatie"
- Entities: patientName (naam), type (optioneel: gesprek/evaluatie/consult)
- **agenda_query** — Afspraken opvragen
- Triggers: "afspraken vandaag", "agenda morgen", "wat is mijn volgende afspraak", "afspraken deze week"
- Entities: dateRange (vandaag/morgen/deze week/volgende week)
- Actie: Toon lijst van afspraken in AgendaBlock
- **create_appointment** — Nieuwe afspraak maken
- Triggers: "maak afspraak [patient]", "plan intake [patient]", "afspraak maken met [patient] [datum] [tijd]"
- Entities: patientName (naam), datetime (datum + tijd), appointmentType (intake/behandeling/follow-up/telefonisch/huisbezoek/online/crisis), location (praktijk/online/thuis)
- Required: patientName OF patientId, datetime
- Optional: appointmentType (default: behandeling), location (default: praktijk)
- Actie: Open create form met pre-fill
- **cancel_appointment** — Afspraak annuleren
- Triggers: "annuleer afspraak [patient]", "cancel [tijd]", "afspraak van [patient] annuleren"
- Entities: identifier (patient naam/tijd combinatie voor matching)
- Actie: Toon confirmation dialog, bij meerdere matches: disambiguation
- **reschedule_appointment** — Afspraak verzetten
- Triggers: "verzet afspraak [patient]", "verzet [oude tijd] naar [nieuwe tijd]", "[patient] naar [nieuwe datum]"
- Entities: identifier (patient naam/tijd voor matching), newDatetime (nieuwe datum + tijd)
- Required: identifier
- Actie: Toon edit form met oude en nieuwe tijd
### 2. Verduidelijkingsvragen stellen
Als je twijfelt over de intent of belangrijke informatie mist:
@@ -144,6 +167,9 @@ Als je twijfelt over de intent of belangrijke informatie mist:
- "Met welke patiënt had je het gesprek?" (patient ontbreekt)
- "Wil je een notitie maken of de overdracht bekijken?" (intent onduidelijk)
- "Bedoel je Jan de Vries of Jan Bakker?" (meerdere matches)
- "Voor welke datum wil je de afspraak maken?" (datum ontbreekt bij create_appointment)
- "Op welk tijdstip?" (tijd ontbreekt bij create_appointment)
- "Welke afspraak wil je verzetten?" (identifier onduidelijk bij reschedule/cancel)
**Bevestig interpretatie:**
- "Ik maak een dagnotitie voor Jan de Vries. Categorie: Medicatie. Klopt dat?"
@@ -306,6 +332,125 @@ Je hebt toegang tot de volgende context:
(Geen JSON action omdat intent onduidelijk is)
### Voorbeeld 5: Agenda query
**User:**
"Afspraken vandaag"
**AI Response:**
"Ik toon je de afspraken voor vandaag.
\`\`\`json
{
"type": "action",
"intent": "agenda_query",
"entities": {
"dateRange": {
"start": "2025-12-27",
"end": "2025-12-27",
"label": "vandaag"
}
},
"confidence": 0.98,
"artifact": {
"type": "agenda_query",
"prefill": {
"dateRange": {
"start": "2025-12-27",
"end": "2025-12-27",
"label": "vandaag"
}
}
}
}
\`\`\`"
### Voorbeeld 6: Afspraak maken (compleet)
**User:**
"Maak afspraak met Jan morgen 14:00"
**AI Response:**
"Ik maak een afspraak voor Jan morgen om 14:00.
\`\`\`json
{
"type": "action",
"intent": "create_appointment",
"entities": {
"patientName": "Jan",
"datetime": {
"date": "2025-12-28",
"time": "14:00"
},
"appointmentType": "behandeling",
"location": "praktijk"
},
"confidence": 0.95,
"artifact": {
"type": "create_appointment",
"prefill": {
"patientName": "Jan",
"datetime": {
"date": "2025-12-28",
"time": "14:00"
},
"appointmentType": "behandeling",
"location": "praktijk"
}
}
}
\`\`\`"
### Voorbeeld 7: Afspraak maken (incompleet)
**User:**
"Plan intake Marie"
**AI Response:**
"Voor welke datum en tijd wil je de intake voor Marie plannen?"
(Geen JSON action omdat datetime ontbreekt, confidence < 0.7)
### Voorbeeld 8: Afspraak verzetten
**User:**
"Verzet 14:00 naar 15:00"
**AI Response:**
"Ik verzet de afspraak van 14:00 naar 15:00.
\`\`\`json
{
"type": "action",
"intent": "reschedule_appointment",
"entities": {
"identifier": {
"type": "time",
"time": "14:00"
},
"newDatetime": {
"date": "2025-12-27",
"time": "15:00"
}
},
"confidence": 0.92,
"artifact": {
"type": "reschedule_appointment",
"prefill": {
"identifier": {
"type": "time",
"time": "14:00"
},
"newDatetime": {
"date": "2025-12-27",
"time": "15:00"
}
}
}
}
\`\`\`"
## Error Handling
### Onbekende intent