Review-Agent: nur Text-Konversation übergeben + Doku aktualisiert
BuildReviewMessages() komplett umgebaut: - Tool-Calls und Tool-Results werden nicht mehr übergeben - Nur noch die reine Text-Konversation (user/assistant) wird extrahiert - Aufeinanderfolgende Messages gleicher Rolle werden zusammengeführt - Korrekte user/assistant-Abwechslung sichergestellt - Fallback wenn nur Tool-Calls ohne Text vorhanden - Unnötigen Serialisierungs-Roundtrip für Rollen-Prüfung entfernt Erwartete Token-Ersparnis: 50-100k+ Input-Tokens pro Review-Runde bei typischen Worker-Sessions mit vielen write_file/edit_file-Calls. ARCHITECTURE.md: - Inhaltsverzeichnis-Nummerierung korrigiert (22-28 statt doppelt 20-21) - ServerSettingsEndpoint.cs in Projektstruktur ergänzt - Tabellenbeschreibungen vervollständigt (users, agents, sessions, chains, messages, cronjobs) mit allen fehlenden Feldern - ChainRecord/MessageRecord/SessionWithStats Felder aktualisiert - AutoCommit mention-Beschreibung korrigiert ARCHITECTURE_QUICK.md: - ToolService 12 → 13 Tools korrigiert - Tabellenbeschreibungen analog zur Hauptdoku aktualisiert
This commit is contained in:
1 parent
87bde0cbaf
commit
f3b6491643
3 files changed
+113
-50
No files matched your search
+29
-18
@@ -33,13 +33,13 @@
|
||||
19. [Interaktive Rückfragen (ask_user_choice)](#interaktive-rückfragen-ask_user_choice)
|
||||
20. [Plan-Modus](#plan-modus)
|
||||
21. [Nachrichten teilen (Shared Messages)](#nachrichten-teilen-shared-messages)
|
||||
20. [Workspace & File-Explorer](#workspace--file-explorer)
|
||||
21. [Avatar-System](#avatar-system)
|
||||
22. [LaTeX/Math-Rendering](#latexmath-rendering)
|
||||
23. [Windows Desktop App](#windows-desktop-app)
|
||||
24. [Deployment](#deployment)
|
||||
25. [Konfiguration](#konfiguration)
|
||||
26. [Datenbank-Migrationen](#datenbank-migrationen)
|
||||
22. [Workspace & File-Explorer](#workspace--file-explorer)
|
||||
23. [Avatar-System](#avatar-system)
|
||||
24. [LaTeX/Math-Rendering](#latexmath-rendering)
|
||||
25. [Windows Desktop App](#windows-desktop-app)
|
||||
26. [Deployment](#deployment)
|
||||
27. [Konfiguration](#konfiguration)
|
||||
28. [Datenbank-Migrationen](#datenbank-migrationen)
|
||||
|
||||
---
|
||||
|
||||
@@ -143,6 +143,7 @@ gott/
|
||||
│ ├── SkillEndpoint.cs # List, Agent-Skill-Mapping, Output-Files
|
||||
│ ├── SharedEndpoint.cs # Nachrichten teilen (öffentliche Links)
|
||||
│ ├── AdminEndpoint.cs # Admin: User-CRUD, Impersonate (Admin-only)
|
||||
│ ├── ServerSettingsEndpoint.cs # Admin: Server-Settings lesen/schreiben (Admin-only)
|
||||
│ ├── ProfileEndpoint.cs # Profil, Persona, Passwort
|
||||
│ ├── SettingsEndpoint.cs # User-Settings (JSON blob)
|
||||
│ ├── BackupEndpoint.cs # Backup als tar.gz Download
|
||||
@@ -277,16 +278,16 @@ Message (1) ─── (*) SharedMessage
|
||||
|
||||
| Tabelle | Beschreibung |
|
||||
|-------------------|-----------------------------------------------------|
|
||||
| `users` | Benutzer (username, password_hash, persona, settings, default_path) |
|
||||
| `users` | Benutzer (username, password_hash, display_name, is_admin, persona, settings, default_path) |
|
||||
| `tokens` | Auth-Tokens (token → user_id) |
|
||||
| `agents` | AI-Agenten (model, soul, identity, memory, tools, avatar_scale, avatar_offset_x/y, allow_user_choice, task_instruction, avatar_small) |
|
||||
| `sessions` | Chat-Sessions (workspace, context, telegram-config, avatar_scale, avatar_offset_x/y, telegram_allowed_chat_ids, preparer_agent_id, review_agent_id, max_review_iterations, finalizer_agent_id, image_small) |
|
||||
| `chains` | Request-Chains (model, tokens, iterations, timing) |
|
||||
| `messages` | Einzelne Nachrichten (text, tool_use, tool_result, web_search_result) |
|
||||
| `agents` | AI-Agenten (model, tool_choice, custom_commands, auto_commit, use_soul/identity/user_info/memory, use_web_search, web_search_version, allow_user_choice, task_instruction, avatar_scale/offset, avatar_small) |
|
||||
| `sessions` | Chat-Sessions (description, image, image_small, workspace, context, custom_commands, telegram-config, telegram_allowed_chat_ids, avatar_scale/offset, preparer_agent_id, review_agent_id, max_review_iterations, finalizer_agent_id) |
|
||||
| `chains` | Request-Chains (model, tokens, iterations, timing, tool_choice, tool_names, stream_error_info, plan_mode, archive_id) |
|
||||
| `messages` | Einzelne Nachrichten (text, tool_use, tool_result, error, web_search_result), Tag für Sub-Agent-Markierung |
|
||||
| `attachments` | Datei-Anhänge (base64, image/document) |
|
||||
| `archives` | Archivierte Chain-Gruppen |
|
||||
| `agent_skills` | Agent ↔ Skill Zuordnung |
|
||||
| `cronjobs` | Geplante Tasks (cron expression, prompt) |
|
||||
| `cronjobs` | Geplante Tasks (cron expression, prompt, notify_session_id, is_enabled, last_run, next_run) |
|
||||
| `shared_messages` | Geteilte Nachrichten (Share-Token, Ablaufdatum) |
|
||||
| `telegram_links` | Telegram Chat ↔ Session Verknüpfung |
|
||||
|
||||
@@ -295,26 +296,36 @@ Message (1) ─── (*) SharedMessage
|
||||
**ChainRecord** – Repräsentiert einen kompletten Request-Response-Zyklus:
|
||||
- `ChainId` – Eindeutige ID
|
||||
- `SessionId` – Zugehörige Session
|
||||
- `AgentId` – Zugehöriger Agent
|
||||
- `Model` – Verwendetes Claude-Modell (z.B. `claude-sonnet-4-6`)
|
||||
- `SystemPrompt` – Der vollständige System-Prompt (gespeichert für Nachvollziehbarkeit)
|
||||
- `InputTokens`, `OutputTokens`, `CacheCreationTokens`, `CacheReadTokens` – Token-Verbrauch
|
||||
- `Iterations` – Anzahl der Tool-Loop-Durchläufe
|
||||
- `StopReason` – `end_turn`, `tool_use`, `max_iterations`, `error`, `client_disconnected`, `awaiting_user_choice`, `preparer_query`
|
||||
- `ToolChoice` – Verwendete Tool-Choice-Strategie
|
||||
- `ToolNames` – Komma-separierte Liste der verwendeten Tools
|
||||
- `ArchiveId` – Zugehöriges Archiv (wenn archiviert)
|
||||
- `StreamErrorInfo` – Fehlerdetails bei Stream-Abbrüchen
|
||||
- `PlanMode` – Ob die Chain im Plan-Modus erstellt wurde (informativ)
|
||||
- `DurationMs` – Gesamtdauer der Chain
|
||||
|
||||
**MessageRecord** – Eine einzelne Nachricht innerhalb einer Chain:
|
||||
- `Role` – `user`, `assistant`, `system`
|
||||
- `Role` – `user`, `assistant`
|
||||
- `Type` – `text`, `tool_use`, `tool_result`, `error`, `web_search_result`
|
||||
- `Content` – Textinhalt oder JSON (bei tool_use: Input-JSON)
|
||||
- `ToolName`, `ToolCallId` – Bei Tool-Aufrufen
|
||||
- `IsMarked` – Als wichtig markierte Nachricht (wird in System-Prompt aufgenommen)
|
||||
- `IsError` – Ob die Nachricht ein Fehler ist
|
||||
- `Iteration` – Welche Tool-Loop-Iteration
|
||||
- `AttachmentCount` – Anzahl angehängter Dateien
|
||||
- `AttachmentNames` – JSON-Array mit Dateinamen
|
||||
- `Tag` – Sub-Agent-Markierung (`null` = normal, `"preparer"/"review"/"finalizer"` = Sub-Agent-Message, wird aus API-History gefiltert)
|
||||
- `IsMarked` – Als wichtig markierte Nachricht (wird in System-Prompt aufgenommen)
|
||||
- `DeletedOn` – Soft-Delete Zeitstempel
|
||||
|
||||
**SessionWithStats** – Erweitertes Session-Objekt für Listen-Endpunkt:
|
||||
- Enthält alle `SessionRecord`-Felder + `MessageCount`, `ArchiveCount`
|
||||
- `GitStatus` – Inline Git-Status-Summary (`Add`, `Edit`, `Delete`, `Outgoing`) oder `null` wenn kein Workspace
|
||||
- Enthält alle `SessionRecord`-Felder + `MessageCount`, `ArchiveMessageCount`, `TotalMessageCount`
|
||||
- `TelegramConfigured`, `TelegramLinked` – Telegram-Status
|
||||
- `GitStatus` – Inline Git-Status-Summary (`Add`, `Edit`, `Delete`, `Outgoing`) oder `null` wenn kein Workspace (wird im Endpoint hinzugefügt, nicht Teil des Records)
|
||||
- `Image` wird durch `ImageSmall` ersetzt (Thumbnail für Dashboard-Performance)
|
||||
|
||||
**GitStatusSummary** – Kompakte Git-Status-Info:
|
||||
@@ -647,7 +658,7 @@ Ein **Agent** definiert die Persönlichkeit und Fähigkeiten der AI:
|
||||
| `Model` | `sonnet`, `sonnet-4-5`, `sonnet-4-6`, `opus`, `opus-4-5`, `opus-4-6`, `haiku`, `haiku-4-5` |
|
||||
| `ToolChoice` | `any` oder `auto` |
|
||||
| `CustomCommands` | JSON-Array mit Slash-Commands (Label + Prompt) |
|
||||
| `AutoCommit` | `""` (nichts), `"mention"` (verbieten), `"enforce"` (erzwingen), `"forbid"` (strikt verboten) |
|
||||
| `AutoCommit` | `""` (nichts), `"mention"` (anmerken – nur auf User-Request), `"enforce"` (erzwingen – nach jeder Änderung), `"forbid"` (strikt verboten) |
|
||||
| `UseSoul` | SOUL.md in System-Prompt einbinden |
|
||||
| `UseIdentity` | IDENTITY.md in System-Prompt einbinden |
|
||||
| `UseUserInfo` | User-Persona in System-Prompt einbinden |
|
||||
|
||||
@@ -63,11 +63,11 @@ User 1──* Agent 1──* Session 1──* Chain 1──* Message 1──* At
|
||||
|
||||
| Tabelle | Zweck |
|
||||
|---------|-------|
|
||||
| `users` | Login, Persona, Settings (JSON), DefaultPath |
|
||||
| `users` | Login, DisplayName, IsAdmin, Persona, Settings (JSON), DefaultPath |
|
||||
| `tokens` | Auth-Tokens → User |
|
||||
| `agents` | AI-Agenten (Model, Tools, Config, AvatarScale, AvatarOffsetX/Y, AvatarSmall) |
|
||||
| `sessions` | Chat-Sessions (Workspace, Context, Telegram, AvatarScale, AvatarOffsetX/Y, AllowedChatIds, PreparerAgentId, ReviewAgentId, MaxReviewIterations, FinalizerAgentId, ImageSmall) |
|
||||
| `chains` | Ein Request-Response-Zyklus (Tokens, Timing, Iterations, PlanMode) |
|
||||
| `agents` | AI-Agenten (Model, ToolChoice, CustomCommands, AutoCommit, UseSoul/Identity/UserInfo/Memory, WebSearch, AllowUserChoice, TaskInstruction, AvatarScale/Offset, AvatarSmall) |
|
||||
| `sessions` | Chat-Sessions (Description, Image, ImageSmall, Workspace, Context, CustomCommands, Telegram, AvatarScale/Offset, AllowedChatIds, PreparerAgentId, ReviewAgentId, MaxReviewIterations, FinalizerAgentId) |
|
||||
| `chains` | Ein Request-Response-Zyklus (Tokens, Timing, Iterations, PlanMode, ToolChoice, ToolNames, StreamErrorInfo, ArchiveId) |
|
||||
| `messages` | Einzelne Nachrichten (text / tool_use / tool_result / error / web_search_result), Tag für Sub-Agent-Markierung |
|
||||
| `attachments` | Base64-Anhänge (Bilder, Dokumente) |
|
||||
| `archives` | Archivierte Chain-Gruppen |
|
||||
@@ -110,7 +110,7 @@ User 1──* Agent 1──* Session 1──* Chain 1──* Message 1──* At
|
||||
| **AuthService** | Token-Auth, Passwort-Hashing (SHA256) |
|
||||
| **ChatService** | Chat-Kontext aufbauen, History aus DB laden |
|
||||
| **AnthropicService** | Claude API: SSE Streaming + Non-Streaming |
|
||||
| **ToolService** | Tool-Definitionen + Ausführung (12 Tools) |
|
||||
| **ToolService** | Tool-Definitionen + Ausführung (13 Tools) |
|
||||
| **WorkspaceHelper** | Workspace-Pfad-Auflösung (relativ → absolut), Path-Traversal-Schutz (static) |
|
||||
| **SystemPromptBuilder** | System-Prompt aus modularen Blöcken zusammenbauen (static) |
|
||||
| **MemoryService** | Agent-Gedächtnis auf Dateisystem |
|
||||
|
||||
@@ -524,10 +524,13 @@ public class AnthropicService
|
||||
/// </summary>
|
||||
private List<object> BuildReviewMessages(List<object> workerMessages)
|
||||
{
|
||||
// Worker-Konversation zusammenfassen
|
||||
var summary = new StringBuilder();
|
||||
summary.AppendLine("Hier ist die bisherige Konversation zwischen User und Worker-Agent. Bitte überprüfe ob die Aufgabe korrekt erledigt wurde:\n");
|
||||
summary.AppendLine("---");
|
||||
// Nur die Text-Konversation extrahieren – Tool-Calls und Tool-Results weglassen.
|
||||
// Der Review/Finalizer-Agent hat eigene Tools und kann bei Bedarf selbst Dateien lesen.
|
||||
// Aufeinanderfolgende Messages gleicher Rolle werden zusammengeführt,
|
||||
// da die Anthropic API abwechselnde user/assistant-Rollen erfordert.
|
||||
var messages = new List<object>();
|
||||
string lastRole = null;
|
||||
var currentParts = new List<string>();
|
||||
|
||||
foreach (var msg in workerMessages)
|
||||
{
|
||||
@@ -537,11 +540,15 @@ public class AnthropicService
|
||||
if (!el.TryGetProperty("role", out var role)) continue;
|
||||
var roleStr = role.GetString() ?? "";
|
||||
|
||||
var textParts = new List<string>();
|
||||
|
||||
if (el.TryGetProperty("content", out var content))
|
||||
{
|
||||
if (content.ValueKind == JsonValueKind.String)
|
||||
{
|
||||
summary.AppendLine($"\n**{roleStr}:** {content.GetString()}");
|
||||
var s = content.GetString() ?? "";
|
||||
if (!string.IsNullOrWhiteSpace(s))
|
||||
textParts.Add(s);
|
||||
}
|
||||
else if (content.ValueKind == JsonValueKind.Array)
|
||||
{
|
||||
@@ -551,37 +558,82 @@ public class AnthropicService
|
||||
if (blockType == "text")
|
||||
{
|
||||
var text = block.TryGetProperty("text", out var t) ? t.GetString() ?? "" : "";
|
||||
summary.AppendLine($"\n**{roleStr}:** {text}");
|
||||
}
|
||||
else if (blockType == "tool_use")
|
||||
{
|
||||
var toolName = block.TryGetProperty("name", out var tn) ? tn.GetString() ?? "" : "";
|
||||
var toolInput = block.TryGetProperty("input", out var ti) ? ti.ToString() : "{}";
|
||||
summary.AppendLine($"\n**{roleStr} [Tool: {toolName}]:** {toolInput}");
|
||||
}
|
||||
else if (blockType == "tool_result")
|
||||
{
|
||||
var resultContent = block.TryGetProperty("content", out var rc) ? rc.ToString() : "";
|
||||
// Tool-Results kürzen für Review-Kontext
|
||||
if (resultContent.Length > 2000)
|
||||
resultContent = resultContent[..2000] + "\n[... gekürzt]";
|
||||
summary.AppendLine($"\n**{roleStr} [Tool-Result]:** {resultContent}");
|
||||
if (!string.IsNullOrWhiteSpace(text))
|
||||
textParts.Add(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
summary.AppendLine("\n---");
|
||||
summary.AppendLine("\nBitte überprüfe ob die Aufgabe korrekt erledigt wurde. Du kannst dazu auch Tools verwenden (z.B. Dateien lesen). Antworte mit exakt [APPROVED] wenn alles korrekt ist, oder beschreibe was falsch ist und korrigiert werden muss.");
|
||||
|
||||
return new List<object>
|
||||
if (textParts.Count == 0) continue;
|
||||
|
||||
if (roleStr == lastRole)
|
||||
{
|
||||
new Dictionary<string, object>
|
||||
// Gleiche Rolle wie vorher → zusammenführen
|
||||
currentParts.AddRange(textParts);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Neue Rolle → vorherige Message abschließen
|
||||
if (lastRole != null && currentParts.Count > 0)
|
||||
{
|
||||
messages.Add(new Dictionary<string, object>
|
||||
{
|
||||
["role"] = lastRole,
|
||||
["content"] = new List<object> { new { type = "text", text = string.Join("\n\n", currentParts) } }
|
||||
});
|
||||
}
|
||||
lastRole = roleStr;
|
||||
currentParts = new List<string>(textParts);
|
||||
}
|
||||
}
|
||||
|
||||
// Letzte angesammelte Message abschließen
|
||||
if (lastRole != null && currentParts.Count > 0)
|
||||
{
|
||||
messages.Add(new Dictionary<string, object>
|
||||
{
|
||||
["role"] = lastRole,
|
||||
["content"] = new List<object> { new { type = "text", text = string.Join("\n\n", currentParts) } }
|
||||
});
|
||||
}
|
||||
|
||||
// Anthropic erfordert: erste Message = user, letzte Message = user,
|
||||
// und abwechselnde Rollen (durch die Zusammenführung oben bereits sichergestellt).
|
||||
if (messages.Count > 0)
|
||||
{
|
||||
var first = (Dictionary<string, object>)messages[0];
|
||||
if ((string)first["role"] == "assistant")
|
||||
{
|
||||
messages.Insert(0, new Dictionary<string, object>
|
||||
{
|
||||
["role"] = "user",
|
||||
["content"] = new List<object> { new { type = "text", text = summary.ToString() } }
|
||||
["content"] = new List<object> { new { type = "text", text = "Hier ist die bisherige Konversation. Bitte überprüfe den aktuellen Zustand." } }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var last = (Dictionary<string, object>)messages[messages.Count - 1];
|
||||
if ((string)last["role"] == "assistant")
|
||||
{
|
||||
messages.Add(new Dictionary<string, object>
|
||||
{
|
||||
["role"] = "user",
|
||||
["content"] = new List<object> { new { type = "text", text = "Bitte überprüfe ob die Aufgabe korrekt erledigt wurde." } }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Falls keine Text-Messages vorhanden, Fallback mit Hinweis
|
||||
if (messages.Count == 0)
|
||||
{
|
||||
messages.Add(new Dictionary<string, object>
|
||||
{
|
||||
["role"] = "user",
|
||||
["content"] = new List<object> { new { type = "text", text = "Die bisherige Konversation enthielt nur Tool-Aufrufe ohne Text. Bitte überprüfe den aktuellen Zustand des Workspaces mit deinen Tools." } }
|
||||
});
|
||||
}
|
||||
|
||||
return messages;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in new issue
Block a user