diff --git a/Directory.Packages.props b/Directory.Packages.props index 412780b628..05ded62687 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -51,6 +51,9 @@ + + + diff --git a/Microsoft.Testing.Platform.slnf b/Microsoft.Testing.Platform.slnf index d29d82d5b1..8508da1581 100644 --- a/Microsoft.Testing.Platform.slnf +++ b/Microsoft.Testing.Platform.slnf @@ -4,6 +4,7 @@ "projects": [ "samples\\Playground\\Playground.csproj", "src\\Platform\\Microsoft.Testing.Extensions.AzureDevOpsReport\\Microsoft.Testing.Extensions.AzureDevOpsReport.csproj", + "src\\Platform\\Microsoft.Testing.Extensions.AzureFoundry\\Microsoft.Testing.Extensions.AzureFoundry.csproj", "src\\Platform\\Microsoft.Testing.Extensions.CrashDump\\Microsoft.Testing.Extensions.CrashDump.csproj", "src\\Platform\\Microsoft.Testing.Extensions.HangDump\\Microsoft.Testing.Extensions.HangDump.csproj", "src\\Platform\\Microsoft.Testing.Extensions.HotReload\\Microsoft.Testing.Extensions.HotReload.csproj", @@ -13,6 +14,7 @@ "src\\Platform\\Microsoft.Testing.Extensions.TrxReport.Abstractions\\Microsoft.Testing.Extensions.TrxReport.Abstractions.csproj", "src\\Platform\\Microsoft.Testing.Extensions.TrxReport\\Microsoft.Testing.Extensions.TrxReport.csproj", "src\\Platform\\Microsoft.Testing.Extensions.VSTestBridge\\Microsoft.Testing.Extensions.VSTestBridge.csproj", + "src\\Platform\\Microsoft.Testing.Platform.AI\\Microsoft.Testing.Platform.AI.csproj", "src\\Platform\\Microsoft.Testing.Platform.MSBuild\\Microsoft.Testing.Platform.MSBuild.csproj", "src\\Platform\\Microsoft.Testing.Platform\\Microsoft.Testing.Platform.csproj", "test\\IntegrationTests\\Microsoft.Testing.Platform.Acceptance.IntegrationTests\\Microsoft.Testing.Platform.Acceptance.IntegrationTests.csproj", diff --git a/TestFx.slnx b/TestFx.slnx index 321210072b..6b71a7412a 100644 --- a/TestFx.slnx +++ b/TestFx.slnx @@ -12,7 +12,7 @@ - + @@ -23,7 +23,7 @@ - + @@ -31,8 +31,9 @@ - + + @@ -43,19 +44,20 @@ + - + - + - + @@ -64,7 +66,7 @@ - + @@ -73,14 +75,14 @@ - + - + @@ -110,15 +112,15 @@ - + - + - + diff --git a/docs/microsoft.testing.platform/001-AI-Extensibility.md b/docs/microsoft.testing.platform/001-AI-Extensibility.md new file mode 100644 index 0000000000..a666410881 --- /dev/null +++ b/docs/microsoft.testing.platform/001-AI-Extensibility.md @@ -0,0 +1,298 @@ +# RFC 001 - AI-Powered Extensibility for Testing Platform + +- [ ] Approved in principle +- [ ] Under discussion +- [ ] Implementation +- [ ] Shipped + +## Summary + +This RFC details the Microsoft.Testing.Platform extensibility model for integrating Large Language Models (LLMs) and AI capabilities into test frameworks and extensions. The goal is to provide a standardized way for any extensibility point in the testing platform to leverage AI for intelligent testing activities such as flaky test analysis, crash dump analysis, hang analysis, test failure root cause analysis, and more. + +## Motivation + +Modern testing scenarios increasingly benefit from AI-powered analysis and automation. Various testing extensibility points could leverage LLMs to provide intelligent insights: + +1. **Test Frameworks** - Analyze flaky tests, suggest test improvements, generate test cases, analyze test failures for root causes +2. **Crash Dump Extensions** - Automatically analyze crash dumps to identify root causes, stack trace analysis, memory corruption detection +3. **Hang Analysis Extensions** - Analyze hanging processes, identify deadlocks, suggest fixes +4. **Code Coverage Extensions** - Suggest areas needing more test coverage, identify critical untested paths +5. **Performance Extensions** - Analyze performance regressions, suggest optimizations +6. **Test Result Extensions** - Summarize test results, identify patterns in failures + +However, each extension implementing its own AI integration would lead to: + +- **Duplication** - Multiple extensions reimplementing the same AI client initialization logic +- **Inconsistency** - Different configuration patterns across extensions +- **Complexity** - Users having to configure AI settings multiple times for different extensions +- **Limited Flexibility** - Difficulty in switching between different AI providers (Azure OpenAI, OpenAI, local models, etc.) + +The platform needs a unified, extensible approach to AI integration that allows extensions to access AI capabilities in a standardized way. + +## Detailed Design + +### Requirements + +1. Extensions should be able to access AI chat clients without implementing provider-specific logic +2. The platform should support multiple AI providers (Azure OpenAI, OpenAI, local models, etc.) +3. Only one AI provider should be active at a time to avoid conflicts and unnecessary resource consumption +4. AI provider availability should be detectable at runtime (e.g., if required environment variables are missing) +5. Extensions should be able to determine if the AI provider supports advanced features like tool calling +6. The design should leverage existing industry-standard abstractions (Microsoft.Extensions.AI) +7. Configuration should be simple and consistent across all extensions + +### Proposed Solution + +The solution introduces a **Chat Client Provider** abstraction that allows AI providers to be registered with the testing platform and consumed by any extension. + +#### Core Components + +##### 1. IChatClientProvider Interface + +This interface defines the contract for AI provider implementations: + +```csharp +namespace Microsoft.Testing.Platform.AI; + +public interface IChatClientProvider +{ + /// + /// Gets a value indicating whether the provider is available and can be used. + /// A provider may be registered but not available if required configuration + /// (e.g., environment variables) is missing. + /// + bool IsAvailable { get; } + + /// + /// Gets a value indicating whether the chat client has tool capability + /// (e.g., MCP tools or functions). + /// + bool HasToolsCapability { get; } + + /// + /// Gets the name of the model being used by the chat client. + /// + string ModelName { get; } + + /// + /// Creates a new instance of IChatClient. + /// + Task CreateChatClientAsync(CancellationToken cancellationToken); +} +``` + +**Design Decisions:** + +- Uses `Microsoft.Extensions.AI.IChatClient` as the return type, leveraging the industry-standard abstraction +- `IsAvailable` allows providers to validate configuration before being used +- `HasToolsCapability` enables extensions to use advanced features when available +- `ModelName` provides transparency about which AI model is being used + +##### 2. ChatClientManager (Internal) + +The platform includes an internal manager that handles provider registration: + +```csharp +internal interface IChatClientManager +{ + void SetChatClientProviderFactory(Func chatClientProviderFactory); + void InstantiateChatClientProvider(ServiceProvider serviceProvider); +} +``` + +**Design Decisions:** + +- `SetChatClientProviderFactory`: Stores the factory function that will create the provider instance +- `InstantiateChatClientProvider`: Invokes the factory function and registers the provider instance to the service provider +- Only one provider can be registered at a time (enforced with an exception) +- Provider registration is deferred until the service provider is fully built +- The manager integrates with the existing platform service provider pattern + +##### 3. Extension Methods for Registration + +Test application builders can register AI providers using extension methods: + +```csharp +namespace Microsoft.Testing.Platform.AI; + +public static class ChatClientProviderExtensions +{ + /// + /// Adds a chat client provider to the test application builder. + /// + public static void AddChatClientProvider( + this ITestApplicationBuilder testApplicationBuilder, + Func chatClientProvider); + + /// + /// Gets a chat client from the service provider. + /// + public static async Task GetChatClientAsync( + this IServiceProvider serviceProvider, + CancellationToken cancellationToken); +} +``` + +**Design Decisions:** + +- `AddChatClientProvider` follows the platform's existing builder pattern +- `GetChatClientAsync` provides a simple way for extensions to access the chat client +- Returns `null` if no provider is registered, allowing graceful degradation + +##### 4. Reference Implementation - Azure OpenAI Provider + +The platform includes a reference implementation for Azure OpenAI: + +```csharp +namespace Microsoft.Testing.Extensions.AzureFoundry; + +public static class TestApplicationBuilderExtensions +{ + public static void AddAzureOpenAIChatClientProvider( + this ITestApplicationBuilder testApplicationBuilder) + => testApplicationBuilder.AddChatClientProvider( + sp => new AzureOpenAIChatClientProvider(sp)); +} +``` + +The Azure OpenAI provider: + +- Reads configuration from environment variables (`AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_DEPLOYMENT_NAME`, `AZURE_OPENAI_API_KEY`) +- Validates availability based on configuration presence +- Supports tool calling +- Uses the official Azure OpenAI SDK + +### Usage Example + +#### Test Framework with Flaky Test Analysis + +```csharp +public class MyTestFramework : ITestFramework +{ + private readonly IServiceProvider _serviceProvider; + + public async Task ExecuteRequestAsync(ExecuteRequestContext context) + { + // Execute tests + var results = await ExecuteTestsAsync(context); + + // Analyze flaky tests using AI + IChatClientProvider? provider = _serviceProvider + .GetServiceInternal(); + + if (provider?.IsAvailable == true) + { + IChatClient chatClient = await provider + .CreateChatClientAsync(context.CancellationToken); + + var flakyTests = results.Where(r => r.IsFlaky); + if (flakyTests.Any()) + { + var analysis = await AnalyzeFlakyTestsAsync( + chatClient, + flakyTests, + context.CancellationToken); + + // Report analysis + await ReportFlakyAnalysisAsync(analysis); + } + } + } + + private async Task AnalyzeFlakyTestsAsync( + IChatClient chatClient, + IEnumerable flakyTests, + CancellationToken cancellationToken) + { + var prompt = $""" + Analyze these flaky tests and suggest potential root causes: + {string.Join("\n", flakyTests.Select(t => t.ToString()))} + """; + + var response = await chatClient.GetResponseAsync( + prompt, + cancellationToken: cancellationToken); + + return response.Text; + } +} +``` + +### Benefits + +#### For Extension Authors + +1. **No AI-specific infrastructure** - Extensions only need to call `GetChatClientAsync()` and use the standard `IChatClient` interface +2. **Works with any provider** - Extension works automatically with Azure OpenAI, OpenAI, local models, or any custom provider +3. **Graceful degradation** - Extension can detect when AI is unavailable and skip AI-powered features +4. **Feature detection** - Extensions can check `SupportsToolCalling` and use advanced features when available + +#### For Test Authors + +1. **Single configuration point** - Configure AI provider once, all extensions use it +2. **Easy provider switching** - Change from Azure OpenAI to OpenAI by swapping one line +3. **Clear availability** - Know which features are available based on configuration +4. **Consistent experience** - All AI-powered features use the same underlying provider + +#### For the Ecosystem + +1. **Reusable providers** - AI providers can be packaged and shared as NuGet packages +2. **Standardization** - All extensions follow the same AI integration pattern +3. **Interoperability** - Leverages `Microsoft.Extensions.AI` for broad ecosystem compatibility +4. **Extensibility** - New providers can be added without changing existing extensions + +### Integration with Testing Platform + +The AI provider is registered during test host initialization: + +```csharp +// In TestHostBuilder.BuildAsync() +public async Task BuildAsync() +{ + // ... existing initialization ... + + // Register AI provider if configured + ChatClientManager.RegisterChatClientProvider(serviceProvider); + + // ... continue with normal flow ... +} +``` + +This ensures: + +- The provider is available when any extension needs it +- Registration happens after all services are configured +- The service provider pattern is consistent with the rest of the platform + +## Architecture: Keeping the Core Platform Dependency-Free + +A critical design principle of this feature is maintaining the independence of the core `Microsoft.Testing.Platform` library. The platform serves as the foundational pillar for the entire ecosystem and must remain lightweight and free from external dependencies. + +### Separation of Concerns + +The AI extensibility is implemented through a separate `Microsoft.Testing.Platform.AI` library that acts as a bridge between: + +1. **AI Provider Implementations** - Concrete implementations like `Microsoft.Testing.Extensions.AzureFoundry` that integrate with specific AI services +2. **Core Platform Service Provider** - The platform's service provider mechanism that makes services available to extensions + +This architectural separation provides several key benefits: + +**For the Core Platform:** + +- `Microsoft.Testing.Platform` remains dependency-free and does not reference AI-related packages like `Microsoft.Extensions.AI` +- The core platform stays lean, fast to load, and suitable for all testing scenarios (including those that don't need AI) +- No breaking changes or version conflicts from AI SDK updates + +**For AI Capabilities:** + +- The `Microsoft.Testing.Platform.AI` library defines the public contract (`IChatClientProvider`) without coupling to specific AI implementations +- Extensions can opt-in to AI capabilities by referencing only the packages they need +- Provider implementations (e.g., Azure OpenAI, OpenAI, local models) can evolve independently + +**For the Integration:** + +- Internal management components in the core platform (`ChatClientManager`) handle provider registration +- The AI library bridges provider implementations to the service provider +- Extensions receive a fully configured `IChatClient` through the standard service provider pattern + +This design ensures that the core testing platform remains a stable, dependency-free foundation while enabling rich AI-powered extensibility for those who need it. diff --git a/samples/Playground/Playground.csproj b/samples/Playground/Playground.csproj index ba8afed52d..c7d96bb63d 100644 --- a/samples/Playground/Playground.csproj +++ b/samples/Playground/Playground.csproj @@ -21,6 +21,8 @@ + + diff --git a/samples/Playground/Program.cs b/samples/Playground/Program.cs index 8e12c8794c..fca420c9ec 100644 --- a/samples/Playground/Program.cs +++ b/samples/Playground/Program.cs @@ -8,8 +8,14 @@ using Microsoft.Testing.Platform.Messages; #if NETCOREAPP using Microsoft.Testing.Platform.ServerMode.IntegrationTests.Messages.V100; + using MSTest.Acceptance.IntegrationTests.Messages.V100; + #endif +using Microsoft.Extensions.AI; +using Microsoft.Testing.Extensions.AzureFoundry; +using Microsoft.Testing.Platform.AI; +using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.TestHost; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -34,8 +40,11 @@ public static async Task Main(string[] args) // Test MSTest testApplicationBuilder.AddMSTest(() => [Assembly.GetEntryAssembly()!]); + // Add Chat client provider + // testApplicationBuilder.AddAzureOpenAIChatClientProvider(); + // Test a custom local test framework - // testApplicationBuilder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, _) => new DummyAdapter()); + // testApplicationBuilder.RegisterTestFramework(_ => new TestFrameworkCapabilities(), (_, s) => new DummyAdapter(s)); // Custom test host controller extension // testApplicationBuilder.TestHostControllers.AddProcessLifetimeHandler(s => new OutOfProc(s.GetMessageBus())); @@ -69,15 +78,19 @@ public static async Task Main(string[] args) await runRequest.WaitCompletionAsync(); await client.ExitAsync(); - - return 0; #endif } + + return 0; } } internal sealed class DummyAdapter : ITestFramework, IDataProducer { + private readonly IServiceProvider _serviceProvider; + + public DummyAdapter(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; + public string Uid => nameof(DummyAdapter); public string Version => string.Empty; @@ -96,6 +109,12 @@ public async Task ExecuteRequestAsync(ExecuteRequestContext context) { try { + IChatClient? chatClient = await _serviceProvider.GetChatClientAsync(context.CancellationToken); + if (chatClient != null) + { + ChatResponse response = await chatClient.GetResponseAsync(chatMessage: "Hello, world!", cancellationToken: context.CancellationToken); + } + MyService.DoSomething(); } catch (Exception e) diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj new file mode 100644 index 0000000000..e8626e6050 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Microsoft.Testing.Extensions.AzureFoundry.csproj @@ -0,0 +1,32 @@ + + + + netstandard2.0;$(SupportedNetFrameworks) + false + + + + + + + true + buildMultiTargeting + + + buildTransitive/$(TargetFramework) + + + build/$(TargetFramework) + + + + + + + + + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/OpenAIChatClientProvider.cs b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/OpenAIChatClientProvider.cs new file mode 100644 index 0000000000..b1984c7328 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/OpenAIChatClientProvider.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ClientModel; + +using Azure.AI.OpenAI; + +using Microsoft.Extensions.AI; +using Microsoft.Testing.Extensions.AzureFoundry.Resources; +using Microsoft.Testing.Platform; +using Microsoft.Testing.Platform.AI; +using Microsoft.Testing.Platform.Helpers; + +namespace Microsoft.Testing.Extensions.AzureFoundry; + +/// +/// Provider for creating Azure OpenAI chat clients. +/// +internal sealed class AzureOpenAIChatClientProvider : IChatClientProvider +{ + private readonly IEnvironment _environment; + + /// + /// Initializes a new instance of the class. + /// + /// The environment service. + internal AzureOpenAIChatClientProvider(IEnvironment environment) + => _environment = environment; + + /// + public bool IsAvailable => + !RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")) && + !RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME")) && + !RoslynString.IsNullOrEmpty(_environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY")); + + /// + public bool HasToolsCapability => true; + + /// + public string ModelName => _environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "unknown"; + + /// + public Task CreateChatClientAsync(CancellationToken cancellationToken) + { + string? endpoint = _environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); + string? deploymentName = _environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME"); + string? apiKey = _environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY"); + + if (RoslynString.IsNullOrEmpty(endpoint)) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.EnvironmentVariableNotSet, "AZURE_OPENAI_ENDPOINT")); + } + + if (RoslynString.IsNullOrEmpty(deploymentName)) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.EnvironmentVariableNotSet, "AZURE_OPENAI_DEPLOYMENT_NAME")); + } + + if (RoslynString.IsNullOrEmpty(apiKey)) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, ExtensionResources.EnvironmentVariableNotSet, "AZURE_OPENAI_API_KEY")); + } + + var client = new AzureOpenAIClient( + new Uri(endpoint!), + new ApiKeyCredential(apiKey!)); + + return Task.FromResult(client.GetChatClient(deploymentName).AsIChatClient()); + } +} diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/ExtensionResources.resx b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/ExtensionResources.resx new file mode 100644 index 0000000000..dc0946744c --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/ExtensionResources.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Environment variable '{0}' is not set. + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.cs.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.cs.xlf new file mode 100644 index 0000000000..011d21eeda --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.cs.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.de.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.de.xlf new file mode 100644 index 0000000000..ee6b892b33 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.de.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.es.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.es.xlf new file mode 100644 index 0000000000..9c84abc121 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.es.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.fr.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.fr.xlf new file mode 100644 index 0000000000..66eb696594 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.fr.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.it.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.it.xlf new file mode 100644 index 0000000000..9854aaa0ad --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.it.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ja.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ja.xlf new file mode 100644 index 0000000000..688eb21768 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ja.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ko.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ko.xlf new file mode 100644 index 0000000000..cf11a6f7ac --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ko.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.pl.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.pl.xlf new file mode 100644 index 0000000000..3134982c18 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.pl.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.pt-BR.xlf new file mode 100644 index 0000000000..cb0d7edb69 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.pt-BR.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ru.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ru.xlf new file mode 100644 index 0000000000..05e9d1acbb --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.ru.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.tr.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.tr.xlf new file mode 100644 index 0000000000..df3e59afe4 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.tr.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.zh-Hans.xlf new file mode 100644 index 0000000000..3249d41d04 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.zh-Hans.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.zh-Hant.xlf new file mode 100644 index 0000000000..454168beac --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/Resources/xlf/ExtensionResources.zh-Hant.xlf @@ -0,0 +1,12 @@ + + + + + + Environment variable '{0}' is not set. + Environment variable '{0}' is not set. + + + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/TestApplicationBuilderExtensions.cs b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/TestApplicationBuilderExtensions.cs new file mode 100644 index 0000000000..0e4c65e7d5 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/TestApplicationBuilderExtensions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.AI; +using Microsoft.Testing.Platform.Builder; +using Microsoft.Testing.Platform.Helpers; +using Microsoft.Testing.Platform.Services; + +namespace Microsoft.Testing.Extensions.AzureFoundry; + +/// +/// Extension methods for configuring Azure Foundry services. +/// +public static class TestApplicationBuilderExtensions +{ + /// + /// Adds the Azure OpenAI chat client provider to the test application. + /// + /// The test application builder. + public static void AddAzureOpenAIChatClientProvider(this ITestApplicationBuilder testApplicationBuilder) + => testApplicationBuilder.AddChatClientProvider(sp => new AzureOpenAIChatClientProvider(sp.GetRequiredService())); +} diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/TestingPlatformBuilderHook.cs b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/TestingPlatformBuilderHook.cs new file mode 100644 index 0000000000..9122137a8b --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/TestingPlatformBuilderHook.cs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Builder; + +namespace Microsoft.Testing.Extensions.AzureFoundry; + +/// +/// This class is used by Microsoft.Testing.Platform.MSBuild to hook into the Testing Platform Builder to add Azure Foundry AI support. +/// +public static class TestingPlatformBuilderHook +{ + /// + /// Adds Azure Foundry AI support to the Testing Platform Builder. + /// + /// The test application builder. + /// The command line arguments. + public static void AddExtensions(ITestApplicationBuilder testApplicationBuilder, string[] _) + => testApplicationBuilder.AddAzureOpenAIChatClientProvider(); +} diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/build/Microsoft.Testing.Extensions.AzureFoundry.props b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/build/Microsoft.Testing.Extensions.AzureFoundry.props new file mode 100644 index 0000000000..de499ce943 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/build/Microsoft.Testing.Extensions.AzureFoundry.props @@ -0,0 +1,3 @@ + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/buildMultiTargeting/Microsoft.Testing.Extensions.AzureFoundry.props b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/buildMultiTargeting/Microsoft.Testing.Extensions.AzureFoundry.props new file mode 100644 index 0000000000..b3dbed5c82 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/buildMultiTargeting/Microsoft.Testing.Extensions.AzureFoundry.props @@ -0,0 +1,9 @@ + + + + + Microsoft.Testing.Extensions.AzureFoundry + Microsoft.Testing.Extensions.AzureFoundry.TestingPlatformBuilderHook + + + diff --git a/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/buildTransitive/Microsoft.Testing.Extensions.AzureFoundry.props b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/buildTransitive/Microsoft.Testing.Extensions.AzureFoundry.props new file mode 100644 index 0000000000..de499ce943 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Extensions.AzureFoundry/buildTransitive/Microsoft.Testing.Extensions.AzureFoundry.props @@ -0,0 +1,3 @@ + + + diff --git a/src/Platform/Microsoft.Testing.Platform.AI/ChatClientProviderExtensions.cs b/src/Platform/Microsoft.Testing.Platform.AI/ChatClientProviderExtensions.cs new file mode 100644 index 0000000000..32b63732d1 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform.AI/ChatClientProviderExtensions.cs @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Extensions.AI; +using Microsoft.Testing.Platform.Builder; +using Microsoft.Testing.Platform.Resources; +using Microsoft.Testing.Platform.Services; + +namespace Microsoft.Testing.Platform.AI; + +/// +/// Extension methods for chat client provider. +/// +public static class ChatClientProviderExtensions +{ + /// + /// Adds a chat client provider to the test application builder. + /// + /// The test application builder. + /// The factory function to create chat client providers. + public static void AddChatClientProvider(this ITestApplicationBuilder testApplicationBuilder, Func chatClientProvider) + { + if (testApplicationBuilder is not TestApplicationBuilder builder) + { + throw new InvalidOperationException(PlatformResources.InvalidTestApplicationBuilderTypeForAI); + } + + builder.ChatClientManager.AddChatClientProvider(chatClientProvider); + } + + /// + /// Gets a chat client from the service provider. + /// + /// The service provider. + /// The cancellation token. + /// A task representing the asynchronous operation that returns an instance of . + public static async Task GetChatClientAsync(this IServiceProvider serviceProvider, CancellationToken cancellationToken) + { + IChatClientProvider? provider = serviceProvider.GetServiceInternal(); + return provider is null + ? null + : await provider.CreateChatClientAsync(cancellationToken).ConfigureAwait(false); + } +} diff --git a/src/Platform/Microsoft.Testing.Platform.AI/IChatClientProvider.cs b/src/Platform/Microsoft.Testing.Platform.AI/IChatClientProvider.cs new file mode 100644 index 0000000000..72b766f9f9 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform.AI/IChatClientProvider.cs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Extensions.AI; + +namespace Microsoft.Testing.Platform.AI; + +/// +/// Provider interface for creating and configuring chat clients. +/// +[Experimental("TPEXP", UrlFormat = "https://aka.ms/testingplatform/experimental")] +public interface IChatClientProvider +{ + /// + /// Gets a value indicating whether the provider is available and can be used. + /// A provider may be registered but not available if required configuration (e.g., environment variables) is missing. + /// + bool IsAvailable { get; } + + /// + /// Gets a value indicating whether the chat client has tool capability (e.g., MCP tools or functions). + /// + bool HasToolsCapability { get; } + + /// + /// Gets the name of the model being used by the chat client. + /// + string ModelName { get; } + + /// + /// Creates a new instance of . + /// + /// The cancellation token. + /// A task representing the asynchronous operation that returns an instance of . + Task CreateChatClientAsync(CancellationToken cancellationToken); +} diff --git a/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj b/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj new file mode 100644 index 0000000000..fbf171f863 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform.AI/Microsoft.Testing.Platform.AI.csproj @@ -0,0 +1,17 @@ + + + + $(SupportedNetFrameworks);netstandard2.0 + false + + + + + + + + + + + + diff --git a/src/Platform/Microsoft.Testing.Platform/AI/ChatClientManager.cs b/src/Platform/Microsoft.Testing.Platform/AI/ChatClientManager.cs new file mode 100644 index 0000000000..1d0810da42 --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/AI/ChatClientManager.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Resources; +using Microsoft.Testing.Platform.Services; + +namespace Microsoft.Testing.Platform.AI; + +internal sealed class ChatClientManager : IChatClientManager +{ + private Func? _chatClientProviderFactory; + + public void AddChatClientProvider(Func chatClientProviderFactory) + { + if (chatClientProviderFactory is null) + { + throw new ArgumentNullException(nameof(chatClientProviderFactory)); + } + + if (_chatClientProviderFactory is not null) + { + throw new InvalidOperationException(PlatformResources.ChatClientProviderAlreadyRegistered); + } + + _chatClientProviderFactory = chatClientProviderFactory; + } + + public void BuildChatClients(ServiceProvider serviceProvider) + { + if (_chatClientProviderFactory is not null) + { + serviceProvider.AddService(_chatClientProviderFactory(serviceProvider)); + } + } +} diff --git a/src/Platform/Microsoft.Testing.Platform/AI/IChatClientManager.cs b/src/Platform/Microsoft.Testing.Platform/AI/IChatClientManager.cs new file mode 100644 index 0000000000..5e2e09dd2c --- /dev/null +++ b/src/Platform/Microsoft.Testing.Platform/AI/IChatClientManager.cs @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Testing.Platform.Services; + +namespace Microsoft.Testing.Platform.AI; + +internal interface IChatClientManager +{ + void AddChatClientProvider(Func chatClientProviderFactory); + + void BuildChatClients(ServiceProvider serviceProvider); +} diff --git a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs index 77aadd626b..9701dcd041 100644 --- a/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Builder/TestApplicationBuilder.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Testing.Internal.Framework; +using Microsoft.Testing.Platform.AI; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.CommandLine; using Microsoft.Testing.Platform.Configurations; @@ -46,6 +47,8 @@ internal TestApplicationBuilder( _unhandledExceptionsHandler = unhandledExceptionsHandler; } + public IChatClientManager ChatClientManager => _testHostBuilder.ChatClientManager; + public ITestHostManager TestHost => _testHostBuilder.TestHost; public ITestHostControllersManager TestHostControllers => _testHostBuilder.TestHostControllers; diff --git a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs index 76e68664cc..1add332506 100644 --- a/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs +++ b/src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using Microsoft.Testing.Internal.Framework; +using Microsoft.Testing.Platform.AI; using Microsoft.Testing.Platform.Builder; using Microsoft.Testing.Platform.Capabilities.TestFramework; using Microsoft.Testing.Platform.CommandLine; @@ -34,6 +35,8 @@ internal sealed class TestHostBuilder(IFileSystem fileSystem, IRuntimeFeature ru private readonly ITestApplicationModuleInfo _testApplicationModuleInfo = testApplicationModuleInfo; private readonly PlatformOutputDeviceManager _outputDisplay = new(); + public IChatClientManager ChatClientManager { get; } = new ChatClientManager(); + public ITestFrameworkManager? TestFramework { get; set; } public ITestHostManager TestHost { get; } = new TestHostManager(); @@ -310,6 +313,9 @@ public async Task BuildAsync( policiesService); serviceProvider.AddService(testApplicationResult); + // Add Chat Client if AI capabilities are enabled + ChatClientManager.BuildChatClients(serviceProvider); + // ============= SETUP COMMON SERVICE USED IN ALL MODES END ===============// // ============= SELECT AND RUN THE ACTUAL MODE ===============// diff --git a/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj b/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj index 67deb6020c..2fde16409a 100644 --- a/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj +++ b/src/Platform/Microsoft.Testing.Platform/Microsoft.Testing.Platform.csproj @@ -39,6 +39,7 @@ This package provides the core platform and the .NET implementation of the proto + @@ -52,6 +53,7 @@ This package provides the core platform and the .NET implementation of the proto + diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx index 5b7a17db4f..87f9857b19 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx +++ b/src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resx @@ -1,17 +1,17 @@  - @@ -501,12 +501,12 @@ Read more about Microsoft Testing Platform telemetry: https://aka.ms/testingplat Diagnostic file (level '{0}' with async flush): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -725,4 +725,10 @@ Takes one argument as string in the format <value>[h|m|s] where 'value' is succeeded + + A chat client provider has already been registered. + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf index 70924b66dc..79c7549bdb 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Diagnostický soubor (úroveň {0} s asynchronním vyprázdněním): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Diagnostický soubor (úroveň {0} se synchronním vyprázdněním): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Platné hodnoty jsou Normal a Detailed. Výchozí hodnota je Normal. celkem + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf index c314934400..3874906346 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Diagnosedatei (Ebene „{0}“ mit asynchroner Leerung): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Diagnosedatei (Ebene „{0}“ mit synchroner Leerung): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Gültige Werte sind „Normal“, „Detailed“. Der Standardwert ist „Normal gesamt + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf index e7eb6c0850..79344cd8fd 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Archivo de diagnóstico (nivel '{0}' con vaciado asincrónico): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Archivo de diagnóstico (nivel '{0}' con vaciado de sincronización): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Los valores válidos son 'Normal', 'Detallado'. El valor predeterminado es 'Norm total + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf index 9e2b86d912..ba5038494a 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Fichier de diagnostic (niveau « {0} » avec vidage asynchrone) : {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Fichier de diagnostic (niveau « {0} » avec vidage synchrone) : {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Les valeurs valides sont « Normal » et « Détaillé ». La valeur par dé total + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf index a1093171d7..b77ec4cc29 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} File di diagnostica (livello '{0}' con scaricamento asincrono): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} File di diagnostica (livello '{0}' con scaricamento sincrono): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ I valori validi sono 'Normal', 'Detailed'. L'impostazione predefinita è 'Normal totali + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf index c447e5d6fa..5f7de1e30c 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} 診断ファイル (レベル '{0}' で非同期フラッシュ): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} 診断ファイル (レベル '{0}' で同期フラッシュ): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -781,7 +781,7 @@ Microsoft Testing Platform collects usage data in order to help us improve your You can opt-out of telemetry by setting the TESTINGPLATFORM_TELEMETRY_OPTOUT or DOTNET_CLI_TELEMETRY_OPTOUT environment variable to '1' or 'true' using your favorite shell. Read more about Microsoft Testing Platform telemetry: https://aka.ms/testingplatform/telemetry - テレメトリ + テレメトリ --------- Microsoft Testing Platform は、お客様のエクスペリエンスの向上に役立てるために使用状況データを収集します。データは Microsoft によって収集され、誰とも共有されません。 テレメトリをオプトアウトするには、お気に入りのシェルを使用して、TESTINGPLATFORM_TELEMETRY_OPTOUT または DOTNET_CLI_TELEMETRY_OPTOUT 環境変数を '1' または 'true' に設定します。 @@ -993,6 +993,16 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 合計 + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf index 7c926166b9..03cdd9e6dd 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} 진단 파일(비동기 플러시를 사용한 수준 '{0}'): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} 진단 파일(동기 플러시를 사용한 수준 '{0}'): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 합계 + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf index d2a1dea339..34ba8e7bb7 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Plik diagnostyczny (poziom „{0}” z asynchronicznym opróżnianiem): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Plik diagnostyczny (poziom „{0}” z synchronicznym opróżnianiem): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Prawidłowe wartości to „Normalne”, „Szczegółowe”. Wartość domyśln łącznie + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf index c9c6afeaa8..24906f1693 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Arquivo de diagnóstico (nível "{0}" com liberação assíncrona): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Arquivo de diagnóstico (nível "{0}" com liberação de sincronização): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -505,7 +505,7 @@ O arquivo será gravado no diretório de saída com o nome log_[yyMMddHHmmssfff] Output directory of the diagnostic logging. If not specified the file will be generated inside the default 'TestResults' directory. - Diretório de saída do log de eventos de diagnóstico + Diretório de saída do log de eventos de diagnóstico Se não for especificado, o arquivo será gerado dentro do diretório padrão “TestResults”. @@ -806,7 +806,7 @@ Leia mais sobre a telemetria da Plataforma de Testes da Microsoft: https://aka.m Output verbosity when reporting tests. Valid values are 'Normal', 'Detailed'. Default is 'Normal'. - Detalhamento da saída ao relatar testes + Detalhamento da saída ao relatar testes Os valores válidos são “Normal”, “Detalhado”. O padrão é “Normal”. @@ -992,6 +992,16 @@ Os valores válidos são “Normal”, “Detalhado”. O padrão é “Normal total + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf index 14fae5b4cf..6e4713c34e 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Файл диагностики (уровень '{0}' асинхронной очисткой): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Файл диагностики (уровень '{0}' синхронизации на диск): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. всего + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf index 54941e803f..63d0ac215f 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} Tanılama dosyası (zaman uyumsuz boşaltma ile düzey '{0}'): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} Tanılama dosyası (zaman uyumlu boşaltma ile düzey '{0}' ): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -992,6 +992,16 @@ Geçerli değerler: ‘Normal’, ‘Ayrıntılı’. Varsayılan değer: ‘Nor toplam + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf index 9eb39457bb..95ea9f1ef4 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} 诊断文件(具有异步刷新的级别“{0}”): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} 诊断文件(具有同步刷新的级别“{0}”): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -272,7 +272,7 @@ Failed to write the log to the channel. Missed log content: {0} - 无法将日志写入通道。遗漏的日志内容: + 无法将日志写入通道。遗漏的日志内容: {0} @@ -992,6 +992,16 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 总计 + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file diff --git a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf index a1d5c14cb9..bd002ff47f 100644 --- a/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf +++ b/src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlf @@ -205,13 +205,13 @@ Diagnostic file (level '{0}' with async flush): {1} 診斷檔案 (具有非同步排清的層級 '{0}'): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file Diagnostic file (level '{0}' with sync flush): {1} 診斷檔案 (具有同步排清的層級 '{0}'): {1} - 0 level such as verbose, + 0 level such as verbose, 1 path to file @@ -588,7 +588,7 @@ The available values are 'Trace', 'Debug', 'Information', 'Warning', 'Error', an '--minimum-expected-tests' expects a single non-zero positive integer value (e.g. '--minimum-expected-tests 10') - '--minimum-expected-tests' 需要單一非零的正整數值 + '--minimum-expected-tests' 需要單一非零的正整數值 (例如 '--minimum-expected-tests 10') @@ -992,6 +992,16 @@ Valid values are 'Normal', 'Detailed'. Default is 'Normal'. 總計 + + A chat client provider has already been registered. + A chat client provider has already been registered. + + + + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + AI extensions only work with builders of type 'Microsoft.Testing.Platform.Builder.TestApplicationBuilder' + + \ No newline at end of file