Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cf0266a
Add MEAI.Evaluation libraries
shyamnamboodiripad Jan 23, 2025
39638f8
Adapt to IChatClient renames
stephentoub Feb 11, 2025
71cda8d
Add docs to test configuration script.
peterwald Feb 11, 2025
1444c71
Version and build the Azure DevOps extension
peterwald Feb 11, 2025
8a28d07
Feedback: Use better overload
shyamnamboodiripad Feb 11, 2025
85af81a
Remove Microsoft.Bcl.Memory dependency since its no longer required
shyamnamboodiripad Feb 12, 2025
850acf4
Feedback: Audit and remove redundant cancellationToken.ThrowIfCancell…
shyamnamboodiripad Feb 12, 2025
63a5163
Feedback: Simplify null checks
shyamnamboodiripad Feb 12, 2025
c8aa7a7
Feedback: Simplify type declaration
shyamnamboodiripad Feb 12, 2025
a7ddf47
Add missing sealed modifier
shyamnamboodiripad Feb 12, 2025
e563454
Feedback: Simplify substring search
shyamnamboodiripad Feb 12, 2025
2752ac5
Feedback: Avoid allocating intermediate string
shyamnamboodiripad Feb 12, 2025
a71fa1b
Feedback: Simplify initialization
shyamnamboodiripad Feb 12, 2025
eaeb44c
Feedback: Simplify empty collection usage
shyamnamboodiripad Feb 12, 2025
c6b7401
Feedback: Use Dictionary.TryAdd on .NET Core
shyamnamboodiripad Feb 12, 2025
c1f7caa
Feedback: Use Task.WhenEach on .NET 9
shyamnamboodiripad Feb 12, 2025
b7c0c9d
Suppress API compat validation
shyamnamboodiripad Feb 12, 2025
59e6721
Fix some typos
shyamnamboodiripad Feb 12, 2025
025a79a
Feedback: Use WithCancellation
shyamnamboodiripad Feb 12, 2025
0a6ef14
Remove SuppressFinalPackageVersion
shyamnamboodiripad Feb 12, 2025
8ccb695
Feedback: Suppress async warning as opposed to adding empty awaits
shyamnamboodiripad Feb 12, 2025
29bd92f
Feedback: Explicitly turn on asynchronous I/O on streams
shyamnamboodiripad Feb 12, 2025
485699c
Feedback: Convert field to property
shyamnamboodiripad Feb 12, 2025
2b3be06
Feedback: Convert readonly fileds to properties
shyamnamboodiripad Feb 12, 2025
9539fb5
Rremove some stale comments
shyamnamboodiripad Feb 12, 2025
ea8b7a7
Add some comments to capture follow up tasks for feedback
shyamnamboodiripad Feb 12, 2025
a178ff5
Use span for CacheEntry Deserialize
peterwald Feb 12, 2025
cce2db6
Merge branch 'shyam-eval' into ado-azdo
peterwald Feb 12, 2025
e083f8f
Stamp azdo package version during C# build.
peterwald Feb 12, 2025
aa27138
Fix the RTC rating serializer.
peterwald Feb 12, 2025
aa5609a
Stamp azdo package version during C# build.
peterwald Feb 12, 2025
091083e
Fix the RTC rating serializer.
peterwald Feb 12, 2025
78e8b76
Update azdo extension build
peterwald Feb 12, 2025
a47f94c
Merge branch 'main' into eval
peterwald Feb 12, 2025
5c0a781
Add issue link.
shyamnamboodiripad Feb 12, 2025
4bf28f1
Fix test configuration script.
peterwald Feb 12, 2025
2e4550e
Merge branch 'eval' of https://github.com/shyamnamboodiripad/extensio…
peterwald Feb 12, 2025
4e9b721
Feedback: Avoid deep recursion
shyamnamboodiripad Feb 12, 2025
f4a5b84
Avoid infinite loops and add tests
shyamnamboodiripad Feb 12, 2025
53a39f5
Rename tests for added clarity
shyamnamboodiripad Feb 12, 2025
4125bf8
Merge branch 'main' into eval
shyamnamboodiripad Feb 12, 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
1 change: 1 addition & 0 deletions eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
Win-x64 is used here because we have picked an arbitrary runtime identifier to flow the version of the latest NETCore.App runtime.
All Runtime.$rid packages should have the same version.
-->
<MicrosoftMLTokenizersVersion>1.0.1</MicrosoftMLTokenizersVersion>
<MicrosoftNETCoreAppRuntimeVersion>$(MicrosoftNETCoreAppRuntimewinx64Version)</MicrosoftNETCoreAppRuntimeVersion>
<!-- Compatibility with VS 17.8/.NET SDK 8.0.1xx -->
<MicrosoftCodeAnalysisVersion>4.8.0</MicrosoftCodeAnalysisVersion>
Expand Down
1 change: 1 addition & 0 deletions eng/packages/General-LTS.props
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(MicrosoftExtensionsHttpLTSVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsLTSVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="$(MicrosoftExtensionsLoggingConfigurationLTSVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsoleLTSVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingLTSVersion)" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="$(MicrosoftExtensionsObjectPoolLTSVersion)" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(MicrosoftExtensionsOptionsConfigurationExtensionsLTSVersion)" />
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 @@ -23,6 +23,7 @@
<PackageVersion Include="Microsoft.Extensions.Http" Version="$(MicrosoftExtensionsHttpVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="$(MicrosoftExtensionsLoggingAbstractionsVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="$(MicrosoftExtensionsLoggingConfigurationVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="$(MicrosoftExtensionsLoggingConsoleVersion)" />
<PackageVersion Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingVersion)" />
<PackageVersion Include="Microsoft.Extensions.ObjectPool" Version="$(MicrosoftExtensionsObjectPoolVersion)" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="$(MicrosoftExtensionsOptionsConfigurationExtensionsVersion)" />
Expand Down
2 changes: 2 additions & 0 deletions eng/packages/General.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<PackageVersion Include="Azure.Storage.Files.DataLake" Version="12.21.0" />
<PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.2" />
<PackageVersion Include="ICSharpCode.Decompiler" Version="8.2.0.7535" />
<PackageVersion Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
Expand All @@ -10,6 +11,7 @@
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageVersion Include="Microsoft.CodeAnalysis" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="$(MicrosoftMLTokenizersVersion)" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="OpenAI" Version="2.2.0-beta.1" />
<PackageVersion Include="Polly" Version="8.4.2" />
Expand Down
3 changes: 2 additions & 1 deletion eng/packages/TestOnly.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<ItemGroup>
<PackageVersion Include="AutoFixture.AutoMoq" Version="4.17.0" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.2.0-beta.1" />
<PackageVersion Include="Azure.Identity" Version="1.13.2" />
<PackageVersion Include="autofixture" Version="4.17.0" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.5" />
<PackageVersion Include="FluentAssertions" Version="6.11.0" />
Expand All @@ -12,7 +13,7 @@
<PackageVersion Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.3" />
<PackageVersion Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="9.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.0" />
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="0.22.0-preview.24378.1" />
<PackageVersion Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="$(MicrosoftMLTokenizersVersion)" />
<PackageVersion Include="Moq.AutoMock" Version="3.1.0" />
<PackageVersion Include="Moq" Version="4.18.4" />
<PackageVersion Include="OpenTelemetry.Exporter.InMemory" Version="1.9.0" />
Expand Down
11 changes: 11 additions & 0 deletions eng/pipelines/templates/BuildAndTest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ parameters:
default: false

steps:
- task: NodeTool@0
displayName: Add NodeJS/npm
inputs:
versionSpec: "20.x"
checkLatest: true

- script: ${{ parameters.buildScript }}
-restore
/bl:${{ parameters.repoLogPath }}/restore.binlog
Expand All @@ -45,6 +51,11 @@ steps:
$(_OfficialBuildIdArgs)
displayName: Build

- ${{ if eq(parameters.isWindows, 'true') }}:
- pwsh: |
$(Build.SourcesDirectory)/src/Libraries/Microsoft.Extensions.AI.Evaluation.Reporting/TypeScript/azure-devops-report/build.ps1 -OutputPath $(Build.ArtifactStagingDirectory)\VSIX
displayName: Build Azure DevOps plugin

- ${{ if ne(parameters.skipTests, 'true') }}:
- script: $(Build.SourcesDirectory)/.dotnet/dotnet dotnet-coverage collect
--settings $(Build.SourcesDirectory)/eng/CodeCoverage.config
Expand Down
3 changes: 2 additions & 1 deletion eng/xunit.runner.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"diagnosticMessages": true,
"longRunningTestSeconds": 300
"longRunningTestSeconds": 300,
"shadowCopy": false
}
65 changes: 65 additions & 0 deletions scripts/ConfigureEvaluationTests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env pwsh

