wiki/implementation/implementation_ai-call-looping-architecture_done.md
2026-01-11 13:07:11 +01:00

1514 lines
64 KiB
Markdown

# 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": "<base64_encoded_image_data>", "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`)
---