V7 / 2a442462cf3f
ScheduleDelivery.cs
Lilith/Core/Scheduling/ScheduleDelivery.cs
Unchanged from the preceding versionCS
namespace Lilith.Core.Scheduling;
/// <summary>The host calls this only while it owns conversation and narration access.</summary>
public static class ScheduleDelivery
{
public static async Task DrainAsync(ProviderClient provider, Func<string, CancellationToken, Task> narrate,
CancellationToken ct = default)
{
var schedules = provider.Schedules ?? throw new InvalidOperationException("Configure schedules first.");
for (int i = 0; i < 10 && schedules.PeekEvent() is { } item; i++)
{
ct.ThrowIfCancellationRequested();
provider.RecordScheduleEvent(item);
string? failure = null;
Exception? speechFailure = null;
try
{
// A speech failure must not prevent the scheduled action from running.
try { await narrate(item.Message, ct); }
catch (Exception ex) when (ex is not OperationCanceledException)
{ speechFailure = ex; }
if (item.Job is { Scenario.Length: > 0 } job)
{
string reply = await provider.RunScheduledScenarioAsync(job.Scenario, job.Inputs, ct);
try { await narrate(reply, ct); }
catch (Exception ex) when (ex is not OperationCanceledException) { speechFailure = ex; }
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested) { throw; }
catch (Exception ex) { failure = ex.Message; }
schedules.CompleteEvent(item.Id, failure);
if (speechFailure is not null) throw new InvalidOperationException("Schedule speech failed; the action outcome was retained.", speechFailure);
}
}
}