Merge branch 'main' into feature-session-statebag

This commit is contained in:
westey
2026-02-10 20:39:26 +00:00
committed by GitHub
93 changed files with 2838 additions and 810 deletions
@@ -19,7 +19,7 @@ public class AIContextProviderTests
#region InvokingAsync Message Stamping Tests
[Fact]
public async Task InvokingAsync_StampsMessagesWithSourceTypeAndSourceAsync()
public async Task InvokingAsync_StampsMessagesWithSourceTypeAndSourceIdAsync()
{
// Arrange
var provider = new TestAIContextProviderWithMessages();
@@ -32,18 +32,18 @@ public class AIContextProviderTests
Assert.NotNull(aiContext.Messages);
ChatMessage message = aiContext.Messages.Single();
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(typeof(TestAIContextProviderWithMessages).FullName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, typedAttribution.SourceType);
Assert.Equal(typeof(TestAIContextProviderWithMessages).FullName, typedAttribution.SourceId);
}
[Fact]
public async Task InvokingAsync_WithCustomSourceName_StampsMessagesWithCustomSourceAsync()
public async Task InvokingAsync_WithCustomSourceId_StampsMessagesWithCustomSourceIdAsync()
{
// Arrange
const string CustomSourceName = "CustomContextSource";
var provider = new TestAIContextProviderWithCustomSource(CustomSourceName);
const string CustomSourceId = "CustomContextSource";
var provider = new TestAIContextProviderWithCustomSource(CustomSourceId);
var context = new AIContextProvider.InvokingContext(s_mockAgent, s_mockSession, [new ChatMessage(ChatRole.User, "Request")]);
// Act
@@ -53,10 +53,10 @@ public class AIContextProviderTests
Assert.NotNull(aiContext.Messages);
ChatMessage message = aiContext.Messages.Single();
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(CustomSourceName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, typedAttribution.SourceType);
Assert.Equal(CustomSourceId, typedAttribution.SourceId);
}
[Fact]
@@ -73,10 +73,10 @@ public class AIContextProviderTests
Assert.NotNull(aiContext.Messages);
ChatMessage message = aiContext.Messages.Single();
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(typeof(TestAIContextProviderWithPreStampedMessages).FullName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, typedAttribution.SourceType);
Assert.Equal(typeof(TestAIContextProviderWithPreStampedMessages).FullName, typedAttribution.SourceId);
}
[Fact]
@@ -97,10 +97,10 @@ public class AIContextProviderTests
foreach (ChatMessage message in messageList)
{
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(typeof(TestAIContextProviderWithMultipleMessages).FullName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, typedAttribution.SourceType);
Assert.Equal(typeof(TestAIContextProviderWithMultipleMessages).FullName, typedAttribution.SourceId);
}
}
@@ -473,7 +473,7 @@ public class AIContextProviderTests
private sealed class TestAIContextProviderWithCustomSource : AIContextProvider
{
public TestAIContextProviderWithCustomSource(string sourceName) : base(sourceName)
public TestAIContextProviderWithCustomSource(string sourceId) : base(sourceId)
{
}
@@ -491,8 +491,7 @@ public class AIContextProviderTests
var message = new ChatMessage(ChatRole.System, "Pre-stamped Message");
message.AdditionalProperties = new AdditionalPropertiesDictionary
{
[AgentRequestMessageSourceType.AdditionalPropertiesKey] = AgentRequestMessageSourceType.AIContextProvider,
[AgentRequestMessageSource.AdditionalPropertiesKey] = this.GetType().FullName!
[AgentRequestMessageSourceAttribution.AdditionalPropertiesKey] = new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.AIContextProvider, this.GetType().FullName!)
};
return new(new AIContext
{
@@ -0,0 +1,466 @@
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Agents.AI.Abstractions.UnitTests;
/// <summary>
/// Contains tests for the <see cref="AgentRequestMessageSourceAttribution"/> struct.
/// </summary>
public sealed class AgentRequestMessageSourceAttributionTests
{
#region Constructor Tests
[Fact]
public void Constructor_SetsSourceTypeAndSourceId()
{
// Arrange
AgentRequestMessageSourceType expectedType = AgentRequestMessageSourceType.AIContextProvider;
const string ExpectedId = "MyProvider";
// Act
AgentRequestMessageSourceAttribution attribution = new(expectedType, ExpectedId);
// Assert
Assert.Equal(expectedType, attribution.SourceType);
Assert.Equal(ExpectedId, attribution.SourceId);
}
[Fact]
public void Constructor_WithNullSourceId_SetsNullSourceId()
{
// Arrange
AgentRequestMessageSourceType sourceType = AgentRequestMessageSourceType.ChatHistory;
// Act
AgentRequestMessageSourceAttribution attribution = new(sourceType, null);
// Assert
Assert.Equal(sourceType, attribution.SourceType);
Assert.Null(attribution.SourceId);
}
#endregion
#region AdditionalPropertiesKey Tests
[Fact]
public void AdditionalPropertiesKey_IsAttribution()
{
// Assert
Assert.Equal("_attribution", AgentRequestMessageSourceAttribution.AdditionalPropertiesKey);
}
#endregion
#region Default Value Tests
[Fact]
public void Default_HasDefaultSourceTypeAndNullSourceId()
{
// Arrange & Act
AgentRequestMessageSourceAttribution attribution = default;
// Assert
Assert.Equal(default, attribution.SourceType);
Assert.Null(attribution.SourceId);
}
#endregion
#region Equals (IEquatable) Tests
[Fact]
public void Equals_WithSameSourceTypeAndSourceId_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.True(result);
}
[Fact]
public void Equals_WithDifferentSourceType_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.ChatHistory, "Provider1");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.False(result);
}
[Fact]
public void Equals_WithDifferentSourceId_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider2");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.False(result);
}
[Fact]
public void Equals_WithDifferentSourceTypeAndSourceId_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.ChatHistory, "Provider2");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.False(result);
}
[Fact]
public void Equals_WithDifferentCaseSourceId_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "provider");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.False(result);
}
[Fact]
public void Equals_BothDefaultValues_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = default;
AgentRequestMessageSourceAttribution attribution2 = default;
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.True(result);
}
[Fact]
public void Equals_WithBothNullSourceIds_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.External, null!);
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.External, null!);
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.True(result);
}
[Fact]
public void Equals_WithOneNullSourceId_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.External, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.External, null!);
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.False(result);
}
#endregion
#region Object.Equals Tests
[Fact]
public void ObjectEquals_WithEqualAttribution_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.ChatHistory, "Provider");
object attribution2 = new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "Provider");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.True(result);
}
[Fact]
public void ObjectEquals_WithDifferentType_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution = new(AgentRequestMessageSourceType.ChatHistory, "Provider");
object other = "NotAnAttribution";
// Act
bool result = attribution.Equals(other);
// Assert
Assert.False(result);
}
[Fact]
public void ObjectEquals_WithNullObject_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution = new(AgentRequestMessageSourceType.ChatHistory, "Provider");
object? other = null;
// Act
bool result = attribution.Equals(other);
// Assert
Assert.False(result);
}
[Fact]
public void ObjectEquals_WithBoxedDifferentAttribution_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.ChatHistory, "Provider1");
object attribution2 = new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "Provider2");
// Act
bool result = attribution1.Equals(attribution2);
// Assert
Assert.False(result);
}
#endregion
#region GetHashCode Tests
[Fact]
public void GetHashCode_WithSameValues_ReturnsSameHashCode()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
// Act
int hashCode1 = attribution1.GetHashCode();
int hashCode2 = attribution2.GetHashCode();
// Assert
Assert.Equal(hashCode1, hashCode2);
}
[Fact]
public void GetHashCode_WithDifferentSourceType_ReturnsDifferentHashCode()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.ChatHistory, "Provider");
// Act
int hashCode1 = attribution1.GetHashCode();
int hashCode2 = attribution2.GetHashCode();
// Assert
Assert.NotEqual(hashCode1, hashCode2);
}
[Fact]
public void GetHashCode_WithDifferentSourceId_ReturnsDifferentHashCode()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider2");
// Act
int hashCode1 = attribution1.GetHashCode();
int hashCode2 = attribution2.GetHashCode();
// Assert
Assert.NotEqual(hashCode1, hashCode2);
}
[Fact]
public void GetHashCode_ConsistentWithEquals()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.External, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.External, "Provider");
// Act & Assert
Assert.True(attribution1.Equals(attribution2));
Assert.Equal(attribution1.GetHashCode(), attribution2.GetHashCode());
}
[Fact]
public void GetHashCode_WithNullSourceId_DoesNotThrow()
{
// Arrange
AgentRequestMessageSourceAttribution attribution = new(AgentRequestMessageSourceType.External, null!);
// Act
int hashCode = attribution.GetHashCode();
// Assert
Assert.IsType<int>(hashCode);
}
#endregion
#region Equality Operator Tests
[Fact]
public void EqualityOperator_WithEqualValues_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
// Act
bool result = attribution1 == attribution2;
// Assert
Assert.True(result);
}
[Fact]
public void EqualityOperator_WithDifferentValues_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.ChatHistory, "Provider2");
// Act
bool result = attribution1 == attribution2;
// Assert
Assert.False(result);
}
[Fact]
public void EqualityOperator_WithBothDefault_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = default;
AgentRequestMessageSourceAttribution attribution2 = default;
// Act
bool result = attribution1 == attribution2;
// Assert
Assert.True(result);
}
[Fact]
public void EqualityOperator_WithDifferentSourceTypeOnly_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.External, "Provider");
// Act
bool result = attribution1 == attribution2;
// Assert
Assert.False(result);
}
[Fact]
public void EqualityOperator_WithDifferentSourceIdOnly_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider2");
// Act
bool result = attribution1 == attribution2;
// Assert
Assert.False(result);
}
#endregion
#region Inequality Operator Tests
[Fact]
public void InequalityOperator_WithEqualValues_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
// Act
bool result = attribution1 != attribution2;
// Assert
Assert.False(result);
}
[Fact]
public void InequalityOperator_WithDifferentValues_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.ChatHistory, "Provider2");
// Act
bool result = attribution1 != attribution2;
// Assert
Assert.True(result);
}
[Fact]
public void InequalityOperator_WithBothDefault_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = default;
AgentRequestMessageSourceAttribution attribution2 = default;
// Act
bool result = attribution1 != attribution2;
// Assert
Assert.False(result);
}
[Fact]
public void InequalityOperator_WithDifferentSourceTypeOnly_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.External, "Provider");
// Act
bool result = attribution1 != attribution2;
// Assert
Assert.True(result);
}
[Fact]
public void InequalityOperator_WithDifferentSourceIdOnly_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceAttribution attribution1 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider1");
AgentRequestMessageSourceAttribution attribution2 = new(AgentRequestMessageSourceType.AIContextProvider, "Provider2");
// Act
bool result = attribution1 != attribution2;
// Assert
Assert.True(result);
}
#endregion
}
@@ -5,7 +5,7 @@ using System;
namespace Microsoft.Agents.AI.Abstractions.UnitTests;
/// <summary>
/// Contains tests for the <see cref="AgentRequestMessageSourceType"/> class.
/// Contains tests for the <see cref="AgentRequestMessageSourceType"/> struct.
/// </summary>
public sealed class AgentRequestMessageSourceTypeTests
{
@@ -38,6 +38,16 @@ public sealed class AgentRequestMessageSourceTypeTests
Assert.Throws<ArgumentException>(() => new AgentRequestMessageSourceType(string.Empty));
}
[Fact]
public void Default_DefaultsToExternal()
{
// Act
AgentRequestMessageSourceType defaultSource = default;
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, defaultSource);
}
#endregion
#region Static Properties Tests
@@ -49,7 +59,6 @@ public sealed class AgentRequestMessageSourceTypeTests
AgentRequestMessageSourceType source = AgentRequestMessageSourceType.External;
// Assert
Assert.NotNull(source);
Assert.Equal("External", source.Value);
}
@@ -60,7 +69,6 @@ public sealed class AgentRequestMessageSourceTypeTests
AgentRequestMessageSourceType source = AgentRequestMessageSourceType.AIContextProvider;
// Assert
Assert.NotNull(source);
Assert.Equal("AIContextProvider", source.Value);
}
@@ -71,22 +79,11 @@ public sealed class AgentRequestMessageSourceTypeTests
AgentRequestMessageSourceType source = AgentRequestMessageSourceType.ChatHistory;
// Assert
Assert.NotNull(source);
Assert.Equal("ChatHistory", source.Value);
}
[Fact]
public void AdditionalPropertiesKey_ReturnsExpectedValue()
{
// Arrange & Act
string key = AgentRequestMessageSourceType.AdditionalPropertiesKey;
// Assert
Assert.Equal("Agent.RequestMessageSourceType", key);
}
[Fact]
public void StaticProperties_ReturnSameInstanceOnMultipleCalls()
public void StaticProperties_ReturnEqualValuesOnMultipleCalls()
{
// Arrange & Act
AgentRequestMessageSourceType external1 = AgentRequestMessageSourceType.External;
@@ -97,9 +94,9 @@ public sealed class AgentRequestMessageSourceTypeTests
AgentRequestMessageSourceType chatHistory2 = AgentRequestMessageSourceType.ChatHistory;
// Assert
Assert.Same(external1, external2);
Assert.Same(aiContextProvider1, aiContextProvider2);
Assert.Same(chatHistory1, chatHistory2);
Assert.Equal(external1, external2);
Assert.Equal(aiContextProvider1, aiContextProvider2);
Assert.Equal(chatHistory1, chatHistory2);
}
#endregion
@@ -148,7 +145,7 @@ public sealed class AgentRequestMessageSourceTypeTests
}
[Fact]
public void Equals_WithNull_ReturnsFalse()
public void Equals_WithNullObject_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceType source = new("Test");
@@ -314,11 +311,11 @@ public sealed class AgentRequestMessageSourceTypeTests
}
[Fact]
public void EqualityOperator_WithBothNull_ReturnsTrue()
public void EqualityOperator_WithDefaultValues_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceType? source1 = null;
AgentRequestMessageSourceType? source2 = null;
AgentRequestMessageSourceType source1 = default;
AgentRequestMessageSourceType source2 = default;
// Act
bool result = source1 == source2;
@@ -327,34 +324,6 @@ public sealed class AgentRequestMessageSourceTypeTests
Assert.True(result);
}
[Fact]
public void EqualityOperator_WithLeftNull_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceType? source1 = null;
AgentRequestMessageSourceType source2 = new("Test");
// Act
bool result = source1 == source2;
// Assert
Assert.False(result);
}
[Fact]
public void EqualityOperator_WithRightNull_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceType source1 = new("Test");
AgentRequestMessageSourceType? source2 = null;
// Act
bool result = source1 == source2;
// Assert
Assert.False(result);
}
[Fact]
public void EqualityOperator_WithStaticInstances_ReturnsTrue()
{
@@ -416,11 +385,11 @@ public sealed class AgentRequestMessageSourceTypeTests
}
[Fact]
public void InequalityOperator_WithBothNull_ReturnsFalse()
public void InequalityOperator_WithBothDefault_ReturnsFalse()
{
// Arrange
AgentRequestMessageSourceType? source1 = null;
AgentRequestMessageSourceType? source2 = null;
AgentRequestMessageSourceType source1 = default;
AgentRequestMessageSourceType source2 = default;
// Act
bool result = source1 != source2;
@@ -429,34 +398,6 @@ public sealed class AgentRequestMessageSourceTypeTests
Assert.False(result);
}
[Fact]
public void InequalityOperator_WithLeftNull_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceType? source1 = null;
AgentRequestMessageSourceType source2 = new("Test");
// Act
bool result = source1 != source2;
// Assert
Assert.True(result);
}
[Fact]
public void InequalityOperator_WithRightNull_ReturnsTrue()
{
// Arrange
AgentRequestMessageSourceType source1 = new("Test");
AgentRequestMessageSourceType? source2 = null;
// Act
bool result = source1 != source2;
// Assert
Assert.True(result);
}
[Fact]
public void InequalityOperator_DifferentStaticInstances_ReturnsTrue()
{
@@ -64,7 +64,7 @@ public sealed class ChatHistoryProviderExtensionsTests
Mock<ChatHistoryProvider> providerMock = new();
List<ChatMessage> requestMessages =
[
new(ChatRole.System, "System") { AdditionalProperties = new() { { AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.ChatHistory } } },
new(ChatRole.System, "System") { AdditionalProperties = new() { { AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "TestSource") } } },
new(ChatRole.User, "Hello")
];
ChatHistoryProvider.InvokedContext context = new(s_mockAgent, s_mockSession, requestMessages)
@@ -114,9 +114,9 @@ public sealed class ChatHistoryProviderExtensionsTests
Mock<ChatHistoryProvider> providerMock = new();
List<ChatMessage> requestMessages =
[
new(ChatRole.System, "System") { AdditionalProperties = new() { { AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.ChatHistory } } },
new(ChatRole.System, "System") { AdditionalProperties = new() { { AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "TestSource") } } },
new(ChatRole.User, "Hello"),
new(ChatRole.System, "Context") { AdditionalProperties = new() { { AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.AIContextProvider } } }
new(ChatRole.System, "Context") { AdditionalProperties = new() { { AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.AIContextProvider, "TestContextSource") } } }
];
ChatHistoryProvider.InvokedContext context = new(s_mockAgent, s_mockSession, requestMessages);
@@ -170,7 +170,7 @@ public sealed class ChatHistoryProviderMessageFilterTests
var innerProviderMock = new Mock<ChatHistoryProvider>();
List<ChatMessage> requestMessages =
[
new(ChatRole.System, "System") { AdditionalProperties = new() { { AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.ChatHistory } } },
new(ChatRole.System, "System") { AdditionalProperties = new() { { AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "TestSource") } } },
new(ChatRole.User, "Hello"),
];
var responseMessages = new List<ChatMessage> { new(ChatRole.Assistant, "Response") };
@@ -189,7 +189,7 @@ public sealed class ChatHistoryProviderMessageFilterTests
// Filter that modifies the context
ChatHistoryProvider.InvokedContext InvokedFilter(ChatHistoryProvider.InvokedContext ctx)
{
var modifiedRequestMessages = ctx.RequestMessages.Where(x => x.GetAgentRequestMessageSource() == AgentRequestMessageSourceType.External).Select(m => new ChatMessage(m.Role, $"[FILTERED] {m.Text}")).ToList();
var modifiedRequestMessages = ctx.RequestMessages.Where(x => x.GetAgentRequestMessageSourceType() == AgentRequestMessageSourceType.External).Select(m => new ChatMessage(m.Role, $"[FILTERED] {m.Text}")).ToList();
return new ChatHistoryProvider.InvokedContext(s_mockAgent, s_mockSession, modifiedRequestMessages)
{
ResponseMessages = ctx.ResponseMessages,
@@ -21,7 +21,7 @@ public class ChatHistoryProviderTests
#region InvokingAsync Message Stamping Tests
[Fact]
public async Task InvokingAsync_StampsMessagesWithSourceTypeAndSourceAsync()
public async Task InvokingAsync_StampsMessagesWithSourceTypeAndSourceIdAsync()
{
// Arrange
var provider = new TestChatHistoryProvider();
@@ -33,18 +33,18 @@ public class ChatHistoryProviderTests
// Assert
ChatMessage message = messages.Single();
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(typeof(TestChatHistoryProvider).FullName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, typedAttribution.SourceType);
Assert.Equal(typeof(TestChatHistoryProvider).FullName, typedAttribution.SourceId);
}
[Fact]
public async Task InvokingAsync_WithCustomSourceName_StampsMessagesWithCustomSourceAsync()
public async Task InvokingAsync_WithCustomSourceId_StampsMessagesWithCustomSourceIdAsync()
{
// Arrange
const string CustomSourceName = "CustomHistorySource";
var provider = new TestChatHistoryProviderWithCustomSource(CustomSourceName);
const string CustomSourceId = "CustomHistorySource";
var provider = new TestChatHistoryProviderWithCustomSource(CustomSourceId);
var context = new ChatHistoryProvider.InvokingContext(s_mockAgent, s_mockSession, [new ChatMessage(ChatRole.User, "Request")]);
// Act
@@ -53,10 +53,10 @@ public class ChatHistoryProviderTests
// Assert
ChatMessage message = messages.Single();
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(CustomSourceName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, typedAttribution.SourceType);
Assert.Equal(CustomSourceId, typedAttribution.SourceId);
}
[Fact]
@@ -72,10 +72,10 @@ public class ChatHistoryProviderTests
// Assert
ChatMessage message = messages.Single();
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(typeof(TestChatHistoryProviderWithPreStampedMessages).FullName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, typedAttribution.SourceType);
Assert.Equal(typeof(TestChatHistoryProviderWithPreStampedMessages).FullName, typedAttribution.SourceId);
}
[Fact]
@@ -95,10 +95,10 @@ public class ChatHistoryProviderTests
foreach (ChatMessage message in messageList)
{
Assert.NotNull(message.AdditionalProperties);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceType.AdditionalPropertiesKey, out object? sourceType));
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, sourceType);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSource.AdditionalPropertiesKey, out object? source));
Assert.Equal(typeof(TestChatHistoryProviderWithMultipleMessages).FullName, source);
Assert.True(message.AdditionalProperties.TryGetValue(AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, out object? attribution));
var typedAttribution = Assert.IsType<AgentRequestMessageSourceAttribution>(attribution);
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, typedAttribution.SourceType);
Assert.Equal(typeof(TestChatHistoryProviderWithMultipleMessages).FullName, typedAttribution.SourceId);
}
}
@@ -379,7 +379,7 @@ public class ChatHistoryProviderTests
private sealed class TestChatHistoryProviderWithCustomSource : ChatHistoryProvider
{
public TestChatHistoryProviderWithCustomSource(string sourceName) : base(sourceName)
public TestChatHistoryProviderWithCustomSource(string sourceId) : base(sourceId)
{
}
@@ -397,8 +397,7 @@ public class ChatHistoryProviderTests
var message = new ChatMessage(ChatRole.User, "Pre-stamped Message");
message.AdditionalProperties = new AdditionalPropertiesDictionary
{
[AgentRequestMessageSourceType.AdditionalPropertiesKey] = AgentRequestMessageSourceType.ChatHistory,
[AgentRequestMessageSource.AdditionalPropertiesKey] = this.GetType().FullName!
[AgentRequestMessageSourceAttribution.AdditionalPropertiesKey] = new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, this.GetType().FullName!)
};
return new([message]);
}
@@ -9,23 +9,23 @@ namespace Microsoft.Agents.AI.Abstractions.UnitTests;
/// </summary>
public sealed class ChatMessageExtensionsTests
{
#region GetAgentRequestMessageSource Tests
#region GetAgentRequestMessageSourceType Tests
[Fact]
public void GetAgentRequestMessageSource_WithNoAdditionalProperties_ReturnsExternal()
public void GetAgentRequestMessageSourceType_WithNoAdditionalProperties_ReturnsExternal()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello");
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithNullAdditionalProperties_ReturnsExternal()
public void GetAgentRequestMessageSourceType_WithNullAdditionalProperties_ReturnsExternal()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
@@ -34,14 +34,14 @@ public sealed class ChatMessageExtensionsTests
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithEmptyAdditionalProperties_ReturnsExternal()
public void GetAgentRequestMessageSourceType_WithEmptyAdditionalProperties_ReturnsExternal()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
@@ -50,130 +50,130 @@ public sealed class ChatMessageExtensionsTests
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithExternalSource_ReturnsExternal()
public void GetAgentRequestMessageSourceType_WithExternalSourceType_ReturnsExternal()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.External }
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.External, "TestSourceId") }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithAIContextProviderSource_ReturnsAIContextProvider()
public void GetAgentRequestMessageSourceType_WithAIContextProviderSourceType_ReturnsAIContextProvider()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.AIContextProvider }
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.AIContextProvider, "TestSourceId") }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithChatHistorySource_ReturnsChatHistory()
public void GetAgentRequestMessageSourceType_WithChatHistorySourceType_ReturnsChatHistory()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.ChatHistory }
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "TestSourceId") }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithCustomSource_ReturnsCustomSource()
public void GetAgentRequestMessageSourceType_WithCustomSourceType_ReturnsCustomSourceType()
{
// Arrange
AgentRequestMessageSourceType customSource = new("CustomSource");
AgentRequestMessageSourceType customSourceType = new("CustomSourceType");
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, customSource }
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(customSourceType, "TestSourceId") }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(customSource, result);
Assert.Equal("CustomSource", result.Value);
Assert.Equal(customSourceType, result);
Assert.Equal("CustomSourceType", result.Value);
}
[Fact]
public void GetAgentRequestMessageSource_WithWrongKeyType_ReturnsExternal()
public void GetAgentRequestMessageSourceType_WithWrongAttributionType_ReturnsExternal()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, "NotAnAgentRequestMessageSource" }
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, "NotAnAgentRequestMessageSourceAttribution" }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithNullValue_ReturnsExternal()
public void GetAgentRequestMessageSourceType_WithNullAttributionValue_ReturnsExternal()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, null! }
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, null! }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.External, result);
}
[Fact]
public void GetAgentRequestMessageSource_WithMultipleProperties_ReturnsCorrectSource()
public void GetAgentRequestMessageSourceType_WithMultipleProperties_ReturnsCorrectSourceType()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
@@ -181,17 +181,345 @@ public sealed class ChatMessageExtensionsTests
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ "OtherProperty", "SomeValue" },
{ AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.ChatHistory },
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "TestSourceId") },
{ "AnotherProperty", 123 }
}
};
// Act
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSource();
AgentRequestMessageSourceType result = message.GetAgentRequestMessageSourceType();
// Assert
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, result);
}
#endregion
#region GetAgentRequestMessageSourceId Tests
[Fact]
public void GetAgentRequestMessageSourceId_WithNoAdditionalProperties_ReturnsNull()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello");
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Null(result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithNullAdditionalProperties_ReturnsNull()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = null
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Null(result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithEmptyAdditionalProperties_ReturnsNull()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary()
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Null(result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithAttribution_ReturnsSourceId()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.AIContextProvider, "MyProvider.FullName") }
}
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Equal("MyProvider.FullName", result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithDifferentSourceIds_ReturnsCorrectSourceId()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "CustomHistorySourceId") }
}
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Equal("CustomHistorySourceId", result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithWrongAttributionType_ReturnsNull()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, "NotAnAgentRequestMessageSourceAttribution" }
}
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Null(result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithNullAttributionValue_ReturnsNull()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, null! }
}
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Null(result);
}
[Fact]
public void GetAgentRequestMessageSourceId_WithMultipleProperties_ReturnsCorrectSourceId()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ "OtherProperty", "SomeValue" },
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.External, "ExpectedSourceId") },
{ "AnotherProperty", 123 }
}
};
// Act
string? result = message.GetAgentRequestMessageSourceId();
// Assert
Assert.Equal("ExpectedSourceId", result);
}
#endregion
#region AsAgentRequestMessageSourcedMessage Tests
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithNoAdditionalProperties_ReturnsClonesMessageWithAttribution()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello");
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.External, "TestSourceId");
// Assert
Assert.NotSame(message, result);
Assert.Equal(AgentRequestMessageSourceType.External, result.GetAgentRequestMessageSourceType());
Assert.Equal("TestSourceId", result.GetAgentRequestMessageSourceId());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithNullAdditionalProperties_ReturnsClonesMessageWithAttribution()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = null
};
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.AIContextProvider, "ProviderSourceId");
// Assert
Assert.NotSame(message, result);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, result.GetAgentRequestMessageSourceType());
Assert.Equal("ProviderSourceId", result.GetAgentRequestMessageSourceId());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithMatchingSourceTypeAndSourceId_ReturnsSameInstance()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "HistoryId") }
}
};
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.ChatHistory, "HistoryId");
// Assert
Assert.Same(message, result);
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithDifferentSourceType_ReturnsClonesMessageWithNewAttribution()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.External, "SourceId") }
}
};
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.AIContextProvider, "SourceId");
// Assert
Assert.NotSame(message, result);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, result.GetAgentRequestMessageSourceType());
Assert.Equal("SourceId", result.GetAgentRequestMessageSourceId());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithDifferentSourceId_ReturnsClonesMessageWithNewAttribution()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.External, "OriginalId") }
}
};
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.External, "NewId");
// Assert
Assert.NotSame(message, result);
Assert.Equal(AgentRequestMessageSourceType.External, result.GetAgentRequestMessageSourceType());
Assert.Equal("NewId", result.GetAgentRequestMessageSourceId());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithDefaultNullSourceId_ReturnsClonesMessageWithNullSourceId()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello");
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.ChatHistory);
// Assert
Assert.NotSame(message, result);
Assert.Equal(AgentRequestMessageSourceType.ChatHistory, result.GetAgentRequestMessageSourceType());
Assert.Null(result.GetAgentRequestMessageSourceId());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithMatchingSourceTypeAndNullSourceId_ReturnsSameInstance()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.External, null) }
}
};
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.External);
// Assert
Assert.Same(message, result);
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_DoesNotModifyOriginalMessage()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello");
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.AIContextProvider, "ProviderId");
// Assert
Assert.Null(message.AdditionalProperties);
Assert.NotNull(result.AdditionalProperties);
Assert.Equal(AgentRequestMessageSourceType.AIContextProvider, result.GetAgentRequestMessageSourceType());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_WithWrongAttributionType_ReturnsClonesMessageWithNewAttribution()
{
// Arrange
ChatMessage message = new(ChatRole.User, "Hello")
{
AdditionalProperties = new AdditionalPropertiesDictionary
{
{ AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, "NotAnAttribution" }
}
};
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.External, "SourceId");
// Assert
Assert.NotSame(message, result);
Assert.Equal(AgentRequestMessageSourceType.External, result.GetAgentRequestMessageSourceType());
Assert.Equal("SourceId", result.GetAgentRequestMessageSourceId());
}
[Fact]
public void AsAgentRequestMessageSourcedMessage_PreservesMessageContent()
{
// Arrange
ChatMessage message = new(ChatRole.Assistant, "Test content");
// Act
ChatMessage result = message.AsAgentRequestMessageSourcedMessage(AgentRequestMessageSourceType.ChatHistory, "HistoryId");
// Assert
Assert.Equal(ChatRole.Assistant, result.Role);
Assert.Equal("Test content", result.Text);
}
#endregion
}
@@ -71,7 +71,7 @@ public class InMemoryChatHistoryProviderTests
var requestMessages = new List<ChatMessage>
{
new(ChatRole.User, "Hello"),
new(ChatRole.System, "additional context") { AdditionalProperties = new() { { AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.ChatHistory } } },
new(ChatRole.System, "additional context") { AdditionalProperties = new() { { AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.ChatHistory, "TestSource") } } },
};
var responseMessages = new List<ChatMessage>
{
@@ -302,7 +302,7 @@ public sealed class CosmosChatHistoryProviderTests : IAsyncLifetime, IDisposable
new ChatMessage(ChatRole.User, "First message"),
new ChatMessage(ChatRole.Assistant, "Second message"),
new ChatMessage(ChatRole.User, "Third message"),
new ChatMessage(ChatRole.System, "System context message") { AdditionalProperties = new() { { AgentRequestMessageSourceType.AdditionalPropertiesKey, AgentRequestMessageSourceType.AIContextProvider } } }
new ChatMessage(ChatRole.System, "System context message") { AdditionalProperties = new() { { AgentRequestMessageSourceAttribution.AdditionalPropertiesKey, new AgentRequestMessageSourceAttribution(AgentRequestMessageSourceType.AIContextProvider, "TestSource") } } }
};
var responseMessages = new[]
{
@@ -478,7 +478,7 @@ public sealed class PurviewClientTests : IDisposable
private static ContentToProcess CreateValidContentToProcess()
{
var content = new PurviewTextContent("Test content");
var metadata = new ProcessConversationMetadata(content, "msg-123", false, "Test message");
var metadata = new ProcessConversationMetadata(content, "msg-123", false, "Test message", "test-correlation-id");
var activityMetadata = new ActivityMetadata(Activity.UploadText);
var deviceMetadata = new DeviceMetadata
{
@@ -1320,6 +1320,45 @@ public partial class ChatClientAgentTests
Assert.Equal("what?", historyMessages[1].Text);
}
/// <summary>
/// Verify that RunStreamingAsync includes chat history in messages sent to the chat client on subsequent calls.
/// </summary>
[Fact]
public async Task RunStreamingAsyncIncludesChatHistoryInMessagesToChatClientAsync()
{
// Arrange
List<IEnumerable<ChatMessage>> capturedMessages = [];
Mock<IChatClient> mockService = new();
ChatResponseUpdate[] returnUpdates =
[
new ChatResponseUpdate(role: ChatRole.Assistant, content: "response"),
];
mockService.Setup(
s => s.GetStreamingResponseAsync(
It.IsAny<IEnumerable<ChatMessage>>(),
It.IsAny<ChatOptions>(),
It.IsAny<CancellationToken>()))
.Returns(ToAsyncEnumerableAsync(returnUpdates))
.Callback<IEnumerable<ChatMessage>, ChatOptions?, CancellationToken>((msgs, _, _) => capturedMessages.Add(msgs.ToList()));
ChatClientAgent agent = new(mockService.Object, options: new()
{
ChatOptions = new() { Instructions = "test instructions" },
});
// Act
ChatClientAgentSession? session = await agent.CreateSessionAsync() as ChatClientAgentSession;
await agent.RunStreamingAsync([new(ChatRole.User, "first")], session).ToListAsync();
await agent.RunStreamingAsync([new(ChatRole.User, "second")], session).ToListAsync();
// Assert - the second call should include chat history (first user message + first response) plus the new message
Assert.Equal(2, capturedMessages.Count);
var secondCallMessages = capturedMessages[1].ToList();
Assert.Equal(3, secondCallMessages.Count);
Assert.Equal("first", secondCallMessages[0].Text);
Assert.Equal("response", secondCallMessages[1].Text);
Assert.Equal("second", secondCallMessages[2].Text);
}
/// <summary>
/// Verify that RunStreamingAsync throws when a <see cref="ChatHistoryProvider"/> is provided and the chat client returns a conversation id.
/// </summary>
@@ -672,4 +672,104 @@ public class JsonSerializationTests
ValidateCheckpoint(retrievedCheckpoint, prototype);
}
/// <summary>
/// Verifies that the default behavior (without AllowOutOfOrderMetadataProperties) fails
/// when $type metadata is not the first property, demonstrating the PostgreSQL jsonb issue.
/// See: https://github.com/microsoft/agent-framework/issues/2962
/// </summary>
[Fact]
public void Test_OutOfOrderMetadataProperties_WithoutOption_Fails()
{
// Arrange
JsonMarshaller marshaller = new();
EdgeInfo edgeInfo = TestEdgeInfo_DirectNoCondition;
// Serialize to JSON
JsonElement serialized = marshaller.Marshal(edgeInfo);
string json = serialized.GetRawText();
// Simulate PostgreSQL jsonb behavior: reorder properties so $type is not first
string reorderedJson = ReorderJsonPropertiesToMoveTypeDiscriminatorLast(json);
// Act & Assert - Without the option, deserialization should fail
JsonElement reorderedElement = JsonDocument.Parse(reorderedJson).RootElement;
Action act = () => marshaller.Marshal<EdgeInfo>(reorderedElement);
act.Should().Throw<JsonException>();
}
/// <summary>
/// Simulates PostgreSQL jsonb behavior where property order is not preserved,
/// causing $type metadata to not be the first property.
/// This test verifies that deserialization works when AllowOutOfOrderMetadataProperties is enabled.
/// See: https://github.com/microsoft/agent-framework/issues/2962
/// </summary>
[Fact]
public void Test_OutOfOrderMetadataProperties_WithOptionEnabled_Succeeds()
{
// Arrange
EdgeInfo edgeInfo = TestEdgeInfo_DirectNoCondition;
// Serialize to JSON using standard marshaller
JsonMarshaller marshaller = new();
JsonElement serialized = marshaller.Marshal(edgeInfo);
string json = serialized.GetRawText();
// Simulate PostgreSQL jsonb behavior: reorder properties so $type is not first
string reorderedJson = ReorderJsonPropertiesToMoveTypeDiscriminatorLast(json);
JsonElement reorderedElement = JsonDocument.Parse(reorderedJson).RootElement;
// Act - Deserialize with AllowOutOfOrderMetadataProperties enabled via JsonSerializerOptions
JsonSerializerOptions options = new() { AllowOutOfOrderMetadataProperties = true };
JsonMarshaller marshallerWithOption = new(options);
EdgeInfo deserialized = marshallerWithOption.Marshal<EdgeInfo>(reorderedElement);
// Assert
deserialized.Should().Match(edgeInfo.CreatePolyValidator());
}
private static string ReorderJsonPropertiesToMoveTypeDiscriminatorLast(string json)
{
// Parse JSON, extract $type, rebuild with $type at end
using JsonDocument doc = JsonDocument.Parse(json);
JsonElement root = doc.RootElement;
Dictionary<string, JsonElement> properties = [];
JsonElement? typeValue = null;
foreach (JsonProperty prop in root.EnumerateObject())
{
if (prop.Name == "$type")
{
typeValue = prop.Value.Clone();
}
else
{
properties[prop.Name] = prop.Value.Clone();
}
}
// Rebuild JSON with $type last
using System.IO.MemoryStream ms = new();
using (Utf8JsonWriter writer = new(ms))
{
writer.WriteStartObject();
foreach (KeyValuePair<string, JsonElement> kvp in properties)
{
writer.WritePropertyName(kvp.Key);
kvp.Value.WriteTo(writer);
}
if (typeValue.HasValue)
{
writer.WritePropertyName("$type");
typeValue.Value.WriteTo(writer);
}
writer.WriteEndObject();
}
return System.Text.Encoding.UTF8.GetString(ms.ToArray());
}
}