Skip to content

Update to Microsoft.Extensions.AI.Abstractions 9.8.0 #3960

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: development
Choose a base branch
from

Conversation

stephentoub
Copy link
Contributor

Description

  • Updated to the latest M.E.AI.Abstractions release
  • Set new ChatMessage.CreatedAt property
  • Set and use new DataContent.Name property
  • Added citations to BedrockChatClient
  • Added implementation of IImageGenerator (as [Experimental] because the interface is itself [Experimental])

Motivation and Context

Light-up new surface area in Microsoft.Extensions.AI.Abstractions.

Testing

Manual testing against various models with basic scenarios.

Screenshots (if appropriate)

image

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed

License

  • I confirm that this pull request can be released under the Apache 2 license

- Set new ChatMessage.CreatedAt property
- Set and use new DataContent.Name property
- Added citations to BedrockChatClient
- Added implementation of IImageGenerator (as [Experimental] because the interface is itself [Experimental])
Copy link

@ericstj ericstj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be able to plumb edit/variation as well.

}
else
{
// Amazon models (e.g. Titan, Nova Canvas)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


if (invokeRequest.ModelId?.IndexOf("stability", StringComparison.OrdinalIgnoreCase) >= 0)
{
// Stability AI models
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stability models should also permit a starting image we should pass that in for edit. https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-diffusion-3-text-image.html

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates the Microsoft.Extensions.AI.Abstractions package from version 9.7.0 to 9.8.0 and implements new features enabled by the updated library. The changes include setting new ChatMessage properties, handling citations in responses, and adding experimental image generation capabilities.

  • Updates Microsoft.Extensions.AI.Abstractions dependency to version 9.8.0 across all project files
  • Adds citation support to BedrockChatClient for both streaming and non-streaming responses
  • Implements experimental IImageGenerator interface with support for multiple image generation models

Reviewed Changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
BedrockMEAITests.NetFramework.csproj Updates test project dependency to version 9.8.0
ExperimentalAttribute.cs Adds polyfill for [Experimental] attribute for non-.NET targets
BedrockImageGenerator.cs Implements IImageGenerator interface with support for Stability AI and Amazon image models
BedrockChatClient.cs Adds CreatedAt property setting, citation handling, and DataContent.Name property usage
AmazonBedrockRuntimeExtensions.cs Adds AsIImageGenerator extension method marked as experimental
AWSSDK.Extensions.Bedrock.MEAI.nuspec Updates package dependency references to version 9.8.0
AWSSDK.Extensions.Bedrock.MEAI.NetStandard.csproj Updates package reference to version 9.8.0
AWSSDK.Extensions.Bedrock.MEAI.NetFramework.csproj Updates package reference to version 9.8.0

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

if (element.TryGetProperty("base64", out JsonElement base64Element) &&
base64Element.ValueKind == JsonValueKind.String)
{
result.Contents.Add(new DataContent(Convert.FromBase64String(base64Element.GetString()!), "image/png"));
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MIME type is hardcoded as 'image/png' but different models may return different image formats. Consider determining the actual format from the response or making it configurable.

Suggested change
result.Contents.Add(new DataContent(Convert.FromBase64String(base64Element.GetString()!), "image/png"));
string mimeType = "image/png";
if (element.TryGetProperty("mime_type", out JsonElement mimeTypeElement) && mimeTypeElement.ValueKind == JsonValueKind.String)
{
mimeType = mimeTypeElement.GetString()!;
}
else if (element.TryGetProperty("type", out JsonElement typeElement) && typeElement.ValueKind == JsonValueKind.String)
{
mimeType = typeElement.GetString()!;
}
result.Contents.Add(new DataContent(Convert.FromBase64String(base64Element.GetString()!), mimeType));

Copilot uses AI. Check for mistakes.

{
if (image.ValueKind == JsonValueKind.String)
{
result.Contents.Add(new DataContent(Convert.FromBase64String(image.GetString()!), "image/png"));
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MIME type is hardcoded as 'image/png' but different models may return different image formats. Consider determining the actual format from the response or making it configurable.

Suggested change
result.Contents.Add(new DataContent(Convert.FromBase64String(image.GetString()!), "image/png"));
{
var imageBytes = Convert.FromBase64String(image.GetString()!);
var mimeType = ImageFormatHelper.GetImageMimeType(imageBytes);
result.Contents.Add(new DataContent(imageBytes, mimeType));
}

Copilot uses AI. Check for mistakes.

Title = citations.Citations![i].Title,
Snippet = citations.Citations![i].SourceContent?.Select(c => c.Text).FirstOrDefault(),
}];
result.Contents.Add(tc);
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference exception when citations.Content[i] is null. The null-forgiving operator ! is used but citations.Content[i] could still be null even after the count check.

Suggested change
result.Contents.Add(tc);
if (citations.Content![i] != null)
{
TextContent tc = new(citations.Content[i]?.Text) { RawRepresentation = citations.Content[i] };
tc.Annotations = [new CitationAnnotation()
{
Title = citations.Citations![i].Title,
Snippet = citations.Citations![i].SourceContent?.Select(c => c.Text).FirstOrDefault(),
}];
result.Contents.Add(tc);
}

Copilot uses AI. Check for mistakes.

Title = citations.Citations![i].Title,
Snippet = citations.Citations![i].SourceContent?.Select(c => c.Text).FirstOrDefault(),
}];
result.Contents.Add(tc);
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference exception when citations.Citations[i] is null. The null-forgiving operator ! is used but citations.Citations[i] could still be null even after the count check.

Suggested change
result.Contents.Add(tc);
var contentItem = citations.Content![i];
var citationItem = citations.Citations![i];
if (contentItem != null && citationItem != null)
{
TextContent tc = new(contentItem.Text) { RawRepresentation = contentItem };
tc.Annotations = [new CitationAnnotation()
{
Title = citationItem.Title,
Snippet = citationItem.SourceContent?.Select(c => c.Text).FirstOrDefault(),
}];
result.Contents.Add(tc);
}

Copilot uses AI. Check for mistakes.

Title = citations.Citations![i].Title,
Snippet = citations.Citations![i].SourceContent?.Select(c => c.Text).FirstOrDefault(),
}];
result.Contents.Add(tc);
Copy link
Preview

