class_docstr: (In preview) A class for generic conversable agents which can be configured as assistant or user proxy.
  
  After receiving each message, the agent will send a reply to the sender unless the msg is a termination msg.
  For example, AssistantAgent and UserProxyAgent are subclasses of this class,
  configured with different default settings.
  
  To modify auto reply, override `generate_reply` method.
  To disable/enable human response in every turn, set `human_input_mode` to "NEVER" or "ALWAYS".
  To modify the way to get human input, override `get_human_input` method.
  To modify the way to execute code blocks, single code block, or function call, override `execute_code_blocks`,
  `run_code`, and `execute_function` methods respectively.
  To customize the initial message when a conversation starts, override `generate_init_message` method.
class_docstr_tok: ["(","In","preview",")","A","class","for","generic","conversable","agents","which","can","be","configured","as","assistant","or","user","proxy",".","After","receiving","each","message",",","the","agent","will","send","a","reply","to","the","sender","unless","the","msg","is","a","termination","msg",".","For","example",",","AssistantAgent","and","UserProxyAgent","are","subclasses","of","this","class",",","configured","with","different","default","settings",".","To","modify","auto","reply",",","override","`","generate_reply","`","method",".","To","disable\/enable","human","response","in","every","turn",",","set","`","human_input_mode","`","to","``","NEVER","''","or","``","ALWAYS","''",".","To","modify","the","way","to","get","human","input",",","override","`","get_human_input","`","method",".","To","modify","the","way","to","execute","code","blocks",",","single","code","block",",","or","function","call",",","override","`","execute_code_blocks","`",",","`","run_code","`",",","and","`","execute_function","`","methods","respectively",".","To","customize","the","initial","message","when","a","conversation","starts",",","override","`","generate_init_message","`","method","."]
docstr: Check if the conversation should be terminated, and if human reply is provided.
  
  This method checks for conditions that require the conversation to be terminated, such as reaching
  a maximum number of consecutive auto-replies or encountering a termination message. Additionally,
  it prompts for and processes human input based on the configured human input mode, which can be
  'ALWAYS', 'NEVER', or 'TERMINATE'. The method also manages the consecutive auto-reply counter
  for the conversation and prints relevant messages based on the human input received.
  
  Args:
      - messages (Optional[List[Dict]]): A list of message dictionaries, representing the conversation history.
      - sender (Optional[Agent]): The agent object representing the sender of the message.
      - config (Optional[Any]): Configuration object, defaults to the current instance if not provided.
  
  Returns:
      - Tuple[bool, Union[str, Dict, None]]: A tuple containing a boolean indicating if the conversation
      should be terminated, and a human reply which can be a string, a dictionary, or None.
