Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
05fe7a5
Merged PR 54952: Getting ready for the 10.0 stable release. Flowing .…
joperezr Nov 6, 2025
de9fc03
[MEDI] start producing NuGet packages (#7016)
adamsitnik Nov 5, 2025
a7f5cbc
Update version numbers in AI changelogs (#7008)
stephentoub Nov 6, 2025
2279548
[MEDI] Don't stop document processing on enricher error (#7005)
adamsitnik Nov 6, 2025
90846d8
[MEDI] add PackageTags (#7022)
adamsitnik Nov 6, 2025
1d693bc
Add MarkItDownMcpReader for MCP server support (#7025)
Copilot Nov 7, 2025
9cd3cf4
Image generation tool (#6749)
ericstj Nov 7, 2025
d6f343c
Make MEAI packages use 10.0 runtime packages (#7028)
ericstj Nov 8, 2025
ea69fde
Merged PR 55051: Backport MEAI libraries updates into release/10.0
jeffhandley Nov 8, 2025
0e1d148
When using latest .NET packages, force System.Numerics.Tensors to 10.…
jeffhandley Nov 9, 2025
fbd3936
Merged PR 55054: When using latest .NET packages, force System.Numeri…
jeffhandley Nov 10, 2025
e3beb46
Add a new Microsoft.Agents.AI.Templates package with an aiagents-weba…
jeffhandley Nov 7, 2025
8917d58
Use `Microsoft.Extensions.DataIngestion` in AI Chat Web template (#7023)
MackinnonBuck Nov 10, 2025
243be68
Add Agent Framework DevUI into the aiagent-webapi template (#7026)
jeffhandley Nov 11, 2025
886cdd8
Fix display of target frameworks in agents template. Hide the chat mo…
jeffhandley Nov 11, 2025
b093829
Port project template updates into the 10.0 release branch
jeffhandley Nov 11, 2025
e9e1d3e
Merging changes from internal branch
joperezr Nov 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
<Import Project="$(MSBuildThisFileDirectory)\eng\MSBuild\Generators.targets" />
<Import Project="$(MSBuildThisFileDirectory)\eng\MSBuild\ProjectStaging.targets" />

<PropertyGroup>
<!-- Workaround https://github.com/dotnet/sdk/issues/51265 - can be removed when updating to .NET 10.0.100 (GA) SDK -->
<RestoreEnablePackagePruning Condition="'$(TargetFrameworkIdentifier)' == '.NETFramework'">false</RestoreEnablePackagePruning>
</PropertyGroup>

<!-- Warning stuff -->
<PropertyGroup>
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);NETSDK1138;MSB3270</MSBuildWarningsAsMessages>
Expand Down
6 changes: 1 addition & 5 deletions eng/MSBuild/LegacySupport.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<ItemGroup Condition="'$(InjectCompilerFeatureRequiredOnLegacy)' == 'true' AND ('$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netcoreapp3.1')">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\CompilerFeatureRequiredAttribute\*.cs" LinkBase="LegacySupport\CompilerFeatureRequiredAttribute" />
</ItemGroup>

<ItemGroup Condition="'$(InjectRequiredMemberOnLegacy)' == 'true' AND ('$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netcoreapp3.1')">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\RequiredMemberAttribute\*.cs" LinkBase="LegacySupport\RequiredMemberAttribute" />
</ItemGroup>
Expand Down Expand Up @@ -47,10 +47,6 @@
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\StringSyntaxAttribute\*.cs" LinkBase="LegacySupport\StringSyntaxAttribute" />
</ItemGroup>

<ItemGroup Condition="'$(InjectJsonSchemaExporterOnLegacy)' == 'true' AND ('$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netcoreapp3.1' or '$(TargetFramework)' == 'net6.0' or '$(TargetFramework)' == 'net7.0' or '$(TargetFramework)' == 'net8.0')">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\Shared\JsonSchemaExporter\**\*.cs" LinkBase="Shared\EmptyCollections" />
</ItemGroup>

<ItemGroup Condition="'$(InjectGetOrAddOnLegacy)' == 'true' AND ('$(TargetFramework)' == 'net462' or '$(TargetFramework)' == 'netstandard2.0')">
<Compile Include="$(MSBuildThisFileDirectory)\..\..\src\LegacySupport\GetOrAdd\*.cs" LinkBase="LegacySupport\GetOrAdd" />
</ItemGroup>
Expand Down
200 changes: 100 additions & 100 deletions eng/Version.Details.xml

Large diffs are not rendered by default.

232 changes: 116 additions & 116 deletions eng/Versions.props

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion eng/build.proj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.Build.Traversal">
<ItemGroup>
<_SnapshotsToExclude Include="$(MSBuildThisFileDirectory)..\test\**\Snapshots\**\*.*proj" />
<_GeneratedContentToExclude Include="$(MSBuildThisFileDirectory)..\test\**\TemplateSandbox\**\*.*proj" />
<_GeneratedContentToExclude Include="$(MSBuildThisFileDirectory)..\test\**\ExecutionTestSandbox\**\*.*proj" />

<!-- We recursively add all of the projects inside the src directory, except for the exclusions above -->
<_ProjectsToBuild Include="$(MSBuildThisFileDirectory)..\src\**\*.csproj" />
Expand Down
1 change: 1 addition & 0 deletions eng/packages/General-net10.props
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<PackageVersion Include="System.IO.Pipelines" Version="$(SystemIOPipelinesNet10Version)" />
<PackageVersion Include="System.Memory.Data" Version="$(SystemMemoryDataNet10Version)" />
<PackageVersion Include="System.Net.Http.Json" Version="$(SystemNetHttpJsonNet10Version)" />
<PackageVersion Include="System.Numerics.Tensors" Version="$(SystemNumericsTensorsNet10Version)" />
<PackageVersion Include="System.Text.Encodings.Web" Version="$(SystemTextEncodingsWebNet10Version)" />
<PackageVersion Include="System.Text.Json" Version="$(SystemTextJsonNet10Version)" />
<PackageVersion Include="System.Threading.Channels" Version="$(SystemThreadingChannelsNet10Version)" />
Expand Down
1 change: 1 addition & 0 deletions eng/packages/General-net9.props
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<PackageVersion Include="System.IO.Pipelines" Version="$(SystemIOPipelinesVersion)" />
<PackageVersion Include="System.Memory.Data" Version="$(SystemMemoryDataVersion)" />
<PackageVersion Include="System.Net.Http.Json" Version="$(SystemNetHttpJsonVersion)" />
<PackageVersion Include="System.Numerics.Tensors" Version="$(SystemNumericsTensorsVersion)" />
<PackageVersion Include="System.Text.Encodings.Web" Version="$(SystemTextEncodingsWebVersion)" />
<PackageVersion Include="System.Text.Json" Version="$(SystemTextJsonVersion)" />
<PackageVersion Include="System.Threading.Channels" Version="$(SystemThreadingChannelsVersion)" />
Expand Down
2 changes: 1 addition & 1 deletion eng/packages/General.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<PackageVersion Include="Microsoft.Extensions.VectorData.Abstractions" Version="$(MicrosoftExtensionsVectorDataAbstractionsVersion)" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="$(MicrosoftMLTokenizersVersion)" />
<PackageVersion Include="ModelContextProtocol.Core" Version="0.4.0-preview.3" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="OllamaSharp" Version="5.1.9" />
<PackageVersion Include="OpenAI" Version="2.6.0" />
Expand All @@ -32,7 +33,6 @@
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Memory" Version="4.5.5" />
<PackageVersion Include="System.Numerics.Tensors" Version="$(SystemNumericsTensorsVersion)" />
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
<PackageVersion Include="System.Runtime.Caching" Version="$(SystemRuntimeCachingVersion)" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.0" />
Expand Down
6 changes: 6 additions & 0 deletions eng/packages/TestOnly.props
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
<PackageVersion Include="Xunit.SkippableFact" Version="1.4.13" />
</ItemGroup>

<PropertyGroup>
<!-- Warn NU1903 happens at restore time when a transitive dependency has been marked with a vulnerability in NuGet. Our test projects get it due to Transitive dependencies to System.Net.Http and System.Text.RegularExpressions.
Given both of those assemblies are in the shared framework, they won't be used at runtime and so we dismiss this warning for test projects. -->
<NoWarn>$(NoWarn);NU1903</NoWarn>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<PackageVersion Include="Microsoft.AspNetCore.Mvc" Version="2.1.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="2.1.3" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Release History

## NOT YET RELEASED
## 9.10.2

- Updated `AIFunctionFactory` to respect `[DisplayName(...)]` on functions as a way to override the function name.
- Updated `AIFunctionFactory` to respect `[DefaultValue(...)]` on function parameters as a way to specify default values.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,47 @@ static async Task<ChatResponse> ToChatResponseAsync(
}
}

/// <summary>
/// Coalesces image result content elements in the provided list of <see cref="AIContent"/> items.
/// Unlike other content coalescing methods, this will coalesce non-sequential items based on their Name property,
/// and it will replace earlier items with later ones when duplicates are found.
/// </summary>
private static void CoalesceImageResultContent(IList<AIContent> contents)
{
Dictionary<string, int>? imageResultIndexById = null;
bool hasRemovals = false;

for (int i = 0; i < contents.Count; i++)
{
if (contents[i] is ImageGenerationToolResultContent imageResult && !string.IsNullOrEmpty(imageResult.ImageId))
{
// Check if there's an existing ImageGenerationToolResultContent with the same ImageId to replace
if (imageResultIndexById is null)
{
imageResultIndexById = new(StringComparer.Ordinal);
}

if (imageResultIndexById.TryGetValue(imageResult.ImageId!, out int existingIndex))
{
// Replace the existing imageResult with the new one
contents[existingIndex] = imageResult;
contents[i] = null!; // Mark the current one for removal, then remove in single o(n) pass
hasRemovals = true;
}
else
{
imageResultIndexById[imageResult.ImageId!] = i;
}
}
}

// Remove all of the null slots left over from the coalescing process.
if (hasRemovals)
{
RemoveNullContents(contents);
}
}

/// <summary>Coalesces sequential <see cref="AIContent"/> content elements.</summary>
internal static void CoalesceContent(IList<AIContent> contents)
{
Expand Down Expand Up @@ -219,6 +260,8 @@ internal static void CoalesceContent(IList<AIContent> contents)
return content;
});

CoalesceImageResultContent(contents);

Coalesce<DataContent>(
contents,
mergeSingle: false,
Expand Down Expand Up @@ -394,29 +437,35 @@ static bool TryAsCoalescable(AIContent content, [NotNullWhen(true)] out TContent
}

// Remove all of the null slots left over from the coalescing process.
if (contents is List<AIContent> contentsList)
{
_ = contentsList.RemoveAll(u => u is null);
}
else
{
int nextSlot = 0;
int contentsCount = contents.Count;
for (int i = 0; i < contentsCount; i++)
{
if (contents[i] is { } content)
{
contents[nextSlot++] = content;
}
}
RemoveNullContents(contents);
}
}

for (int i = contentsCount - 1; i >= nextSlot; i--)
private static void RemoveNullContents<T>(IList<T> contents)
where T : class
{
if (contents is List<AIContent> contentsList)
{
_ = contentsList.RemoveAll(u => u is null);
}
else
{
int nextSlot = 0;
int contentsCount = contents.Count;
for (int i = 0; i < contentsCount; i++)
{
if (contents[i] is { } content)
{
contents.RemoveAt(i);
contents[nextSlot++] = content;
}
}

Debug.Assert(nextSlot == contents.Count, "Expected final count to equal list length.");
for (int i = contentsCount - 1; i >= nextSlot; i--)
{
contents.RemoveAt(i);
}

Debug.Assert(nextSlot == contents.Count, "Expected final count to equal list length.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace Microsoft.Extensions.AI;
/// </para>
/// <para>
/// The relationship between <see cref="ChatResponse"/> and <see cref="ChatResponseUpdate"/> is
/// codified in the <see cref="ChatResponseExtensions.ToChatResponseAsync"/> and
/// codified in the <see cref="ChatResponseExtensions.ToChatResponseAsync(IAsyncEnumerable{ChatResponseUpdate}, System.Threading.CancellationToken)"/> and
/// <see cref="ChatResponse.ToChatResponseUpdates"/>, which enable bidirectional conversions
/// between the two. Note, however, that the provided conversions might be lossy, for example, if multiple
/// updates all have different <see cref="RawRepresentation"/> objects whereas there's only one slot for
Expand Down Expand Up @@ -58,6 +58,29 @@ public ChatResponseUpdate(ChatRole? role, IList<AIContent>? contents)
_contents = contents;
}

/// <summary>
/// Creates a new ChatResponseUpdate instance that is a copy of the current object.
/// </summary>
/// <remarks>The cloned object is a shallow copy; reference-type properties will reference the same
/// objects as the original. Use this method to duplicate the response update for further modification without
/// affecting the original instance.</remarks>
/// <returns>A new ChatResponseUpdate object with the same property values as the current instance.</returns>
public ChatResponseUpdate Clone() =>
new()
{
AdditionalProperties = AdditionalProperties,
AuthorName = AuthorName,
Contents = Contents,
CreatedAt = CreatedAt,
ConversationId = ConversationId,
FinishReason = FinishReason,
MessageId = MessageId,
ModelId = ModelId,
RawRepresentation = RawRepresentation,
ResponseId = ResponseId,
Role = Role,
};

/// <summary>Gets or sets the name of the author of the response update.</summary>
public string? AuthorName
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Extensions.AI;

/// <summary>
/// Represents the invocation of an image generation tool call by a hosted service.
/// </summary>
[Experimental("MEAI001")]
public sealed class ImageGenerationToolCallContent : AIContent
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageGenerationToolCallContent"/> class.
/// </summary>
public ImageGenerationToolCallContent()
{
}

/// <summary>
/// Gets or sets the unique identifier of the image generation item.
/// </summary>
public string? ImageId { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Extensions.AI;

/// <summary>
/// Represents an image generation tool call invocation by a hosted service.
/// </summary>
/// <remarks>
/// This content type represents when a hosted AI service invokes an image generation tool.
/// It is informational only and represents the call itself, not the result.
/// </remarks>
[Experimental("MEAI001")]
public sealed class ImageGenerationToolResultContent : AIContent
{
/// <summary>
/// Initializes a new instance of the <see cref="ImageGenerationToolResultContent"/> class.
/// </summary>
public ImageGenerationToolResultContent()
{
}

/// <summary>
/// Gets or sets the unique identifier of the image generation item.
/// </summary>
public string? ImageId { get; set; }

/// <summary>
/// Gets or sets the generated content items.
/// </summary>
/// <remarks>
/// Content is typically <see cref="DataContent"/> for images streamed from the tool, or <see cref="UriContent"/> for remotely hosted images, but
/// can also be provider-specific content types that represent the generated images.
/// </remarks>
public IList<AIContent>? Outputs { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ protected ImageGenerationOptions(ImageGenerationOptions? other)
/// </summary>
public ImageGenerationResponseFormat? ResponseFormat { get; set; }

/// <summary>
/// Gets or sets the number of intermediate streaming images to generate.
/// </summary>
public int? StreamingCount { get; set; }

/// <summary>Gets or sets any additional properties associated with the options.</summary>
public AdditionalPropertiesDictionary? AdditionalProperties { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<RootNamespace>Microsoft.Extensions.AI</RootNamespace>
<Description>Abstractions representing generative AI components.</Description>
<Workstream>AI</Workstream>
<ForceLatestDotnetVersions>true</ForceLatestDotnetVersions>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -21,21 +22,20 @@

<PropertyGroup>
<InjectExperimentalAttributeOnLegacy>true</InjectExperimentalAttributeOnLegacy>
<InjectJsonSchemaExporterOnLegacy>true</InjectJsonSchemaExporterOnLegacy>
<InjectRequiredMemberOnLegacy>true</InjectRequiredMemberOnLegacy>
<InjectSharedEmptyCollections>true</InjectSharedEmptyCollections>
<InjectStringHashOnLegacy>true</InjectStringHashOnLegacy>
<InjectStringSyntaxAttributeOnLegacy>true</InjectStringSyntaxAttributeOnLegacy>
<InjectSystemIndexOnLegacy>true</InjectSystemIndexOnLegacy>
</PropertyGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'">
<ItemGroup>
<PackageReference Include="System.Text.Json" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
<Reference Include="System.Net.Http" />
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,10 @@
"Member": "Microsoft.Extensions.AI.ChatResponseUpdate.ChatResponseUpdate(Microsoft.Extensions.AI.ChatRole? role, System.Collections.Generic.IList<Microsoft.Extensions.AI.AIContent>? contents);",
"Stage": "Stable"
},
{
"Member": "Microsoft.Extensions.AI.ChatResponseUpdate Microsoft.Extensions.AI.ChatResponseUpdate.Clone();",
"Stage": "Stable"
},
{
"Member": "override string Microsoft.Extensions.AI.ChatResponseUpdate.ToString();",
"Stage": "Stable"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics.CodeAnalysis;

namespace Microsoft.Extensions.AI;

/// <summary>Represents a hosted tool that can be specified to an AI service to enable it to perform image generation.</summary>
/// <remarks>
/// This tool does not itself implement image generation. It is a marker that can be used to inform a service
/// that the service is allowed to perform image generation if the service is capable of doing so.
/// </remarks>
[Experimental("MEAI001")]
public class HostedImageGenerationTool : AITool
{
/// <summary>
/// Initializes a new instance of the <see cref="HostedImageGenerationTool"/> class with the specified options.
/// </summary>
public HostedImageGenerationTool()
{
}

/// <summary>
/// Gets or sets the options used to configure image generation.
/// </summary>
public ImageGenerationOptions? Options { get; set; }
}
Loading
Loading