// Copyright (c) Microsoft. All rights reserved. using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Agents; using Microsoft.SemanticKernel.ChatCompletion; using Resources; namespace GettingStarted; /// /// Demonstrate creation of and /// eliciting its response to three explicit user messages. /// public class Step01_Agent(ITestOutputHelper output) : BaseAgentsTest(output) { private const string ParrotName = "Parrot"; private const string ParrotInstructions = "Repeat the user message in the voice of a pirate and then end with a parrot sound."; private const string JokerName = "Joker"; private const string JokerInstructions = "You are good at telling jokes."; /// /// Demonstrate the usage of where each invocation is /// a unique interaction with no conversation history between them. /// [Theory] [InlineData(true)] [InlineData(false)] public async Task UseSingleChatCompletionAgent(bool useChatClient) { Kernel kernel = this.CreateKernelWithChatCompletion(useChatClient, out var chatClient); // Define the agent ChatCompletionAgent agent = new() { Name = ParrotName, Instructions = ParrotInstructions, Kernel = kernel }; // Respond to user input await InvokeAgentAsync("Fortune favors the bold."); await InvokeAgentAsync("I came, I saw, I conquered."); await InvokeAgentAsync("Practice makes perfect."); chatClient?.Dispose(); // Local function to invoke agent and display the conversation messages. async Task InvokeAgentAsync(string input) { ChatMessageContent message = new(AuthorRole.User, input); this.WriteAgentChatMessage(message); await foreach (AgentResponseItem response in agent.InvokeAsync(message)) { this.WriteAgentChatMessage(response); } } } /// /// Demonstrate the usage of where a conversation history is maintained. /// [Fact] public async Task UseSingleChatCompletionAgentWithConversation() { Kernel kernel = this.CreateKernelWithChatCompletion(); // Define the agent ChatCompletionAgent agent = new() { Name = JokerName, Instructions = JokerInstructions, Kernel = this.CreateKernelWithChatCompletion(), }; // Define a thread variable to maintain the conversation context. // Since we are passing a null thread to InvokeAsync on the first invocation, // the agent will create a new thread for the conversation. AgentThread? thread = null; // Respond to user input await InvokeAgentAsync("Tell me a joke about a pirate."); await InvokeAgentAsync("Now add some emojis to the joke."); // Local function to invoke agent and display the conversation messages. async Task InvokeAgentAsync(string input) { ChatMessageContent message = new(AuthorRole.User, input); this.WriteAgentChatMessage(message); await foreach (AgentResponseItem response in agent.InvokeAsync(message, thread)) { this.WriteAgentChatMessage(response); thread = response.Thread; } } } /// /// Demonstrate the usage of where a conversation history is maintained /// and where the thread containing the conversation is created manually. /// [Fact] public async Task UseSingleChatCompletionAgentWithManuallyCreatedThread() { Kernel kernel = this.CreateKernelWithChatCompletion(); // Define the agent ChatCompletionAgent agent = new() { Name = JokerName, Instructions = JokerInstructions, Kernel = this.CreateKernelWithChatCompletion(), }; // Define a thread variable to maintain the conversation context. // Since we are creating the thread, we can pass some initial messages to it. AgentThread? thread = new ChatHistoryAgentThread( [ new ChatMessageContent(AuthorRole.User, "Tell me a joke about a pirate."), new ChatMessageContent(AuthorRole.Assistant, "Why did the pirate go to school? Because he wanted to improve his \"arrrrrrrrrticulation\""), ]); // Respond to user input await InvokeAgentAsync("Now add some emojis to the joke."); await InvokeAgentAsync("Now make the joke sillier."); // Local function to invoke agent and display the conversation messages. async Task InvokeAgentAsync(string input) { ChatMessageContent message = new(AuthorRole.User, input); this.WriteAgentChatMessage(message); // Use the thread we created earlier to continue the conversation. await foreach (AgentResponseItem response in agent.InvokeAsync(message, thread)) { this.WriteAgentChatMessage(response); } } } [Theory] [InlineData(true)] [InlineData(false)] public async Task UseTemplateForChatCompletionAgent(bool useChatClient) { // Define the agent string generateStoryYaml = EmbeddedResource.Read("GenerateStory.yaml"); PromptTemplateConfig templateConfig = KernelFunctionYaml.ToPromptTemplateConfig(generateStoryYaml); KernelPromptTemplateFactory templateFactory = new(); // Instructions, Name and Description properties defined via the config. ChatCompletionAgent agent = new(templateConfig, templateFactory) { Kernel = this.CreateKernelWithChatCompletion(useChatClient, out var chatClient), Arguments = new() { { "topic", "Dog" }, { "length", "3" }, } }; // Invoke the agent with the default arguments. await InvokeAgentAsync(); // Invoke the agent with the override arguments. await InvokeAgentAsync( new() { { "topic", "Cat" }, { "length", "3" }, }); chatClient?.Dispose(); // Local function to invoke agent and display the conversation messages. async Task InvokeAgentAsync(KernelArguments? arguments = null) { // Invoke the agent without any messages, since the agent has all that it needs via the template and arguments. await foreach (ChatMessageContent content in agent.InvokeAsync(options: new() { KernelArguments = arguments })) { WriteAgentChatMessage(content); } } } }