docstr_tok: ["Check","if","the","conversation","should","be","terminated",",","and","if","human","reply","is","provided",".","This","method","checks","for","conditions","that","require","the","conversation","to","be","terminated",",","such","as","reaching","a","maximum","number","of","consecutive","auto-replies","or","encountering","a","termination","message",".","Additionally",",","it","prompts","for","and","processes","human","input","based","on","the","configured","human","input","mode",",","which","can","be","'ALWAYS","'",",","'NEVER","'",",","or","'TERMINATE","'",".","The","method","also","manages","the","consecutive","auto-reply","counter","for","the","conversation","and","prints","relevant","messages","based","on","the","human","input","received",".","Args",":","-","messages","(","Optional","[","List","[","Dict","]","]",")",":","A","list","of","message","dictionaries",",","representing","the","conversation","history",".","-","sender","(","Optional","[","Agent","]",")",":","The","agent","object","representing","the","sender","of","the","message",".","-","config","(","Optional","[","Any","]",")",":","Configuration","object",",","defaults","to","the","current","instance","if","not","provided",".","Returns",":","-","Tuple","[","bool",",","Union","[","str",",","Dict",",","None","]","]",":","A","tuple","containing","a","boolean","indicating","if","the","conversation","should","be","terminated",",","and","a","human","reply","which","can","be","a","string",",","a","dictionary",",","or","None","."]
code: def check_termination_and_human_reply(
      self,
      messages: Optional[List[Dict]] = None,
      sender: Optional[Agent] = None,
      config: Optional[Any] = None,
  ) -> Tuple[bool, Union[str, None]]:
      """Check if the conversation should be terminated, and if human reply is provided.
  
      This method checks for conditions that require the conversation to be terminated, such as reaching
      a maximum number of consecutive auto-replies or encountering a termination message. Additionally,
      it prompts for and processes human input based on the configured human input mode, which can be
      'ALWAYS', 'NEVER', or 'TERMINATE'. The method also manages the consecutive auto-reply counter
      for the conversation and prints relevant messages based on the human input received.
  
      Args:
          - messages (Optional[List[Dict]]): A list of message dictionaries, representing the conversation history.
          - sender (Optional[Agent]): The agent object representing the sender of the message.
          - config (Optional[Any]): Configuration object, defaults to the current instance if not provided.
  
      Returns:
          - Tuple[bool, Union[str, Dict, None]]: A tuple containing a boolean indicating if the conversation
          should be terminated, and a human reply which can be a string, a dictionary, or None.
      """
      # Function implementation...
  
      if config is None:
          config = self
      if messages is None:
          messages = self._oai_messages[sender]
      message = messages[-1]
      reply = ""
      no_human_input_msg = ""
      if self.human_input_mode == "ALWAYS":
          reply = self.get_human_input(
              f"Provide feedback to {sender.name}. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: "
          )
          no_human_input_msg = (
              "NO HUMAN INPUT RECEIVED." if not reply else ""
          )
          # if the human input is empty, and the message is a termination message, then we will terminate the conversation
          reply = (
              reply
              if reply or not self._is_termination_msg(message)
              else "exit"
          )
      else:
          if (
              self._consecutive_auto_reply_counter[sender]
              >= self._max_consecutive_auto_reply_dict[sender]
          ):
              if self.human_input_mode == "NEVER":
                  reply = "exit"
              else:
                  # self.human_input_mode == "TERMINATE":
                  terminate = self._is_termination_msg(message)
                  reply = self.get_human_input(
                      f"Please give feedback to {sender.name}. Press enter or type 'exit' to stop the conversation: "
                      if terminate
                      else f"Please give feedback to {sender.name}. Press enter to skip and use auto-reply, or type 'exit' to stop the conversation: "
                  )
                  no_human_input_msg = (
                      "NO HUMAN INPUT RECEIVED." if not reply else ""
                  )
                  # if the human input is empty, and the message is a termination message, then we will terminate the conversation
                  reply = reply if reply or not terminate else "exit"
          elif self._is_termination_msg(message):
              if self.human_input_mode == "NEVER":
                  reply = "exit"
              else:
                  # self.human_input_mode == "TERMINATE":
                  reply = self.get_human_input(
                      f"Please give feedback to {sender.name}. Press enter or type 'exit' to stop the conversation: "
                  )
                  no_human_input_msg = (
                      "NO HUMAN INPUT RECEIVED." if not reply else ""
                  )
                  # if the human input is empty, and the message is a termination message, then we will terminate the conversation
                  reply = reply or "exit"
  
      # print the no_human_input_msg
      if no_human_input_msg:
          print(
              colored(f"\n>>>>>>>> {no_human_input_msg}", "red"),
              flush=True,
          )
  
      # stop the conversation
      if reply == "exit":
          # reset the consecutive_auto_reply_counter
          self._consecutive_auto_reply_counter[sender] = 0
          return True, None
  
      # send the human reply
      if reply or self._max_consecutive_auto_reply_dict[sender] == 0:
          # reset the consecutive_auto_reply_counter
          self._consecutive_auto_reply_counter[sender] = 0
          # User provided a custom response, return function and tool failures indicating user interruption
          tool_returns = []
          if message.get("function_call", False):
              tool_returns.append(
                  {
                      "role": "function",
                      "name": message["function_call"].get("name", ""),
                      "content": "USER INTERRUPTED",
                  }
              )
  
          if message.get("tool_calls", False):
              tool_returns.extend(
                  [
                      {
                          "role": "tool",
                          "tool_call_id": tool_call.get("id", ""),
                          "content": "USER INTERRUPTED",
                      }
                      for tool_call in message["tool_calls"]
                  ]
              )
  
          response = {"role": "user", "content": reply}
          if tool_returns:
              response["tool_responses"] = tool_returns
  
          return True, response
  
      # increment the consecutive_auto_reply_counter
      self._consecutive_auto_reply_counter[sender] += 1
      if self.human_input_mode != "NEVER":
          print(
              colored("\n>>>>>>>> USING AUTO REPLY...", "red"),
              flush=True,
          )
  
      return False, None
  
imports: import asyncio
  import copy
  import functools
  import inspect
  import json
  import logging
  import re
  from collections import defaultdict
  from typing import Any, Awaitable, Callable, Dict, List, Literal, Optional, Tuple, Type, TypeVar, Union
  from ..None import OpenAIWrapper
  from ..code_utils import DEFAULT_MODEL, UNKNOWN, content_str, execute_code, extract_code, infer_lang
  from ..function_utils import get_function_schema, load_basemodels_if_needed, serialize_to_str
  from .agent import Agent
  from .._pydantic import model_dump
label_desc: Use image node_id 30 for calling the ConversableAgent obj's underlying member method code with example usage: obj.check_termination_and_human_reply(messages, sender, config) and returns: False,  None, True,  None, True,  response