Zum Inhalt springen
EN DE

Boss Fight: Persistenter Chat mit Reload

Du baust ein Chat-System mit vollstaendigem Persistence-Cycle — ein Programm, das eine Chat-ID generiert, Nachrichten validiert, nach jedem LLM-Call speichert und nach einem simulierten Reload den Verlauf laedt und das Gespraech nahtlos fortsetzt.

Dein System soll sich so verhalten:

--- Neuer Chat gestartet: a1b2c3d4... ---
[Request 1] User: Was ist TypeScript?
[Validation] OK
[Saved] 2 messages
Assistant: TypeScript ist eine typisierte Erweiterung von JavaScript...
[Request 2] User: Nenne 3 Vorteile.
[Validation] OK
[Saved] 4 messages
Assistant: 1. Statische Typen fangen Fehler frueh ab...
--- Simulierter Reload ---
[Loaded] 4 messages für Chat a1b2c3d4...
[Request 3] User: Welchen Vorteil findest Du am wichtigsten?
[Validation] OK
[Saved] 6 messages
Assistant: Basierend auf unserer Diskussion über TypeScript...
--- Ungueltige Nachricht ---
[Request 4] Invalid: role "admin" not allowed
[Blocked] Message nicht gespeichert.

Dieses Projekt kombiniert alle vier Bausteine aus Level 4:

Chat ID fliesst in Validation, bei valid Load History, generateText, onFinish, Persistence, Database; bei invalid Error
  1. Chat ID generieren (Challenge 4.2) — Beim Start wird eine UUID generiert. Alle Messages gehören zu dieser ID.
  2. Message Validation (Challenge 4.4) — Jeder Request wird vor der Verarbeitung gegen ein Zod Schema validiert. Ungueltige Messages werden abgelehnt und nicht gespeichert.
  3. onFinish Callback (Challenge 4.1) — Im onFinish werden die neuen Messages (User + Assistant) automatisch gespeichert und der Token-Verbrauch geloggt.
  4. Persistence (Challenge 4.3) — Messages werden in einer In-Memory “DB” (Map) gespeichert. Nach einem simulierten Reload wird der Verlauf geladen und der Chat fortgesetzt.
  5. Simulierter Reload — Zwischen den Requests wird ein “Reload” simuliert: Die Laufzeitvariablen werden zurueckgesetzt, nur die “DB” bleibt. Der Chat muss trotzdem nahtlos weitergehen.
  6. Token-Tracking — Der onFinish Callback loggt den Token-Verbrauch pro Request.
  7. Fehlerfall testen — Mindestens ein ungueltiger Request wird gesendet und korrekt abgelehnt.
  8. Vollstaendiger Verlauf — Nach allen Requests zeigt ein Log den kompletten Chat-Verlauf mit Rollen und Message-Previews.

Erstelle eine Datei boss-fight-4.ts:

import { generateText } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
// --- Datenbank (simuliert) ---
// TODO: Map als In-Memory DB
// --- Schemas ---
// TODO: Zod Schema für Messages und Chat-Requests
// --- DB-Funktionen ---
// TODO: saveMessages(chatId, messages)
// TODO: loadMessages(chatId)
// --- Validation ---
// TODO: validate(body) — gibt { success, data?, error? } zurück
// --- Chat-Funktion ---
// TODO: chat(chatId, userMessage) — der vollständige Cycle:
// 1. Validate
// 2. Load history
// 3. generateText mit onFinish (Save + Token-Log)
// 4. Return result
// --- Ausfuehrung ---
// Phase 1: Neuer Chat
// TODO: Chat ID generieren
// TODO: Erste Nachricht senden
// TODO: Zweite Nachricht senden
// Phase 2: Simulierter Reload
// TODO: Laufzeitvariablen zuruecksetzen (nur DB bleibt)
// TODO: Verlauf laden und loggen
// TODO: Dritte Nachricht senden (Chat geht weiter)
// Phase 3: Fehlerfall
// TODO: Ungueltigen Request senden (z.B. role: "admin")
// TODO: Sicherstellen, dass er abgelehnt wird
// Phase 4: Verlauf anzeigen
// TODO: Alle Messages des Chats loggen

Ausfuehren mit: npx tsx boss-fight-4.ts

Dein Boss Fight ist bestanden, wenn:

  • Eine Chat ID wird beim Start generiert und für alle Requests verwendet
  • Jeder Request wird vor der Verarbeitung gegen ein Zod Schema validiert
  • Ungueltige Messages werden abgelehnt und nicht in der DB gespeichert
  • onFinish speichert Messages automatisch nach jeder Completion
  • onFinish loggt den Token-Verbrauch pro Request
  • Nach einem simulierten “Reload” wird der Verlauf korrekt geladen
  • Der Chat setzt nach dem Reload nahtlos fort (LLM bezieht sich auf fruehere Messages)
  • Am Ende zeigt ein Log den vollstaendigen Verlauf mit allen Messages
Hinweis 1: Den Reload simulieren

Du brauchst keinen echten Server-Neustart. Erstelle einfach eine neue Variable für den Verlauf (let currentHistory = []) und setze sie auf leer. Dann lade den Verlauf mit loadMessages(chatId) neu aus der Map. Das simuliert, was bei einem echten Reload passiert: Der Arbeitsspeicher ist leer, aber die DB hat die Daten.

Hinweis 2: Validation und Chat-Funktion trennen

Baue die Validation als separate Funktion, nicht direkt in der Chat-Logik. Deine chat(chatId, userMessage)-Funktion sollte zuerst validate() aufrufen. Wenn die Validation fehlschlaegt, gibt die Funktion frueh zurück — ohne DB-Zugriff und ohne LLM-Call. So ist klar: Nur validierte Messages erreichen generateText.

Hinweis 3: Messages-Array richtig aufbauen

Beim Fortsetzen nach dem Reload muss das Messages-Array alle bisherigen Messages enthalten — nicht nur die neue. Lade den Verlauf mit loadMessages(chatId), haenge die neue User-Message an, und uebergib das gesamte Array an generateText. Im onFinish speicherst Du dann das komplette Array (inklusive der neuen Assistant-Antwort) zurück in die DB.

Part of AI Learning — free courses from prompt to production. Jan on LinkedIn