Skip to content

Commit f78418d

Browse files
authored
Lower M.E.AI dependencies on .NET 8 and lower back to 8.0.x (#6230)
We had been relying on System.Text.Json 9.0.x. This removes that override to only use 8.x versions of packages until building for .NET 9.
1 parent 52db82b commit f78418d

File tree

10 files changed

+89
-30
lines changed

10 files changed

+89
-30
lines changed

src/Libraries/Microsoft.Extensions.AI/ChatCompletion/AnonymousDelegatingChatClient.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Diagnostics;
7+
using System.Runtime.CompilerServices;
78
using System.Threading;
89
using System.Threading.Channels;
910
using System.Threading.Tasks;
@@ -158,7 +159,22 @@ await _sharedFunc(messages, options, async (messages, options, cancellationToken
158159
}
159160
});
160161

162+
#if NET9_0_OR_GREATER
161163
return updates.Reader.ReadAllAsync(cancellationToken);
164+
#else
165+
return ReadAllAsync(updates, cancellationToken);
166+
static async IAsyncEnumerable<ChatResponseUpdate> ReadAllAsync(
167+
ChannelReader<ChatResponseUpdate> channel, [EnumeratorCancellation] CancellationToken cancellationToken)
168+
{
169+
while (await channel.WaitToReadAsync(cancellationToken).ConfigureAwait(false))
170+
{
171+
while (channel.TryRead(out var update))
172+
{
173+
yield return update;
174+
}
175+
}
176+
}
177+
#endif
162178
}
163179
else if (_getStreamingResponseFunc is not null)
164180
{

src/Libraries/Microsoft.Extensions.AI/ChatCompletion/ChatResponse{T}.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ namespace Microsoft.Extensions.AI;
2020
/// </remarks>
2121
public class ChatResponse<T> : ChatResponse
2222
{
23-
private static readonly JsonReaderOptions _allowMultipleValuesJsonReaderOptions = new() { AllowMultipleValues = true };
23+
private static readonly JsonReaderOptions _allowMultipleValuesJsonReaderOptions = new()
24+
{
25+
#if NET9_0_OR_GREATER
26+
AllowMultipleValues = true
27+
#endif
28+
};
2429
private readonly JsonSerializerOptions _serializerOptions;
2530

2631
private T? _deserializedResult;

src/Libraries/Microsoft.Extensions.AI/ChatCompletion/OpenTelemetryChatClient.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
using Microsoft.Shared.Diagnostics;
1919

2020
#pragma warning disable S3358 // Ternary operators should not be nested
21+
#pragma warning disable SA1111 // Closing parenthesis should be on line of last parameter
22+
#pragma warning disable SA1113 // Comma should be on the same line as previous parameter
2123

2224
namespace Microsoft.Extensions.AI;
2325

@@ -70,14 +72,20 @@ public OpenTelemetryChatClient(IChatClient innerClient, ILogger? logger = null,
7072
_tokenUsageHistogram = _meter.CreateHistogram<int>(
7173
OpenTelemetryConsts.GenAI.Client.TokenUsage.Name,
7274
OpenTelemetryConsts.TokensUnit,
73-
OpenTelemetryConsts.GenAI.Client.TokenUsage.Description,
74-
advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.TokenUsage.ExplicitBucketBoundaries });
75+
OpenTelemetryConsts.GenAI.Client.TokenUsage.Description
76+
#if NET9_0_OR_GREATER
77+
, advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.TokenUsage.ExplicitBucketBoundaries }
78+
#endif
79+
);
7580

7681
_operationDurationHistogram = _meter.CreateHistogram<double>(
7782
OpenTelemetryConsts.GenAI.Client.OperationDuration.Name,
7883
OpenTelemetryConsts.SecondsUnit,
79-
OpenTelemetryConsts.GenAI.Client.OperationDuration.Description,
80-
advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.OperationDuration.ExplicitBucketBoundaries });
84+
OpenTelemetryConsts.GenAI.Client.OperationDuration.Description
85+
#if NET9_0_OR_GREATER
86+
, advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.OperationDuration.ExplicitBucketBoundaries }
87+
#endif
88+
);
8189

8290
_jsonSerializerOptions = AIJsonUtilities.DefaultOptions;
8391
}

src/Libraries/Microsoft.Extensions.AI/Embeddings/OpenTelemetryEmbeddingGenerator.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
using Microsoft.Extensions.Logging;
1313
using Microsoft.Shared.Diagnostics;
1414

15+
#pragma warning disable SA1111 // Closing parenthesis should be on line of last parameter
16+
#pragma warning disable SA1113 // Comma should be on the same line as previous parameter
17+
1518
namespace Microsoft.Extensions.AI;
1619

