fixed ai looping jsonBase overwriting before getting successful answer

This commit is contained in:
ValueOn AG 2026-01-06 18:20:40 +01:00
parent 30ad4bb762
commit c3dce9221c
3 changed files with 15 additions and 6 deletions

View file

@ -57,7 +57,7 @@ When an AI response is too large, it may be truncated (cut) at an arbitrary poin
**Function:** `self.aiService.callAi(request)` **Function:** `self.aiService.callAi(request)`
- Returns `response.content` as `result` - Returns `response.content` as `result`
- Store raw response: `lastRawResponse = result` - NOTE: Do NOT update `lastRawResponse` yet! (only after successful merge)
### Step 4: MERGE ### Step 4: MERGE
@ -73,10 +73,12 @@ ELSE:
IF hasOverlap = False (MERGE FAILED): IF hasOverlap = False (MERGE FAILED):
→ mergeFailCount++ → mergeFailCount++
→ If mergeFailCount >= 3: return lastValidCompletePart (fallback) → If mergeFailCount >= 3: return lastValidCompletePart (fallback)
→ Else: continue (retry with unchanged jsonBase) → Else: continue (retry with unchanged jsonBase AND lastRawResponse!)
ELSE: ELSE:
→ candidateJson = mergedJsonString (don't update jsonBase yet!) → candidateJson = mergedJsonString (don't update jsonBase yet!)
→ lastRawResponse = candidateJson (ONLY after first iteration or successful merge!)
TRY DIRECT PARSE of candidateJson: TRY DIRECT PARSE of candidateJson:
IF parse succeeds: IF parse succeeds:
→ jsonBase = candidateJson (commit) → jsonBase = candidateJson (commit)

View file

@ -307,8 +307,9 @@ class AiCallLooper:
self.services.chat.progressLogFinish(iterationOperationId, True) self.services.chat.progressLogFinish(iterationOperationId, True)
return result return result
# Store raw response for continuation (even if broken) # NOTE: Do NOT update lastRawResponse here!
lastRawResponse = result # lastRawResponse should only be updated after successful merge
# This ensures retry iterations use the correct base context
# Handle use cases that return JSON directly (no section extraction needed) # Handle use cases that return JSON directly (no section extraction needed)
# Check if use case supports direct return (all registered use cases do) # Check if use case supports direct return (all registered use cases do)
@ -387,6 +388,11 @@ class AiCallLooper:
candidateJson = mergedJsonString candidateJson = mergedJsonString
logger.debug(f"Iteration {iteration}: Merge succeeded, candidateJson ({len(candidateJson)} chars)") logger.debug(f"Iteration {iteration}: Merge succeeded, candidateJson ({len(candidateJson)} chars)")
# Update lastRawResponse ONLY after we have a valid candidateJson
# (first iteration or successful merge - NOT on merge failure!)
# This ensures retry iterations use the correct base context
lastRawResponse = candidateJson
# Try direct parse of candidate # Try direct parse of candidate
try: try:
extracted = extractJsonString(candidateJson) extracted = extractJsonString(candidateJson)

View file

@ -333,8 +333,9 @@ class JsonAnalyzer:
cutPos = len(self.jsonStr) cutPos = len(self.jsonStr)
# Build both hierarchy contexts from the SAME structure BEFORE generating complete part # Build both hierarchy contexts from the SAME structure BEFORE generating complete part
# Generate hierarchy context WITHOUT budget (full structure for internal use) # CRITICAL: hierarchyContext must be the EXACT original JSON (for merge overlap detection!)
hierarchyContext = self._renderFromStructure(structure) # The rendered version would have different formatting, breaking overlap matching
hierarchyContext = self.jsonStr
# Generate hierarchy context WITH budget (for prompts) - uses same structure # Generate hierarchy context WITH budget (for prompts) - uses same structure
hierarchyContextForPrompt = self._renderWithBudgetFromStructure(structure, cutPos) hierarchyContextForPrompt = self._renderWithBudgetFromStructure(structure, cutPos)