Fixes 4 bugs preventing intake blocks from working: 1. Chat API validation: Add 'nudge' to message type enum, allow empty content for streaming messages 2. AI chat recognition: Add P3 intake intents (intake_status, risico_query, diagnose_query, intake_navigeer) to system prompt with triggers, entities, and JSON examples 3. Artifact rendering: Add intake block imports and switch cases to artifact-container.tsx 4. API 400 error: Convert null to undefined for optional Zod params (searchParams.get returns null, Zod .optional() expects undefined) Also adds: - Testplan for E2E testing (60+ test cases) - Session log with lessons learned and new intent checklist Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
8.7 KiB
Session Log — 03-02-2026
Project: Cortex Intake Blocks MVP Sessie: Testing, Bugfixes & Integration Tijd: Avond
Samenvatting
Deze sessie richtte zich op het volledig werkend krijgen van de Intake Blocks MVP:
- Testplan maken
- Meerdere kritieke bugs oplossen
- Intake intents integreren in de volledige flow
Eindresultaat: ✅ Alle 4 intake intents werken nu volledig
Bugs Opgelost
Bug 1: Chat API Validatiefout
Symptoom: Chat API error: Error: Validatiefout
Oorzaak: Twee issues in Zod schema:
nudgetype ontbrak inChatMessageSchema.typeenumcontent: z.string().min(1)blokkeerde lege streaming berichten
Fix: app/api/cortex/chat/route.ts
// VOOR:
type: z.enum(['user', 'assistant', 'system', 'error']),
content: z.string().min(1),
// NA:
type: z.enum(['user', 'assistant', 'system', 'error', 'nudge']),
content: z.string(), // Allow empty
Bug 2: AI Chat herkent intake intents niet
Symptoom: Chat AI vraagt "Wil je het dossier opzoeken?" ipv navigeren
Oorzaak: Intake intents (intake_status, risico_query, diagnose_query, intake_navigeer) ontbraken in de AI system prompt.
Fix: app/api/cortex/chat/route.ts - System prompt uitgebreid met:
- P3 Intents sectie met 4 intake intents
- Triggers en entities per intent
- 4 voorbeelden (voorbeeld 9-12) met correcte JSON format
Bug 3: Intake blocks worden niet gerenderd
Symptoom: Console log toont "Opening artifact: intake_status" maar niets verschijnt
Oorzaak: artifact-container.tsx miste:
- Imports voor intake block components
- Switch cases in
renderArtifactBlock() - Titles in
getArtifactTitle()
Fix: components/cortex/artifacts/artifact-container.tsx
// Imports toegevoegd:
import { IntakeStatusBlock } from '../blocks/intake-status-block';
import { RisicoBlock } from '../blocks/risico-block';
import { DiagnoseBlock } from '../blocks/diagnose-block';
// Switch cases toegevoegd:
case 'intake_status':
return <IntakeStatusBlock key={artifact.id} prefill={artifact.prefill} />;
case 'risico_query':
return <RisicoBlock key={artifact.id} prefill={artifact.prefill} />;
case 'diagnose_query':
return <DiagnoseBlock key={artifact.id} prefill={artifact.prefill} />;
Bug 4: API retourneert 400 Bad Request
Symptoom: /api/cortex/intake/status?patientId=xxx → 400 error
Oorzaak: searchParams.get('intakeId') retourneert null, maar Zod .optional() verwacht undefined.
Fix: Alle 3 intake API routes:
// VOOR:
const intakeId = searchParams.get('intakeId');
// NA:
const intakeId = searchParams.get('intakeId') || undefined;
Bestanden:
app/api/cortex/intake/status/route.tsapp/api/cortex/intake/risico/route.tsapp/api/cortex/intake/diagnose/route.ts
Lessons Learned
1. Zod + URLSearchParams
searchParams.get() retourneert null, niet undefined. Gebruik altijd || undefined voor optionele Zod parameters.
2. AI Chat System Prompt
Nieuwe intents moeten expliciet in de system prompt staan met:
- Intent naam
- Trigger voorbeelden
- Entities
- Voorbeeld JSON output
3. Artifact Rendering
Nieuwe blocks vereisen wijzigingen op 3 plekken in artifact-container.tsx:
- Import statement
- Switch case in
renderArtifactBlock() - Title in
getArtifactTitle()
4. Intent Flow
Een intent doorloopt meerdere lagen - elke laag moet de intent kennen:
- Reflex classifier (patterns)
- AI chat (system prompt)
- Action parser (routing)
- Artifact container (rendering)
Checklist: Nieuwe Intent Toevoegen
Stap 1: Types & Patterns
lib/cortex/types.ts
// 1. Voeg toe aan CortexIntent type
type CortexIntent =
| 'bestaande_intent'
| 'nieuwe_intent' // ← nieuw
| 'unknown';
// 2. Voeg toe aan BLOCK_CONFIGS (als het een block is)
nieuwe_intent: {
type: 'nieuwe_intent',
title: 'Nieuwe Intent',
size: 'md',
icon: 'IconName',
},
lib/cortex/reflex-classifier.ts
// Voeg patterns toe aan REFLEX_PATTERNS
nieuwe_intent: [
{ pattern: /^trigger woorden/i, weight: 1.0 },
{ pattern: /^alternatieve trigger/i, weight: 0.9 },
],
Stap 2: AI Chat Integration
app/api/cortex/chat/route.ts
// In buildSystemPrompt(), voeg toe aan intents lijst:
- **nieuwe_intent** — Beschrijving
- Triggers: "woord1", "woord2", "woord3"
- Entities: entity1 (type), entity2 (type)
- Actie: Wat er gebeurt
// Voeg een voorbeeld toe:
### Voorbeeld N: Nieuwe Intent
**User:**
"trigger zin"
**AI Response:**
"Korte bevestiging.
\`\`\`json
{
"type": "action",
"intent": "nieuwe_intent",
"entities": { ... },
"confidence": 0.98,
"artifact": {
"type": "nieuwe_intent",
"prefill": { ... }
}
}
\`\`\`"
Stap 3: Action Parser
lib/cortex/action-parser.ts
// 1. Voeg toe aan VALID_INTENTS array
const VALID_INTENTS = [
'bestaande_intent',
'nieuwe_intent', // ← nieuw
];
// 2. Voeg toe aan routeIntentToArtifact()
case 'nieuwe_intent':
return {
type: 'nieuwe_intent',
prefill: { ...entities },
};
Stap 4: API Route (als data nodig is)
app/api/cortex/[domain]/route.ts
// Query params validatie - let op null → undefined!
const optionalParam = searchParams.get('param') || undefined;
// Zod schema
const QuerySchema = z.object({
requiredParam: z.string().uuid(),
optionalParam: z.string().optional(), // NOT .nullable()!
});
Stap 5: Block Component
components/cortex/blocks/nieuwe-intent-block.tsx
export function NieuweIntentBlock({ prefill }: Props) {
const { patientId, hasPatientContext } = useIntakeContext(prefill);
const { data, isLoading, error } = useBlockData<ResponseType>({
endpoint: '/api/cortex/...',
params: { patientId },
enabled: hasPatientContext,
});
if (!hasPatientContext) return <BlockEmpty ... />;
if (isLoading) return <BlockLoading ... />;
if (error) return <BlockError ... />;
return <BlockContainer>...</BlockContainer>;
}
Stap 6: Artifact Container
components/cortex/artifacts/artifact-container.tsx
// 1. Import
import { NieuweIntentBlock } from '../blocks/nieuwe-intent-block';
// 2. renderArtifactBlock() switch case
case 'nieuwe_intent':
return <NieuweIntentBlock key={artifact.id} prefill={artifact.prefill} />;
// 3. getArtifactTitle() switch case
case 'nieuwe_intent':
return 'Nieuwe Intent Titel';
Stap 7: Navigatie Intent (optioneel)
Als de intent navigeert ipv een block toont:
components/cortex/command-center/command-center.tsx
// In useEffect voor pendingAction:
if (pendingAction.intent === 'nieuwe_navigeer') {
// Extract target
const target = pendingAction.entities.navigationTarget;
// Navigate
router.push(`/epd/path/${target}`);
// Toast feedback
toast({ title: 'Navigeren...', description: `Naar ${target}` });
// Clear action
setPendingAction(null);
return;
}
Checklist: Nieuwe UI Block
-
Block component maken
components/cortex/blocks/xxx-block.tsx- Gebruik shared components:
BlockContainer,BlockLoading,BlockError,BlockEmpty - Gebruik hooks:
useBlockData,useIntakeContext
-
API route maken (indien nodig)
app/api/cortex/[domain]/route.ts- Let op:
|| undefinedvoor optionele params!
-
Artifact container updaten
- Import toevoegen
- Switch case toevoegen
- Title toevoegen
-
Types updaten
BLOCK_CONFIGSintypes.ts
Gewijzigde Bestanden (Totaal)
| Bestand | Wijziging |
|---|---|
app/api/cortex/chat/route.ts |
Zod fix + intake intents in prompt |
app/api/cortex/intake/status/route.ts |
null → undefined fix + logging |
app/api/cortex/intake/risico/route.ts |
null → undefined fix |
app/api/cortex/intake/diagnose/route.ts |
null → undefined fix |
lib/cortex/chat-api.ts |
Betere error logging |
lib/cortex/hooks/use-block-data.ts |
Error details logging |
components/cortex/artifacts/artifact-container.tsx |
Intake blocks import + render |
docs/.../testplan-intake-blocks-mvp.md |
Nieuw testplan |
docs/.../session-log-2026-02-03.md |
Deze log |
Eindstatus
| Component | Status |
|---|---|
intake_status intent |
✅ Werkt |
risico_query intent |
✅ Werkt |
diagnose_query intent |
✅ Werkt |
intake_navigeer intent |
✅ Werkt |
| IntakeStatusBlock | ✅ Toont data |
| RisicoBlock | ✅ Toont data |
| DiagnoseBlock | ✅ Toont data |
| Navigatie | ✅ Werkt met toast |
Volgende Stappen
- E2E tests uitvoeren volgens testplan
- Performance monitoring (API response times)
- Voice input testen
- Fase 3b intents toevoegen (kindcheck, anamnese, behandeladvies)