< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Workflows.Budget.TokenBudgetExtensions
Assembly: NexusLabs.Needlr.AgentFramework.Workflows
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Workflows/Budget/TokenBudgetExtensions.cs
Line coverage
100%
Covered lines: 30
Uncovered lines: 0
Coverable lines: 30
Total lines: 72
Line coverage: 100%
Branch coverage
60%
Covered branches: 6
Total branches: 10
Branch coverage: 60%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
UsingTokenTracking(...)66.66%66100%
UsingTokenBudget(...)50%44100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Workflows/Budget/TokenBudgetExtensions.cs

#LineLine coverage
 1using Microsoft.Extensions.AI;
 2using Microsoft.Extensions.DependencyInjection;
 3
 4using NexusLabs.Needlr.AgentFramework;
 5using NexusLabs.Needlr.AgentFramework.Budget;
 6using NexusLabs.Needlr.AgentFramework.Progress;
 7
 8namespace NexusLabs.Needlr.AgentFramework.Workflows.Budget;
 9
 10/// <summary>
 11/// Extension methods for wiring token-budget enforcement into the agent framework.
 12/// </summary>
 13public static class TokenBudgetExtensions
 14{
 15    /// <summary>
 16    /// Wires <see cref="TokenUsageRecordingMiddleware"/> to record token usage from
 17    /// every LLM call into <see cref="ITokenBudgetTracker"/>. This enables
 18    /// <see cref="ITokenBudgetTracker.CurrentTokens"/> without enforcing any budget.
 19    /// </summary>
 20    /// <remarks>
 21    /// Idempotent — calling this multiple times (or via both <c>UsingTokenBudget()</c>
 22    /// and <c>UsingDiagnostics()</c>) wires the recording middleware exactly once.
 23    /// </remarks>
 24    public static AgentFrameworkSyringe UsingTokenTracking(
 25        this AgentFrameworkSyringe syringe)
 26    {
 3727        ArgumentNullException.ThrowIfNull(syringe);
 3828        if (syringe.TokenTrackingWired) return syringe;
 29
 3630        var result = syringe.Configure(opts =>
 3631        {
 3532            var tracker = opts.ServiceProvider.GetRequiredService<ITokenBudgetTracker>();
 3533            var existingFactory = opts.ChatClientFactory;
 3534            opts.ChatClientFactory = sp =>
 3535            {
 4436                var innerClient = existingFactory?.Invoke(sp)
 4437                    ?? sp.GetRequiredService<IChatClient>();
 4438                return new TokenUsageRecordingMiddleware(innerClient, tracker);
 3539            };
 7140        });
 41
 3642        return result with { TokenTrackingWired = true };
 43    }
 44
 45    /// <summary>
 46    /// Wraps the configured <see cref="IChatClient"/> with <see cref="TokenBudgetChatMiddleware"/>,
 47    /// enabling per-pipeline token budgets via <see cref="ITokenBudgetTracker"/>.
 48    /// Automatically includes <see cref="UsingTokenTracking"/> for token recording.
 49    /// </summary>
 50    public static AgentFrameworkSyringe UsingTokenBudget(
 51        this AgentFrameworkSyringe syringe)
 52    {
 153        ArgumentNullException.ThrowIfNull(syringe);
 54
 155        syringe = syringe.UsingTokenTracking();
 56
 157        return syringe.Configure(opts =>
 158        {
 159            var tracker = opts.ServiceProvider.GetRequiredService<ITokenBudgetTracker>();
 160            var progressAccessor = opts.ServiceProvider.GetRequiredService<IProgressReporterAccessor>();
 161
 162            var existingFactory = opts.ChatClientFactory;
 163            opts.ChatClientFactory = sp =>
 164            {
 165                var innerClient = existingFactory?.Invoke(sp)
 166                    ?? sp.GetRequiredService<IChatClient>();
 167
 168                return new TokenBudgetChatMiddleware(innerClient, tracker, progressAccessor);
 169            };
 270        });
 71    }
 72}