From 43d3e9dc26e864e23df39ef5402fdcdf84408579 Mon Sep 17 00:00:00 2001 From: Meleki Date: Sat, 7 Mar 2026 15:37:28 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20Tag-Feld=20f=C3=BCr=20Sub-Agent-Messages?= =?UTF-8?q?=20=E2=80=93=20verhindert=20API=20400=20bei=20tool=5Fuse=20ohne?= =?UTF-8?q?=20tool=5Fresult?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - MessageRecord: neues Tag-Feld (null=normal, preparer/review/finalizer=Sub-Agent) - DatabaseService: Migration tag-Spalte, INSERT-Statements erweitert - AnthropicService: RunAgentChat setzt Tag=agentType bei allen 4 SaveMessage-Aufrufen - ChatService: BuildHistoryFromDb filtert getaggte Messages aus API-History Sub-Agent-Messages bleiben in der DB (Frontend-Anzeige), werden aber nie an die Claude API geschickt – löst das Problem für Preparer, Review und Finalizer gleichermaßen. --- Models/MessageRecord.cs | 1 + Services/AnthropicService.cs | 12 ++++++++---- Services/ChatService.cs | 4 +++- Services/DatabaseService.cs | 9 +++++---- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Models/MessageRecord.cs b/Models/MessageRecord.cs index 5397399..e60aaba 100644 --- a/Models/MessageRecord.cs +++ b/Models/MessageRecord.cs @@ -13,6 +13,7 @@ public class MessageRecord public int Iteration { get; set; } // welche Loop-Iteration public int AttachmentCount { get; set; } // Anzahl angehängter Dateien public string AttachmentNames { get; set; } // JSON-Array mit Dateinamen + public string Tag { get; set; } // null = normal, "preparer"/"review"/"finalizer" = Sub-Agent-Message public bool IsMarked { get; set; } // als wichtig markiert public string DeletedOn { get; set; } // null = aktiv, sonst Zeitstempel der Löschung public string CreatedAt { get; set; } diff --git a/Services/AnthropicService.cs b/Services/AnthropicService.cs index 246aba0..b52ccd8 100644 --- a/Services/AnthropicService.cs +++ b/Services/AnthropicService.cs @@ -691,7 +691,8 @@ public class AnthropicService Iteration = baseIterations + iterations, Role = "assistant", Type = "text", - Content = $"[{tag}: {agentName}] {text}" + Content = $"[{tag}: {agentName}] {text}", + Tag = agentType }); } else if (blockType == "tool_use") @@ -718,7 +719,8 @@ public class AnthropicService Type = "tool_use", Content = toolInput.GetRawText(), ToolName = toolName, - ToolCallId = toolId + ToolCallId = toolId, + Tag = agentType }); string toolResult; @@ -748,7 +750,8 @@ public class AnthropicService Content = toolResult, ToolName = toolName, ToolCallId = toolId, - IsError = isError + IsError = isError, + Tag = agentType }); } else if (blockType == "web_search_tool_result") @@ -779,7 +782,8 @@ public class AnthropicService Iteration = baseIterations + iterations, Role = "assistant", Type = "web_search_result", - Content = JsonSerializer.Serialize(sources) + Content = JsonSerializer.Serialize(sources), + Tag = agentType }); } } diff --git a/Services/ChatService.cs b/Services/ChatService.cs index 35e1340..ca28ddb 100644 --- a/Services/ChatService.cs +++ b/Services/ChatService.cs @@ -329,7 +329,9 @@ Bitte speichere es in die Datei products.json im Workspace. var chain = chainsList[i]; isLastChain = (i == chainsList.Count - 1); - var msgs = (await _db.GetChainMessages(chain.ChainId)).ToList(); + var msgs = (await _db.GetChainMessages(chain.ChainId)) + .Where(m => string.IsNullOrEmpty(m.Tag)) // Sub-Agent-Messages (preparer/review/finalizer) aus API-History ausfiltern + .ToList(); // Letzte User-Message-ID der letzten Chain merken (für Attachments) if (isLastChain || i == fullChainStartIndex) diff --git a/Services/DatabaseService.cs b/Services/DatabaseService.cs index ba2d74d..199b9a7 100644 --- a/Services/DatabaseService.cs +++ b/Services/DatabaseService.cs @@ -181,6 +181,7 @@ public class DatabaseService TryAddColumn(conn, "agents", "allow_user_choice", "INTEGER NOT NULL DEFAULT 1"); TryAddColumn(conn, "chains", "plan_mode", "INTEGER NOT NULL DEFAULT 0"); TryAddColumn(conn, "sessions", "preparer_agent_id", "TEXT"); + TryAddColumn(conn, "messages", "tag", "TEXT"); conn.Execute(@" CREATE TABLE IF NOT EXISTS agent_skills ( @@ -629,8 +630,8 @@ public class DatabaseService using var conn = CreateConnection(); record.CreatedAt = DateTime.UtcNow.ToString("o"); return await conn.ExecuteScalarAsync(@" - INSERT INTO messages (chain_id, role, type, content, tool_name, tool_call_id, is_error, iteration, attachment_count, created_at) - VALUES (@ChainId, @Role, @Type, @Content, @ToolName, @ToolCallId, @IsError, @Iteration, @AttachmentCount, @CreatedAt); + INSERT INTO messages (chain_id, role, type, content, tool_name, tool_call_id, is_error, iteration, attachment_count, tag, created_at) + VALUES (@ChainId, @Role, @Type, @Content, @ToolName, @ToolCallId, @IsError, @Iteration, @AttachmentCount, @Tag, @CreatedAt); SELECT last_insert_rowid(); ", record); } @@ -651,8 +652,8 @@ public class DatabaseService record.AttachmentNames = System.Text.Json.JsonSerializer.Serialize(names); } var messageId = await conn.ExecuteScalarAsync(@" - INSERT INTO messages (chain_id, role, type, content, tool_name, tool_call_id, is_error, iteration, attachment_count, attachment_names, created_at) - VALUES (@ChainId, @Role, @Type, @Content, @ToolName, @ToolCallId, @IsError, @Iteration, @AttachmentCount, @AttachmentNames, @CreatedAt); + INSERT INTO messages (chain_id, role, type, content, tool_name, tool_call_id, is_error, iteration, attachment_count, attachment_names, tag, created_at) + VALUES (@ChainId, @Role, @Type, @Content, @ToolName, @ToolCallId, @IsError, @Iteration, @AttachmentCount, @AttachmentNames, @Tag, @CreatedAt); SELECT last_insert_rowid(); ", record, tx);