Files
triqura-ecd/docs/intent/intake-intent-proces/session-log-2026-02-03.md
colinislit 601ad8c3f0 fix(cortex): integrate intake intents into full chat + artifact flow
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>
2026-02-04 00:07:10 +01:00

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:

  1. Testplan maken
  2. Meerdere kritieke bugs oplossen
  3. 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:

  1. nudge type ontbrak in ChatMessageSchema.type enum
  2. content: 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:

  1. Imports voor intake block components
  2. Switch cases in renderArtifactBlock()
  3. 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.ts
  • app/api/cortex/intake/risico/route.ts
  • app/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:

  1. Import statement
  2. Switch case in renderArtifactBlock()
  3. Title in getArtifactTitle()

4. Intent Flow

Een intent doorloopt meerdere lagen - elke laag moet de intent kennen:

  1. Reflex classifier (patterns)
  2. AI chat (system prompt)
  3. Action parser (routing)
  4. 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

  1. Block component maken

    • components/cortex/blocks/xxx-block.tsx
    • Gebruik shared components: BlockContainer, BlockLoading, BlockError, BlockEmpty
    • Gebruik hooks: useBlockData, useIntakeContext
  2. API route maken (indien nodig)

    • app/api/cortex/[domain]/route.ts
    • Let op: || undefined voor optionele params!
  3. Artifact container updaten

    • Import toevoegen
    • Switch case toevoegen
    • Title toevoegen
  4. Types updaten

    • BLOCK_CONFIGS in types.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

  1. E2E tests uitvoeren volgens testplan
  2. Performance monitoring (API response times)
  3. Voice input testen
  4. Fase 3b intents toevoegen (kindcheck, anamnese, behandeladvies)