final changes

This commit is contained in:
Madhu 2025-01-14 22:29:10 +05:30
parent 1df6d6d62f
commit d47f8d479d
3 changed files with 73 additions and 76 deletions

View file

@ -2,7 +2,7 @@
This is a simple Chess game that uses an AI agents - Player black and player white to play the game. There's also a board proxy agent to execute the tools and manage the game. It is important to use a board proxy as a non-LLM "guard rail" to ensure the game is played correctly and to prevent agents from making illegal moves. This is a simple Chess game that uses an AI agents - Player black and player white to play the game. There's also a board proxy agent to execute the tools and manage the game. It is important to use a board proxy as a non-LLM "guard rail" to ensure the game is played correctly and to prevent agents from making illegal moves.
Two agents (player_white and player_black) are initialized using the OpenAI API key. These agents are configured to play chess as white and black, respectively. Two agents (agent_white and agent_black) are initialized using the OpenAI API key. These agents are configured to play chess as white and black, respectively.
A board_proxy agent is created to manage the board state and validate moves. A board_proxy agent is created to manage the board state and validate moves.
Functions (make_move and available_moves) are registered with the agents to allow them to interact with the board. Functions (make_move and available_moves) are registered with the agents to allow them to interact with the board.
@ -29,10 +29,3 @@ pip install -r requirements.txt
streamlit run ai_chess_agents.py streamlit run ai_chess_agents.py
``` ```
## Requirements
- autogen
- numpy
- openai
- streamlit
- chess

View file

