# AI-Call Looping Architektur ## Übersicht Dieses Dokument beschreibt die zentrale Architektur für **AI-Calls mit Looping-Funktionalität** nach cut-response. Es dokumentiert die verschiedenen Use Cases, ihre Looping-Mechanismen, Continuation-Prompt-Strukturen und die Unterschiede zwischen ihnen. **Fokus**: AI-Loop-Call mit automatischen Iterationen nach unvollständigen JSON-Responses. **Ziel**: Übersichtliche Grundlage für das Aufräumen und Vereinheitlichen der Looping-Logik. --- ## Use Cases Summary **Alle registrierten Use Cases**: 1. `section_content` - Section-Content-Generierung ✅ **Looping** 2. `chapter_structure` - Chapter-Struktur-Generierung ✅ **Looping** 3. `code_structure` - Code-Struktur-Generierung ✅ **Looping** 4. `code_content` - Code-Content-Generierung ✅ **Looping** **Vergleichstabelle**: | Use Case | Looping | Direct Return | Accumulation | Extraction | Prompt Builder | Template Konsistenz | Prompt Builder Parameter | |----------|---------|---------------|--------------|------------|----------------|---------------------|------------------------| | `section_content` | ✅ | ✅ | ❌ | ❌ | `buildSectionPromptWithContinuation()` | ✅ IDENTISCH | `section`, `contentParts`, `userPrompt`, `generationHint`, `allSections`, `sectionIndex`, `isAggregation`, `services` | | `chapter_structure` | ✅ | ✅ | ❌ | ❌ | `buildChapterStructurePromptWithContinuation()` | ✅ IDENTISCH | `userPrompt`, `contentParts`, `outputFormat`, `services` | | `code_structure` | ✅ | ✅ | ❌ | ❌ | ❌ **FEHLT** | ❌ PROBLEM | ❌ **FEHLT** | | `code_content` | ✅ | ✅ | ✅ | ❌ | `buildCodeContentPromptWithContinuation()` | ✅ IDENTISCH | `filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services` | **Hinweis zu Prompt-Builder-Parametern**: - Alle Prompt-Builder akzeptieren zusätzlich: `continuationContext: Dict[str, Any]` (wird automatisch übergeben) - Aktuell verwenden alle Builder `**kwargs` für Parameter-Extraktion - **Ziel-Architektur**: Explizite Parameter statt `**kwargs` (siehe "Ziel-Architektur" Abschnitt) --- ## Kern-System: `callAiWithLooping` **Location**: `gateway/modules/services/serviceAi/subAiCallLooping.py` **Zentrale Funktion**: `AiCallLooper.callAiWithLooping()` **Funktionsweise**: 1. **Erste Iteration**: Verwendet den initialen Prompt 2. **Weitere Iterationen (nach cut-response)**: - Prüft, ob JSON vollständig ist (String-basierte und Parsing-basierte Checks) - Wenn unvollständig: Baut Continuation-Prompt mit `promptBuilder` - Merged JSON-Fragmente mit Overlap-Detection - Wiederholt bis JSON vollständig oder kein Overlap gefunden **Loop-Bedingungen**: - **Stoppt wenn**: JSON vollständig, kein Overlap gefunden, Fehler, max Iterationen erreicht - **Weiter wenn**: JSON unvollständig, Overlap gefunden, Parsing fehlgeschlagen --- ## Ziel-Architektur: Harmonisiertes AI-Looping-System ### 1. Continuation-Context-Building **Aktueller Zustand**: - `buildContinuationContext(allSections, lastRawResponse, useCaseId)` extrahiert `template_structure` aus dem Response - `template_structure` wird aus dem Response abgeleitet, nicht explizit übergeben **⚠️ KRITISCH: Template-Struktur NICHT extrahieren** - **Template-Struktur wird NICHT aus dem initialen Prompt extrahiert** - **Template-Struktur wird NICHT aus dem Response extrahiert** - **Template-Struktur ist ein expliziter Parameter**, der beim Erstellen des initialen Prompts erstellt wird - **Derselbe Template-Struktur-Parameter** wird dann für den Continuation-Prompt verwendet - Dies garantiert **exakte Identität** zwischen initialem und Continuation-Prompt **Ziel-Architektur**: ```python from pydantic import BaseModel from typing import Optional, List, Dict, Any class ContinuationContext(BaseModel): """Pydantic model for continuation context information.""" section_count: int delivered_summary: str cut_off_element: Optional[str] = None element_before_cutoff: Optional[str] = None template_structure: Optional[str] = None # JSON structure template from initial prompt last_complete_part: Optional[str] = None incomplete_part: Optional[str] = None structure_context: Optional[str] = None last_raw_json: Optional[str] = None def buildContinuationContext( allSections: List[Dict[str, Any]], lastRawResponse: Optional[str] = None, useCaseId: Optional[str] = None, templateStructure: Optional[str] = None # NEU: Expliziter Parameter ) -> ContinuationContext: """ Build context information from accumulated sections for continuation prompt. Args: allSections: List of ALL sections accumulated across ALL iterations lastRawResponse: Raw JSON response from last iteration (can be broken/incomplete) useCaseId: Optional use case ID to determine expected JSON structure templateStructure: JSON structure template from initial prompt (MUST be identical) Returns: ContinuationContext: Pydantic model with all continuation context information """ # ... implementation ... return ContinuationContext( section_count=len(allSections), delivered_summary=delivered_summary, cut_off_element=cut_off_element, element_before_cutoff=element_before_cutoff, template_structure=templateStructure, # Explizit übergeben last_complete_part=last_complete_part, incomplete_part=incomplete_part, structure_context=structure_context, last_raw_json=lastRawResponse ) ``` **Vorteile**: - ✅ **Typsicherheit**: Pydantic-Modell statt Dict für bessere IDE-Support und Validierung - ✅ **Konsistenz**: Gleiche Architektur wie andere Modelle im System (z.B. Prompt-Args-Dataclasses) - ✅ **Validierung**: Automatische Validierung der Felder durch Pydantic - ✅ **Dokumentation**: Explizite Feld-Definitionen statt Dict-Keys - ✅ Initialer und iterativer Prompt haben garantiert die gleiche Struktur - ✅ Keine Abhängigkeit von Response-Parsing für Template-Extraktion - ✅ Explizite Kontrolle über Template-Struktur **Erforderliche Änderungen**: 1. `ContinuationContext` Pydantic-Modell erstellen (`jsonUtils.py` oder separate Model-Datei) 2. `buildContinuationContext()` erweitern um `templateStructure` Parameter 3. `buildContinuationContext()` Rückgabetyp ändern von `Dict[str, Any]` zu `ContinuationContext` 4. Alle Aufrufe von `buildContinuationContext()` anpassen, um `templateStructure` zu übergeben 5. Alle Verwendungen von `continuationContext` anpassen (Dict-Zugriff → Attribut-Zugriff) - `continuationContext.get("delivered_summary")` → `continuationContext.delivered_summary` - `continuationContext.get("cut_off_element")` → `continuationContext.cut_off_element` - etc. --- ### 2. Prompt-Builder-Architektur **Aktueller Zustand**: - Alle Prompt-Builder verwenden `**kwargs` für Parameter - Parameter werden aus `kwargs` extrahiert (nicht typsicher) - 3 identische Instanzen von `buildSectionPromptWithContinuation()` in `subStructureFilling.py` **Ziel-Architektur**: **Entscheidungen**: - ✅ **BasePrompt als Parameter übergeben**: Saubere Lösung, garantiert Identität mit initialem Prompt - ✅ **Dataclasses für Parameter-Strukturen**: Ja, für Typsicherheit und bessere Code-Qualität - ✅ **Schrittweise Migration**: Von `**kwargs` zu expliziten Parametern mit klarem Plan - ✅ **Einheitliche Signatur**: Alle Builder auf die gleiche Signatur umstellen **Einheitliche Signatur mit Dataclasses**: ```python from typing import Protocol from dataclasses import dataclass # Beispiel: Section Content Prompt Args @dataclass class SectionPromptArgs: """Type-safe arguments for section content prompt builder.""" section: Dict[str, Any] contentParts: List[ContentPart] userPrompt: str generationHint: str allSections: List[Dict[str, Any]] sectionIndex: int isAggregation: bool services: Any # Beispiel: Chapter Structure Prompt Args @dataclass class ChapterStructurePromptArgs: """Type-safe arguments for chapter structure prompt builder.""" userPrompt: str contentParts: List[ContentPart] outputFormat: str services: Any # Einheitliche Signatur für ALLE Prompt-Builder: class PromptBuilder(Protocol): """Protocol for prompt builders with unified signature.""" async def __call__( self, continuationContext: ContinuationContext, # Pydantic-Modell (NICHT Optional - wird immer übergeben) templateStructure: str, # Expliziter Parameter (aus promptArgs) - NICHT extrahiert, sondern als Parameter übergeben basePrompt: str, # Initialer Prompt (als Parameter übergeben) - NICHT regeneriert, sondern als Parameter übergeben promptArgs: Any # Dataclass mit use-case-spezifischen Parametern ) -> str: """Build continuation prompt with unified signature.""" ... ``` **Vorteile**: - ✅ Typsicherheit durch Dataclasses - ✅ Einheitliche Signatur für alle Builder - ✅ BasePrompt als Parameter garantiert Identität - ✅ Bessere IDE-Support und Dokumentation **Aufruf-Stelle** (`subAiCallLooping.py` Zeile 124): ```python # Aktueller Aufruf: iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs) ``` **Aktuelle Signaturen (INKONSISTENT)**: - `buildSectionPromptWithContinuation(continuationContext: Dict[str, Any], **kwargs)` → `continuationContext` NICHT Optional - `buildChapterStructurePromptWithContinuation(continuationContext: Optional[Dict[str, Any]] = None, **kwargs)` → `continuationContext` Optional - `buildCodeContentPromptWithContinuation(continuationContext: Optional[Dict[str, Any]] = None, **kwargs)` → `continuationContext` Optional **Problem**: Inkonsistente Signaturen! Einige Builder haben `Optional`, andere nicht. **Parameter-Übergabe-Unterschiede (AKTUELL)**: | Use Case | Parameter-Übergabe | Beschreibung | |----------|-------------------|--------------| | `section_content` | Alle `promptArgs` werden übergeben | `section`, `contentParts`, `userPrompt`, `generationHint`, `allSections`, `sectionIndex`, `isAggregation`, `services` | | `chapter_structure` | Alle `promptArgs` werden übergeben | `userPrompt`, `contentParts`, `outputFormat`, `services` | | `code_content` | Alle `promptArgs` werden übergeben | `filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services` | | Andere Use Cases (historisch) | Gefilterte `promptArgs` | Nur: `outputFormat`, `userPrompt`, `title`, `extracted_content`, `services` | **Hinweis**: Die historische Unterscheidung zwischen `section_content` (alle Parameter) und anderen Use Cases (gefilterte Parameter) wurde bereits aufgehoben. Alle aktuellen Use Cases verwenden alle `promptArgs`. **⚠️ KRITISCH: Template-Struktur-Quelle** **WICHTIG**: Template-Struktur wird **NICHT aus dem initialen Prompt extrahiert**. Stattdessen: | Use Case | Template-Erstellung | Beschreibung | |----------|---------------------|--------------| | `section_content` | Wird erstellt via `_getContentStructureExample(contentType)` | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) | | `chapter_structure` | Wird erstellt aus "EXAMPLE STRUCTURE" Struktur | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) | | `code_content` | Wird erstellt aus JSON-Struktur-Definition | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) | | `code_structure` | Wird erstellt aus "## FILE STRUCTURE REQUIREMENTS" | Template wird beim Erstellen des initialen Prompts **erstellt** (nicht extrahiert) | **Ziel-Architektur**: - **Template wird beim Erstellen des initialen Prompts erstellt** (nicht extrahiert!) - **Template wird als separater Parameter zurückgegeben**: `(prompt, templateStructure)` - **Template wird in `promptArgs` gespeichert** beim Aufruf von `callAiWithLooping()` - **Template wird aus `promptArgs` geholt** und an Continuation-Prompt-Builder übergeben - **Garantiert exakte Identität** zwischen initialem und Continuation-Prompt **Einheitliche Signatur (ZIEL)**: ```python # Einheitliche Signatur für ALLE Prompt-Builder: async def buildXxxPromptWithContinuation( continuationContext: ContinuationContext, # Pydantic-Modell (NICHT Optional - wird immer übergeben) templateStructure: str, # Expliziter Parameter (aus promptArgs) basePrompt: str, # Initialer Prompt (als Parameter übergeben) promptArgs: Any # Dataclass mit use-case-spezifischen Parametern ) -> str: """Build continuation prompt with unified signature.""" ... ``` **Erforderliche Änderungen**: 1. **Einheitlicher Prompt-Builder für `section_content`**: - 3 Instanzen zu einer einzigen Funktion konsolidieren - Funktion als Methode der Klasse definieren (nicht nested) - Dataclass `SectionPromptArgs` für Parameter verwenden 2. **Alle Prompt-Builder harmonisieren**: - `continuationContext` als **NICHT-Optional** Parameter (wird immer übergeben) - `templateStructure` als expliziten Parameter hinzufügen - `basePrompt` als expliziten Parameter hinzufügen (garantiert Identität) - Dataclasses für use-case-spezifische Parameter einführen - `**kwargs` schrittweise durch Dataclass-Parameter ersetzen 3. **`buildCodeStructurePromptWithContinuation()` implementieren**: - Als Klassenmethode in `CodeGenerationPath` - Ähnlich wie `buildChapterStructurePromptWithContinuation()` - Template aus "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303 in `codePath.py`) - Dataclass `CodeStructurePromptArgs` erstellen 4. **Aufruf-Stelle anpassen** (`subAiCallLooping.py` Zeile 112-124): ```python # Aktuell: continuationContext = buildContinuationContext(allSections, lastRawResponse, useCaseId) # Gibt Dict zurück iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs) # Verwendung (aktuell): deliveredSummary = continuationContext.get("delivered_summary", "") cutOffElement = continuationContext.get("cut_off_element", "") # Ziel (nach vollständiger Migration): # templateStructure und basePrompt werden bereits beim Erstellen des initialen Prompts als Parameter übergeben templateStructure = promptArgs.get("templateStructure") # Aus promptArgs basePrompt = prompt # Initialer Prompt (wird bereits übergeben) continuationContext = buildContinuationContext( allSections, lastRawResponse, useCaseId, templateStructure ) # Dataclass aus promptArgs erstellen (use-case-spezifisch) # Beispiel für section_content: sectionArgs = SectionPromptArgs( section=promptArgs["section"], contentParts=promptArgs["contentParts"], userPrompt=promptArgs["userPrompt"], generationHint=promptArgs["generationHint"], allSections=promptArgs["allSections"], sectionIndex=promptArgs["sectionIndex"], isAggregation=promptArgs["isAggregation"], services=promptArgs["services"] ) iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, basePrompt=basePrompt, promptArgs=sectionArgs # Dataclass statt **kwargs ) ``` **⚠️ WICHTIG: Keine Rückwärtskompatibilität** - **Keine Backward Compatibility** - neue Architektur wird vollständig implementiert - **Keine Fallback-Logik** - alle Parameter sind REQUIRED - **Klare neue Architektur** - alte Implementierungen werden vollständig ersetzt **Schrittweise Migration**: - **Phase 1**: `ContinuationContext` Pydantic-Modell erstellen, `templateStructure` als expliziten Parameter hinzufügen - **Phase 2**: `basePrompt` als expliziten Parameter hinzufügen - **Phase 3**: Prompt-Builder konsolidieren und als Klassenmethoden definieren - **Phase 4**: Alle Builder auf einheitliche Signatur umstellen (einheitliche Continuation-Prompt-Struktur) - **Phase 5**: Dataclasses einführen und `**kwargs` schrittweise ersetzen --- ### 5. Prompt-Builder-Aufruf-Mechanismus **Zentrale Aufruf-Stelle**: `subAiCallLooping.py` Zeile 112-124 **Aktueller Aufruf-Mechanismus**: ```python # In subAiCallLooping.py (Zeile 112-124): if (len(allSections) > 0 or lastRawResponse) and promptBuilder and promptArgs: # Build continuation context continuationContext = buildContinuationContext(allSections, lastRawResponse, useCaseId) # Ensure services is available in promptArgs if not promptArgs.get('services') and hasattr(self, 'services'): promptArgs['services'] = self.services # Call prompt builder with continuationContext and **kwargs iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs) else: # First iteration - use original prompt iterationPrompt = prompt ``` **Aufruf-Beispiele für verschiedene Use Cases**: #### 1. `section_content` Use Case **Aufruf-Stelle**: `subStructureFilling.py` (3 Instanzen: Zeilen ~850, ~1100, ~1461) **Aktueller Aufruf**: ```python # In _generateSectionContent() oder ähnlicher Methode: generationPrompt, templateStructure = self._buildSectionGenerationPrompt( section=section, contentParts=contentParts, userPrompt=userPrompt, generationHint=generationHint, allSections=allSections, sectionIndex=sectionIndex, isAggregation=isAggregation, language=language ) # Nested function definieren (wird später als promptBuilder übergeben) async def buildSectionPromptWithContinuation( continuationContext: Dict[str, Any], **kwargs ) -> str: # Extrahiert Parameter aus kwargs: section = kwargs.get("section") contentParts = kwargs.get("contentParts", []) userPrompt = kwargs.get("userPrompt", "") generationHint = kwargs.get("generationHint", "") allSections = kwargs.get("allSections", []) sectionIndex = kwargs.get("sectionIndex", 0) isAggregation = kwargs.get("isAggregation", False) # ... baut Continuation-Prompt return continuationPrompt # Aufruf von callAiWithLooping: aiResponse = await self.aiService.callAiWithLooping( prompt=generationPrompt, options=options, promptBuilder=buildSectionPromptWithContinuation, # Nested function promptArgs={ "section": section, "contentParts": contentParts, "userPrompt": userPrompt, "generationHint": generationHint, "allSections": allSections, "sectionIndex": sectionIndex, "isAggregation": isAggregation, "services": self.services }, useCaseId="section_content", debugPrefix=f"{chapterId}_section_{sectionId}", contentParts=contentParts ) ``` **Ziel-Aufruf (nach Migration)**: ```python # In _generateSectionContent(): generationPrompt, templateStructure = self._buildSectionGenerationPrompt(...) # Prompt-Builder als Klassenmethode (konsolidiert): # (wird als self.buildSectionPromptWithContinuation definiert) # Aufruf von callAiWithLooping: aiResponse = await self.aiService.callAiWithLooping( prompt=generationPrompt, options=options, promptBuilder=self.buildSectionPromptWithContinuation, # Klassenmethode promptArgs={ "section": section, "contentParts": contentParts, "userPrompt": userPrompt, "generationHint": generationHint, "allSections": allSections, "sectionIndex": sectionIndex, "isAggregation": isAggregation, "services": self.services, "templateStructure": templateStructure, # NEU: Explizit hinzugefügt "basePrompt": generationPrompt # NEU: Explizit hinzugefügt }, useCaseId="section_content", debugPrefix=f"{chapterId}_section_{sectionId}", contentParts=contentParts ) # In subAiCallLooping.py (nach Migration): templateStructure = promptArgs.get("templateStructure") basePrompt = prompt # Initialer Prompt continuationContext = buildContinuationContext( allSections, lastRawResponse, useCaseId, templateStructure ) # Dataclass erstellen (use-case-spezifisch): sectionArgs = SectionPromptArgs( section=promptArgs["section"], contentParts=promptArgs["contentParts"], userPrompt=promptArgs["userPrompt"], generationHint=promptArgs["generationHint"], allSections=promptArgs["allSections"], sectionIndex=promptArgs["sectionIndex"], isAggregation=promptArgs["isAggregation"], services=promptArgs["services"] ) iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, basePrompt=basePrompt, promptArgs=sectionArgs # Dataclass statt **kwargs ) ``` #### 2. `chapter_structure` Use Case **Aufruf-Stelle**: `subStructureGeneration.py` Zeile 162-176 **Aktueller Aufruf**: ```python # In _generateChapterStructure(): structurePrompt = self._buildChapterStructurePrompt( userPrompt=userPrompt, contentParts=contentParts, outputFormat=outputFormat ) # Nested function definieren: async def buildChapterStructurePromptWithContinuation( continuationContext: Optional[Dict[str, Any]] = None, **kwargs ) -> str: userPrompt = kwargs.get("userPrompt", "") contentParts = kwargs.get("contentParts", []) outputFormat = kwargs.get("outputFormat", "txt") # ... baut Continuation-Prompt return continuationPrompt or basePrompt # Aufruf von callAiWithLooping: aiResponseJson = await self.aiService.callAiWithLooping( prompt=structurePrompt, options=options, promptBuilder=buildChapterStructurePromptWithContinuation, promptArgs={ "userPrompt": userPrompt, "outputFormat": outputFormat, "services": self.services # HINWEIS: contentParts wird NICHT übergeben (nur Metadata im Prompt) }, useCaseId="chapter_structure", debugPrefix="chapter_structure_generation", contentParts=None # Explizit None - nur Metadata benötigt ) ``` **Ziel-Aufruf (nach Migration)**: ```python # In _generateChapterStructure(): structurePrompt, templateStructure = self._buildChapterStructurePrompt(...) # Aufruf von callAiWithLooping: aiResponseJson = await self.aiService.callAiWithLooping( prompt=structurePrompt, options=options, promptBuilder=self.buildChapterStructurePromptWithContinuation, # Klassenmethode promptArgs={ "userPrompt": userPrompt, "outputFormat": outputFormat, "services": self.services, "templateStructure": templateStructure, # NEU "basePrompt": structurePrompt # NEU }, useCaseId="chapter_structure", debugPrefix="chapter_structure_generation", contentParts=None ) # In subAiCallLooping.py (nach Migration): chapterArgs = ChapterStructurePromptArgs( userPrompt=promptArgs["userPrompt"], contentParts=promptArgs.get("contentParts", []), outputFormat=promptArgs["outputFormat"], services=promptArgs["services"] ) iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, basePrompt=basePrompt, promptArgs=chapterArgs # Dataclass ) ``` #### 3. `code_content` Use Case **Aufruf-Stelle**: `codePath.py` Zeile 812-830 **Aktueller Aufruf**: ```python # In _generateCodeContent() -> generateFileContent(): contentPrompt = f"""# TASK: Generate Code File Content ... Return ONLY valid JSON in this format: {{ "files": [ {{ "filename": "{filename}", "content": "// Complete code here", ... }} ] }} """ # Nested function definieren: async def buildCodeContentPromptWithContinuation( continuationContext: Optional[Dict[str, Any]] = None, **kwargs ) -> str: filename = kwargs.get("filename", "") fileType = kwargs.get("fileType", "") functions = kwargs.get("functions", []) classes = kwargs.get("classes", []) dependencies = kwargs.get("dependencies", []) metadata = kwargs.get("metadata", {}) userPrompt = kwargs.get("userPrompt", "") contentParts = kwargs.get("contentParts", []) contextInfo = kwargs.get("contextInfo", "") # ... baut Continuation-Prompt return continuationPrompt or basePrompt # Aufruf von callAiWithLooping: contentJson = await self.services.ai.callAiWithLooping( prompt=contentPrompt, options=options, promptBuilder=buildCodeContentPromptWithContinuation, promptArgs={ "filename": filename, "fileType": fileType, "functions": functions, "classes": classes, "dependencies": dependencies, "metadata": metadata, "userPrompt": userPrompt, "contentParts": contentParts, "contextInfo": contextInfo, "services": self.services }, useCaseId="code_content", debugPrefix=f"code_content_{fileStructure.get('id', 'file')}", ) ``` **Ziel-Aufruf (nach Migration)**: ```python # In generateFileContent(): contentPrompt, templateStructure = self._buildCodeContentPrompt(...) # Aufruf von callAiWithLooping: contentJson = await self.services.ai.callAiWithLooping( prompt=contentPrompt, options=options, promptBuilder=self.buildCodeContentPromptWithContinuation, # Klassenmethode promptArgs={ "filename": filename, "fileType": fileType, "functions": functions, "classes": classes, "dependencies": dependencies, "metadata": metadata, "userPrompt": userPrompt, "contentParts": contentParts, "contextInfo": contextInfo, "services": self.services, "templateStructure": templateStructure, # NEU "basePrompt": contentPrompt # NEU }, useCaseId="code_content", debugPrefix=f"code_content_{fileStructure.get('id', 'file')}", ) # In subAiCallLooping.py (nach Migration): codeContentArgs = CodeContentPromptArgs( filename=promptArgs["filename"], fileType=promptArgs["fileType"], functions=promptArgs["functions"], classes=promptArgs["classes"], dependencies=promptArgs["dependencies"], metadata=promptArgs["metadata"], userPrompt=promptArgs["userPrompt"], contentParts=promptArgs["contentParts"], contextInfo=promptArgs["contextInfo"], services=promptArgs["services"] ) iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, basePrompt=basePrompt, promptArgs=codeContentArgs # Dataclass ) ``` #### 4. `code_structure` Use Case **Aufruf-Stelle**: `codePath.py` Zeile 311-317 **Aktueller Aufruf** (OHNE Prompt-Builder - noch nicht implementiert): ```python # In _generateCodeStructure(): structureJson = await self.services.ai.callAiWithLooping( prompt=structurePrompt, options=options, useCaseId="code_structure", debugPrefix="code_structure_generation", contentParts=contentParts # KEIN promptBuilder - noch nicht implementiert! ) ``` **Ziel-Aufruf (nach Implementierung)**: ```python # In _generateCodeStructure(): structurePrompt, templateStructure = self._buildCodeStructurePrompt(...) # Aufruf von callAiWithLooping: structureJson = await self.services.ai.callAiWithLooping( prompt=structurePrompt, options=options, promptBuilder=self.buildCodeStructurePromptWithContinuation, # NEU: Implementieren promptArgs={ "userPrompt": userPrompt, "contentParts": contentParts, "services": self.services, "templateStructure": templateStructure, # NEU "basePrompt": structurePrompt # NEU }, useCaseId="code_structure", debugPrefix="code_structure_generation", contentParts=contentParts ) # In subAiCallLooping.py (nach Migration): codeStructureArgs = CodeStructurePromptArgs( userPrompt=promptArgs["userPrompt"], contentParts=promptArgs["contentParts"], services=promptArgs["services"] ) iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, basePrompt=basePrompt, promptArgs=codeStructureArgs # Dataclass ) ``` **Zusammenfassung der Aufruf-Mechanismen**: | Use Case | Aktueller Aufruf | Ziel-Aufruf | Status | |----------|------------------|-------------|--------| | `section_content` | ✅ Mit `promptBuilder` (nested function, 3 Instanzen) | ✅ Klassenmethode, Dataclass `SectionPromptArgs` | ⏳ Migration erforderlich | | `chapter_structure` | ✅ Mit `promptBuilder` (nested function) | ✅ Klassenmethode, Dataclass `ChapterStructurePromptArgs` | ⏳ Migration erforderlich | | `code_content` | ✅ Mit `promptBuilder` (nested function) | ✅ Klassenmethode, Dataclass `CodeContentPromptArgs` | ⏳ Migration erforderlich | | `code_structure` | ❌ OHNE `promptBuilder` | ✅ Klassenmethode, Dataclass `CodeStructurePromptArgs` | ⏳ Implementierung erforderlich | **Wichtige Punkte**: 1. **Zentrale Aufruf-Stelle**: Alle Prompt-Builder werden zentral in `subAiCallLooping.py` Zeile 112-124 aufgerufen 2. **Parameter-Übergabe**: Aktuell via `**kwargs` in `promptArgs` Dict, zukünftig via Dataclasses 3. **Template-Struktur**: Wird aktuell im Builder regeneriert, zukünftig als expliziter Parameter übergeben 4. **BasePrompt**: Wird aktuell im Builder regeneriert, zukünftig als expliziter Parameter übergeben 5. **Konsolidierung**: `section_content` hat 3 identische Instanzen → 1 konsolidierte Klassenmethode **Parameter-Mapping für explizite Signatures mit Dataclasses**: | Prompt-Builder | Aktuelle Parameter (aus `**kwargs`) | Dataclass | Ziel-Signature (einheitlich) | |----------------|--------------------------------------|-----------|------------------------------| | `buildSectionPromptWithContinuation()` | `section`, `contentParts`, `userPrompt`, `generationHint`, `allSections`, `sectionIndex`, `isAggregation`, `services` | `SectionPromptArgs` | `async def buildSectionPromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: SectionPromptArgs) -> str` | | `buildChapterStructurePromptWithContinuation()` | `userPrompt`, `contentParts`, `outputFormat`, `services` | `ChapterStructurePromptArgs` | `async def buildChapterStructurePromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: ChapterStructurePromptArgs) -> str` | | `buildCodeContentPromptWithContinuation()` | `filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services` | `CodeContentPromptArgs` | `async def buildCodeContentPromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: CodeContentPromptArgs) -> str` | | `buildCodeStructurePromptWithContinuation()` | ❌ **FEHLT** | `CodeStructurePromptArgs` | `async def buildCodeStructurePromptWithContinuation(continuationContext: Dict[str, Any], templateStructure: str, basePrompt: str, promptArgs: CodeStructurePromptArgs) -> str` | **Vollständige Dataclass-Definitionen**: ```python @dataclass class SectionPromptArgs: """Type-safe arguments for section content prompt builder.""" section: Dict[str, Any] contentParts: List[ContentPart] userPrompt: str generationHint: str allSections: List[Dict[str, Any]] sectionIndex: int isAggregation: bool services: Any @dataclass class ChapterStructurePromptArgs: """Type-safe arguments for chapter structure prompt builder.""" userPrompt: str contentParts: List[ContentPart] outputFormat: str services: Any @dataclass class CodeContentPromptArgs: """Type-safe arguments for code content prompt builder.""" filename: str fileType: str functions: List[Dict] classes: List[Dict] dependencies: List[str] metadata: Dict[str, Any] userPrompt: str contentParts: List[ContentPart] contextInfo: str services: Any @dataclass class CodeStructurePromptArgs: """Type-safe arguments for code structure prompt builder.""" userPrompt: str contentParts: List[ContentPart] services: Any ``` **Prompt-Builder Locations und Konsolidierung**: | Prompt-Builder | Location | Anzahl | Typ | Konsolidierung | |----------------|----------|--------|-----|----------------| | `buildSectionPromptWithContinuation` | `subStructureFilling.py` | 3 Instanzen | Nested functions (Zeilen 814, 1100, 1461) | ✅ 3 → 1 (als Klassenmethode in `StructureFiller`) | | `buildChapterStructurePromptWithContinuation` | `subStructureGeneration.py` | 1 Instanz | Nested function (Zeile 111) | ✅ Als Klassenmethode in `StructureGenerator` | | `buildCodeContentPromptWithContinuation` | `codePath.py` | 1 Instanz | Nested function (Zeile 683) | ✅ Als Klassenmethode in `CodeGenerationPath` | | `buildCodeStructurePromptWithContinuation` | ❌ **FEHLT** | 0 | - | ✅ Als Klassenmethode in `CodeGenerationPath` (neu erstellen) | **Architektur-Entscheidung**: - **NICHT** in eine zentrale Klasse verschieben (zu enge Kopplung) - **ABER**: Konsolidierung innerhalb der jeweiligen Klassen - **Vorteil**: Modulare Struktur, keine enge Kopplung, einfache Wartung **Aufruf-Mechanismus**: - Alle Builder werden in `subAiCallLooping.py` Zeile 124 aufgerufen - Einheitliche Signatur ermöglicht einheitlichen Aufruf ohne use-case-spezifische Logik - Nach Migration: `await promptBuilder(continuationContext=..., templateStructure=..., basePrompt=..., promptArgs=dataclassInstance)` --- ### 3. Template-Struktur-Parameter **⚠️ KRITISCH: Template-Struktur ist ein expliziter Parameter** **WICHTIG**: - **Template-Struktur wird NICHT aus dem initialen Prompt extrahiert** - **Template-Struktur wird NICHT aus dem Response extrahiert** - **Template-Struktur ist ein expliziter Parameter**, der beim Erstellen des initialen Prompts **erstellt** wird - **Derselbe Template-Struktur-Parameter** wird dann für den Continuation-Prompt verwendet - Dies garantiert **exakte Identität** zwischen initialem und Continuation-Prompt **Ziel-Architektur**: - **Template wird beim Erstellen des initialen Prompts als expliziter Parameter erstellt** - **Template wird in `promptArgs` gespeichert** beim Aufruf von `callAiWithLooping()` - **Template wird aus `promptArgs` extrahiert** und an `buildContinuationContext()` und `promptBuilder` übergeben - **Keine Extraktion aus Prompt-String** - Template ist ein expliziter Parameter, garantiert identisch **Beispiel-Implementierung**: ```python # Beim Erstellen des initialen Prompts: def _buildSectionGenerationPrompt( self, section: Dict[str, Any], contentParts: List[ContentPart], userPrompt: str, generationHint: str, allSections: List[Dict[str, Any]], sectionIndex: int, isAggregation: bool, language: str ) -> tuple[str, str]: # Gibt (prompt, templateStructure) zurück """Build section generation prompt and return prompt + template structure. WICHTIG: templateStructure wird hier ERSTELLT (nicht extrahiert) und als separater Parameter zurückgegeben. Derselbe Parameter wird dann für den Continuation-Prompt verwendet. """ contentType = section.get("content_type", "paragraph") contentStructureExample = self._getContentStructureExample(contentType) # Template-Struktur explizit ERSTELLEN (nicht extrahieren!) # Dies ist der Parameter, der später für den Continuation-Prompt verwendet wird templateStructure = f"""{{ "elements": [ {{ "type": "{contentType}", "content": {contentStructureExample} }} ] }}""" # Prompt mit Template erstellen (Template wird hier eingebettet) prompt = f"""... Return ONLY valid JSON in this format: {templateStructure} ...""" # WICHTIG: Beide zurückgeben - prompt UND templateStructure als separater Parameter return prompt, templateStructure # templateStructure wird NICHT aus prompt extrahiert! # Beim Aufruf von callAiWithLooping: prompt, templateStructure = self._buildSectionGenerationPrompt(...) promptArgs["templateStructure"] = templateStructure # In promptArgs speichern promptArgs["basePrompt"] = prompt # BasePrompt auch speichern # Später im Continuation-Prompt: templateStructure = promptArgs.get("templateStructure") # Aus promptArgs holen basePrompt = promptArgs.get("basePrompt") # BasePrompt aus promptArgs holen continuationContext = buildContinuationContext( allSections, lastRawResponse, useCaseId, templateStructure ) # Dataclass erstellen (nach Migration): sectionArgs = SectionPromptArgs( section=promptArgs["section"], contentParts=promptArgs["contentParts"], userPrompt=promptArgs["userPrompt"], generationHint=promptArgs["generationHint"], allSections=promptArgs["allSections"], sectionIndex=promptArgs["sectionIndex"], isAggregation=promptArgs["isAggregation"], services=promptArgs["services"] ) iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, # Derselbe Parameter wie im initialen Prompt basePrompt=basePrompt, # Derselbe Prompt wie initial promptArgs=sectionArgs # Dataclass statt **kwargs ) ``` **Vorteil**: - ✅ Garantierte Identität: Initialer und Continuation-Prompt verwenden exakt denselben Template-Parameter - ✅ Keine Extraktion nötig: Template wird nicht aus Prompt-String geparst - ✅ Einfacher: Template wird einmal erstellt und wiederverwendet **Erforderliche Änderungen**: 1. **Alle Prompt-Erstellungs-Funktionen anpassen**: - Template-Struktur **explizit erstellen** (nicht extrahieren!) - Template-Struktur als separater Rückgabewert zurückgeben: `(prompt, templateStructure)` - Template-Struktur in `promptArgs` speichern beim Aufruf von `callAiWithLooping()` 2. **In `callAiWithLooping()`**: - `templateStructure` aus `promptArgs` holen (REQUIRED - Fehler wenn fehlt) - `basePrompt` aus `prompt` Parameter holen (ist der initiale Prompt) - Beide an `buildContinuationContext()` und `promptBuilder` übergeben 3. **Alle Prompt-Builder anpassen**: - `templateStructure` als expliziten Parameter akzeptieren (nicht extrahieren!) - `basePrompt` als expliziten Parameter akzeptieren (nicht regenerieren!) - Template und BasePrompt direkt verwenden (garantiert identisch mit initialem Prompt) --- ### 4. Konsolidierung: 3 Instanzen → 1 Funktion **Aktueller Zustand**: - 3 identische Instanzen von `buildSectionPromptWithContinuation()` in `subStructureFilling.py` - Unterschiede nur in `promptArgs` (z.B. `contentParts` manchmal leer, manchmal gefüllt) **Ziel-Architektur**: ```python class StructureFiller: """Handles structure filling for document generation.""" async def buildSectionPromptWithContinuation( self, continuationContext: Dict[str, Any], templateStructure: str, # NEU: Expliziter Parameter section: Dict[str, Any], contentParts: List[ContentPart], userPrompt: str, generationHint: str, allSections: List[Dict[str, Any]], sectionIndex: int, isAggregation: bool, language: str ) -> str: """ Build section prompt with continuation context. Single unified implementation for all section content generation contexts. """ # Build base prompt basePrompt = self._buildSectionGenerationPrompt( section=section, contentParts=contentParts, userPrompt=userPrompt, generationHint=generationHint, allSections=allSections, sectionIndex=sectionIndex, isAggregation=isAggregation, language=language ) # Use provided templateStructure (from initial prompt) # This ensures exact match between initial and continuation prompts structureTemplate = f"""JSON Structure Template: {templateStructure} """ # Build continuation prompt with template and context ... ``` **Erforderliche Änderungen**: 1. Eine einzige Methode `buildSectionPromptWithContinuation()` in `StructureFiller` Klasse definieren 2. Alle 3 nested functions entfernen 3. Alle Aufrufe anpassen, um die neue Methode zu verwenden --- ## Zusammenfassung: Erforderliche Code-Änderungen ### Priorität 1: Template-Struktur-Konsistenz (KRITISCH) 1. **`ContinuationContext` Pydantic-Modell erstellen** (`jsonUtils.py` oder separate Model-Datei): - Alle Felder definieren: `section_count`, `delivered_summary`, `cut_off_element`, `element_before_cutoff`, `template_structure`, `last_complete_part`, `incomplete_part`, `structure_context`, `last_raw_json` - Optional-Felder korrekt markieren 2. **`buildContinuationContext()` erweitern** (`jsonUtils.py`): - Parameter `templateStructure: Optional[str]` hinzufügen - Rückgabetyp ändern von `Dict[str, Any]` zu `ContinuationContext` - `ContinuationContext`-Instanz erstellen und zurückgeben statt Dict 3. **Prompt-Erstellungs-Funktionen anpassen** (z.B. `_buildSectionGenerationPrompt()`, `_buildChapterStructurePrompt()`, etc.): - Template-Struktur explizit erstellen (nicht extrahieren) - Template-Struktur in `promptArgs` speichern beim Erstellen des initialen Prompts - Template-Struktur als Teil des Prompts einbetten 4. **Alle Verwendungen von `continuationContext` anpassen**: - **Prompt-Builder** (`subStructureFilling.py`, `subStructureGeneration.py`, `codePath.py`, etc.): - `continuationContext.get("delivered_summary")` → `continuationContext.delivered_summary` - `continuationContext.get("cut_off_element")` → `continuationContext.cut_off_element` - `continuationContext.get("element_before_cutoff")` → `continuationContext.element_before_cutoff` - `continuationContext.get("template_structure")` → `continuationContext.template_structure` - `continuationContext.get("last_complete_part")` → `continuationContext.last_complete_part` - `continuationContext.get("incomplete_part")` → `continuationContext.incomplete_part` - `continuationContext.get("structure_context")` → `continuationContext.structure_context` - `continuationContext.get("last_raw_json")` → `continuationContext.last_raw_json` - **Andere Verwendungen** (`subPromptBuilderGeneration.py`, etc.): - Alle Dict-Zugriffe auf Attribut-Zugriffe umstellen 5. **`callAiWithLooping()` anpassen** (`subAiCallLooping.py`): - **Parameter-Validierung**: `templateStructure` und `basePrompt` aus `promptArgs` holen (REQUIRED - Fehler wenn fehlt) - **Error Handling**: `ValueError` werfen wenn `templateStructure` oder `basePrompt` fehlen - `templateStructure` an `buildContinuationContext()` übergeben - `basePrompt` aus `prompt` Parameter holen (ist der initiale Prompt) - `continuationContext` (Pydantic-Modell) an `promptBuilder` übergeben - `templateStructure` und `basePrompt` an `promptBuilder` übergeben ### Priorität 2: Prompt-Builder-Harmonisierung 4. **`buildSectionPromptWithContinuation()` konsolidieren** (`subStructureFilling.py`): - 3 Instanzen zu einer Methode zusammenführen - Als Klassenmethode definieren (nicht nested) 5. **Alle Prompt-Builder erweitern**: - `templateStructure` als expliziten Parameter hinzufügen - Template aus Parameter verwenden (nicht aus `continuationContext` extrahieren) ### Priorität 3: Typsicherheit (Optional, aber empfohlen) 6. **Typsichere Parameter einführen**: - Dataclasses für Parameter-Strukturen erstellen - `**kwargs` durch explizite Parameter ersetzen --- ## Use Cases im Detail **Hinweis zu JSON-Template-Strukturen**: Die **JSON-Template-Struktur im Prompt** ist die Struktur, die der AI im initialen Prompt als Vorlage gegeben wird. Diese Struktur wird auch im Continuation-Prompt verwendet, um Konsistenz zu gewährleisten. Die Template-Struktur zeigt der AI, welches JSON-Format erwartet wird. --- ### 1. `section_content` ✅ **JSON-Template-Struktur im Prompt**: ```json { "elements": [ { "type": "{contentType}", "content": {contentStructureExample} } ] } ``` **Template-Quelle**: `_getContentStructureExample(contentType)` - dynamisch je nach `contentType`: - `table`: `{"headers": ["Column1", "Column2"], "rows": [["Value1", "Value2"], ["Value3", "Value4"]]}` - `bullet_list`: `{"items": ["Item 1", "Item 2", "Item 3"]}` - `heading`: `{"text": "Section Title", "level": 2}` - `paragraph`: `{"text": "This is paragraph text."}` - `code_block`: `{"code": "function example() { return true; }", "language": "javascript"}` - `image`: `{"base64Data": "", "altText": "Description", "caption": "Optional caption"}` **Prompt-Location**: `subStructureFilling.py` Zeile 2338-2348 ("## OUTPUT FORMAT") **Looping-Mechanismus**: - ✅ **In `loopingUseCases` Liste**: Ja - ✅ **In `directReturnUseCases` Liste**: Ja - ✅ **Unterstützt Iterationen**: Ja - ✅ **Unterstützt Accumulation**: Nein (`supportsAccumulation=False`) - ✅ **Requires Extraction**: Nein (`requiresExtraction=False`) **Prompt-Builder**: - **Spezifisch**: `buildSectionPromptWithContinuation()` (3 Instanzen → **SOLLTE konsolidiert werden**) - **Parameter**: Alle `promptArgs` werden übergeben - **Location**: `subStructureFilling.py` (nested functions → **SOLLTE Klassenmethode werden**) **Merging-Strategie**: - String-basiertes Merging mit Overlap-Detection - Fallback auf Deep-Structure-Merging bei Parsing-Fehlern - Normalisierung: Konvertiert Listen von Strings zu `paragraph` Elementen **Besonderheiten**: - Verwendet spezifischen Prompt-Builder (`buildSectionPromptWithContinuation`) - JSON-Struktur-Template kommt aus initialem Prompt (`_getContentStructureExample()`) - **PROBLEM**: 3 verschiedene Implementierungen des Prompt-Builders (je nach Kontext) - **Template-Struktur-Quelle**: ✅ **KORREKT** - Kommt aus initialem Prompt, nicht aus Response-Extraktion **Template-Struktur-Quelle Analyse**: - ✅ **`section_content`**: Template kommt aus initialem Prompt via `_getContentStructureExample(contentType)` - ✅ **Template wird dynamisch generiert** basierend auf `contentType` (z.B. `table`, `paragraph`, etc.) - ✅ **Template wird im Continuation-Prompt exakt wiederholt** (gleiche Logik wie im initialen Prompt) - ✅ **Keine Extraktion aus Response** - Template wird als Parameter übergeben (Ziel-Architektur) **✅ Template-Konsistenz geprüft**: - **Initial**: `subStructureFilling.py` Zeile 2342-2349 ("## OUTPUT FORMAT") - **Continuation**: `subStructureFilling.py` Zeile 877-887 ("JSON Structure Template") - **Status**: ✅ **IDENTISCH** - Beide verwenden `contentType = section.get("content_type", "paragraph")` und `contentStructureExample = self._getContentStructureExample(contentType)` --- ### 2. `chapter_structure` ✅ **JSON-Template-Struktur im Prompt**: ```json { "metadata": { "title": "...", "language": "..." }, "documents": [{ "id": "doc_1", "title": "...", "filename": "...", "outputFormat": "...", "language": "...", "chapters": [ { "id": "chapter_1", "level": 1, "title": "...", "contentParts": {}, "generationHint": "...", "sections": [] } ] }] } ``` **Template-Quelle**: Im initialen Prompt bei "EXAMPLE STRUCTURE" (Zeile 418-445 in `subStructureGeneration.py`) **Prompt-Location**: `subStructureGeneration.py` Zeile 418-445 ("EXAMPLE STRUCTURE") **Looping-Mechanismus**: - ✅ **In `loopingUseCases` Liste**: Ja - ✅ **In `directReturnUseCases` Liste**: Ja - ✅ **Unterstützt Iterationen**: Ja - ✅ **Unterstützt Accumulation**: Nein (`supportsAccumulation=False`) - ✅ **Requires Extraction**: Nein (`requiresExtraction=False`) **Prompt-Builder**: - **Spezifisch**: `buildChapterStructurePromptWithContinuation()` (nested function in `subStructureGeneration.py`) - **Parameter**: Alle `promptArgs` werden übergeben (`userPrompt`, `contentParts`, `outputFormat`, `services`) - **Location**: `subStructureGeneration.py` (nested function) **Merging-Strategie**: - String-basiertes Merging mit Overlap-Detection - Fallback auf Deep-Structure-Merging bei Parsing-Fehlern - Direkter Return nach Completion **Besonderheiten**: - Verwendet spezifischen Prompt-Builder (`buildChapterStructurePromptWithContinuation`) - JSON-Struktur-Template kommt aus initialem Prompt ("EXAMPLE STRUCTURE") - Template wird im Continuation-Prompt exakt wiederholt **✅ Template-Konsistenz geprüft**: - **Initial**: `subStructureGeneration.py` Zeile 418-445 ("EXAMPLE STRUCTURE") - **Continuation**: `subStructureGeneration.py` Zeile 111-155 (`buildChapterStructurePromptWithContinuation`) - **Status**: ✅ **IDENTISCH** - Beide verwenden das gleiche Template aus `_buildChapterStructurePrompt()` --- ### 3. `code_structure` ✅ **JSON-Template-Struktur im Prompt**: ```json { "metadata": { "language": "", "projectType": "single_file|multi_file", "projectName": "" }, "files": [ { "id": "", "filename": "", "fileType": "", "dependencies": [], "imports": [], "functions": [], "classes": [] } ] } ``` **Template-Quelle**: Im initialen Prompt bei "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303 in `codePath.py`) **Prompt-Location**: `codePath.py` Zeile 276-303 ("## FILE STRUCTURE REQUIREMENTS") **Looping-Mechanismus**: - ✅ **In `loopingUseCases` Liste**: Ja - ✅ **In `directReturnUseCases` Liste**: Ja - ✅ **Unterstützt Iterationen**: Ja - ✅ **Unterstützt Accumulation**: Nein (`supportsAccumulation=False`) - ✅ **Requires Extraction**: Nein (`requiresExtraction=False`) **Prompt-Builder**: - **Status**: ❌ **FEHLT** - Kein `promptBuilder` wird übergeben - **Problem**: Continuation-Prompts werden nicht unterstützt **Merging-Strategie**: - String-basiertes Merging mit Overlap-Detection - Fallback auf Deep-Structure-Merging bei Parsing-Fehlern - Direkter Return nach Completion **Besonderheiten**: - **KRITISCH**: Es gibt **KEINEN `promptBuilder`** für `code_structure`! - Continuation-Prompts werden nicht gebaut, daher keine Iterationen möglich **❌ Template-Konsistenz geprüft**: - **Initial**: `codePath.py` Zeile 276-303 ("## FILE STRUCTURE REQUIREMENTS") - **Continuation**: ❌ **FEHLT** - Kein Prompt-Builder vorhanden - **Status**: ❌ **PROBLEM** - Es gibt **KEINEN `promptBuilder`** für `code_structure`! Continuation-Prompts werden nicht unterstützt. - **Erforderliche Änderung**: Ein `buildCodeStructurePromptWithContinuation()` muss erstellt werden, der: 1. Das Template aus "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303) extrahiert 2. Es im Continuation-Prompt als "JSON Structure Template:" wiederholt 3. Die gleiche Struktur wie `buildChapterStructurePromptWithContinuation` verwendet --- ### 4. `code_content` ✅ **JSON-Template-Struktur im Prompt**: ```json { "files": [ { "filename": "{filename}", "content": "// Complete code here", "functions": [], "classes": [] } ] } ``` **Template-Quelle**: Im initialen Prompt bei "Return ONLY valid JSON in this format:" (Zeile 668-678 in `codePath.py`) **Prompt-Location**: `codePath.py` Zeile 643-679 **Looping-Mechanismus**: - ✅ **In `loopingUseCases` Liste**: Ja - ✅ **In `directReturnUseCases` Liste**: Ja - ✅ **Unterstützt Iterationen**: Ja - ✅ **Unterstützt Accumulation**: Ja (`supportsAccumulation=True`) - ✅ **Requires Extraction**: Nein (`requiresExtraction=False`) **Prompt-Builder**: - **Spezifisch**: `buildCodeContentPromptWithContinuation()` (nested function in `codePath.py`) - **Parameter**: Alle `promptArgs` werden übergeben (`filename`, `fileType`, `functions`, `classes`, `dependencies`, `metadata`, `userPrompt`, `contentParts`, `contextInfo`, `services`) - **Location**: `codePath.py` (nested function) **Merging-Strategie**: - String-basiertes Merging mit Overlap-Detection - Fallback auf Deep-Structure-Merging bei Parsing-Fehlern - Direkter Return nach Completion **Besonderheiten**: - Verwendet spezifischen Prompt-Builder (`buildCodeContentPromptWithContinuation`) - JSON-Struktur-Template kommt aus initialem Prompt (Zeile 668-678) - Template wird im Continuation-Prompt exakt wiederholt **✅ Template-Konsistenz geprüft**: - **Initial**: `codePath.py` Zeile 668-678 ("Return ONLY valid JSON in this format:") - **Continuation**: `codePath.py` Zeile 668-678 (wird im `buildCodeContentPromptWithContinuation` exakt wiederholt) - **Status**: ✅ **IDENTISCH** - Beide verwenden das gleiche Template mit den gleichen Beispielwerten --- ## Merging-Strategien **Merging-Strategien**: - **Primär**: String-basiertes Merging mit `mergeJsonStringsWithOverlap()` - **Fallback**: Deep-Structure-Merging bei Parsing-Fehlern (für alle Use Cases) - Wenn String-Merge erfolgreich, aber Parsing fehlschlägt: Versucht jedes Fragment einzeln zu parsen - Verwendet `mergeDeepStructures()` für intelligentes Merging der geparsten Fragmente - Funktioniert rekursiv für beliebige JSON-Strukturen (Arrays, Objekte, verschachtelt) - **Overlap-Detection**: Multi-Strategy (exact, line-based, partial line-based, structure-aware) --- ## Continuation-Prompt-Strukturen im Detail ### Fix vs. Variabel Analyse **Kernprinzip**: Alle Iterations-Prompts sollten nach der **gleichen Logik** aufgebaut sein, aber für verschiedene JSON-Strukturen. Die Struktur des Iterations-Prompts selbst sollte bei allen Use Cases **gleich** sein. #### ✅ FIX (sollte bei allen Use Cases identisch sein) | Element | Inhalt | Beschreibung | |---------|--------|--------------| | **Separator** | `--- CONTINUATION REQUEST ---` | Trennlinie zwischen Base Prompt und Continuation-Anweisungen | | **Einleitung** | `The previous JSON response was incomplete. Continue from where it stopped.` | Standard-Einleitung für alle Continuation-Requests | | **Section-Header** | `JSON Structure Template:` | Header für Template-Sektion | | **Section-Header** | `Context showing structure hierarchy with cut point:` | Header für Context-Sektion | | **Section-Header** | `Overlap Requirement:` | Header für Overlap-Anweisungen | | **Overlap-Anweisung** | `To ensure proper merging, your response MUST start by repeating approximately the last 100 characters from the previous response, then continue with new content.` | Standard-Overlap-Anweisung | | **Section-Header** | `Last ~100 characters from previous response (repeat these at the start):` | Header für Overlap-Context | | **Section-Header** | `TASK:` | Header für Task-Anweisungen | | **TASK Punkt 1** | `Start your response by repeating the last ~100 characters shown above (for overlap/merging)` | Overlap-Start-Anweisung | | **TASK Punkt 2** | `Complete the incomplete element shown in the context above (marked with CUT POINT)` | Completion-Anweisung | | **TASK Punkt 3** | `Continue generating the remaining content following the JSON structure template above` | Continuation-Anweisung | | **TASK Punkt 4** | `Return ONLY valid JSON following the structure template - no overlap/continuation wrapper objects` | Format-Anweisung | | **Section-Header** | `CRITICAL:` | Header für kritische Anweisungen | | **CRITICAL Punkt 1** | `Your response must be valid JSON matching the structure template above` | JSON-Format-Anforderung | | **CRITICAL Punkt 2** | `Start with overlap (~100 chars) then continue seamlessly` | Overlap-Seamless-Anweisung | | **CRITICAL Punkt 3** | `Complete the incomplete element and continue with remaining elements` | Completion-Continuation-Anweisung | #### 🔄 VARIABEL (use-case-spezifisch) | Element | Beschreibung | Aktuelle Implementierung | |---------|--------------|-------------------------| | **`basePrompt`** | Initialer Prompt (use-case-spezifisch) | Wird als Parameter übergeben, variiert je nach Use Case | | **`structureTemplate`** | JSON-Struktur-Template (use-case-spezifisch) | Wird aus initialem Prompt extrahiert oder als Parameter übergeben | | **`unifiedContext`** | Hierarchischer Cut-Point-Context (use-case-spezifisch, aber gleiche Logik) | Wird aus `_buildIncompleteContext()` erstellt - sollte für alle Use Cases nach gleicher Logik funktionieren | | **`overlapContext`** | Letzte ~100 Zeichen (gleiche Logik, aber unterschiedlicher Inhalt) | `lastRawJson[-100:].strip()` - gleiche Logik für alle | **⚠️ MANDATORY: Alle Use Cases müssen die einheitliche Struktur verwenden** **Wichtig**: - ✅ **Fix-Elemente** MÜSSEN bei allen Use Cases **exakt identisch** sein - keine Variationen erlaubt - 🔄 **Variable Elemente** variieren im Inhalt, aber die **Logik** zur Erstellung ist gleich - ✅ **Alle Use Cases** (`section_content`, `chapter_structure`, `code_structure`, `code_content`) verwenden **dieselbe Continuation-Prompt-Struktur** ### Einheitliche Continuation-Prompt-Struktur (Ziel) **⚠️ MANDATORY: Alle Use Cases MÜSSEN diese einheitliche Struktur verwenden** **Keine Variationen erlaubt** - alle Use Cases (`section_content`, `chapter_structure`, `code_structure`, `code_content`) verwenden **exakt dieselbe Continuation-Prompt-Struktur**: 1. **Base Prompt** (initialer Prompt - unverändert, als Parameter übergeben) 2. **--- CONTINUATION REQUEST ---** (Trennlinie) 3. **JSON Structure Template:** (Header) 4. **Template-Struktur** (exakt identisch mit initialem Prompt, als Parameter übergeben) 5. **Context showing structure hierarchy with cut point:** (Header) 6. **Hierarchischer Context** (hierarchischer Cut-Point-Context) 7. **Overlap Requirement:** (Header) 8. **Overlap-Anweisung** (~100 Zeichen) 9. **Last ~100 characters from previous response (repeat these at the start):** (Header) 10. **Overlap-Context** (letzte ~100 Zeichen) 11. **TASK:** (Header) 12. **TASK-Anweisungen** (4 Punkte) 13. **CRITICAL:** (Header) 14. **CRITICAL-Anweisungen** (3 Punkte) **⚠️ KRITISCH: Template-Konsistenz** - Das `JSON Structure Template` im Continuation-Prompt **MUSS exakt identisch** mit dem Template im initialen Prompt sein - **Template wird NICHT extrahiert** - es wird als expliziter Parameter (`templateStructure`) übergeben - **BasePrompt wird NICHT regeneriert** - es wird als expliziter Parameter (`basePrompt`) übergeben - Dies garantiert **exakte Identität** zwischen initialem und Continuation-Prompt ### Die 3 Prompt-Systeme für `section_content` **Besonderheit**: Der `section_content` Use Case verwendet **3 verschiedene Prompt-Systeme**, die sich durch den **Verarbeitungsmodus** unterscheiden, aber alle die gleiche Template-Struktur verwenden: #### System 1: Aggregation-Modus **Kontext**: `if needsAggregation and useAiCall` **Verwendung**: - Alle ContentParts einer Section werden **zusammen** verarbeitet - Ein einziger AI-Call für alle Parts - Verwendet `isAggregation=True` im Prompt **Code-Location**: - `subStructureFilling.py` Zeile ~611-922 - `buildSectionPromptWithContinuation` Zeile ~814-901 **Besonderheiten**: - Verarbeitet mehrere ContentParts gleichzeitig - Aggregiert alle Parts zu einem einzigen Prompt - Verwendet `useCaseId="section_content"` #### System 2: Einzelverarbeitung ohne ContentParts **Kontext**: `if len(contentPartIds) == 0 and useAiCall and generationHint` **Verwendung**: - **Keine ContentParts** vorhanden - Generation **nur mit generationHint** - Content wird von Grund auf generiert **Code-Location**: - `subStructureFilling.py` Zeile ~1039-1208 - `buildSectionPromptWithContinuation` Zeile ~1101-1197 **Besonderheiten**: - Generiert Content ohne Input-ContentParts - Verwendet nur `generationHint` als Basis - Verwendet `useCaseId="section_content"` #### System 3: Einzelverarbeitung mit ContentParts **Kontext**: Einzelne ContentParts werden nacheinander verarbeitet **Verwendung**: - **Einzelne ContentParts** werden sequenziell verarbeitet - Jeder Part wird einzeln an die AI gesendet - Mehrere AI-Calls pro Section (einer pro Part) **Code-Location**: - `subStructureFilling.py` Zeile ~1350-1570 - `buildSectionPromptWithContinuation` Zeile ~1463-1567 **Besonderheiten**: - Verarbeitet Parts einzeln - Kann mehrere Iterationen pro Section haben - Verwendet `useCaseId="section_content"` **Gemeinsame Basis aller 3 Systeme**: - ✅ Alle verwenden die **gleiche Template-Struktur** aus `_getContentStructureExample()` - ✅ Alle verwenden `useCaseId="section_content"` - ✅ Alle verwenden die **gleiche Continuation-Prompt-Struktur** (Fix-Elemente) - ✅ Alle verwenden `buildSectionPromptWithContinuation()` (aktuell 3 Instanzen, zukünftig 1 konsolidierte Funktion) **Entscheidungslogik** (in `_processSingleSection()`): ```python if needsAggregation and useAiCall: # System 1: Aggregation elif len(contentPartIds) == 0 and useAiCall and generationHint: # System 2: Ohne ContentParts else: # System 3: Mit ContentParts (Einzelverarbeitung) ``` **Ziel-Architektur**: - Alle 3 Systeme sollten die **konsolidierte** `buildSectionPromptWithContinuation()` Klassenmethode verwenden - Template-Struktur wird als Parameter übergeben (garantiert Identität) - BasePrompt wird als Parameter übergeben (garantiert Identität) --- ## Error Handling **Parameter-Validierung in `callAiWithLooping()`**: ```python # In subAiCallLooping.py: if (len(allSections) > 0 or lastRawResponse) and promptBuilder and promptArgs: # REQUIRED: templateStructure und basePrompt müssen in promptArgs vorhanden sein templateStructure = promptArgs.get("templateStructure") if not templateStructure: raise ValueError( f"templateStructure is REQUIRED in promptArgs for use case '{useCaseId}'. " "Prompt creation functions must return (prompt, templateStructure) tuple." ) basePrompt = promptArgs.get("basePrompt") if not basePrompt: # Fallback: use prompt parameter (should be the same) basePrompt = prompt # Log warning if they differ if basePrompt != prompt: logger.warning( f"basePrompt not found in promptArgs for use case '{useCaseId}', " "using prompt parameter instead. This may indicate a bug." ) # Build continuation context continuationContext = buildContinuationContext( allSections, lastRawResponse, useCaseId, templateStructure ) # Call prompt builder with validated parameters iterationPrompt = await promptBuilder( continuationContext=continuationContext, templateStructure=templateStructure, basePrompt=basePrompt, **promptArgs # During migration, still use **kwargs ) ``` **Error Messages**: - Klare Fehlermeldungen wenn REQUIRED Parameter fehlen - Hinweise auf erwartete Format (z.B. "Prompt creation functions must return (prompt, templateStructure) tuple") - Logging für Warnungen (z.B. wenn basePrompt nicht in promptArgs gefunden wird) --- ## Implementierungs-Roadmap ### Phase 1: ContinuationContext Pydantic-Modell und Template-Struktur-Parameter (KRITISCH) 1. ✅ `ContinuationContext` Pydantic-Modell erstellen (`jsonUtils.py` oder separate Model-Datei) 2. ✅ `buildContinuationContext()` um `templateStructure` Parameter erweitern 3. ✅ `buildContinuationContext()` Rückgabetyp ändern von `Dict[str, Any]` zu `ContinuationContext` 4. ✅ Alle Prompt-Erstellungs-Funktionen anpassen, um `templateStructure` zu **erstellen** (nicht extrahieren!) und als `(prompt, templateStructure)` Tuple zurückzugeben 5. ✅ Alle Aufrufe anpassen, um `templateStructure` in `promptArgs` zu speichern 6. ✅ `callAiWithLooping()` anpassen, um `templateStructure` aus `promptArgs` zu holen (mit Validierung) und an `buildContinuationContext()` zu übergeben 7. ✅ Alle Prompt-Builder um `templateStructure` Parameter erweitern (als expliziten Parameter, nicht extrahieren!) ### Phase 2: BasePrompt als Parameter 8. ✅ Alle Prompt-Erstellungs-Funktionen anpassen, um `basePrompt` in `promptArgs` zu speichern (oder aus `prompt` Parameter verwenden) 9. ✅ `callAiWithLooping()` anpassen, um `basePrompt` aus `promptArgs` zu holen (mit Validierung) 10. ✅ Alle Prompt-Builder um `basePrompt` Parameter erweitern (als expliziten Parameter, nicht regenerieren!) 11. ✅ BasePrompt als Parameter übergeben (garantiert Identität mit initialem Prompt) ### Phase 3: Prompt-Builder-Konsolidierung und einheitliche Continuation-Prompt-Struktur 12. ✅ `buildSectionPromptWithContinuation()` konsolidieren (3 → 1) 13. ✅ `buildCodeStructurePromptWithContinuation()` implementieren (fehlt aktuell) 14. ✅ Alle Prompt-Builder als Klassenmethoden definieren (nicht nested) 15. ✅ **Alle Prompt-Builder auf einheitliche Continuation-Prompt-Struktur umstellen** (siehe "Einheitliche Continuation-Prompt-Struktur") 16. ✅ `continuationContext` als NICHT-Optional Parameter (wird immer übergeben, Typ: `ContinuationContext`) ### Phase 4: Einheitliche Signatur 17. ✅ Alle Builder auf einheitliche Signatur umstellen: - `continuationContext: ContinuationContext` (Pydantic-Modell, NICHT Optional) - `templateStructure: str` (expliziter Parameter) - `basePrompt: str` (expliziter Parameter) - `promptArgs: Any` (während Migration noch Dict, später Dataclass) ### Phase 5: Typsicherheit mit Dataclasses 18. ✅ Dataclasses für Parameter-Strukturen einführen (`SectionPromptArgs`, `ChapterStructurePromptArgs`, `CodeContentPromptArgs`, `CodeStructurePromptArgs`) 19. ✅ Schrittweise Migration von `**kwargs` zu Dataclass-Parametern 20. ✅ Alle Builder auf Dataclass-basierte Parameter umstellen (`promptArgs: SectionPromptArgs` statt `promptArgs: Any`) ---