< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Diagnostics.AgentDiagnosticsAccessor
Assembly: NexusLabs.Needlr.AgentFramework
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework/Diagnostics/AgentDiagnosticsAccessor.cs
Line coverage
100%
Covered lines: 24
Uncovered lines: 0
Coverable lines: 24
Total lines: 78
Line coverage: 100%
Branch coverage
83%
Covered branches: 5
Total branches: 6
Branch coverage: 83.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%11100%
get_LastRunDiagnostics()100%22100%
get_CompletionCollector()100%11100%
get_ToolCallCollector()100%11100%
BeginCapture()100%11100%
NexusLabs.Needlr.AgentFramework.Diagnostics.IAgentDiagnosticsWriter.Set(...)100%11100%
Set(...)100%11100%
SetCore(...)100%22100%
.ctor(...)100%11100%
Dispose()50%22100%

File(s)

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

#LineLine coverage
 1namespace NexusLabs.Needlr.AgentFramework.Diagnostics;
 2
 3/// <summary>
 4/// <see cref="AsyncLocal{T}"/>-backed implementation of <see cref="IAgentDiagnosticsAccessor"/>
 5/// using the mutable-holder pattern. A mutable <see cref="Holder"/> reference is stored in the
 6/// <see cref="AsyncLocal{T}"/> slot — because the reference flows downward, mutations made by
 7/// child async flows (middleware) are visible to the parent scope.
 8/// </summary>
 9[DoNotAutoRegister]
 10internal sealed class AgentDiagnosticsAccessor : IAgentDiagnosticsAccessor, IAgentDiagnosticsWriter
 11{
 112    private static readonly AsyncLocal<Holder?> Current = new();
 13    private readonly IChatCompletionCollector? _completionCollector;
 14    private readonly IToolCallCollector? _toolCallCollector;
 15
 9716    internal AgentDiagnosticsAccessor(
 9717        ChatCompletionCollectorHolder? completionCollector = null,
 9718        ToolCallCollectorHolder? toolCallCollector = null)
 19    {
 9720        _completionCollector = completionCollector;
 9721        _toolCallCollector = toolCallCollector;
 9722    }
 23
 24    /// <inheritdoc />
 4225    public IAgentRunDiagnostics? LastRunDiagnostics => Current.Value?.Value;
 26
 27    /// <inheritdoc />
 1628    public IChatCompletionCollector? CompletionCollector => _completionCollector;
 29
 30    /// <inheritdoc />
 1031    public IToolCallCollector? ToolCallCollector => _toolCallCollector;
 32
 33    /// <inheritdoc />
 34    public IDisposable BeginCapture()
 35    {
 3336        var previous = Current.Value;
 3337        Current.Value = new Holder();
 3338        return new Scope(previous);
 39    }
 40
 41    /// <inheritdoc />
 4642    void IAgentDiagnosticsWriter.Set(IAgentRunDiagnostics diagnostics) => SetCore(diagnostics);
 43
 44    /// <summary>
 45    /// Stores completed diagnostics into the current holder. Called by the diagnostics
 46    /// middleware after an agent run completes.
 47    /// </summary>
 648    internal void Set(IAgentRunDiagnostics diagnostics) => SetCore(diagnostics);
 49
 50    private static void SetCore(IAgentRunDiagnostics diagnostics)
 51    {
 5252        if (Current.Value is { } holder)
 53        {
 3554            holder.Value = diagnostics;
 55        }
 56        else
 57        {
 1758            Current.Value = new Holder { Value = diagnostics };
 59        }
 1760    }
 61
 62    private sealed class Holder
 63    {
 64        public IAgentRunDiagnostics? Value;
 65    }
 66
 3367    private sealed class Scope(Holder? previous) : IDisposable
 68    {
 69        private bool _disposed;
 70
 71        public void Dispose()
 72        {
 3373            if (_disposed) return;
 3374            _disposed = true;
 3375            Current.Value = previous;
 3376        }
 77    }
 78}