< Summary

Information
Class: Orchestrator.Infrastructure.Langfuse.LangfuseTextPromptTemplateProvider
Assembly: Orchestrator
File(s): /home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Infrastructure/Langfuse/LangfuseTextPromptTemplateProvider.cs
Line coverage
92%
Covered lines: 65
Uncovered lines: 5
Coverable lines: 70
Total lines: 142
Line coverage: 92.8%
Branch coverage
70%
Covered branches: 21
Total branches: 30
Branch coverage: 70%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)62.5%88100%
get_Prompt()100%210%
GetPromptTemplateTelemetryMetadata()50%22100%
LoadMatchTemplate(...)75%4485.71%
LoadBonusTemplate(...)50%2275%
LoadPrompt()100%44100%
BuildPromptPath(...)50%22100%
LoadFallbackPrompt(...)75%8883.33%
.ctor(...)100%11100%

File(s)

/home/runner/work/KicktippAi/KicktippAi/src/Orchestrator/Infrastructure/Langfuse/LangfuseTextPromptTemplateProvider.cs

#LineLine coverage
 1using OpenAiIntegration;
 2
 3namespace Orchestrator.Infrastructure.Langfuse;
 4
 5internal enum LangfusePromptKind
 6{
 7    Match,
 8    Bonus
 9}
 10
 11internal sealed class LangfuseTextPromptTemplateProvider : IInstructionsTemplateProvider, IPromptTemplateTelemetryMetada
 12{
 13    private readonly ILangfusePublicApiClient _client;
 14    private readonly string _promptName;
 15    private readonly string? _label;
 16    private readonly int? _version;
 17    private readonly LangfusePrompt? _preloadedPrompt;
 18    private readonly LangfusePromptKind _promptKind;
 19    private readonly IInstructionsTemplateProvider? _fallbackTemplateProvider;
 20    private readonly string? _fallbackModel;
 21    private readonly Action<string>? _fallbackWarning;
 22    private readonly Lazy<ResolvedPrompt> _prompt;
 23
 124    public LangfuseTextPromptTemplateProvider(
 125        ILangfusePublicApiClient client,
 126        string promptName,
 127        string? label,
 128        int? version,
 129        LangfusePrompt? preloadedPrompt = null,
 130        LangfusePromptKind promptKind = LangfusePromptKind.Match,
 131        IInstructionsTemplateProvider? fallbackTemplateProvider = null,
 132        string? fallbackModel = null,
 133        Action<string>? fallbackWarning = null)
 34    {
 135        _client = client ?? throw new ArgumentNullException(nameof(client));
 136        _promptName = string.IsNullOrWhiteSpace(promptName)
 137            ? throw new ArgumentException("Langfuse prompt name must be provided.", nameof(promptName))
 138            : promptName.Trim();
 139        _label = string.IsNullOrWhiteSpace(label) ? null : label.Trim();
 140        _version = version;
 141        _preloadedPrompt = preloadedPrompt;
 142        _promptKind = promptKind;
 143        _fallbackTemplateProvider = fallbackTemplateProvider;
 144        _fallbackModel = string.IsNullOrWhiteSpace(fallbackModel) ? null : fallbackModel.Trim();
 145        _fallbackWarning = fallbackWarning;
 146        _prompt = new Lazy<ResolvedPrompt>(LoadPrompt);
 147    }
 48
 049    public LangfusePrompt? Prompt => _prompt.Value.Prompt;
 50
 51    public PromptTemplateTelemetryMetadata? GetPromptTemplateTelemetryMetadata()
 52    {
 153        return _prompt.IsValueCreated ? _prompt.Value.TelemetryMetadata : null;
 54    }
 55
 56    public (string template, string path) LoadMatchTemplate(string model, bool includeJustification)
 57    {
 158        if (_promptKind != LangfusePromptKind.Match)
 59        {
 060            throw new NotSupportedException("This Langfuse prompt provider is configured for bonus prompts.");
 61        }
 62
 163        if (includeJustification)
 64        {
 165            throw new NotSupportedException(
 166                "The Langfuse prompt source only supports WM 2026 match prompts without justification in this version.")
 67        }
 68
 169        var prompt = _prompt.Value;
 170        return (prompt.Template, prompt.Path);
 71    }
 72
 73    public (string template, string path) LoadBonusTemplate(string model)
 74    {
 175        if (_promptKind != LangfusePromptKind.Bonus)
 76        {
 077            throw new NotSupportedException("This Langfuse prompt provider is configured for match prompts.");
 78        }
 79
 180        var prompt = _prompt.Value;
 181        return (prompt.Template, prompt.Path);
 82    }
 83
 84    private ResolvedPrompt LoadPrompt()
 85    {
 86        try
 87        {
 188            var prompt = _preloadedPrompt
 189                         ?? _client.GetPromptAsync(_promptName, _label, _version)
 190                             .GetAwaiter()
 191                             .GetResult();
 92
 193            if (prompt is not null)
 94            {
 195                var path = BuildPromptPath(prompt);
 196                return new ResolvedPrompt(
 197                    prompt.GetTextPrompt(),
 198                    path,
 199                    prompt,
 1100                    new PromptTemplateTelemetryMetadata(prompt.Name, prompt.Version, IsFallback: false, path));
 101            }
 102
 1103            return LoadFallbackPrompt($"Langfuse prompt '{_promptName}' was not found.");
 104        }
 1105        catch (Exception ex) when (_fallbackTemplateProvider is not null)
 106        {
 1107            return LoadFallbackPrompt($"Failed to fetch Langfuse prompt '{_promptName}': {ex.Message}");
 108        }
 1109    }
 110
 111    private string BuildPromptPath(LangfusePrompt prompt)
 112    {
 1113        var labelSuffix = string.IsNullOrWhiteSpace(_label) ? string.Empty : $"?label={Uri.EscapeDataString(_label)}";
 1114        return $"langfuse://prompts/{Uri.EscapeDataString(prompt.Name)}/versions/{prompt.Version}{labelSuffix}";
 115    }
 116
 117    private ResolvedPrompt LoadFallbackPrompt(string reason)
 118    {
 1119        if (_fallbackTemplateProvider is null || string.IsNullOrWhiteSpace(_fallbackModel))
 120        {
 0121            throw new FileNotFoundException(
 0122                $"{reason} No local fallback prompt was configured for '{_promptName}'.");
 123        }
 124
 1125        var fallback = _promptKind == LangfusePromptKind.Match
 1126            ? _fallbackTemplateProvider.LoadMatchTemplate(_fallbackModel, includeJustification: false)
 1127            : _fallbackTemplateProvider.LoadBonusTemplate(_fallbackModel);
 128
 1129        _fallbackWarning?.Invoke($"{reason} Using local fallback prompt '{fallback.path}'.");
 1130        return new ResolvedPrompt(
 1131            fallback.template,
 1132            fallback.path,
 1133            Prompt: null,
 1134            new PromptTemplateTelemetryMetadata(_promptName, null, IsFallback: true, fallback.path));
 135    }
 136
 1137    private sealed record ResolvedPrompt(
 1138        string Template,
 1139        string Path,
 1140        LangfusePrompt? Prompt,
 1141        PromptTemplateTelemetryMetadata TelemetryMetadata);
 142}