Copilot AI Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference exception when citations.Citations[i] is null. The null-forgiving operator ! is used but citations.Citations[i] could still be null even after the count check.

Suggested change
result.Contents.Add(tc);
var citation = citations.Citations![i];
var contentItem = citations.Content![i];
if (citation != null && contentItem != null)
{
TextContent tc = new(contentItem.Text) { RawRepresentation = contentItem };
tc.Annotations = [new CitationAnnotation()
{
Title = citation.Title,
Snippet = citation.SourceContent?.Select(c => c.Text).FirstOrDefault(),
}];
result.Contents.Add(tc);
}

Copilot uses AI. Check for mistakes.

@@ -97,6 +98,21 @@ public async Task<ChatResponse> GetResponseAsync(
result.Contents.Add(new TextContent(text) { RawRepresentation = content });
}

if (content.CitationsContent is { } citations)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im not a huge fan of the ! null checks everywhere (unless there was a specific reason you needed them?). wondering if we can do something like below instead?

i havent tested it but it gives the general idea

if (content.CitationsContent is { } citations)
{
    for (int i = 0; i < Math.Min(citations.Citations?.Count ?? 0, citations.Content?.Count ?? 0); i++)
    {
        var contentItem = citations.Content?[i];
        var citationItem = citations.Citations?[i];

        if (contentItem != null && citationItem != null)
        {
            TextContent tc = new(contentItem.Text) { RawRepresentation = contentItem };
            tc.Annotations = new[]
            {
                new CitationAnnotation
                {
                    Title = citationItem.Title,
                    Snippet = citationItem.SourceContent?.Select(c => c.Text).FirstOrDefault(),
                }
            };
            result.Contents.Add(tc);
        }
    }
}

same in other places

@@ -18,7 +18,7 @@
</PropertyGroup>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add tests for the citation changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants