Skip to content

Commit b797b53

Browse files
authored
Stage an MEAI 10.4.1 release (#7402)
2 parents 6708d1d + d39d26d commit b797b53

173 files changed

Lines changed: 15231 additions & 1329 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

eng/MSBuild/Packaging.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/overview -->
3838
<EnablePackageValidation>true</EnablePackageValidation>
3939

40-
<PackageValidationBaselineVersion Condition="'$(Stage)' == 'normal' and '$(PackageValidationBaselineVersion)' == ''">10.2.0</PackageValidationBaselineVersion>
40+
<PackageValidationBaselineVersion Condition="'$(Stage)' == 'normal' and '$(PackageValidationBaselineVersion)' == ''">10.4.0</PackageValidationBaselineVersion>
4141
</PropertyGroup>
4242

4343
<!-- Verify that the minimum supported TFM is actually used. Not applicable for project template packages. -->

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup Label="Version settings">
33
<MajorVersion>10</MajorVersion>
44
<MinorVersion>4</MinorVersion>
5-
<PatchVersion>0</PatchVersion>
5+
<PatchVersion>1</PatchVersion>
66
<PreReleaseVersionLabel>preview</PreReleaseVersionLabel>
77
<PreReleaseVersionIteration>1</PreReleaseVersionIteration>
88
<VersionPrefix>$(MajorVersion).$(MinorVersion).$(PatchVersion)</VersionPrefix>

eng/packages/General.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion)" />
1717
<PackageVersion Include="Microsoft.Extensions.VectorData.Abstractions" Version="$(MicrosoftExtensionsVectorDataAbstractionsVersion)" />
1818
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="$(MicrosoftMLTokenizersVersion)" />
19-
<PackageVersion Include="ModelContextProtocol.Core" Version="0.4.0-preview.3" />
19+
<PackageVersion Include="ModelContextProtocol.Core" Version="1.1.0" />
2020
<PackageVersion Include="OpenAI" Version="2.9.1" />
2121
<PackageVersion Include="Polly" Version="8.4.2" />
2222
<PackageVersion Include="Polly.Core" Version="8.4.2" />

src/Libraries/Microsoft.Extensions.AI.Abstractions/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## NOT YET RELEASED
44

5+
- Added `ITextToSpeechClient` abstraction for interacting with text-to-speech capabilities.
6+
7+
## 10.4.0
8+
59
- `AddAIContentType` now automatically registers the content type against every base in the inheritance chain up to `AIContent`.
610
- Added `IHostedFileClient` interface and related types for interacting with files hosted by the service.
711
- Added `WebSearchToolCallContent` and `WebSearchToolResultContent` for representing web search tool calls and results.
@@ -10,6 +14,7 @@
1014
- Updated AI function parameter JSON schema generation to honor `[Required]` attributes.
1115
- Updated `AIFunctionFactory` to work better with `DynamicMethod`-based functions.
1216
- Removed the experimental `IToolReductionStrategy` type.
17+
- Fixed the serialization of `ResponseContinuationToken` / `AllowBackgroundResponses` properties.
1318

1419
## 10.3.0
1520

src/Libraries/Microsoft.Extensions.AI.Abstractions/CompatibilitySuppressions.xml

Lines changed: 0 additions & 808 deletions
This file was deleted.

src/Libraries/Microsoft.Extensions.AI.Abstractions/Contents/UriContent.cs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System;
55
using System.Diagnostics;
6+
using System.Net.Mime;
67
using System.Text.Json.Serialization;
78
using Microsoft.Shared.Diagnostics;
89