1720
/// <summary>Represents a delegating embedding generator that implements the OpenTelemetry Semantic Conventions for Generative AI systems.</summary>
@@ -67,14 +70,20 @@ public OpenTelemetryEmbeddingGenerator(IEmbeddingGenerator<TInput, TEmbedding> i
6770
_tokenUsageHistogram = _meter.CreateHistogram<int>(
6871
OpenTelemetryConsts.GenAI.Client.TokenUsage.Name,
6972
OpenTelemetryConsts.TokensUnit,
70-
OpenTelemetryConsts.GenAI.Client.TokenUsage.Description,
71-
advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.TokenUsage.ExplicitBucketBoundaries });
73+
OpenTelemetryConsts.GenAI.Client.TokenUsage.Description
74+
#if NET9_0_OR_GREATER
75+
, advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.TokenUsage.ExplicitBucketBoundaries }
76+
#endif
77+
);
7278

7379
_operationDurationHistogram = _meter.CreateHistogram<double>(
7480
OpenTelemetryConsts.GenAI.Client.OperationDuration.Name,
7581
OpenTelemetryConsts.SecondsUnit,
76-
OpenTelemetryConsts.GenAI.Client.OperationDuration.Description,
77-
advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.OperationDuration.ExplicitBucketBoundaries });
82+
OpenTelemetryConsts.GenAI.Client.OperationDuration.Description
83+
#if NET9_0_OR_GREATER
84+
, advice: new() { HistogramBucketBoundaries = OpenTelemetryConsts.GenAI.Client.OperationDuration.ExplicitBucketBoundaries }
85+
#endif
86+
);
7887
}
7988

8089
/// <inheritdoc/>

src/Libraries/Microsoft.Extensions.AI/Microsoft.Extensions.AI.csproj

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
<RootNamespace>Microsoft.Extensions.AI</RootNamespace>
55
<Description>Utilities for working with generative AI components.</Description>
66
<Workstream>AI</Workstream>
7-
<!-- This package needs to stay referencing .NET 9 versions of its dependencies -->
8-
<ForceLatestDotnetVersions>true</ForceLatestDotnetVersions>
97
</PropertyGroup>
108

119
<PropertyGroup>

test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/AssertExtensions.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.Linq;
66
using System.Text.Json;
7+
using System.Text.Json.Nodes;
78
using Xunit;
89
using Xunit.Sdk;
910

@@ -57,7 +58,9 @@ private static void AreJsonEquivalentValues(object? expected, object? actual, Js
5758
options ??= JsonSerializerOptions.Default;
5859
JsonElement expectedElement = NormalizeToElement(expected, options);
5960
JsonElement actualElement = NormalizeToElement(actual, options);
60-
if (!JsonElement.DeepEquals(expectedElement, actualElement))
61+
if (!JsonNode.DeepEquals(
62+
JsonSerializer.SerializeToNode(expectedElement),
63+
JsonSerializer.SerializeToNode(actualElement)))
6164
{
6265
string message = propertyName is null
6366
? $"Function result does not match expected JSON.\r\nExpected: {expectedElement.GetRawText()}\r\nActual: {actualElement.GetRawText()}"

test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Microsoft.Extensions.AI.Abstractions.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
</ItemGroup>
2525

2626
<ItemGroup>
27+
<PackageReference Include="System.Text.Json" />
2728
<PackageReference Include="Microsoft.Extensions.Logging" />
2829
<PackageReference Include="System.Memory.Data" />
2930
<PackageReference Include="JsonSchema.Net" />

test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ public static void CreateJsonSchema_DefaultParameters_GeneratesExpectedJsonSchem
147147

148148
JsonElement actual = AIJsonUtilities.CreateJsonSchema(typeof(MyPoco), serializerOptions: JsonSerializerOptions.Default);
149149

150-
Assert.True(JsonElement.DeepEquals(expected, actual));
150+
Assert.True(DeepEquals(expected, actual));
151151
}
152152

153153
[Fact]
@@ -192,7 +192,7 @@ public static void CreateJsonSchema_OverriddenParameters_GeneratesExpectedJsonSc
192192
serializerOptions: JsonSerializerOptions.Default,
193193
inferenceOptions: inferenceOptions);
194194

195-
Assert.True(JsonElement.DeepEquals(expected, actual));
195+
Assert.True(DeepEquals(expected, actual));
196196
}
197197

198198
[Fact]
@@ -237,7 +237,7 @@ public static void CreateJsonSchema_UserDefinedTransformer()
237237

238238
JsonElement actual = AIJsonUtilities.CreateJsonSchema(typeof(MyPoco), serializerOptions: JsonSerializerOptions.Default, inferenceOptions: inferenceOptions);
239239

