Eine einmalige Aufgabe mit fill_by (spaetestens bis) statt Termin laeuft, wenn der Tag Budget uebrig laesst: nach regulaerer und nachgeholter Arbeit, nur wenn nichts vom Agenten wartet, bevorzugt ab 18 Uhr, und nur wenn ihre eigene Schaetzung in den Spielraum aus #716 passt. Kurz vor der Frist wird einmal ein Mensch gefragt; nach der Frist laeuft sie als regulaere Arbeit. Ehrliche Schaetzung (TaskCostEstimator): eigene Laeufe, dann Geschwister unter derselben Elternaufgabe, dann die Angabe des Autors (als Schaetzung gekennzeichnet), zuletzt das Mittel des Agenten. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.4 KiB
C#
54 lines
2.4 KiB
C#
using System.Globalization;
|
|
using System.Text;
|
|
using ClawdDotNet.Core.Tasks;
|
|
|
|
namespace ClawdDotNet.Core.Budget;
|
|
|
|
/// <summary>
|
|
/// #717: The question to a human about fill work that has found no room before its deadline.
|
|
/// Only a human can answer it — raise the budget or move the deadline — so it goes on the
|
|
/// board as a human's task, below the fill work it is about.
|
|
/// </summary>
|
|
public static class FillWorkNotice
|
|
{
|
|
public static TaskItem QuestionFor(TaskItem fill, TaskEstimate estimate)
|
|
{
|
|
var body = new StringBuilder();
|
|
body.AppendLine($"Fill work {fill.Id} (\"{fill.Title}\") is due by {fill.FillBy:yyyy-MM-dd HH:mm} UTC " +
|
|
"and has not found room in the budget so far.");
|
|
body.AppendLine();
|
|
body.AppendLine($"Assigned to: {fill.Assignee}");
|
|
body.AppendLine($"Expected cost per run: {Describe(estimate)}");
|
|
body.AppendLine();
|
|
body.AppendLine("Fill work only runs on budget the rest of the day leaves unused. Please decide:");
|
|
body.AppendLine("- raise the agent's daily budget, or");
|
|
body.AppendLine($"- move the deadline (fill_by in {fill.Id}), or");
|
|
body.AppendLine("- leave it: at the deadline it runs as regular work, ahead of other late work.");
|
|
|
|
return new TaskItem
|
|
{
|
|
Title = $"Fill work {fill.Id} finds no room before its deadline",
|
|
Body = body.ToString().TrimEnd(),
|
|
Assignee = TaskAssignee.Human,
|
|
Type = TaskItemType.HumanInput,
|
|
Priority = Math.Clamp(fill.Priority + 1, 1, 5),
|
|
Status = TaskItemStatus.Todo,
|
|
ParentId = fill.Id
|
|
};
|
|
}
|
|
|
|
/// <summary>"0.80 USD (measured over 3 runs)" — and a guess says it is one.</summary>
|
|
public static string Describe(TaskEstimate estimate)
|
|
{
|
|
var usd = estimate.Run.CostUsd.ToString("0.00##", CultureInfo.InvariantCulture) + " USD";
|
|
return estimate.Source switch
|
|
{
|
|
EstimateSource.Measured => $"{usd} (measured over {estimate.Samples} run(s))",
|
|
EstimateSource.Siblings => $"{usd} (measured on {estimate.Samples} run(s) of its sibling tasks)",
|
|
EstimateSource.Stated => $"{usd} (estimated by its author, not measured)",
|
|
EstimateSource.AgentAverage => $"{usd} (the agent's average run, not measured on this task)",
|
|
_ => "unknown - nothing measured and no estimate given"
|
|
};
|
|
}
|
|
}
|