@@ -18,6 +19,9 @@ namespace Microsoft.Extensions.AI;
1819
[DebuggerDisplay("{DebuggerDisplay,nq}")]
1920
public class UriContent : AIContent
2021
{
22+
/// <summary>The default media type for unknown file extensions.</summary>
23+
private const string DefaultMediaType = "application/octet-stream";
24+
2125
/// <summary>The URI represented.</summary>
2226
private Uri _uri;
2327

@@ -26,37 +30,35 @@ public class UriContent : AIContent
2630

2731
/// <summary>Initializes a new instance of the <see cref="UriContent"/> class.</summary>
2832
/// <param name="uri">The URI to the represented content.</param>
29-
/// <param name="mediaType">The media type (also known as MIME type) represented by the content.</param>
33+
/// <param name="mediaType">
34+
/// The media type (also known as MIME type) represented by the content. If not provided,
35+
/// it will be inferred from the file extension of the URI. If it cannot be inferred,
36+
/// "application/octet-stream" is used.
37+
/// </param>
3038
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
31-
/// <exception cref="ArgumentNullException"><paramref name="mediaType"/> is <see langword="null"/>.</exception>
3239
/// <exception cref="ArgumentException"><paramref name="mediaType"/> is an invalid media type.</exception>
3340
/// <exception cref="UriFormatException"><paramref name="uri"/> is an invalid URL.</exception>
34-
/// <remarks>
35-
/// A media type must be specified, so that consumers know what to do with the content.
36-
/// If an exact media type is not known, but the category (e.g. image) is known, a wildcard
37-
/// may be used (e.g. "image/*").
38-
/// </remarks>
39-
public UriContent(string uri, string mediaType)
41+
public UriContent(string uri, string? mediaType = null)
4042
: this(new Uri(Throw.IfNull(uri)), mediaType)
4143
{
4244
}
4345

4446
/// <summary>Initializes a new instance of the <see cref="UriContent"/> class.</summary>
4547
/// <param name="uri">The URI to the represented content.</param>
46-
/// <param name="mediaType">The media type (also known as MIME type) represented by the content.</param>
48+
/// <param name="mediaType">
49+
/// The media type (also known as MIME type) represented by the content. If not provided,
50+
/// it will be inferred from the file extension of the URI. If it cannot be inferred,
51+
/// "application/octet-stream" is used.
52+
/// </param>
4753
/// <exception cref="ArgumentNullException"><paramref name="uri"/> is <see langword="null"/>.</exception>
48-
/// <exception cref="ArgumentNullException"><paramref name="mediaType"/> is <see langword="null"/>.</exception>
4954
/// <exception cref="ArgumentException"><paramref name="mediaType"/> is an invalid media type.</exception>
50-
/// <remarks>
51-
/// A media type must be specified, so that consumers know what to do with the content.
52-
/// If an exact media type is not known, but the category (e.g. image) is known, a wildcard
53-
/// may be used (e.g. "image/*").
54-
/// </remarks>
5555
[JsonConstructor]
56-
public UriContent(Uri uri, string mediaType)
56+
public UriContent(Uri uri, string? mediaType = null)
5757
{
5858
_uri = Throw.IfNull(uri);
59-
_mediaType = DataUriParser.ThrowIfInvalidMediaType(mediaType);
59+
_mediaType = mediaType is not null
60+
? DataUriParser.ThrowIfInvalidMediaType(mediaType)
61+
: InferMediaType(uri);
6062
}
6163

6264
/// <summary>Gets or sets the <see cref="Uri"/> for this content.</summary>
@@ -90,4 +92,25 @@ public string MediaType
9092
/// <summary>Gets a string representing this instance to display in the debugger.</summary>
9193
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
9294
private string DebuggerDisplay => $"Uri = {_uri}";
95+
96+
/// <summary>Infers the media type from the URI's file extension.</summary>
97+
private static string InferMediaType(Uri uri)
98+
{
99+
string path;
100+
if (uri.IsAbsoluteUri)
101+
{
102+
path = uri.AbsolutePath;
103+
}
104+
else
105+
{
106+
path = uri.OriginalString;
107+
int i = path.AsSpan().IndexOfAny('?', '#');
108+
if (i >= 0)
109+
{
110+
path = path.Substring(0, i);
111+
}
112+
}
113+
114+
return MediaTypeMap.GetMediaType(path) ?? DefaultMediaType;
115+
}
93116
}

src/Libraries/Microsoft.Extensions.AI.Abstractions/Files/HostedFileDownloadStream.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,40 @@ protected HostedFileDownloadStream()
5151
/// </remarks>
5252
public virtual string? FileName => null;
5353

54+
/// <inheritdoc />
55+
public override bool CanWrite => false;
56+
57+
/// <inheritdoc />
58+
public override void SetLength(long value) => throw new NotSupportedException();
59+
60+
/// <inheritdoc />
61+
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) =>
62+
throw new NotSupportedException();
63+
64+
/// <inheritdoc />
65+
public override void EndWrite(IAsyncResult asyncResult) => throw new NotSupportedException();
66+
67+
/// <inheritdoc />
68+
public override void WriteByte(byte value) => throw new NotSupportedException();
69+
70+
/// <inheritdoc />
71+
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
72+
73+
#if NET
74+
/// <inheritdoc />
75+
public override void Write(ReadOnlySpan<byte> buffer) => throw new NotSupportedException();
76+
#endif
77+
78+
/// <inheritdoc />
79+
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
80+
throw new NotSupportedException();
81+
82+
#if NET
83+
/// <inheritdoc />
84+
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) =>
85+
throw new NotSupportedException();
86+
#endif
87+
5488
/// <summary>
5589
/// Reads the entire stream content from its current position and returns it as a <see cref="DataContent"/>.
5690
/// </summary>

