namespace ClawdDotNet.Core.Accounting;
/// Verbrauch eines abgeschlossenen Laufs.
public sealed record RunUsage
{
public long Id { get; init; }
public string AgentId { get; init; } = "";
public string Model { get; init; } = "";
public int PromptTokens { get; init; }
public int CompletionTokens { get; init; }
/// Anteil der Eingabe-Tokens aus dem Prompt-Cache — in PromptTokens enthalten.
public int CachedTokens { get; init; }
public int TotalTokens => PromptTokens + CompletionTokens;
public decimal CostUsd { get; init; }
///
/// Ob für das Modell Preise vorlagen. Ohne diese Angabe wäre eine zu niedrige
/// Summe von einer vollständigen nicht zu unterscheiden.
///
public bool CostIsKnown { get; init; }
public string Status { get; init; } = "";
public int StepCount { get; init; }
public long DurationMs { get; init; }
public DateTime OccurredAt { get; init; }
///
/// #717: The task whose special budget the run drew on; empty for the daily budget. Such
/// runs do not count against the daily limits — that is what the pot is for.
///
public string BudgetPot { get; init; } = "";
/// #712: The runtime of the run; empty for native.
public string Runtime { get; init; } = "";
/// #712: Paid from a subscription's quota. The cost is 0 $, the tokens are real (#699).
public bool OnSubscription { get; init; }
}
/// Verbrauch eines Tages, aggregiert.
public sealed record DailyUsage(
DateOnly Date,
int PromptTokens,
int CompletionTokens,
decimal CostUsd,
bool CostIsComplete,
int RunCount)
{
public int TotalTokens => PromptTokens + CompletionTokens;
public static DailyUsage Empty(DateOnly date) => new(date, 0, 0, 0m, true, 0);
}
public interface IUsageRepository
{
Task RecordAsync(RunUsage usage, CancellationToken ct);
/// Tagesverbrauch eines Agenten. leer = ganze Instanz.
Task GetDailyAsync(DateOnly date, string agentId, CancellationToken ct);
///
/// #717: What counts against the daily limits — the day's usage without runs that drew on
/// a special budget. keeps showing everything that was used.
///
Task GetDailyForBudgetAsync(DateOnly date, string agentId, CancellationToken ct)
=> GetDailyAsync(date, agentId, ct);
Task> GetRecentAsync(int limit, CancellationToken ct);
///
/// #716: The most recent runs of one agent — the basis for estimating what a run of
/// it will cost. Without an implementation there is no estimate, and a reservation
/// counts nothing.
///
Task> GetRecentForAgentAsync(string agentId, int limit, CancellationToken ct)
=> Task.FromResult>([]);
/// Entfernt Einträge älter als das angegebene Datum. Gibt die Anzahl zurück.
Task PurgeBeforeAsync(DateOnly date, CancellationToken ct);
}