Skip to content

Commit 95a3264

Browse files
authored
Add ChatClientAgent constructor overload (#188)
* Add ChatClientAgent constructor overload * Add unit tests for new constructor * Up code coverage with extra tests * Address PR comments. * Address PR comment * Add additional test to increase code coverage.
1 parent e6d611a commit 95a3264

File tree

17 files changed

+276
-107
lines changed

17 files changed

+276
-107
lines changed

dotnet/samples/GettingStarted/GettingStarted.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<RootNamespace>GettingStarted</RootNamespace>
1010
<OutputType>Library</OutputType>
1111
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
12-
<NoWarn>$(NoWarn);CA1707;CA1716;IDE0009;IDE1006;</NoWarn>
12+
<NoWarn>$(NoWarn);CA1707;CA1716;IDE0009;IDE1006;OPENAI001;</NoWarn>
1313
<ImplicitUsings>enable</ImplicitUsings>
1414
<InjectSharedSamples>true</InjectSharedSamples>
1515
</PropertyGroup>

dotnet/samples/GettingStarted/Providers/ChatClientAgent_With_AzureOpenAIChatCompletion.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,7 @@ public async Task RunWithChatCompletion()
2929
.AsIChatClient();
3030

3131
// Define the agent
32-
ChatClientAgent agent =
33-
new(chatClient, new()
34-
{
35-
Name = JokerName,
36-
Instructions = JokerInstructions,
37-
});
32+
ChatClientAgent agent = new(chatClient, JokerInstructions, JokerName);
3833

3934
// Start a new thread for the agent conversation.
4035
AgentThread thread = agent.GetNewThread();

dotnet/samples/GettingStarted/Providers/ChatClientAgent_With_OpenAIChatCompletion.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,7 @@ public async Task RunWithChatCompletion()
2424
.AsIChatClient();
2525

2626
// Define the agent
27-
ChatClientAgent agent =
28-
new(chatClient, new()
29-
{
30-
Name = JokerName,
31-
Instructions = JokerInstructions,
32-
});
27+
ChatClientAgent agent = new(chatClient, JokerInstructions, JokerName);
3328

3429
// Start a new thread for the agent conversation.
3530
AgentThread thread = agent.GetNewThread();

dotnet/samples/GettingStarted/Providers/ChatClientAgent_With_OpenAIResponseChatCompletion.cs

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
using OpenAI;
77
using OpenAI.Responses;
88

9-
#pragma warning disable CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value.
10-
119
namespace Providers;
1210

1311
/// <summary>
@@ -18,29 +16,63 @@ public sealed class ChatClientAgent_With_OpenAIResponsesChatCompletion(ITestOutp
1816
private const string JokerName = "Joker";
1917
private const string JokerInstructions = "You are good at telling jokes.";
2018

21-
[Theory]
22-
[InlineData(false)] // This will use in-memory messages to store the thread state.
23-
[InlineData(true)] // This will use the conversation id to reference the thread state on the server side.
24-
public async Task RunWithChatCompletion(bool useConversationIdThread)
19+
/// <summary>
20+
/// This will use the conversation id to reference the thread state on the server side.
21+
/// </summary>
22+
[Fact]
23+
public async Task RunWithChatCompletionServiceManagedThread()
24+
{
25+
// Get the chat client to use for the agent.
26+
using var chatClient = new OpenAIClient(TestConfiguration.OpenAI.ApiKey)
27+
.GetOpenAIResponseClient(TestConfiguration.OpenAI.ChatModelId)
28+
.AsIChatClient();
29+
30+
// Define the agent
31+
ChatClientAgent agent = new(chatClient, JokerInstructions, JokerName);
32+
33+
// Start a new thread for the agent conversation based on the type.
34+
AgentThread thread = agent.GetNewThread();
35+
36+
// Respond to user input.
37+
await RunAgentAsync("Tell me a joke about a pirate.");
38+
await RunAgentAsync("Now add some emojis to the joke.");
39+
40+
// Local function to invoke agent and display the conversation messages for the thread.
41+
async Task RunAgentAsync(string input)
42+
{
43+
this.WriteUserMessage(input);
44+
45+
var response = await agent.RunAsync(input, thread);
46+
47+
this.WriteResponseOutput(response);
48+
}
49+
}
50+
51+
/// <summary>
52+
/// This will use in-memory messages to store the thread state.
53+
/// </summary>
54+
[Fact]
55+
public async Task RunWithChatCompletionInMemoryThread()
2556
{
2657
// Get the chat client to use for the agent.
27-
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
2858
using var chatClient = new OpenAIClient(TestConfiguration.OpenAI.ApiKey)
2959
.GetOpenAIResponseClient(TestConfiguration.OpenAI.ChatModelId)
3060
.AsIChatClient();
3161

3262
// Define the agent
3363
ChatClientAgent agent =
34-
new(chatClient, new()
64+
new(chatClient, options: new()
3565
{
3666
Name = JokerName,
3767
Instructions = JokerInstructions,
3868
ChatOptions = new ChatOptions
3969
{
40-
RawRepresentationFactory = (_) => new ResponseCreationOptions() { StoredOutputEnabled = useConversationIdThread }
70+
// We can use the RawRepresentationFactory to provide Response service specific
71+
// options. Here we can indicate that we do not want the service to store the
72+
// conversation in a service managed thread.
73+
RawRepresentationFactory = (_) => new ResponseCreationOptions() { StoredOutputEnabled = false }
4174
}
4275
});
43-
#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
4476

4577
// Start a new thread for the agent conversation based on the type.
4678
AgentThread thread = agent.GetNewThread();

dotnet/samples/GettingStarted/Steps/Step01_ChatClientAgent_Running.cs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,7 @@ public async Task RunBasic(ChatClientProviders provider)
3333
IChatClient chatClient = base.GetChatClient(provider);
3434

3535
// Define the agent
36-
Agent agent = new ChatClientAgent(chatClient, options: new()
37-
{
38-
Name = ParrotName,
39-
Instructions = ParrotInstructions,
40-
});
36+
Agent agent = new ChatClientAgent(chatClient, ParrotInstructions, ParrotName);
4137

4238
// Invoke the agent and output the text result.
4339
Console.WriteLine(await agent.RunAsync("Fortune favors the bold."));

dotnet/samples/GettingStarted/Steps/Step02_ChatClientAgent_UsingFunctionTools.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,33 @@ namespace Steps;
1212
/// </summary>
1313
public sealed class Step02_ChatClientAgent_UsingFunctionTools(ITestOutputHelper output) : AgentSample(output)
1414
{
15+
[Theory]
16+
[InlineData(ChatClientProviders.AzureOpenAI)]
17+
[InlineData(ChatClientProviders.OpenAIChatCompletion)]
18+
public async Task RunningWithToolsBasic(ChatClientProviders provider)
19+
{
20+
// Creating a MenuTools instance to be used by the agent.
21+
var menuTools = new MenuTools();
22+
23+
// Get the chat client to use for the agent.
24+
var chatClient = base.GetChatClient(provider);
25+
26+
// Define the agent and add the GetSpecials tool.
27+
var agent = new ChatClientAgent(
28+
chatClient,
29+
instructions: "Answer questions about the menu.",
30+
tools: [AIFunctionFactory.Create(menuTools.GetSpecials)]);
31+
32+
// Respond to user input, invoking functions where appropriate.
33+
Console.WriteLine(await agent.RunAsync("What is the special soup and its price?"));
34+
}
35+
1536
[Theory]
1637
[InlineData(ChatClientProviders.AzureOpenAI)]
1738
[InlineData(ChatClientProviders.OpenAIChatCompletion)]
1839
public async Task RunningWithTools(ChatClientProviders provider)
1940
{
20-
// Creating a Menu Tools to be used by the agent.
41+
// Creating a MenuTools instance to be used by the agent.
2142
var menuTools = new MenuTools();
2243

2344
// Define the options for the chat client agent.
@@ -65,7 +86,7 @@ async Task RunAgentAsync(string input)
6586
[InlineData(ChatClientProviders.OpenAIChatCompletion)]
6687
public async Task StreamingRunWithTools(ChatClientProviders provider)
6788
{
68-
// Creating a Menu Tools to be used by the agent.
89+
// Creating a MenuTools instance to be used by the agent.
6990
var menuTools = new MenuTools();
7091

7192
// Define the options for the chat client agent.

dotnet/samples/GettingStarted/Steps/Step03_ChatClientAgent_UsingCodeInterpreterTools.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ private async Task<string> UploadFileAsync(string filePath, ChatClientProviders
105105
/// <returns>The code interpreter output as a string.</returns>
106106
private static string? GetCodeInterpreterOutput(object rawRepresentation, ChatClientProviders provider)
107107
{
108-
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
109108
switch (provider)
110109
{
111110
case ChatClientProviders.OpenAIAssistant
@@ -114,7 +113,6 @@ private async Task<string> UploadFileAsync(string filePath, ChatClientProviders
114113
string.Empty,
115114
stepDetails.CodeInterpreterOutputs.SelectMany(l => l.Logs)
116115
)}";
117-
#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
118116

119117
case ChatClientProviders.AzureAIAgentsPersistent
120118
when rawRepresentation is Azure.AI.Agents.Persistent.RunStepDetailsUpdate stepDetails:

dotnet/src/Microsoft.Extensions.AI.Agents/ChatCompletion/ChatClientAgent.cs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,35 @@ public sealed class ChatClientAgent : Agent
2525
/// Initializes a new instance of the <see cref="ChatClientAgent"/> class.
2626
/// </summary>
2727
/// <param name="chatClient">The chat client to use for invoking the agent.</param>
28-
/// <param name="options">Optional agent options to configure the agent.</param>
28+
/// <param name="instructions">Optional instructions for the agent.</param>
29+
/// <param name="name">Optional name for the agent.</param>
30+
/// <param name="description">Optional description for the agent.</param>
31+
/// <param name="tools">Optional list of tools that the agent can use during invocation.</param>
2932
/// <param name="loggerFactory">Optional logger factory to use for logging.</param>
30-
public ChatClientAgent(IChatClient chatClient, ChatClientAgentOptions? options = null, ILoggerFactory? loggerFactory = null)
33+
public ChatClientAgent(IChatClient chatClient, string? instructions = null, string? name = null, string? description = null, IList<AITool>? tools = null, ILoggerFactory? loggerFactory = null)
34+
: this(
35+
chatClient,
36+
new ChatClientAgentOptions()
37+
{
38+
Name = name,
39+
Description = description,
40+
Instructions = instructions,
41+
ChatOptions = tools is null ? null : new ChatOptions()
42+
{
43+
Tools = tools,
44+
}
45+
},
46+
loggerFactory)
47+
{
48+
}
49+
50+
/// <summary>
51+
/// Initializes a new instance of the <see cref="ChatClientAgent"/> class.
52+
/// </summary>
53+
/// <param name="chatClient">The chat client to use for invoking the agent.</param>
54+
/// <param name="options">Full set of options to configure the agent.</param>
55+
/// <param name="loggerFactory">Optional logger factory to use for logging.</param>
56+
public ChatClientAgent(IChatClient chatClient, ChatClientAgentOptions options, ILoggerFactory? loggerFactory = null)
3157
{
3258
Throw.IfNull(chatClient);
3359

dotnet/tests/AzureAIAgentsPersistent.IntegrationTests/AzureAIAgentsPersistentFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public async Task<ChatClientAgent> CreateChatClientAgentAsync(
7373

7474
return new ChatClientAgent(
7575
this._persistentAgentsClient.AsIChatClient(persistentAgent.Id),
76-
new()
76+
options: new()
7777
{
7878
Id = persistentAgent.Id,
7979
ChatOptions = new() { Tools = aiTools }

0 commit comments

Comments
 (0)