<#
.SYNOPSIS
Configures local repo for online evaluation tests, which use external resources.

.DESCRIPTION
This script copies appsettings files from a location on the developer's machine to the test
project directories so that the tests are configured to connect to external resources. The online
configuration files are gitignore'd and not checked in to the repo.

.PARAMETER Configure
Configure this repo for online evaluation tests, by copying appsettings files from the developer's
machine to this repo.
.PARAMETER Unconfigure
Unconfigure this repo for online evaluation tests, by removing the appsettings files from this repo.
.PARAMETER ConfigRoot
ConfigRoot specifies where to copy the configuration files from. The default is $HOME/.config/dotnet-extensions.
#>

param (
[switch]$Configure=$False,
[switch]$Unconfigure=$False,
[string]$ConfigRoot=$Null
)

Write-Host "$PSScriptRoot"

if ($Configure -and $Unconfigure) {
Write-Error -Message "Cannot specify both -Configure and -Unconfigure"
Exit 1
}

if (!(Test-Path $ConfigRoot)) {
$ConfigRoot = "$HOME/.config/dotnet-extensions"
}

$ProjectRoot = Resolve-Path "$PSScriptRoot/../test/Libraries"
$ReportingConfig = "Microsoft.Extensions.AI.Evaluation.Reporting.Tests/appsettings.local.json"
$IntegrationConfig = "Microsoft.Extensions.AI.Evaluation.Integration.Tests/appsettings.local.json"

