File: Components\ConversationTurnRenderer.cs
Web Access
Project: src\aspnetcore\src\Components\AI\src\Microsoft.AspNetCore.Components.AI.csproj (Microsoft.AspNetCore.Components.AI)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using Microsoft.AspNetCore.Components.Rendering;
 
namespace Microsoft.AspNetCore.Components.AI;
 
// Renders one conversation turn: its request blocks followed by its response blocks.
internal class ConversationTurnRenderer : IDisposable
{
    private readonly ConversationTurn _turn;
    private readonly MessageListContext _listContext;
    private readonly Action _requestRender;
    private readonly List<BlockContainer> _blockContainers = new();
    private readonly IDisposable? _blockAddedSub;
 
    internal ConversationTurnRenderer(
        AgentContext agentContext,
        ConversationTurn turn,
        MessageListContext listContext,
        Action requestRender)
    {
        _turn = turn;
        _listContext = listContext;
        _requestRender = requestRender;
 
        _blockAddedSub = agentContext.RegisterOnBlockAdded((t, block) =>
        {
            if (ReferenceEquals(t, _turn))
            {
                OnBlockAdded(block);
            }
        });
 
        foreach (var block in turn.RequestBlocks)
        {
            _blockContainers.Add(new BlockContainer(block, _listContext, _requestRender));
        }
        foreach (var block in turn.ResponseBlocks)
        {
            _blockContainers.Add(new BlockContainer(block, _listContext, _requestRender));
        }
    }
 
    private void OnBlockAdded(ContentBlock block)
    {
        _blockContainers.Add(new BlockContainer(block, _listContext, _requestRender));
        _requestRender();
    }
 
    internal void RenderTo(RenderTreeBuilder builder, int baseSeq)
    {
        // Determine role from request blocks (user turn) or response blocks
        var role = _turn.RequestBlocks.Count > 0 ? "user" : "assistant";
        builder.OpenElement(baseSeq, "div");
        builder.AddAttribute(baseSeq + 1, "class", $"sc-ai-turn sc-ai-turn--{role}");
        var seq = baseSeq + 10;
        foreach (var container in _blockContainers)
        {
            container.RenderTo(builder, seq);
            seq += 10;
        }
        builder.CloseElement();
    }
 
    public void Dispose()
    {
        _blockAddedSub?.Dispose();
        foreach (var container in _blockContainers)
        {
            container.Dispose();
        }
    }
}