diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/PersistentAgentsClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/PersistentAgentsClientExtensions.cs
index ddb1ee7840..a05fca18ba 100644
--- a/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/PersistentAgentsClientExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.AzureAI.Persistent/PersistentAgentsClientExtensions.cs
@@ -17,15 +17,21 @@ public static class PersistentAgentsClientExtensions
/// The response containing the persistent agent 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 to use for resolving services required by the instances being invoked.
/// A instance that can be used to perform operations on the persistent agent.
- public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentAgentsClient, Response persistentAgentResponse, ChatOptions? chatOptions = null, Func? clientFactory = null)
+ public static ChatClientAgent GetAIAgent(
+ this PersistentAgentsClient persistentAgentsClient,
+ Response persistentAgentResponse,
+ ChatOptions? chatOptions = null,
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (persistentAgentResponse is null)
{
throw new ArgumentNullException(nameof(persistentAgentResponse));
}
- return GetAIAgent(persistentAgentsClient, persistentAgentResponse.Value, chatOptions, clientFactory);
+ return GetAIAgent(persistentAgentsClient, persistentAgentResponse.Value, chatOptions, clientFactory, services);
}
///
@@ -35,8 +41,14 @@ public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentA
/// The persistent agent metadata 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 to use for resolving services required by the instances being invoked.
/// A instance that can be used to perform operations on the persistent agent.
- public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentAgentsClient, PersistentAgent persistentAgentMetadata, ChatOptions? chatOptions = null, Func? clientFactory = null)
+ public static ChatClientAgent GetAIAgent(
+ this PersistentAgentsClient persistentAgentsClient,
+ PersistentAgent persistentAgentMetadata,
+ ChatOptions? chatOptions = null,
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (persistentAgentMetadata is null)
{
@@ -62,7 +74,7 @@ public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentA
Description = persistentAgentMetadata.Description,
Instructions = persistentAgentMetadata.Instructions,
ChatOptions = chatOptions
- });
+ }, services: services);
}
///
@@ -73,6 +85,7 @@ public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentA
/// 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 persistent agent.
public static ChatClientAgent GetAIAgent(
@@ -80,6 +93,7 @@ public static ChatClientAgent GetAIAgent(
string agentId,
ChatOptions? chatOptions = null,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -93,7 +107,7 @@ public static ChatClientAgent GetAIAgent(
}
var persistentAgentResponse = persistentAgentsClient.Administration.GetAgent(agentId, cancellationToken);
- return persistentAgentsClient.GetAIAgent(persistentAgentResponse, chatOptions, clientFactory);
+ return persistentAgentsClient.GetAIAgent(persistentAgentResponse, chatOptions, clientFactory, services);
}
///
@@ -104,6 +118,7 @@ public static ChatClientAgent GetAIAgent(
/// 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 persistent agent.
public static async Task GetAIAgentAsync(
@@ -111,6 +126,7 @@ public static async Task GetAIAgentAsync(
string agentId,
ChatOptions? chatOptions = null,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -124,7 +140,7 @@ public static async Task GetAIAgentAsync(
}
var persistentAgentResponse = await persistentAgentsClient.Administration.GetAgentAsync(agentId, cancellationToken).ConfigureAwait(false);
- return persistentAgentsClient.GetAIAgent(persistentAgentResponse, chatOptions, clientFactory);
+ return persistentAgentsClient.GetAIAgent(persistentAgentResponse, chatOptions, clientFactory, services);
}
///
@@ -134,16 +150,22 @@ public static async Task GetAIAgentAsync(
/// The response containing the persistent agent 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 to use for resolving services required by the instances being invoked.
/// A instance that can be used to perform operations on the persistent agent.
/// Thrown when or is .
- public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentAgentsClient, Response persistentAgentResponse, ChatClientAgentOptions options, Func? clientFactory = null)
+ public static ChatClientAgent GetAIAgent(
+ this PersistentAgentsClient persistentAgentsClient,
+ Response persistentAgentResponse,
+ ChatClientAgentOptions options,
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (persistentAgentResponse is null)
{
throw new ArgumentNullException(nameof(persistentAgentResponse));
}
- return GetAIAgent(persistentAgentsClient, persistentAgentResponse.Value, options, clientFactory);
+ return GetAIAgent(persistentAgentsClient, persistentAgentResponse.Value, options, clientFactory, services);
}
///
@@ -153,9 +175,15 @@ public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentA
/// The persistent agent metadata 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 to use for resolving services required by the instances being invoked.
/// A instance that can be used to perform operations on the persistent agent.
/// Thrown when or is .
- public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentAgentsClient, PersistentAgent persistentAgentMetadata, ChatClientAgentOptions options, Func? clientFactory = null)
+ public static ChatClientAgent GetAIAgent(
+ this PersistentAgentsClient persistentAgentsClient,
+ PersistentAgent persistentAgentMetadata,
+ ChatClientAgentOptions options,
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (persistentAgentMetadata is null)
{
@@ -191,7 +219,7 @@ public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentA
UseProvidedChatClientAsIs = options.UseProvidedChatClientAsIs
};
- return new ChatClientAgent(chatClient, agentOptions);
+ return new ChatClientAgent(chatClient, agentOptions, services: services);
}
///
@@ -201,6 +229,7 @@ public static ChatClientAgent GetAIAgent(this PersistentAgentsClient persistentA
/// 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 persistent agent.
/// Thrown when or is .
@@ -210,6 +239,7 @@ public static ChatClientAgent GetAIAgent(
string agentId,
ChatClientAgentOptions options,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -228,7 +258,7 @@ public static ChatClientAgent GetAIAgent(
}
var persistentAgentResponse = persistentAgentsClient.Administration.GetAgent(agentId, cancellationToken);
- return persistentAgentsClient.GetAIAgent(persistentAgentResponse, options, clientFactory);
+ return persistentAgentsClient.GetAIAgent(persistentAgentResponse, options, clientFactory, services);
}
///
@@ -238,6 +268,7 @@ public static ChatClientAgent GetAIAgent(
/// 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 persistent agent.
/// Thrown when or is .
@@ -247,6 +278,7 @@ public static async Task GetAIAgentAsync(
string agentId,
ChatClientAgentOptions options,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -265,7 +297,7 @@ public static async Task GetAIAgentAsync(
}
var persistentAgentResponse = await persistentAgentsClient.Administration.GetAgentAsync(agentId, cancellationToken).ConfigureAwait(false);
- return persistentAgentsClient.GetAIAgent(persistentAgentResponse, options, clientFactory);
+ return persistentAgentsClient.GetAIAgent(persistentAgentResponse, options, clientFactory, services);
}
///
@@ -283,6 +315,7 @@ public static async Task GetAIAgentAsync(
/// The response format for the agent.
/// The metadata for 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 newly created agent.
public static async Task CreateAIAgentAsync(
@@ -298,6 +331,7 @@ public static async Task CreateAIAgentAsync(
BinaryData? responseFormat = null,
IReadOnlyDictionary? metadata = null,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -319,7 +353,7 @@ public static async Task CreateAIAgentAsync(
cancellationToken: cancellationToken).ConfigureAwait(false);
// Get a local proxy for the agent to work with.
- return await persistentAgentsClient.GetAIAgentAsync(createPersistentAgentResponse.Value.Id, clientFactory: clientFactory, cancellationToken: cancellationToken).ConfigureAwait(false);
+ return await persistentAgentsClient.GetAIAgentAsync(createPersistentAgentResponse.Value.Id, clientFactory: clientFactory, services: services, cancellationToken: cancellationToken).ConfigureAwait(false);
}
///
@@ -337,6 +371,7 @@ public static async Task CreateAIAgentAsync(
/// The response format for the agent.
/// The metadata for 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 newly created agent.
public static ChatClientAgent CreateAIAgent(
@@ -352,6 +387,7 @@ public static ChatClientAgent CreateAIAgent(
BinaryData? responseFormat = null,
IReadOnlyDictionary? metadata = null,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -373,7 +409,7 @@ public static ChatClientAgent CreateAIAgent(
cancellationToken: cancellationToken);
// Get a local proxy for the agent to work with.
- return persistentAgentsClient.GetAIAgent(createPersistentAgentResponse.Value.Id, clientFactory: clientFactory, cancellationToken: cancellationToken);
+ return persistentAgentsClient.GetAIAgent(createPersistentAgentResponse.Value.Id, clientFactory: clientFactory, services: services, cancellationToken: cancellationToken);
}
///
@@ -383,6 +419,7 @@ public static ChatClientAgent CreateAIAgent(
/// The model to be used by the agent.
/// 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 newly created agent.
/// Thrown when or or is .
@@ -392,6 +429,7 @@ public static ChatClientAgent CreateAIAgent(
string model,
ChatClientAgentOptions options,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -431,7 +469,7 @@ public static ChatClientAgent CreateAIAgent(
}
// Get a local proxy for the agent to work with.
- return persistentAgentsClient.GetAIAgent(createPersistentAgentResponse.Value.Id, options, clientFactory: clientFactory, cancellationToken: cancellationToken);
+ return persistentAgentsClient.GetAIAgent(createPersistentAgentResponse.Value.Id, options, clientFactory: clientFactory, services: services, cancellationToken: cancellationToken);
}
///
@@ -441,6 +479,7 @@ public static ChatClientAgent CreateAIAgent(
/// The model to be used by the agent.
/// 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 newly created agent.
/// Thrown when or or is .
@@ -450,6 +489,7 @@ public static async Task CreateAIAgentAsync(
string model,
ChatClientAgentOptions options,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (persistentAgentsClient is null)
@@ -489,7 +529,7 @@ public static async Task CreateAIAgentAsync(
}
// Get a local proxy for the agent to work with.
- return await persistentAgentsClient.GetAIAgentAsync(createPersistentAgentResponse.Value.Id, options, clientFactory: clientFactory, cancellationToken: cancellationToken).ConfigureAwait(false);
+ return await persistentAgentsClient.GetAIAgentAsync(createPersistentAgentResponse.Value.Id, options, clientFactory: clientFactory, services: services, cancellationToken: cancellationToken).ConfigureAwait(false);
}
private static (List? ToolDefinitions, ToolResources? ToolResources, List? FunctionToolsAndOtherTools) ConvertAIToolsToToolDefinitions(IList? tools)
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs
index 07cb47da81..a36f6957b8 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIAssistantClientExtensions.cs
@@ -28,19 +28,21 @@ public static class OpenAIAssistantClientExtensions
/// 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.
public static ChatClientAgent GetAIAgent(
this AssistantClient assistantClient,
ClientResult assistantClientResult,
ChatOptions? chatOptions = null,
- Func? clientFactory = null)
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (assistantClientResult is null)
{
throw new ArgumentNullException(nameof(assistantClientResult));
}
- return assistantClient.GetAIAgent(assistantClientResult.Value, chatOptions, clientFactory);
+ return assistantClient.GetAIAgent(assistantClientResult.Value, chatOptions, clientFactory, services);
}
///
@@ -50,12 +52,14 @@ public static ChatClientAgent GetAIAgent(
/// 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.
public static ChatClientAgent GetAIAgent(
this AssistantClient assistantClient,
Assistant assistantMetadata,
ChatOptions? chatOptions = null,
- Func? clientFactory = null)
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (assistantMetadata is null)
{
@@ -80,7 +84,7 @@ public static ChatClientAgent GetAIAgent(
Description = assistantMetadata.Description,
Instructions = assistantMetadata.Instructions,
ChatOptions = chatOptions
- });
+ }, services: services);
}
///
@@ -90,6 +94,7 @@ public static ChatClientAgent GetAIAgent(
/// 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.
public static ChatClientAgent GetAIAgent(
@@ -97,6 +102,7 @@ public static ChatClientAgent GetAIAgent(
string agentId,
ChatOptions? chatOptions = null,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (assistantClient is null)
@@ -110,7 +116,7 @@ public static ChatClientAgent GetAIAgent(
}
var assistant = assistantClient.GetAssistant(agentId, cancellationToken);
- return assistantClient.GetAIAgent(assistant, chatOptions, clientFactory);
+ return assistantClient.GetAIAgent(assistant, chatOptions, clientFactory, services);
}
///
@@ -120,6 +126,7 @@ public static ChatClientAgent GetAIAgent(
/// 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.
public static async Task GetAIAgentAsync(
@@ -127,6 +134,7 @@ public static async Task GetAIAgentAsync(
string agentId,
ChatOptions? chatOptions = null,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (assistantClient is null)
@@ -140,7 +148,7 @@ public static async Task GetAIAgentAsync(
}
var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
- return assistantClient.GetAIAgent(assistantResponse, chatOptions, clientFactory);
+ return assistantClient.GetAIAgent(assistantResponse, chatOptions, clientFactory, services);
}
///
@@ -150,20 +158,22 @@ public static async Task GetAIAgentAsync(
/// 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 .
public static ChatClientAgent GetAIAgent(
this AssistantClient assistantClient,
ClientResult assistantClientResult,
ChatClientAgentOptions options,
- Func? clientFactory = null)
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (assistantClientResult is null)
{
throw new ArgumentNullException(nameof(assistantClientResult));
}
- return assistantClient.GetAIAgent(assistantClientResult.Value, options, clientFactory);
+ return assistantClient.GetAIAgent(assistantClientResult.Value, options, clientFactory, services);
}
///
@@ -173,13 +183,15 @@ public static ChatClientAgent GetAIAgent(
/// 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 .
public static ChatClientAgent GetAIAgent(
this AssistantClient assistantClient,
Assistant assistantMetadata,
ChatClientAgentOptions options,
- Func? clientFactory = null)
+ Func? clientFactory = null,
+ IServiceProvider? services = null)
{
if (assistantMetadata is null)
{
@@ -215,7 +227,7 @@ public static ChatClientAgent GetAIAgent(
UseProvidedChatClientAsIs = options.UseProvidedChatClientAsIs
};
- return new ChatClientAgent(chatClient, mergedOptions);
+ return new ChatClientAgent(chatClient, mergedOptions, services: services);
}
///
@@ -225,6 +237,7 @@ public static ChatClientAgent GetAIAgent(
/// 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 .
@@ -234,6 +247,7 @@ public static ChatClientAgent GetAIAgent(
string agentId,
ChatClientAgentOptions options,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (assistantClient is null)
@@ -252,7 +266,7 @@ public static ChatClientAgent GetAIAgent(
}
var assistant = assistantClient.GetAssistant(agentId, cancellationToken);
- return assistantClient.GetAIAgent(assistant, options, clientFactory);
+ return assistantClient.GetAIAgent(assistant, options, clientFactory, services);
}
///
@@ -262,6 +276,7 @@ public static ChatClientAgent GetAIAgent(
/// 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 .
@@ -271,6 +286,7 @@ public static async Task GetAIAgentAsync(
string agentId,
ChatClientAgentOptions options,
Func? clientFactory = null,
+ IServiceProvider? services = null,
CancellationToken cancellationToken = default)
{
if (assistantClient is null)
@@ -289,7 +305,7 @@ public static async Task GetAIAgentAsync(
}
var assistantResponse = await assistantClient.GetAssistantAsync(agentId, cancellationToken).ConfigureAwait(false);
- return assistantClient.GetAIAgent(assistantResponse, options, clientFactory);
+ return assistantClient.GetAIAgent(assistantResponse, options, clientFactory, services);
}
///
@@ -303,6 +319,7 @@ public static async Task GetAIAgentAsync(
/// 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.
/// An instance backed by the OpenAI Assistant service.
/// Thrown when or is .
/// Thrown when is empty or whitespace.
@@ -314,7 +331,8 @@ public static ChatClientAgent CreateAIAgent(
string? description = null,
IList? tools = null,
Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null) =>
+ ILoggerFactory? loggerFactory = null,
+ IServiceProvider? services = null) =>
client.CreateAIAgent(
model,
new ChatClientAgentOptions()
@@ -328,7 +346,8 @@ public static ChatClientAgent CreateAIAgent(
}
},
clientFactory,
- loggerFactory);
+ loggerFactory,
+ services);
///
/// Creates an AI agent from an using the OpenAI Assistant API.
@@ -338,6 +357,7 @@ public static ChatClientAgent CreateAIAgent(
/// 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.
/// An instance backed by the OpenAI Assistant service.
/// Thrown when or or is .
/// Thrown when is empty or whitespace.
@@ -346,7 +366,8 @@ public static ChatClientAgent CreateAIAgent(
string model,
ChatClientAgentOptions options,
Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null)
+ ILoggerFactory? loggerFactory = null,
+ IServiceProvider? services = null)
{
Throw.IfNull(client);
Throw.IfNullOrEmpty(model);
@@ -387,7 +408,7 @@ public static ChatClientAgent CreateAIAgent(
options.ChatOptions ??= new ChatOptions();
options.ChatOptions!.Tools = toolDefinitionsAndResources.FunctionToolsAndOtherTools;
- return new ChatClientAgent(chatClient, agentOptions, loggerFactory);
+ return new ChatClientAgent(chatClient, agentOptions, loggerFactory, services);
}
///
@@ -401,6 +422,8 @@ public static ChatClientAgent CreateAIAgent(
/// 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.
@@ -412,7 +435,9 @@ public static async Task CreateAIAgentAsync(
string? description = null,
IList? tools = null,
Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null) =>
+ ILoggerFactory? loggerFactory = null,
+ IServiceProvider? services = null,
+ CancellationToken cancellationToken = default) =>
await client.CreateAIAgentAsync(model,
new ChatClientAgentOptions()
{
@@ -425,7 +450,9 @@ await client.CreateAIAgentAsync(model,
}
},
clientFactory,
- loggerFactory).ConfigureAwait(false);
+ loggerFactory,
+ services,
+ cancellationToken).ConfigureAwait(false);
///
/// Creates an AI agent from an using the OpenAI Assistant API.
@@ -435,6 +462,8 @@ await client.CreateAIAgentAsync(model,
/// 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.
@@ -443,7 +472,9 @@ public static async Task CreateAIAgentAsync(
string model,
ChatClientAgentOptions options,
Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null)
+ ILoggerFactory? loggerFactory = null,
+ IServiceProvider? services = null,
+ CancellationToken cancellationToken = default)
{
Throw.IfNull(client);
Throw.IfNull(model);
@@ -468,7 +499,7 @@ public static async Task CreateAIAgentAsync(
}
// Create the assistant in the assistant service.
- var assistantCreateResult = await client.CreateAssistantAsync(model, assistantOptions).ConfigureAwait(false);
+ var assistantCreateResult = await client.CreateAssistantAsync(model, assistantOptions, cancellationToken).ConfigureAwait(false);
var assistantId = assistantCreateResult.Value.Id;
// Build the local agent object.
@@ -483,7 +514,7 @@ public static async Task CreateAIAgentAsync(
options.ChatOptions ??= new ChatOptions();
options.ChatOptions!.Tools = toolDefinitionsAndResources.FunctionToolsAndOtherTools;
- return new ChatClientAgent(chatClient, agentOptions, loggerFactory);
+ return new ChatClientAgent(chatClient, agentOptions, loggerFactory, services);
}
private static (List? ToolDefinitions, ToolResources? ToolResources, List? FunctionToolsAndOtherTools) ConvertAIToolsToToolDefinitions(IList? tools)
diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIResponseClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIResponseClientExtensions.cs
index c9f2743229..a4375052ed 100644
--- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIResponseClientExtensions.cs
+++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/Extensions/OpenAIResponseClientExtensions.cs
@@ -30,6 +30,7 @@ public static class OpenAIResponseClientExtensions
/// 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.
/// An instance backed by the OpenAI Response service.
/// Thrown when is .
public static ChatClientAgent CreateAIAgent(
@@ -39,7 +40,8 @@ public static ChatClientAgent CreateAIAgent(
string? description = null,
IList? tools = null,
Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null)
+ ILoggerFactory? loggerFactory = null,
+ IServiceProvider? services = null)
{
Throw.IfNull(client);
@@ -55,7 +57,8 @@ public static ChatClientAgent CreateAIAgent(
}
},
clientFactory,
- loggerFactory);
+ loggerFactory,
+ services);
}
///
@@ -65,13 +68,15 @@ public static ChatClientAgent CreateAIAgent(
/// 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.
/// An instance backed by the OpenAI Response service.
/// Thrown when or is .
public static ChatClientAgent CreateAIAgent(
this OpenAIResponseClient client,
ChatClientAgentOptions options,
Func? clientFactory = null,
- ILoggerFactory? loggerFactory = null)
+ ILoggerFactory? loggerFactory = null,
+ IServiceProvider? services = null)
{
Throw.IfNull(client);
Throw.IfNull(options);
@@ -83,6 +88,6 @@ public static ChatClientAgent CreateAIAgent(
chatClient = clientFactory(chatClient);
}
- return new ChatClientAgent(chatClient, options, loggerFactory);
+ return new ChatClientAgent(chatClient, options, loggerFactory, services);
}
}
diff --git a/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs
index 56b89d2df8..8d35f7f0b7 100644
--- a/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs
@@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Azure;
@@ -726,6 +727,159 @@ public async Task CreateAIAgentAsync_WithEmptyModel_ThrowsArgumentExceptionAsync
Assert.Equal("model", exception.ParamName);
}
+ ///
+ /// Verify that CreateAIAgent with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithServices_PassesServicesToAgent()
+ {
+ // Arrange
+ var client = CreateFakePersistentAgentsClient();
+ var serviceProvider = new TestServiceProvider();
+ const string Model = "test-model";
+
+ // Act
+ var agent = client.CreateAIAgent(
+ Model,
+ 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 CreateAIAgentAsync with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public async Task CreateAIAgentAsync_WithServices_PassesServicesToAgentAsync()
+ {
+ // Arrange
+ var client = CreateFakePersistentAgentsClient();
+ var serviceProvider = new TestServiceProvider();
+ const string Model = "test-model";
+
+ // Act
+ var agent = await client.CreateAIAgentAsync(
+ Model,
+ 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 GetAIAgent with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public void GetAIAgent_WithServices_PassesServicesToAgent()
+ {
+ // Arrange
+ var client = CreateFakePersistentAgentsClient();
+ var serviceProvider = new TestServiceProvider();
+
+ // Act
+ var agent = client.GetAIAgent("agent_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 GetAIAgentAsync with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public async Task GetAIAgentAsync_WithServices_PassesServicesToAgentAsync()
+ {
+ // Arrange
+ var client = CreateFakePersistentAgentsClient();
+ var serviceProvider = new TestServiceProvider();
+
+ // Act
+ var agent = await client.GetAIAgentAsync("agent_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 void CreateAIAgent_WithClientFactoryAndServices_AppliesBothCorrectly()
+ {
+ // Arrange
+ var client = CreateFakePersistentAgentsClient();
+ var serviceProvider = new TestServiceProvider();
+ TestChatClient? testChatClient = null;
+ const string Model = "test-model";
+
+ // Act
+ var agent = client.CreateAIAgent(
+ Model,
+ instructions: "Test instructions",
+ name: "Test Agent",
+ clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient),
+ 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;
+ }
+
///
/// Test custom chat client that can be used to verify clientFactory functionality.
///
@@ -736,6 +890,14 @@ public TestChatClient(IChatClient innerClient) : base(innerClient)
}
}
+ ///
+ /// A simple test IServiceProvider implementation for testing.
+ ///
+ private sealed class TestServiceProvider : IServiceProvider
+ {
+ public object? GetService(Type serviceType) => null;
+ }
+
public sealed class FakePersistentAgentsAdministrationClient : PersistentAgentsAdministrationClient
{
public FakePersistentAgentsAdministrationClient()
@@ -761,7 +923,7 @@ private static PersistentAgentsClient CreateFakePersistentAgentsClient()
{
var client = new PersistentAgentsClient("https://any.com", DelegatedTokenCredential.Create((_, _) => new AccessToken()));
- ((System.Reflection.TypeInfo)typeof(PersistentAgentsClient)).DeclaredFields.First(f => f.Name == "_client")
+ ((TypeInfo)typeof(PersistentAgentsClient)).DeclaredFields.First(f => f.Name == "_client")
.SetValue(client, new FakePersistentAgentsAdministrationClient());
return client;
}
diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs
index 61e3f5ef57..c14582958b 100644
--- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs
@@ -4,6 +4,7 @@
using System.ClientModel;
using System.ClientModel.Primitives;
using System.IO;
+using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.AI;
@@ -455,6 +456,162 @@ public async Task GetAIAgentAsync_WithEmptyAgentId_ThrowsArgumentExceptionAsync(
Assert.Equal("agentId", exception.ParamName);
}
+ ///
+ /// Verify that CreateAIAgent with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithServices_PassesServicesToAgent()
+ {
+ // Arrange
+ var assistantClient = new TestAssistantClient();
+ var serviceProvider = new TestServiceProvider();
+ const string ModelId = "test-model";
+
+ // Act
+ var agent = assistantClient.CreateAIAgent(
+ 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 void CreateAIAgent_WithOptionsAndServices_PassesServicesToAgent()
+ {
+ // Arrange
+ var assistantClient = new TestAssistantClient();
+ var serviceProvider = new TestServiceProvider();
+ const string ModelId = "test-model";
+ var options = new ChatClientAgentOptions
+ {
+ Name = "Test Agent",
+ Instructions = "Test instructions"
+ };
+
+ // Act
+ var agent = assistantClient.CreateAIAgent(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 GetAIAgent with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public void GetAIAgent_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.GetAIAgent(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 void CreateAIAgent_WithClientFactoryAndServices_AppliesBothCorrectly()
+ {
+ // 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 = assistantClient.CreateAIAgent(
+ 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;
+ }
+
///
/// Creates a test AssistantClient implementation for testing.
///
@@ -488,6 +645,11 @@ 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();
diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIResponseClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIResponseClientExtensionsTests.cs
index 2612f4bfa9..11c42548da 100644
--- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIResponseClientExtensionsTests.cs
+++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIResponseClientExtensionsTests.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
@@ -167,4 +168,114 @@ public void CreateAIAgent_WithNullOptions_ThrowsArgumentNullException()
Assert.Equal("options", exception.ParamName);
}
+
+ ///
+ /// Verify that CreateAIAgent with services parameter correctly passes it through to the ChatClientAgent.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithServices_PassesServicesToAgent()
+ {
+ // Arrange
+ var responseClient = new TestOpenAIResponseClient();
+ var serviceProvider = new TestServiceProvider();
+
+ // Act
+ var agent = responseClient.CreateAIAgent(
+ 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 void CreateAIAgent_WithOptionsAndServices_PassesServicesToAgent()
+ {
+ // Arrange
+ var responseClient = new TestOpenAIResponseClient();
+ var serviceProvider = new TestServiceProvider();
+ var options = new ChatClientAgentOptions
+ {
+ Name = "Test Agent",
+ Instructions = "Test instructions"
+ };
+
+ // Act
+ var agent = responseClient.CreateAIAgent(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 CreateAIAgent with both clientFactory and services works correctly.
+ ///
+ [Fact]
+ public void CreateAIAgent_WithClientFactoryAndServices_AppliesBothCorrectly()
+ {
+ // Arrange
+ var responseClient = new TestOpenAIResponseClient();
+ var serviceProvider = new TestServiceProvider();
+ var testChatClient = new TestChatClient(responseClient.AsIChatClient());
+
+ // Act
+ var agent = responseClient.CreateAIAgent(
+ 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));
+ }
+
+ ///
+ /// A simple test IServiceProvider implementation for testing.
+ ///
+ private sealed class TestServiceProvider : IServiceProvider
+ {
+ public object? GetService(Type serviceType) => null;
+ }
+
+ ///
+ /// 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;
+ }
}