"""This is an example of simulating a chess game with two agents that play against each other, using tools to reason about the game state and make moves.""" import argparse import asyncio import logging from typing import Annotated from agnext.application import SingleThreadedAgentRuntime from agnext.chat.agents.chat_completion_agent import ChatCompletionAgent from agnext.chat.patterns.group_chat import GroupChat, GroupChatOutput from agnext.chat.types import TextMessage from agnext.components.models import OpenAI, SystemMessage from agnext.components.tools import FunctionTool from agnext.core import AgentRuntime from chess import SQUARE_NAMES, Board, Move from chess import piece_name as get_piece_name logging.basicConfig(level=logging.WARNING) logging.getLogger("agnext").setLevel(logging.DEBUG) class ChessGameOutput(GroupChatOutput): # type: ignore def on_message_received(self, message: TextMessage) -> None: # type: ignore pass def get_output(self) -> None: pass def reset(self) -> None: pass def chess_game(runtime: AgentRuntime) -> GroupChat: # type: ignore """Create agents for a chess game and return the group chat.""" # Create the board. board = Board() # Create shared tools. def get_legal_moves() -> Annotated[str, "A list of legal moves in UCI format."]: return "Possible moves are: " + ", ".join([str(move) for move in board.legal_moves]) get_legal_moves_tool = FunctionTool(get_legal_moves, description="Get legal moves.") def make_move(input: Annotated[str, "A move in UCI format."]) -> Annotated[str, "Result of the move."]: move = Move.from_uci(input) board.push(move) print(board.unicode(borders=True)) # Get the piece name. piece = board.piece_at(move.to_square) assert piece is not None piece_symbol = piece.unicode_symbol() piece_name = get_piece_name(piece.piece_type) if piece_symbol.isupper(): piece_name = piece_name.capitalize() return f"Moved {piece_name} ({piece_symbol}) from {SQUARE_NAMES[move.from_square]} to {SQUARE_NAMES[move.to_square]}." make_move_tool = FunctionTool(make_move, description="Call this tool to make a move.") tools = [get_legal_moves_tool, make_move_tool] black = ChatCompletionAgent( name="PlayerBlack", description="Player playing black.", runtime=runtime, system_messages=[ SystemMessage( content="You are a chess player and you play as black. " "First call get_legal_moves() first, to get list of legal moves. " "Then call make_move(move) to make a move." ), ], model_client=OpenAI(model="gpt-4-turbo"), tools=tools, ) white = ChatCompletionAgent( name="PlayerWhite", description="Player playing white.", runtime=runtime, system_messages=[ SystemMessage( content="You are a chess player and you play as white. " "First call get_legal_moves() first, to get list of legal moves. " "Then call make_move(move) to make a move." ), ], model_client=OpenAI(model="gpt-4-turbo"), tools=tools, ) game_chat = GroupChat( name="ChessGame", description="A chess game between two agents.", runtime=runtime, agents=[white, black], num_rounds=10, output=ChessGameOutput(), ) return game_chat async def main(message: str) -> None: runtime = SingleThreadedAgentRuntime() game_chat = chess_game(runtime) future = runtime.send_message(TextMessage(content=message, source="Human"), game_chat) while not future.done(): await runtime.process_next() if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run a chess game between two agents.") parser.add_argument( "--initial-message", default="Please make a move.", help="The initial message to send to the agent playing white.", ) args = parser.parse_args() asyncio.run(main(args.initial_message))