namespace AIStudio.Provider; /// /// What a provider said one request actually carried, in tokens. /// /// /// The counterpart to what the app counts for itself: the app estimates what the next request will /// cost, while this is what the provider counted for the last one. Two different statements, and /// this one is the only exact one of the two. /// /// Only the prompt is kept. Providers state what the answer cost as well, but that number includes /// the model's reasoning and whatever the model wrote between think tags, and neither of them ever /// becomes part of the answer's text. No later request carries them, so the number has no place in /// a statement about those requests. /// /// Nothing here says "unknown" with a zero. The default value of this type is unknown, which is the /// right answer for every provider which reports nothing, and a counted request can never cost zero /// prompt tokens because the factory below refuses to build one. /// public readonly record struct TokenUsage { /// /// The usage of a request nobody reported anything about. /// public static readonly TokenUsage UNKNOWN = new(); /// /// Whether a provider reported anything at all. When false, the number is meaningless. /// public bool IsKnown { get; private init; } /// /// What everything sent to the model cost: the conversation so far, its attachments, the system /// prompt, and whatever tools were offered. /// public int PromptTokens { get; private init; } /// /// States what a provider reported. /// /// /// A prompt of zero is not a report, because there is no request without one, and a provider /// sending it means we read the wrong field. /// /// What the request carried. Has to be greater than zero. /// The usage. public static TokenUsage Of(int promptTokens) { ArgumentOutOfRangeException.ThrowIfNegativeOrZero(promptTokens); return new() { IsKnown = true, PromptTokens = promptTokens, }; } /// /// States what a provider reported, or unknown when it reported nothing usable. /// /// /// For the reading side, where the number comes out of somebody else's JSON: a missing field, a /// null, or a zero all mean the same thing there, and none of them is worth an exception. /// /// What the request carried, as the provider stated it. /// The usage, or UNKNOWN. public static TokenUsage OfReported(int? promptTokens) => promptTokens is > 0 ? Of(promptTokens.Value) : UNKNOWN; }