Files
ClawdDotNet/src/ClawdDotNet.Core/Accounting/UsageModels.cs
T

86 lines
3.2 KiB
C#

namespace ClawdDotNet.Core.Accounting;
/// <summary>Verbrauch eines abgeschlossenen Laufs.</summary>
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; }
/// <summary>Anteil der Eingabe-Tokens aus dem Prompt-Cache — in PromptTokens enthalten.</summary>
public int CachedTokens { get; init; }
public int TotalTokens => PromptTokens + CompletionTokens;
public decimal CostUsd { get; init; }
/// <summary>
/// Ob für das Modell Preise vorlagen. Ohne diese Angabe wäre eine zu niedrige
/// Summe von einer vollständigen nicht zu unterscheiden.
/// </summary>
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; }
/// <summary>
/// #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.
/// </summary>
public string BudgetPot { get; init; } = "";
/// <summary>#712: The runtime of the run; empty for native.</summary>
public string Runtime { get; init; } = "";
/// <summary>#712: Paid from a subscription's quota. The cost is 0 $, the tokens are real (#699).</summary>
public bool OnSubscription { get; init; }
}
/// <summary>Verbrauch eines Tages, aggregiert.</summary>
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);
/// <summary>Tagesverbrauch eines Agenten. <paramref name="agentId"/> leer = ganze Instanz.</summary>
Task<DailyUsage> GetDailyAsync(DateOnly date, string agentId, CancellationToken ct);
/// <summary>
/// #717: What counts against the daily limits — the day's usage without runs that drew on
/// a special budget. <see cref="GetDailyAsync"/> keeps showing everything that was used.
/// </summary>
Task<DailyUsage> GetDailyForBudgetAsync(DateOnly date, string agentId, CancellationToken ct)
=> GetDailyAsync(date, agentId, ct);
Task<IReadOnlyList<RunUsage>> GetRecentAsync(int limit, CancellationToken ct);
/// <summary>
/// #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.
/// </summary>
Task<IReadOnlyList<RunUsage>> GetRecentForAgentAsync(string agentId, int limit, CancellationToken ct)
=> Task.FromResult<IReadOnlyList<RunUsage>>([]);
/// <summary>Entfernt Einträge älter als das angegebene Datum. Gibt die Anzahl zurück.</summary>
Task<int> PurgeBeforeAsync(DateOnly date, CancellationToken ct);
}