fix: Tag-Feld für Sub-Agent-Messages – verhindert API 400 bei tool_use ohne tool_result

- 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.
This commit is contained in:
Meleki committed 2026-03-07 15:37:28 +01:00
1 parent 494f431963
commit 43d3e9dc26
4 files changed
+17 -9

No files matched your search

+1
View File
@@ -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; }
+8 -4
View File
@@ -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
});
}
}
+3 -1
View File
@@ -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)
+5 -4
View File
@@ -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<long>(@"
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<long>(@"
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);