Boss Fight: Persistenter Chat mit Reload
Das Szenario
Abschnitt betitelt „Das Szenario“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 messagesAssistant: TypeScript ist eine typisierte Erweiterung von JavaScript...
[Request 2] User: Nenne 3 Vorteile.[Validation] OK[Saved] 4 messagesAssistant: 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 messagesAssistant: 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:
Anforderungen
Abschnitt betitelt „Anforderungen“- Chat ID generieren (Challenge 4.2) — Beim Start wird eine UUID generiert. Alle Messages gehören zu dieser ID.
- Message Validation (Challenge 4.4) — Jeder Request wird vor der Verarbeitung gegen ein Zod Schema validiert. Ungueltige Messages werden abgelehnt und nicht gespeichert.
- onFinish Callback (Challenge 4.1) — Im
onFinishwerden die neuen Messages (User + Assistant) automatisch gespeichert und der Token-Verbrauch geloggt. - 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.
- Simulierter Reload — Zwischen den Requests wird ein “Reload” simuliert: Die Laufzeitvariablen werden zurueckgesetzt, nur die “DB” bleibt. Der Chat muss trotzdem nahtlos weitergehen.
- Token-Tracking — Der
onFinishCallback loggt den Token-Verbrauch pro Request. - Fehlerfall testen — Mindestens ein ungueltiger Request wird gesendet und korrekt abgelehnt.
- Vollstaendiger Verlauf — Nach allen Requests zeigt ein Log den kompletten Chat-Verlauf mit Rollen und Message-Previews.
Starter-Code
Abschnitt betitelt „Starter-Code“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 loggenAusfuehren mit: npx tsx boss-fight-4.ts
Bewertungskriterien
Abschnitt betitelt „Bewertungskriterien“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
-
onFinishspeichert Messages automatisch nach jeder Completion -
onFinishloggt 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
Hinweise
Abschnitt betitelt „Hinweise“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.