You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_conversable_agent.py 51 kB

Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
raise error when msg is invalid; fix docstr; improve ResponsiveAgent; update doc and packaging; capture ipython output; find code blocks with llm when regex fails. (#1154) * autogen.agent -> autogen.agentchat * bug fix in portfolio * notebook * timeout * timeout * infer lang; close #1150 * timeout * message context * context handling * add sender to generate_reply * clean up the receive function * move mathchat to contrib * contrib * last_message * Add OptiGuide: agent and notebook * Optiguide notebook: add figures and URL 1. figures and code points to remote URL 2. simplify the prompt for the interpreter, because all information is already in the chat history. * Update name: Agent -> GenericAgent * Update notebook * Rename: GenericAgent -> ResponsiveAgent * Rebase to autogen.agentchat * OptiGuide: Comment, sytle, and notebook updates * simplify optiguide * raise error when msg is invalid; fix docstr * allow return None for generate_reply() * update_system_message * test update_system_message * simplify optiguide * simplify optiguide * simplify optiguide * simplify optiguide * move test * add test and fix bug * doc update * doc update * doc update * color * optiguide * prompt * test danger case * packaging * docker * remove path in traceback * capture ipython output * simplify * find code blocks with llm * find code with llm * order * order * fix bug in context handling * print executing msg * print executing msg * test find code * test find code * disable find_code * default_auto_reply * default auto reply * remove optiguide * remove -e --------- Co-authored-by: Beibin Li <beibin79@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
raise error when msg is invalid; fix docstr; improve ResponsiveAgent; update doc and packaging; capture ipython output; find code blocks with llm when regex fails. (#1154) * autogen.agent -> autogen.agentchat * bug fix in portfolio * notebook * timeout * timeout * infer lang; close #1150 * timeout * message context * context handling * add sender to generate_reply * clean up the receive function * move mathchat to contrib * contrib * last_message * Add OptiGuide: agent and notebook * Optiguide notebook: add figures and URL 1. figures and code points to remote URL 2. simplify the prompt for the interpreter, because all information is already in the chat history. * Update name: Agent -> GenericAgent * Update notebook * Rename: GenericAgent -> ResponsiveAgent * Rebase to autogen.agentchat * OptiGuide: Comment, sytle, and notebook updates * simplify optiguide * raise error when msg is invalid; fix docstr * allow return None for generate_reply() * update_system_message * test update_system_message * simplify optiguide * simplify optiguide * simplify optiguide * simplify optiguide * move test * add test and fix bug * doc update * doc update * doc update * color * optiguide * prompt * test danger case * packaging * docker * remove path in traceback * capture ipython output * simplify * find code blocks with llm * find code with llm * order * order * fix bug in context handling * print executing msg * print executing msg * test find code * test find code * disable find_code * default_auto_reply * default auto reply * remove optiguide * remove -e --------- Co-authored-by: Beibin Li <beibin79@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
raise error when msg is invalid; fix docstr; improve ResponsiveAgent; update doc and packaging; capture ipython output; find code blocks with llm when regex fails. (#1154) * autogen.agent -> autogen.agentchat * bug fix in portfolio * notebook * timeout * timeout * infer lang; close #1150 * timeout * message context * context handling * add sender to generate_reply * clean up the receive function * move mathchat to contrib * contrib * last_message * Add OptiGuide: agent and notebook * Optiguide notebook: add figures and URL 1. figures and code points to remote URL 2. simplify the prompt for the interpreter, because all information is already in the chat history. * Update name: Agent -> GenericAgent * Update notebook * Rename: GenericAgent -> ResponsiveAgent * Rebase to autogen.agentchat * OptiGuide: Comment, sytle, and notebook updates * simplify optiguide * raise error when msg is invalid; fix docstr * allow return None for generate_reply() * update_system_message * test update_system_message * simplify optiguide * simplify optiguide * simplify optiguide * simplify optiguide * move test * add test and fix bug * doc update * doc update * doc update * color * optiguide * prompt * test danger case * packaging * docker * remove path in traceback * capture ipython output * simplify * find code blocks with llm * find code with llm * order * order * fix bug in context handling * print executing msg * print executing msg * test find code * test find code * disable find_code * default_auto_reply * default auto reply * remove optiguide * remove -e --------- Co-authored-by: Beibin Li <beibin79@gmail.com>
3 years ago
raise error when msg is invalid; fix docstr; improve ResponsiveAgent; update doc and packaging; capture ipython output; find code blocks with llm when regex fails. (#1154) * autogen.agent -> autogen.agentchat * bug fix in portfolio * notebook * timeout * timeout * infer lang; close #1150 * timeout * message context * context handling * add sender to generate_reply * clean up the receive function * move mathchat to contrib * contrib * last_message * Add OptiGuide: agent and notebook * Optiguide notebook: add figures and URL 1. figures and code points to remote URL 2. simplify the prompt for the interpreter, because all information is already in the chat history. * Update name: Agent -> GenericAgent * Update notebook * Rename: GenericAgent -> ResponsiveAgent * Rebase to autogen.agentchat * OptiGuide: Comment, sytle, and notebook updates * simplify optiguide * raise error when msg is invalid; fix docstr * allow return None for generate_reply() * update_system_message * test update_system_message * simplify optiguide * simplify optiguide * simplify optiguide * simplify optiguide * move test * add test and fix bug * doc update * doc update * doc update * color * optiguide * prompt * test danger case * packaging * docker * remove path in traceback * capture ipython output * simplify * find code blocks with llm * find code with llm * order * order * fix bug in context handling * print executing msg * print executing msg * test find code * test find code * disable find_code * default_auto_reply * default auto reply * remove optiguide * remove -e --------- Co-authored-by: Beibin Li <beibin79@gmail.com>
3 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
[Core] [Tool Call] adjust conversable agent to support tool_calls (#974) * adjust conversable and compressible agents to support tool_calls * split out tools into their own reply def * copilot typo * address review comments * revert compressible_agent and token_count_utils calls * cleanup terminate check and remove unnecessary code * doc search and update * return function/tool calls as interrupted when user provides a reply to a tool call request * fix tool name reference * fix formatting * fix initiate receiving a dict * missed changed roled * ignore incoming role, more similiar to existing code * consistency * redundant to_dict * fix todo comment * uneeded change * handle dict reply in groupchat * Fix generate_tool_call_calls_reply_comment * change method annotation for register_for_llm from functions to tools * typo autogen/agentchat/conversable_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * add deprecation comments for function_call * tweak doc strings * switch to ToolFunction type * update the return to * fix generate_init_message return type * Revert "fix generate_init_message return type" This reverts commit 645ba8b76afa06f160223ecdac6f3dc1822fd249. * undo force init to dict * fix notebooks and groupchat tool handling * fix type * use get for key error * fix teachable to pull content from dict * change single message tool response * cleanup unnessary changes * little better tool response concatenation * update tools tests * add skip openai check to tools tests * fix nits * move func name normalization to oai_reply and assert configured names * fix whitespace * remove extra normalize * tool name is now normalized in the generate_reply function, so will not be incorrect when sent to receive * validate function names in init and expand comments for validation methods * fix dict comprehension * Dummy llm config for unit tests * handle tool_calls set to None * fix tool name reference * method operates on responses not calls --------- Co-authored-by: Yiran Wu <32823396+kevin666aa@users.noreply.github.com> Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2 years ago
[Core] [Tool Call] adjust conversable agent to support tool_calls (#974) * adjust conversable and compressible agents to support tool_calls * split out tools into their own reply def * copilot typo * address review comments * revert compressible_agent and token_count_utils calls * cleanup terminate check and remove unnecessary code * doc search and update * return function/tool calls as interrupted when user provides a reply to a tool call request * fix tool name reference * fix formatting * fix initiate receiving a dict * missed changed roled * ignore incoming role, more similiar to existing code * consistency * redundant to_dict * fix todo comment * uneeded change * handle dict reply in groupchat * Fix generate_tool_call_calls_reply_comment * change method annotation for register_for_llm from functions to tools * typo autogen/agentchat/conversable_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * add deprecation comments for function_call * tweak doc strings * switch to ToolFunction type * update the return to * fix generate_init_message return type * Revert "fix generate_init_message return type" This reverts commit 645ba8b76afa06f160223ecdac6f3dc1822fd249. * undo force init to dict * fix notebooks and groupchat tool handling * fix type * use get for key error * fix teachable to pull content from dict * change single message tool response * cleanup unnessary changes * little better tool response concatenation * update tools tests * add skip openai check to tools tests * fix nits * move func name normalization to oai_reply and assert configured names * fix whitespace * remove extra normalize * tool name is now normalized in the generate_reply function, so will not be incorrect when sent to receive * validate function names in init and expand comments for validation methods * fix dict comprehension * Dummy llm config for unit tests * handle tool_calls set to None * fix tool name reference * method operates on responses not calls --------- Co-authored-by: Yiran Wu <32823396+kevin666aa@users.noreply.github.com> Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2 years ago
[Core] [Tool Call] adjust conversable agent to support tool_calls (#974) * adjust conversable and compressible agents to support tool_calls * split out tools into their own reply def * copilot typo * address review comments * revert compressible_agent and token_count_utils calls * cleanup terminate check and remove unnecessary code * doc search and update * return function/tool calls as interrupted when user provides a reply to a tool call request * fix tool name reference * fix formatting * fix initiate receiving a dict * missed changed roled * ignore incoming role, more similiar to existing code * consistency * redundant to_dict * fix todo comment * uneeded change * handle dict reply in groupchat * Fix generate_tool_call_calls_reply_comment * change method annotation for register_for_llm from functions to tools * typo autogen/agentchat/conversable_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * add deprecation comments for function_call * tweak doc strings * switch to ToolFunction type * update the return to * fix generate_init_message return type * Revert "fix generate_init_message return type" This reverts commit 645ba8b76afa06f160223ecdac6f3dc1822fd249. * undo force init to dict * fix notebooks and groupchat tool handling * fix type * use get for key error * fix teachable to pull content from dict * change single message tool response * cleanup unnessary changes * little better tool response concatenation * update tools tests * add skip openai check to tools tests * fix nits * move func name normalization to oai_reply and assert configured names * fix whitespace * remove extra normalize * tool name is now normalized in the generate_reply function, so will not be incorrect when sent to receive * validate function names in init and expand comments for validation methods * fix dict comprehension * Dummy llm config for unit tests * handle tool_calls set to None * fix tool name reference * method operates on responses not calls --------- Co-authored-by: Yiran Wu <32823396+kevin666aa@users.noreply.github.com> Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2 years ago
[Core] [Tool Call] adjust conversable agent to support tool_calls (#974) * adjust conversable and compressible agents to support tool_calls * split out tools into their own reply def * copilot typo * address review comments * revert compressible_agent and token_count_utils calls * cleanup terminate check and remove unnecessary code * doc search and update * return function/tool calls as interrupted when user provides a reply to a tool call request * fix tool name reference * fix formatting * fix initiate receiving a dict * missed changed roled * ignore incoming role, more similiar to existing code * consistency * redundant to_dict * fix todo comment * uneeded change * handle dict reply in groupchat * Fix generate_tool_call_calls_reply_comment * change method annotation for register_for_llm from functions to tools * typo autogen/agentchat/conversable_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * add deprecation comments for function_call * tweak doc strings * switch to ToolFunction type * update the return to * fix generate_init_message return type * Revert "fix generate_init_message return type" This reverts commit 645ba8b76afa06f160223ecdac6f3dc1822fd249. * undo force init to dict * fix notebooks and groupchat tool handling * fix type * use get for key error * fix teachable to pull content from dict * change single message tool response * cleanup unnessary changes * little better tool response concatenation * update tools tests * add skip openai check to tools tests * fix nits * move func name normalization to oai_reply and assert configured names * fix whitespace * remove extra normalize * tool name is now normalized in the generate_reply function, so will not be incorrect when sent to receive * validate function names in init and expand comments for validation methods * fix dict comprehension * Dummy llm config for unit tests * handle tool_calls set to None * fix tool name reference * method operates on responses not calls --------- Co-authored-by: Yiran Wu <32823396+kevin666aa@users.noreply.github.com> Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2 years ago
[Core] [Tool Call] adjust conversable agent to support tool_calls (#974) * adjust conversable and compressible agents to support tool_calls * split out tools into their own reply def * copilot typo * address review comments * revert compressible_agent and token_count_utils calls * cleanup terminate check and remove unnecessary code * doc search and update * return function/tool calls as interrupted when user provides a reply to a tool call request * fix tool name reference * fix formatting * fix initiate receiving a dict * missed changed roled * ignore incoming role, more similiar to existing code * consistency * redundant to_dict * fix todo comment * uneeded change * handle dict reply in groupchat * Fix generate_tool_call_calls_reply_comment * change method annotation for register_for_llm from functions to tools * typo autogen/agentchat/conversable_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * add deprecation comments for function_call * tweak doc strings * switch to ToolFunction type * update the return to * fix generate_init_message return type * Revert "fix generate_init_message return type" This reverts commit 645ba8b76afa06f160223ecdac6f3dc1822fd249. * undo force init to dict * fix notebooks and groupchat tool handling * fix type * use get for key error * fix teachable to pull content from dict * change single message tool response * cleanup unnessary changes * little better tool response concatenation * update tools tests * add skip openai check to tools tests * fix nits * move func name normalization to oai_reply and assert configured names * fix whitespace * remove extra normalize * tool name is now normalized in the generate_reply function, so will not be incorrect when sent to receive * validate function names in init and expand comments for validation methods * fix dict comprehension * Dummy llm config for unit tests * handle tool_calls set to None * fix tool name reference * method operates on responses not calls --------- Co-authored-by: Yiran Wu <32823396+kevin666aa@users.noreply.github.com> Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Eric Zhu <ekzhu@users.noreply.github.com>
2 years ago
Validate llm_config passed to ConversableAgent (issue #1522) (#1654) * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None`. - The `llm_config` is valid, but `config_list` is missing or lacks elements. - The `config_list` is valid, but no `model` is specified. The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Fix the test_web_surfer issue For anyone reading this: you need to `pip install markdownify` for the `import WebSurferAgent` to succeed. That is needed to run the `test_web_surfer.py` locally. Test logic needs `llm_config` that is not `None` and that is not `False`. Let us pray that this works as part of GitHub actions ... * One more fix for llm_config validation contract
2 years ago
Validate llm_config passed to ConversableAgent (issue #1522) (#1654) * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None`. - The `llm_config` is valid, but `config_list` is missing or lacks elements. - The `config_list` is valid, but no `model` is specified. The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Fix the test_web_surfer issue For anyone reading this: you need to `pip install markdownify` for the `import WebSurferAgent` to succeed. That is needed to run the `test_web_surfer.py` locally. Test logic needs `llm_config` that is not `None` and that is not `False`. Let us pray that this works as part of GitHub actions ... * One more fix for llm_config validation contract
2 years ago
Validate llm_config passed to ConversableAgent (issue #1522) (#1654) * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None`. - The `llm_config` is valid, but `config_list` is missing or lacks elements. - The `config_list` is valid, but no `model` is specified. The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Validate llm_config passed to ConversableAgent Based on #1522, this commit implements the additional validation checks in `ConversableAgent.` Add the following validation and `raise ValueError` if: - The `llm_config` is `None` (validated in `ConversableAgent`). - The `llm_config` has no `model` specified and `config_list` is empty (validated in `OpenAIWrapper`). - The `config_list` has at least one entry, but not all the entries have the `model` is specified (validated in `OpenAIWrapper`). The rest of the changes are code churn to adjust or add the test cases. * Fix the test_web_surfer issue For anyone reading this: you need to `pip install markdownify` for the `import WebSurferAgent` to succeed. That is needed to run the `test_web_surfer.py` locally. Test logic needs `llm_config` that is not `None` and that is not `False`. Let us pray that this works as part of GitHub actions ... * One more fix for llm_config validation contract
2 years ago
Support function_call in `autogen/agent` (#1091) * update funccall * code format * update to comments * update notebook * remove test for py3.7 * allow funccall to class functions * add test and clean up notebook * revise notebook and test * update * update mathagent * Update flaml/autogen/agent/agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * revise to comments * revise function call design, notebook and test. add doc * code format * ad message_to_dict function * update mathproxyagent * revise docstr * update * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * Update flaml/autogen/agent/math_user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * Update flaml/autogen/agent/user_proxy_agent.py Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> * simply funccall in userproxyagent, rewind auto-gen.md, revise to comments * code format * update * remove notebook for another pr * revise oai_conversation part in agent, revise function exec in user_proxy_agent * update test_funccall * update * update * fix pydantic version * Update test/autogen/test_agent.py Co-authored-by: Chi Wang <wang.chi@microsoft.com> * fix bug * fix bug * update * update is_termination_msg to accept dict --------- Co-authored-by: Chi Wang <wang.chi@microsoft.com> Co-authored-by: Qingyun Wu <qingyun.wu@psu.edu> Co-authored-by: Li Jiang <bnujli@gmail.com>
3 years ago
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325
  1. #!/usr/bin/env python3 -m pytest
  2. import asyncio
  3. import copy
  4. import sys
  5. import time
  6. from typing import Any, Callable, Dict, Literal
  7. import unittest
  8. import inspect
  9. from unittest.mock import MagicMock
  10. import pytest
  11. from pydantic import BaseModel, Field
  12. from typing_extensions import Annotated
  13. import autogen
  14. import os
  15. from autogen.agentchat import ConversableAgent, UserProxyAgent
  16. from autogen.agentchat.conversable_agent import register_function
  17. from autogen.exception_utils import InvalidCarryOverType, SenderRequired
  18. from test_assistant_agent import KEY_LOC, OAI_CONFIG_LIST
  19. sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
  20. from conftest import MOCK_OPEN_AI_API_KEY, skip_openai # noqa: E402
  21. here = os.path.abspath(os.path.dirname(__file__))
  22. REASON = "requested to skip openai tests"
  23. @pytest.fixture
  24. def conversable_agent():
  25. return ConversableAgent(
  26. "conversable_agent_0",
  27. max_consecutive_auto_reply=10,
  28. code_execution_config=False,
  29. llm_config=False,
  30. human_input_mode="NEVER",
  31. )
  32. def test_sync_trigger():
  33. agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  34. agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  35. agent.register_reply(agent1, lambda recipient, messages, sender, config: (True, "hello"))
  36. agent1.initiate_chat(agent, message="hi")
  37. assert agent1.last_message(agent)["content"] == "hello"
  38. agent.register_reply("a1", lambda recipient, messages, sender, config: (True, "hello a1"))
  39. agent1.initiate_chat(agent, message="hi")
  40. assert agent1.last_message(agent)["content"] == "hello a1"
  41. agent.register_reply(
  42. ConversableAgent, lambda recipient, messages, sender, config: (True, "hello conversable agent")
  43. )
  44. agent1.initiate_chat(agent, message="hi")
  45. assert agent1.last_message(agent)["content"] == "hello conversable agent"
  46. agent.register_reply(
  47. lambda sender: sender.name.startswith("a"), lambda recipient, messages, sender, config: (True, "hello a")
  48. )
  49. agent1.initiate_chat(agent, message="hi")
  50. assert agent1.last_message(agent)["content"] == "hello a"
  51. agent.register_reply(
  52. lambda sender: sender.name.startswith("b"), lambda recipient, messages, sender, config: (True, "hello b")
  53. )
  54. agent1.initiate_chat(agent, message="hi")
  55. assert agent1.last_message(agent)["content"] == "hello a"
  56. agent.register_reply(
  57. ["agent2", agent1], lambda recipient, messages, sender, config: (True, "hello agent2 or agent1")
  58. )
  59. agent1.initiate_chat(agent, message="hi")
  60. assert agent1.last_message(agent)["content"] == "hello agent2 or agent1"
  61. agent.register_reply(
  62. ["agent2", "agent3"], lambda recipient, messages, sender, config: (True, "hello agent2 or agent3")
  63. )
  64. agent1.initiate_chat(agent, message="hi")
  65. assert agent1.last_message(agent)["content"] == "hello agent2 or agent1"
  66. pytest.raises(ValueError, agent.register_reply, 1, lambda recipient, messages, sender, config: (True, "hi"))
  67. pytest.raises(ValueError, agent._match_trigger, 1, agent1)
  68. @pytest.mark.asyncio
  69. async def test_async_trigger():
  70. agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  71. agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  72. async def a_reply(recipient, messages, sender, config):
  73. print("hello from a_reply")
  74. return (True, "hello")
  75. agent.register_reply(agent1, a_reply)
  76. await agent1.a_initiate_chat(agent, message="hi")
  77. assert agent1.last_message(agent)["content"] == "hello"
  78. async def a_reply_a1(recipient, messages, sender, config):
  79. print("hello from a_reply_a1")
  80. return (True, "hello a1")
  81. agent.register_reply("a1", a_reply_a1)
  82. await agent1.a_initiate_chat(agent, message="hi")
  83. assert agent1.last_message(agent)["content"] == "hello a1"
  84. async def a_reply_conversable_agent(recipient, messages, sender, config):
  85. print("hello from a_reply_conversable_agent")
  86. return (True, "hello conversable agent")
  87. agent.register_reply(ConversableAgent, a_reply_conversable_agent)
  88. await agent1.a_initiate_chat(agent, message="hi")
  89. assert agent1.last_message(agent)["content"] == "hello conversable agent"
  90. async def a_reply_a(recipient, messages, sender, config):
  91. print("hello from a_reply_a")
  92. return (True, "hello a")
  93. agent.register_reply(lambda sender: sender.name.startswith("a"), a_reply_a)
  94. await agent1.a_initiate_chat(agent, message="hi")
  95. assert agent1.last_message(agent)["content"] == "hello a"
  96. async def a_reply_b(recipient, messages, sender, config):
  97. print("hello from a_reply_b")
  98. return (True, "hello b")
  99. agent.register_reply(lambda sender: sender.name.startswith("b"), a_reply_b)
  100. await agent1.a_initiate_chat(agent, message="hi")
  101. assert agent1.last_message(agent)["content"] == "hello a"
  102. async def a_reply_agent2_or_agent1(recipient, messages, sender, config):
  103. print("hello from a_reply_agent2_or_agent1")
  104. return (True, "hello agent2 or agent1")
  105. agent.register_reply(["agent2", agent1], a_reply_agent2_or_agent1)
  106. await agent1.a_initiate_chat(agent, message="hi")
  107. assert agent1.last_message(agent)["content"] == "hello agent2 or agent1"
  108. async def a_reply_agent2_or_agent3(recipient, messages, sender, config):
  109. print("hello from a_reply_agent2_or_agent3")
  110. return (True, "hello agent2 or agent3")
  111. agent.register_reply(["agent2", "agent3"], a_reply_agent2_or_agent3)
  112. await agent1.a_initiate_chat(agent, message="hi")
  113. assert agent1.last_message(agent)["content"] == "hello agent2 or agent1"
  114. with pytest.raises(ValueError):
  115. agent.register_reply(1, a_reply)
  116. with pytest.raises(ValueError):
  117. agent._match_trigger(1, agent1)
  118. def test_async_trigger_in_sync_chat():
  119. agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  120. agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  121. agent2 = ConversableAgent("a2", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  122. reply_mock = unittest.mock.MagicMock()
  123. async def a_reply(recipient, messages, sender, config):
  124. reply_mock()
  125. print("hello from a_reply")
  126. return (True, "hello from reply function")
  127. agent.register_reply(agent1, a_reply)
  128. with pytest.raises(RuntimeError) as e:
  129. agent1.initiate_chat(agent, message="hi")
  130. assert (
  131. e.value.args[0] == "Async reply functions can only be used with ConversableAgent.a_initiate_chat(). "
  132. "The following async reply functions are found: a_reply"
  133. )
  134. agent2.register_reply(agent1, a_reply, ignore_async_in_sync_chat=True)
  135. reply_mock.assert_not_called()
  136. @pytest.mark.asyncio
  137. async def test_sync_trigger_in_async_chat():
  138. agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  139. agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  140. def a_reply(recipient, messages, sender, config):
  141. print("hello from a_reply")
  142. return (True, "hello from reply function")
  143. agent.register_reply(agent1, a_reply)
  144. await agent1.a_initiate_chat(agent, message="hi")
  145. assert agent1.last_message(agent)["content"] == "hello from reply function"
  146. def test_context():
  147. agent = ConversableAgent("a0", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  148. agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  149. agent1.send(
  150. {
  151. "content": "hello {name}",
  152. "context": {
  153. "name": "there",
  154. },
  155. },
  156. agent,
  157. )
  158. # expect hello {name} to be printed
  159. agent1.send(
  160. {
  161. "content": lambda context: f"hello {context['name']}",
  162. "context": {
  163. "name": "there",
  164. },
  165. },
  166. agent,
  167. )
  168. # expect hello there to be printed
  169. agent.llm_config = {"allow_format_str_template": True}
  170. agent1.send(
  171. {
  172. "content": "hello {name}",
  173. "context": {
  174. "name": "there",
  175. },
  176. },
  177. agent,
  178. )
  179. # expect hello there to be printed
  180. def test_generate_code_execution_reply():
  181. agent = ConversableAgent(
  182. "a0", max_consecutive_auto_reply=10, code_execution_config=False, llm_config=False, human_input_mode="NEVER"
  183. )
  184. dummy_messages = [
  185. {
  186. "content": "no code block",
  187. "role": "user",
  188. },
  189. {
  190. "content": "no code block",
  191. "role": "user",
  192. },
  193. ]
  194. code_message = {
  195. "content": '```python\nprint("hello world")\n```',
  196. "role": "user",
  197. }
  198. # scenario 1: if code_execution_config is not provided, the code execution should return false, none
  199. assert agent.generate_code_execution_reply(dummy_messages, config=False) == (False, None)
  200. # scenario 2: if code_execution_config is provided, but no code block is found, the code execution should return false, none
  201. assert agent.generate_code_execution_reply(dummy_messages, config={}) == (False, None)
  202. # scenario 3: if code_execution_config is provided, and code block is found, but it's not within the range of last_n_messages, the code execution should return false, none
  203. assert agent.generate_code_execution_reply([code_message] + dummy_messages, config={"last_n_messages": 1}) == (
  204. False,
  205. None,
  206. )
  207. # scenario 4: if code_execution_config is provided, and code block is found, and it's within the range of last_n_messages, the code execution should return true, code block
  208. agent._code_execution_config = {"last_n_messages": 3, "use_docker": False}
  209. assert agent.generate_code_execution_reply([code_message] + dummy_messages) == (
  210. True,
  211. "exitcode: 0 (execution succeeded)\nCode output: \nhello world\n",
  212. )
  213. assert agent._code_execution_config["last_n_messages"] == 3
  214. # scenario 5: if last_n_messages is set to 'auto' and no code is found, then nothing breaks both when an assistant message is and isn't present
  215. assistant_message_for_auto = {
  216. "content": "This is me! The assistant!",
  217. "role": "assistant",
  218. }
  219. dummy_messages_for_auto = []
  220. for i in range(3):
  221. dummy_messages_for_auto.append(
  222. {
  223. "content": "no code block",
  224. "role": "user",
  225. }
  226. )
  227. # Without an assistant present
  228. agent._code_execution_config = {"last_n_messages": "auto", "use_docker": False}
  229. assert agent.generate_code_execution_reply(dummy_messages_for_auto) == (
  230. False,
  231. None,
  232. )
  233. # With an assistant message present
  234. agent._code_execution_config = {"last_n_messages": "auto", "use_docker": False}
  235. assert agent.generate_code_execution_reply([assistant_message_for_auto] + dummy_messages_for_auto) == (
  236. False,
  237. None,
  238. )
  239. # scenario 6: if last_n_messages is set to 'auto' and code is found, then we execute it correctly
  240. dummy_messages_for_auto = []
  241. for i in range(4):
  242. # Without an assistant present
  243. agent._code_execution_config = {"last_n_messages": "auto", "use_docker": False}
  244. assert agent.generate_code_execution_reply([code_message] + dummy_messages_for_auto) == (
  245. True,
  246. "exitcode: 0 (execution succeeded)\nCode output: \nhello world\n",
  247. )
  248. # With an assistant message present
  249. agent._code_execution_config = {"last_n_messages": "auto", "use_docker": False}
  250. assert agent.generate_code_execution_reply(
  251. [assistant_message_for_auto] + [code_message] + dummy_messages_for_auto
  252. ) == (
  253. True,
  254. "exitcode: 0 (execution succeeded)\nCode output: \nhello world\n",
  255. )
  256. dummy_messages_for_auto.append(
  257. {
  258. "content": "no code block",
  259. "role": "user",
  260. }
  261. )
  262. # scenario 7: if last_n_messages is set to 'auto' and code is present, but not before an assistant message, then nothing happens
  263. agent._code_execution_config = {"last_n_messages": "auto", "use_docker": False}
  264. assert agent.generate_code_execution_reply(
  265. [code_message] + [assistant_message_for_auto] + dummy_messages_for_auto
  266. ) == (
  267. False,
  268. None,
  269. )
  270. assert agent._code_execution_config["last_n_messages"] == "auto"
  271. # scenario 8: if last_n_messages is misconfigures, we expect to see an error
  272. with pytest.raises(ValueError):
  273. agent._code_execution_config = {"last_n_messages": -1, "use_docker": False}
  274. agent.generate_code_execution_reply([code_message])
  275. with pytest.raises(ValueError):
  276. agent._code_execution_config = {"last_n_messages": "hello world", "use_docker": False}
  277. agent.generate_code_execution_reply([code_message])
  278. def test_max_consecutive_auto_reply():
  279. agent = ConversableAgent("a0", max_consecutive_auto_reply=2, llm_config=False, human_input_mode="NEVER")
  280. agent1 = ConversableAgent("a1", max_consecutive_auto_reply=0, llm_config=False, human_input_mode="NEVER")
  281. assert agent.max_consecutive_auto_reply() == agent.max_consecutive_auto_reply(agent1) == 2
  282. agent.update_max_consecutive_auto_reply(1)
  283. assert agent.max_consecutive_auto_reply() == agent.max_consecutive_auto_reply(agent1) == 1
  284. agent1.initiate_chat(agent, message="hello")
  285. assert agent._consecutive_auto_reply_counter[agent1] == 1
  286. agent1.initiate_chat(agent, message="hello again")
  287. # with auto reply because the counter is reset
  288. assert agent1.last_message(agent)["role"] == "user"
  289. assert len(agent1.chat_messages[agent]) == 2
  290. assert len(agent.chat_messages[agent1]) == 2
  291. assert agent._consecutive_auto_reply_counter[agent1] == 1
  292. agent1.send(message="bye", recipient=agent)
  293. # no auto reply
  294. assert agent1.last_message(agent)["role"] == "assistant"
  295. agent1.initiate_chat(agent, clear_history=False, message="hi")
  296. assert len(agent1.chat_messages[agent]) > 2
  297. assert len(agent.chat_messages[agent1]) > 2
  298. assert agent1.reply_at_receive[agent] == agent.reply_at_receive[agent1] is True
  299. agent1.stop_reply_at_receive(agent)
  300. assert agent1.reply_at_receive[agent] is False and agent.reply_at_receive[agent1] is True
  301. def test_conversable_agent():
  302. dummy_agent_1 = ConversableAgent(name="dummy_agent_1", llm_config=False, human_input_mode="ALWAYS")
  303. dummy_agent_2 = ConversableAgent(name="dummy_agent_2", llm_config=False, human_input_mode="TERMINATE")
  304. # monkeypatch.setattr(sys, "stdin", StringIO("exit"))
  305. dummy_agent_1.receive("hello", dummy_agent_2) # receive a str
  306. # monkeypatch.setattr(sys, "stdin", StringIO("TERMINATE\n\n"))
  307. dummy_agent_1.receive(
  308. {
  309. "content": "hello {name}",
  310. "context": {
  311. "name": "dummy_agent_2",
  312. },
  313. },
  314. dummy_agent_2,
  315. ) # receive a dict
  316. assert "context" in dummy_agent_1.chat_messages[dummy_agent_2][-1]
  317. # receive dict without openai fields to be printed, such as "content", 'function_call'. There should be no error raised.
  318. pre_len = len(dummy_agent_1.chat_messages[dummy_agent_2])
  319. with pytest.raises(ValueError):
  320. dummy_agent_1.receive({"message": "hello"}, dummy_agent_2)
  321. assert pre_len == len(
  322. dummy_agent_1.chat_messages[dummy_agent_2]
  323. ), "When the message is not an valid openai message, it should not be appended to the oai conversation."
  324. # monkeypatch.setattr(sys, "stdin", StringIO("exit"))
  325. dummy_agent_1.send("TERMINATE", dummy_agent_2) # send a str
  326. # monkeypatch.setattr(sys, "stdin", StringIO("exit"))
  327. dummy_agent_1.send(
  328. {
  329. "content": "TERMINATE",
  330. },
  331. dummy_agent_2,
  332. ) # send a dict
  333. # send dict with no openai fields
  334. pre_len = len(dummy_agent_1.chat_messages[dummy_agent_2])
  335. with pytest.raises(ValueError):
  336. dummy_agent_1.send({"message": "hello"}, dummy_agent_2)
  337. assert pre_len == len(
  338. dummy_agent_1.chat_messages[dummy_agent_2]
  339. ), "When the message is not a valid openai message, it should not be appended to the oai conversation."
  340. # update system message
  341. dummy_agent_1.update_system_message("new system message")
  342. assert dummy_agent_1.system_message == "new system message"
  343. dummy_agent_3 = ConversableAgent(name="dummy_agent_3", llm_config=False, human_input_mode="TERMINATE")
  344. with pytest.raises(KeyError):
  345. dummy_agent_1.last_message(dummy_agent_3)
  346. # Check the description field
  347. assert dummy_agent_1.description != dummy_agent_1.system_message
  348. assert dummy_agent_2.description == dummy_agent_2.system_message
  349. dummy_agent_4 = ConversableAgent(
  350. name="dummy_agent_4",
  351. system_message="The fourth dummy agent used for testing.",
  352. llm_config=False,
  353. human_input_mode="TERMINATE",
  354. )
  355. assert dummy_agent_4.description == "The fourth dummy agent used for testing." # Same as system message
  356. dummy_agent_5 = ConversableAgent(
  357. name="dummy_agent_5",
  358. system_message="",
  359. description="The fifth dummy agent used for testing.",
  360. llm_config=False,
  361. human_input_mode="TERMINATE",
  362. )
  363. assert dummy_agent_5.description == "The fifth dummy agent used for testing." # Same as system message
  364. def test_generate_reply():
  365. def add_num(num_to_be_added):
  366. given_num = 10
  367. return num_to_be_added + given_num
  368. dummy_agent_2 = ConversableAgent(
  369. name="user_proxy", llm_config=False, human_input_mode="TERMINATE", function_map={"add_num": add_num}
  370. )
  371. messages = [{"function_call": {"name": "add_num", "arguments": '{ "num_to_be_added": 5 }'}, "role": "assistant"}]
  372. # when sender is None, messages is provided
  373. assert (
  374. dummy_agent_2.generate_reply(messages=messages, sender=None)["content"] == "15"
  375. ), "generate_reply not working when sender is None"
  376. # when sender is provided, messages is None
  377. dummy_agent_1 = ConversableAgent(name="dummy_agent_1", llm_config=False, human_input_mode="ALWAYS")
  378. dummy_agent_2._oai_messages[dummy_agent_1] = messages
  379. assert (
  380. dummy_agent_2.generate_reply(messages=None, sender=dummy_agent_1)["content"] == "15"
  381. ), "generate_reply not working when messages is None"
  382. dummy_agent_2.register_reply(["str", None], ConversableAgent.generate_oai_reply)
  383. with pytest.raises(SenderRequired):
  384. dummy_agent_2.generate_reply(messages=messages, sender=None)
  385. def test_generate_reply_raises_on_messages_and_sender_none(conversable_agent):
  386. with pytest.raises(AssertionError):
  387. conversable_agent.generate_reply(messages=None, sender=None)
  388. @pytest.mark.asyncio
  389. async def test_a_generate_reply_raises_on_messages_and_sender_none(conversable_agent):
  390. with pytest.raises(AssertionError):
  391. await conversable_agent.a_generate_reply(messages=None, sender=None)
  392. def test_generate_reply_with_messages_and_sender_none(conversable_agent):
  393. messages = [{"role": "user", "content": "hello"}]
  394. try:
  395. response = conversable_agent.generate_reply(messages=messages, sender=None)
  396. assert response is not None, "Response should not be None"
  397. except AssertionError as e:
  398. pytest.fail(f"Unexpected AssertionError: {e}")
  399. except Exception as e:
  400. pytest.fail(f"Unexpected exception: {e}")
  401. @pytest.mark.asyncio
  402. async def test_a_generate_reply_with_messages_and_sender_none(conversable_agent):
  403. messages = [{"role": "user", "content": "hello"}]
  404. try:
  405. response = await conversable_agent.a_generate_reply(messages=messages, sender=None)
  406. assert response is not None, "Response should not be None"
  407. except AssertionError as e:
  408. pytest.fail(f"Unexpected AssertionError: {e}")
  409. except Exception as e:
  410. pytest.fail(f"Unexpected exception: {e}")
  411. def test_update_function_signature_and_register_functions() -> None:
  412. with pytest.MonkeyPatch.context() as mp:
  413. mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
  414. agent = ConversableAgent(name="agent", llm_config={"config_list": [{"model": "gpt-4"}]})
  415. def exec_python(cell: str) -> None:
  416. pass
  417. def exec_sh(script: str) -> None:
  418. pass
  419. agent.update_function_signature(
  420. {
  421. "name": "python",
  422. "description": "run cell in ipython and return the execution result.",
  423. "parameters": {
  424. "type": "object",
  425. "properties": {
  426. "cell": {
  427. "type": "string",
  428. "description": "Valid Python cell to execute.",
  429. }
  430. },
  431. "required": ["cell"],
  432. },
  433. },
  434. is_remove=False,
  435. )
  436. functions = agent.llm_config["functions"]
  437. assert {f["name"] for f in functions} == {"python"}
  438. agent.update_function_signature(
  439. {
  440. "name": "sh",
  441. "description": "run a shell script and return the execution result.",
  442. "parameters": {
  443. "type": "object",
  444. "properties": {
  445. "script": {
  446. "type": "string",
  447. "description": "Valid shell script to execute.",
  448. }
  449. },
  450. "required": ["script"],
  451. },
  452. },
  453. is_remove=False,
  454. )
  455. functions = agent.llm_config["functions"]
  456. assert {f["name"] for f in functions} == {"python", "sh"}
  457. # register the functions
  458. agent.register_function(
  459. function_map={
  460. "python": exec_python,
  461. "sh": exec_sh,
  462. }
  463. )
  464. assert set(agent.function_map.keys()) == {"python", "sh"}
  465. assert agent.function_map["python"] == exec_python
  466. assert agent.function_map["sh"] == exec_sh
  467. # remove the functions
  468. agent.register_function(
  469. function_map={
  470. "python": None,
  471. }
  472. )
  473. assert set(agent.function_map.keys()) == {"sh"}
  474. assert agent.function_map["sh"] == exec_sh
  475. def test__wrap_function_sync():
  476. CurrencySymbol = Literal["USD", "EUR"]
  477. class Currency(BaseModel):
  478. currency: Annotated[CurrencySymbol, Field(..., description="Currency code")]
  479. amount: Annotated[float, Field(100.0, description="Amount of money in the currency")]
  480. Currency(currency="USD", amount=100.0)
  481. def exchange_rate(base_currency: CurrencySymbol, quote_currency: CurrencySymbol) -> float:
  482. if base_currency == quote_currency:
  483. return 1.0
  484. elif base_currency == "USD" and quote_currency == "EUR":
  485. return 1 / 1.1
  486. elif base_currency == "EUR" and quote_currency == "USD":
  487. return 1.1
  488. else:
  489. raise ValueError(f"Unknown currencies {base_currency}, {quote_currency}")
  490. agent = ConversableAgent(name="agent", llm_config=False)
  491. @agent._wrap_function
  492. def currency_calculator(
  493. base: Annotated[Currency, "Base currency"],
  494. quote_currency: Annotated[CurrencySymbol, "Quote currency"] = "EUR",
  495. ) -> Currency:
  496. quote_amount = exchange_rate(base.currency, quote_currency) * base.amount
  497. return Currency(amount=quote_amount, currency=quote_currency)
  498. assert (
  499. currency_calculator(base={"currency": "USD", "amount": 110.11}, quote_currency="EUR")
  500. == '{"currency":"EUR","amount":100.1}'
  501. )
  502. assert not inspect.iscoroutinefunction(currency_calculator)
  503. @pytest.mark.asyncio
  504. async def test__wrap_function_async():
  505. CurrencySymbol = Literal["USD", "EUR"]
  506. class Currency(BaseModel):
  507. currency: Annotated[CurrencySymbol, Field(..., description="Currency code")]
  508. amount: Annotated[float, Field(100.0, description="Amount of money in the currency")]
  509. Currency(currency="USD", amount=100.0)
  510. def exchange_rate(base_currency: CurrencySymbol, quote_currency: CurrencySymbol) -> float:
  511. if base_currency == quote_currency:
  512. return 1.0
  513. elif base_currency == "USD" and quote_currency == "EUR":
  514. return 1 / 1.1
  515. elif base_currency == "EUR" and quote_currency == "USD":
  516. return 1.1
  517. else:
  518. raise ValueError(f"Unknown currencies {base_currency}, {quote_currency}")
  519. agent = ConversableAgent(name="agent", llm_config=False)
  520. @agent._wrap_function
  521. async def currency_calculator(
  522. base: Annotated[Currency, "Base currency"],
  523. quote_currency: Annotated[CurrencySymbol, "Quote currency"] = "EUR",
  524. ) -> Currency:
  525. quote_amount = exchange_rate(base.currency, quote_currency) * base.amount
  526. return Currency(amount=quote_amount, currency=quote_currency)
  527. assert (
  528. await currency_calculator(base={"currency": "USD", "amount": 110.11}, quote_currency="EUR")
  529. == '{"currency":"EUR","amount":100.1}'
  530. )
  531. assert inspect.iscoroutinefunction(currency_calculator)
  532. def get_origin(d: Dict[str, Callable[..., Any]]) -> Dict[str, Callable[..., Any]]:
  533. return {k: v._origin for k, v in d.items()}
  534. def test_register_for_llm():
  535. with pytest.MonkeyPatch.context() as mp:
  536. mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
  537. agent3 = ConversableAgent(name="agent3", llm_config={"config_list": [{"model": "gpt-4"}]})
  538. agent2 = ConversableAgent(name="agent2", llm_config={"config_list": [{"model": "gpt-4"}]})
  539. agent1 = ConversableAgent(name="agent1", llm_config={"config_list": [{"model": "gpt-4"}]})
  540. @agent3.register_for_llm()
  541. @agent2.register_for_llm(name="python")
  542. @agent1.register_for_llm(description="run cell in ipython and return the execution result.")
  543. def exec_python(cell: Annotated[str, "Valid Python cell to execute."]) -> str:
  544. pass
  545. expected1 = [
  546. {
  547. "type": "function",
  548. "function": {
  549. "description": "run cell in ipython and return the execution result.",
  550. "name": "exec_python",
  551. "parameters": {
  552. "type": "object",
  553. "properties": {
  554. "cell": {
  555. "type": "string",
  556. "description": "Valid Python cell to execute.",
  557. }
  558. },
  559. "required": ["cell"],
  560. },
  561. },
  562. }
  563. ]
  564. expected2 = copy.deepcopy(expected1)
  565. expected2[0]["function"]["name"] = "python"
  566. expected3 = expected2
  567. assert agent1.llm_config["tools"] == expected1
  568. assert agent2.llm_config["tools"] == expected2
  569. assert agent3.llm_config["tools"] == expected3
  570. @agent3.register_for_llm()
  571. @agent2.register_for_llm()
  572. @agent1.register_for_llm(name="sh", description="run a shell script and return the execution result.")
  573. async def exec_sh(script: Annotated[str, "Valid shell script to execute."]) -> str:
  574. pass
  575. expected1 = expected1 + [
  576. {
  577. "type": "function",
  578. "function": {
  579. "name": "sh",
  580. "description": "run a shell script and return the execution result.",
  581. "parameters": {
  582. "type": "object",
  583. "properties": {
  584. "script": {
  585. "type": "string",
  586. "description": "Valid shell script to execute.",
  587. }
  588. },
  589. "required": ["script"],
  590. },
  591. },
  592. }
  593. ]
  594. expected2 = expected2 + [expected1[1]]
  595. expected3 = expected3 + [expected1[1]]
  596. assert agent1.llm_config["tools"] == expected1
  597. assert agent2.llm_config["tools"] == expected2
  598. assert agent3.llm_config["tools"] == expected3
  599. def test_register_for_llm_api_style_function():
  600. with pytest.MonkeyPatch.context() as mp:
  601. mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
  602. agent3 = ConversableAgent(name="agent3", llm_config={"config_list": [{"model": "gpt-4"}]})
  603. agent2 = ConversableAgent(name="agent2", llm_config={"config_list": [{"model": "gpt-4"}]})
  604. agent1 = ConversableAgent(name="agent1", llm_config={"config_list": [{"model": "gpt-4"}]})
  605. @agent3.register_for_llm(api_style="function")
  606. @agent2.register_for_llm(name="python", api_style="function")
  607. @agent1.register_for_llm(
  608. description="run cell in ipython and return the execution result.", api_style="function"
  609. )
  610. def exec_python(cell: Annotated[str, "Valid Python cell to execute."]) -> str:
  611. pass
  612. expected1 = [
  613. {
  614. "description": "run cell in ipython and return the execution result.",
  615. "name": "exec_python",
  616. "parameters": {
  617. "type": "object",
  618. "properties": {
  619. "cell": {
  620. "type": "string",
  621. "description": "Valid Python cell to execute.",
  622. }
  623. },
  624. "required": ["cell"],
  625. },
  626. }
  627. ]
  628. expected2 = copy.deepcopy(expected1)
  629. expected2[0]["name"] = "python"
  630. expected3 = expected2
  631. assert agent1.llm_config["functions"] == expected1
  632. assert agent2.llm_config["functions"] == expected2
  633. assert agent3.llm_config["functions"] == expected3
  634. @agent3.register_for_llm(api_style="function")
  635. @agent2.register_for_llm(api_style="function")
  636. @agent1.register_for_llm(
  637. name="sh", description="run a shell script and return the execution result.", api_style="function"
  638. )
  639. async def exec_sh(script: Annotated[str, "Valid shell script to execute."]) -> str:
  640. pass
  641. expected1 = expected1 + [
  642. {
  643. "name": "sh",
  644. "description": "run a shell script and return the execution result.",
  645. "parameters": {
  646. "type": "object",
  647. "properties": {
  648. "script": {
  649. "type": "string",
  650. "description": "Valid shell script to execute.",
  651. }
  652. },
  653. "required": ["script"],
  654. },
  655. }
  656. ]
  657. expected2 = expected2 + [expected1[1]]
  658. expected3 = expected3 + [expected1[1]]
  659. assert agent1.llm_config["functions"] == expected1
  660. assert agent2.llm_config["functions"] == expected2
  661. assert agent3.llm_config["functions"] == expected3
  662. def test_register_for_llm_without_description():
  663. with pytest.MonkeyPatch.context() as mp:
  664. mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
  665. agent = ConversableAgent(name="agent", llm_config={"config_list": [{"model": "gpt-4"}]})
  666. with pytest.raises(ValueError) as e:
  667. @agent.register_for_llm()
  668. def exec_python(cell: Annotated[str, "Valid Python cell to execute."]) -> str:
  669. pass
  670. assert e.value.args[0] == "Function description is required, none found."
  671. def test_register_for_llm_without_LLM():
  672. agent = ConversableAgent(name="agent", llm_config=None)
  673. with pytest.raises(
  674. AssertionError,
  675. match="To update a tool signature, agent must have an llm_config",
  676. ):
  677. @agent.register_for_llm(description="do things.")
  678. def do_stuff(s: str) -> str:
  679. return f"{s} done"
  680. def test_register_for_llm_without_configuration():
  681. with pytest.raises(
  682. ValueError,
  683. match="When using OpenAI or Azure OpenAI endpoints, specify a non-empty 'model' either in 'llm_config' or in each config of 'config_list'.",
  684. ):
  685. ConversableAgent(name="agent", llm_config={"config_list": []})
  686. def test_register_for_llm_without_model_name():
  687. with pytest.raises(
  688. ValueError,
  689. match="When using OpenAI or Azure OpenAI endpoints, specify a non-empty 'model' either in 'llm_config' or in each config of 'config_list'.",
  690. ):
  691. ConversableAgent(name="agent", llm_config={"config_list": [{"model": ""}]})
  692. def test_register_for_execution():
  693. with pytest.MonkeyPatch.context() as mp:
  694. mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
  695. agent = ConversableAgent(name="agent", llm_config={"config_list": [{"model": "gpt-4"}]})
  696. user_proxy_1 = UserProxyAgent(name="user_proxy_1")
  697. user_proxy_2 = UserProxyAgent(name="user_proxy_2")
  698. @user_proxy_2.register_for_execution(name="python")
  699. @agent.register_for_execution()
  700. @agent.register_for_llm(description="run cell in ipython and return the execution result.")
  701. @user_proxy_1.register_for_execution()
  702. def exec_python(cell: Annotated[str, "Valid Python cell to execute."]):
  703. pass
  704. expected_function_map_1 = {"exec_python": exec_python}
  705. assert get_origin(agent.function_map) == expected_function_map_1
  706. assert get_origin(user_proxy_1.function_map) == expected_function_map_1
  707. expected_function_map_2 = {"python": exec_python}
  708. assert get_origin(user_proxy_2.function_map) == expected_function_map_2
  709. @agent.register_for_execution()
  710. @agent.register_for_llm(description="run a shell script and return the execution result.")
  711. @user_proxy_1.register_for_execution(name="sh")
  712. async def exec_sh(script: Annotated[str, "Valid shell script to execute."]):
  713. pass
  714. expected_function_map = {
  715. "exec_python": exec_python,
  716. "sh": exec_sh,
  717. }
  718. assert get_origin(agent.function_map) == expected_function_map
  719. assert get_origin(user_proxy_1.function_map) == expected_function_map
  720. def test_register_functions():
  721. with pytest.MonkeyPatch.context() as mp:
  722. mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY)
  723. agent = ConversableAgent(name="agent", llm_config={"config_list": [{"model": "gpt-4"}]})
  724. user_proxy = UserProxyAgent(name="user_proxy")
  725. def exec_python(cell: Annotated[str, "Valid Python cell to execute."]) -> str:
  726. pass
  727. register_function(
  728. exec_python,
  729. caller=agent,
  730. executor=user_proxy,
  731. description="run cell in ipython and return the execution result.",
  732. )
  733. expected_function_map = {"exec_python": exec_python}
  734. assert get_origin(user_proxy.function_map) == expected_function_map
  735. expected = [
  736. {
  737. "type": "function",
  738. "function": {
  739. "description": "run cell in ipython and return the execution result.",
  740. "name": "exec_python",
  741. "parameters": {
  742. "type": "object",
  743. "properties": {
  744. "cell": {
  745. "type": "string",
  746. "description": "Valid Python cell to execute.",
  747. }
  748. },
  749. "required": ["cell"],
  750. },
  751. },
  752. }
  753. ]
  754. assert agent.llm_config["tools"] == expected
  755. @pytest.mark.skipif(
  756. skip_openai,
  757. reason=REASON,
  758. )
  759. def test_function_registration_e2e_sync() -> None:
  760. config_list = autogen.config_list_from_json(
  761. OAI_CONFIG_LIST,
  762. filter_dict={
  763. "model": ["gpt-4", "gpt-4-0314", "gpt4", "gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-v0314"],
  764. },
  765. file_location=KEY_LOC,
  766. )
  767. llm_config = {
  768. "config_list": config_list,
  769. }
  770. coder = autogen.AssistantAgent(
  771. name="chatbot",
  772. system_message="For coding tasks, only use the functions you have been provided with. Reply TERMINATE when the task is done.",
  773. llm_config=llm_config,
  774. )
  775. # create a UserProxyAgent instance named "user_proxy"
  776. user_proxy = autogen.UserProxyAgent(
  777. name="user_proxy",
  778. system_message="A proxy for the user for executing code.",
  779. is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
  780. human_input_mode="NEVER",
  781. max_consecutive_auto_reply=10,
  782. code_execution_config={"work_dir": "coding"},
  783. )
  784. # define functions according to the function description
  785. timer_mock = unittest.mock.MagicMock()
  786. stopwatch_mock = unittest.mock.MagicMock()
  787. # An example async function registered using decorators
  788. @user_proxy.register_for_execution()
  789. @coder.register_for_llm(description="create a timer for N seconds")
  790. def timer(num_seconds: Annotated[str, "Number of seconds in the timer."]) -> str:
  791. print("timer is running")
  792. for i in range(int(num_seconds)):
  793. print(".", end="")
  794. time.sleep(0.01)
  795. print()
  796. timer_mock(num_seconds=num_seconds)
  797. return "Timer is done!"
  798. # An example sync function registered using register_function
  799. def stopwatch(num_seconds: Annotated[str, "Number of seconds in the stopwatch."]) -> str:
  800. print("stopwatch is running")
  801. # assert False, "stopwatch's alive!"
  802. for i in range(int(num_seconds)):
  803. print(".", end="")
  804. time.sleep(0.01)
  805. print()
  806. stopwatch_mock(num_seconds=num_seconds)
  807. return "Stopwatch is done!"
  808. register_function(stopwatch, caller=coder, executor=user_proxy, description="create a stopwatch for N seconds")
  809. # start the conversation
  810. # 'await' is used to pause and resume code execution for async IO operations.
  811. # Without 'await', an async function returns a coroutine object but doesn't execute the function.
  812. # With 'await', the async function is executed and the current function is paused until the awaited function returns a result.
  813. user_proxy.initiate_chat( # noqa: F704
  814. coder,
  815. message="Create a timer for 1 second and then a stopwatch for 2 seconds.",
  816. )
  817. timer_mock.assert_called_once_with(num_seconds="1")
  818. stopwatch_mock.assert_called_once_with(num_seconds="2")
  819. @pytest.mark.skipif(
  820. skip_openai,
  821. reason=REASON,
  822. )
  823. @pytest.mark.asyncio()
  824. async def test_function_registration_e2e_async() -> None:
  825. config_list = autogen.config_list_from_json(
  826. OAI_CONFIG_LIST,
  827. filter_dict={
  828. "model": ["gpt-4", "gpt-4-0314", "gpt4", "gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-v0314"],
  829. },
  830. file_location=KEY_LOC,
  831. )
  832. llm_config = {
  833. "config_list": config_list,
  834. }
  835. coder = autogen.AssistantAgent(
  836. name="chatbot",
  837. system_message="For coding tasks, only use the functions you have been provided with. Reply TERMINATE when the task is done.",
  838. llm_config=llm_config,
  839. )
  840. # create a UserProxyAgent instance named "user_proxy"
  841. user_proxy = autogen.UserProxyAgent(
  842. name="user_proxy",
  843. system_message="A proxy for the user for executing code.",
  844. is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
  845. human_input_mode="NEVER",
  846. max_consecutive_auto_reply=10,
  847. code_execution_config={"work_dir": "coding"},
  848. )
  849. # define functions according to the function description
  850. timer_mock = unittest.mock.MagicMock()
  851. stopwatch_mock = unittest.mock.MagicMock()
  852. # An example async function registered using register_function
  853. async def timer(num_seconds: Annotated[str, "Number of seconds in the timer."]) -> str:
  854. print("timer is running")
  855. for i in range(int(num_seconds)):
  856. print(".", end="")
  857. await asyncio.sleep(0.01)
  858. print()
  859. timer_mock(num_seconds=num_seconds)
  860. return "Timer is done!"
  861. register_function(timer, caller=coder, executor=user_proxy, description="create a timer for N seconds")
  862. # An example sync function registered using decorators
  863. @user_proxy.register_for_execution()
  864. @coder.register_for_llm(description="create a stopwatch for N seconds")
  865. def stopwatch(num_seconds: Annotated[str, "Number of seconds in the stopwatch."]) -> str:
  866. print("stopwatch is running")
  867. # assert False, "stopwatch's alive!"
  868. for i in range(int(num_seconds)):
  869. print(".", end="")
  870. time.sleep(0.01)
  871. print()
  872. stopwatch_mock(num_seconds=num_seconds)
  873. return "Stopwatch is done!"
  874. # start the conversation
  875. # 'await' is used to pause and resume code execution for async IO operations.
  876. # Without 'await', an async function returns a coroutine object but doesn't execute the function.
  877. # With 'await', the async function is executed and the current function is paused until the awaited function returns a result.
  878. await user_proxy.a_initiate_chat( # noqa: F704
  879. coder,
  880. message="Create a timer for 1 second and then a stopwatch for 2 seconds.",
  881. )
  882. timer_mock.assert_called_once_with(num_seconds="1")
  883. stopwatch_mock.assert_called_once_with(num_seconds="2")
  884. @pytest.mark.skipif(skip_openai, reason=REASON)
  885. def test_max_turn():
  886. config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC)
  887. # create an AssistantAgent instance named "assistant"
  888. assistant = autogen.AssistantAgent(
  889. name="assistant",
  890. max_consecutive_auto_reply=10,
  891. llm_config={"timeout": 600, "cache_seed": 41, "config_list": config_list},
  892. )
  893. user_proxy = autogen.UserProxyAgent(name="user", human_input_mode="ALWAYS", code_execution_config=False)
  894. # Use MagicMock to create a mock get_human_input function
  895. user_proxy.get_human_input = MagicMock(return_value="Not funny. Try again.")
  896. res = user_proxy.initiate_chat(assistant, clear_history=True, max_turns=3, message="Hello, make a joke about AI.")
  897. print("Result summary:", res.summary)
  898. print("Human input:", res.human_input)
  899. print("history", res.chat_history)
  900. assert len(res.chat_history) <= 6
  901. @pytest.mark.skipif(skip_openai, reason=REASON)
  902. def test_message_func():
  903. import random
  904. class Function:
  905. call_count = 0
  906. def get_random_number(self):
  907. self.call_count += 1
  908. return random.randint(0, 100)
  909. config_list = autogen.config_list_from_json(
  910. OAI_CONFIG_LIST,
  911. file_location=KEY_LOC,
  912. )
  913. def my_message_play(sender, recipient, context):
  914. final_msg = {}
  915. final_msg["content"] = "Let's play a game."
  916. final_msg["function_call"] = {"name": "get_random_number", "arguments": "{}"}
  917. return final_msg
  918. func = Function()
  919. # autogen.ChatCompletion.start_logging()
  920. user = UserProxyAgent(
  921. "user",
  922. code_execution_config={
  923. "work_dir": here,
  924. "use_docker": False,
  925. },
  926. human_input_mode="NEVER",
  927. max_consecutive_auto_reply=10,
  928. )
  929. player = autogen.AssistantAgent(
  930. name="Player",
  931. system_message="You will use function `get_random_number` to get a random number. Stop only when you get at least 1 even number and 1 odd number. Reply TERMINATE to stop.",
  932. description="A player that makes function_calls.",
  933. llm_config={"config_list": config_list},
  934. function_map={"get_random_number": func.get_random_number},
  935. )
  936. chat_res_play = user.initiate_chat(
  937. player,
  938. message={"content": "Let's play a game.", "function_call": {"name": "get_random_number", "arguments": "{}"}},
  939. max_turns=1,
  940. )
  941. print(chat_res_play.summary)
  942. chat_res_play = user.initiate_chat(
  943. player,
  944. message=my_message_play,
  945. max_turns=1,
  946. )
  947. print(chat_res_play.summary)
  948. @pytest.mark.skipif(skip_openai, reason=REASON)
  949. def test_summary():
  950. import random
  951. class Function:
  952. call_count = 0
  953. def get_random_number(self):
  954. self.call_count += 1
  955. return random.randint(0, 100)
  956. config_list = autogen.config_list_from_json(
  957. OAI_CONFIG_LIST,
  958. file_location=KEY_LOC,
  959. )
  960. def my_message_play(sender, recipient, context):
  961. final_msg = {}
  962. final_msg["content"] = "Let's play a game."
  963. final_msg["function_call"] = {"name": "get_random_number", "arguments": "{}"}
  964. return final_msg
  965. def my_summary(sender, recipient, summary_args):
  966. prefix = summary_args.get("prefix", "Summary:")
  967. return prefix + recipient.chat_messages[sender][-1].get("content", "")
  968. func = Function()
  969. # autogen.ChatCompletion.start_logging()
  970. user = UserProxyAgent(
  971. "user",
  972. code_execution_config={
  973. "work_dir": here,
  974. "use_docker": False,
  975. },
  976. human_input_mode="NEVER",
  977. max_consecutive_auto_reply=10,
  978. )
  979. player = autogen.AssistantAgent(
  980. name="Player",
  981. system_message="You will use function `get_random_number` to get a random number. Stop only when you get at least 1 even number and 1 odd number. Reply TERMINATE to stop.",
  982. description="A player that makes function_calls.",
  983. llm_config={"config_list": config_list},
  984. function_map={"get_random_number": func.get_random_number},
  985. )
  986. chat_res_play = user.initiate_chat(
  987. player,
  988. message=my_message_play,
  989. # message="Make a joke about AI",
  990. max_turns=1,
  991. summary_method="reflection_with_llm",
  992. summary_args={"summary_prompt": "Summarize the conversation into less than five words."},
  993. )
  994. print(chat_res_play.summary)
  995. chat_res_play = user.initiate_chat(
  996. player,
  997. # message=my_message_play,
  998. message="Make a joke about AI",
  999. max_turns=1,
  1000. summary_method=my_summary,
  1001. summary_args={"prefix": "This is the last message:"},
  1002. )
  1003. print(chat_res_play.summary)
  1004. chat_res_play = user.initiate_chat(
  1005. player,
  1006. message={"content": "Let's play a game.", "function_call": {"name": "get_random_number", "arguments": "{}"}},
  1007. max_turns=1,
  1008. summary_method=my_summary,
  1009. summary_args={"prefix": "This is the last message:"},
  1010. )
  1011. print(chat_res_play.summary)
  1012. def test_process_before_send():
  1013. print_mock = unittest.mock.MagicMock()
  1014. # Updated to include sender parameter
  1015. def send_to_frontend(sender, message, recipient, silent):
  1016. assert sender.name == "dummy_agent_1", "Sender is not the expected agent"
  1017. if not silent:
  1018. print(f"Message sent from {sender.name} to {recipient.name}: {message}")
  1019. print_mock(message=message)
  1020. return message
  1021. dummy_agent_1 = ConversableAgent(name="dummy_agent_1", llm_config=False, human_input_mode="NEVER")
  1022. dummy_agent_2 = ConversableAgent(name="dummy_agent_2", llm_config=False, human_input_mode="NEVER")
  1023. dummy_agent_1.register_hook("process_message_before_send", send_to_frontend)
  1024. dummy_agent_1.send("hello", dummy_agent_2)
  1025. print_mock.assert_called_once_with(message="hello")
  1026. dummy_agent_1.send("silent hello", dummy_agent_2, silent=True)
  1027. print_mock.assert_called_once_with(message="hello")
  1028. def test_messages_with_carryover():
  1029. agent1 = autogen.ConversableAgent(
  1030. "alice",
  1031. max_consecutive_auto_reply=10,
  1032. human_input_mode="NEVER",
  1033. llm_config=False,
  1034. default_auto_reply="This is alice speaking.",
  1035. )
  1036. context = dict(message="hello", carryover="Testing carryover.")
  1037. generated_message = agent1.generate_init_message(**context)
  1038. assert isinstance(generated_message, str)
  1039. context = dict(message="hello", carryover=["Testing carryover.", "This should pass"])
  1040. generated_message = agent1.generate_init_message(**context)
  1041. assert isinstance(generated_message, str)
  1042. context = dict(message="hello", carryover=3)
  1043. with pytest.raises(InvalidCarryOverType):
  1044. agent1.generate_init_message(**context)
  1045. # Test multimodal messages
  1046. mm_content = [
  1047. {"type": "text", "text": "hello"},
  1048. {"type": "text", "text": "goodbye"},
  1049. {
  1050. "type": "image_url",
  1051. "image_url": {"url": "https://example.com/image.png"},
  1052. },
  1053. ]
  1054. mm_message = {"content": mm_content}
  1055. context = dict(
  1056. message=mm_message,
  1057. carryover="Testing carryover.",
  1058. )
  1059. generated_message = agent1.generate_init_message(**context)
  1060. assert isinstance(generated_message, dict)
  1061. assert len(generated_message["content"]) == 4
  1062. context = dict(message=mm_message, carryover=["Testing carryover.", "This should pass"])
  1063. generated_message = agent1.generate_init_message(**context)
  1064. assert isinstance(generated_message, dict)
  1065. assert len(generated_message["content"]) == 4
  1066. context = dict(message=mm_message, carryover=3)
  1067. with pytest.raises(InvalidCarryOverType):
  1068. agent1.generate_init_message(**context)
  1069. # Test without carryover
  1070. print(mm_message)
  1071. context = dict(message=mm_message)
  1072. generated_message = agent1.generate_init_message(**context)
  1073. assert isinstance(generated_message, dict)
  1074. assert len(generated_message["content"]) == 3
  1075. # Test without text in multimodal message
  1076. mm_content = [
  1077. {"type": "image_url", "image_url": {"url": "https://example.com/image.png"}},
  1078. ]
  1079. mm_message = {"content": mm_content}
  1080. context = dict(message=mm_message)
  1081. generated_message = agent1.generate_init_message(**context)
  1082. assert isinstance(generated_message, dict)
  1083. assert len(generated_message["content"]) == 1
  1084. generated_message = agent1.generate_init_message(**context, carryover="Testing carryover.")
  1085. assert isinstance(generated_message, dict)
  1086. assert len(generated_message["content"]) == 2
  1087. if __name__ == "__main__":
  1088. # test_trigger()
  1089. # test_context()
  1090. # test_max_consecutive_auto_reply()
  1091. # test_generate_code_execution_reply()
  1092. # test_conversable_agent()
  1093. # test_no_llm_config()
  1094. # test_max_turn()
  1095. # test_process_before_send()
  1096. test_message_func()
  1097. test_summary()