< Summary

Information
Class: NexusLabs.Needlr.AgentFramework.Evaluation.CapturedChatResponsePayload
Assembly: NexusLabs.Needlr.AgentFramework.Evaluation
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Evaluation/CapturedChatResponsePayload.cs
Line coverage
60%
Covered lines: 53
Uncovered lines: 35
Coverable lines: 88
Total lines: 165
Line coverage: 60.2%
Branch coverage
47%
Covered branches: 22
Total branches: 46
Branch coverage: 47.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_ResponseId()100%11100%
get_ModelId()100%11100%
get_Messages()100%11100%
FromChatResponse(...)66.66%461855.81%
ToChatResponse()35.71%1172851.51%
get_Role()100%11100%
get_Text()100%11100%
get_Contents()100%11100%
get_Kind()100%11100%
get_Text()100%11100%
get_CallId()100%11100%
get_Name()100%11100%
get_Arguments()100%11100%
get_Result()100%11100%

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.AgentFramework.Evaluation/CapturedChatResponsePayload.cs

#LineLine coverage
 1using System.Text.Json;
 2
 3using Microsoft.Extensions.AI;
 4
 5namespace NexusLabs.Needlr.AgentFramework.Evaluation;
 6
 7/// <summary>
 8/// Serialization-friendly projection of a <see cref="ChatResponse"/> used by
 9/// <see cref="FileEvaluationCaptureStore"/>. Captures textual content, function
 10/// call payloads, and function result payloads in their original message order.
 11/// </summary>
 12internal sealed class CapturedChatResponsePayload
 13{
 1214    public string? ResponseId { get; set; }
 1215    public string? ModelId { get; set; }
 2016    public List<CapturedMessage> Messages { get; set; } = new();
 17
 18    public static CapturedChatResponsePayload FromChatResponse(ChatResponse response)
 19    {
 420        var messages = new List<CapturedMessage>(response.Messages.Count);
 1821        foreach (var message in response.Messages)
 22        {
 523            var captured = new CapturedMessage
 524            {
 525                Role = message.Role.Value,
 526                Text = message.Text,
 527            };
 28
 529            if (message.Contents.Count > 0)
 30            {
 531                var contents = new List<CapturedContent>();
 2032                foreach (var content in message.Contents)
 33                {
 34                    switch (content)
 35                    {
 36                        case FunctionCallContent fc:
 037                            contents.Add(new CapturedContent
 038                            {
 039                                Kind = CapturedContentKind.FunctionCall,
 040                                CallId = fc.CallId,
 041                                Name = fc.Name,
 042                                Arguments = fc.Arguments is not null
 043                                    ? JsonSerializer.Serialize(fc.Arguments)
 044                                    : null,
 045                            });
 046                            break;
 47                        case FunctionResultContent fr:
 048                            contents.Add(new CapturedContent
 049                            {
 050                                Kind = CapturedContentKind.FunctionResult,
 051                                CallId = fr.CallId,
 052                                Result = fr.Result is not null
 053                                    ? JsonSerializer.Serialize(fr.Result)
 054                                    : null,
 055                            });
 056                            break;
 57                        case TextContent tc:
 558                            contents.Add(new CapturedContent
 559                            {
 560                                Kind = CapturedContentKind.Text,
 561                                Text = tc.Text,
 562                            });
 63                            break;
 64                    }
 65                }
 66
 567                if (contents.Count > 0)
 68                {
 569                    captured.Contents = contents;
 70                }
 71            }
 72
 573            messages.Add(captured);
 74        }
 75
 476        return new CapturedChatResponsePayload
 477        {
 478            ResponseId = response.ResponseId,
 479            ModelId = response.ModelId,
 480            Messages = messages,
 481        };
 82    }
 83
 84    public ChatResponse ToChatResponse()
 85    {
 286        var messages = new List<ChatMessage>(Messages.Count);
 1087        foreach (var captured in Messages)
 88        {
 389            var role = string.IsNullOrEmpty(captured.Role)
 390                ? ChatRole.Assistant
 391                : new ChatRole(captured.Role);
 92
 393            if (captured.Contents is { Count: > 0 })
 94            {
 395                var contentItems = new List<AIContent>(captured.Contents.Count);
 1296                foreach (var c in captured.Contents)
 97                {
 398                    switch (c.Kind)
 99                    {
 100                        case CapturedContentKind.Text:
 3101                            contentItems.Add(new TextContent(c.Text ?? string.Empty));
 3102                            break;
 103                        case CapturedContentKind.FunctionCall:
 0104                            IDictionary<string, object?>? args = null;
 0105                            if (c.Arguments is not null)
 106                            {
 0107                                args = JsonSerializer
 0108                                    .Deserialize<Dictionary<string, object?>>(c.Arguments);
 109                            }
 0110                            contentItems.Add(new FunctionCallContent(
 0111                                c.CallId ?? string.Empty,
 0112                                c.Name ?? string.Empty,
 0113                                args));
 0114                            break;
 115                        case CapturedContentKind.FunctionResult:
 0116                            object? result = null;
 0117                            if (c.Result is not null)
 118                            {
 0119                                result = JsonSerializer.Deserialize<JsonElement>(c.Result);
 120                            }
 0121                            contentItems.Add(new FunctionResultContent(
 0122                                c.CallId ?? string.Empty,
 0123                                result));
 124                            break;
 125                    }
 126                }
 3127                messages.Add(new ChatMessage(role, contentItems));
 128            }
 129            else
 130            {
 0131                messages.Add(new ChatMessage(role, captured.Text ?? string.Empty));
 132            }
 133        }
 134
 2135        return new ChatResponse(messages)
 2136        {
 2137            ResponseId = ResponseId,
 2138            ModelId = ModelId,
 2139        };
 140    }
 141
 142    internal sealed class CapturedMessage
 143    {
 19144        public string? Role { get; set; }
 13145        public string? Text { get; set; }
 22146        public List<CapturedContent>? Contents { get; set; }
 147    }
 148
 149    internal sealed class CapturedContent
 150    {
 16151        public CapturedContentKind Kind { get; set; }
 16152        public string? Text { get; set; }
 8153        public string? CallId { get; set; }
 8154        public string? Name { get; set; }
 8155        public string? Arguments { get; set; }
 8156        public string? Result { get; set; }
 157    }
 158
 159    internal enum CapturedContentKind
 160    {
 161        Text,
 162        FunctionCall,
 163        FunctionResult,
 164    }
 165}