using ClawdDotNet.Core.Api.Models; namespace ClawdDotNet.Core.Engine; /// /// Setzt Prompt-Caching-Breakpoints in die Nachrichtenliste. /// /// Hintergrund: In einem Agenten-Run wird bei JEDEM Schritt der komplette Prompt erneut /// gesendet und voll berechnet — inklusive Tool-Definitionen und System-Prompt, die sich /// nie ändern. Bei zehn Schritten und einem 15k-Präfix sind das 150.000 Eingabe-Tokens /// statt 15.000. /// /// Ein Breakpoint markiert das Ende eines stabilen Prompt-Abschnitts. Alles davor wird /// beim nächsten Aufruf aus dem Cache gelesen und kostet nur einen Bruchteil. /// /// Zwei Breakpoints werden gesetzt: /// 1. auf den System-Prompt — deckt Tool-Definitionen und System-Prompt ab, /// 2. rollierend auf die letzte Nachricht — deckt den bereits gelaufenen Gesprächsverlauf ab. /// public static class PromptCache { /// /// Modelle, bei denen "auto" das Caching einschaltet. Andere Anbieter ignorieren /// cache_control entweder oder cachen ohnehin automatisch. /// private static readonly string[] AutoEnabledPrefixes = ["anthropic/"]; public static bool IsEnabledFor(string setting, string model) => setting?.ToLowerInvariant() switch { "on" => true, "off" => false, _ => AutoEnabledPrefixes.Any(p => model.StartsWith(p, StringComparison.OrdinalIgnoreCase)) }; /// /// Setzt die Breakpoints neu. Vorherige werden entfernt, damit sich pro Schritt /// nie mehr als die beabsichtigten Markierungen ansammeln. /// public static void ApplyBreakpoints(List messages) { foreach (var msg in messages) msg.CacheBreakpoint = false; if (messages.Count == 0) return; // 1. System-Prompt — der stabilste Teil überhaupt. var system = messages[0].Role == "system" ? messages[0] : null; if (system?.Content is not null) system.CacheBreakpoint = true; // 2. Letzte Nachricht mit Inhalt. Beim nächsten Schritt ist alles bis hierher // unverändert und wird aus dem Cache gelesen. // Eine assistant-Nachricht mit tool_calls hat keinen Textinhalt und kann // deshalb keinen Block tragen — in dem Fall bleibt es beim System-Breakpoint. for (var i = messages.Count - 1; i >= 1; i--) { if (messages[i].Content is null) continue; if (!ReferenceEquals(messages[i], system)) messages[i].CacheBreakpoint = true; break; } } }