if ($Configure) {
if (!(Test-Path -Path "$ConfigRoot/$ReportingConfig")) {
Write-Host "No configuration found at $ConfigRoot/$ReportingConfig"
Exit 0
}
if (!(Test-Path -Path "$ConfigRoot/$IntegrationConfig")) {
Write-Host "No configuration found at $ConfigRoot/$IntegrationConfig"
Exit 0
}

Copy-Item -Path "$ConfigRoot/$ReportingConfig" -Destination "$ProjectRoot/$ReportingConfig" -Force
Copy-Item -Path "$ConfigRoot/$IntegrationConfig" -Destination "$ProjectRoot/$IntegrationConfig" -Force

Write-Host "Test configured to use external resources"
} elseif ($Unconfigure) {
Remove-Item -Path "$ProjectRoot/$ReportingConfig" -Force
Remove-Item -Path "$ProjectRoot/$IntegrationConfig" -Force

Write-Host "Test unconfigured from using external resources"
} else {
Write-Error -Message "Must specify either -Configure or -Unconfigure"
Exit 1
}

1 change: 0 additions & 1 deletion src/Libraries/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
<InjectTrimAttributesOnLegacy Condition="'$(InjectTrimAttributesOnLegacy)' == ''">true</InjectTrimAttributesOnLegacy>
<InjectSkipLocalsInitAttributeOnLegacy Condition="'$(InjectSkipLocalsInitAttributeOnLegacy)' == ''">true</InjectSkipLocalsInitAttributeOnLegacy>
<InjectCallerAttributesOnLegacy Condition="'$(InjectCallerAttributesOnLegacy)' == ''">true</InjectCallerAttributesOnLegacy>
<InjectDiagnosticAttributesOnLegacy Condition="'$(InjectDiagnosticAttributesOnLegacy)' == ''">true</InjectDiagnosticAttributesOnLegacy>
<InjectSharedThrow Condition="'$(InjectSharedThrow)' == ''">true</InjectSharedThrow>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI.Evaluation.Console.Utilities;
using Microsoft.Extensions.AI.Evaluation.Reporting.Storage;
using Microsoft.Extensions.Logging;

namespace Microsoft.Extensions.AI.Evaluation.Console.Commands;

