From 1e7b68fb0939eb87c4e295f6dcaa401ed9614ca8 Mon Sep 17 00:00:00 2001 From: Meleki Date: Mon, 9 Mar 2026 19:44:07 +0100 Subject: [PATCH] Fix: ask_user_choice Dauerschleife bei mehreren aufeinanderfolgenden Choice-Runden MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: Bei 2+ aufeinanderfolgenden ask_user_choice-Runden wurden ältere Choice-Chains nur als Text geladen. Claude sah die früheren tool_use/ tool_result-Paare nicht → kein Kontext über bereits beantwortete Fragen → Agent stellte dieselben Fragen erneut (Dauerschleife). Fix: fullChainStartIndex-Logik traversiert jetzt rückwärts durch alle zusammenhängenden Choice-Chains (erkannt an tool_result mit Iteration 999). Alle werden vollständig geladen, damit die gesamte Frage-Antwort-Historie für Claude sichtbar bleibt. --- Services/ChatService.cs | 27 ++++++++++++++++++--------- Services/SystemPromptBuilder.cs | 2 +- Services/ToolService.cs | 2 +- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Services/ChatService.cs b/Services/ChatService.cs index 19bb2d5..66dcbfc 100644 --- a/Services/ChatService.cs +++ b/Services/ChatService.cs @@ -222,18 +222,27 @@ Für welche Plattform soll die App entwickelt werden? Web, Mobile oder Desktop? var isLastChain = false; long? lastUserMsgId = null; - // Bestimme welche Chain als "vollständige letzte Chain" gilt. - // Wenn die letzte Chain leer oder nur tool_result enthält (z.B. nach ask_user_choice), - // dann muss die vorletzte Chain vollständig rekonstruiert werden. + // 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) int fullChainStartIndex = chainsList.Count - 1; - if (chainsList.Count >= 2) + for (int ci = chainsList.Count - 1; ci >= 1; ci--) { - var lastChainMsgs = (await _db.GetChainMessages(chainsList[chainsList.Count - 1].ChainId)).ToList(); - if (lastChainMsgs.Count == 0 || - (lastChainMsgs.All(m => m.Type == "tool_result") && lastChainMsgs.Count <= 2)) + var chainMsgs = (await _db.GetChainMessages(chainsList[ci].ChainId)).ToList(); + bool needsPrevious = chainMsgs.Count == 0 || + chainMsgs.Any(m => m.Type == "tool_result" && m.Iteration == 999); + if (needsPrevious) { - // Vorletzte Chain hatte einen ask_user_choice → beide Chains vollständig laden - fullChainStartIndex = chainsList.Count - 2; + // 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 + { + break; } } diff --git a/Services/SystemPromptBuilder.cs b/Services/SystemPromptBuilder.cs index 682270f..f30e360 100644 --- a/Services/SystemPromptBuilder.cs +++ b/Services/SystemPromptBuilder.cs @@ -89,7 +89,7 @@ Alle Dateipfade in Tool-Aufrufen müssen relativ zu diesem Workspace sein oder a { Icon = "fa-question-circle", Label = "Agent · Rückfragen (AllowUserChoice)", - Content = "## Rückfragen\nWenn du dir bei einer Aufgabe unsicher bist oder es mehrere sinnvolle Wege gibt, nutze das `ask_user_choice`-Tool um dem User eine Auswahlliste zu präsentieren. Nutze es, wenn eine Entscheidung vom User getroffen werden soll." + Content = "## Rückfragen\nWenn du dir bei einer Aufgabe unsicher bist oder es mehrere sinnvolle Wege gibt, nutze das `ask_user_choice`-Tool um dem User eine Auswahlliste zu präsentieren. Nutze es immer, wenn eine Entscheidung vom User getroffen werden soll." }); } diff --git a/Services/ToolService.cs b/Services/ToolService.cs index 136e4c5..b5c5714 100644 --- a/Services/ToolService.cs +++ b/Services/ToolService.cs @@ -71,7 +71,7 @@ public class ToolService return new { name = AskUserChoiceToolName, - description = "Stellt dem User eine Frage mit Auswahlmöglichkeiten, wenn du unsicher bist oder es mehrere sinnvolle Wege gibt. Der User wählt eine Option und du arbeitest mit seiner Antwort weiter. Nutze dies sparsam – nur wenn die Entscheidung wirklich vom User getroffen werden sollte.", + description = "Stellt dem User eine Frage mit Auswahlmöglichkeiten, wenn du unsicher bist oder es mehrere sinnvolle Wege gibt. Der User wählt eine Option und du arbeitest mit seiner Antwort weiter.", input_schema = new { type = "object",