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..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 .
///
@@ -53,8 +66,8 @@ 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 UriContent(inputImage.ImageUrl, "image/*"),
+ ? new DataContent(inputImage.ImageUrl)
+ : new UriContent(inputImage.ImageUrl, ImageUriToMediaType(inputImage.ImageUrl)),
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..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, "image/*") :
- new UriContent(uriText, "image/*");
+ new DataContent(uriText) :
+ 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.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs b/dotnet/tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/ItemContentConverterTests.cs
new file mode 100644
index 0000000000..f2e24e9562
--- /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..9e589b4686
--- /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..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
@@ -666,4 +666,75 @@ 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", "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);
+
+ // Assert
+ Assert.NotNull(result);
+ UriContent uriContent = Assert.IsType(result);
+ Assert.Equal(expectedMediaType, 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_InfersMimeTypeFromExtension()
+ {
+ // 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/png", uriContent.MediaType);
+ }
}