mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-09-27 00:13:38 +00:00
Read the reported token usage in one place
This commit is contained in:
parent
bbd73f389b
commit
ceb78ff9b7
@ -1123,11 +1123,12 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
// send it as the last line of the stream, with no choices at all. It is handled
|
||||
// before the check below, which would otherwise drop it as an empty response.
|
||||
//
|
||||
if (providerResponse.ContainsUsage())
|
||||
var usage = providerResponse.GetUsage();
|
||||
if (usage.IsKnown)
|
||||
{
|
||||
yield return providerResponse.ContainsContent()
|
||||
? providerResponse.GetContent() with { Usage = providerResponse.GetUsage() }
|
||||
: new(string.Empty, [], providerResponse.GetUsage());
|
||||
? providerResponse.GetContent() with { Usage = usage }
|
||||
: new(string.Empty, [], usage);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -29,10 +29,7 @@ public readonly record struct ResponseStreamLine(string Id, string Object, uint
|
||||
public ChatCompletionUsage? Usage { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsUsage() => this.GetUsage().IsKnown;
|
||||
|
||||
/// <inheritdoc />
|
||||
public TokenUsage GetUsage() => this.Usage is null ? TokenUsage.UNKNOWN : TokenUsage.OfReported(this.Usage.PromptTokens, this.Usage.CompletionTokens);
|
||||
public TokenUsage GetUsage() => this.Usage?.ToTokenUsage() ?? TokenUsage.UNKNOWN;
|
||||
|
||||
#region Implementation of IAnnotationStreamLine
|
||||
|
||||
|
||||
@ -18,18 +18,16 @@ public interface IResponseStreamLine : IAnnotationStreamLine
|
||||
public ContentStreamChunk GetContent();
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the response line states what the request cost.
|
||||
/// Gets what the provider said the request cost.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Answered here for every wire format which says nothing about it, which is most of them: a
|
||||
/// provider who reports no usage is the normal case, not a gap somebody has to fill in.
|
||||
///
|
||||
/// Unlike content and sources, there is no separate check for whether a line carries it. This
|
||||
/// never fails on a line without one, and whether the answer means anything is what IsKnown of
|
||||
/// the returned usage says.
|
||||
/// </remarks>
|
||||
/// <returns>True when the response line carries a token usage, false otherwise.</returns>
|
||||
public bool ContainsUsage() => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets what the provider said the request cost.
|
||||
/// </summary>
|
||||
/// <returns>The usage, or TokenUsage.UNKNOWN when the line carries none.</returns>
|
||||
public TokenUsage GetUsage() => TokenUsage.UNKNOWN;
|
||||
}
|
||||
@ -34,10 +34,7 @@ public record ChatCompletionDeltaStreamLine(string Id, string Object, uint Creat
|
||||
public ContentStreamChunk GetContent() => new(this.Choices[0].Delta.Content, []);
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsUsage() => this.GetUsage().IsKnown;
|
||||
|
||||
/// <inheritdoc />
|
||||
public TokenUsage GetUsage() => this.Usage is null ? TokenUsage.UNKNOWN : TokenUsage.OfReported(this.Usage.PromptTokens, this.Usage.CompletionTokens);
|
||||
public TokenUsage GetUsage() => this.Usage?.ToTokenUsage() ?? TokenUsage.UNKNOWN;
|
||||
|
||||
#region Implementation of IAnnotationStreamLine
|
||||
|
||||
|
||||
@ -22,9 +22,12 @@ public sealed record ChatCompletionUsage
|
||||
public int? CompletionTokens { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// What the provider says both of them add up to. Read but not relied upon: it is the sum of
|
||||
/// the other two wherever a provider fills all three, and this way a provider which sends only
|
||||
/// this one is not a reason to throw the other numbers away.
|
||||
/// States what this block reports, as far as it can be believed.
|
||||
/// </summary>
|
||||
public int? TotalTokens { get; init; }
|
||||
/// <remarks>
|
||||
/// The one way from the wire to a usage, shared by every stream line which carries this block,
|
||||
/// so that what counts as believable is decided in a single place.
|
||||
/// </remarks>
|
||||
/// <returns>The usage, or TokenUsage.UNKNOWN when the block states nothing usable.</returns>
|
||||
public TokenUsage ToTokenUsage() => TokenUsage.OfReported(this.PromptTokens, this.CompletionTokens);
|
||||
}
|
||||
@ -30,10 +30,7 @@ public readonly record struct ResponseStreamLine(string Id, string Object, uint
|
||||
public ChatCompletionUsage? Usage { get; init; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsUsage() => this.GetUsage().IsKnown;
|
||||
|
||||
/// <inheritdoc />
|
||||
public TokenUsage GetUsage() => this.Usage is null ? TokenUsage.UNKNOWN : TokenUsage.OfReported(this.Usage.PromptTokens, this.Usage.CompletionTokens);
|
||||
public TokenUsage GetUsage() => this.Usage?.ToTokenUsage() ?? TokenUsage.UNKNOWN;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsSources() => this != default && this.SearchResults.Count > 0;
|
||||
|
||||
@ -41,7 +41,7 @@ public sealed class ChatCompletionUsageTests
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(line!.ContainsUsage(), Is.True);
|
||||
Assert.That(line!.GetUsage().IsKnown, Is.True);
|
||||
Assert.That(line.GetUsage().PromptTokens, Is.EqualTo(1200));
|
||||
Assert.That(line.GetUsage().CompletionTokens, Is.EqualTo(345));
|
||||
Assert.That(line.GetUsage().TotalTokens, Is.EqualTo(1545));
|
||||
@ -61,8 +61,7 @@ public sealed class ChatCompletionUsageTests
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(line!.ContainsUsage(), Is.False);
|
||||
Assert.That(line.GetUsage().IsKnown, Is.False);
|
||||
Assert.That(line!.GetUsage().IsKnown, Is.False);
|
||||
Assert.That(line.ContainsContent(), Is.True);
|
||||
});
|
||||
}
|
||||
@ -103,7 +102,7 @@ public sealed class ChatCompletionUsageTests
|
||||
{"id":"chatcmpl-1","object":"chat.completion.chunk","created":1,"model":"gpt-5","choices":[],"usage":{"prompt_tokens":0,"completion_tokens":0}}
|
||||
""", ProviderJsonOptions.OPTIONS);
|
||||
|
||||
Assert.That(line!.ContainsUsage(), Is.False);
|
||||
Assert.That(line!.GetUsage().IsKnown, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -124,7 +123,7 @@ public sealed class ChatCompletionUsageTests
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(line!.ContainsUsage(), Is.True);
|
||||
Assert.That(line!.GetUsage().IsKnown, Is.True);
|
||||
Assert.That(line.GetUsage().TotalTokens, Is.EqualTo(133));
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user