From a356a165681d0ecd3583250aeff2159820269ce8 Mon Sep 17 00:00:00 2001
From: SergeyMenshykh <68852919+SergeyMenshykh@users.noreply.github.com>
Date: Thu, 2 Apr 2026 14:51:41 +0100
Subject: [PATCH] .NET: Remove OpenAIAssistantClientExtensions class (#5058)
* Remove OpenAIAssistantClientExtensions class
Remove the deprecated OpenAI Assistants API extension methods, along with
their unit tests, integration tests, sample project, and related references.
- Delete OpenAIAssistantClientExtensions.cs (source)
- Delete OpenAIAssistantClientExtensionsTests.cs (unit + integration tests)
- Delete Agent_With_OpenAIAssistants sample project
- Remove sample from solution file, README, and verify-samples definitions
- Remove AIOpenAIAssistants diagnostic ID constant
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* add removed extension methods to the suppression file
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
dotnet/agent-framework-dotnet.slnx | 1 -
dotnet/eng/verify-samples/AgentsSamples.cs | 13 -
.../Agent_With_OpenAIAssistants.csproj | 15 -
.../Agent_With_OpenAIAssistants/Program.cs | 41 -
.../Agent_With_OpenAIAssistants/README.md | 16 -
.../02-agents/AgentProviders/README.md | 1 -
.../CompatibilitySuppressions.xml | 35 +
.../OpenAIAssistantClientExtensions.cs | 433 -------
.../Shared/DiagnosticIds/DiagnosticsIds.cs | 1 -
.../OpenAIAssistantClientExtensionsTests.cs | 1013 -----------------
.../OpenAIAssistantClientExtensionsTests.cs | 268 -----
11 files changed, 35 insertions(+), 1802 deletions(-)
delete mode 100644 dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Agent_With_OpenAIAssistants.csproj
delete mode 100644 dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Program.cs
delete mode 100644 dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/README.md
delete mode 100644 dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs
delete mode 100644 dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs
delete mode 100644 dotnet/tests/OpenAIAssistant.IntegrationTests/OpenAIAssistantClientExtensionsTests.cs
diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx
index 20ea58eaeb..22c37b1d5b 100644
--- a/dotnet/agent-framework-dotnet.slnx
+++ b/dotnet/agent-framework-dotnet.slnx
@@ -34,7 +34,6 @@
-
diff --git a/dotnet/eng/verify-samples/AgentsSamples.cs b/dotnet/eng/verify-samples/AgentsSamples.cs
index 87707a384e..f44dd2f1f6 100644
--- a/dotnet/eng/verify-samples/AgentsSamples.cs
+++ b/dotnet/eng/verify-samples/AgentsSamples.cs
@@ -781,19 +781,6 @@ internal static class AgentsSamples
SkipReason = "Requires local Ollama server.",
},
- new SampleDefinition
- {
- Name = "Agent_With_OpenAIAssistants",
- ProjectPath = "samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants",
- RequiredEnvironmentVariables = ["OPENAI_API_KEY"],
- OptionalEnvironmentVariables = ["OPENAI_CHAT_MODEL_NAME"],
- ExpectedOutputDescription =
- [
- "The output should contain a joke about a pirate from the OpenAI Assistants API.",
- "The output should not contain error messages or stack traces.",
- ],
- },
-
new SampleDefinition
{
Name = "Agent_With_OpenAIChatCompletion",
diff --git a/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Agent_With_OpenAIAssistants.csproj b/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Agent_With_OpenAIAssistants.csproj
deleted file mode 100644
index eeda3eef6f..0000000000
--- a/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Agent_With_OpenAIAssistants.csproj
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
- Exe
- net10.0
-
- enable
- enable
-
-
-
-
-
-
-
diff --git a/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Program.cs b/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Program.cs
deleted file mode 100644
index 02d19ab52c..0000000000
--- a/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/Program.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-// This sample shows how to create and use a simple AI agent with OpenAI Assistants as the backend.
-
-// WARNING: The Assistants API is deprecated and will be shut down.
-// For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration
-
-#pragma warning disable CS0618 // Type or member is obsolete - OpenAI Assistants API is deprecated but still used in this sample
-
-using Microsoft.Agents.AI;
-using OpenAI;
-using OpenAI.Assistants;
-
-var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
-var model = Environment.GetEnvironmentVariable("OPENAI_CHAT_MODEL_NAME") ?? "gpt-4o-mini";
-
-const string JokerName = "Joker";
-const string JokerInstructions = "You are good at telling jokes.";
-
-// Get a client to create/retrieve server side agents with.
-var assistantClient = new OpenAIClient(apiKey).GetAssistantClient();
-
-// You can create a server side assistant with the OpenAI SDK.
-var createResult = await assistantClient.CreateAssistantAsync(model, new() { Name = JokerName, Instructions = JokerInstructions });
-
-// You can retrieve an already created server side assistant as an AIAgent.
-AIAgent agent1 = await assistantClient.GetAIAgentAsync(createResult.Value.Id);
-
-// You can also create a server side assistant and return it as an AIAgent directly.
-AIAgent agent2 = await assistantClient.CreateAIAgentAsync(
- model: model,
- name: JokerName,
- instructions: JokerInstructions);
-
-// You can invoke the agent like any other AIAgent.
-AgentSession session = await agent1.CreateSessionAsync();
-Console.WriteLine(await agent1.RunAsync("Tell me a joke about a pirate.", session));
-
-// Cleanup for sample purposes.
-await assistantClient.DeleteAssistantAsync(agent1.Id);
-await assistantClient.DeleteAssistantAsync(agent2.Id);
diff --git a/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/README.md b/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/README.md
deleted file mode 100644
index b0a7638ab5..0000000000
--- a/dotnet/samples/02-agents/AgentProviders/Agent_With_OpenAIAssistants/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Prerequisites
-
-WARNING: The Assistants API is deprecated and will be shut down.
-For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration
-
-Before you begin, ensure you have the following prerequisites:
-
-- .NET 10 SDK or later
-- OpenAI API key
-
-Set the following environment variables:
-
-```powershell
-$env:OPENAI_API_KEY="*****" # Replace with your OpenAI API key
-$env:OPENAI_CHAT_MODEL_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
-```
diff --git a/dotnet/samples/02-agents/AgentProviders/README.md b/dotnet/samples/02-agents/AgentProviders/README.md
index ee83f8c08c..5584fdc810 100644
--- a/dotnet/samples/02-agents/AgentProviders/README.md
+++ b/dotnet/samples/02-agents/AgentProviders/README.md
@@ -25,7 +25,6 @@ See the README.md for each sample for the prerequisites for that sample.
|[Creating an AIAgent with GitHub Copilot](./Agent_With_GitHubCopilot/)|This sample demonstrates how to create an AIAgent using GitHub Copilot SDK as the underlying inference service|
|[Creating an AIAgent with Ollama](./Agent_With_Ollama/)|This sample demonstrates how to create an AIAgent using Ollama as the underlying inference service|
|[Creating an AIAgent with ONNX](./Agent_With_ONNX/)|This sample demonstrates how to create an AIAgent using ONNX as the underlying inference service|
-|[Creating an AIAgent with OpenAI Assistants](./Agent_With_OpenAIAssistants/)|This sample demonstrates how to create an AIAgent using OpenAI Assistants as the underlying inference service.WARNING: The Assistants API is deprecated and will be shut down. For more information see the OpenAI documentation: https://platform.openai.com/docs/assistants/migration|
|[Creating an AIAgent with OpenAI ChatCompletion](./Agent_With_OpenAIChatCompletion/)|This sample demonstrates how to create an AIAgent using OpenAI ChatCompletion as the underlying inference service|
|[Creating an AIAgent with OpenAI Responses](./Agent_With_OpenAIResponses/)|This sample demonstrates how to create an AIAgent using OpenAI Responses as the underlying inference service|
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/CompatibilitySuppressions.xml b/dotnet/src/Microsoft.Agents.AI.OpenAI/CompatibilitySuppressions.xml
index fe04c26eca..25439ed1a1 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/CompatibilitySuppressions.xml
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/CompatibilitySuppressions.xml
@@ -1,6 +1,41 @@
+
+ CP0001
+ T:OpenAI.Assistants.OpenAIAssistantClientExtensions
+ lib/net10.0/Microsoft.Agents.AI.OpenAI.dll
+ lib/net10.0/Microsoft.Agents.AI.OpenAI.dll
+ true
+
+
+ CP0001
+ T:OpenAI.Assistants.OpenAIAssistantClientExtensions
+ lib/net472/Microsoft.Agents.AI.OpenAI.dll
+ lib/net472/Microsoft.Agents.AI.OpenAI.dll
+ true
+
+
+ CP0001
+ T:OpenAI.Assistants.OpenAIAssistantClientExtensions
+ lib/net8.0/Microsoft.Agents.AI.OpenAI.dll
+ lib/net8.0/Microsoft.Agents.AI.OpenAI.dll
+ true
+
+
+ CP0001
+ T:OpenAI.Assistants.OpenAIAssistantClientExtensions
+ lib/net9.0/Microsoft.Agents.AI.OpenAI.dll
+ lib/net9.0/Microsoft.Agents.AI.OpenAI.dll
+ true
+
+
+ CP0001
+ T:OpenAI.Assistants.OpenAIAssistantClientExtensions
+ lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll
+ lib/netstandard2.0/Microsoft.Agents.AI.OpenAI.dll
+ true
+
CP0002
M:OpenAI.Responses.OpenAIResponseClientExtensions.AsAIAgent(OpenAI.Responses.ResponsesClient,Microsoft.Agents.AI.ChatClientAgentOptions,System.Func{Microsoft.Extensions.AI.IChatClient,Microsoft.Extensions.AI.IChatClient},Microsoft.Extensions.Logging.ILoggerFactory,System.IServiceProvider)
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs
deleted file mode 100644
index a1f083ae06..0000000000
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs
+++ /dev/null
@@ -1,433 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.ClientModel;
-using System.Diagnostics.CodeAnalysis;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
-using Microsoft.Extensions.Logging;
-using Microsoft.Shared.DiagnosticIds;
-using Microsoft.Shared.Diagnostics;
-
-namespace OpenAI.Assistants;
-
-///
-/// Provides extension methods for OpenAI
-/// to simplify the creation of AI agents that work with OpenAI services.
-///
-///
-/// These extensions bridge the gap between OpenAI SDK client objects and the Microsoft Agent Framework,
-/// allowing developers to easily create AI agents that leverage OpenAI's chat completion and response services.
-/// The methods handle the conversion from OpenAI clients to instances and then wrap them
-/// in objects that implement the interface.
-///
-[Experimental(DiagnosticIds.Experiments.AIOpenAIAssistants)]
-public static class OpenAIAssistantClientExtensions
-{
- ///
- /// Gets a from a .
- ///
- /// The assistant client.
- /// The client result containing the assistant.
- /// Optional chat options.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// A instance that can be used to perform operations on the assistant.
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static ChatClientAgent AsAIAgent(
- this AssistantClient assistantClient,
- ClientResult assistantClientResult,
- ChatOptions? chatOptions = null,
- Func? clientFactory = null,
- IServiceProvider? services = null)
- {
- if (assistantClientResult is null)
- {
- throw new ArgumentNullException(nameof(assistantClientResult));
- }
-
- return assistantClient.AsAIAgent(assistantClientResult.Value, chatOptions, clientFactory, services);
- }
-
- ///
- /// Gets a from an .
- ///
- /// The assistant client.
- /// The assistant metadata.
- /// Optional chat options.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// A instance that can be used to perform operations on the assistant.
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static ChatClientAgent AsAIAgent(
- this AssistantClient assistantClient,
- Assistant assistantMetadata,
- ChatOptions? chatOptions = null,
- Func? clientFactory = null,
- IServiceProvider? services = null)
- {
- if (assistantMetadata is null)
- {
- throw new ArgumentNullException(nameof(assistantMetadata));
- }
- if (assistantClient is null)
- {
- throw new ArgumentNullException(nameof(assistantClient));
- }
-
- var chatClient = assistantClient.AsIChatClient(assistantMetadata.Id);
-
- if (clientFactory is not null)
- {
- chatClient = clientFactory(chatClient);
- }
-
- if (!string.IsNullOrWhiteSpace(assistantMetadata.Instructions) && chatOptions?.Instructions is null)
- {
- chatOptions ??= new ChatOptions();
- chatOptions.Instructions = assistantMetadata.Instructions;
- }
-
- return new ChatClientAgent(chatClient, options: new()
- {
- Id = assistantMetadata.Id,
- Name = assistantMetadata.Name,
- Description = assistantMetadata.Description,
- ChatOptions = chatOptions
- }, services: services);
- }
-
- ///
- /// Retrieves an existing server side agent, wrapped as a using the provided .
- ///
- /// The to create the with.
- /// The ID of the server side agent to create a for.
- /// Options that should apply to all runs of the agent.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// The to monitor for cancellation requests. The default is .
- /// A instance that can be used to perform operations on the assistant agent.
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static async Task GetAIAgentAsync(
- this AssistantClient assistantClient,
- string agentId,
- ChatOptions? chatOptions = null,
- Func? clientFactory = null,
- IServiceProvider? services = null,
- CancellationToken cancellationToken = default)
- {
- if (assistantClient is null)
- {
- throw new ArgumentNullException(nameof(assistantClient));
- }
-
- if (string.IsNullOrWhiteSpace(agentId))
- {
- throw new ArgumentException($"{nameof(agentId)} should not be null or whitespace.", nameof(agentId));
- }
-
- var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
- return assistantClient.AsAIAgent(assistantResponse, chatOptions, clientFactory, services);
- }
-
- ///
- /// Gets a from a .
- ///
- /// The assistant client.
- /// The client result containing the assistant.
- /// Full set of options to configure the agent.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// A instance that can be used to perform operations on the assistant.
- /// or is .
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static ChatClientAgent AsAIAgent(
- this AssistantClient assistantClient,
- ClientResult assistantClientResult,
- ChatClientAgentOptions options,
- Func? clientFactory = null,
- IServiceProvider? services = null)
- {
- if (assistantClientResult is null)
- {
- throw new ArgumentNullException(nameof(assistantClientResult));
- }
-
- return assistantClient.AsAIAgent(assistantClientResult.Value, options, clientFactory, services);
- }
-
- ///
- /// Gets a from an .
- ///
- /// The assistant client.
- /// The assistant metadata.
- /// Full set of options to configure the agent.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// A instance that can be used to perform operations on the assistant.
- /// or is .
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static ChatClientAgent AsAIAgent(
- this AssistantClient assistantClient,
- Assistant assistantMetadata,
- ChatClientAgentOptions options,
- Func? clientFactory = null,
- IServiceProvider? services = null)
- {
- if (assistantMetadata is null)
- {
- throw new ArgumentNullException(nameof(assistantMetadata));
- }
-
- if (assistantClient is null)
- {
- throw new ArgumentNullException(nameof(assistantClient));
- }
-
- if (options is null)
- {
- throw new ArgumentNullException(nameof(options));
- }
-
- var chatClient = assistantClient.AsIChatClient(assistantMetadata.Id);
-
- if (clientFactory is not null)
- {
- chatClient = clientFactory(chatClient);
- }
-
- if (string.IsNullOrWhiteSpace(options.ChatOptions?.Instructions) && !string.IsNullOrWhiteSpace(assistantMetadata.Instructions))
- {
- options.ChatOptions ??= new ChatOptions();
- options.ChatOptions.Instructions = assistantMetadata.Instructions;
- }
-
- var mergedOptions = new ChatClientAgentOptions()
- {
- Id = assistantMetadata.Id,
- Name = options.Name ?? assistantMetadata.Name,
- Description = options.Description ?? assistantMetadata.Description,
- ChatOptions = options.ChatOptions,
- AIContextProviders = options.AIContextProviders,
- ChatHistoryProvider = options.ChatHistoryProvider,
- UseProvidedChatClientAsIs = options.UseProvidedChatClientAsIs
- };
-
- return new ChatClientAgent(chatClient, mergedOptions, services: services);
- }
-
- ///
- /// Retrieves an existing server side agent, wrapped as a using the provided .
- ///
- /// The to create the with.
- /// The ID of the server side agent to create a for.
- /// Full set of options to configure the agent.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// The to monitor for cancellation requests. The default is .
- /// A instance that can be used to perform operations on the assistant agent.
- /// or is .
- /// is empty or whitespace.
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static async Task GetAIAgentAsync(
- this AssistantClient assistantClient,
- string agentId,
- ChatClientAgentOptions options,
- Func? clientFactory = null,
- IServiceProvider? services = null,
- CancellationToken cancellationToken = default)
- {
- if (assistantClient is null)
- {
- throw new ArgumentNullException(nameof(assistantClient));
- }
-
- if (string.IsNullOrWhiteSpace(agentId))
- {
- throw new ArgumentException($"{nameof(agentId)} should not be null or whitespace.", nameof(agentId));
- }
-
- if (options is null)
- {
- throw new ArgumentNullException(nameof(options));
- }
-
- var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
- return assistantClient.AsAIAgent(assistantResponse, options, clientFactory, services);
- }
-
- ///
- /// Creates an AI agent from an using the OpenAI Assistant API.
- ///
- /// The OpenAI to use for the agent.
- /// The model identifier to use (e.g., "gpt-4").
- /// Optional system instructions that define the agent's behavior and personality.
- /// Optional name for the agent for identification purposes.
- /// Optional description of the agent's capabilities and purpose.
- /// Optional collection of AI tools that the agent can use during conversations.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// Optional logger factory for enabling logging within the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// The to monitor for cancellation requests. The default is .
- /// An instance backed by the OpenAI Assistant service.
- /// Thrown when or is .
- /// Thrown when is empty or whitespace.
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static async Task CreateAIAgentAsync(
- this AssistantClient client,
- string model,
- string? instructions = null,
- string? name = null,
- string? description = null,
- IList? tools = null,
- Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null,
- IServiceProvider? services = null,
- CancellationToken cancellationToken = default) =>
- await client.CreateAIAgentAsync(model,
- new ChatClientAgentOptions()
- {
- Name = name,
- Description = description,
- ChatOptions = tools is null && string.IsNullOrWhiteSpace(instructions) ? null : new ChatOptions()
- {
- Tools = tools,
- Instructions = instructions,
- }
- },
- clientFactory,
- loggerFactory,
- services,
- cancellationToken).ConfigureAwait(false);
-
- ///
- /// Creates an AI agent from an using the OpenAI Assistant API.
- ///
- /// The OpenAI to use for the agent.
- /// The model identifier to use (e.g., "gpt-4").
- /// Full set of options to configure the agent.
- /// Provides a way to customize the creation of the underlying used by the agent.
- /// Optional logger factory for enabling logging within the agent.
- /// An optional to use for resolving services required by the instances being invoked.
- /// The to monitor for cancellation requests. The default is .
- /// An instance backed by the OpenAI Assistant service.
- /// Thrown when or is .
- /// Thrown when is empty or whitespace.
- [Obsolete("The Assistants API has been deprecated. Please use the Responses API instead.")]
- public static async Task CreateAIAgentAsync(
- this AssistantClient client,
- string model,
- ChatClientAgentOptions options,
- Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null,
- IServiceProvider? services = null,
- CancellationToken cancellationToken = default)
- {
- Throw.IfNull(client);
- Throw.IfNull(model);
- Throw.IfNull(options);
-
- var assistantOptions = new AssistantCreationOptions()
- {
- Name = options.Name,
- Description = options.Description,
- Instructions = options.ChatOptions?.Instructions,
- };
-
- // Convert AITools to ToolDefinitions and ToolResources
- var toolDefinitionsAndResources = ConvertAIToolsToToolDefinitions(options.ChatOptions?.Tools);
- if (toolDefinitionsAndResources.ToolDefinitions is { Count: > 0 } toolDefinitions)
- {
- toolDefinitions.ForEach(x => assistantOptions.Tools.Add(x));
- }
- if (toolDefinitionsAndResources.ToolResources is not null)
- {
- assistantOptions.ToolResources = toolDefinitionsAndResources.ToolResources;
- }
-
- // Create the assistant in the assistant service.
- var assistantCreateResult = await client.CreateAssistantAsync(model, assistantOptions, cancellationToken).ConfigureAwait(false);
- var assistantId = assistantCreateResult.Value.Id;
-
- // Build the local agent object.
- var chatClient = client.AsIChatClient(assistantId);
- if (clientFactory is not null)
- {
- chatClient = clientFactory(chatClient);
- }
-
- var agentOptions = options.Clone();
- agentOptions.Id = assistantId;
- options.ChatOptions ??= new ChatOptions();
- options.ChatOptions!.Tools = toolDefinitionsAndResources.FunctionToolsAndOtherTools;
-
- return new ChatClientAgent(chatClient, agentOptions, loggerFactory, services);
- }
-
- private static (List? ToolDefinitions, ToolResources? ToolResources, List? FunctionToolsAndOtherTools) ConvertAIToolsToToolDefinitions(IList? tools)
- {
- List? toolDefinitions = null;
- ToolResources? toolResources = null;
- List? functionToolsAndOtherTools = null;
-
- if (tools is not null)
- {
- foreach (AITool tool in tools)
- {
- switch (tool)
- {
- case HostedCodeInterpreterTool codeTool:
-
- toolDefinitions ??= [];
- toolDefinitions.Add(new CodeInterpreterToolDefinition());
-
- if (codeTool.Inputs is { Count: > 0 })
- {
- foreach (var input in codeTool.Inputs)
- {
- switch (input)
- {
- case HostedFileContent hostedFile:
- // If the input is a HostedFileContent, we can use its ID directly.
- toolResources ??= new();
- toolResources.CodeInterpreter ??= new();
- toolResources.CodeInterpreter.FileIds.Add(hostedFile.FileId);
- break;
- }
- }
- }
- break;
-
- case HostedFileSearchTool fileSearchTool:
- toolDefinitions ??= [];
- toolDefinitions.Add(new FileSearchToolDefinition
- {
- MaxResults = fileSearchTool.MaximumResultCount,
- });
-
- if (fileSearchTool.Inputs is { Count: > 0 })
- {
- foreach (var input in fileSearchTool.Inputs)
- {
- switch (input)
- {
- case HostedVectorStoreContent hostedVectorStore:
- toolResources ??= new();
- toolResources.FileSearch ??= new();
- toolResources.FileSearch.VectorStoreIds.Add(hostedVectorStore.VectorStoreId);
- break;
- }
- }
- }
- break;
-
- default:
- functionToolsAndOtherTools ??= [];
- functionToolsAndOtherTools.Add(tool);
- break;
- }
- }
- }
-
- return (toolDefinitions, toolResources, functionToolsAndOtherTools);
- }
-}
diff --git a/dotnet/src/Shared/DiagnosticIds/DiagnosticsIds.cs b/dotnet/src/Shared/DiagnosticIds/DiagnosticsIds.cs
index 6316c6f607..2d4d02e3bf 100644
--- a/dotnet/src/Shared/DiagnosticIds/DiagnosticsIds.cs
+++ b/dotnet/src/Shared/DiagnosticIds/DiagnosticsIds.cs
@@ -26,7 +26,6 @@ internal static class DiagnosticIds
// We use the same IDs so consumers do not need to suppress additional diagnostics
// when using the experimental OpenAI APIs.
internal const string AIOpenAIResponses = "OPENAI001";
- internal const string AIOpenAIAssistants = "OPENAI001";
private const string MEAIExperiments = "MEAI001";
}
diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs
deleted file mode 100644
index 44a4b73b52..0000000000
--- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs
+++ /dev/null
@@ -1,1013 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-#pragma warning disable CS0618 // Type or member is obsolete - This is intentional as we are testing deprecated methods
-
-using System;
-using System.ClientModel;
-using System.ClientModel.Primitives;
-using System.IO;
-using System.Reflection;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Extensions.AI;
-using OpenAI.Assistants;
-
-namespace Microsoft.Agents.AI.OpenAI.UnitTests.Extensions;
-
-///
-/// Unit tests for the class.
-///
-public sealed class OpenAIAssistantClientExtensionsTests
-{
- ///
- /// Verify that CreateAIAgent with clientFactory parameter correctly applies the factory.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithClientFactory_AppliesFactoryCorrectlyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var testChatClient = new TestChatClient(assistantClient.AsIChatClient("test-model"));
- const string ModelId = "test-model";
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- instructions: "Test instructions",
- name: "Test Agent",
- description: "Test description",
- clientFactory: (innerClient) => testChatClient);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- Assert.Equal("Test description", agent.Description);
-
- // Verify that the custom chat client can be retrieved from the agent's service collection
- var retrievedTestClient = agent.GetService();
- Assert.NotNull(retrievedTestClient);
- Assert.Same(testChatClient, retrievedTestClient);
- }
-
- ///
- /// Verify that CreateAIAgent with clientFactory using AsBuilder pattern works correctly.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithClientFactoryUsingAsBuilder_AppliesFactoryCorrectlyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- TestChatClient? testChatClient = null;
-
- const string ModelId = "test-model";
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- instructions: "Test instructions",
- clientFactory: (innerClient) =>
- innerClient.AsBuilder()
- .Use((innerClient) => testChatClient = new TestChatClient(innerClient))
- .Build());
-
- // Assert
- Assert.NotNull(agent);
-
- // Verify that the custom chat client can be retrieved from the agent's service collection
- var retrievedTestClient = agent.GetService();
- Assert.NotNull(retrievedTestClient);
- Assert.Same(testChatClient, retrievedTestClient);
- }
-
- ///
- /// Verify that CreateAIAgent with options and clientFactory parameter correctly applies the factory.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithOptionsAndClientFactory_AppliesFactoryCorrectlyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var testChatClient = new TestChatClient(assistantClient.AsIChatClient("test-model"));
- const string ModelId = "test-model";
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- Description = "Test description",
- ChatOptions = new() { Instructions = "Test instructions" }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- options,
- clientFactory: (innerClient) => testChatClient);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- Assert.Equal("Test description", agent.Description);
-
- // Verify that the custom chat client can be retrieved from the agent's service collection
- var retrievedTestClient = agent.GetService();
- Assert.NotNull(retrievedTestClient);
- Assert.Same(testChatClient, retrievedTestClient);
- }
-
- ///
- /// Verify that CreateAIAgent without clientFactory works normally.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithoutClientFactory_WorksNormallyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- instructions: "Test instructions",
- name: "Test Agent");
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
-
- // Verify that no TestChatClient is available since no factory was provided
- var retrievedTestClient = agent.GetService();
- Assert.Null(retrievedTestClient);
- }
-
- ///
- /// Verify that CreateAIAgent with null clientFactory works normally.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithNullClientFactory_WorksNormallyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- instructions: "Test instructions",
- name: "Test Agent",
- clientFactory: null);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
-
- // Verify that no TestChatClient is available since no factory was provided
- var retrievedTestClient = agent.GetService();
- Assert.Null(retrievedTestClient);
- }
-
- ///
- /// Verify that CreateAIAgent throws ArgumentNullException when client is null.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithNullClient_ThrowsArgumentNullExceptionAsync()
- {
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- ((AssistantClient)null!).CreateAIAgentAsync("test-model"));
-
- Assert.Equal("client", exception.ParamName);
- }
-
- ///
- /// Verify that CreateAIAgent throws ArgumentNullException when model is null.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithNullModel_ThrowsArgumentNullExceptionAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient.CreateAIAgentAsync(null!));
-
- Assert.Equal("model", exception.ParamName);
- }
-
- ///
- /// Verify that CreateAIAgent with options throws ArgumentNullException when options is null.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithNullOptions_ThrowsArgumentNullExceptionAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient.CreateAIAgentAsync("test-model", (ChatClientAgentOptions)null!));
-
- Assert.Equal("options", exception.ParamName);
- }
-
- ///
- /// Verify that AsAIAgent with ClientResult and options works correctly.
- ///
- [Fact]
- public void AsAIAgent_WithClientResultAndOptions_WorksCorrectly()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Original Name", "description": "Original Description", "instructions": "Original Instructions"}"""))!;
- var clientResult = ClientResult.FromValue(assistant, new FakePipelineResponse());
-
- var options = new ChatClientAgentOptions
- {
- Name = "Override Name",
- Description = "Override Description",
- ChatOptions = new() { Instructions = "Override Instructions" }
- };
-
- // Act
- var agent = assistantClient.AsAIAgent(clientResult, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Override Name", agent.Name);
- Assert.Equal("Override Description", agent.Description);
- Assert.Equal("Override Instructions", agent.Instructions);
- }
-
- ///
- /// Verify that AsAIAgent with Assistant and options works correctly.
- ///
- [Fact]
- public void AsAIAgent_WithAssistantAndOptions_WorksCorrectly()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Original Name", "description": "Original Description", "instructions": "Original Instructions"}"""))!;
-
- var options = new ChatClientAgentOptions
- {
- Name = "Override Name",
- Description = "Override Description",
- ChatOptions = new() { Instructions = "Override Instructions" }
- };
-
- // Act
- var agent = assistantClient.AsAIAgent(assistant, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Override Name", agent.Name);
- Assert.Equal("Override Description", agent.Description);
- Assert.Equal("Override Instructions", agent.Instructions);
- }
-
- ///
- /// Verify that AsAIAgent with Assistant and options falls back to assistant metadata when options are null.
- ///
- [Fact]
- public void AsAIAgent_WithAssistantAndOptionsWithNullFields_FallsBackToAssistantMetadata()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Original Name", "description": "Original Description", "instructions": "Original Instructions"}"""))!;
-
- var options = new ChatClientAgentOptions(); // Empty options
-
- // Act
- var agent = assistantClient.AsAIAgent(assistant, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Original Name", agent.Name);
- Assert.Equal("Original Description", agent.Description);
- Assert.Equal("Original Instructions", agent.Instructions);
- }
-
- ///
- /// Verify that GetAIAgentAsync with agentId and options works correctly.
- ///
- [Fact]
- public async Task GetAIAgentAsync_WithAgentIdAndOptions_WorksCorrectlyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string AgentId = "asst_abc123";
-
- var options = new ChatClientAgentOptions
- {
- Name = "Override Name",
- Description = "Override Description",
- ChatOptions = new() { Instructions = "Override Instructions" }
- };
-
- // Act
- var agent = await assistantClient.GetAIAgentAsync(AgentId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Override Name", agent.Name);
- Assert.Equal("Override Description", agent.Description);
- Assert.Equal("Override Instructions", agent.Instructions);
- }
-
- ///
- /// Verify that AsAIAgent with clientFactory parameter correctly applies the factory.
- ///
- [Fact]
- public void AsAIAgent_WithClientFactory_AppliesFactoryCorrectly()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent"}"""))!;
- var testChatClient = new TestChatClient(assistantClient.AsIChatClient("asst_abc123"));
-
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent"
- };
-
- // Act
- var agent = assistantClient.AsAIAgent(
- assistant,
- options,
- clientFactory: (innerClient) => testChatClient);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
-
- // Verify that the custom chat client can be retrieved from the agent's service collection
- var retrievedTestClient = agent.GetService();
- Assert.NotNull(retrievedTestClient);
- Assert.Same(testChatClient, retrievedTestClient);
- }
-
- ///
- /// Verify that AsAIAgent throws ArgumentNullException when assistantClientResult is null.
- ///
- [Fact]
- public void AsAIAgent_WithNullClientResult_ThrowsArgumentNullException()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var options = new ChatClientAgentOptions();
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient.AsAIAgent(null!, options));
-
- Assert.Equal("assistantClientResult", exception.ParamName);
- }
-
- ///
- /// Verify that AsAIAgent throws ArgumentNullException when assistant is null.
- ///
- [Fact]
- public void AsAIAgent_WithNullAssistant_ThrowsArgumentNullException()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var options = new ChatClientAgentOptions();
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient.AsAIAgent((Assistant)null!, options));
-
- Assert.Equal("assistantMetadata", exception.ParamName);
- }
-
- ///
- /// Verify that AsAIAgent throws ArgumentNullException when options is null.
- ///
- [Fact]
- public void AsAIAgent_WithNullOptions_ThrowsArgumentNullException()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123"}"""))!;
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient.AsAIAgent(assistant, (ChatClientAgentOptions)null!));
-
- Assert.Equal("options", exception.ParamName);
- }
-
- ///
- /// Verify that GetAIAgentAsync throws ArgumentException when agentId is empty.
- ///
- [Fact]
- public async Task GetAIAgentAsync_WithEmptyAgentId_ThrowsArgumentExceptionAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var options = new ChatClientAgentOptions();
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient.GetAIAgentAsync(string.Empty, options));
-
- Assert.Equal("agentId", exception.ParamName);
- }
-
- ///
- /// Verify that CreateAIAgent with services parameter correctly passes it through to the ChatClientAgent.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithServices_PassesServicesToAgentAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var serviceProvider = new TestServiceProvider();
- const string ModelId = "test-model";
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- instructions: "Test instructions",
- name: "Test Agent",
- services: serviceProvider);
-
- // Assert
- Assert.NotNull(agent);
-
- // Verify the IServiceProvider was passed through to the FunctionInvokingChatClient
- var chatClient = agent.GetService();
- Assert.NotNull(chatClient);
- var functionInvokingClient = chatClient.GetService();
- Assert.NotNull(functionInvokingClient);
- Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient));
- }
-
- ///
- /// Verify that CreateAIAgent with options and services parameter correctly passes it through to the ChatClientAgent.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithOptionsAndServices_PassesServicesToAgentAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var serviceProvider = new TestServiceProvider();
- const string ModelId = "test-model";
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new() { Instructions = "Test instructions" }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options, services: serviceProvider);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
-
- // Verify the IServiceProvider was passed through to the FunctionInvokingChatClient
- var chatClient = agent.GetService();
- Assert.NotNull(chatClient);
- var functionInvokingClient = chatClient.GetService();
- Assert.NotNull(functionInvokingClient);
- Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient));
- }
-
- ///
- /// Verify that AsAIAgent with services parameter correctly passes it through to the ChatClientAgent.
- ///
- [Fact]
- public void AsAIAgent_WithServices_PassesServicesToAgent()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var serviceProvider = new TestServiceProvider();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent"}"""))!;
-
- // Act
- var agent = assistantClient.AsAIAgent(assistant, services: serviceProvider);
-
- // Assert
- Assert.NotNull(agent);
-
- // Verify the IServiceProvider was passed through to the FunctionInvokingChatClient
- var chatClient = agent.GetService();
- Assert.NotNull(chatClient);
- var functionInvokingClient = chatClient.GetService();
- Assert.NotNull(functionInvokingClient);
- Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient));
- }
-
- ///
- /// Verify that GetAIAgentAsync with services parameter correctly passes it through to the ChatClientAgent.
- ///
- [Fact]
- public async Task GetAIAgentAsync_WithServices_PassesServicesToAgentAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var serviceProvider = new TestServiceProvider();
-
- // Act
- var agent = await assistantClient.GetAIAgentAsync("asst_abc123", services: serviceProvider);
-
- // Assert
- Assert.NotNull(agent);
-
- // Verify the IServiceProvider was passed through to the FunctionInvokingChatClient
- var chatClient = agent.GetService();
- Assert.NotNull(chatClient);
- var functionInvokingClient = chatClient.GetService();
- Assert.NotNull(functionInvokingClient);
- Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient));
- }
-
- ///
- /// Verify that CreateAIAgent with both clientFactory and services works correctly.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithClientFactoryAndServices_AppliesBothCorrectlyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var serviceProvider = new TestServiceProvider();
- var testChatClient = new TestChatClient(assistantClient.AsIChatClient("test-model"));
- const string ModelId = "test-model";
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(
- ModelId,
- instructions: "Test instructions",
- name: "Test Agent",
- clientFactory: (innerClient) => testChatClient,
- services: serviceProvider);
-
- // Assert
- Assert.NotNull(agent);
-
- // Verify the custom chat client was applied
- var retrievedTestClient = agent.GetService();
- Assert.NotNull(retrievedTestClient);
- Assert.Same(testChatClient, retrievedTestClient);
-
- // Verify the IServiceProvider was passed through
- var chatClient = agent.GetService();
- Assert.NotNull(chatClient);
- var functionInvokingClient = chatClient.GetService();
- Assert.NotNull(functionInvokingClient);
- Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient));
- }
-
- ///
- /// Uses reflection to access the FunctionInvocationServices property which is not public.
- ///
- private static IServiceProvider? GetFunctionInvocationServices(FunctionInvokingChatClient client)
- {
- var property = typeof(FunctionInvokingChatClient).GetProperty(
- "FunctionInvocationServices",
- BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- return property?.GetValue(client) as IServiceProvider;
- }
-
- ///
- /// Verify that CreateAIAgentAsync with HostedCodeInterpreterTool properly adds CodeInterpreter tool definition.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithHostedCodeInterpreterTool_CreatesAgentWithToolAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new ChatOptions
- {
- Instructions = "Test instructions",
- Tools = [new HostedCodeInterpreterTool()]
- }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that CreateAIAgentAsync with HostedCodeInterpreterTool with HostedFileContent input properly creates agent.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithHostedCodeInterpreterToolAndHostedFileContent_CreatesAgentWithToolResourcesAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
- var codeInterpreterTool = new HostedCodeInterpreterTool
- {
- Inputs = [new HostedFileContent("test-file-id")]
- };
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new ChatOptions
- {
- Instructions = "Test instructions",
- Tools = [codeInterpreterTool]
- }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that CreateAIAgentAsync with HostedFileSearchTool properly adds FileSearch tool definition.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithHostedFileSearchTool_CreatesAgentWithToolAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new ChatOptions
- {
- Instructions = "Test instructions",
- Tools = [new HostedFileSearchTool()]
- }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that CreateAIAgentAsync with HostedFileSearchTool with HostedVectorStoreContent input properly creates agent.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithHostedFileSearchToolAndHostedVectorStoreContent_CreatesAgentWithToolResourcesAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
- var fileSearchTool = new HostedFileSearchTool
- {
- MaximumResultCount = 10,
- Inputs = [new HostedVectorStoreContent("test-vector-store-id")]
- };
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new ChatOptions
- {
- Instructions = "Test instructions",
- Tools = [fileSearchTool]
- }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that CreateAIAgentAsync with multiple tools including functions properly creates agent.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithMixedTools_CreatesAgentWithAllToolsAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
- var testFunction = AIFunctionFactory.Create(() => "test", "TestFunction", "A test function");
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new ChatOptions
- {
- Instructions = "Test instructions",
- Tools = [new HostedCodeInterpreterTool(), new HostedFileSearchTool(), testFunction]
- }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that CreateAIAgentAsync with function tools properly categorizes them as other tools.
- ///
- [Fact]
- public async Task CreateAIAgentAsync_WithFunctionTools_CategorizesAsOtherToolsAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string ModelId = "test-model";
- var testFunction = AIFunctionFactory.Create(() => "test", "TestFunction", "A test function");
- var options = new ChatClientAgentOptions
- {
- Name = "Test Agent",
- ChatOptions = new ChatOptions
- {
- Instructions = "Test instructions",
- Tools = [testFunction]
- }
- };
-
- // Act
- var agent = await assistantClient.CreateAIAgentAsync(ModelId, options);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that AsAIAgent with legacy overload works correctly when assistant instructions are set.
- ///
- [Fact]
- public void AsAIAgent_LegacyOverload_WithAssistantInstructions_SetsInstructions()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent", "instructions": "Original Instructions"}"""))!;
-
- // Act
- var agent = assistantClient.AsAIAgent(assistant);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- Assert.Equal("Original Instructions", agent.Instructions);
- }
-
- ///
- /// Verify that AsAIAgent with legacy overload works correctly when chatOptions with instructions is provided.
- ///
- [Fact]
- public void AsAIAgent_LegacyOverload_WithChatOptionsInstructions_UsesChatOptionsInstructions()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent", "instructions": "Original Instructions"}"""))!;
- var chatOptions = new ChatOptions { Instructions = "Override Instructions" };
-
- // Act
- var agent = assistantClient.AsAIAgent(assistant, chatOptions);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- Assert.Equal("Override Instructions", agent.Instructions);
- }
-
- ///
- /// Verify that AsAIAgent with legacy overload and ClientResult works correctly.
- ///
- [Fact]
- public void AsAIAgent_LegacyOverload_WithClientResult_WorksCorrectly()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent", "instructions": "Original Instructions"}"""))!;
- var clientResult = ClientResult.FromValue(assistant, new FakePipelineResponse());
-
- // Act
- var agent = assistantClient.AsAIAgent(clientResult);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Test Agent", agent.Name);
- }
-
- ///
- /// Verify that AsAIAgent with legacy overload throws ArgumentNullException when assistant client is null.
- ///
- [Fact]
- public void AsAIAgent_LegacyOverload_WithNullAssistantClient_ThrowsArgumentNullException()
- {
- // Arrange
- AssistantClient? assistantClient = null;
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123"}"""))!;
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient!.AsAIAgent(assistant));
-
- Assert.Equal("assistantClient", exception.ParamName);
- }
-
- ///
- /// Verify that AsAIAgent with legacy overload throws ArgumentNullException when assistantMetadata is null.
- ///
- [Fact]
- public void AsAIAgent_LegacyOverload_WithNullAssistantMetadata_ThrowsArgumentNullException()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient.AsAIAgent((Assistant)null!));
-
- Assert.Equal("assistantMetadata", exception.ParamName);
- }
-
- ///
- /// Verify that AsAIAgent with legacy overload throws ArgumentNullException when clientResult is null.
- ///
- [Fact]
- public void AsAIAgent_LegacyOverload_WithNullClientResult_ThrowsArgumentNullException()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient.AsAIAgent(null!, chatOptions: null));
-
- Assert.Equal("assistantClientResult", exception.ParamName);
- }
-
- ///
- /// Verify that GetAIAgentAsync with legacy overload works correctly.
- ///
- [Fact]
- public async Task GetAIAgentAsync_LegacyOverload_WorksCorrectlyAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
- const string AgentId = "asst_abc123";
-
- // Act
- var agent = await assistantClient.GetAIAgentAsync(AgentId);
-
- // Assert
- Assert.NotNull(agent);
- Assert.Equal("Original Name", agent.Name);
- }
-
- ///
- /// Verify that GetAIAgentAsync with legacy overload throws ArgumentNullException when assistantClient is null.
- ///
- [Fact]
- public async Task GetAIAgentAsync_LegacyOverload_WithNullAssistantClient_ThrowsArgumentNullExceptionAsync()
- {
- // Arrange
- AssistantClient? assistantClient = null;
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient!.GetAIAgentAsync("asst_abc123"));
-
- Assert.Equal("assistantClient", exception.ParamName);
- }
-
- ///
- /// Verify that GetAIAgentAsync with legacy overload throws ArgumentException when agentId is empty.
- ///
- [Fact]
- public async Task GetAIAgentAsync_LegacyOverload_WithEmptyAgentId_ThrowsArgumentExceptionAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient.GetAIAgentAsync(string.Empty));
-
- Assert.Equal("agentId", exception.ParamName);
- }
-
- ///
- /// Verify that GetAIAgentAsync with options throws ArgumentNullException when assistantClient is null.
- ///
- [Fact]
- public async Task GetAIAgentAsync_WithOptions_WithNullAssistantClient_ThrowsArgumentNullExceptionAsync()
- {
- // Arrange
- AssistantClient? assistantClient = null;
- var options = new ChatClientAgentOptions();
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient!.GetAIAgentAsync("asst_abc123", options));
-
- Assert.Equal("assistantClient", exception.ParamName);
- }
-
- ///
- /// Verify that GetAIAgentAsync with options throws ArgumentNullException when options is null.
- ///
- [Fact]
- public async Task GetAIAgentAsync_WithOptions_WithNullOptions_ThrowsArgumentNullExceptionAsync()
- {
- // Arrange
- var assistantClient = new TestAssistantClient();
-
- // Act & Assert
- var exception = await Assert.ThrowsAsync(() =>
- assistantClient.GetAIAgentAsync("asst_abc123", (ChatClientAgentOptions)null!));
-
- Assert.Equal("options", exception.ParamName);
- }
-
- ///
- /// Verify that AsAIAgent with options throws ArgumentNullException when assistantClient is null.
- ///
- [Fact]
- public void AsAIAgent_WithOptions_WithNullAssistantClient_ThrowsArgumentNullException()
- {
- // Arrange
- AssistantClient? assistantClient = null;
- var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123"}"""))!;
- var options = new ChatClientAgentOptions();
-
- // Act & Assert
- var exception = Assert.Throws(() =>
- assistantClient!.AsAIAgent(assistant, options));
-
- Assert.Equal("assistantClient", exception.ParamName);
- }
-
- ///
- /// Creates a test AssistantClient implementation for testing.
- ///
- private sealed class TestAssistantClient : AssistantClient
- {
- public TestAssistantClient()
- {
- }
-
- public override Task> CreateAssistantAsync(string model, AssistantCreationOptions? options = null, CancellationToken cancellationToken = default)
- {
- return Task.FromResult>(ClientResult.FromValue(ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123"}""")), new FakePipelineResponse())!);
- }
-
- public override async Task> GetAssistantAsync(string assistantId, CancellationToken cancellationToken = default)
- {
- await Task.Delay(1, cancellationToken); // Simulate async operation
- return ClientResult.FromValue(ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Original Name", "description": "Original Description", "instructions": "Original Instructions"}""")), new FakePipelineResponse())!;
- }
- }
-
- private sealed class TestChatClient : DelegatingChatClient
- {
- public TestChatClient(IChatClient innerClient) : base(innerClient)
- {
- }
- }
-
- private sealed class TestServiceProvider : IServiceProvider
- {
- public object? GetService(Type serviceType) => null;
- }
-
- private sealed class FakePipelineResponse : PipelineResponse
- {
- public override int Status => throw new NotImplementedException();
-
- public override string ReasonPhrase => throw new NotImplementedException();
-
- public override Stream? ContentStream { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
-
- public override BinaryData Content => throw new NotImplementedException();
-
- protected override PipelineResponseHeaders HeadersCore => throw new NotImplementedException();
-
- public override BinaryData BufferContent(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public override ValueTask BufferContentAsync(CancellationToken cancellationToken = default)
- {
- throw new NotImplementedException();
- }
-
- public override void Dispose()
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/dotnet/tests/OpenAIAssistant.IntegrationTests/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/OpenAIAssistant.IntegrationTests/OpenAIAssistantClientExtensionsTests.cs
deleted file mode 100644
index 9441d9534b..0000000000
--- a/dotnet/tests/OpenAIAssistant.IntegrationTests/OpenAIAssistantClientExtensionsTests.cs
+++ /dev/null
@@ -1,268 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-#pragma warning disable CS0618 // Type or member is obsolete - Testing deprecated OpenAI Assistants API extension methods
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading.Tasks;
-using AgentConformance.IntegrationTests.Support;
-using Microsoft.Agents.AI;
-using Microsoft.Extensions.AI;
-using OpenAI;
-using OpenAI.Assistants;
-using OpenAI.Files;
-using OpenAI.VectorStores;
-using Shared.IntegrationTests;
-
-namespace OpenAIAssistant.IntegrationTests;
-
-public class OpenAIAssistantClientExtensionsTests
-{
- private const string SkipCodeInterpreterReason = "OpenAI Assistant Code Interpreter intermittently fails in CI";
-
- private readonly AssistantClient _assistantClient = new OpenAIClient(TestConfiguration.GetRequiredValue(TestSettings.OpenAIApiKey)).GetAssistantClient();
- private readonly OpenAIFileClient _fileClient = new OpenAIClient(TestConfiguration.GetRequiredValue(TestSettings.OpenAIApiKey)).GetOpenAIFileClient();
-
- [Theory]
- [InlineData("CreateWithChatClientAgentOptionsAsync")]
- [InlineData("CreateWithChatClientAgentOptionsSync")]
- [InlineData("CreateWithParamsAsync")]
- public async Task CreateAIAgentAsync_WithAIFunctionTool_InvokesFunctionAsync(string createMechanism)
- {
- // Arrange
- const string AgentInstructions = "You are a helpful weather assistant. Always call the GetWeather function to answer questions about weather.";
-
- static string GetWeather(string location) => $"The weather in {location} is sunny with a high of 23C.";
- var weatherFunction = AIFunctionFactory.Create(GetWeather, nameof(GetWeather));
-
- // Act
- var agent = createMechanism switch
- {
- "CreateWithChatClientAgentOptionsAsync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- options: new ChatClientAgentOptions()
- {
- ChatOptions = new()
- {
- Instructions = AgentInstructions,
- Tools = [weatherFunction]
- }
- }),
- "CreateWithChatClientAgentOptionsSync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- options: new ChatClientAgentOptions()
- {
- ChatOptions = new()
- {
- Instructions = AgentInstructions,
- Tools = [weatherFunction]
- }
- }),
- "CreateWithParamsAsync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- instructions: AgentInstructions,
- tools: [weatherFunction]),
- _ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
- };
-
- try
- {
- // Trigger function call.
- var response = await agent.RunAsync("What is the weather like in Amsterdam?");
- var text = response.Text;
-
- // Assert
- Assert.Contains("Amsterdam", text, StringComparison.OrdinalIgnoreCase);
- Assert.Contains("sunny", text, StringComparison.OrdinalIgnoreCase);
- Assert.Contains("23", text, StringComparison.OrdinalIgnoreCase);
- }
- finally
- {
- await this._assistantClient.DeleteAssistantAsync(agent.Id);
- }
- }
-
- [Theory(Skip = SkipCodeInterpreterReason)]
- [InlineData("CreateWithChatClientAgentOptionsAsync")]
- [InlineData("CreateWithChatClientAgentOptionsSync")]
- [InlineData("CreateWithParamsAsync")]
- public async Task CreateAIAgentAsync_WithHostedCodeInterpreter_RunsCodeAsync(string createMechanism)
- {
- // Arrange
- const string Instructions = "Use the Code Interpreter Tool to run the uploaded python file and respond only with the secret number.";
-
- // Create a python file that prints a known value.
- var codeFilePath = Path.GetTempFileName() + "openai_secret_number.py";
- File.WriteAllText(
- path: codeFilePath,
- contents: "print(\"OPENAI_SECRET=13579\")" // Deterministic output we will look for.
- );
-
- // Upload file to OpenAI Assistants file store for use with the Code Interpreter.
- var uploadResult = await this._fileClient.UploadFileAsync(codeFilePath, FileUploadPurpose.Assistants);
- string uploadedFileId = uploadResult.Value.Id;
- var codeInterpreterTool = new HostedCodeInterpreterTool() { Inputs = [new HostedFileContent(uploadedFileId)] };
-
- var agent = createMechanism switch
- {
- "CreateWithChatClientAgentOptionsAsync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- options: new ChatClientAgentOptions()
- {
- ChatOptions = new()
- {
- Instructions = Instructions,
- Tools = [codeInterpreterTool]
- }
- }),
- "CreateWithChatClientAgentOptionsSync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- options: new ChatClientAgentOptions()
- {
- ChatOptions = new()
- {
- Instructions = Instructions,
- Tools = [codeInterpreterTool]
- }
- }),
- "CreateWithParamsAsync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- instructions: Instructions,
- tools: [codeInterpreterTool]),
- _ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
- };
-
- try
- {
- var response = await agent.RunAsync("What is the OPENAI_SECRET number?");
- var text = response.ToString();
- Assert.Contains("13579", text);
- }
- finally
- {
- await this._assistantClient.DeleteAssistantAsync(agent.Id);
- await this._fileClient.DeleteFileAsync(uploadedFileId);
- File.Delete(codeFilePath);
- }
- }
-
- [Theory(Skip = "For manual testing only")]
- [InlineData("CreateWithChatClientAgentOptionsAsync")]
- [InlineData("CreateWithChatClientAgentOptionsSync")]
- [InlineData("CreateWithParamsAsync")]
- public async Task CreateAIAgentAsync_WithHostedFileSearchTool_SearchesFilesAsync(string createMechanism)
- {
- // Arrange.
- const string Instructions = """
- You are a helpful agent that can help fetch data from files you know about.
- Use the File Search Tool to look up codes for words.
- Do not answer a question unless you can find the answer using the File Search Tool.
- """;
-
- // Create a local file with deterministic content and upload it.
- var searchFilePath = Path.GetTempFileName() + "wordcodelookup.txt";
- File.WriteAllText(
- path: searchFilePath,
- contents: "The word 'apple' uses the code 442345, while the word 'banana' uses the code 673457.");
- var uploadResult = await this._fileClient.UploadFileAsync(searchFilePath, FileUploadPurpose.Assistants);
- string uploadedFileId = uploadResult.Value.Id;
-
- // Create a vector store backing the file search (HostedFileSearchTool requires a vector store id).
- var vectorStoreClient = new OpenAIClient(TestConfiguration.GetRequiredValue(TestSettings.OpenAIApiKey)).GetVectorStoreClient();
- var vectorStoreCreate = await vectorStoreClient.CreateVectorStoreAsync(options: new VectorStoreCreationOptions()
- {
- Name = "WordCodeLookup_VectorStore",
- FileIds = { uploadedFileId }
- });
- string vectorStoreId = vectorStoreCreate.Value.Id;
-
- // Wait for vector store indexing to complete before using it
- await WaitForVectorStoreReadyAsync(vectorStoreClient, vectorStoreId);
-
- var fileSearchTool = new HostedFileSearchTool() { Inputs = [new HostedVectorStoreContent(vectorStoreId)] };
-
- var agent = createMechanism switch
- {
- "CreateWithChatClientAgentOptionsAsync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- options: new ChatClientAgentOptions()
- {
- ChatOptions = new()
- {
- Instructions = Instructions,
- Tools = [fileSearchTool]
- }
- }),
- "CreateWithChatClientAgentOptionsSync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- options: new ChatClientAgentOptions()
- {
- ChatOptions = new()
- {
- Instructions = Instructions,
- Tools = [fileSearchTool]
- }
- }),
- "CreateWithParamsAsync" => await this._assistantClient.CreateAIAgentAsync(
- model: TestConfiguration.GetRequiredValue(TestSettings.OpenAIChatModelName),
- instructions: Instructions,
- tools: [fileSearchTool]),
- _ => throw new InvalidOperationException($"Unknown create mechanism: {createMechanism}")
- };
-
- try
- {
- // Act - ask about banana code which must be retrieved via file search.
- var response = await agent.RunAsync("Can you give me the documented code for 'banana'?");
- var text = response.ToString();
- Assert.Contains("673457", text);
- }
- finally
- {
- await this._assistantClient.DeleteAssistantAsync(agent.Id);
- await vectorStoreClient.DeleteVectorStoreAsync(vectorStoreId);
- await this._fileClient.DeleteFileAsync(uploadedFileId);
- File.Delete(searchFilePath);
- }
- }
-
- ///
- /// Waits for a vector store to complete indexing by polling its status.
- ///
- /// The vector store client.
- /// The ID of the vector store.
- /// Maximum time to wait in seconds (default: 30).
- /// A task that completes when the vector store is ready or throws on timeout/failure.
- private static async Task WaitForVectorStoreReadyAsync(
- VectorStoreClient client,
- string vectorStoreId,
- int maxWaitSeconds = 30)
- {
- Stopwatch sw = Stopwatch.StartNew();
- while (sw.Elapsed.TotalSeconds < maxWaitSeconds)
- {
- VectorStore vectorStore = await client.GetVectorStoreAsync(vectorStoreId);
- VectorStoreStatus status = vectorStore.Status;
-
- if (status == VectorStoreStatus.Completed)
- {
- if (vectorStore.FileCounts.Failed > 0)
- {
- throw new InvalidOperationException("Vector store indexing failed for some files");
- }
-
- return;
- }
-
- if (status == VectorStoreStatus.Expired)
- {
- throw new InvalidOperationException("Vector store has expired");
- }
-
- await Task.Delay(1000);
- }
-
- throw new TimeoutException($"Vector store did not complete indexing within {maxWaitSeconds}s");
- }
-}