From 1cd1beaf2ce6c0f24afaea639624e4858659633e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 20:51:21 +0000 Subject: [PATCH 1/6] Initial plan From 6a81ab32d1956784ee4b879448a8b950169cb4ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 21:02:09 +0000 Subject: [PATCH 2/6] Fix MIME type override in DataContent constructors for data URIs Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../ChatCompletions/Converters/MessageContentPartConverter.cs | 2 +- .../Responses/Converters/ItemContentConverter.cs | 2 +- .../Extensions/ChatMessageExtensions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Converters/MessageContentPartConverter.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Converters/MessageContentPartConverter.cs index 1a0a37cdc0..87b266cba6 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Converters/MessageContentPartConverter.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/ChatCompletions/Converters/MessageContentPartConverter.cs @@ -26,7 +26,7 @@ private static string AudioFormatToMediaType(string format) => // image ImageContentPart imagePart when !string.IsNullOrEmpty(imagePart.UrlOrData) => imagePart.UrlOrData.StartsWith("data:", StringComparison.OrdinalIgnoreCase) - ? new DataContent(imagePart.UrlOrData, "image/*") + ? new DataContent(imagePart.UrlOrData) : new UriContent(imagePart.Url, ImageUriToMediaType(imagePart.Url)), // audio diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs index 2476ce2fbd..8cb77f43d1 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs @@ -53,7 +53,7 @@ private static string MediaTypeToAudioFormat(string mediaType) => // Image content ItemContentInputImage inputImage when !string.IsNullOrEmpty(inputImage.ImageUrl) => inputImage.ImageUrl!.StartsWith("data:", StringComparison.OrdinalIgnoreCase) - ? new DataContent(inputImage.ImageUrl, "image/*") + ? new DataContent(inputImage.ImageUrl) : new UriContent(inputImage.ImageUrl, "image/*"), ItemContentInputImage inputImage when !string.IsNullOrEmpty(inputImage.FileId) => new HostedFileContent(inputImage.FileId!), diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs index 1aa9a6ef71..bf7d46a52e 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs @@ -176,7 +176,7 @@ private static IEnumerable GetContent(this RecordDataValue message) private static AIContent GetImageContent(string uriText) => uriText.StartsWith("data:", StringComparison.OrdinalIgnoreCase) ? - new DataContent(uriText, "image/*") : + new DataContent(uriText) : new UriContent(uriText, "image/*"); private static TValue? GetProperty(this RecordDataValue record, string name) From a9ff77c08d044e01f85b6a878f16cffa68936703 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 21:12:23 +0000 Subject: [PATCH 3/6] Use ImageUriToMediaType helper for image URI MIME type inference Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../Responses/Converters/ItemContentConverter.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs index 8cb77f43d1..d282f543df 100644 --- a/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs +++ b/dotnet/src/Microsoft.Agents.AI.Hosting.OpenAI/Responses/Converters/ItemContentConverter.cs @@ -28,6 +28,19 @@ private static string MediaTypeToAudioFormat(string mediaType) => mediaType.Equals("audio/flac", StringComparison.OrdinalIgnoreCase) ? "flac" : mediaType.Equals("audio/pcm", StringComparison.OrdinalIgnoreCase) ? "pcm16" : "mp3"; + + private static string ImageUriToMediaType(string uri) + { + return + uri.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ? "image/png" : + uri.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ? "image/jpeg" : + uri.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ? "image/jpeg" : + uri.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ? "image/gif" : + uri.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ? "image/bmp" : + uri.EndsWith(".webp", StringComparison.OrdinalIgnoreCase) ? "image/webp" : + "image/*"; + } + /// /// Converts to . /// @@ -54,7 +67,7 @@ private static string MediaTypeToAudioFormat(string mediaType) => ItemContentInputImage inputImage when !string.IsNullOrEmpty(inputImage.ImageUrl) => inputImage.ImageUrl!.StartsWith("data:", StringComparison.OrdinalIgnoreCase) ? new DataContent(inputImage.ImageUrl) - : new UriContent(inputImage.ImageUrl, "image/*"), + : new UriContent(inputImage.ImageUrl, ImageUriToMediaType(inputImage.ImageUrl)), ItemContentInputImage inputImage when !string.IsNullOrEmpty(inputImage.FileId) => new HostedFileContent(inputImage.FileId!), From c1c2930b30d45084b39a13aec8f20ef393527214 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 21:44:35 +0000 Subject: [PATCH 4/6] Add comprehensive tests for MIME type handling in image URI converters Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../ItemContentConverterTests.cs | 200 +++++++++++++++ .../MessageContentPartConverterTests.cs | 235 ++++++++++++++++++ .../Extensions/ChatMessageExtensionsTests.cs | 72 ++++++ 3 files changed, 507 insertions(+) create mode 100644 dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs create mode 100644 dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs new file mode 100644 index 0000000000..e2a813ac3e --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using Microsoft.Agents.AI.Hosting.OpenAI.Responses.Converters; +using Microsoft.Agents.AI.Hosting.OpenAI.Responses.Models; +using Microsoft.Extensions.AI; + +namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests; + +/// +/// Tests for ItemContentConverter focusing on MIME type handling for image URIs. +/// +public sealed class ItemContentConverterTests +{ + [Theory] + [InlineData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", "image/png")] + [InlineData("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlbaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5/ooooA//2Q==", "image/jpeg")] + [InlineData("data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==", "image/gif")] + [InlineData("data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAgA0JaQAA3AA/vuUAAA=", "image/webp")] + [InlineData("data:image/bmp;base64,Qk0eAAAAAAAAABoAAAAMAAAAAQAAAAEAAAABACAAAAA=", "image/bmp")] + public void ToAIContent_DataUri_PreservesMimeType(string dataUri, string expectedMediaType) + { + // Arrange + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = dataUri + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal(expectedMediaType, dataContent.MediaType); + Assert.Equal(dataUri, dataContent.Uri); + } + + [Theory] + [InlineData("https://example.com/image.png", "image/png")] + [InlineData("https://example.com/photo.jpg", "image/jpeg")] + [InlineData("https://example.com/photo.jpeg", "image/jpeg")] + [InlineData("https://example.com/animation.gif", "image/gif")] + [InlineData("https://example.com/picture.bmp", "image/bmp")] + [InlineData("https://example.com/modern.webp", "image/webp")] + [InlineData("https://example.com/IMAGE.PNG", "image/png")] // Case insensitive + [InlineData("https://example.com/PHOTO.JPG", "image/jpeg")] // Case insensitive + public void ToAIContent_HttpUri_InfersMimeTypeFromExtension(string uri, string expectedMediaType) + { + // Arrange + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = uri + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.Equal(expectedMediaType, uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Theory] + [InlineData("https://example.com/image")] + [InlineData("https://example.com/image.unknown")] + [InlineData("https://example.com/image.txt")] + public void ToAIContent_HttpUri_UnknownExtension_UsesGenericMimeType(string uri) + { + // Arrange + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = uri + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.Equal("image/*", uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Fact] + public void ToAIContent_DataUriPng_CreatesDataContent() + { + // Arrange + const string dataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = dataUri + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal("image/png", dataContent.MediaType); + Assert.Equal(dataUri, dataContent.Uri); + } + + [Fact] + public void ToAIContent_HttpUriPng_CreatesUriContent() + { + // Arrange + const string uri = "https://example.com/test.png"; + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = uri + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.Equal("image/png", uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Fact] + public void ToAIContent_FileId_CreatesHostedFileContent() + { + // Arrange + const string fileId = "file-abc123"; + ItemContentInputImage inputImage = new ItemContentInputImage + { + FileId = fileId + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + HostedFileContent hostedFile = Assert.IsType(result); + Assert.Equal(fileId, hostedFile.FileId); + } + + [Fact] + public void ToAIContent_NullImageUrl_ReturnsNull() + { + // Arrange + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = null + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.Null(result); + } + + [Fact] + public void ToAIContent_EmptyImageUrl_ReturnsNull() + { + // Arrange + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = string.Empty + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.Null(result); + } + + [Fact] + public void ToAIContent_PreservesImageDetail() + { + // Arrange + const string uri = "https://example.com/test.png"; + ItemContentInputImage inputImage = new ItemContentInputImage + { + ImageUrl = uri, + Detail = "high" + }; + + // Act + AIContent? result = ItemContentConverter.ToAIContent(inputImage); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.NotNull(uriContent.AdditionalProperties); + Assert.True(uriContent.AdditionalProperties.TryGetValue("detail", out object? detail)); + Assert.Equal("high", detail?.ToString()); + } +} diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs new file mode 100644 index 0000000000..23068abfe7 --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using Microsoft.Agents.AI.Hosting.OpenAI.ChatCompletions.Converters; +using Microsoft.Agents.AI.Hosting.OpenAI.ChatCompletions.Models; +using Microsoft.Extensions.AI; + +namespace Microsoft.Agents.AI.Hosting.OpenAI.UnitTests; + +/// +/// Tests for MessageContentPartConverter focusing on MIME type handling for image URIs. +/// +public sealed class MessageContentPartConverterTests +{ + [Theory] + [InlineData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", "image/png")] + [InlineData("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlbaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5/ooooA//2Q==", "image/jpeg")] + [InlineData("data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==", "image/gif")] + [InlineData("data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAgA0JaQAA3AA/vuUAAA=", "image/webp")] + [InlineData("data:image/bmp;base64,Qk0eAAAAAAAAABoAAAAMAAAAAQAAAAEAAAABACAAAAA=", "image/bmp")] + public void ToAIContent_ImageDataUri_PreservesMimeType(string dataUri, string expectedMediaType) + { + // Arrange + ImageContentPart imagePart = new ImageContentPart + { + ImageUrl = new ImageUrl { Url = dataUri } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(imagePart); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal(expectedMediaType, dataContent.MediaType); + Assert.Equal(dataUri, dataContent.Uri); + } + + [Theory] + [InlineData("https://example.com/image.png", "image/png")] + [InlineData("https://example.com/photo.jpg", "image/jpeg")] + [InlineData("https://example.com/photo.jpeg", "image/jpeg")] + [InlineData("https://example.com/animation.gif", "image/gif")] + [InlineData("https://example.com/picture.bmp", "image/bmp")] + [InlineData("https://example.com/modern.webp", "image/webp")] + [InlineData("https://example.com/IMAGE.PNG", "image/png")] // Case insensitive + [InlineData("https://example.com/PHOTO.JPG", "image/jpeg")] // Case insensitive + public void ToAIContent_ImageHttpUri_InfersMimeTypeFromExtension(string uri, string expectedMediaType) + { + // Arrange + ImageContentPart imagePart = new ImageContentPart + { + ImageUrl = new ImageUrl { Url = uri } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(imagePart); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.Equal(expectedMediaType, uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Theory] + [InlineData("https://example.com/image")] + [InlineData("https://example.com/image.unknown")] + [InlineData("https://example.com/image.txt")] + public void ToAIContent_ImageHttpUri_UnknownExtension_UsesGenericMimeType(string uri) + { + // Arrange + ImageContentPart imagePart = new ImageContentPart + { + ImageUrl = new ImageUrl { Url = uri } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(imagePart); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.Equal("image/*", uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Fact] + public void ToAIContent_ImageDataUriPng_CreatesDataContent() + { + // Arrange + const string dataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; + ImageContentPart imagePart = new ImageContentPart + { + ImageUrl = new ImageUrl { Url = dataUri } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(imagePart); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal("image/png", dataContent.MediaType); + Assert.Equal(dataUri, dataContent.Uri); + } + + [Fact] + public void ToAIContent_ImageHttpUriPng_CreatesUriContent() + { + // Arrange + const string uri = "https://example.com/test.png"; + ImageContentPart imagePart = new ImageContentPart + { + ImageUrl = new ImageUrl { Url = uri } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(imagePart); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + Assert.Equal("image/png", uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Fact] + public void ToAIContent_TextPart_CreatesTextContent() + { + // Arrange + const string text = "Hello, world!"; + TextContentPart textPart = new TextContentPart + { + Text = text + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(textPart); + + // Assert + Assert.NotNull(result); + TextContent textContent = Assert.IsType(result); + Assert.Equal(text, textContent.Text); + } + + [Fact] + public void ToAIContent_EmptyImageUrl_ReturnsNull() + { + // Arrange + ImageContentPart imagePart = new ImageContentPart + { + ImageUrl = new ImageUrl { Url = string.Empty } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(imagePart); + + // Assert + Assert.Null(result); + } + + [Theory] + [InlineData("mp3", "audio/mpeg")] + [InlineData("wav", "audio/wav")] + [InlineData("opus", "audio/opus")] + [InlineData("aac", "audio/aac")] + [InlineData("flac", "audio/flac")] + [InlineData("pcm16", "audio/pcm")] + public void ToAIContent_AudioPart_CorrectMimeType(string format, string expectedMediaType) + { + // Arrange + const string audioData = "data:audio/wav;base64,UklGRiQAAABXQVZF"; + AudioContentPart audioPart = new AudioContentPart + { + InputAudio = new InputAudio + { + Data = audioData, + Format = format + } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(audioPart); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal(expectedMediaType, dataContent.MediaType); + } + + [Fact] + public void ToAIContent_FilePartWithFileId_CreatesHostedFileContent() + { + // Arrange + const string fileId = "file-abc123"; + FileContentPart filePart = new FileContentPart + { + File = new InputFile { FileId = fileId } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(filePart); + + // Assert + Assert.NotNull(result); + HostedFileContent hostedFile = Assert.IsType(result); + Assert.Equal(fileId, hostedFile.FileId); + } + + [Fact] + public void ToAIContent_FilePartWithFileData_CreatesDataContent() + { + // Arrange + const string fileData = "data:application/pdf;base64,JVBERi0xLjQ="; + const string filename = "document.pdf"; + FileContentPart filePart = new FileContentPart + { + File = new InputFile + { + FileData = fileData, + Filename = filename + } + }; + + // Act + AIContent? result = MessageContentPartConverter.ToAIContent(filePart); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal("application/octet-stream", dataContent.MediaType); + Assert.Equal(filename, dataContent.Name); + } +} diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs index 8fdc76af95..934ef4e8ea 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs @@ -666,4 +666,76 @@ public void ToRecordWithMessageContainingMetadata() RecordValue metadataRecord = Assert.IsType(metadataField, exactMatch: false); Assert.Equal(2, metadataRecord.Fields.Count()); } + + [Theory] + [InlineData("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", "image/png")] + [InlineData("data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlbaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5/ooooA//2Q==", "image/jpeg")] + [InlineData("data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==", "image/gif")] + [InlineData("data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAgA0JaQAA3AA/vuUAAA=", "image/webp")] + [InlineData("data:image/bmp;base64,Qk0eAAAAAAAAABoAAAAMAAAAAQAAAAEAAAABACAAAAA=", "image/bmp")] + public void ToContentWithImageDataUri_PreservesMimeType(string dataUri, string expectedMediaType) + { + // Arrange & Act + AIContent? result = AgentMessageContentType.ImageUrl.ToContent(dataUri); + + // Assert + Assert.NotNull(result); + DataContent dataContent = Assert.IsType(result); + Assert.Equal(expectedMediaType, dataContent.MediaType); + Assert.Equal(dataUri, dataContent.Uri); + } + + [Theory] + [InlineData("https://example.com/image.png")] + [InlineData("https://example.com/photo.jpg")] + [InlineData("https://example.com/animation.gif")] + [InlineData("http://test.com/picture.webp")] + public void ToContentWithImageHttpUri_UsesGenericMimeType(string uri) + { + // Arrange & Act + AIContent? result = AgentMessageContentType.ImageUrl.ToContent(uri); + + // Assert + Assert.NotNull(result); + UriContent uriContent = Assert.IsType(result); + // ChatMessageExtensions.GetImageContent uses "image/*" for all non-data URIs + Assert.Equal("image/*", uriContent.MediaType); + Assert.Equal(uri, uriContent.Uri?.ToString()); + } + + [Fact] + public void ToChatMessageFromRecordWithImageDataUri_PreservesMimeType() + { + // Arrange + const string dataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"; + ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent(dataUri)!]); + DataValue record = source.ToRecord().ToDataValue(); + + // Act + ChatMessage? result = record.ToChatMessage(); + + // Assert + Assert.NotNull(result); + AIContent content = Assert.Single(result.Contents); + DataContent dataContent = Assert.IsType(content); + Assert.Equal("image/png", dataContent.MediaType); + } + + [Fact] + public void ToChatMessageFromRecordWithImageHttpUri_UsesGenericMimeType() + { + // Arrange + const string uri = "https://example.com/test.png"; + ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent(uri)!]); + DataValue record = source.ToRecord().ToDataValue(); + + // Act + ChatMessage? result = record.ToChatMessage(); + + // Assert + Assert.NotNull(result); + AIContent content = Assert.Single(result.Contents); + UriContent uriContent = Assert.IsType(content); + Assert.Equal("image/*", uriContent.MediaType); + } } From cc57a28241d539bb6a8ea2d09ad8e10b16db0890 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 21:50:58 +0000 Subject: [PATCH 5/6] Add ImageUriToMediaType helper to ChatMessageExtensions for consistent MIME type inference Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../Extensions/ChatMessageExtensions.cs | 14 +++++++++++++- .../Extensions/ChatMessageExtensionsTests.cs | 17 ++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs index bf7d46a52e..10a3a11d97 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/ChatMessageExtensions.cs @@ -174,10 +174,22 @@ private static IEnumerable GetContent(this RecordDataValue message) } } + private static string ImageUriToMediaType(string uri) + { + return + uri.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ? "image/png" : + uri.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ? "image/jpeg" : + uri.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ? "image/jpeg" : + uri.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ? "image/gif" : + uri.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ? "image/bmp" : + uri.EndsWith(".webp", StringComparison.OrdinalIgnoreCase) ? "image/webp" : + "image/*"; + } + private static AIContent GetImageContent(string uriText) => uriText.StartsWith("data:", StringComparison.OrdinalIgnoreCase) ? new DataContent(uriText) : - new UriContent(uriText, "image/*"); + new UriContent(uriText, ImageUriToMediaType(uriText)); private static TValue? GetProperty(this RecordDataValue record, string name) where TValue : DataValue diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs index 934ef4e8ea..b28d2efc62 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs @@ -686,11 +686,11 @@ public void ToContentWithImageDataUri_PreservesMimeType(string dataUri, string e } [Theory] - [InlineData("https://example.com/image.png")] - [InlineData("https://example.com/photo.jpg")] - [InlineData("https://example.com/animation.gif")] - [InlineData("http://test.com/picture.webp")] - public void ToContentWithImageHttpUri_UsesGenericMimeType(string uri) + [InlineData("https://example.com/image.png", "image/png")] + [InlineData("https://example.com/photo.jpg", "image/jpeg")] + [InlineData("https://example.com/animation.gif", "image/gif")] + [InlineData("http://test.com/picture.webp", "image/webp")] + public void ToContentWithImageHttpUri_InfersMimeTypeFromExtension(string uri, string expectedMediaType) { // Arrange & Act AIContent? result = AgentMessageContentType.ImageUrl.ToContent(uri); @@ -698,8 +698,7 @@ public void ToContentWithImageHttpUri_UsesGenericMimeType(string uri) // Assert Assert.NotNull(result); UriContent uriContent = Assert.IsType(result); - // ChatMessageExtensions.GetImageContent uses "image/*" for all non-data URIs - Assert.Equal("image/*", uriContent.MediaType); + Assert.Equal(expectedMediaType, uriContent.MediaType); Assert.Equal(uri, uriContent.Uri?.ToString()); } @@ -722,7 +721,7 @@ public void ToChatMessageFromRecordWithImageDataUri_PreservesMimeType() } [Fact] - public void ToChatMessageFromRecordWithImageHttpUri_UsesGenericMimeType() + public void ToChatMessageFromRecordWithImageHttpUri_InfersMimeTypeFromExtension() { // Arrange const string uri = "https://example.com/test.png"; @@ -736,6 +735,6 @@ public void ToChatMessageFromRecordWithImageHttpUri_UsesGenericMimeType() Assert.NotNull(result); AIContent content = Assert.Single(result.Contents); UriContent uriContent = Assert.IsType(content); - Assert.Equal("image/*", uriContent.MediaType); + Assert.Equal("image/png", uriContent.MediaType); } } From 3edd7399a01ab47ffdb7cf5f9d3bced2f4efd8cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 25 Jan 2026 15:43:41 +0000 Subject: [PATCH 6/6] Fix naming rule violations: Use PascalCase for const local variables in tests Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../ItemContentConverterTests.cs | 22 +++++------ .../MessageContentPartConverterTests.cs | 38 +++++++++---------- .../Extensions/ChatMessageExtensionsTests.cs | 8 ++-- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs index e2a813ac3e..f2e24e9562 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs @@ -89,10 +89,10 @@ public void ToAIContent_HttpUri_UnknownExtension_UsesGenericMimeType(string uri) public void ToAIContent_DataUriPng_CreatesDataContent() { // Arrange - const string dataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; + const string DataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; ItemContentInputImage inputImage = new ItemContentInputImage { - ImageUrl = dataUri + ImageUrl = DataUri }; // Act @@ -102,17 +102,17 @@ public void ToAIContent_DataUriPng_CreatesDataContent() Assert.NotNull(result); DataContent dataContent = Assert.IsType(result); Assert.Equal("image/png", dataContent.MediaType); - Assert.Equal(dataUri, dataContent.Uri); + Assert.Equal(DataUri, dataContent.Uri); } [Fact] public void ToAIContent_HttpUriPng_CreatesUriContent() { // Arrange - const string uri = "https://example.com/test.png"; + const string Uri = "https://example.com/test.png"; ItemContentInputImage inputImage = new ItemContentInputImage { - ImageUrl = uri + ImageUrl = Uri }; // Act @@ -122,17 +122,17 @@ public void ToAIContent_HttpUriPng_CreatesUriContent() Assert.NotNull(result); UriContent uriContent = Assert.IsType(result); Assert.Equal("image/png", uriContent.MediaType); - Assert.Equal(uri, uriContent.Uri?.ToString()); + Assert.Equal(Uri, uriContent.Uri?.ToString()); } [Fact] public void ToAIContent_FileId_CreatesHostedFileContent() { // Arrange - const string fileId = "file-abc123"; + const string FileId = "file-abc123"; ItemContentInputImage inputImage = new ItemContentInputImage { - FileId = fileId + FileId = FileId }; // Act @@ -141,7 +141,7 @@ public void ToAIContent_FileId_CreatesHostedFileContent() // Assert Assert.NotNull(result); HostedFileContent hostedFile = Assert.IsType(result); - Assert.Equal(fileId, hostedFile.FileId); + Assert.Equal(FileId, hostedFile.FileId); } [Fact] @@ -180,10 +180,10 @@ public void ToAIContent_EmptyImageUrl_ReturnsNull() public void ToAIContent_PreservesImageDetail() { // Arrange - const string uri = "https://example.com/test.png"; + const string Uri = "https://example.com/test.png"; ItemContentInputImage inputImage = new ItemContentInputImage { - ImageUrl = uri, + ImageUrl = Uri, Detail = "high" }; diff --git a/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs index 23068abfe7..9e589b4686 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/MessageContentPartConverterTests.cs @@ -89,10 +89,10 @@ public void ToAIContent_ImageHttpUri_UnknownExtension_UsesGenericMimeType(string public void ToAIContent_ImageDataUriPng_CreatesDataContent() { // Arrange - const string dataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; + const string DataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="; ImageContentPart imagePart = new ImageContentPart { - ImageUrl = new ImageUrl { Url = dataUri } + ImageUrl = new ImageUrl { Url = DataUri } }; // Act @@ -102,17 +102,17 @@ public void ToAIContent_ImageDataUriPng_CreatesDataContent() Assert.NotNull(result); DataContent dataContent = Assert.IsType(result); Assert.Equal("image/png", dataContent.MediaType); - Assert.Equal(dataUri, dataContent.Uri); + Assert.Equal(DataUri, dataContent.Uri); } [Fact] public void ToAIContent_ImageHttpUriPng_CreatesUriContent() { // Arrange - const string uri = "https://example.com/test.png"; + const string Uri = "https://example.com/test.png"; ImageContentPart imagePart = new ImageContentPart { - ImageUrl = new ImageUrl { Url = uri } + ImageUrl = new ImageUrl { Url = Uri } }; // Act @@ -122,17 +122,17 @@ public void ToAIContent_ImageHttpUriPng_CreatesUriContent() Assert.NotNull(result); UriContent uriContent = Assert.IsType(result); Assert.Equal("image/png", uriContent.MediaType); - Assert.Equal(uri, uriContent.Uri?.ToString()); + Assert.Equal(Uri, uriContent.Uri?.ToString()); } [Fact] public void ToAIContent_TextPart_CreatesTextContent() { // Arrange - const string text = "Hello, world!"; + const string Text = "Hello, world!"; TextContentPart textPart = new TextContentPart { - Text = text + Text = Text }; // Act @@ -141,7 +141,7 @@ public void ToAIContent_TextPart_CreatesTextContent() // Assert Assert.NotNull(result); TextContent textContent = Assert.IsType(result); - Assert.Equal(text, textContent.Text); + Assert.Equal(Text, textContent.Text); } [Fact] @@ -170,12 +170,12 @@ public void ToAIContent_EmptyImageUrl_ReturnsNull() public void ToAIContent_AudioPart_CorrectMimeType(string format, string expectedMediaType) { // Arrange - const string audioData = "data:audio/wav;base64,UklGRiQAAABXQVZF"; + const string AudioData = "data:audio/wav;base64,UklGRiQAAABXQVZF"; AudioContentPart audioPart = new AudioContentPart { InputAudio = new InputAudio { - Data = audioData, + Data = AudioData, Format = format } }; @@ -193,10 +193,10 @@ public void ToAIContent_AudioPart_CorrectMimeType(string format, string expected public void ToAIContent_FilePartWithFileId_CreatesHostedFileContent() { // Arrange - const string fileId = "file-abc123"; + const string FileId = "file-abc123"; FileContentPart filePart = new FileContentPart { - File = new InputFile { FileId = fileId } + File = new InputFile { FileId = FileId } }; // Act @@ -205,21 +205,21 @@ public void ToAIContent_FilePartWithFileId_CreatesHostedFileContent() // Assert Assert.NotNull(result); HostedFileContent hostedFile = Assert.IsType(result); - Assert.Equal(fileId, hostedFile.FileId); + Assert.Equal(FileId, hostedFile.FileId); } [Fact] public void ToAIContent_FilePartWithFileData_CreatesDataContent() { // Arrange - const string fileData = "data:application/pdf;base64,JVBERi0xLjQ="; - const string filename = "document.pdf"; + const string FileData = "data:application/pdf;base64,JVBERi0xLjQ="; + const string Filename = "document.pdf"; FileContentPart filePart = new FileContentPart { File = new InputFile { - FileData = fileData, - Filename = filename + FileData = FileData, + Filename = Filename } }; @@ -230,6 +230,6 @@ public void ToAIContent_FilePartWithFileData_CreatesDataContent() Assert.NotNull(result); DataContent dataContent = Assert.IsType(result); Assert.Equal("application/octet-stream", dataContent.MediaType); - Assert.Equal(filename, dataContent.Name); + Assert.Equal(Filename, dataContent.Name); } } diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs index b28d2efc62..293a1ef6c9 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/ChatMessageExtensionsTests.cs @@ -706,8 +706,8 @@ public void ToContentWithImageHttpUri_InfersMimeTypeFromExtension(string uri, st public void ToChatMessageFromRecordWithImageDataUri_PreservesMimeType() { // Arrange - const string dataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"; - ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent(dataUri)!]); + const string DataUri = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA"; + ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent(DataUri)!]); DataValue record = source.ToRecord().ToDataValue(); // Act @@ -724,8 +724,8 @@ public void ToChatMessageFromRecordWithImageDataUri_PreservesMimeType() public void ToChatMessageFromRecordWithImageHttpUri_InfersMimeTypeFromExtension() { // Arrange - const string uri = "https://example.com/test.png"; - ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent(uri)!]); + const string Uri = "https://example.com/test.png"; + ChatMessage source = new(ChatRole.User, [AgentMessageContentType.ImageUrl.ToContent(Uri)!]); DataValue record = source.ToRecord().ToDataValue(); // Act