-
Notifications
You must be signed in to change notification settings - Fork 870
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
base: development
Are you sure you want to change the base?
Conversation
- 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])
There was a problem hiding this 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These also support a starting image -- https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-image.html
|
||
if (invokeRequest.ModelId?.IndexOf("stability", StringComparison.OrdinalIgnoreCase) >= 0) | ||
{ | ||
// Stability AI models |
There was a problem hiding this comment.
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
There was a problem hiding this 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")); |
There was a problem hiding this comment.
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.
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")); |
There was a problem hiding this comment.
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.
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); |
There was a problem hiding this comment.
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.
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); |
There was a problem hiding this comment.
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.
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); |
There was a problem hiding this comment.
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.
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) |
There was a problem hiding this comment.
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> | |||
|
There was a problem hiding this comment.
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?
Description
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)
Types of changes
Checklist
License