diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Program.cs index d6eb139ebb..76c7ffdcd6 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Program.cs @@ -22,10 +22,10 @@ var agentDefinition = new PromptAgentDefinition(model: deploymentName) { Instruc var agentVersion = agentsClient.CreateAgentVersion(agentName: JokerName, definition: agentDefinition).Value; // You can retrieve an already created server side agent as an AIAgent. -AIAgent existingAgent = await agentsClient.GetAIAgentAsync(deploymentName, agentVersion.Name); +AIAgent existingAgent = await agentsClient.GetAIAgentAsync(agentVersion.Name); // You can also create a server side persistent agent and return it as an AIAgent directly. -var createdAgent = agentsClient.CreateAIAgent(deploymentName, name: JokerName, instructions: JokerInstructions); +var createdAgent = agentsClient.CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions); // You can then invoke the agent like any other AIAgent. AgentThread thread = existingAgent.GetNewThread(); diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAIAgents/AgentsClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.AzureAIAgents/AgentsClientExtensions.cs index 1df8a88282..4a72e15c2e 100644 --- a/dotnet/src/Microsoft.Agents.AI.AzureAIAgents/AgentsClientExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.AzureAIAgents/AgentsClientExtensions.cs @@ -25,7 +25,6 @@ public static class AgentsClientExtensions /// Gets a runnable agent instance from the provided agent record. /// /// The client used to interact with Azure AI Agents. Cannot be . - /// The model to be used by the agent. /// The agent record to be converted. The latest version will be used. Cannot be . /// The default to use when interacting with the agent. /// Provides a way to customize the creation of the underlying used by the agent. @@ -34,7 +33,6 @@ public static class AgentsClientExtensions /// A instance that can be used to perform operations based on the latest version of the Azure AI Agent. public static ChatClientAgent GetAIAgent( this AgentsClient agentsClient, - string model, AgentRecord agentRecord, ChatOptions? chatOptions = null, Func? clientFactory = null, @@ -42,27 +40,24 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNull(agentRecord); - return GetAIAgent(agentsClient, model, agentRecord.Versions.Latest, chatOptions, clientFactory, openAIClientOptions, cancellationToken); + return GetAIAgent(agentsClient, agentRecord.Versions.Latest, chatOptions, clientFactory, openAIClientOptions, cancellationToken); } /// /// Gets a runnable agent instance from the provided agent record. /// /// The client used to interact with Azure AI Agents. Cannot be . - /// The model to be used by the agent. Cannot be . /// The agent version to be converted. Cannot be . /// The default to use when interacting with the agent. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the specified version of the Azure AI Agent. - /// Thrown when , , or is . + /// Thrown when or is . public static ChatClientAgent GetAIAgent( this AgentsClient agentsClient, - string model, AgentVersion agentVersion, ChatOptions? chatOptions = null, Func? clientFactory = null, @@ -70,29 +65,26 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNull(agentVersion); - return GetAIAgent(agentsClient, model, agentVersion, new ChatClientAgentOptions() { ChatOptions = chatOptions }, clientFactory, openAIClientOptions, cancellationToken); + return GetAIAgent(agentsClient, agentVersion, new ChatClientAgentOptions() { ChatOptions = chatOptions }, clientFactory, openAIClientOptions, cancellationToken); } /// /// Retrieves an existing server side agent, wrapped as a using the provided . /// /// The to create the with. Cannot be . - /// The model to be used by the agent. Cannot be or whitespace. /// The name of the server side agent to create a for. Cannot be or whitespace. /// The default to use when interacting with the agent. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the latest version of the named Azure AI Agent. - /// Thrown when , , or is . - /// Thrown when or is empty or whitespace, or when the agent with the specified name was not found. + /// Thrown when or is . + /// Thrown when is empty or whitespace, or when the agent with the specified name was not found. /// The agent with the specified name was not found. public static ChatClientAgent GetAIAgent( this AgentsClient agentsClient, - string model, string name, ChatOptions? chatOptions = null, Func? clientFactory = null, @@ -100,32 +92,29 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNullOrWhitespace(name); var agentRecord = agentsClient.GetAgent(name, cancellationToken).Value ?? throw new InvalidOperationException($"Agent with name '{name}' not found."); - return GetAIAgent(agentsClient, model, agentRecord, chatOptions, clientFactory, openAIClientOptions, cancellationToken); + return GetAIAgent(agentsClient, agentRecord, chatOptions, clientFactory, openAIClientOptions, cancellationToken); } /// /// Asynchronously retrieves an existing server side agent, wrapped as a using the provided . /// /// The to create the with. Cannot be . - /// The model to be used by the agent. Cannot be or whitespace. /// The name of the server side agent to create a for. Cannot be or whitespace. /// The default to use when interacting with the agent. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the latest version of the named Azure AI Agent. - /// Thrown when , , or is . - /// Thrown when or is empty or whitespace, or when the agent with the specified name was not found. + /// Thrown when or is . + /// Thrown when is empty or whitespace, or when the agent with the specified name was not found. /// The agent with the specified name was not found. public static async Task GetAIAgentAsync( this AgentsClient agentsClient, - string model, string name, ChatOptions? chatOptions = null, Func? clientFactory = null, @@ -133,30 +122,27 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNullOrWhitespace(name); var agentRecord = (await agentsClient.GetAgentAsync(name, cancellationToken).ConfigureAwait(false)).Value ?? throw new InvalidOperationException($"Agent with name '{name}' not found."); - return GetAIAgent(agentsClient, model, agentRecord, chatOptions, clientFactory, openAIClientOptions, cancellationToken); + return GetAIAgent(agentsClient, agentRecord, chatOptions, clientFactory, openAIClientOptions, cancellationToken); } /// /// Gets a runnable agent instance from a containing metadata about an Azure AI Agent. /// /// The client used to interact with Azure AI Agents. Cannot be . - /// The model to be used by the agent. /// The agent record to be converted. The latest version will be used. Cannot be . /// Full set of options to configure the agent. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the latest version of the Azure AI Agent record. - /// Thrown when , , or is . + /// Thrown when , or is . public static ChatClientAgent GetAIAgent( this AgentsClient agentsClient, - string model, AgentRecord agentRecord, ChatClientAgentOptions? options = null, Func? clientFactory = null, @@ -164,12 +150,10 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNull(agentRecord); return GetAIAgent( agentsClient, - model, agentRecord.Versions.Latest, options, clientFactory, @@ -181,17 +165,15 @@ public static class AgentsClientExtensions /// Gets a runnable agent instance from a containing metadata about an Azure AI Agent. /// /// The client used to interact with Azure AI Agents. Cannot be . - /// The model to be used by the agent. /// The agent version to be converted. Cannot be . /// Full set of options to configure the agent. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the provided version of the Azure AI Agent. - /// Thrown when , , or is . + /// Thrown when or is . public static ChatClientAgent GetAIAgent( this AgentsClient agentsClient, - string model, AgentVersion agentVersion, ChatClientAgentOptions? options = null, Func? clientFactory = null, @@ -199,8 +181,9 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNull(agentVersion); + + string model = (agentVersion.Definition as PromptAgentDefinition)?.Model ?? NoOpModel; IChatClient chatClient = new AzureAIAgentChatClient(agentsClient, agentVersion, model, openAIClientOptions); if (clientFactory is not null) @@ -216,7 +199,7 @@ public static class AgentsClientExtensions if (options is null) { agentOptions = new(); - agentOptions.Id = GetAgentId(agentVersion); + agentOptions.Id = agentVersion.Id; agentOptions.Name = agentVersion.Name; agentOptions.Description = version.Description; @@ -238,7 +221,7 @@ public static class AgentsClientExtensions // When agent options it is used when available otherwise fallback to the agent definition used for the agent record. agentOptions = new ChatClientAgentOptions() { - Id = options.Id ?? GetAgentId(agentVersion), + Id = options.Id ?? agentVersion.Id, Name = options.Name ?? agentVersion.Name, Description = options.Description ?? version.Description, Instructions = options.Instructions ?? options.ChatOptions?.Instructions ?? (version.Definition as PromptAgentDefinition)?.Instructions, @@ -268,7 +251,6 @@ public static class AgentsClientExtensions /// Retrieves an existing server side agent, wrapped as a using the provided . /// /// The to create the with. - /// The model to be used by the agent. /// 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. @@ -279,7 +261,6 @@ public static class AgentsClientExtensions /// Thrown when is empty or whitespace. public static async Task GetAIAgentAsync( this AgentsClient agentsClient, - string model, string name, ChatClientAgentOptions options, Func? clientFactory = null, @@ -293,15 +274,15 @@ public static class AgentsClientExtensions var agentRecord = await agentsClient.GetAgentAsync(name, cancellationToken).ConfigureAwait(false) ?? throw new InvalidOperationException($"Agent with name '{name}' not found."); - return GetAIAgent(agentsClient, model, agentRecord, options, clientFactory, openAIClientOptions, cancellationToken); + return GetAIAgent(agentsClient, agentRecord, options, clientFactory, openAIClientOptions, cancellationToken); } /// /// Creates a new server side agent using the provided . /// /// The to create the agent with. - /// The model to be used by the agent. /// The name of the agent. + /// The model to be used by the agent. /// The instructions for the agent. /// The description for the agent. /// The tools to be used by the agent. @@ -318,8 +299,8 @@ public static class AgentsClientExtensions /// A instance that can be used to perform operations on the newly created agent. public static ChatClientAgent CreateAIAgent( this AgentsClient agentsClient, - string model, string name, + string model, string? instructions = null, string? description = null, IList? tools = null, @@ -335,8 +316,8 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNullOrWhitespace(name); + Throw.IfNullOrWhitespace(model); var (promptAgentDefinition, versionCreationOptions, chatClientAgentOptions) = CreatePromptAgentDefinitionAndOptions( name, @@ -369,19 +350,16 @@ public static class AgentsClientExtensions /// The client used to manage and interact with AI agents. Cannot be . /// The name for the agent. /// The definition that specifies the configuration and behavior of the agent to create. Cannot be . - /// The name of the model to use for the agent. Model must be provided either directly or as part of a specialization property. /// Settings that control the creation of the agent. /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. /// A token to monitor for cancellation requests. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when or is . - /// Thrown if neither the 'model' parameter nor a model in the agent definition is provided. public static ChatClientAgent CreateAIAgent( this AgentsClient agentsClient, string name, AgentDefinition agentDefinition, - string? model = null, AgentCreationOptions? creationOptions = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, @@ -391,11 +369,7 @@ public static class AgentsClientExtensions Throw.IfNullOrWhitespace(name); Throw.IfNull(agentDefinition); - model ??= (agentDefinition as PromptAgentDefinition)?.Model; - if (string.IsNullOrWhiteSpace(model)) - { - throw new ArgumentException("Model must be provided either directly or as part of a PromptAgentDefinition specialization.", nameof(model)); - } + string model = (agentDefinition as PromptAgentDefinition)?.Model ?? NoOpModel; AgentRecord agentRecord = agentsClient.CreateAgent(name, agentDefinition, creationOptions, cancellationToken); IChatClient chatClient = new AzureAIAgentChatClient(agentsClient, agentRecord, model, openAIClientOptions); @@ -412,25 +386,25 @@ public static class AgentsClientExtensions /// Creates a new Prompt AI Agent using the provided and options. /// /// The client used to manage and interact with AI agents. Cannot be . - /// The name of the model to use for the agent. Cannot be or whitespace. /// The options for creating the agent. Cannot be . + /// The name of the model to use for the agent. Cannot be or whitespace. /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. /// A to cancel the operation if needed. /// A instance that can be used to perform operations on the newly created agent. - /// Thrown when , , or is . + /// Thrown when or is . /// Thrown when is empty or whitespace, or when the agent name is not provided in the options. public static ChatClientAgent CreateAIAgent( this AgentsClient agentsClient, - string model, ChatClientAgentOptions options, + string model, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); - Throw.IfNullOrWhitespace(model); Throw.IfNull(options); + Throw.IfNullOrWhitespace(model); if (string.IsNullOrWhiteSpace(options.Name)) { @@ -459,7 +433,7 @@ public static class AgentsClientExtensions chatClient = clientFactory(chatClient); } - chatClientAgentOptions.Id = GetAgentId(agentVersion); + chatClientAgentOptions.Id = agentVersion.Id; return new ChatClientAgent(chatClient, chatClientAgentOptions); } @@ -470,7 +444,6 @@ public static class AgentsClientExtensions /// /// The client used to manage and interact with AI agents. Cannot be . /// The definition that specifies the configuration and behavior of the agent to create. Cannot be . - /// The name of the model to use for the agent. If not specified, the model must be provided as part of the agent definition. /// The name for the agent. /// Settings that control the creation of the agent. /// A factory function to customize the creation of the chat client used by the agent. @@ -478,11 +451,9 @@ public static class AgentsClientExtensions /// A token to monitor for cancellation requests. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when or is . - /// Thrown if neither the 'model' parameter nor a model in the agent definition is provided. public static async Task CreateAIAgentAsync( this AgentsClient agentsClient, AgentDefinition agentDefinition, - string? model = null, string? name = null, AgentVersionCreationOptions? agentVersionCreationOptions = null, Func? clientFactory = null, @@ -492,11 +463,7 @@ public static class AgentsClientExtensions Throw.IfNull(agentsClient); Throw.IfNull(agentDefinition); - model ??= (agentDefinition as PromptAgentDefinition)?.Model; - if (string.IsNullOrWhiteSpace(model)) - { - throw new ArgumentException("Model must be provided either directly or as part of a PromptAgentDefinition specialization.", nameof(model)); - } + string model = (agentDefinition as PromptAgentDefinition)?.Model ?? NoOpModel; AgentVersion agentVersion = await agentsClient.CreateAgentVersionAsync(name, agentDefinition, agentVersionCreationOptions, cancellationToken).ConfigureAwait(false); IChatClient chatClient = new AzureAIAgentChatClient(agentsClient, agentVersion, model, openAIClientOptions); @@ -514,7 +481,7 @@ public static class AgentsClientExtensions return new ChatClientAgent(chatClient, new ChatClientAgentOptions() { - Id = GetAgentId(agentVersion), + Id = agentVersion.Id, Name = name, Description = agentVersionCreationOptions?.Description, Instructions = (agentDefinition as PromptAgentDefinition)?.Instructions, @@ -529,8 +496,8 @@ public static class AgentsClientExtensions /// Creates a new server side prompt agent using the provided . /// /// The to create the agent with. - /// The model to be used by the agent. /// The name of the agent. + /// The model to be used by the agent. /// The instructions for the agent. /// The description for the agent. /// The tools to be used by the agent. @@ -547,8 +514,8 @@ public static class AgentsClientExtensions /// A instance that can be used to perform operations on the newly created agent. public static async Task CreateAIAgentAsync( this AgentsClient agentsClient, - string model, string name, + string model, string? instructions = null, string? description = null, IList? tools = null, @@ -564,6 +531,7 @@ public static class AgentsClientExtensions CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); + Throw.IfNullOrWhitespace(name); Throw.IfNullOrWhitespace(model); var (promptAgentDefinition, versionCreationOptions, chatClientAgentOptions) = CreatePromptAgentDefinitionAndOptions(name, model, instructions, description, temperature, topP, raiConfig, reasoningOptions, textOptions, tools, structuredInputs, metadata); @@ -576,13 +544,19 @@ public static class AgentsClientExtensions chatClient = clientFactory(chatClient); } - chatClientAgentOptions.Id = GetAgentId(agentVersion); + chatClientAgentOptions.Id = agentVersion.Id; return new ChatClientAgent(chatClient, chatClientAgentOptions); } #region Private + /// + /// The usage of a no-op model is a necessary change to avoid OpenAIClients to throw exceptions when + /// used with Azure AI Agents as the model used is now defined at the agent creation time. + /// + private const string NoOpModel = "no-op"; + private static (PromptAgentDefinition, AgentVersionCreationOptions?, ChatClientAgentOptions) CreatePromptAgentDefinitionAndOptions( string name, string model, @@ -660,9 +634,6 @@ public static class AgentsClientExtensions return (promptAgentDefinition, versionCreationOptions, chatClientAgentOptions); } - private static string GetAgentId(AgentVersion agentVersion) - => $"{agentVersion.Name}:{agentVersion.Id}"; - #endregion #region Polyfill from MEAI.OpenAI for AITool -> ResponseTool conversion diff --git a/dotnet/tests/Microsoft.Agents.AI.AzureAIAgents.UnitTests/AgentsClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.AzureAIAgents.UnitTests/AgentsClientExtensionsTests.cs index 793f75dc2d..83869d53c1 100644 --- a/dotnet/tests/Microsoft.Agents.AI.AzureAIAgents.UnitTests/AgentsClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.AzureAIAgents.UnitTests/AgentsClientExtensionsTests.cs @@ -33,62 +33,11 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - client!.GetAIAgent("model", agentRecord, chatOptions: null)); + client!.GetAIAgent(agentRecord, chatOptions: null)); Assert.Equal("agentsClient", exception.ParamName); } - /// - /// Verify that GetAIAgent throws ArgumentNullException when model is null. - /// - [Fact] - public void GetAIAgent_WithAgentRecord_WithNullModel_ThrowsArgumentNullException() - { - // Arrange - var mockClient = new Mock(); - AgentRecord agentRecord = this.CreateTestAgentRecord(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent(null!, agentRecord, chatOptions: null)); - - Assert.Equal("model", exception.ParamName); - } - - /// - /// Verify that GetAIAgent throws ArgumentException when model is empty. - /// - [Fact] - public void GetAIAgent_WithAgentRecord_WithEmptyModel_ThrowsArgumentException() - { - // Arrange - var mockClient = new Mock(); - AgentRecord agentRecord = this.CreateTestAgentRecord(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent(string.Empty, agentRecord, chatOptions: null)); - - Assert.Equal("model", exception.ParamName); - } - - /// - /// Verify that GetAIAgent throws ArgumentException when model is whitespace. - /// - [Fact] - public void GetAIAgent_WithAgentRecord_WithWhitespaceModel_ThrowsArgumentException() - { - // Arrange - var mockClient = new Mock(); - AgentRecord agentRecord = this.CreateTestAgentRecord(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent(" ", agentRecord, chatOptions: null)); - - Assert.Equal("model", exception.ParamName); - } - /// /// Verify that GetAIAgent throws ArgumentNullException when agentRecord is null. /// @@ -100,7 +49,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent("model", (AgentRecord)null!, chatOptions: null)); + mockClient.Object.GetAIAgent((AgentRecord)null!, chatOptions: null)); Assert.Equal("agentRecord", exception.ParamName); } @@ -116,7 +65,7 @@ public sealed class AgentsClientExtensionsTests AgentRecord agentRecord = this.CreateTestAgentRecord(); // Act - var agent = client.GetAIAgent("test-model", agentRecord, chatOptions: null); + var agent = client.GetAIAgent(agentRecord, chatOptions: null); // Assert Assert.NotNull(agent); @@ -136,7 +85,6 @@ public sealed class AgentsClientExtensionsTests // Act var agent = client.GetAIAgent( - "test-model", agentRecord, chatOptions: null, clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); @@ -164,28 +112,11 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - client!.GetAIAgent("model", agentVersion, chatOptions: null)); + client!.GetAIAgent(agentVersion, chatOptions: null)); Assert.Equal("agentsClient", exception.ParamName); } - /// - /// Verify that GetAIAgent throws ArgumentNullException when model is null. - /// - [Fact] - public void GetAIAgent_WithAgentVersion_WithNullModel_ThrowsArgumentNullException() - { - // Arrange - var mockClient = new Mock(); - AgentVersion agentVersion = this.CreateTestAgentVersion(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent(null!, agentVersion, chatOptions: null)); - - Assert.Equal("model", exception.ParamName); - } - /// /// Verify that GetAIAgent throws ArgumentNullException when agentVersion is null. /// @@ -197,7 +128,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent("model", (AgentVersion)null!, chatOptions: null)); + mockClient.Object.GetAIAgent((AgentVersion)null!, chatOptions: null)); Assert.Equal("agentVersion", exception.ParamName); } @@ -213,7 +144,7 @@ public sealed class AgentsClientExtensionsTests AgentVersion agentVersion = this.CreateTestAgentVersion(); // Act - var agent = client.GetAIAgent("test-model", agentVersion, chatOptions: null); + var agent = client.GetAIAgent(agentVersion, chatOptions: null); // Assert Assert.NotNull(agent); @@ -233,7 +164,6 @@ public sealed class AgentsClientExtensionsTests // Act var agent = client.GetAIAgent( - "test-model", agentVersion, chatOptions: null, clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); @@ -247,7 +177,7 @@ public sealed class AgentsClientExtensionsTests #endregion - #region GetAIAgent(AgentsClient, string, string) Tests + #region GetAIAgent(AgentsClient, string) Tests /// /// Verify that GetAIAgent throws ArgumentNullException when agentsClient is null. @@ -260,27 +190,11 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - client!.GetAIAgent("model", "test-agent", chatOptions: null)); + client!.GetAIAgent("test-agent", chatOptions: null)); Assert.Equal("agentsClient", exception.ParamName); } - /// - /// Verify that GetAIAgent throws ArgumentNullException when model is null. - /// - [Fact] - public void GetAIAgent_ByName_WithNullModel_ThrowsArgumentNullException() - { - // Arrange - var mockClient = new Mock(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent(null!, "test-agent", chatOptions: null)); - - Assert.Equal("model", exception.ParamName); - } - /// /// Verify that GetAIAgent throws ArgumentNullException when name is null. /// @@ -292,7 +206,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent("model", (string)null!, chatOptions: null)); + mockClient.Object.GetAIAgent((string)null!, chatOptions: null)); Assert.Equal("name", exception.ParamName); } @@ -308,7 +222,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent("model", string.Empty, chatOptions: null)); + mockClient.Object.GetAIAgent(string.Empty, chatOptions: null)); Assert.Equal("name", exception.ParamName); } @@ -326,14 +240,14 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.GetAIAgent("model", "non-existent-agent", chatOptions: null)); + mockClient.Object.GetAIAgent("non-existent-agent", chatOptions: null)); Assert.Contains("not found", exception.Message); } #endregion - #region GetAIAgentAsync(AgentsClient, string, string) Tests + #region GetAIAgentAsync(AgentsClient, string) Tests /// /// Verify that GetAIAgentAsync throws ArgumentNullException when agentsClient is null. @@ -346,27 +260,11 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = await Assert.ThrowsAsync(() => - client!.GetAIAgentAsync("model", "test-agent")); + client!.GetAIAgentAsync("test-agent")); Assert.Equal("agentsClient", exception.ParamName); } - /// - /// Verify that GetAIAgentAsync throws ArgumentNullException when model is null. - /// - [Fact] - public async Task GetAIAgentAsync_ByName_WithNullModel_ThrowsArgumentNullExceptionAsync() - { - // Arrange - var mockClient = new Mock(); - - // Act & Assert - var exception = await Assert.ThrowsAsync(() => - mockClient.Object.GetAIAgentAsync(null!, "test-agent")); - - Assert.Equal("model", exception.ParamName); - } - /// /// Verify that GetAIAgentAsync throws ArgumentNullException when name is null. /// @@ -378,7 +276,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = await Assert.ThrowsAsync(() => - mockClient.Object.GetAIAgentAsync("model", null!)); + mockClient.Object.GetAIAgentAsync(null!)); Assert.Equal("name", exception.ParamName); } @@ -396,14 +294,14 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = await Assert.ThrowsAsync(() => - mockClient.Object.GetAIAgentAsync("model", "non-existent-agent")); + mockClient.Object.GetAIAgentAsync("non-existent-agent")); Assert.Contains("not found", exception.Message); } #endregion - #region GetAIAgent(AgentsClient, string, AgentRecord, ChatClientAgentOptions) Tests + #region GetAIAgent(AgentsClient, AgentRecord, ChatClientAgentOptions) Tests /// /// Verify that GetAIAgent with options uses provided options correctly. @@ -422,7 +320,7 @@ public sealed class AgentsClientExtensionsTests }; // Act - var agent = client.GetAIAgent("test-model", agentRecord, options); + var agent = client.GetAIAgent(agentRecord, options); // Assert Assert.NotNull(agent); @@ -442,7 +340,7 @@ public sealed class AgentsClientExtensionsTests AgentRecord agentRecord = this.CreateTestAgentRecord(); // Act - var agent = client.GetAIAgent("test-model", agentRecord, options: null); + var agent = client.GetAIAgent(agentRecord, options: null); // Assert Assert.NotNull(agent); @@ -451,7 +349,7 @@ public sealed class AgentsClientExtensionsTests #endregion - #region GetAIAgentAsync(AgentsClient, string, string, ChatClientAgentOptions) Tests + #region GetAIAgentAsync(AgentsClient, string, ChatClientAgentOptions) Tests /// /// Verify that GetAIAgentAsync throws ArgumentNullException when options is null. @@ -464,7 +362,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = await Assert.ThrowsAsync(() => - mockClient.Object.GetAIAgentAsync("model", "test-agent", (ChatClientAgentOptions)null!)); + mockClient.Object.GetAIAgentAsync("test-agent", (ChatClientAgentOptions)null!)); Assert.Equal("options", exception.ParamName); } @@ -484,27 +382,11 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - client!.CreateAIAgent("model", "test-agent")); + client!.CreateAIAgent("test-agent", "model")); Assert.Equal("agentsClient", exception.ParamName); } - /// - /// Verify that CreateAIAgent throws ArgumentNullException when model is null. - /// - [Fact] - public void CreateAIAgent_WithBasicParams_WithNullModel_ThrowsArgumentNullException() - { - // Arrange - var mockClient = new Mock(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.CreateAIAgent(null!, "test-agent")); - - Assert.Equal("model", exception.ParamName); - } - /// /// Verify that CreateAIAgent throws ArgumentNullException when name is null. /// @@ -516,7 +398,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.CreateAIAgent("model", (string)null!)); + mockClient.Object.CreateAIAgent((string)null!, "model")); Assert.Equal("name", exception.ParamName); } @@ -575,26 +457,9 @@ public sealed class AgentsClientExtensionsTests Assert.Equal("agentDefinition", exception.ParamName); } - /// - /// Verify that CreateAIAgent throws ArgumentException when model is not provided. - /// - [Fact] - public void CreateAIAgent_WithAgentDefinition_WithoutModel_ThrowsArgumentNullException() - { - // Arrange - AgentsClient client = this.CreateTestAgentsClient(); - var definition = new PromptAgentDefinition(""); - - // Act & Assert - var exception = Assert.Throws(() => - client.CreateAIAgent("test-agent", definition, model: null)); - - Assert.Contains("Model must be provided", exception.Message); - } - #endregion - #region CreateAIAgent(AgentsClient, string, ChatClientAgentOptions) Tests + #region CreateAIAgent(AgentsClient, ChatClientAgentOptions, string) Tests /// /// Verify that CreateAIAgent throws ArgumentNullException when agentsClient is null. @@ -608,11 +473,27 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - client!.CreateAIAgent("model", options)); + client!.CreateAIAgent(options, "model")); Assert.Equal("agentsClient", exception.ParamName); } + /// + /// Verify that CreateAIAgent throws ArgumentNullException when options is null. + /// + [Fact] + public void CreateAIAgent_WithOptions_WithNullOptions_ThrowsArgumentNullException() + { + // Arrange + var mockClient = new Mock(); + + // Act & Assert + var exception = Assert.Throws(() => + mockClient.Object.CreateAIAgent((ChatClientAgentOptions)null!, "model")); + + Assert.Equal("options", exception.ParamName); + } + /// /// Verify that CreateAIAgent throws ArgumentNullException when model is null. /// @@ -625,27 +506,11 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - mockClient.Object.CreateAIAgent(null!, options)); + mockClient.Object.CreateAIAgent(options, null!)); Assert.Equal("model", exception.ParamName); } - /// - /// Verify that CreateAIAgent throws ArgumentNullException when options is null. - /// - [Fact] - public void CreateAIAgent_WithOptions_WithNullOptions_ThrowsArgumentNullException() - { - // Arrange - var mockClient = new Mock(); - - // Act & Assert - var exception = Assert.Throws(() => - mockClient.Object.CreateAIAgent("model", (ChatClientAgentOptions)null!)); - - Assert.Equal("options", exception.ParamName); - } - /// /// Verify that CreateAIAgent throws ArgumentNullException when options.Name is null. /// @@ -658,7 +523,7 @@ public sealed class AgentsClientExtensionsTests // Act & Assert var exception = Assert.Throws(() => - client.CreateAIAgent("test-model", options)); + client.CreateAIAgent(options, "test-model")); Assert.Contains("Agent name must be provided", exception.Message); } @@ -700,23 +565,6 @@ public sealed class AgentsClientExtensionsTests Assert.Equal("agentDefinition", exception.ParamName); } - /// - /// Verify that CreateAIAgentAsync throws ArgumentException when model is not provided. - /// - [Fact] - public async Task CreateAIAgentAsync_WithAgentDefinition_WithoutModel_ThrowsExceptionAsync() - { - // Arrange - AgentsClient client = this.CreateTestAgentsClient(); - var definition = new PromptAgentDefinition(""); - - // Act & Assert - var exception = await Assert.ThrowsAsync(() => - client.CreateAIAgentAsync(definition, model: null)); - - Assert.Contains("Model must be provided", exception.Message); - } - #endregion #region Helper Methods