Skip to content

Commit

Permalink
Supporting callable message (#1852)
Browse files Browse the repository at this point in the history
* add message field

* send

* message func doc str

* test dict message

* retiring soon

* generate_init_message docstr

* remove todo

* update notebook

* CompressibleAgent

* update notebook

* add test

* retrieve agent

* update test

* summary_method args

* summary

* carryover

* dict message

* update nested doc

* generate_init_message

* fix typo

* update docs for mathchat

* Fix missing message

* Add docstrings

* model

* notebook

* default naming

---------

Co-authored-by: Chi Wang <wang.chi@microsoft.com>
Co-authored-by: kevin666aa <yrwu000627@gmail.com>
Co-authored-by: Li Jiang <bnujli@gmail.com>
Co-authored-by: Li Jiang <lijiang1@microsoft.com>
  • Loading branch information
5 people authored Mar 9, 2024
1 parent 83e1789 commit c75655a
Show file tree
Hide file tree
Showing 22 changed files with 2,955 additions and 2,438 deletions.
52 changes: 21 additions & 31 deletions autogen/agentchat/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,19 @@ def __post_carryover_processing(chat_info: Dict[str, Any]):
if isinstance(chat_info["carryover"], list)
else chat_info["carryover"]
)
message = chat_info.get("message")
if isinstance(message, str):
print_message = message
elif callable(message):
print_message = "Callable: " + message.__name__
elif isinstance(message, dict):
print_message = "Dict: " + str(message)
elif message is None:
print_message = "None"
print(colored("\n" + "*" * 80, "blue"), flush=True, sep="")
print(
colored(
"Start a new chat with the following message: \n"
+ chat_info.get("message")
+ "\n\nWith the following carryover: \n"
+ print_carryover,
"Starting a new chat....\n\nMessage:\n" + print_message + "\n\nCarryover: \n" + print_carryover,
"blue",
),
flush=True,
Expand All @@ -132,35 +138,19 @@ def initiate_chats(chat_queue: List[Dict[str, Any]]) -> List[ChatResult]:
chat_queue (List[Dict]): a list of dictionaries containing the information of the chats.
Each dictionary should contain the input arguments for `ConversableAgent.initiate_chat`.
More specifically, each dictionary could include the following fields:
- recipient: the recipient agent.
- "sender": the sender agent.
- "recipient": the recipient agent.
- clear_history (bool): whether to clear the chat history with the agent. Default is True.
- silent (bool or None): (Experimental) whether to print the messages for this conversation. Default is False.
- cache (Cache or None): the cache client to be used for this conversation. Default is None.
- max_turns (int or None): the maximum number of turns for the chat. If None, the chat will continue until a termination condition is met. Default is None.
- "message" needs to be provided if the `generate_init_message` method is not overridden.
Otherwise, input() will be called to get the initial message.
- "summary_method": a string or callable specifying the method to get a summary from the chat. Default is DEFAULT_summary_method, i.e., "last_msg".
- Supported string are "last_msg" and "reflection_with_llm":
when set "last_msg", it returns the last message of the dialog as the summary.
when set "reflection_with_llm", it returns a summary extracted using an llm client.
`llm_config` must be set in either the recipient or sender.
"reflection_with_llm" requires the llm_config to be set in either the sender or the recipient.
- A callable summary_method should take the recipient and sender agent in a chat as input and return a string of summary. E.g,
```python
def my_summary_method(
sender: ConversableAgent,
recipient: ConversableAgent,
):
return recipient.last_message(sender)["content"]
```
- "summary_prompt": This filed can be used to specify the prompt used to extract a summary when summary_method is "reflection_with_llm".
Default is None and the following default prompt will be used when "summary_method" is set to "reflection_with_llm":
"Identify and extract the final solution to the originally asked question based on the conversation."
- "carryover": It can be used to specify the carryover information to be passed to this chat.
If provided, we will combine this carryover with the "message" content when generating the initial chat
message in `generate_init_message`.
- "clear_history" (bool): whether to clear the chat history with the agent. Default is True.
- "silent" (bool or None): (Experimental) whether to print the messages for this conversation. Default is False.
- "cache" (Cache or None): the cache client to be used for this conversation. Default is None.
- "max_turns" (int or None): the maximum number of turns for the chat. If None, the chat will continue until a termination condition is met. Default is None.
- "summary_method" (str or callable): a string or callable specifying the method to get a summary from the chat. Default is DEFAULT_summary_method, i.e., "last_msg".
- "summary_args" (dict): a dictionary of arguments to be passed to the summary_method. Default is {}.
- "message" (str, callable or None): if None, input() will be called to get the initial message.
- **context: additional context information to be passed to the chat.
- "carryover": It can be used to specify the carryover information to be passed to this chat.
If provided, we will combine this carryover with the "message" content when generating the initial chat
message in `generate_init_message`.
Returns:
(list): a list of ChatResult objects corresponding to the finished chats in the chat_queue.
Expand Down
2 changes: 1 addition & 1 deletion autogen/agentchat/contrib/compressible_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def colored(x, *args, **kwargs):


class CompressibleAgent(ConversableAgent):
"""(Experimental) CompressibleAgent agent. While this agent retains all the default functionalities of the `AssistantAgent`,
"""(CompressibleAgent will be deprecated. Refer to https://github.com/microsoft/autogen/blob/main/notebook/agentchat_capability_long_context_handling.ipynb for long context handling capability.) CompressibleAgent agent. While this agent retains all the default functionalities of the `AssistantAgent`,
it also provides the added feature of compression when activated through the `compress_config` setting.
`compress_config` is set to False by default, making this agent equivalent to the `AssistantAgent`.
Expand Down
37 changes: 22 additions & 15 deletions autogen/agentchat/contrib/math_user_proxy_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,28 +177,35 @@ def __init__(
self._previous_code = ""
self.last_reply = None

def generate_init_message(self, problem, prompt_type="default", customized_prompt=None):
@staticmethod
def message_generator(sender, recipient, context):
"""Generate a prompt for the assistant agent with the given problem and prompt.
Args:
problem (str): the problem to be solved.
prompt_type (str): the type of the prompt. Possible values are "default", "python", "wolfram".
(1) "default": the prompt that allows the agent to choose between 3 ways to solve a problem:
1. write a python program to solve it directly.
2. solve it directly without python.
3. solve it step by step with python.
(2) "python":
a simplified prompt from the third way of the "default" prompt, that asks the assistant
to solve the problem step by step with python.
(3) "two_tools":
a simplified prompt similar to the "python" prompt, but allows the model to choose between
Python and Wolfram Alpha to solve the problem.
customized_prompt (str): a customized prompt to be used. If it is not None, the prompt_type will be ignored.
sender (Agent): the sender of the message.
recipient (Agent): the recipient of the message.
context (dict): a dictionary with the following fields:
problem (str): the problem to be solved.
prompt_type (str, Optional): the type of the prompt. Possible values are "default", "python", "wolfram".
(1) "default": the prompt that allows the agent to choose between 3 ways to solve a problem:
1. write a python program to solve it directly.
2. solve it directly without python.
3. solve it step by step with python.
(2) "python":
a simplified prompt from the third way of the "default" prompt, that asks the assistant
to solve the problem step by step with python.
(3) "two_tools":
a simplified prompt similar to the "python" prompt, but allows the model to choose between
Python and Wolfram Alpha to solve the problem.
customized_prompt (str, Optional): a customized prompt to be used. If it is not None, the prompt_type will be ignored.
Returns:
str: the generated prompt ready to be sent to the assistant agent.
"""
self._reset()
sender._reset()
problem = context.get("problem")
prompt_type = context.get("prompt_type", "default")
customized_prompt = context.get("customized_prompt", None)
if customized_prompt is not None:
return customized_prompt + problem
return PROMPTS[prompt_type] + problem
Expand Down
36 changes: 22 additions & 14 deletions autogen/agentchat/contrib/retrieve_user_proxy_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,23 +408,31 @@ def retrieve_docs(self, problem: str, n_results: int = 20, search_string: str =
self._results = results
print("doc_ids: ", results["ids"])

def generate_init_message(self, problem: str, n_results: int = 20, search_string: str = ""):
"""Generate an initial message with the given problem and prompt.
@staticmethod
def message_generator(sender, recipient, context):
"""
Generate an initial message with the given context for the RetrieveUserProxyAgent.
Args:
problem (str): the problem to be solved.
n_results (int): the number of results to be retrieved.
search_string (str): only docs containing this string will be retrieved.
sender (Agent): the sender agent. It should be the instance of RetrieveUserProxyAgent.
recipient (Agent): the recipient agent. Usually it's the assistant agent.
context (dict): the context for the message generation. It should contain the following keys:
- problem (str): the problem to be solved.
- n_results (int): the number of results to be retrieved. Default is 20.
- search_string (str): only docs that contain an exact match of this string will be retrieved. Default is "".
Returns:
str: the generated prompt ready to be sent to the assistant agent.
str: the generated message ready to be sent to the recipient agent.
"""
self._reset()
self.retrieve_docs(problem, n_results, search_string)
self.problem = problem
self.n_results = n_results
doc_contents = self._get_context(self._results)
message = self._generate_message(doc_contents, self._task)
sender._reset()

problem = context.get("problem", "")
n_results = context.get("n_results", 20)
search_string = context.get("search_string", "")

sender.retrieve_docs(problem, n_results, search_string)
sender.problem = problem
sender.n_results = n_results
doc_contents = sender._get_context(sender._results)
message = sender._generate_message(doc_contents, sender._task)
return message

def run_code(self, code, **kwargs):
Expand Down
Loading

0 comments on commit c75655a

Please sign in to comment.