@ -3,7 +3,6 @@ import chess.svg
import streamlit as st import streamlit as st
from autogen import ConversableAgent, register_function from autogen import ConversableAgent, register_function
# Initialize session state for the OpenAI API key and game state
if "openai_api_key" not in st.session_state: if "openai_api_key" not in st.session_state:
st.session_state.openai_api_key = None st.session_state.openai_api_key = None
if "board" not in st.session_state: if "board" not in st.session_state:
@ -14,49 +13,64 @@ if "board_svg" not in st.session_state:
st.session_state.board_svg = None st.session_state.board_svg = None
if "move_history" not in st.session_state: if "move_history" not in st.session_state:
st.session_state.move_history = [] st.session_state.move_history = []
if "max_turns" not in st.session_state:
st.session_state.max_turns = 5
# Streamlit sidebar for OpenAI API key input
st.sidebar.title("Chess Agent Configuration") st.sidebar.title("Chess Agent Configuration")
openai_api_key = st.sidebar.text_input("Enter your OpenAI API key:", type="password") openai_api_key = st.sidebar.text_input("Enter your OpenAI API key:", type="password")
if openai_api_key: if openai_api_key:
st.session_state.openai_api_key = openai_api_key st.session_state.openai_api_key = openai_api_key
st.sidebar.success("API key saved!") st.sidebar.success("API key saved!")
# Function to get legal moves st.sidebar.info("""
For a complete chess game with potential checkmate, it would take max_turns > 200 approximately.
However, this will consume significant API credits and a lot of time.
For demo purposes, using 5-10 turns is recommended.
""")
max_turns_input = st.sidebar.number_input(
"Enter the number of turns (max_turns):",
min_value=1,
max_value=1000,
value=st.session_state.max_turns,
step=1
)
if max_turns_input:
st.session_state.max_turns = max_turns_input
st.sidebar.success(f"Max turns of total chess moves set to {st.session_state.max_turns}!")
st.title("Chess with AutoGen Agents")
def available_moves() -> str: def available_moves() -> str:
available_moves = [str(move) for move in st.session_state.board.legal_moves] available_moves = [str(move) for move in st.session_state.board.legal_moves]
return "Available moves are: " + ",".join(available_moves) return "Available moves are: " + ",".join(available_moves)
# Function to make a move def execute_move(move: str) -> str:
def make_move(move: str) -> str:
try: try:
chess_move = chess.Move.from_uci(move) chess_move = chess.Move.from_uci(move)
if chess_move not in st.session_state.board.legal_moves: if chess_move not in st.session_state.board.legal_moves:
return f"Invalid move: {move}. Please call get_legal_moves() to see valid moves." return f"Invalid move: {move}. Please call available_moves() to see valid moves."
st.session_state.board.push(chess_move) st.session_state.board.push(chess_move)
st.session_state.made_move = True st.session_state.made_move = True
# Render board visualization
board_svg = chess.svg.board( board_svg = chess.svg.board(
st.session_state.board, st.session_state.board,
arrows=[(chess_move.from_square, chess_move.to_square)], arrows=[(chess_move.from_square, chess_move.to_square)],
fill={chess_move.from_square: "gray"}, fill={chess_move.from_square: "gray"},
size=400 size=400
) )
st.session_state.board_svg = board_svg # Save SVG to session state st.session_state.board_svg = board_svg
st.session_state.move_history.append(board_svg) # Save move history st.session_state.move_history.append(board_svg)
# Get moved piece details
moved_piece = st.session_state.board.piece_at(chess_move.to_square) moved_piece = st.session_state.board.piece_at(chess_move.to_square)
piece_unicode = moved_piece.unicode_symbol() piece_unicode = moved_piece.unicode_symbol()
piece_type_name = chess.piece_name(moved_piece.piece_type) piece_type_name = chess.piece_name(moved_piece.piece_type)
piece_name = piece_type_name.capitalize() if piece_unicode.isupper() else piece_type_name piece_name = piece_type_name.capitalize() if piece_unicode.isupper() else piece_type_name
# Build move description
move_desc = f"Moved {piece_name} ({piece_unicode}) from {chess.SQUARE_NAMES[chess_move.from_square]} to {chess.SQUARE_NAMES[chess_move.to_square]}." move_desc = f"Moved {piece_name} ({piece_unicode}) from {chess.SQUARE_NAMES[chess_move.from_square]} to {chess.SQUARE_NAMES[chess_move.to_square]}."
# Check game state
if st.session_state.board.is_checkmate(): if st.session_state.board.is_checkmate():
winner = 'White' if st.session_state.board.turn == chess.BLACK else 'Black' winner = 'White' if st.session_state.board.turn == chess.BLACK else 'Black'
move_desc += f"\nCheckmate! {winner} wins!" move_desc += f"\nCheckmate! {winner} wins!"
@ -71,7 +85,6 @@ def make_move(move: str) -> str:
except ValueError: except ValueError:
return f"Invalid move format: {move}. Please use UCI format (e.g., 'e2e4')." return f"Invalid move format: {move}. Please use UCI format (e.g., 'e2e4')."
# Check if the player has made a move, and reset the flag if move is made.
def check_made_move(msg): def check_made_move(msg):
if st.session_state.made_move: if st.session_state.made_move:
st.session_state.made_move = False st.session_state.made_move = False
@ -79,119 +92,112 @@ def check_made_move(msg):
else: else:
return False return False
# Initialize players and proxy agent if API key is provided
if st.session_state.openai_api_key: if st.session_state.openai_api_key:
try: try:
player_white_config_list = [ agent_white_config_list = [
{ {
"model": "gpt-4o-mini", "model": "gpt-4o-mini",
"api_key": st.session_state.openai_api_key, "api_key": st.session_state.openai_api_key,
}, },
] ]
player_black_config_list = [ agent_black_config_list = [
{ {
"model": "gpt-4o-mini", "model": "gpt-4o-mini",
"api_key": st.session_state.openai_api_key, "api_key": st.session_state.openai_api_key,
}, },
] ]
player_white = ConversableAgent( agent_white = ConversableAgent(
name="Player_White", name="Agent_White",
system_message="You are a professional chess player and you play as white. " system_message="You are a professional chess player and you play as white. "
"First call get_legal_moves() first, to get list of legal moves. " "First call available_moves() first, to get list of legal moves. "
"Then call make_move(move) to make a move.", "Then call execute_move(move) to make a move.",
llm_config={"config_list": player_white_config_list, "cache_seed": None}, llm_config={"config_list": agent_white_config_list, "cache_seed": None},
) )
player_black = ConversableAgent( agent_black = ConversableAgent(
name="Player_Black", name="Agent_Black",
system_message="You are a professional chess player and you play as black. " system_message="You are a professional chess player and you play as black. "
"First call get_legal_moves() first, to get list of legal moves. " "First call available_moves() first, to get list of legal moves. "
"Then call make_move(move) to make a move.", "Then call execute_move(move) to make a move.",
llm_config={"config_list": player_black_config_list, "cache_seed": None}, llm_config={"config_list": agent_black_config_list, "cache_seed": None},
) )
# Proxy agent to manage the board and validate moves game_master = ConversableAgent(
board_proxy = ConversableAgent( name="Game_Master",
name="Board_Proxy",
llm_config=False, llm_config=False,
is_termination_msg=check_made_move, is_termination_msg=check_made_move,
default_auto_reply="Please make a move.", default_auto_reply="Please make a move.",
human_input_mode="NEVER", human_input_mode="NEVER",
) )
# Register functions for both players
register_function( register_function(
make_move, execute_move,
caller=player_white, caller=agent_white,
executor=board_proxy, executor=game_master,
name="make_move", name="execute_move",
description="Call this tool to make a move.", description="Call this tool to make a move.",
) )
register_function( register_function(
available_moves, available_moves,
caller=player_white, caller=agent_white,
executor=board_proxy, executor=game_master,
name="available_moves", name="available_moves",
description="Get legal moves.", description="Get legal moves.",
) )
register_function( register_function(
make_move, execute_move,
caller=player_black, caller=agent_black,
executor=board_proxy, executor=game_master,
name="make_move", name="execute_move",
description="Call this tool to make a move.", description="Call this tool to make a move.",
) )
register_function( register_function(
available_moves, available_moves,
caller=player_black, caller=agent_black,
executor=board_proxy, executor=game_master,
name="available_moves", name="available_moves",
description="Get legal moves.", description="Get legal moves.",
) )
# Register nested chats for both players agent_white.register_nested_chats(
player_white.register_nested_chats( trigger=agent_black,
trigger=player_black,
chat_queue=[ chat_queue=[
{ {
"sender": board_proxy, "sender": game_master,
"recipient": player_white, "recipient": agent_white,
"summary_method": "last_msg", "summary_method": "last_msg",
} }
], ],
) )
player_black.register_nested_chats( agent_black.register_nested_chats(
trigger=player_white, trigger=agent_white,
chat_queue=[ chat_queue=[
{ {
"sender": board_proxy, "sender": game_master,
"recipient": player_black, "recipient": agent_black,
"summary_method": "last_msg", "summary_method": "last_msg",
} }
], ],
) )
# Streamlit UI for playing the game
st.title("Chess with AG2 Agents")
st.info(""" st.info("""
This chess game is played between two AutoGen AI agents: This chess game is played between two AG2 AI agents:
- **Player White**: A GPT-4o-mini powered chess player controlling white pieces - **Agent White**: A GPT-4o-mini powered chess player controlling white pieces
- **Player Black**: A GPT-4o-mini powered chess player controlling black pieces - **Agent Black**: A GPT-4o-mini powered chess player controlling black pieces
The game is managed by a **Board Proxy Agent** that: The game is managed by a **Game Master** that:
- Validates all moves - Validates all moves
- Updates the chess board - Updates the chess board
- Manages turn-taking between players - Manages turn-taking between players
- Provides legal move information - Provides legal move information
""") """)
# Display the initial board state before the game starts
initial_board_svg = chess.svg.board(st.session_state.board, size=300) initial_board_svg = chess.svg.board(st.session_state.board, size=300)
st.subheader("Initial Board") st.subheader("Initial Board")
st.image(initial_board_svg) st.image(initial_board_svg)
@ -199,28 +205,26 @@ The game is managed by a **Board Proxy Agent** that:
if st.button("Start Game"): if st.button("Start Game"):
st.session_state.board.reset() st.session_state.board.reset()
st.session_state.made_move = False st.session_state.made_move = False
st.session_state.move_history = [] # Reset move history st.session_state.move_history = []
st.session_state.board_svg = chess.svg.board(st.session_state.board, size=300) st.session_state.board_svg = chess.svg.board(st.session_state.board, size=300)
st.info("The AI agents will now play against each other. Each agent will analyze the board, " st.info("The AI agents will now play against each other. Each agent will analyze the board, "
"request legal moves, and make strategic decisions.") "request legal moves from the Game Master (proxy agent), and make strategic decisions.")
st.success("You can view the interaction between the agents in the terminal output, after the turns between agents end, you get view all the chess board moves displayed below!")
st.write("Game started! White's turn.") st.write("Game started! White's turn.")
# Initiate the chat between Player_White and Board_Proxy chat_result = agent_black.initiate_chat(
chat_result = player_black.initiate_chat( recipient=agent_white,
recipient=player_white,
message="Let's play chess! You go first, its your move.", message="Let's play chess! You go first, its your move.",
max_turns=5, max_turns=st.session_state.max_turns,
summary_method="reflection_with_llm" summary_method="reflection_with_llm"
) )
st.markdown(chat_result.summary) st.markdown(chat_result.summary)
# Display the move history (boards for each move)
st.subheader("Move History") st.subheader("Move History")
for i, move_svg in enumerate(st.session_state.move_history): for i, move_svg in enumerate(st.session_state.move_history):
st.write(f"Move {i + 1}") st.write(f"Move {i + 1}")
st.image(move_svg) st.image(move_svg)
# Reset Game button
if st.button("Reset Game"): if st.button("Reset Game"):
st.session_state.board.reset() st.session_state.board.reset()
st.session_state.made_move = False st.session_state.made_move = False

View file

@ -1,5 +1,5 @@
streamlit streamlit
python-chess chess==1.11.1
autogen autogen==0.6.1
cairosvg cairosvg
pillow pillow