// Copyright (c) Microsoft. All rights reserved. using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.Shared; using Microsoft.Extensions.AI; namespace Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests; public sealed class AgentRunResponseUpdateAGUIExtensionsTests { [Fact] public async Task AsAGUIEventStreamAsync_YieldsRunStartedEvent_AtBeginningWithCorrectIdsAsync() { // Arrange const string ThreadId = "thread1"; const string RunId = "run1"; List updates = []; // Act List events = []; await foreach (BaseEvent evt in updates.ToAsyncEnumerableAsync().AsAGUIEventStreamAsync(ThreadId, RunId, CancellationToken.None)) { events.Add(evt); } // Assert Assert.NotEmpty(events); RunStartedEvent startEvent = Assert.IsType(events.First()); Assert.Equal(ThreadId, startEvent.ThreadId); Assert.Equal(RunId, startEvent.RunId); Assert.Equal(AGUIEventTypes.RunStarted, startEvent.Type); } [Fact] public async Task AsAGUIEventStreamAsync_YieldsRunFinishedEvent_AtEndWithCorrectIdsAsync() { // Arrange const string ThreadId = "thread1"; const string RunId = "run1"; List updates = []; // Act List events = []; await foreach (BaseEvent evt in updates.ToAsyncEnumerableAsync().AsAGUIEventStreamAsync(ThreadId, RunId, CancellationToken.None)) { events.Add(evt); } // Assert Assert.NotEmpty(events); RunFinishedEvent finishEvent = Assert.IsType(events.Last()); Assert.Equal(ThreadId, finishEvent.ThreadId); Assert.Equal(RunId, finishEvent.RunId); Assert.Equal(AGUIEventTypes.RunFinished, finishEvent.Type); } [Fact] public async Task AsAGUIEventStreamAsync_ConvertsTextContentUpdates_ToTextMessageEventsAsync() { // Arrange const string ThreadId = "thread1"; const string RunId = "run1"; List updates = [ new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, "Hello") { MessageId = "msg1" }), new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, " World") { MessageId = "msg1" }) ]; // Act List events = []; await foreach (BaseEvent evt in updates.ToAsyncEnumerableAsync().AsAGUIEventStreamAsync(ThreadId, RunId, CancellationToken.None)) { events.Add(evt); } // Assert Assert.Contains(events, e => e is TextMessageStartEvent); Assert.Contains(events, e => e is TextMessageContentEvent); Assert.Contains(events, e => e is TextMessageEndEvent); } [Fact] public async Task AsAGUIEventStreamAsync_GroupsConsecutiveUpdates_WithSameMessageIdAsync() { // Arrange const string ThreadId = "thread1"; const string RunId = "run1"; const string MessageId = "msg1"; List updates = [ new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, "Hello") { MessageId = MessageId }), new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, " ") { MessageId = MessageId }), new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, "World") { MessageId = MessageId }) ]; // Act List events = []; await foreach (BaseEvent evt in updates.ToAsyncEnumerableAsync().AsAGUIEventStreamAsync(ThreadId, RunId, CancellationToken.None)) { events.Add(evt); } // Assert List startEvents = events.OfType().ToList(); List endEvents = events.OfType().ToList(); Assert.Single(startEvents); Assert.Single(endEvents); Assert.Equal(MessageId, startEvents[0].MessageId); Assert.Equal(MessageId, endEvents[0].MessageId); } [Fact] public async Task AsAGUIEventStreamAsync_WithRoleChanges_EmitsProperTextMessageStartEventsAsync() { // Arrange const string ThreadId = "thread1"; const string RunId = "run1"; List updates = [ new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, "Hello") { MessageId = "msg1" }), new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.User, "Hi") { MessageId = "msg2" }) ]; // Act List events = []; await foreach (BaseEvent evt in updates.ToAsyncEnumerableAsync().AsAGUIEventStreamAsync(ThreadId, RunId, CancellationToken.None)) { events.Add(evt); } // Assert List startEvents = events.OfType().ToList(); Assert.Equal(2, startEvents.Count); Assert.Equal("msg1", startEvents[0].MessageId); Assert.Equal("msg2", startEvents[1].MessageId); } [Fact] public async Task AsAGUIEventStreamAsync_EmitsTextMessageEndEvent_WhenMessageIdChangesAsync() { // Arrange const string ThreadId = "thread1"; const string RunId = "run1"; List updates = [ new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, "First") { MessageId = "msg1" }), new AgentRunResponseUpdate(new ChatResponseUpdate(ChatRole.Assistant, "Second") { MessageId = "msg2" }) ]; // Act List events = []; await foreach (BaseEvent evt in updates.ToAsyncEnumerableAsync().AsAGUIEventStreamAsync(ThreadId, RunId, CancellationToken.None)) { events.Add(evt); } // Assert List endEvents = events.OfType().ToList(); Assert.NotEmpty(endEvents); Assert.Contains(endEvents, e => e.MessageId == "msg1"); } }