src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionDeclaration.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,29 @@ protected AIFunctionDeclaration()
4040
/// The metadata present in the schema document plays an important role in guiding AI function invocation.
4141
/// </para>
4242
/// <para>
43+
/// When an <see cref="AIFunction"/> is created via <see cref="AIFunctionFactory"/>, this schema is automatically derived from the
44+
/// method's parameters using the configured <see cref="JsonSerializerOptions"/> and <see cref="AIJsonSchemaCreateOptions"/>.
45+
/// </para>
46+
/// <para>
4347
/// When no schema is specified, consuming chat clients should assume the "{}" or "true" schema, indicating that any JSON input is admissible.
4448
/// </para>
4549
/// </remarks>
4650
public virtual JsonElement JsonSchema => AIJsonUtilities.DefaultJsonSchema;
4751

4852
/// <summary>Gets a JSON Schema describing the function's return value.</summary>
4953
/// <remarks>
50-
/// A <see langword="null"/> typically reflects a function that doesn't specify a return schema
51-
/// or a function that returns <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>.
54+
/// <para>
55+
/// When an <see cref="AIFunction"/> is created via <see cref="AIFunctionFactory"/>, this schema is automatically derived from the
56+
/// method's return type using the configured <see cref="JsonSerializerOptions"/> and <see cref="AIJsonSchemaCreateOptions"/>.
57+
/// For methods returning <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/>, the schema is based on the
58+
/// unwrapped result type. Return schema generation can be excluded by setting
59+
/// <see cref="AIFunctionFactoryOptions.ExcludeResultSchema"/> to <see langword="true"/>.
60+
/// </para>
61+
/// <para>
62+
/// A <see langword="null"/> value typically reflects a function that doesn't specify a return schema,
63+
/// a function that returns <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>,
64+
/// or a function for which <see cref="AIFunctionFactoryOptions.ExcludeResultSchema"/> was set to <see langword="true"/>.
65+
/// </para>
5266
/// </remarks>
5367
public virtual JsonElement? ReturnJsonSchema => null;
5468
}

src/Libraries/Microsoft.Extensions.AI.Abstractions/Functions/AIFunctionFactory.cs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@
2727
namespace Microsoft.Extensions.AI;
2828

