64 KiB
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:
section_content- Section-Content-Generierung ✅ Loopingchapter_structure- Chapter-Struktur-Generierung ✅ Loopingcode_structure- Code-Struktur-Generierung ✅ Loopingcode_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
**kwargsfü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:
- Erste Iteration: Verwendet den initialen Prompt
- 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)extrahierttemplate_structureaus dem Responsetemplate_structurewird 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:
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:
ContinuationContextPydantic-Modell erstellen (jsonUtils.pyoder separate Model-Datei)buildContinuationContext()erweitern umtemplateStructureParameterbuildContinuationContext()Rückgabetyp ändern vonDict[str, Any]zuContinuationContext- Alle Aufrufe von
buildContinuationContext()anpassen, umtemplateStructurezu übergeben - Alle Verwendungen von
continuationContextanpassen (Dict-Zugriff → Attribut-Zugriff)continuationContext.get("delivered_summary")→continuationContext.delivered_summarycontinuationContext.get("cut_off_element")→continuationContext.cut_off_element- etc.
2. Prompt-Builder-Architektur
Aktueller Zustand:
- Alle Prompt-Builder verwenden
**kwargsfür Parameter - Parameter werden aus
kwargsextrahiert (nicht typsicher) - 3 identische Instanzen von
buildSectionPromptWithContinuation()insubStructureFilling.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
**kwargszu expliziten Parametern mit klarem Plan - ✅ Einheitliche Signatur: Alle Builder auf die gleiche Signatur umstellen
Einheitliche Signatur mit Dataclasses:
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):
# Aktueller Aufruf:
iterationPrompt = await promptBuilder(continuationContext=continuationContext, **promptArgs)
Aktuelle Signaturen (INKONSISTENT):
buildSectionPromptWithContinuation(continuationContext: Dict[str, Any], **kwargs)→continuationContextNICHT OptionalbuildChapterStructurePromptWithContinuation(continuationContext: Optional[Dict[str, Any]] = None, **kwargs)→continuationContextOptionalbuildCodeContentPromptWithContinuation(continuationContext: Optional[Dict[str, Any]] = None, **kwargs)→continuationContextOptional
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
promptArgsgespeichert beim Aufruf voncallAiWithLooping() - Template wird aus
promptArgsgeholt und an Continuation-Prompt-Builder übergeben - Garantiert exakte Identität zwischen initialem und Continuation-Prompt
Einheitliche Signatur (ZIEL):
# 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:
-
Einheitlicher Prompt-Builder für
section_content:- 3 Instanzen zu einer einzigen Funktion konsolidieren
- Funktion als Methode der Klasse definieren (nicht nested)
- Dataclass
SectionPromptArgsfür Parameter verwenden
-
Alle Prompt-Builder harmonisieren:
continuationContextals NICHT-Optional Parameter (wird immer übergeben)templateStructureals expliziten Parameter hinzufügenbasePromptals expliziten Parameter hinzufügen (garantiert Identität)- Dataclasses für use-case-spezifische Parameter einführen
**kwargsschrittweise durch Dataclass-Parameter ersetzen
-
buildCodeStructurePromptWithContinuation()implementieren:- Als Klassenmethode in
CodeGenerationPath - Ähnlich wie
buildChapterStructurePromptWithContinuation() - Template aus "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303 in
codePath.py) - Dataclass
CodeStructurePromptArgserstellen
- Als Klassenmethode in
-
Aufruf-Stelle anpassen (
subAiCallLooping.pyZeile 112-124):# 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:
ContinuationContextPydantic-Modell erstellen,templateStructureals expliziten Parameter hinzufügen - Phase 2:
basePromptals 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
**kwargsschrittweise ersetzen
5. Prompt-Builder-Aufruf-Mechanismus
Zentrale Aufruf-Stelle: subAiCallLooping.py Zeile 112-124
Aktueller Aufruf-Mechanismus:
# 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:
# 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):
# 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:
# 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):
# 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:
# 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):
# 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):
# 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):
# 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:
- Zentrale Aufruf-Stelle: Alle Prompt-Builder werden zentral in
subAiCallLooping.pyZeile 112-124 aufgerufen - Parameter-Übergabe: Aktuell via
**kwargsinpromptArgsDict, zukünftig via Dataclasses - Template-Struktur: Wird aktuell im Builder regeneriert, zukünftig als expliziter Parameter übergeben
- BasePrompt: Wird aktuell im Builder regeneriert, zukünftig als expliziter Parameter übergeben
- Konsolidierung:
section_contenthat 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:
@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.pyZeile 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
promptArgsgespeichert beim Aufruf voncallAiWithLooping() - Template wird aus
promptArgsextrahiert und anbuildContinuationContext()undpromptBuilderübergeben - Keine Extraktion aus Prompt-String - Template ist ein expliziter Parameter, garantiert identisch
Beispiel-Implementierung:
# 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:
- Alle Prompt-Erstellungs-Funktionen anpassen:
- Template-Struktur explizit erstellen (nicht extrahieren!)
- Template-Struktur als separater Rückgabewert zurückgeben:
(prompt, templateStructure) - Template-Struktur in
promptArgsspeichern beim Aufruf voncallAiWithLooping()
- In
callAiWithLooping():templateStructureauspromptArgsholen (REQUIRED - Fehler wenn fehlt)basePromptauspromptParameter holen (ist der initiale Prompt)- Beide an
buildContinuationContext()undpromptBuilderübergeben
- Alle Prompt-Builder anpassen:
templateStructureals expliziten Parameter akzeptieren (nicht extrahieren!)basePromptals 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()insubStructureFilling.py - Unterschiede nur in
promptArgs(z.B.contentPartsmanchmal leer, manchmal gefüllt)
Ziel-Architektur:
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:
- Eine einzige Methode
buildSectionPromptWithContinuation()inStructureFillerKlasse definieren - Alle 3 nested functions entfernen
- Alle Aufrufe anpassen, um die neue Methode zu verwenden
Zusammenfassung: Erforderliche Code-Änderungen
Priorität 1: Template-Struktur-Konsistenz (KRITISCH)
-
ContinuationContextPydantic-Modell erstellen (jsonUtils.pyoder 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
- Alle Felder definieren:
-
buildContinuationContext()erweitern (jsonUtils.py):- Parameter
templateStructure: Optional[str]hinzufügen - Rückgabetyp ändern von
Dict[str, Any]zuContinuationContext ContinuationContext-Instanz erstellen und zurückgeben statt Dict
- Parameter
-
Prompt-Erstellungs-Funktionen anpassen (z.B.
_buildSectionGenerationPrompt(),_buildChapterStructurePrompt(), etc.):- Template-Struktur explizit erstellen (nicht extrahieren)
- Template-Struktur in
promptArgsspeichern beim Erstellen des initialen Prompts - Template-Struktur als Teil des Prompts einbetten
-
Alle Verwendungen von
continuationContextanpassen:- Prompt-Builder (
subStructureFilling.py,subStructureGeneration.py,codePath.py, etc.):continuationContext.get("delivered_summary")→continuationContext.delivered_summarycontinuationContext.get("cut_off_element")→continuationContext.cut_off_elementcontinuationContext.get("element_before_cutoff")→continuationContext.element_before_cutoffcontinuationContext.get("template_structure")→continuationContext.template_structurecontinuationContext.get("last_complete_part")→continuationContext.last_complete_partcontinuationContext.get("incomplete_part")→continuationContext.incomplete_partcontinuationContext.get("structure_context")→continuationContext.structure_contextcontinuationContext.get("last_raw_json")→continuationContext.last_raw_json
- Andere Verwendungen (
subPromptBuilderGeneration.py, etc.):- Alle Dict-Zugriffe auf Attribut-Zugriffe umstellen
- Prompt-Builder (
-
callAiWithLooping()anpassen (subAiCallLooping.py):- Parameter-Validierung:
templateStructureundbasePromptauspromptArgsholen (REQUIRED - Fehler wenn fehlt) - Error Handling:
ValueErrorwerfen wenntemplateStructureoderbasePromptfehlen templateStructureanbuildContinuationContext()übergebenbasePromptauspromptParameter holen (ist der initiale Prompt)continuationContext(Pydantic-Modell) anpromptBuilderübergebentemplateStructureundbasePromptanpromptBuilderübergeben
- Parameter-Validierung:
Priorität 2: Prompt-Builder-Harmonisierung
-
buildSectionPromptWithContinuation()konsolidieren (subStructureFilling.py):- 3 Instanzen zu einer Methode zusammenführen
- Als Klassenmethode definieren (nicht nested)
-
Alle Prompt-Builder erweitern:
templateStructureals expliziten Parameter hinzufügen- Template aus Parameter verwenden (nicht aus
continuationContextextrahieren)
Priorität 3: Typsicherheit (Optional, aber empfohlen)
- Typsichere Parameter einführen:
- Dataclasses für Parameter-Strukturen erstellen
**kwargsdurch 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:
{
"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
loopingUseCasesListe: Ja - ✅ In
directReturnUseCasesListe: 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
promptArgswerden ü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
paragraphElementen
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.pyZeile 2342-2349 ("## OUTPUT FORMAT") - Continuation:
subStructureFilling.pyZeile 877-887 ("JSON Structure Template") - Status: ✅ IDENTISCH - Beide verwenden
contentType = section.get("content_type", "paragraph")undcontentStructureExample = self._getContentStructureExample(contentType)
2. chapter_structure ✅
JSON-Template-Struktur im Prompt:
{
"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
loopingUseCasesListe: Ja - ✅ In
directReturnUseCasesListe: Ja - ✅ Unterstützt Iterationen: Ja
- ✅ Unterstützt Accumulation: Nein (
supportsAccumulation=False) - ✅ Requires Extraction: Nein (
requiresExtraction=False)
Prompt-Builder:
- Spezifisch:
buildChapterStructurePromptWithContinuation()(nested function insubStructureGeneration.py) - Parameter: Alle
promptArgswerden ü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.pyZeile 418-445 ("EXAMPLE STRUCTURE") - Continuation:
subStructureGeneration.pyZeile 111-155 (buildChapterStructurePromptWithContinuation) - Status: ✅ IDENTISCH - Beide verwenden das gleiche Template aus
_buildChapterStructurePrompt()
3. code_structure ✅
JSON-Template-Struktur im Prompt:
{
"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
loopingUseCasesListe: Ja - ✅ In
directReturnUseCasesListe: Ja - ✅ Unterstützt Iterationen: Ja
- ✅ Unterstützt Accumulation: Nein (
supportsAccumulation=False) - ✅ Requires Extraction: Nein (
requiresExtraction=False)
Prompt-Builder:
- Status: ❌ FEHLT - Kein
promptBuilderwird ü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
promptBuilderfürcode_structure! - Continuation-Prompts werden nicht gebaut, daher keine Iterationen möglich
❌ Template-Konsistenz geprüft:
- Initial:
codePath.pyZeile 276-303 ("## FILE STRUCTURE REQUIREMENTS") - Continuation: ❌ FEHLT - Kein Prompt-Builder vorhanden
- Status: ❌ PROBLEM - Es gibt KEINEN
promptBuilderfürcode_structure! Continuation-Prompts werden nicht unterstützt. - Erforderliche Änderung: Ein
buildCodeStructurePromptWithContinuation()muss erstellt werden, der:- Das Template aus "## FILE STRUCTURE REQUIREMENTS" (Zeile 276-303) extrahiert
- Es im Continuation-Prompt als "JSON Structure Template:" wiederholt
- Die gleiche Struktur wie
buildChapterStructurePromptWithContinuationverwendet
4. code_content ✅
JSON-Template-Struktur im Prompt:
{
"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
loopingUseCasesListe: Ja - ✅ In
directReturnUseCasesListe: Ja - ✅ Unterstützt Iterationen: Ja
- ✅ Unterstützt Accumulation: Ja (
supportsAccumulation=True) - ✅ Requires Extraction: Nein (
requiresExtraction=False)
Prompt-Builder:
- Spezifisch:
buildCodeContentPromptWithContinuation()(nested function incodePath.py) - Parameter: Alle
promptArgswerden ü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.pyZeile 668-678 ("Return ONLY valid JSON in this format:") - Continuation:
codePath.pyZeile 668-678 (wird imbuildCodeContentPromptWithContinuationexakt 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:
- Base Prompt (initialer Prompt - unverändert, als Parameter übergeben)
- --- CONTINUATION REQUEST --- (Trennlinie)
- JSON Structure Template: (Header)
- Template-Struktur (exakt identisch mit initialem Prompt, als Parameter übergeben)
- Context showing structure hierarchy with cut point: (Header)
- Hierarchischer Context (hierarchischer Cut-Point-Context)
- Overlap Requirement: (Header)
- Overlap-Anweisung (~100 Zeichen)
- Last ~100 characters from previous response (repeat these at the start): (Header)
- Overlap-Context (letzte ~100 Zeichen)
- TASK: (Header)
- TASK-Anweisungen (4 Punkte)
- CRITICAL: (Header)
- CRITICAL-Anweisungen (3 Punkte)
⚠️ KRITISCH: Template-Konsistenz
- Das
JSON Structure Templateim 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=Trueim Prompt
Code-Location:
subStructureFilling.pyZeile ~611-922buildSectionPromptWithContinuationZeile ~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.pyZeile ~1039-1208buildSectionPromptWithContinuationZeile ~1101-1197
Besonderheiten:
- Generiert Content ohne Input-ContentParts
- Verwendet nur
generationHintals 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.pyZeile ~1350-1570buildSectionPromptWithContinuationZeile ~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()):
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():
# 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)
- ✅
ContinuationContextPydantic-Modell erstellen (jsonUtils.pyoder separate Model-Datei) - ✅
buildContinuationContext()umtemplateStructureParameter erweitern - ✅
buildContinuationContext()Rückgabetyp ändern vonDict[str, Any]zuContinuationContext - ✅ Alle Prompt-Erstellungs-Funktionen anpassen, um
templateStructurezu erstellen (nicht extrahieren!) und als(prompt, templateStructure)Tuple zurückzugeben - ✅ Alle Aufrufe anpassen, um
templateStructureinpromptArgszu speichern - ✅
callAiWithLooping()anpassen, umtemplateStructureauspromptArgszu holen (mit Validierung) und anbuildContinuationContext()zu übergeben - ✅ Alle Prompt-Builder um
templateStructureParameter erweitern (als expliziten Parameter, nicht extrahieren!)
Phase 2: BasePrompt als Parameter
- ✅ Alle Prompt-Erstellungs-Funktionen anpassen, um
basePromptinpromptArgszu speichern (oder auspromptParameter verwenden) - ✅
callAiWithLooping()anpassen, umbasePromptauspromptArgszu holen (mit Validierung) - ✅ Alle Prompt-Builder um
basePromptParameter erweitern (als expliziten Parameter, nicht regenerieren!) - ✅ BasePrompt als Parameter übergeben (garantiert Identität mit initialem Prompt)
Phase 3: Prompt-Builder-Konsolidierung und einheitliche Continuation-Prompt-Struktur
- ✅
buildSectionPromptWithContinuation()konsolidieren (3 → 1) - ✅
buildCodeStructurePromptWithContinuation()implementieren (fehlt aktuell) - ✅ Alle Prompt-Builder als Klassenmethoden definieren (nicht nested)
- ✅ Alle Prompt-Builder auf einheitliche Continuation-Prompt-Struktur umstellen (siehe "Einheitliche Continuation-Prompt-Struktur")
- ✅
continuationContextals NICHT-Optional Parameter (wird immer übergeben, Typ:ContinuationContext)
Phase 4: Einheitliche Signatur
- ✅ 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
- ✅ Dataclasses für Parameter-Strukturen einführen (
SectionPromptArgs,ChapterStructurePromptArgs,CodeContentPromptArgs,CodeStructurePromptArgs) - ✅ Schrittweise Migration von
**kwargszu Dataclass-Parametern - ✅ Alle Builder auf Dataclass-basierte Parameter umstellen (
promptArgs: SectionPromptArgsstattpromptArgs: Any)