In this lesson, you will dive into tool use in the nested chat between agents. You will get to build a conversational chess game between two agent players, who both can call a tool and make legal moves on the chessboard. All right, let's have some fun. In a previous session, we learned about how to use a conversable agent in AutoGen, To form conversations, and we learned how to use large language models to generate replies. In this lesson, we're going to learn a new capability for tool using. And we will still use a nested chat as one conversation pattern to make agents use the tools, finish tasks, and we will build a conversational chess game to showcase this example. So, we will build a conversational chess game between two agent players who both can call a tool and make legal moves on the chessboard. For this lecture we will use the GPT-4 turbo model, as they are much better chess players than GPT-3. The first step is to create the tools needed for this chess game. For that, we will need to import a few libraries. We import as a chess library, which can offer us programmer ways to carry over the game. We will initialize the chessboard. To make the chessboard aware of the current status, we will need to have a variable to keep track whether a move has been made. So we initialize that variable as "false". Okay. Now, we are ready to define the tools needed by the agents. First, we define a tool called "Get legal moves". This is the Python function that will return a string as a list of legal moves in UCI format. This UCI format is a format for the language for agents to understand what move it has been made. The definition is very simple. We'll just return a string with the content. Possible moves are the moves available in the board's legal moves. This annotated part is very important. This will allow the agent to understand the format of the returned content and the semantic meaning of it. And next, we also need to define a tool to make a move on the board. This function has one input argument named "move." Okay. So one agent decides to move in the move they can call this function with a particular string. And this move also needs to be in UCI format. And the returned value of this function should be a string of the result of the move. And to define this function, we first need to get the move from the chessboard. So we will call the chess.move from UCI, to get the move. And then we are going to push that move to the board. And now, we will need to make use of the, variable made the move to update that variable. So, we'll declare that the variable as a global variable and set the variable to "true." Other than that, the step, we also want to display the board. So we'll call the "Chess Library's board function" to create the board. And now, before we return the information, to the agent, we want to get The omission about the move we just made. So, we'll get a piece from the original point of the move, get the symbol of that piece, and create a piece name using the chessboard function, and do some normalization. And at last, we return the move content return string saying "we moved one piece from an original location to a new location." So that finishes the definition of the tool. Now, we're ready to create agents. Again, we'll import the conversable agent from AutoGen. And we'll first create a player agent. Player White. And give it a system message. "You're a chess player and you play as white." And we also need to let agents know what tools are available. So we'll tell it "first call the to get a list of legal moves and then call make move to make a move." 88 00:04:46,700 --> 00:04:49,600 Let the agent know the two functions available. And we also need to pass a large language model configuration to it. Okay well, one player agent. How about another one? The only difference is the name and system message. okay. What about that again? Now we created two player agents. One thing to remember is that, although we tell the two agents in the system message about the tool functions that they can use, we have to give them the concrete definition so later we will need to register the tools. And before that, let's create an agent called board agent. The board agent plays the role of checking the moves with the players until the move is illegal. And also update the status of the board. To define that board agent, we also need to have a stopping condition for the agent. So we define that stopping condition and define the function call the "checkmate move." So this will check whether a move has been made. Now we can define the board agent, give it name "board proxy". And set the large language model configuration to be "false". This agent will not use large language models. And we pass the termination condition function to "check made Move". So this agent will stop conversing with other agents when a move has been made. Otherwise, it will keep asking the other agent and say "please make a move." This is the only reply it will make. We also set the human input mode to be "never". Let's run it. So. now we have defined all the agents. We can register the tools to the agents. To do that, we will import a function called the "register function AutoGen". We'll need to register for both players. So we'll use a for loop between these two player agents and in the for loop first function we want to register is "get legal moves". We'll pass the get legal moves function and set to the caller to be one of these players agent and the executor to be the board agent. And we'll give it a name and give it its description. In a similar way, we can register the second function. Make move. After these functions are registered, the caller that is one of these player agents, will be able to propose the function call. And the executor, which is a board proxy agent, will be able to execute that tool. Let's run that. And we could actually inspect the tool registration. For example, we can check for the player black. What It's current configuration tool section. Here we go. So this is the tool definition following OpenAI definition. There's a list of tool functions. The first function is "get legal moves". The second function is "make move". We see that a few fields like the type, the function description, the parameters are automatically populated into this tool definition. This is what the register function from AutoGen did. So the user still needs to manually write all of these definitions following the OpenAI definition AutoGen library will do that for you. All the user needs to do, is to define the functions in this way, provide the necessary annotation. Other than that it's just a normal Python function you have to write. So there's no actual work needed for the agent to consume these tools. After registering these tools, we also want to create this nested chat conversation pattern. Because, we want that when the two players play the game with each other, we want them to have nested chat with the board agent before they make a move. To make sure the move is legal. To do that, we first register a nested chat with the player white. 166 00:09:05,000 --> 00:09:08,000 The trigger of the nested chat is player black, so when player white they receive a message from player black, this nested chat will be triggered. And then this nested chat would be performed before it replies to player black. And what's the definition of the nested chat? Here we're using a chat queue. With only one chat, so that in the nested chat the chat will be initiated from the proxy. The board proxy. And the recipient will be player white. And we will use the Last message as a summarization method for this chat. So before player white replies to player black until first initiate this nested chat between the board proxy and the player white until the player white chooses a move. And then the reply to player black about the move. Similarly, we can register in the nested chat for player black as well. The trigger at this time is the player white and the inner chat is between board proxy and player back. Okay, that's all the work we need to do. Let's get ready to play the game. We will first, call the chessboard function to create a new board, and we will call player black to initiate the chat method. And with an initial message, "Let's play chess. Your move." Will set the turn to be "two". When we hit the wrong button, we see that the player black initiates a message and now the player white receives the message. It will enter this auto reply with the nested chat. This nested chat is between the board proxy and the player white. We notice that the player white first suggests a tool called Get the legal moves to gather the legal moves from board. The board proxy returns tool execution result, returning all the possible moves. And then player white uses the make move tool with argument e2 e4. So that's a move. selected by the player white. The board agent now executes that and returns this message. "We move the pawn from e2 to e4." So that's the end of nested chat because, the move has been made. So after that nested chat finishes, the player white will return the reply to player black. This is the actual reply sent from player white to player black. Now, the same message will happen between board proxy and the player black. The player black will also call these tools of "get legal moves." And suggest moves using "make move". So the move set by player black is G8 f6. Now the board proxy returns a confirmation. We move the knight from G8 to F6. So the final message from Player Black is "I've moved my knight from G8 to f6 is your turn." That inner nested chat finished. So the player black will send the summary back to player white. So, the same pattern will happen again. Player white will get legal moves and shows the move. It will play another knight. And that's the end of this two-turn conversation. How can we make this game more fun? We noted that, in this game, the players are only talking about the moves they're making. How about we add a little fun to make them chit-chat beyond these moves only. So we could modify our definition about these player agents. Now, we can change the system message. Say, "After a move is made, chitchat to make the game fun." So that's the one extra, extra action we added. let's run that and let's do the same for player black. And we will need to repeat the registration about the tool use and nested chat. So do all of that. 236 00:13:07,600 --> 00:13:13,133 And finally, we will recreate the board and restart the conversation. And by the way, we also added a flag side and equal to true in the for the nested chat. So this time we don't need to inspect the inner conversation. We just want to see the outer conversation between the two player agents. Let's see. So, this time we see the first move made by player white. And not only the teammate moves, but it says "Let's see how you respond to this classic opening." This time player black throws the move of the pawn and says "I move my palm to c5, opting for the Sicilian Defense. Your move. What strategy are you planning next in this chess battle?" So they're starting to challenge each other. And player white responded "I just moved my pawn to d4, pushing the game into the openly contested territories of the Sicilian Defense. The center is heating up, and I'm curious to see how you will respond." So they keep making fun and carry over. You could try this example yourself and modify this yourself, to make them behave differently. In this example, we see two AI players playing with each other. We could watch how they play with each other, where they set. How do you like this example? This demonstrates, one particular way of using tools within nested chat, but it's not the only way. But in general, when you use tools, you need an agent that's able to propose the tool use and then another agent that's able to execute the tool. If you want to hide this proposing and tool using inside the nested chat, you could do that in a similar way. And I can see that, when we do that, and from outside, we don't necessarily need to know there are two agents involved, and we can simply create the experience of one agent, that is, not able to make use of tools and perform some functions. In some other applications, you may want to explicitly, demonstrate these separations of tool proposal and tool execution. And in the next lesson, we will also demonstrate other ways of using tools, for example, using free-form code or making an agent or suggest a code or make the agent to consume user-defined functions. in a more freestyle coding.