feat: Memory-System mit persistenten Markdown-Dateien pro Agent

- MemoryService: Verwaltet data/agents/{agentId}/ Verzeichnisse
  - MEMORY.md als Haupt-Memory-File
  - memory/ Unterordner für Tages-Logs und thematische Notizen
  - Sandbox-Prüfung verhindert Zugriff außerhalb des Agent-Dirs

- Memory-Tools für den Agent:
  - memory_read: Liest Memory-Dateien
  - memory_write: Schreibt/überschreibt oder hängt an (append)
  - memory_list: Listet alle Memory-Dateien auf

- SystemPromptBuilder: Memory-Abschnitt mit Regeln und aktuellem
  MEMORY.md-Inhalt wird in den System-Prompt injiziert

- ToolService/AnthropicService: Memory-Tools werden automatisch
  eingebunden wenn MemoryService und AgentId verfügbar sind

- TODO.md: Embedding-basierte Suche und Subagents als Features
This commit is contained in:
Meleki committed 2026-03-01 13:27:08 +01:00
1 parent 875229964c
commit d913557173
8 files changed
+250 -14

No files matched your search

+98 -2
View File
@@ -11,7 +11,21 @@ namespace Gott.Services;
public class ToolService
{
public object[] GetToolDefinitions()
public object[] GetToolDefinitions(bool includeMemory = false)
{
var tools = GetFileTools();
if (includeMemory)
{
var memTools = GetMemoryToolDefinitions();
var all = new object[tools.Length + memTools.Length];
tools.CopyTo(all, 0);
memTools.CopyTo(all, tools.Length);
return all;
}
return tools;
}
private object[] GetFileTools()
{
return new object[]
{
@@ -105,7 +119,58 @@ public class ToolService
};
}
public async Task<string> ExecuteTool(string name, JsonElement input, string workspace)
private object[] GetMemoryToolDefinitions()
{
return new object[]
{
new
{
name = "memory_read",
description = "Liest eine Memory-Datei des Agents. Nutze dies um gespeicherte Erinnerungen, Notizen oder Kontextinformationen abzurufen.",
input_schema = new
{
type = "object",
properties = new Dictionary<string, object>
{
["path"] = new { type = "string", description = "Relativer Pfad zur Memory-Datei (z.B. 'MEMORY.md' oder 'memory/2025-01-15.md')" }
},
required = new[] { "path" }
}
},
new
{
name = "memory_write",
description = "Schreibt oder überschreibt eine Memory-Datei. Nutze dies um wichtige Informationen, Entscheidungen oder Präferenzen dauerhaft zu speichern.",
input_schema = new
{
type = "object",
properties = new Dictionary<string, object>
{
["path"] = new { type = "string", description = "Relativer Pfad zur Memory-Datei (z.B. 'MEMORY.md' oder 'memory/2025-01-15.md')" },
["content"] = new { type = "string", description = "Inhalt der Datei" },
["append"] = new { type = "boolean", description = "Wenn true, wird der Inhalt angehängt statt überschrieben (Default: false)" }
},
required = new[] { "path", "content" }
}
},
new
{
name = "memory_list",
description = "Listet alle Memory-Dateien des Agents auf.",
input_schema = new
{
type = "object",
properties = new Dictionary<string, object>
{
["path"] = new { type = "string", description = "Optionaler Unterpfad zum Auflisten (leer = Root)" }
},
required = Array.Empty<string>()
}
}
};
}
public async Task<string> ExecuteTool(string name, JsonElement input, string workspace, MemoryService memoryService = null, string agentId = null)
{
switch (name)
{
@@ -206,6 +271,37 @@ public class ToolService
else if (proc.ExitCode != 0) result.Append($"\n(exit code {proc.ExitCode})");
return result.ToString();
}
case "memory_read":
{
if (memoryService == null || string.IsNullOrEmpty(agentId))
return "Fehler: Memory-Service nicht verfügbar";
var path = input.GetProperty("path").GetString() ?? "";
var content = memoryService.ReadMemoryFile(agentId, path);
if (content == null)
return $"Datei nicht gefunden: {path}";
return content;
}
case "memory_write":
{
if (memoryService == null || string.IsNullOrEmpty(agentId))
return "Fehler: Memory-Service nicht verfügbar";
var path = input.GetProperty("path").GetString() ?? "";
var content = input.GetProperty("content").GetString() ?? "";
var append = input.TryGetProperty("append", out var a) && a.GetBoolean();
if (append)
memoryService.AppendMemoryFile(agentId, path, content);
else
memoryService.WriteMemoryFile(agentId, path, content);
return $"Memory-Datei {(append ? "erweitert" : "geschrieben")}: {path} ({content.Length} Zeichen)";
}
case "memory_list":
{
if (memoryService == null || string.IsNullOrEmpty(agentId))
return "Fehler: Memory-Service nicht verfügbar";
var subPath = input.TryGetProperty("path", out var p) ? p.GetString() ?? "" : "";
var files = memoryService.ListMemoryFiles(agentId, subPath);
return files.Count == 0 ? "(keine Memory-Dateien vorhanden)" : string.Join("\n", files);
}
default:
return $"Fehler: Unbekanntes Tool: {name}";
}