< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Diagnostics.DiagnosticsCharCounter
Assembly: NexusLabs.Needlr.AgentFramework
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework/Diagnostics/DiagnosticsCharCounter.cs
Line coverage
96%
Covered lines: 28
Uncovered lines: 1
Coverable lines: 29
Total lines: 104
Line coverage: 96.5%
Branch coverage
90%
Covered branches: 20
Total branches: 22
Branch coverage: 90.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
ChatMessagesLength(...)100%44100%
ChatResponseLength(...)100%22100%
JsonLength(...)100%22100%
SumTextContents(...)85.71%141488.88%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework/Diagnostics/DiagnosticsCharCounter.cs

#LineLine coverage
 1using System.Text.Json;
 2
 3using Microsoft.Extensions.AI;
 4
 5namespace NexusLabs.Needlr.AgentFramework.Diagnostics;
 6
 7/// <summary>
 8/// Computes character counts of chat messages, responses, tool arguments, and tool
 9/// results for diagnostics capture. Character counts are a direct programmatic
 10/// measure of payload size — distinct from the LLM-provider-reported
 11/// <see cref="TokenUsage"/> — and are useful for detecting chat-reducer drift,
 12/// prompt bloat, and unexpectedly large tool responses during evaluation.
 13/// </summary>
 14/// <remarks>
 15/// All methods are null-safe and exception-tolerant: any failure to measure
 16/// returns <c>0</c> rather than throwing. This matches the diagnostics alpha
 17/// invariant that capture must never destabilize the live path.
 18/// </remarks>
 19public static class DiagnosticsCharCounter
 20{
 121    private static readonly JsonSerializerOptions _options = new()
 122    {
 123        WriteIndented = false,
 124    };
 25
 26    /// <summary>
 27    /// Sums the character count of all text contents across the supplied chat
 28    /// messages. Non-text content (images, function calls) is ignored.
 29    /// </summary>
 30    public static long ChatMessagesLength(IEnumerable<ChatMessage>? messages)
 31    {
 60832        if (messages is null)
 33        {
 134            return 0;
 35        }
 36
 60737        long total = 0;
 326638        foreach (var message in messages)
 39        {
 102640            total += SumTextContents(message.Contents);
 41        }
 60742        return total;
 43    }
 44
 45    /// <summary>
 46    /// Sums the character count of all text contents across every message in the
 47    /// supplied <see cref="ChatResponse"/>. Returns <c>0</c> when the response
 48    /// is <see langword="null"/> or contains no text content.
 49    /// </summary>
 50    public static long ChatResponseLength(ChatResponse? response)
 51    {
 29852        if (response is null)
 53        {
 154            return 0;
 55        }
 56
 29757        return ChatMessagesLength(response.Messages);
 58    }
 59
 60    /// <summary>
 61    /// Returns the character length of the JSON-serialized representation of
 62    /// the supplied value. Null-safe and exception-tolerant: returns <c>0</c>
 63    /// when the value is <see langword="null"/> or cannot be serialized.
 64    /// </summary>
 65    public static long JsonLength(object? value)
 66    {
 32567        if (value is null)
 68        {
 7769            return 0;
 70        }
 71
 72        try
 73        {
 24874            var json = JsonSerializer.Serialize(value, _options);
 24775            return json.Length;
 76        }
 177        catch
 78        {
 179            return 0;
 80        }
 24881    }
 82
 83    private static long SumTextContents(IList<AIContent>? contents)
 84    {
 102685        if (contents is null || contents.Count == 0)
 86        {
 087            return 0;
 88        }
 89
 102690        long total = 0;
 413291        foreach (var content in contents)
 92        {
 104093            if (content is TextContent text && text.Text is not null)
 94            {
 70795                total += text.Text.Length;
 96            }
 33397            else if (content is TextReasoningContent reasoning && reasoning.Text is not null)
 98            {
 399                total += reasoning.Text.Length;
 100            }
 101        }
 1026102        return total;
 103    }
 104}