From 9f4746c2e751f1c19ec99faeaf9149f873ba2c75 Mon Sep 17 00:00:00 2001 From: Meleki Date: Tue, 10 Mar 2026 22:29:40 +0100 Subject: [PATCH] fix: fullChainStartIndex erkennt awaiting_user_choice der vorherigen Chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- Services/ChatService.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Services/ChatService.cs b/Services/ChatService.cs index 16e9f1e..82f7786 100644 --- a/Services/ChatService.cs +++ b/Services/ChatService.cs @@ -223,21 +223,24 @@ Für welche Plattform soll die App entwickelt werden? Web, Mobile oder Desktop? long? lastUserMsgId = null; // Bestimme ab welcher Chain vollständig geladen werden muss (mit Tool-Calls). - // Bei aufeinanderfolgenden ask_user_choice-Runden entstehen mehrere Chains, - // die alle vollständig geladen werden müssen (tool_use + tool_result Paare). - // Eine Chain braucht die vorherige vollständig, wenn sie: - // - leer ist (gerade erst erstellt für Choice-Antwort) - // - mit einem tool_result beginnt (Antwort auf ask_user_choice der vorherigen Chain) + // Bei ask_user_choice entstehen mehrere Chains die zusammengehören: + // Chain A (awaiting_user_choice) → tool_result(iter 999) wird in A gespeichert → Chain B (neue Chain) + // Chain B braucht Chain A vollständig, weil A den tool_use UND tool_result enthält. + // Drei Fälle, in denen die VORHERIGE Chain vollständig gebraucht wird: + // 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; for (int ci = chainsList.Count - 1; ci >= 1; ci--) { var chainMsgs = (await _db.GetChainMessages(chainsList[ci].ChainId)).ToList(); + var prevChainStopReason = chainsList[ci - 1].StopReason; + 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) { - // 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; } else