using System.ComponentModel; using ClawdDotNet.Core.Config; namespace ClawdDotNet.Models; [TypeConverter(typeof(ExpandableObjectConverter))] public sealed class AgentSettingsViewModel { private readonly AgentConfig _config; public AgentSettingsViewModel(AgentConfig config) { _config = config; } // ──────────────── Identity ──────────────── [Category("1 - Identity")] [DisplayName("Agent-ID")] [Description("Eindeutige ID des Agenten. Wird intern und in Logs verwendet.")] [ReadOnly(true)] public string AgentId => _config.AgentId; [Category("1 - Identity")] [DisplayName("Anzeigename")] [Description("Freundlicher Name des Agenten (z.B. 'Marktanalyst').")] public string DisplayName { get => _config.DisplayName; set => _config.DisplayName = value; } [Category("1 - Identity")] [DisplayName("Modell")] [Description("LLM-Modell das dieser Agent verwendet. Dropdown zeigt verfügbare Modelle von OpenRouter.")] [TypeConverter(typeof(ModelTypeConverter))] public string Model { get => _config.Model; set => _config.Model = value; } [Category("1 - Identity")] [DisplayName("Identity")] [Description("Aus Identity.md geladen – definiert WER der Agent ist. Bearbeitung über den Toolbar-Button 'Identity bearbeiten'.")] [ReadOnly(true)] public string IdentityStatus => string.IsNullOrWhiteSpace(_config.Identity) ? "(nicht definiert)" : $"✔ {_config.Identity.Split('\n').Length} Zeilen"; [Category("1 - Identity")] [DisplayName("Soul")] [Description("Aus Soul.md geladen – definiert WIE der Agent denkt. Bearbeitung über den Toolbar-Button 'Soul bearbeiten'.")] [ReadOnly(true)] public string SoulStatus => string.IsNullOrWhiteSpace(_config.Soul) ? "(nicht definiert)" : $"✔ {_config.Soul.Split('\n').Length} Zeilen"; // ──────────────── Loop-Schutz ──────────────── [Category("2 - Loop-Schutz")] [DisplayName("Max. Schritte pro Run")] [Description("Maximale Anzahl LLM-Aufrufe pro Run. Verhindert Endlosschleifen bei fehlerhaften Tool-Calls.")] public int MaxSteps { get => _config.LoopGuard.MaxSteps; set => _config.LoopGuard.MaxSteps = Math.Max(1, value); } [Category("2 - Loop-Schutz")] [DisplayName("Kostenbudget pro Run (Tokens)")] [Description("Summe ALLER abgerechneten Tokens eines Runs über alle Schritte. " + "Da jeder Schritt den kompletten Kontext erneut sendet, wächst diese Summe " + "überproportional — der Wert liegt deutlich über der Kontextgröße. " + "Für die Kontextgröße ist 'Max. Kontext-Tokens' zuständig.")] public int MaxCumulativeTokens { get => _config.LoopGuard.MaxCumulativeTokens; set => _config.LoopGuard.MaxCumulativeTokens = Math.Max(10_000, value); } [Category("2 - Loop-Schutz")] [DisplayName("Timeout (Sekunden)")] [Description("Maximale Laufzeit pro Run in Sekunden. Danach wird der Run abgebrochen.")] public int TimeoutSeconds { get => _config.LoopGuard.TimeoutSeconds; set => _config.LoopGuard.TimeoutSeconds = Math.Max(10, value); } // ──────────────── Kontext-Management ──────────────── [Category("3 - Kontext-Management")] [DisplayName("Max. Kontext-Tokens")] [Description("Maximales Token-Budget für den gesamten Konversationskontext. Bei Überschreitung wird automatisch kompaktiert.")] public int MaxContextTokens { get => _config.LoopGuard.MaxContextTokens; set => _config.LoopGuard.MaxContextTokens = Math.Max(10_000, value); } [Category("3 - Kontext-Management")] [DisplayName("Kompaktierungs-Schwelle (%)")] [Description("Ab welchem Prozentsatz der Max. Kontext-Tokens wird kompaktiert. 80 = bei 80% Auslastung. Stufe 1: Tool-Results kürzen. Stufe 2: LLM-Zusammenfassung.")] public int CompactionThresholdPercent { get => (int)(_config.LoopGuard.CompactionThreshold * 100); set => _config.LoopGuard.CompactionThreshold = Math.Clamp(value, 50, 95) / 100.0; } // ──────────────── Tools (Read-Only) ──────────────── [Category("4 - Tools")] [DisplayName("Zugewiesene Tools")] [Description("Liste der Tool-Namen, die diesem Agent zugewiesen sind. Zuweisung über die Tabelle unten.")] [ReadOnly(true)] public string AssignedTools => _config.Tools.Count == 0 ? "(keine)" : string.Join(", ", _config.Tools.Keys); [Category("4 - Tools")] [DisplayName("Anzahl")] [ReadOnly(true)] public int ToolCount => _config.Tools.Count; // ──────────────── Intern ──────────────── [Browsable(false)] public AgentConfig UnderlyingConfig => _config; public override string ToString() => string.IsNullOrWhiteSpace(_config.DisplayName) ? _config.AgentId : _config.DisplayName; }