240-
Assert.True(JsonElement.DeepEquals(expected, actual));
240+
Assert.True(DeepEquals(expected, actual));
241241
}
242242

243243
[Fact]
@@ -265,7 +265,7 @@ public static void CreateJsonSchema_FiltersDisallowedKeywords()
265265

266266
JsonElement actual = AIJsonUtilities.CreateJsonSchema(typeof(PocoWithTypesWithOpenAIUnsupportedKeywords), serializerOptions: JsonSerializerOptions.Default);
267267

268-
Assert.True(JsonElement.DeepEquals(expected, actual));
268+
Assert.True(DeepEquals(expected, actual));
269269
}
270270

271271
public class PocoWithTypesWithOpenAIUnsupportedKeywords
@@ -289,7 +289,7 @@ public static void CreateFunctionJsonSchema_ReturnsExpectedValue()
289289
Assert.NotNull(func.UnderlyingMethod);
290290

291291
JsonElement resolvedSchema = AIJsonUtilities.CreateFunctionJsonSchema(func.UnderlyingMethod, title: func.Name);
292-
Assert.True(JsonElement.DeepEquals(resolvedSchema, func.JsonSchema));
292+
Assert.True(DeepEquals(resolvedSchema, func.JsonSchema));
293293
}
294294

295295
[Fact]
@@ -301,7 +301,9 @@ public static void CreateFunctionJsonSchema_TreatsIntegralTypesAsInteger_EvenWit
301301
JsonElement schemaParameters = func.JsonSchema.GetProperty("properties");
302302
Assert.NotNull(func.UnderlyingMethod);
303303
ParameterInfo[] parameters = func.UnderlyingMethod.GetParameters();
304+
#if NET9_0_OR_GREATER
304305
Assert.Equal(parameters.Length, schemaParameters.GetPropertyCount());
306+
#endif
305307

306308
int i = 0;
307309
foreach (JsonProperty property in schemaParameters.EnumerateObject())
@@ -317,7 +319,7 @@ public static void CreateFunctionJsonSchema_TreatsIntegralTypesAsInteger_EvenWit
317319
""").RootElement;
318320

319321
JsonElement actualSchema = property.Value;
320-
Assert.True(JsonElement.DeepEquals(expected, actualSchema));
322+
Assert.True(DeepEquals(expected, actualSchema));
321323
i++;
322324
}
323325
}
@@ -480,4 +482,15 @@ private class DerivedAIContent : AIContent
480482
{
481483
public int DerivedValue { get; set; }
482484
}
485+
486+
private static bool DeepEquals(JsonElement element1, JsonElement element2)
487+
{
488+
#if NET9_0_OR_GREATER
489+
return JsonElement.DeepEquals(element1, element2);
490+
#else
491+
return JsonNode.DeepEquals(
492+
JsonSerializer.SerializeToNode(element1),
493+
JsonSerializer.SerializeToNode(element2));
494+
#endif
495+
}
483496
}

test/Shared/JsonSchemaExporter/TestData.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@
66
using System.Diagnostics.CodeAnalysis;
77
using System.Text.Json;
88
using System.Text.Json.Nodes;
9-
using System.Text.Json.Schema;
109

1110
namespace Microsoft.Extensions.AI.JsonSchemaExporter;
1211

1312
internal sealed record TestData<T>(
1413
T? Value,
1514
[StringSyntax(StringSyntaxAttribute.Json)] string ExpectedJsonSchema,
1615
IEnumerable<T?>? AdditionalValues = null,
17-
JsonSchemaExporterOptions? ExporterOptions = null,
16+
object? ExporterOptions = null,
1817
JsonSerializerOptions? Options = null,
1918
bool WritesNumbersAsStrings = false)
2019
: ITestData
@@ -33,7 +32,9 @@ IEnumerable<ITestData> ITestData.GetTestDataForAllValues()
3332
yield return this;
3433

3534
if (default(T) is null &&
36-
ExporterOptions is { TreatNullObliviousAsNonNullable: false } &&
35+
#if NET9_0_OR_GREATER
36+
ExporterOptions is System.Text.Json.Schema.JsonSchemaExporterOptions { TreatNullObliviousAsNonNullable: false } &&
37+
#endif
3738
Value is not null)
3839
{
3940
yield return this with { Value = default };

test/Shared/JsonSchemaExporter/TestTypes.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,14 @@
99
using System.ComponentModel.DataAnnotations;
1010
using System.Diagnostics.CodeAnalysis;
1111
using System.Linq;
12+
#if NET9_0_OR_GREATER
1213
using System.Reflection;
14+
#endif
1315
using System.Text.Json;
1416
using System.Text.Json.Nodes;
17+
#if NET9_0_OR_GREATER
1518
using System.Text.Json.Schema;
19+
#endif
1620
using System.Text.Json.Serialization;
1721
using System.Xml.Linq;
1822

@@ -148,6 +152,7 @@ public static IEnumerable<ITestData> GetTestDataCore()
148152
}
149153
""");
150154

