fix: fullChainStartIndex erkennt awaiting_user_choice der vorherigen Chain

Bug: Nach ask_user_choice wurde die vorherige Chain (mit allen tool_use/
tool_result Paaren) nur als Text geladen statt vollständig. Die API bekam
tool_use IDs ohne zugehörige tool_result Blöcke → 400 Error.

Ursache: Die fullChainStartIndex-Logik prüfte nur ob die AKTUELLE Chain
eine tool_result mit Iteration 999 hat. Aber die Choice-Antwort wird in
die VORHERIGE Chain gespeichert (ChatEndpoint Zeile 68-78), nicht in die
aktuelle. Deshalb wurde needsPrevious=false → vorherige Chain nur als Text.

Fix: Dritte Prüfung hinzugefügt - wenn die vorherige Chain mit
stop_reason='awaiting_user_choice' endete, muss sie vollständig geladen
werden (sie enthält den tool_use UND den tool_result für die Choice).
This commit is contained in:
Meleki committed 2026-03-10 22:29:40 +01:00
1 parent c9b1523e86
commit 9f4746c2e7
1 file changed
+11 -8
+11 -8
View File
@@ -223,21 +223,24 @@ Für welche Plattform soll die App entwickelt werden? Web, Mobile oder Desktop?
long? lastUserMsgId = null; long? lastUserMsgId = null;
// Bestimme ab welcher Chain vollständig geladen werden muss (mit Tool-Calls). // Bestimme ab welcher Chain vollständig geladen werden muss (mit Tool-Calls).
// Bei aufeinanderfolgenden ask_user_choice-Runden entstehen mehrere Chains, // Bei ask_user_choice entstehen mehrere Chains die zusammengehören:
// die alle vollständig geladen werden müssen (tool_use + tool_result Paare). // Chain A (awaiting_user_choice) → tool_result(iter 999) wird in A gespeichert → Chain B (neue Chain)
// Eine Chain braucht die vorherige vollständig, wenn sie: // Chain B braucht Chain A vollständig, weil A den tool_use UND tool_result enthält.
// - leer ist (gerade erst erstellt für Choice-Antwort) // Drei Fälle, in denen die VORHERIGE Chain vollständig gebraucht wird:
// - mit einem tool_result beginnt (Antwort auf ask_user_choice der vorherigen Chain) // 1. Aktuelle Chain ist leer (gerade erst erstellt)
// 2. Aktuelle Chain hat eine tool_result mit Iteration 999 (Choice-Antwort in aktueller Chain)
// 3. Vorherige Chain endete mit awaiting_user_choice (Choice-Antwort wurde dort gespeichert)
int fullChainStartIndex = chainsList.Count - 1; int fullChainStartIndex = chainsList.Count - 1;
for (int ci = chainsList.Count - 1; ci >= 1; ci--) for (int ci = chainsList.Count - 1; ci >= 1; ci--)
{ {
var chainMsgs = (await _db.GetChainMessages(chainsList[ci].ChainId)).ToList(); var chainMsgs = (await _db.GetChainMessages(chainsList[ci].ChainId)).ToList();
var prevChainStopReason = chainsList[ci - 1].StopReason;
bool needsPrevious = chainMsgs.Count == 0 || bool needsPrevious = chainMsgs.Count == 0 ||
chainMsgs.Any(m => m.Type == "tool_result" && m.Iteration == 999); chainMsgs.Any(m => m.Type == "tool_result" && m.Iteration == 999) ||
prevChainStopReason == "awaiting_user_choice";
if (needsPrevious) if (needsPrevious)
{ {
// Diese Chain enthält eine Choice-Antwort oder ist leer →
// vorherige Chain enthält den zugehörigen tool_use und muss vollständig geladen werden
fullChainStartIndex = ci - 1; fullChainStartIndex = ci - 1;
} }
else else