2929
/// <summary>Provides factory methods for creating commonly-used implementations of <see cref="AIFunction"/>.</summary>
30+
/// <remarks>
31+
/// <para>
32+
/// The <see cref="AIFunctionFactory"/> class creates <see cref="AIFunction"/> instances that wrap .NET methods
33+
/// (specified as <see cref="Delegate"/> or <see cref="MethodInfo"/>). As part of this process, JSON schemas are
34+
/// automatically derived for both the function's input parameters (exposed via <see cref="AIFunctionDeclaration.JsonSchema"/>)
35+
/// and, by default, the function's return type (exposed via <see cref="AIFunctionDeclaration.ReturnJsonSchema"/>).
36+
/// These schemas are produced using the <see cref="AIFunctionFactoryOptions.SerializerOptions"/> and
37+
/// <see cref="AIFunctionFactoryOptions.JsonSchemaCreateOptions"/>, and enable AI services to understand and
38+
/// interact with the function. Return value serialization and schema derivation behavior can be customized
39+
/// via <see cref="AIFunctionFactoryOptions.MarshalResult"/> and <see cref="AIFunctionFactoryOptions.ExcludeResultSchema"/>,
40+
/// respectively.
41+
/// </para>
42+
/// </remarks>
3043
/// <related type="Article" href="https://learn.microsoft.com/dotnet/ai/quickstarts/use-function-calling">Invoke .NET functions using an AI model.</related>
3144
public static partial class AIFunctionFactory
3245
{
@@ -98,7 +111,14 @@ public static partial class AIFunctionFactory
98111
/// special-cased and are not serialized: the created function returns the original instance(s) directly to enable
99112
/// callers (such as an <c>IChatClient</c>) to perform type tests and implement specialized handling. If
100113
/// <see cref="AIFunctionFactoryOptions.MarshalResult"/> is supplied, that delegate governs the behavior instead.
101-
/// Handling of return values can be overridden via <see cref="AIFunctionFactoryOptions.MarshalResult"/>.
114+
/// </para>
115+
/// <para>
116+
/// In addition to the parameter schema, a JSON schema is also derived from the method's return type and exposed via the
117+
/// returned <see cref="AIFunction"/>'s <see cref="AIFunctionDeclaration.ReturnJsonSchema"/>. For methods returning
118+
/// <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>, no return schema is produced (the property is <see langword="null"/>).
119+
/// For methods returning <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/>, the schema is derived from the
120+
/// unwrapped result type. Return schema generation can be excluded via <see cref="AIFunctionFactoryOptions.ExcludeResultSchema"/>,
121+
/// and its generation is governed by <paramref name="options"/>'s <see cref="AIFunctionFactoryOptions.JsonSchemaCreateOptions"/>.
102122
/// </para>
103123
/// </remarks>
104124
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
@@ -169,6 +189,11 @@ public static AIFunction Create(Delegate method, AIFunctionFactoryOptions? optio
169189
/// derived type of <see cref="AIContent"/>, or any type assignable from <see cref="IEnumerable{AIContent}"/> are not serialized;
170190
/// they are returned as-is to facilitate specialized handling.
171191
/// </para>
192+
/// <para>
193+
/// A JSON schema is also derived from the method's return type and exposed via <see cref="AIFunctionDeclaration.ReturnJsonSchema"/>.
194+
/// For methods returning <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>, no return schema is produced.
195+
/// For methods returning <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/>, the schema is derived from the unwrapped result type.
196+
/// </para>
172197
/// </remarks>
173198
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
174199
/// <exception cref="JsonException">A parameter to <paramref name="method"/> is not serializable.</exception>
@@ -255,6 +280,14 @@ public static AIFunction Create(Delegate method, string? name = null, string? de
255280
/// any type assignable from <see cref="IEnumerable{AIContent}"/> are not serialized and are instead returned directly.
256281
/// Handling of return values can be overridden via <see cref="AIFunctionFactoryOptions.MarshalResult"/>.
257282
/// </para>
283+
/// <para>
284+
/// In addition to the parameter schema, a JSON schema is also derived from the method's return type and exposed via the
285+
/// returned <see cref="AIFunction"/>'s <see cref="AIFunctionDeclaration.ReturnJsonSchema"/>. For methods returning
286+
/// <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>, no return schema is produced (the property is <see langword="null"/>).
287+
/// For methods returning <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/>, the schema is derived from the
288+
/// unwrapped result type. Return schema generation can be excluded via <see cref="AIFunctionFactoryOptions.ExcludeResultSchema"/>,
289+
/// and its generation is governed by <paramref name="options"/>'s <see cref="AIFunctionFactoryOptions.JsonSchemaCreateOptions"/>.
290+
/// </para>
258291
/// </remarks>
259292
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
260293
/// <exception cref="ArgumentNullException"><paramref name="method"/> represents an instance method but <paramref name="target"/> is null.</exception>
@@ -334,6 +367,11 @@ public static AIFunction Create(MethodInfo method, object? target, AIFunctionFac
334367
/// derived type of <see cref="AIContent"/>, or any type assignable from <see cref="IEnumerable{AIContent}"/> are returned
335368
/// without serialization to enable specialized handling.
336369
/// </para>
370+
/// <para>
371+
/// A JSON schema is also derived from the method's return type and exposed via <see cref="AIFunctionDeclaration.ReturnJsonSchema"/>.
372+
/// For methods returning <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>, no return schema is produced.
373+
/// For methods returning <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/>, the schema is derived from the unwrapped result type.
374+
/// </para>
337375
/// </remarks>
338376
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
339377
/// <exception cref="ArgumentNullException"><paramref name="method"/> represents an instance method but <paramref name="target"/> is null.</exception>
@@ -433,6 +471,14 @@ public static AIFunction Create(MethodInfo method, object? target, string? name
433471
/// assignable from <see cref="IEnumerable{AIContent}"/> are returned directly without serialization.
434472
/// Handling of return values can be overridden via <see cref="AIFunctionFactoryOptions.MarshalResult"/>.
435473
/// </para>
474+
/// <para>
475+
/// In addition to the parameter schema, a JSON schema is also derived from the method's return type and exposed via the
476+
/// returned <see cref="AIFunction"/>'s <see cref="AIFunctionDeclaration.ReturnJsonSchema"/>. For methods returning
477+
/// <see cref="void"/>, <see cref="Task"/>, or <see cref="ValueTask"/>, no return schema is produced (the property is <see langword="null"/>).
478+
/// For methods returning <see cref="Task{TResult}"/> or <see cref="ValueTask{TResult}"/>, the schema is derived from the
479+
/// unwrapped result type. Return schema generation can be excluded via <see cref="AIFunctionFactoryOptions.ExcludeResultSchema"/>,
480+
/// and its generation is governed by <paramref name="options"/>'s <see cref="AIFunctionFactoryOptions.JsonSchemaCreateOptions"/>.
481+
/// </para>
436482
/// </remarks>
437483
/// <exception cref="ArgumentNullException"><paramref name="method"/> is <see langword="null"/>.</exception>
438484
/// <exception cref="ArgumentNullException"><paramref name="createInstanceFunc"/> is <see langword="null"/>.</exception>

0 commit comments

Comments
 (0)