class_docstr: (In preview) A group chat class that contains the following data fields:
  - agents: a list of participating agents.
  - messages: a list of messages in the group chat.
  - max_round: the maximum number of rounds.
  - admin_name: the name of the admin agent if there is one. Default is "Admin".
      KeyBoardInterrupt will make the admin agent take over.
  - func_call_filter: whether to enforce function call filter. Default is True.
      When set to True and when a message is a function call suggestion,
      the next speaker will be chosen from an agent which contains the corresponding function name
      in its `function_map`.
  - speaker_selection_method: the method for selecting the next speaker. Default is "auto".
      Could be any of the following (case insensitive), will raise ValueError if not recognized:
      - "auto": the next speaker is selected automatically by LLM.
      - "manual": the next speaker is selected manually by user input.
      - "random": the next speaker is selected randomly.
      - "round_robin": the next speaker is selected in a round robin fashion, i.e., iterating in the same order as provided in `agents`.
  - allow_repeat_speaker: whether to allow the same speaker to speak consecutively. Default is True, in which case all speakers are allowed to speak consecutively. If allow_repeat_speaker is a list of Agents, then only those listed agents are allowed to repeat. If set to False, then no speakers are allowed to repeat.
class_docstr_tok: ["(","In","preview",")","A","group","chat","class","that","contains","the","following","data","fields",":","-","agents",":","a","list","of","participating","agents",".","-","messages",":","a","list","of","messages","in","the","group","chat",".","-","max_round",":","the","maximum","number","of","rounds",".","-","admin_name",":","the","name","of","the","admin","agent","if","there","is","one",".","Default","is","``","Admin","''",".","KeyBoardInterrupt","will","make","the","admin","agent","take","over",".","-","func_call_filter",":","whether","to","enforce","function","call","filter",".","Default","is","True",".","When","set","to","True","and","when","a","message","is","a","function","call","suggestion",",","the","next","speaker","will","be","chosen","from","an","agent","which","contains","the","corresponding","function","name","in","its","`","function_map","`",".","-","speaker_selection_method",":","the","method","for","selecting","the","next","speaker",".","Default","is","``","auto","''",".","Could","be","any","of","the","following","(","case","insensitive",")",",","will","raise","ValueError","if","not","recognized",":","-","``","auto","''",":","the","next","speaker","is","selected","automatically","by","LLM",".","-","``","manual","''",":","the","next","speaker","is","selected","manually","by","user","input",".","-","``","random","''",":","the","next","speaker","is","selected","randomly",".","-","``","round_robin","''",":","the","next","speaker","is","selected","in","a","round","robin","fashion",",","i.e.",",","iterating","in","the","same","order","as","provided","in","`","agents","`",".","-","allow_repeat_speaker",":","whether","to","allow","the","same","speaker","to","speak","consecutively",".","Default","is","True",",","in","which","case","all","speakers","are","allowed","to","speak","consecutively",".","If","allow_repeat_speaker","is","a","list","of","Agents",",","then","only","those","listed","agents","are","allowed","to","repeat",".","If","set","to","False",",","then","no","speakers","are","allowed","to","repeat","."]
code: def _prepare_and_select_agents(
      self, last_speaker: Agent
  ) -> Tuple[Optional[Agent], List[Agent], Optional[List[Dict]]]:
      if (
          self.speaker_selection_method.lower()
          not in self._VALID_SPEAKER_SELECTION_METHODS
      ):
          raise ValueError(
              f"GroupChat speaker_selection_method is set to '{self.speaker_selection_method}'. "
              f"It should be one of {self._VALID_SPEAKER_SELECTION_METHODS} (case insensitive). "
          )
  
      if not isinstance(self.allow_repeat_speaker, (bool, list)):
          raise ValueError(
              "GroupChat allow_repeat_speaker should be a bool or a list of Agents."
          )
      # If provided a list, make sure the agent is in the list
      allow_repeat_speaker = (
          self.allow_repeat_speaker
          if isinstance(self.allow_repeat_speaker, bool)
          else last_speaker in self.allow_repeat_speaker
      )
  
      agents = self.agents
      n_agents = len(agents)
      # Warn if GroupChat is underpopulated
      if n_agents < 2:
          raise ValueError(
              f"GroupChat is underpopulated with {n_agents} agents. "
              "Please add more agents to the GroupChat or use direct communication instead."
          )
      elif (
          n_agents == 2
          and self.speaker_selection_method.lower() != "round_robin"
          and allow_repeat_speaker
      ):
          logger.warning(
              f"GroupChat is underpopulated with {n_agents} agents. "
              "It is recommended to set speaker_selection_method to 'round_robin' or allow_repeat_speaker to False."
              "Or, use direct communication instead."
          )
  
      if (
          self.func_call_filter
          and self.messages
          and (
              "function_call" in self.messages[-1]
              or "tool_calls" in self.messages[-1]
          )
      ):
          funcs = []
          if "function_call" in self.messages[-1]:
              funcs += [self.messages[-1]["function_call"]["name"]]
          if "tool_calls" in self.messages[-1]:
              funcs += [
                  tool["function"]["name"]
                  for tool in self.messages[-1]["tool_calls"]
                  if tool["type"] == "function"
              ]
  
          # find agents with the right function_map which contains the function name
          agents = [
              agent
              for agent in self.agents
              if agent.can_execute_function(funcs)
          ]
          if len(agents) == 1:
              # only one agent can execute the function
              return agents[0], agents, None
          elif not agents:
              # find all the agents with function_map
              agents = [
                  agent for agent in self.agents if agent.function_map
              ]
              if len(agents) == 1:
                  return agents[0], agents, None
              elif not agents:
                  raise ValueError(
                      f"No agent can execute the function {', '.join(funcs)}. "
                      "Please check the function_map of the agents."
                  )
      # remove the last speaker from the list to avoid selecting the same speaker if allow_repeat_speaker is False
      agents = (
          agents
          if allow_repeat_speaker
          else [agent for agent in agents if agent != last_speaker]
      )
  
      select_speaker_messages = None
      if self.speaker_selection_method.lower() == "manual":
          selected_agent = self.manual_select_speaker(agents)
      elif self.speaker_selection_method.lower() == "round_robin":
          selected_agent = self.next_agent(last_speaker, agents)
      elif self.speaker_selection_method.lower() == "random":
          selected_agent = random.choice(agents)
      else:
          selected_agent = None
          select_speaker_messages = self.messages.copy()
          # If last message is a tool call or function call, blank the call so the api doesn't throw
          if select_speaker_messages[-1].get("function_call", False):
              select_speaker_messages[-1] = dict(
                  select_speaker_messages[-1], function_call=None
              )
          if select_speaker_messages[-1].get("tool_calls", False):
              select_speaker_messages[-1] = dict(
                  select_speaker_messages[-1], tool_calls=None
              )
          select_speaker_messages = select_speaker_messages + [
              {
                  "role": "system",
                  "content": self.select_speaker_prompt(agents),
              }
          ]
      return selected_agent, agents, select_speaker_messages
  
imports: import logging
  import random
  import re
  import sys
  from dataclasses import dataclass
  from typing import Dict, List, Optional, Union, Tuple
  from ..code_utils import content_str
  from .agent import Agent
  from .conversable_agent import ConversableAgent
label_desc: Use image node_id 9 for calling the GroupChat obj's underlying member method code with example usage: obj._prepare_and_select_agents(last_speaker) and returns: selected_agent,  agents,  select_speaker_messages, agents,  agents,  None, agents,  agents,  None