155+
#if NET9_0_OR_GREATER
151156
// Same as above but with nullable types set to non-nullable
152157
yield return new TestData<SimplePoco>(
153158
Value: new() { String = "string", StringNullable = "string", Int = 42, Double = 3.14, Boolean = true },
@@ -164,7 +169,8 @@ public static IEnumerable<ITestData> GetTestDataCore()
164169
}
165170
}
166171
""",
167-
ExporterOptions: new() { TreatNullObliviousAsNonNullable = true });
172+
ExporterOptions: new JsonSchemaExporterOptions { TreatNullObliviousAsNonNullable = true });
173+
#endif
168174

169175
yield return new TestData<SimpleRecord>(
170176
Value: new(1, "two", true, 3.14),
@@ -305,6 +311,7 @@ public static IEnumerable<ITestData> GetTestDataCore()
305311
}
306312
""");
307313

314+
#if NET9_0_OR_GREATER
308315
// Same as above but with non-nullable reference types by default.
309316
yield return new TestData<PocoWithRecursiveMembers>(
310317
Value: new() { Value = 1, Next = new() { Value = 2, Next = new() { Value = 3 } } },
@@ -324,9 +331,8 @@ public static IEnumerable<ITestData> GetTestDataCore()
324331
}
325332
}
326333
""",
327-
ExporterOptions: new() { TreatNullObliviousAsNonNullable = true });
334+
ExporterOptions: new JsonSchemaExporterOptions { TreatNullObliviousAsNonNullable = true });
328335

329-
#if !NET9_0 // Disable until https://github.com/dotnet/runtime/pull/108764 gets backported
330336
SimpleRecord recordValue = new(42, "str", true, 3.14);
331337
yield return new TestData<PocoWithNonRecursiveDuplicateOccurrences>(
332338
Value: new() { Value1 = recordValue, Value2 = recordValue, ArrayValue = [recordValue], ListValue = [recordValue] },
@@ -755,6 +761,7 @@ of the type which points to the first occurrence. */
755761
}
756762
""");
757763

764+
#if NET9_0_OR_GREATER
758765
yield return new TestData<ClassWithComponentModelAttributes>(
759766
Value: new("string", -1),
760767
ExpectedJsonSchema: """
@@ -767,7 +774,7 @@ of the type which points to the first occurrence. */
767774
"required": ["StringValue","IntValue"]
768775
}
769776
""",
770-
ExporterOptions: new()
777+
ExporterOptions: new JsonSchemaExporterOptions
771778
{
772779
TransformSchemaNode = static (ctx, schema) =>
773780
{
@@ -789,6 +796,7 @@ of the type which points to the first occurrence. */
789796
return jObj;
790797
}
791798
});
799+
#endif
792800

793801
// Collection types
794802
yield return new TestData<int[]>([1, 2, 3], """{"type":["array","null"],"items":{"type":"integer"}}""");
@@ -1292,6 +1300,7 @@ public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions
12921300
[JsonSerializable(typeof(XElement))]
12931301
public partial class TestTypesContext : JsonSerializerContext;
12941302

1303+
#if NET9_0_OR_GREATER
12951304
private static TAttribute? ResolveAttribute<TAttribute>(this JsonSchemaExporterContext ctx)
12961305
where TAttribute : Attribute
12971306
{
@@ -1300,16 +1309,12 @@ public partial class TestTypesContext : JsonSerializerContext;
13001309
// 2. Parameter-level attributes and
13011310
// 3. Type-level attributes.
13021311
return
1303-
#if NET9_0_OR_GREATER || !TESTS_JSON_SCHEMA_EXPORTER_POLYFILL
13041312
GetAttrs(ctx.PropertyInfo?.AttributeProvider) ??
13051313
GetAttrs(ctx.PropertyInfo?.AssociatedParameter?.AttributeProvider) ??
1306-
#else
1307-
GetAttrs(ctx.PropertyAttributeProvider) ??
1308-
GetAttrs(ctx.ParameterInfo) ??
1309-
#endif
13101314
GetAttrs(ctx.TypeInfo.Type);
13111315

13121316
static TAttribute? GetAttrs(ICustomAttributeProvider? provider) =>
13131317
(TAttribute?)provider?.GetCustomAttributes(typeof(TAttribute), inherit: false).FirstOrDefault();
13141318
}
1319+
#endif
13151320
}

0 commit comments

Comments
 (0)