internal sealed class CleanCacheCommand(ILogger logger)
{
internal async Task<int> InvokeAsync(DirectoryInfo storageRootDir, CancellationToken cancellationToken = default)
{
string storageRootPath = storageRootDir.FullName;
logger.LogInformation("Storage root path: {storageRootPath}", storageRootPath);
logger.LogInformation("Deleting expired cache entries...");

var cacheProvider = new DiskBasedResponseCacheProvider(storageRootPath);

await logger.ExecuteWithCatchAsync(
() => cacheProvider.DeleteExpiredCacheEntriesAsync(cancellationToken)).ConfigureAwait(false);

return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// 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.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI.Evaluation.Console.Utilities;
using Microsoft.Extensions.AI.Evaluation.Reporting.Storage;
using Microsoft.Extensions.Logging;

namespace Microsoft.Extensions.AI.Evaluation.Console.Commands;

internal sealed class CleanResultsCommand(ILogger logger)
{
internal async Task<int> InvokeAsync(
DirectoryInfo storageRootDir,
int lastN,
CancellationToken cancellationToken = default)
{
string storageRootPath = storageRootDir.FullName;
logger.LogInformation("Storage root path: {storageRootPath}", storageRootPath);

var resultStore = new DiskBasedResultStore(storageRootPath);

await logger.ExecuteWithCatchAsync(
async ValueTask () =>
{
if (lastN is 0)
{
logger.LogInformation("Deleting all results...");

await resultStore.DeleteResultsAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
}
else
{
logger.LogInformation("Deleting all results except the {lastN} most recent ones...", lastN);

HashSet<string> toPreserve = [];

await foreach (string executionName in
resultStore.GetLatestExecutionNamesAsync(lastN, cancellationToken).ConfigureAwait(false))
{
_ = toPreserve.Add(executionName);
}

await foreach (string executionName in
resultStore.GetLatestExecutionNamesAsync(
cancellationToken: cancellationToken).ConfigureAwait(false))
{
if (!toPreserve.Contains(executionName))
{
await resultStore.DeleteResultsAsync(
executionName,
cancellationToken: cancellationToken).ConfigureAwait(false);
}
}
}
}).ConfigureAwait(false);

return 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Extensions.AI.Evaluation.Console.Commands;

internal partial class ReportCommand
{
internal enum Format
{
html,
json
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI.Evaluation.Reporting;
using Microsoft.Extensions.AI.Evaluation.Reporting.Formats.Html;
using Microsoft.Extensions.AI.Evaluation.Reporting.Formats.Json;
using Microsoft.Extensions.AI.Evaluation.Reporting.Storage;
using Microsoft.Extensions.Logging;

namespace Microsoft.Extensions.AI.Evaluation.Console.Commands;

internal sealed partial class ReportCommand(ILogger logger)
{
internal async Task<int> InvokeAsync(
DirectoryInfo storageRootDir,
FileInfo outputFile,
int lastN,
Format format,
CancellationToken cancellationToken = default)
{
string storageRootPath = storageRootDir.FullName;
logger.LogInformation("Storage root path: {storageRootPath}", storageRootPath);

var results = new List<ScenarioRunResult>();
var resultStore = new DiskBasedResultStore(storageRootPath);

await foreach (string executionName in
resultStore.GetLatestExecutionNamesAsync(lastN, cancellationToken).ConfigureAwait(false))
{
await foreach (ScenarioRunResult result in
resultStore.ReadResultsAsync(
executionName,
cancellationToken: cancellationToken).ConfigureAwait(false))
{
results.Add(result);
}
}

string outputFilePath = outputFile.FullName;
string? outputPath = Path.GetDirectoryName(outputFilePath);
if (outputPath is not null && !Directory.Exists(outputPath))
{
_ = Directory.CreateDirectory(outputPath);
}

IEvaluationReportWriter reportWriter = format switch
{
Format.html => new HtmlReportWriter(outputFilePath),
Format.json => new JsonReportWriter(outputFilePath),
_ => throw new NotSupportedException(),
};

await reportWriter.WriteReportAsync(results, cancellationToken).ConfigureAwait(false);
logger.LogInformation("Report: {outputFilePath} [{format}]", outputFilePath, format);

return 0;
}
}
Loading