ScenarioSystem/ScenarioLog.cscsharp

Documentation

Lilith (Version 3)

Version 3 Lilith agent library. Entry point: Lilith.cs with partials under Boot/, Chat/, Ollama/, and SystemPrompt/.

Build the solution or run python ../Build-v3.py from this tree.

using Agent.Core.Logging;namespace Lilith.Agent.ScenarioSystem;/// <summary>/// Scenario log wrapper for the AdminDashboard test overlay./// The overlay already renders a dedicated "Task" bubble for lines starting with "Delegating to "./// We exploit that convention to create distinct boxes for scenarios + steps without changing Logger./// </summary>internal static class ScenarioLog{    // Unique marker codes so the overlay can style scenario headers differently.    // These are embedded inside the "Delegating to ..." line so existing overlay logic still works.    private const string ScenarioMarker = "[SCN]";    private const string StepMarker = "[STP]";    public static IDisposable BeginScenario(Lilith lilith, string scenarioId, string? title = null)    {        WriteDelegation(lilith, ScenarioMarker, $"Scenario {scenarioId}{(string.IsNullOrWhiteSpace(title) ? "" : $"{title}")}");        return new Scope(() => WriteDelegation(lilith, ScenarioMarker, $"Scenario {scenarioId} — done"));    }    public static IDisposable BeginStep(Lilith lilith, int stepIndex1, int totalSteps, string prompt)    {        var shortPrompt = Trunc(prompt, 100);        WriteDelegation(lilith, StepMarker, $"Step {stepIndex1}/{totalSteps}: {shortPrompt}");        return new Scope(() => { });    }    private static void WriteDelegation(Lilith lilith, string marker, string text)    {        // IMPORTANT: in the DLL-based runner, the dashboard only receives Logger output.        // So emit via Lilith.Logger (and keep the exact "Delegating to ..." prefix).        lilith.Logger.WriteLine("Scenario", $"Delegating to {marker} {text}", LogColors.Gray);    }    private static string Trunc(string s, int max)    {        s = (s ?? "").Replace("\r", " ").Replace("\n", " ").Trim();        return s.Length > max ? s[..max] + "…" : s;    }    private sealed class Scope(Action onDispose) : IDisposable    {        public void Dispose() => onDispose();    }}