Skip to content

Tool Use

Tool Use and Conversational ChessΒΆ

In this example, we build a conversational chess game using three agents: Player White, Player Black, and Board Proxy. The agents interact to play a game of chess, with each player taking turns to make moves. The Board Proxy manages the board state and facilitates communication between the players.

Example 4 overview Example 4 overview

Note

Can you find a better way to handle the board state and move tracking between agents, without using globals? Give it a try! We'd love to hear your feedback on this example, either by contributing to the repository, or by reaching out to us.

OverviewΒΆ

The flow includes:

  • Player White and Player Black agents for each chess player.
  • Board Proxy to manage board state and relay information between players.

Agents and SkillsΒΆ

AgentsΒΆ

  1. Player White: The agent playing white pieces. Calls methods to get legal moves and make moves.
  2. Player Black: The agent playing black pieces. Operates similarly to Player White.
  3. Board Proxy: Manages the board’s state and facilitates move tracking between agents.

SkillsΒΆ

Each player has access to the following skills:

  • get_legal_moves: Fetches the list of legal moves in UCI format.
  • make_move: Executes a move and provides feedback on the action taken.

Example 4 skills Example 4 skills

This function generates a list of possible legal moves from the current board state.

  • Content:

    from typing import Annotated
    
     import chess
    
     if "BOARD" not in globals():
         BOARD = chess.Board()
         globals()["BOARD"] = BOARD
     else:
         BOARD = globals()["BOARD"]
    
    
     def get_legal_moves() -> Annotated[str, "A list of legal moves in UCI format"]:
         """Get a list of legal moves."""
         return "Possible moves are: " + ",".join(
         [str(move) for move in BOARD.legal_moves]
     )
    
make_moveΒΆ

Executes a chosen move and outputs the result.

  • Content:
    from typing import Annotated
    import chess
    # Global variables to store the board and move status.
    if "BOARD" not in globals():
        BOARD = chess.Board()
        globals()["BOARD"] = BOARD
    else:
        BOARD = globals()["BOARD"]
    if "MADE_MOVE" not in globals():
        MADE_MOVE = False
        globals()["MADE_MOVE"] = MADE_MOVE
    else:
        MADE_MOVE = globals()["MADE_MOVE"]
    
    def make_move(
        move: Annotated[str, "A move in UCI format."],
    ) -> Annotated[str, "Result of the move."]:
        """Make a move on the board."""
        global MADE_MOVE
        try:
            move = chess.Move.from_uci(move)
        except BaseException:  # pylint: disable=broad-except
            move = BOARD.parse_san(move)
        BOARD.push_uci(str(move))
        # Get the piece name.
        piece = BOARD.piece_at(move.to_square)
        piece_symbol = piece.unicode_symbol()
        piece_name = (
            chess.piece_name(piece.piece_type).capitalize()
            if piece_symbol.isupper()
            else chess.piece_name(piece.piece_type)
        )
        MADE_MOVE = True
        return f"Moved {piece_name} ({piece_symbol}) from "\
            f"{chess.SQUARE_NAMES[move.from_square]} to "\
            f"{chess.SQUARE_NAMES[move.to_square]}."
    

Agent ConfigurationΒΆ

  1. Player White and Player Black Agents:

    • System Message: You are a chess player and you play as black / white. First call get_legal_moves(), to get a list of legal moves. Then call make_move(move) to make a move.
    • Skills: Assign get_legal_moves and make_move to each agent. Set the executor to the board proxy.

      Agent's skills Agent's skills

  2. Board Proxy:

    • Termination Method: Set up a termination method to end the conversation after a move is made. This method resets a flag (MADE_MOVE) after each move to monitor the game flow.

      Termination custom method Termination custom method

ChatsΒΆ

The flow starts with the black player challenging the white player to a game of chess. The white player then makes the first move.

  • Player Black => Player White: The black player challenges the white player to a game of chess. For the message we use the "Text" type and for content, we use:
    Let's play chess! Your move.
    
  • Player White => Board Proxy: When the white player receives the challenge, a new nested chat is triggered to get the move to play using the board proxy.
  • Player Black => Board Proxy: When the black player gets a reply from the white player, a new nested chat is triggered to get the move to play using the board proxy. And the beat goes on!

    Black player's message Black player's message

Register Nested ChatsΒΆ

On each agent, set up the nested chats we defined above, to handle the flow of the game. For the white player, a nested chat is triggered when the black player makes a move. For the black player, a nested chat is triggered when the white player replies. The message to use is the board proxy's reply, after a new move is made.

Black player's Nested chats Black player's Nested chats

Flow chats and requirementsΒΆ

  1. Edit Flow: Set up the flow order to start with the "Player Black => Player White" connection.
  2. Additional requirements: As we have seen, running the flow requires the usage of the "chess" library, so make sure to add it in the "Other" tab Additional requirements Additional requirements

Files used in this example: