using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Gott.Services; public class MemoryService { private readonly string _dataDir; private readonly string _templateDir; public string DataDir => _dataDir; public MemoryService(string dataDir) { _dataDir = dataDir; _templateDir = Path.Combine(AppContext.BaseDirectory, "Templates"); } /// /// Liest ein Template aus dem Templates-Ordner. Gibt null zurück wenn nicht vorhanden. /// private string ReadTemplate(string fileName) { var path = Path.Combine(_templateDir, fileName); return File.Exists(path) ? File.ReadAllText(path) : null; } /// /// Gibt den Memory-Ordner für einen Agent zurück. Erstellt ihn bei Bedarf. /// public string GetAgentMemoryDir(string agentId) { var dir = Path.Combine(_dataDir, "agents", agentId); Directory.CreateDirectory(dir); return dir; } /// /// Liest eine Memory-Datei. Gibt null zurück wenn nicht vorhanden. /// public string ReadMemoryFile(string agentId, string fileName) { var path = ResolvePath(agentId, fileName); if (path == null || !File.Exists(path)) return null; return File.ReadAllText(path); } /// /// Schreibt/überschreibt eine Memory-Datei. /// public void WriteMemoryFile(string agentId, string fileName, string content) { var path = ResolvePath(agentId, fileName); if (path == null) throw new Exception("Ungültiger Dateipfad"); var dir = Path.GetDirectoryName(path); if (dir != null) Directory.CreateDirectory(dir); File.WriteAllText(path, content); } /// /// Hängt Inhalt an eine Memory-Datei an. /// public void AppendMemoryFile(string agentId, string fileName, string content) { var path = ResolvePath(agentId, fileName); if (path == null) throw new Exception("Ungültiger Dateipfad"); var dir = Path.GetDirectoryName(path); if (dir != null) Directory.CreateDirectory(dir); File.AppendAllText(path, content); } /// /// Listet alle Memory-Dateien eines Agents auf. /// public List ListMemoryFiles(string agentId, string subPath = null) { var baseDir = GetAgentMemoryDir(agentId); var targetDir = string.IsNullOrEmpty(subPath) ? baseDir : Path.GetFullPath(Path.Combine(baseDir, subPath)); if (!WorkspaceHelper.IsSubPathOf(targetDir, baseDir)) throw new Exception("Zugriff außerhalb des Memory-Verzeichnisses nicht erlaubt"); if (!Directory.Exists(targetDir)) return new List(); var entries = new List(); foreach (var dir in Directory.GetDirectories(targetDir)) entries.Add(WorkspaceHelper.GetRelativePath(baseDir, dir) + "/"); foreach (var file in Directory.GetFiles(targetDir)) entries.Add(WorkspaceHelper.GetRelativePath(baseDir, file)); return entries; } /// /// Erstellt die Standard-Files (IDENTITY.md, SOUL.md) für einen Agent. /// Überschreibt NICHT, falls bereits vorhanden. /// public void InitializeAgentFiles(string agentId, string agentName) { var dir = GetAgentMemoryDir(agentId); var identityPath = Path.Combine(dir, "IDENTITY.md"); if (!File.Exists(identityPath)) { var template = ReadTemplate("IDENTITY.md") ?? "# IDENTITY.md\n"; File.WriteAllText(identityPath, template.Replace("{NAME}", agentName)); } var soulPath = Path.Combine(dir, "SOUL.md"); if (!File.Exists(soulPath)) { var template = ReadTemplate("SOUL.md") ?? "# SOUL.md\n"; File.WriteAllText(soulPath, template); } InitializeUserFile(); } /// /// Erstellt die globale USER.md im Data-Ordner, falls nicht vorhanden. /// public void InitializeUserFile() { var userPath = Path.Combine(_dataDir, "USER.md"); if (!File.Exists(userPath)) { var template = ReadTemplate("USER.md") ?? "# USER.md\n"; File.WriteAllText(userPath, template); } } /// /// Liest MEMORY.md (das Haupt-Memory-File). Gibt leeren String zurück wenn nicht vorhanden. /// public string GetMainMemory(string agentId) { return ReadMemoryFile(agentId, "MEMORY.md") ?? ""; } /// /// Löst einen Pfad relativ zum Agent-Memory-Dir auf und prüft Sandbox. /// private string ResolvePath(string agentId, string fileName) { var baseDir = GetAgentMemoryDir(agentId); var full = Path.GetFullPath(Path.Combine(baseDir, fileName)); if (!WorkspaceHelper.IsSubPathOf(full, baseDir)) return null; return full; } }