using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Gott.Services; public class MemoryService { private readonly string _dataDir; public string DataDir => _dataDir; public MemoryService(string dataDir) { _dataDir = dataDir; } /// /// 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 (!targetDir.StartsWith(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(Path.GetRelativePath(baseDir, dir) + "/"); foreach (var file in Directory.GetFiles(targetDir)) entries.Add(Path.GetRelativePath(baseDir, file)); return entries; } /// /// Erstellt die Standard-Files (IDENTITY.md, SOUL.md) für einen neuen 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)) { File.WriteAllText(identityPath, $@"# IDENTITY.md - Who Am I? - **Name:** {agentName} - **Creature:** Unbekannt - **Vibe:** Unbekannt - **Language:** Deutsch "); } var soulPath = Path.Combine(dir, "SOUL.md"); if (!File.Exists(soulPath)) { File.WriteAllText(soulPath, @"# SOUL.md - Who You Are ## Core Truths **Be genuinely helpful, not performatively helpful.** Skip filler words - just help. Actions speak louder. **Be resourceful before asking.** Try to figure it out. Read the file. Check the context. _Then_ ask if you're stuck. **Earn trust through competence.** Be careful with external actions. Be bold with internal ones (reading, organizing, building). ## Continuity Each session, you wake up fresh. These files _are_ your memory. Read them. Update them. They're how you persist. --- _This file is yours to evolve. As you learn who you are, update it._ "); } } /// /// 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 (!full.StartsWith(baseDir)) return null; return full; } }