From 9a8c1c5517eebca9555fad770442baa8828eb163 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Thu, 28 Nov 2024 01:53:31 +0000 Subject: [PATCH 01/40] Added system_message_func to SwarmAgent and update of sys message when selected Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index c1c790a906..b3f1bd931c 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -110,7 +110,17 @@ def custom_afterwork_func(last_speaker: SwarmAgent, messages: List[Dict[str, Any INIT_AGENT_USED = False def swarm_transition(last_speaker: SwarmAgent, groupchat: GroupChat): - """Swarm transition function to determine the next agent in the conversation""" + """Swarm transition function to determine and prepare the next agent in the conversation""" + next_agent = determine_next_agent(last_speaker, groupchat) + + if next_agent and isinstance(next_agent, SwarmAgent): + # Update their state + next_agent.update_state(context_variables, groupchat.messages) + + return next_agent + + def determine_next_agent(last_speaker: SwarmAgent, groupchat: GroupChat): + """Determine the next agent in the conversation""" nonlocal INIT_AGENT_USED if not INIT_AGENT_USED: INIT_AGENT_USED = True @@ -257,6 +267,7 @@ def __init__( human_input_mode: Literal["ALWAYS", "NEVER", "TERMINATE"] = "NEVER", description: Optional[str] = None, code_execution_config=False, + system_message_func: Optional[Callable] = None, **kwargs, ) -> None: super().__init__( @@ -286,6 +297,8 @@ def __init__( self._context_variables = {} self._next_agent = None + self._system_message_func = system_message_func + def _set_to_tool_execution(self, context_variables: Optional[Dict[str, Any]] = None): """Set to a special instance of SwarmAgent that is responsible for executing tool calls from other swarm agents. This agent will be used internally and should not be visible to the user. @@ -458,6 +471,11 @@ def add_functions(self, func_list: List[Callable]): for func in func_list: self.add_single_function(func) + def update_state(self, context_variables: Optional[Dict[str, Any]], messages: List[Dict[str, Any]]): + """Updates the state of the agent, system message so far. This is called when they're selected and just before they speak.""" + if self._system_message_func: + self.update_system_message(self._system_message_func(context_variables, messages)) + # Forward references for SwarmAgent in SwarmResult SwarmResult.update_forward_refs() From db729dd71096622e280b2bf855bdcf8ca7c9d33e Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Thu, 28 Nov 2024 02:11:20 +0000 Subject: [PATCH 02/40] Add a test for the system message function Signed-off-by: Mark Sze --- test/agentchat/contrib/test_swarm.py | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/agentchat/contrib/test_swarm.py b/test/agentchat/contrib/test_swarm.py index 0987ba9ca0..ca906ea194 100644 --- a/test/agentchat/contrib/test_swarm.py +++ b/test/agentchat/contrib/test_swarm.py @@ -460,6 +460,50 @@ def test_initialization(): initial_agent=agent1, messages=TEST_MESSAGES, agents=[agent1, agent2], max_rounds=3 ) + def test_sys_message_func(): + """Tests a custom system message function""" + + # This test will use context variables and the messages to construct a custom system message + # This will be available at the point of reply (we use register a reply to capture it at that point) + + # To store the system message + class MessageContainer: + def __init__(self): + self.final_sys_message = "" + + message_container = MessageContainer() + + def my_sys_message(context_variables, messages) -> str: + return f"This is a custom system message with {context_variables['sample_name']} and a total of {len(messages)} message(s)." + + agent1 = SwarmAgent("agent1", system_message_func=my_sys_message) + agent2 = SwarmAgent("agent2") + + test_context_variables = {"sample_name": "Bob"} + + # Mock a reply to be able to capture the system message + def mock_generate_oai_reply(*args, **kwargs): + message_container.final_sys_message = args[0]._oai_system_message[0][ + "content" + ] # The SwarmAgent's system message + return True, "This is a mock response from the agent." + + agent1.register_reply([ConversableAgent, None], mock_generate_oai_reply) + + chat_result, context_vars, last_speaker = initiate_swarm_chat( + initial_agent=agent1, + messages=TEST_MESSAGES, + agents=[agent1, agent2], + context_variables=test_context_variables, + max_rounds=4, + ) + + # The system message should be the custom message + assert ( + message_container.final_sys_message + == "This is a custom system message with Bob and a total of 1 message(s)." + ) + if __name__ == "__main__": pytest.main([__file__]) From a191e5f6db9da2be3b006cdb0b2b06a2e4adf56c Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Fri, 29 Nov 2024 13:50:59 -0600 Subject: [PATCH 03/40] Add watsonx on litellm --- .../cloud-litellm-watsonx.ipynb | 265 ++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb diff --git a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb new file mode 100644 index 0000000000..0fa8288d2b --- /dev/null +++ b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb @@ -0,0 +1,265 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# LiteLLM with WatsonX \n", + "\n", + "LiteLLM is an open-source, locally run proxy server providing an OpenAI-compatible API. It supports various LLM providers, including IBM's WatsonX, enabling seamless integration with tools like AutoGen.\n", + "\n", + "Running LiteLLM with WatsonX requires the following installations:\n", + "\n", + "1. **AutoGen** – A framework for building and orchestrating AI agents.\n", + "2. **LiteLLM** – An OpenAI-compatible proxy for bridging non-compliant APIs.\n", + "3. **IBM WatsonX** – LLM service requiring specific session token authentication.\n", + "\n", + "### Prerequisites\n", + "\n", + "Before setting up, ensure **Docker** is installed. Refer to the [Docker installation guide](https://docs.docker.com/get-docker/). Optionally, consider using **Postman** to easily test API requests.\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installing WatsonX \n", + "\n", + "To set up WatsonX, follow these steps:\n", + "\n", + "1. **Access WatsonX:**\n", + " - Sign up for [WatsonX.ai](https://www.ibm.com/watsonx).\n", + " - Create an API_KEY and PROJECT_ID.\n", + "\n", + "2. **Validate WatsonX API Access:**\n", + " - Verify access using the following commands:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'bash\\ncurl -L \"https://iam.cloud.ibm.com/identity/token?=null\" -H \"Content-Type: application/x-www-form-urlencoded\" -d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" -d \"apikey=\"\\n'" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "'''bash\n", + "curl -L \"https://iam.cloud.ibm.com/identity/token?=null\" -H \"Content-Type: application/x-www-form-urlencoded\" -d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" -d \"apikey=\"\n", + "'''" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + " \n", + "\n", + " ```\n", + "\n", + " ```bash\n", + " curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/foundation_model_specs?version=2024-09-16&project_id=1eeb4112-5f6e-4a81-9b61-8eac7f9653b4&filters=function_text_generation%2C%21lifecycle_withdrawn%3Aand&limit=200\" \\\n", + " -H \"Authorization: Bearer \"\n", + "\n", + " ```\n", + "\n", + " ```bash\n", + " # Test querying the LLM\n", + " curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02\" \\\n", + " -H \"Content-Type: application/json\" \\\n", + " -H \"Accept: application/json\" \\\n", + " -H \"Authorization: Bearer \" \\\n", + " -d \"{\n", + " \\\"model_id\\\": \\\"google/flan-t5-xxl\\\",\n", + " \\\"input\\\": \\\"What is the capital of Arkansas?:\\\",\n", + " \\\"parameters\\\": {\n", + " \\\"max_new_tokens\\\": 100,\n", + " \\\"time_limit\\\": 1000\n", + " },\n", + " \\\"project_id\\\": \\\"\"\n", + " }\"\n", + "\n", + " ```\n", + "\n", + "3. **Install WatsonX Python SDK:**\n", + "\n", + " ```bash\n", + " pip install watsonx\n", + " ```\n", + "\n", + " For detailed instructions, visit the [WatsonX SDK documentation](https://ibm.github.io/watsonx-ai-python-sdk/install.html).\n", + "\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installing LiteLLM \n", + "\n", + "1. **Download LiteLLM Docker Image:**\n", + "\n", + " ```bash\n", + " docker pull ghcr.io/berriai/litellm:main-latest\n", + " ```\n", + "\n", + " **(ALTERNATIVE). Install LiteLLM Python Library:**\n", + "\n", + " ```bash\n", + " pip install 'litellm[proxy]'\n", + " ```\n", + "\n", + "\n", + "\n", + "---\n", + "\n", + "2. **Create a LiteLLM Configuration File:**\n", + "\n", + " - Save as `litellm_config.yaml` in a local directory.\n", + " - Example content for WatsonX:\n", + "\n", + " ```yaml\n", + " model_list:\n", + " - model_name: llama-3-8b\n", + " litellm_params:\n", + " # all params accepted by litellm.completion()\n", + " model: watsonx/meta-llama/llama-3-8b-instruct\n", + " api_key: \"os.environ/WATSONX_API_KEY\" \n", + " project_id: \"os.environ/WX_PROJECT_ID\"\n", + "\n", + " ```\n", + "'''yaml\n", + " - model_name: \"llama_3_2_90\"\n", + " litellm_params:\n", + " model: watsonx/meta-llama/llama-3-2-90b-vision-instruct\n", + " api_key: os.environ[\"WATSONX_APIKEY\"] = \"\" # IBM cloud API key\n", + " max_new_tokens: 4000\n", + "'''\n", + "3. **Start LiteLLM Container:**\n", + "\n", + " ```bash\n", + " docker run -v \\litellm_config.yaml:/app/config.yaml -e WATSONX_API_KEY= -e WATSONX_URL=https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02 -e WX_PROJECT_ID= -p 4000:4000 ghcr.io/berriai/litellm:main-latest --config /app/config.yaml --detailed_debug\n", + " ```\n", + "\n", + " ---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Installing AutoGen \n", + "\n", + "AutoGen simplifies orchestration and communication between agents. To install:\n", + "\n", + "1. Open a terminal with administrator rights.\n", + "2. Run the following command:\n", + "\n", + " ```bash\n", + " pip install ag2\n", + " ```\n", + "\n", + "Once installed, AutoGen agents can leverage WatsonX APIs via LiteLLM.\n", + "\n", + "---\n", + "\n", + "phi1 = {\n", + " \"config_list\": [\n", + " {\n", + " \"model\": \"llama-3-8b\",\n", + " \"base_url\": \"http://localhost:4000\",\n", + " \"api_key\":\"watsonx\",\n", + " \"price\" : [0,0]\n", + " },\n", + " ],\n", + " \"cache_seed\": None, # Disable caching.\n", + "}\n", + "\n", + "\n", + "\n", + "\n", + "phi2 = {\n", + " \"config_list\": [\n", + " {\n", + " \"model\": \"llama-3-8b\",\n", + " \"base_url\": \"http://localhost:4000\",\n", + " \"api_key\":\"watsonx\",\n", + " \"price\" : [0,0]\n", + " },\n", + " ],\n", + " \"cache_seed\": None, # Disable caching.\n", + "}\n", + "\n", + "from autogen import ConversableAgent, AssistantAgent\n", + "\n", + "jack = ConversableAgent(\n", + " \"Jack (Phi-2)\",\n", + " llm_config=phi2,\n", + " system_message=\"Your name is Jack and you are a comedian in a two-person comedy show.\",\n", + ")\n", + "\n", + "emma = ConversableAgent(\n", + " \"Emma (Gemma)\",\n", + " llm_config=phi1, \n", + " system_message=\"Your name is Emma and you are a comedian in two-person comedy show.\",\n", + ")\n", + "\n", + "#autogen\n", + "chat_result = jack.initiate_chat(emma, message=\"Emma, tell me a joke.\", max_turns=2)\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From e768a6923973c95ea1a62f1e66628f4de4ab3943 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sat, 30 Nov 2024 04:30:55 +0000 Subject: [PATCH 04/40] Interim commit with context_variables on ConversableAgent Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 56 +++++++++++++++++++----- autogen/agentchat/conversable_agent.py | 4 ++ 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index b3f1bd931c..af8f2272bc 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -101,12 +101,17 @@ def custom_afterwork_func(last_speaker: SwarmAgent, messages: List[Dict[str, Any name="Tool_Execution", system_message="Tool Execution", ) - tool_execution._set_to_tool_execution(context_variables=context_variables) + tool_execution._set_to_tool_execution() # Update tool execution agent with all the functions from all the agents for agent in agents: tool_execution._function_map.update(agent._function_map) + # Point all SwarmAgent's context variables to this function's context_variables + # providing a single (shared) context across all SwarmAgents in the swarm + for agent in agents + [tool_execution]: + agent._context_variables = context_variables + INIT_AGENT_USED = False def swarm_transition(last_speaker: SwarmAgent, groupchat: GroupChat): @@ -267,7 +272,7 @@ def __init__( human_input_mode: Literal["ALWAYS", "NEVER", "TERMINATE"] = "NEVER", description: Optional[str] = None, code_execution_config=False, - system_message_func: Optional[Callable] = None, + update_state_functions: Optional[Union[List[Callable], Callable]] = None, **kwargs, ) -> None: super().__init__( @@ -294,19 +299,40 @@ def __init__( self.after_work = None # use in the tool execution agent to transfer to the next agent - self._context_variables = {} self._next_agent = None - self._system_message_func = system_message_func + self.register_update_states_functions(update_state_functions) + + def register_update_states_functions(self, functions: Optional[Union[List[Callable], Callable]]): + """ + Register functions that will be called when the agent is selected and before it speaks. + You can add your own validation or precondition functions here. + + Args: + functions (List[Callable[[], None]]): A list of functions to be registered. Each function + is called when the agent is selected and before it speaks. + """ + + # TEMP - THIS WILL BE UPDATED TO UTILISE A NEW HOOK - update_agent_state - def _set_to_tool_execution(self, context_variables: Optional[Dict[str, Any]] = None): + if functions is None: + return + if not isinstance(functions, list) and not isinstance(functions, Callable): + raise ValueError("functions must be a list of callables") + + if isinstance(functions, Callable): + functions = [functions] + + for func in functions: + self.register_hook("update_states_once_selected", func) + + def _set_to_tool_execution(self): """Set to a special instance of SwarmAgent that is responsible for executing tool calls from other swarm agents. This agent will be used internally and should not be visible to the user. - It will execute the tool calls and update the context_variables and next_agent accordingly. + It will execute the tool calls and update the referenced context_variables and next_agent accordingly. """ self._next_agent = None - self._context_variables = context_variables or {} self._reply_func_list.clear() self.register_reply([Agent, None], SwarmAgent.generate_swarm_tool_reply) @@ -472,9 +498,19 @@ def add_functions(self, func_list: List[Callable]): self.add_single_function(func) def update_state(self, context_variables: Optional[Dict[str, Any]], messages: List[Dict[str, Any]]): - """Updates the state of the agent, system message so far. This is called when they're selected and just before they speak.""" - if self._system_message_func: - self.update_system_message(self._system_message_func(context_variables, messages)) + """Updates the state of the agent prior to reply""" + + # TEMP - THIS WILL BE REPLACED BY A NEW HOOK - update_agent_state + + for hook in self.hook_lists["update_states_once_selected"]: + result = hook(self, context_variables, messages) + + if result is None: + continue + + returned_variables, returned_messages = result + self._context_variables.update(returned_variables) + messages = self.process_all_messages_before_reply(returned_messages) # Forward references for SwarmAgent in SwarmResult diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index 840da79204..b558038eec 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -85,6 +85,7 @@ def __init__( description: Optional[str] = None, chat_messages: Optional[Dict[Agent, List[Dict]]] = None, silent: Optional[bool] = None, + context_variables: Optional[Dict[str, Any]] = None, ): """ Args: @@ -135,6 +136,7 @@ def __init__( resume previous had conversations. Defaults to an empty chat history. silent (bool or None): (Experimental) whether to print the message sent. If None, will use the value of silent in each function. + context_variables (dict or None): Context variables that provide a persistent context for the agent. Only used in Swarms at this stage. """ # we change code_execution_config below and we have to make sure we don't change the input # in case of UserProxyAgent, without this we could even change the default value {} @@ -193,6 +195,8 @@ def __init__( self.register_reply([Agent, None], ConversableAgent.generate_oai_reply) self.register_reply([Agent, None], ConversableAgent.a_generate_oai_reply, ignore_async_in_sync_chat=True) + self._context_variables = context_variables if context_variables is not None else {} + # Setting up code execution. # Do not register code execution reply if code execution is disabled. if code_execution_config is not False: From 40c0b475c6684181d99fafd7db964e6179d722d2 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sat, 30 Nov 2024 05:57:10 +0000 Subject: [PATCH 05/40] Implemented update_agent_state hook, UPDATE_SYSTEM_MESSAGE Signed-off-by: Mark Sze --- autogen/agentchat/__init__.py | 2 + autogen/agentchat/contrib/swarm_agent.py | 73 ++++++++++++++++-------- autogen/agentchat/conversable_agent.py | 25 ++++++++ 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/autogen/agentchat/__init__.py b/autogen/agentchat/__init__.py index 6c3c12e6ce..c41820bf9b 100644 --- a/autogen/agentchat/__init__.py +++ b/autogen/agentchat/__init__.py @@ -12,6 +12,7 @@ from .contrib.swarm_agent import ( AFTER_WORK, ON_CONDITION, + UPDATE_SYSTEM_MESSAGE, AfterWorkOption, SwarmAgent, SwarmResult, @@ -39,4 +40,5 @@ "ON_CONDITION", "AFTER_WORK", "AfterWorkOption", + "UPDATE_SYSTEM_MESSAGE", ] diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index af8f2272bc..1465e60564 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -49,6 +49,23 @@ def __post_init__(self): assert isinstance(self.agent, SwarmAgent), "Agent must be a SwarmAgent" +@dataclass +class UPDATE_SYSTEM_MESSAGE: + update_function: Union[Callable, str] + + def __post_init__(self): + if isinstance(self.update_function, str): + pass + elif isinstance(self.update_function, Callable): + sig = signature(self.update_function) + if len(sig.parameters) != 2: + raise ValueError("Update function must accept two parameters, context_variables and messages") + if sig.return_annotation != str: + raise ValueError("Update function must return a string") + else: + raise ValueError("Update function must be either a string or a callable") + + def initiate_swarm_chat( initial_agent: "SwarmAgent", messages: Union[List[Dict[str, Any]], str], @@ -118,10 +135,6 @@ def swarm_transition(last_speaker: SwarmAgent, groupchat: GroupChat): """Swarm transition function to determine and prepare the next agent in the conversation""" next_agent = determine_next_agent(last_speaker, groupchat) - if next_agent and isinstance(next_agent, SwarmAgent): - # Update their state - next_agent.update_state(context_variables, groupchat.messages) - return next_agent def determine_next_agent(last_speaker: SwarmAgent, groupchat: GroupChat): @@ -301,9 +314,9 @@ def __init__( # use in the tool execution agent to transfer to the next agent self._next_agent = None - self.register_update_states_functions(update_state_functions) + self.register_update_state_functions(update_state_functions) - def register_update_states_functions(self, functions: Optional[Union[List[Callable], Callable]]): + def register_update_state_functions(self, functions: Optional[Union[List[Callable], Callable]]): """ Register functions that will be called when the agent is selected and before it speaks. You can add your own validation or precondition functions here. @@ -312,9 +325,6 @@ def register_update_states_functions(self, functions: Optional[Union[List[Callab functions (List[Callable[[], None]]): A list of functions to be registered. Each function is called when the agent is selected and before it speaks. """ - - # TEMP - THIS WILL BE UPDATED TO UTILISE A NEW HOOK - update_agent_state - if functions is None: return if not isinstance(functions, list) and not isinstance(functions, Callable): @@ -324,7 +334,35 @@ def register_update_states_functions(self, functions: Optional[Union[List[Callab functions = [functions] for func in functions: - self.register_hook("update_states_once_selected", func) + if isinstance(func, UPDATE_SYSTEM_MESSAGE): + + # Wrapper function that allows this to be used in the update_agent_state hook + # Its primary purpose, however, is just to update the agent's system message + # Outer function to create a closure with the update function + def create_wrapper(update_func: UPDATE_SYSTEM_MESSAGE): + def update_system_message_wrapper( + context_variables: Dict[str, Any], messages: List[Dict[str, Any]] + ) -> List[Dict[str, Any]]: + if isinstance(update_func.update_function, str): + # Templates like "My context variable passport is {passport}" will + # use the context_variables for substitution + sys_message = OpenAIWrapper.instantiate( + template=update_func.update_function, + context=context_variables, + allow_format_str_template=True, + ) + else: + sys_message = update_func.update_function(context_variables, messages) + + self.update_system_message(sys_message) + return messages + + return update_system_message_wrapper + + self.register_hook(hookable_method="update_agent_state", hook=create_wrapper(func)) + + else: + self.register_hook(hookable_method="update_agent_state", hook=func) def _set_to_tool_execution(self): """Set to a special instance of SwarmAgent that is responsible for executing tool calls from other swarm agents. @@ -497,21 +535,6 @@ def add_functions(self, func_list: List[Callable]): for func in func_list: self.add_single_function(func) - def update_state(self, context_variables: Optional[Dict[str, Any]], messages: List[Dict[str, Any]]): - """Updates the state of the agent prior to reply""" - - # TEMP - THIS WILL BE REPLACED BY A NEW HOOK - update_agent_state - - for hook in self.hook_lists["update_states_once_selected"]: - result = hook(self, context_variables, messages) - - if result is None: - continue - - returned_variables, returned_messages = result - self._context_variables.update(returned_variables) - messages = self.process_all_messages_before_reply(returned_messages) - # Forward references for SwarmAgent in SwarmResult SwarmResult.update_forward_refs() diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index b558038eec..e05510e8a5 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -261,6 +261,7 @@ def __init__( "process_last_received_message": [], "process_all_messages_before_reply": [], "process_message_before_send": [], + "update_agent_state": [], } def _validate_llm_config(self, llm_config): @@ -2046,6 +2047,9 @@ def generate_reply( if messages is None: messages = self._oai_messages[sender] + # Call the hookable method that gives registered hooks a chance to update agent state, used for their context variables. + messages = self.process_update_agent_states(messages) + # Call the hookable method that gives registered hooks a chance to process the last message. # Message modifications do not affect the incoming messages or self._oai_messages. messages = self.process_last_received_message(messages) @@ -2116,6 +2120,9 @@ async def a_generate_reply( if messages is None: messages = self._oai_messages[sender] + # Call the hookable method that gives registered hooks a chance to update agent state, used for their context variables. + messages = self.process_update_agent_states(messages) + # Call the hookable method that gives registered hooks a chance to process all messages. # Message modifications do not affect the incoming messages or self._oai_messages. messages = self.process_all_messages_before_reply(messages) @@ -2802,6 +2809,24 @@ def register_hook(self, hookable_method: str, hook: Callable): assert hook not in hook_list, f"{hook} is already registered as a hook." hook_list.append(hook) + def process_update_agent_states(self, messages: List[Dict]) -> List[Dict]: + """ + Calls any registered capability hooks to update the agent's state. + Primarily used to update context variables. + Will, potentially, modify the messages. + """ + hook_list = self.hook_lists["update_agent_state"] + + # If no hooks are registered, or if there are no messages to process, return the original message list. + if len(hook_list) == 0 or messages is None: + return messages + + # Call each hook (in order of registration) to process the messages. + processed_messages = messages + for hook in hook_list: + processed_messages = hook(self._context_variables, processed_messages) + return processed_messages + def process_all_messages_before_reply(self, messages: List[Dict]) -> List[Dict]: """ Calls any registered capability hooks to process all messages, potentially modifying the messages. From 0b8ba3be9e710fef4618c13ea373796492c84976 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sat, 30 Nov 2024 06:08:01 +0000 Subject: [PATCH 06/40] process_update_agent_states no longer returns messages Signed-off-by: Mark Sze --- autogen/agentchat/conversable_agent.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index e05510e8a5..4d06fd33e4 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -2048,7 +2048,7 @@ def generate_reply( messages = self._oai_messages[sender] # Call the hookable method that gives registered hooks a chance to update agent state, used for their context variables. - messages = self.process_update_agent_states(messages) + self.process_update_agent_states(messages) # Call the hookable method that gives registered hooks a chance to process the last message. # Message modifications do not affect the incoming messages or self._oai_messages. @@ -2809,7 +2809,7 @@ def register_hook(self, hookable_method: str, hook: Callable): assert hook not in hook_list, f"{hook} is already registered as a hook." hook_list.append(hook) - def process_update_agent_states(self, messages: List[Dict]) -> List[Dict]: + def process_update_agent_states(self, messages: List[Dict]) -> None: """ Calls any registered capability hooks to update the agent's state. Primarily used to update context variables. @@ -2817,15 +2817,9 @@ def process_update_agent_states(self, messages: List[Dict]) -> List[Dict]: """ hook_list = self.hook_lists["update_agent_state"] - # If no hooks are registered, or if there are no messages to process, return the original message list. - if len(hook_list) == 0 or messages is None: - return messages - # Call each hook (in order of registration) to process the messages. - processed_messages = messages for hook in hook_list: - processed_messages = hook(self._context_variables, processed_messages) - return processed_messages + hook(self._context_variables, messages) def process_all_messages_before_reply(self, messages: List[Dict]) -> List[Dict]: """ From 12b0bbe347d61251cc41814066caa8b10c82f375 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sat, 30 Nov 2024 08:49:48 +0000 Subject: [PATCH 07/40] Update hook to pass in agent and messages (context available on agent), context access functions Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 6 +-- autogen/agentchat/conversable_agent.py | 47 +++++++++++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index 1465e60564..53258115e0 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -341,18 +341,18 @@ def register_update_state_functions(self, functions: Optional[Union[List[Callabl # Outer function to create a closure with the update function def create_wrapper(update_func: UPDATE_SYSTEM_MESSAGE): def update_system_message_wrapper( - context_variables: Dict[str, Any], messages: List[Dict[str, Any]] + agent: ConversableAgent, messages: List[Dict[str, Any]] ) -> List[Dict[str, Any]]: if isinstance(update_func.update_function, str): # Templates like "My context variable passport is {passport}" will # use the context_variables for substitution sys_message = OpenAIWrapper.instantiate( template=update_func.update_function, - context=context_variables, + context=agent._context_variables, allow_format_str_template=True, ) else: - sys_message = update_func.update_function(context_variables, messages) + sys_message = update_func.update_function(self, messages) self.update_system_message(sys_message) return messages diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index 4d06fd33e4..ef33dd3bc3 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -530,6 +530,51 @@ def system_message(self) -> str: """Return the system message.""" return self._oai_system_message[0]["content"] + def get_context(self, key: str, default: Any = None) -> Any: + """ + Get a context variable by key. + + Args: + key: The key to look up + default: Value to return if key doesn't exist + + Returns: + The value associated with the key, or default if not found + """ + return self._context_variables.get(key, default) + + def set_context(self, key: str, value: Any) -> None: + """ + Set a context variable. + + Args: + key: The key to set + value: The value to associate with the key + """ + self._context_variables[key] = value + + def update_context(self, context_variables: Dict[str, Any]) -> None: + """ + Update multiple context variables at once. + + Args: + context_variables: Dictionary of variables to update/add + """ + self._context_variables.update(context_variables) + + def pop_context(self, key: str, default: Any = None) -> Any: + """ + Remove and return a context variable. + + Args: + key: The key to remove + default: Value to return if key doesn't exist + + Returns: + The value that was removed, or default if key not found + """ + return self._context_variables.pop(key, default) + def update_system_message(self, system_message: str) -> None: """Update the system message. @@ -2819,7 +2864,7 @@ def process_update_agent_states(self, messages: List[Dict]) -> None: # Call each hook (in order of registration) to process the messages. for hook in hook_list: - hook(self._context_variables, messages) + hook(self, messages) def process_all_messages_before_reply(self, messages: List[Dict]) -> List[Dict]: """ From d212e2b223faacee507aa01e7073c7287bbae6ef Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sat, 30 Nov 2024 09:08:11 +0000 Subject: [PATCH 08/40] Updated context variable access methods, update_agent_before_reply parameter name changed Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 6 +++--- autogen/agentchat/conversable_agent.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index a9b2a1733f..957551f486 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -286,7 +286,7 @@ def __init__( human_input_mode: Literal["ALWAYS", "NEVER", "TERMINATE"] = "NEVER", description: Optional[str] = None, code_execution_config=False, - update_state_functions: Optional[Union[List[Callable], Callable]] = None, + update_agent_before_reply: Optional[Union[List[Callable], Callable]] = None, **kwargs, ) -> None: super().__init__( @@ -315,9 +315,9 @@ def __init__( # use in the tool execution agent to transfer to the next agent self._next_agent = None - self.register_update_state_functions(update_state_functions) + self.register_update_agent_before_reply(update_agent_before_reply) - def register_update_state_functions(self, functions: Optional[Union[List[Callable], Callable]]): + def register_update_agent_before_reply(self, functions: Optional[Union[List[Callable], Callable]]): """ Register functions that will be called when the agent is selected and before it speaks. You can add your own validation or precondition functions here. diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index ef33dd3bc3..91fa7d7fb0 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -530,7 +530,7 @@ def system_message(self) -> str: """Return the system message.""" return self._oai_system_message[0]["content"] - def get_context(self, key: str, default: Any = None) -> Any: + def get_context_value(self, key: str, default: Any = None) -> Any: """ Get a context variable by key. @@ -543,7 +543,7 @@ def get_context(self, key: str, default: Any = None) -> Any: """ return self._context_variables.get(key, default) - def set_context(self, key: str, value: Any) -> None: + def set_context_value(self, key: str, value: Any) -> None: """ Set a context variable. @@ -553,7 +553,7 @@ def set_context(self, key: str, value: Any) -> None: """ self._context_variables[key] = value - def update_context(self, context_variables: Dict[str, Any]) -> None: + def set_context_values(self, context_variables: Dict[str, Any]) -> None: """ Update multiple context variables at once. @@ -562,7 +562,7 @@ def update_context(self, context_variables: Dict[str, Any]) -> None: """ self._context_variables.update(context_variables) - def pop_context(self, key: str, default: Any = None) -> Any: + def pop_context_key(self, key: str, default: Any = None) -> Any: """ Remove and return a context variable. From bb385735df029ed43a7f454e6164678ae609098c Mon Sep 17 00:00:00 2001 From: "margelnin@gmail.com" Date: Sat, 30 Nov 2024 13:57:26 -0500 Subject: [PATCH 09/40] test update_system_message --- autogen/agentchat/contrib/swarm_agent.py | 18 ++- test/agentchat/contrib/test_swarm.py | 137 +++++++++++++++++------ 2 files changed, 115 insertions(+), 40 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index 957551f486..ebe9b9af7b 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -6,7 +6,9 @@ from dataclasses import dataclass from enum import Enum from inspect import signature +import re from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union +import warnings from pydantic import BaseModel @@ -56,7 +58,11 @@ class UPDATE_SYSTEM_MESSAGE: def __post_init__(self): if isinstance(self.update_function, str): - pass + # find all {var} in the string + vars = re.findall(r"\{(\w+)\}", self.update_function) + if len(vars) == 0: + warnings.warn("Update function string contains no variables. This is probably unintended.") + elif isinstance(self.update_function, Callable): sig = signature(self.update_function) if len(sig.parameters) != 2: @@ -286,7 +292,7 @@ def __init__( human_input_mode: Literal["ALWAYS", "NEVER", "TERMINATE"] = "NEVER", description: Optional[str] = None, code_execution_config=False, - update_agent_before_reply: Optional[Union[List[Callable], Callable]] = None, + update_agent_before_reply: Optional[Union[List[Union[Callable, UPDATE_SYSTEM_MESSAGE]], Callable, UPDATE_SYSTEM_MESSAGE]] = None, **kwargs, ) -> None: super().__init__( @@ -328,10 +334,10 @@ def register_update_agent_before_reply(self, functions: Optional[Union[List[Call """ if functions is None: return - if not isinstance(functions, list) and not isinstance(functions, Callable): + if not isinstance(functions, list) and type(functions) not in [UPDATE_SYSTEM_MESSAGE, Callable]: raise ValueError("functions must be a list of callables") - if isinstance(functions, Callable): + if type(functions) is not list: functions = [functions] for func in functions: @@ -353,9 +359,9 @@ def update_system_message_wrapper( allow_format_str_template=True, ) else: - sys_message = update_func.update_function(self, messages) + sys_message = update_func.update_function(agent._context_variables, messages) - self.update_system_message(sys_message) + agent.update_system_message(sys_message) return messages return update_system_message_wrapper diff --git a/test/agentchat/contrib/test_swarm.py b/test/agentchat/contrib/test_swarm.py index ca906ea194..8cf4de5c3d 100644 --- a/test/agentchat/contrib/test_swarm.py +++ b/test/agentchat/contrib/test_swarm.py @@ -1,7 +1,7 @@ # Copyright (c) 2023 - 2024, Owners of https://github.com/ag2ai # # SPDX-License-Identifier: Apache-2.0 -from typing import Any, Dict +from typing import Any, Dict, List from unittest.mock import MagicMock, patch import pytest @@ -11,6 +11,7 @@ AFTER_WORK, ON_CONDITION, AfterWorkOption, + UPDATE_SYSTEM_MESSAGE, SwarmAgent, SwarmResult, initiate_swarm_chat, @@ -460,50 +461,118 @@ def test_initialization(): initial_agent=agent1, messages=TEST_MESSAGES, agents=[agent1, agent2], max_rounds=3 ) - def test_sys_message_func(): - """Tests a custom system message function""" - # This test will use context variables and the messages to construct a custom system message - # This will be available at the point of reply (we use register a reply to capture it at that point) +def test_update_system_message(): + """Tests the update_agent_before_reply functionality with different scenarios""" + + # Test container to capture system messages + class MessageContainer: + def __init__(self): + self.captured_sys_message = "" + + message_container = MessageContainer() - # To store the system message - class MessageContainer: - def __init__(self): - self.final_sys_message = "" + # 1. Test with a callable function + def custom_update_function(context_variables: Dict[str, Any], messages: List[Dict]) -> str: + return f"System message with {context_variables['test_var']} and {len(messages)} messages" - message_container = MessageContainer() + # 2. Test with a string template + template_message = "Template message with {test_var}" - def my_sys_message(context_variables, messages) -> str: - return f"This is a custom system message with {context_variables['sample_name']} and a total of {len(messages)} message(s)." + # Create agents with different update configurations + agent1 = SwarmAgent( + "agent1", + update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(custom_update_function) + ) + + agent2 = SwarmAgent( + "agent2", + update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(template_message) + ) - agent1 = SwarmAgent("agent1", system_message_func=my_sys_message) - agent2 = SwarmAgent("agent2") + # Mock the reply function to capture the system message + def mock_generate_oai_reply(*args, **kwargs): + # Capture the system message for verification + message_container.captured_sys_message = args[0]._oai_system_message[0]["content"] + return True, "Mock response" - test_context_variables = {"sample_name": "Bob"} + # Register mock reply for both agents + agent1.register_reply([ConversableAgent, None], mock_generate_oai_reply) + agent2.register_reply([ConversableAgent, None], mock_generate_oai_reply) - # Mock a reply to be able to capture the system message - def mock_generate_oai_reply(*args, **kwargs): - message_container.final_sys_message = args[0]._oai_system_message[0][ - "content" - ] # The SwarmAgent's system message - return True, "This is a mock response from the agent." + # Test context and messages + test_context = {"test_var": "test_value"} + test_messages = [{"role": "user", "content": "Test message"}] - agent1.register_reply([ConversableAgent, None], mock_generate_oai_reply) + # Run chat with first agent (using callable function) + chat_result1, context_vars1, last_speaker1 = initiate_swarm_chat( + initial_agent=agent1, + messages=test_messages, + agents=[agent1], + context_variables=test_context, + max_rounds=2 + ) - chat_result, context_vars, last_speaker = initiate_swarm_chat( - initial_agent=agent1, - messages=TEST_MESSAGES, - agents=[agent1, agent2], - context_variables=test_context_variables, - max_rounds=4, - ) + # Verify callable function result + assert message_container.captured_sys_message == "System message with test_value and 1 messages" - # The system message should be the custom message - assert ( - message_container.final_sys_message - == "This is a custom system message with Bob and a total of 1 message(s)." - ) + # Reset captured message + message_container.captured_sys_message = "" + + # Run chat with second agent (using string template) + chat_result2, context_vars2, last_speaker2 = initiate_swarm_chat( + initial_agent=agent2, + messages=test_messages, + agents=[agent2], + context_variables=test_context, + max_rounds=2 + ) + # Verify template result + assert message_container.captured_sys_message == "Template message with test_value" + + # Test invalid update function + with pytest.raises(ValueError, match="Update function must be either a string or a callable"): + SwarmAgent("agent3", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(123)) + + # Test invalid callable (wrong number of parameters) + def invalid_update_function(context_variables): + return "Invalid function" + + with pytest.raises(ValueError, match="Update function must accept two parameters"): + SwarmAgent("agent4", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(invalid_update_function)) + + # Test invalid callable (wrong return type) + def invalid_return_function(context_variables, messages) -> dict: + return {} + + with pytest.raises(ValueError, match="Update function must return a string"): + SwarmAgent("agent5", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(invalid_return_function)) + + # Test multiple update functions + def another_update_function(context_variables: Dict[str, Any], messages: List[Dict]) -> str: + return "Another update" + + agent6 = SwarmAgent( + "agent6", + update_agent_before_reply=[ + UPDATE_SYSTEM_MESSAGE(custom_update_function), + UPDATE_SYSTEM_MESSAGE(another_update_function) + ] + ) + + agent6.register_reply([ConversableAgent, None], mock_generate_oai_reply) + + chat_result6, context_vars6, last_speaker6 = initiate_swarm_chat( + initial_agent=agent6, + messages=test_messages, + agents=[agent6], + context_variables=test_context, + max_rounds=2 + ) + # Verify last update function took effect + assert message_container.captured_sys_message == "Another update" + if __name__ == "__main__": pytest.main([__file__]) From 10a4e8f9c5bac42f48abf32dc28df8baa85a5f74 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 1 Dec 2024 19:39:23 +0000 Subject: [PATCH 10/40] pre-commit updates Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 13 ++++--- test/agentchat/contrib/test_swarm.py | 45 ++++++++---------------- 2 files changed, 22 insertions(+), 36 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index ebe9b9af7b..ff95405b2c 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -3,12 +3,12 @@ # SPDX-License-Identifier: Apache-2.0 import copy import json +import re +import warnings from dataclasses import dataclass from enum import Enum from inspect import signature -import re from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union -import warnings from pydantic import BaseModel @@ -62,7 +62,7 @@ def __post_init__(self): vars = re.findall(r"\{(\w+)\}", self.update_function) if len(vars) == 0: warnings.warn("Update function string contains no variables. This is probably unintended.") - + elif isinstance(self.update_function, Callable): sig = signature(self.update_function) if len(sig.parameters) != 2: @@ -292,7 +292,9 @@ def __init__( human_input_mode: Literal["ALWAYS", "NEVER", "TERMINATE"] = "NEVER", description: Optional[str] = None, code_execution_config=False, - update_agent_before_reply: Optional[Union[List[Union[Callable, UPDATE_SYSTEM_MESSAGE]], Callable, UPDATE_SYSTEM_MESSAGE]] = None, + update_agent_before_reply: Optional[ + Union[List[Union[Callable, UPDATE_SYSTEM_MESSAGE]], Callable, UPDATE_SYSTEM_MESSAGE] + ] = None, **kwargs, ) -> None: super().__init__( @@ -337,7 +339,7 @@ def register_update_agent_before_reply(self, functions: Optional[Union[List[Call if not isinstance(functions, list) and type(functions) not in [UPDATE_SYSTEM_MESSAGE, Callable]: raise ValueError("functions must be a list of callables") - if type(functions) is not list: + if not isinstance(functions, list): functions = [functions] for func in functions: @@ -508,6 +510,7 @@ def generate_swarm_tool_reply( return False, None def add_single_function(self, func: Callable, name=None, description=""): + """Add a single function to the agent, removing context variables for LLM use""" if name: func._name = name else: diff --git a/test/agentchat/contrib/test_swarm.py b/test/agentchat/contrib/test_swarm.py index 8cf4de5c3d..bc79661a93 100644 --- a/test/agentchat/contrib/test_swarm.py +++ b/test/agentchat/contrib/test_swarm.py @@ -10,8 +10,8 @@ __CONTEXT_VARIABLES_PARAM_NAME__, AFTER_WORK, ON_CONDITION, - AfterWorkOption, UPDATE_SYSTEM_MESSAGE, + AfterWorkOption, SwarmAgent, SwarmResult, initiate_swarm_chat, @@ -463,13 +463,13 @@ def test_initialization(): def test_update_system_message(): - """Tests the update_agent_before_reply functionality with different scenarios""" - + """Tests the update_agent_before_reply functionality with multiple scenarios""" + # Test container to capture system messages class MessageContainer: def __init__(self): self.captured_sys_message = "" - + message_container = MessageContainer() # 1. Test with a callable function @@ -480,15 +480,9 @@ def custom_update_function(context_variables: Dict[str, Any], messages: List[Dic template_message = "Template message with {test_var}" # Create agents with different update configurations - agent1 = SwarmAgent( - "agent1", - update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(custom_update_function) - ) - - agent2 = SwarmAgent( - "agent2", - update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(template_message) - ) + agent1 = SwarmAgent("agent1", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(custom_update_function)) + + agent2 = SwarmAgent("agent2", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(template_message)) # Mock the reply function to capture the system message def mock_generate_oai_reply(*args, **kwargs): @@ -506,11 +500,7 @@ def mock_generate_oai_reply(*args, **kwargs): # Run chat with first agent (using callable function) chat_result1, context_vars1, last_speaker1 = initiate_swarm_chat( - initial_agent=agent1, - messages=test_messages, - agents=[agent1], - context_variables=test_context, - max_rounds=2 + initial_agent=agent1, messages=test_messages, agents=[agent1], context_variables=test_context, max_rounds=2 ) # Verify callable function result @@ -521,11 +511,7 @@ def mock_generate_oai_reply(*args, **kwargs): # Run chat with second agent (using string template) chat_result2, context_vars2, last_speaker2 = initiate_swarm_chat( - initial_agent=agent2, - messages=test_messages, - agents=[agent2], - context_variables=test_context, - max_rounds=2 + initial_agent=agent2, messages=test_messages, agents=[agent2], context_variables=test_context, max_rounds=2 ) # Verify template result @@ -557,22 +543,19 @@ def another_update_function(context_variables: Dict[str, Any], messages: List[Di "agent6", update_agent_before_reply=[ UPDATE_SYSTEM_MESSAGE(custom_update_function), - UPDATE_SYSTEM_MESSAGE(another_update_function) - ] + UPDATE_SYSTEM_MESSAGE(another_update_function), + ], ) agent6.register_reply([ConversableAgent, None], mock_generate_oai_reply) chat_result6, context_vars6, last_speaker6 = initiate_swarm_chat( - initial_agent=agent6, - messages=test_messages, - agents=[agent6], - context_variables=test_context, - max_rounds=2 + initial_agent=agent6, messages=test_messages, agents=[agent6], context_variables=test_context, max_rounds=2 ) # Verify last update function took effect assert message_container.captured_sys_message == "Another update" - + + if __name__ == "__main__": pytest.main([__file__]) From 623727b19e9582e40aad632cc61cd9b9c4a6d480 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 1 Dec 2024 20:48:28 +0000 Subject: [PATCH 11/40] Fix for ConversableAgent's a_generate_reply Signed-off-by: Mark Sze --- autogen/agentchat/conversable_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index 91fa7d7fb0..385ea5bc1b 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -2166,7 +2166,7 @@ async def a_generate_reply( messages = self._oai_messages[sender] # Call the hookable method that gives registered hooks a chance to update agent state, used for their context variables. - messages = self.process_update_agent_states(messages) + self.process_update_agent_states(messages) # Call the hookable method that gives registered hooks a chance to process all messages. # Message modifications do not affect the incoming messages or self._oai_messages. From 8188593e5b25868cc0a59a533543d24928be97bb Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 1 Dec 2024 20:57:04 +0000 Subject: [PATCH 12/40] Added ConversableAgent context variable tests Signed-off-by: Mark Sze --- test/agentchat/test_conversable_agent.py | 72 ++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/test/agentchat/test_conversable_agent.py b/test/agentchat/test_conversable_agent.py index 81e0036dc0..cc059ce29b 100755 --- a/test/agentchat/test_conversable_agent.py +++ b/test/agentchat/test_conversable_agent.py @@ -1527,6 +1527,67 @@ def test_handle_carryover(): assert proc_content_empty_carryover == content, "Incorrect carryover processing" +@pytest.mark.skipif(skip_openai, reason=reason) +def test_context_variables(): + # Test initialization with context_variables + initial_context = {"test_key": "test_value", "number": 42, "nested": {"inner": "value"}} + agent = ConversableAgent(name="context_test_agent", llm_config=False, context_variables=initial_context) + + # Check that context was properly initialized + assert agent._context_variables == initial_context + + # Test initialization without context_variables + agent_no_context = ConversableAgent(name="no_context_agent", llm_config=False) + assert agent_no_context._context_variables == {} + + # Test get_context_value + assert agent.get_context_value("test_key") == "test_value" + assert agent.get_context_value("number") == 42 + assert agent.get_context_value("nested") == {"inner": "value"} + assert agent.get_context_value("non_existent") is None + assert agent.get_context_value("non_existent", default="default") == "default" + + # Test set_context_value + agent.set_context_value("new_key", "new_value") + assert agent.get_context_value("new_key") == "new_value" + + # Test overwriting existing value + agent.set_context_value("test_key", "updated_value") + assert agent.get_context_value("test_key") == "updated_value" + + # Test set_context_values + new_values = {"bulk_key1": "bulk_value1", "bulk_key2": "bulk_value2", "test_key": "bulk_updated_value"} + agent.set_context_values(new_values) + assert agent.get_context_value("bulk_key1") == "bulk_value1" + assert agent.get_context_value("bulk_key2") == "bulk_value2" + assert agent.get_context_value("test_key") == "bulk_updated_value" + + # Test pop_context_key + # Pop existing key + popped_value = agent.pop_context_key("bulk_key1") + assert popped_value == "bulk_value1" + assert agent.get_context_value("bulk_key1") is None + + # Pop with default value + default_value = "default_value" + popped_default = agent.pop_context_key("non_existent", default=default_value) + assert popped_default == default_value + + # Pop without default (should return None) + popped_none = agent.pop_context_key("another_non_existent") + assert popped_none is None + + # Verify final state of context + expected_final_context = { + "number": 42, + "nested": {"inner": "value"}, + "new_key": "new_value", + "bulk_key2": "bulk_value2", + "test_key": "bulk_updated_value", + } + assert agent._context_variables == expected_final_context + + if __name__ == "__main__": # test_trigger() # test_context() @@ -1537,10 +1598,9 @@ def test_handle_carryover(): # test_max_turn() # test_process_before_send() # test_message_func() - - test_summary() - test_adding_duplicate_function_warning() + # test_summary() + # test_adding_duplicate_function_warning() # test_function_registration_e2e_sync() - - test_process_gemini_carryover() - test_process_carryover() + # test_process_gemini_carryover() + # test_process_carryover() + test_context_variables() From afb227c8c2d901070a614e621c1c9cfc7bbf0e81 Mon Sep 17 00:00:00 2001 From: Lazaros Toumanidis Date: Mon, 2 Dec 2024 08:17:57 +0200 Subject: [PATCH 13/40] update: llamaindex_conversable_agent.py --- autogen/agentchat/contrib/llamaindex_conversable_agent.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/autogen/agentchat/contrib/llamaindex_conversable_agent.py b/autogen/agentchat/contrib/llamaindex_conversable_agent.py index e29393748f..f8dcf17aa3 100644 --- a/autogen/agentchat/contrib/llamaindex_conversable_agent.py +++ b/autogen/agentchat/contrib/llamaindex_conversable_agent.py @@ -16,14 +16,16 @@ from llama_index.core.agent.runner.base import AgentRunner from llama_index.core.base.llms.types import ChatMessage from llama_index.core.chat_engine.types import AgentChatResponse - from pydantic import BaseModel, __version__ as pydantic_version - + from pydantic import BaseModel + from pydantic import __version__ as pydantic_version + # let's Avoid: AttributeError: type object 'Config' has no attribute 'copy' if pydantic_version >= "2.0": from pydantic import ConfigDict Config = ConfigDict(arbitrary_types_allowed=True) else: + class Config: arbitrary_types_allowed = True From 4b5ab2318d1fa2aa108d84e67799cd74c10a22da Mon Sep 17 00:00:00 2001 From: Lazaros Toumanidis Date: Tue, 3 Dec 2024 10:33:49 +0200 Subject: [PATCH 14/40] Update llamaindex_conversable_agent.py --- autogen/agentchat/contrib/llamaindex_conversable_agent.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/autogen/agentchat/contrib/llamaindex_conversable_agent.py b/autogen/agentchat/contrib/llamaindex_conversable_agent.py index f8dcf17aa3..950b5995ec 100644 --- a/autogen/agentchat/contrib/llamaindex_conversable_agent.py +++ b/autogen/agentchat/contrib/llamaindex_conversable_agent.py @@ -16,11 +16,12 @@ from llama_index.core.agent.runner.base import AgentRunner from llama_index.core.base.llms.types import ChatMessage from llama_index.core.chat_engine.types import AgentChatResponse + from packaging import version from pydantic import BaseModel from pydantic import __version__ as pydantic_version # let's Avoid: AttributeError: type object 'Config' has no attribute 'copy' - if pydantic_version >= "2.0": + if version.parse(pydantic_version) >= version.parse("2.0.0"): from pydantic import ConfigDict Config = ConfigDict(arbitrary_types_allowed=True) From 53f186c84f6cdade2e13e9defb976d8add12bf53 Mon Sep 17 00:00:00 2001 From: Lazaros Toumanidis Date: Tue, 3 Dec 2024 10:50:41 +0200 Subject: [PATCH 15/40] Update llamaindex_conversable_agent.py --- autogen/agentchat/contrib/llamaindex_conversable_agent.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/autogen/agentchat/contrib/llamaindex_conversable_agent.py b/autogen/agentchat/contrib/llamaindex_conversable_agent.py index 582ff396a5..3cfafb5f7e 100644 --- a/autogen/agentchat/contrib/llamaindex_conversable_agent.py +++ b/autogen/agentchat/contrib/llamaindex_conversable_agent.py @@ -17,6 +17,9 @@ from llama_index.core.base.llms.types import ChatMessage from llama_index.core.chat_engine.types import AgentChatResponse + from packaging import version + from pydantic import BaseModel + from pydantic import __version__ as pydantic_version # let's Avoid: AttributeError: type object 'Config' has no attribute 'copy' if version.parse(pydantic_version) >= version.parse("2.0.0"): from pydantic import ConfigDict From e871878dac7c5f7fa8c1341e304065e5dc4876bf Mon Sep 17 00:00:00 2001 From: Lazaros Toumanidis Date: Tue, 3 Dec 2024 10:54:48 +0200 Subject: [PATCH 16/40] Update llamaindex_conversable_agent.py --- autogen/agentchat/contrib/llamaindex_conversable_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen/agentchat/contrib/llamaindex_conversable_agent.py b/autogen/agentchat/contrib/llamaindex_conversable_agent.py index 3cfafb5f7e..950b5995ec 100644 --- a/autogen/agentchat/contrib/llamaindex_conversable_agent.py +++ b/autogen/agentchat/contrib/llamaindex_conversable_agent.py @@ -16,10 +16,10 @@ from llama_index.core.agent.runner.base import AgentRunner from llama_index.core.base.llms.types import ChatMessage from llama_index.core.chat_engine.types import AgentChatResponse - from packaging import version from pydantic import BaseModel from pydantic import __version__ as pydantic_version + # let's Avoid: AttributeError: type object 'Config' has no attribute 'copy' if version.parse(pydantic_version) >= version.parse("2.0.0"): from pydantic import ConfigDict From b9352daaa00be902ba39644dfe03bed9d8deadce Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Fri, 6 Dec 2024 23:40:12 +0000 Subject: [PATCH 17/40] Corrected missing variable from nested chat PR Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index aa90a7f441..5dc60e3002 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -376,9 +376,13 @@ def __init__( self.after_work = None - # use in the tool execution agent to transfer to the next agent + # Used in the tool execution agent to transfer to the next agent self._next_agent = None + # Store nested chats hand offs as we'll establish these in the initiate_swarm_chat + # List of Dictionaries containing the nested_chats and condition + self._nested_chat_handoffs = [] + self.register_update_agent_before_reply(update_agent_before_reply) def register_update_agent_before_reply(self, functions: Optional[Union[List[Callable], Callable]]): From 71cc5c7b4c92bf6e30ba9a53bd0cf05d182914cc Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Fri, 6 Dec 2024 23:48:01 +0000 Subject: [PATCH 18/40] Restore conversable agent context getters/setters Signed-off-by: Mark Sze --- autogen/agentchat/conversable_agent.py | 45 -------------------------- 1 file changed, 45 deletions(-) diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index 8251cadab7..db69574f96 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -572,51 +572,6 @@ def system_message(self) -> str: """Return the system message.""" return self._oai_system_message[0]["content"] - def get_context_value(self, key: str, default: Any = None) -> Any: - """ - Get a context variable by key. - - Args: - key: The key to look up - default: Value to return if key doesn't exist - - Returns: - The value associated with the key, or default if not found - """ - return self._context_variables.get(key, default) - - def set_context_value(self, key: str, value: Any) -> None: - """ - Set a context variable. - - Args: - key: The key to set - value: The value to associate with the key - """ - self._context_variables[key] = value - - def set_context_values(self, context_variables: Dict[str, Any]) -> None: - """ - Update multiple context variables at once. - - Args: - context_variables: Dictionary of variables to update/add - """ - self._context_variables.update(context_variables) - - def pop_context_key(self, key: str, default: Any = None) -> Any: - """ - Remove and return a context variable. - - Args: - key: The key to remove - default: Value to return if key doesn't exist - - Returns: - The value that was removed, or default if key not found - """ - return self._context_variables.pop(key, default) - def update_system_message(self, system_message: str) -> None: """Update the system message. From 790f0372a3a5765b55e3ba9f4ee2e82b60950e2e Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sat, 7 Dec 2024 00:48:35 +0000 Subject: [PATCH 19/40] Docs and update system message callable signature change Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 6 ++- test/agentchat/contrib/test_swarm.py | 4 +- website/docs/topics/swarm.ipynb | 54 +++++++++++++++++++++++- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index 5dc60e3002..fcb6db08a1 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -73,7 +73,9 @@ def __post_init__(self): elif isinstance(self.update_function, Callable): sig = signature(self.update_function) if len(sig.parameters) != 2: - raise ValueError("Update function must accept two parameters, context_variables and messages") + raise ValueError( + "Update function must accept two parameters of type ConversableAgent and List[Dict[str Any]], respectively" + ) if sig.return_annotation != str: raise ValueError("Update function must return a string") else: @@ -421,7 +423,7 @@ def update_system_message_wrapper( allow_format_str_template=True, ) else: - sys_message = update_func.update_function(agent._context_variables, messages) + sys_message = update_func.update_function(agent, messages) agent.update_system_message(sys_message) return messages diff --git a/test/agentchat/contrib/test_swarm.py b/test/agentchat/contrib/test_swarm.py index f27bfe874f..85130baac2 100644 --- a/test/agentchat/contrib/test_swarm.py +++ b/test/agentchat/contrib/test_swarm.py @@ -473,8 +473,8 @@ def __init__(self): message_container = MessageContainer() # 1. Test with a callable function - def custom_update_function(context_variables: Dict[str, Any], messages: List[Dict]) -> str: - return f"System message with {context_variables['test_var']} and {len(messages)} messages" + def custom_update_function(agent: ConversableAgent, messages: List[Dict]) -> str: + return f"System message with {agent.get_context('test_var')} and {len(messages)} messages" # 2. Test with a string template template_message = "Template message with {test_var}" diff --git a/website/docs/topics/swarm.ipynb b/website/docs/topics/swarm.ipynb index 1724eea982..2edd76fcde 100644 --- a/website/docs/topics/swarm.ipynb +++ b/website/docs/topics/swarm.ipynb @@ -159,8 +159,58 @@ "])\n", "\n", "agent_2.handoff(hand_to=[AFTER_WORK(AfterWorkOption.TERMINATE)]) # Terminate the chat if no handoff is suggested\n", - "```\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Update Agent state before replying\n", + "\n", + "It can be useful to update an agent's state before they reply, particularly their system message/prompt.\n", + "\n", + "When initialising an agent you can use the `update_agent_before_reply` to register the updates run when the agent is selected, but before they reply.\n", + "\n", + "The `update_agent_before_reply` takes a list of any combination of the following (executing them in the provided order):\n", "\n", + "- `UPDATE_SYSTEM_MESSAGE` provides a simple way to update the agent's system message via an f-string that substitutes the values of context variables, or a Callable that returns a string\n", + "- Callable with two parameters of type `ConversableAgent` for the agent and `List[Dict[str Any]]` for the messages, and does not return a value\n", + "\n", + "Below is an example of setting these up when creating a Swarm agent.\n", + "\n", + "```python\n", + "# Creates a system message string\n", + "def create_system_prompt_function(my_agent: ConversableAgent, messages: List[Dict[]]) -> str:\n", + " preferred_name = my_agent.get_context(\"preferred_name\", \"(name not provided)\")\n", + "\n", + " # Note that the returned string will be treated like an f-string using the context variables\n", + " return \"You are a customer service representative helping a customer named \"\n", + " + preferred_name\n", + " + \" and their passport number is '{passport_number}'.\"\n", + "\n", + "# Function to update an Agent's state\n", + "def my_callable_state_update_function(my_agent: ConversableAgent, messages: List[Dict[]]) -> None:\n", + " agent.set_context(\"context_key\", 43)\n", + " agent.update_system_message(\"You are a customer service representative.\")\n", + "\n", + "# Create the SwarmAgent and set agent updates\n", + "customer_service = SwarmAgent(\n", + " name=\"CustomerServiceRep\",\n", + " system_message=\"You are a customer service representative.\",\n", + " update_agent_before_reply=[\n", + " UPDATE_SYSTEM_MESSAGE(\"You are a customer service representative. Quote passport number '{passport_number}'\"),\n", + " UPDATE_SYSTEM_MESSAGE(create_system_prompt_function),\n", + " my_callable_state_update_function]\n", + " ...\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "### Initialize SwarmChat with `initiate_swarm_chat`\n", "\n", "After a set of swarm agents are created, you can initiate a swarm chat by calling `initiate_swarm_chat`.\n", @@ -185,7 +235,7 @@ "\n", "> How are context variables updated?\n", "\n", - "The context variables will only be updated through custom function calls when returning a `SwarmResult` object. In fact, all interactions with context variables will be done through function calls (accessing and updating). The context variables dictionary is a reference, and any modification will be done in place.\n", + "In a swarm, the context variables are shared amongst Swarm agents. As context variables are available at the agent level, you can use the context variable getters/setters on the agent to view and change the shared context variables. If you're working with a function that returns a `SwarmResult` you should update the passed in context variables and return it in the `SwarmResult`, this will ensure the shared context is updated.\n", "\n", "> What is the difference between ON_CONDITION and AFTER_WORK?\n", "\n", From f8b5e55118320fe119f9d578110222bd4c627949 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 8 Dec 2024 22:21:35 +0000 Subject: [PATCH 20/40] Sample test of update to 4o-mini for tests Signed-off-by: Mark Sze --- test/agentchat/test_async_chats.py | 2 +- test/agentchat/test_chats.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/agentchat/test_async_chats.py b/test/agentchat/test_async_chats.py index d2587ff273..25f974d1b1 100755 --- a/test/agentchat/test_async_chats.py +++ b/test/agentchat/test_async_chats.py @@ -26,7 +26,7 @@ async def test_async_chats(): config_list_35 = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) financial_tasks = [ diff --git a/test/agentchat/test_chats.py b/test/agentchat/test_chats.py index 8f243c1664..9fb7512a35 100755 --- a/test/agentchat/test_chats.py +++ b/test/agentchat/test_chats.py @@ -36,7 +36,7 @@ else autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) ) From a898cc97055bd28e3f58da5fa349146c7b48b26e Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 8 Dec 2024 22:42:11 +0000 Subject: [PATCH 21/40] Additional updates from 3.5 to 4o-mini and 4 to 4o Signed-off-by: Mark Sze --- .../contrib/agent_eval/test_agent_eval.py | 5 ++-- .../capabilities/chat_with_teachable_agent.py | 8 ++----- .../test_image_generation_capability.py | 12 +++++----- .../capabilities/test_teachable_agent.py | 4 +--- .../capabilities/test_transform_messages.py | 2 +- test/agentchat/contrib/test_agent_builder.py | 20 ++++++++-------- test/agentchat/contrib/test_gpt_assistant.py | 3 --- .../test_llamaindex_conversable_agent.py | 2 +- .../agentchat/contrib/test_reasoning_agent.py | 7 ++++-- test/agentchat/test_agent_logging.py | 2 +- test/agentchat/test_agent_usage.py | 18 +++++++------- test/agentchat/test_assistant_agent.py | 8 +++---- test/agentchat/test_async_get_human_input.py | 4 ++-- test/agentchat/test_cache_agent.py | 4 ++-- test/agentchat/test_conversable_agent.py | 11 ++++----- test/agentchat/test_function_call.py | 4 ++-- .../agentchat/test_function_call_groupchat.py | 2 +- test/agentchat/test_human_input.py | 2 +- test/agentchat/test_math_user_proxy_agent.py | 2 +- test/agentchat/test_nested.py | 2 +- test/agentchat/test_tool_calls.py | 2 +- test/io/test_websockets.py | 10 ++------ test/oai/_test_completion.py | 24 ++++++------------- test/test_code_utils.py | 2 +- test/test_logging.py | 12 +++++----- test/test_token_count.py | 2 ++ 26 files changed, 75 insertions(+), 99 deletions(-) diff --git a/test/agentchat/contrib/agent_eval/test_agent_eval.py b/test/agentchat/contrib/agent_eval/test_agent_eval.py index e871b9e347..65e03af36e 100644 --- a/test/agentchat/contrib/agent_eval/test_agent_eval.py +++ b/test/agentchat/contrib/agent_eval/test_agent_eval.py @@ -38,13 +38,12 @@ def remove_ground_truth(test_case: str): filter_dict={ "api_type": ["openai"], "model": [ + "gpt-4o-mini", + "gpt-4o", "gpt-4-turbo", "gpt-4-turbo-preview", "gpt-4-0125-preview", "gpt-4-1106-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-1106", ], }, ) diff --git a/test/agentchat/contrib/capabilities/chat_with_teachable_agent.py b/test/agentchat/contrib/capabilities/chat_with_teachable_agent.py index 8dc0e2256e..38b526ea25 100755 --- a/test/agentchat/contrib/capabilities/chat_with_teachable_agent.py +++ b/test/agentchat/contrib/capabilities/chat_with_teachable_agent.py @@ -17,12 +17,8 @@ from test_assistant_agent import KEY_LOC, OAI_CONFIG_LIST # noqa: E402 # Specify the model to use. GPT-3.5 is less reliable than GPT-4 at learning from user input. -filter_dict = {"model": ["gpt-4-0125-preview"]} -# filter_dict = {"model": ["gpt-3.5-turbo-1106"]} -# filter_dict = {"model": ["gpt-4-0613"]} -# filter_dict = {"model": ["gpt-3.5-turbo"]} -# filter_dict = {"model": ["gpt-4"]} -# filter_dict = {"model": ["gpt-35-turbo-16k", "gpt-3.5-turbo-16k"]} +filter_dict = {"model": ["gpt-4o-mini"]} +# filter_dict = {"model": ["gpt-4-0125-preview"]} def create_teachable_agent(reset_db=False): diff --git a/test/agentchat/contrib/capabilities/test_image_generation_capability.py b/test/agentchat/contrib/capabilities/test_image_generation_capability.py index c0cb6fc1a9..abd73d52ce 100644 --- a/test/agentchat/contrib/capabilities/test_image_generation_capability.py +++ b/test/agentchat/contrib/capabilities/test_image_generation_capability.py @@ -32,7 +32,7 @@ sys.path.append(os.path.join(os.path.dirname(__file__), "../..")) from conftest import MOCK_OPEN_AI_API_KEY, skip_openai # noqa: E402 -filter_dict = {"model": ["gpt-35-turbo-16k", "gpt-3.5-turbo-16k"]} +filter_dict = {"model": ["gpt-4o-mini"]} RESOLUTIONS = ["256x256", "512x512", "1024x1024"] QUALITIES = ["standard", "hd"] @@ -67,21 +67,21 @@ def api_key(): @pytest.fixture def dalle_config() -> Dict[str, Any]: - config_list = openai_utils.config_list_from_models(model_list=["dall-e-2"], exclude="aoai") + config_list = openai_utils.config_list_from_models(model_list=["dall-e-3"], exclude="aoai") if not config_list: - config_list = [{"model": "dall-e-2", "api_key": api_key()}] + config_list = [{"model": "dall-e-3", "api_key": api_key()}] return {"config_list": config_list, "timeout": 120, "cache_seed": None} @pytest.fixture -def gpt3_config() -> Dict[str, Any]: +def gpt4_config() -> Dict[str, Any]: config_list = [ { - "model": "gpt-35-turbo-16k", + "model": "gpt-4o-mini", "api_key": api_key(), }, { - "model": "gpt-3.5-turbo-16k", + "model": "gpt-4o", "api_key": api_key(), }, ] diff --git a/test/agentchat/contrib/capabilities/test_teachable_agent.py b/test/agentchat/contrib/capabilities/test_teachable_agent.py index ade6aa1e7f..82252f07f6 100755 --- a/test/agentchat/contrib/capabilities/test_teachable_agent.py +++ b/test/agentchat/contrib/capabilities/test_teachable_agent.py @@ -31,10 +31,8 @@ # Specify the model to use by uncommenting one of the following lines. # filter_dict={"model": ["gpt-4-1106-preview"]} # filter_dict={"model": ["gpt-4-0613"]} -# filter_dict={"model": ["gpt-3.5-turbo-1106"]} -# filter_dict={"model": ["gpt-3.5-turbo-0613"]} # filter_dict={"model": ["gpt-4"]} -filter_dict = {"tags": ["gpt-35-turbo-16k", "gpt-3.5-turbo-16k"]} +filter_dict = {"tags": ["gpt-4o-mini"]} def create_teachable_agent(reset_db=False, verbosity=0): diff --git a/test/agentchat/contrib/capabilities/test_transform_messages.py b/test/agentchat/contrib/capabilities/test_transform_messages.py index 9121a8d8bb..b3dee65d1b 100644 --- a/test/agentchat/contrib/capabilities/test_transform_messages.py +++ b/test/agentchat/contrib/capabilities/test_transform_messages.py @@ -33,7 +33,7 @@ def test_transform_messages_capability(): OAI_CONFIG_LIST, KEY_LOC, filter_dict={ - "model": "gpt-3.5-turbo", + "model": "gpt-4o-mini", }, ) diff --git a/test/agentchat/contrib/test_agent_builder.py b/test/agentchat/contrib/test_agent_builder.py index 9dee05766e..cab4a051b5 100755 --- a/test/agentchat/contrib/test_agent_builder.py +++ b/test/agentchat/contrib/test_agent_builder.py @@ -51,8 +51,8 @@ def test_build(): builder = AgentBuilder( config_file_or_env=OAI_CONFIG_LIST, config_file_location=KEY_LOC, - builder_model_tags=["gpt-4"], - agent_model_tags=["gpt-4"], + builder_model_tags=["gpt-4o"], + agent_model_tags=["gpt-4o"], ) building_task = ( "Find a paper on arxiv by programming, and analyze its application in some domain. " @@ -83,8 +83,8 @@ def test_build_from_library(): builder = AgentBuilder( config_file_or_env=OAI_CONFIG_LIST, config_file_location=KEY_LOC, - builder_model_tags=["gpt-4"], - agent_model_tags=["gpt-4"], + builder_model_tags=["gpt-4o"], + agent_model_tags=["gpt-4o"], ) building_task = ( "Find a paper on arxiv by programming, and analyze its application in some domain. " @@ -136,8 +136,8 @@ def test_save(): builder = AgentBuilder( config_file_or_env=OAI_CONFIG_LIST, config_file_location=KEY_LOC, - builder_model_tags=["gpt-4"], - agent_model_tags=["gpt-4"], + builder_model_tags=["gpt-4o"], + agent_model_tags=["gpt-4o"], ) building_task = ( "Find a paper on arxiv by programming, and analyze its application in some domain. " @@ -175,8 +175,8 @@ def test_load(): config_file_location=KEY_LOC, # builder_model=["gpt-4", "gpt-4-1106-preview"], # agent_model=["gpt-4", "gpt-4-1106-preview"], - builder_model_tags=["gpt-4"], - agent_model_tags=["gpt-4"], + builder_model_tags=["gpt-4o"], + agent_model_tags=["gpt-4o"], ) config_save_path = f"{here}/example_test_agent_builder_config.json" @@ -204,8 +204,8 @@ def test_clear_agent(): builder = AgentBuilder( config_file_or_env=OAI_CONFIG_LIST, config_file_location=KEY_LOC, - builder_model_tags=["gpt-4"], - agent_model_tags=["gpt-4"], + builder_model_tags=["gpt-4o"], + agent_model_tags=["gpt-4o"], ) config_save_path = f"{here}/example_test_agent_builder_config.json" diff --git a/test/agentchat/contrib/test_gpt_assistant.py b/test/agentchat/contrib/test_gpt_assistant.py index c67130f77a..ce29c7651c 100755 --- a/test/agentchat/contrib/test_gpt_assistant.py +++ b/test/agentchat/contrib/test_gpt_assistant.py @@ -40,9 +40,6 @@ "gpt-4-turbo-preview", "gpt-4-0125-preview", "gpt-4-1106-preview", - "gpt-3.5-turbo", - "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-1106", ], }, ) diff --git a/test/agentchat/contrib/test_llamaindex_conversable_agent.py b/test/agentchat/contrib/test_llamaindex_conversable_agent.py index 6fd74d4d18..bc9bec4fd1 100644 --- a/test/agentchat/contrib/test_llamaindex_conversable_agent.py +++ b/test/agentchat/contrib/test_llamaindex_conversable_agent.py @@ -48,7 +48,7 @@ def test_group_chat_with_llama_index_conversable_agent(chat_mock: MagicMock) -> Each agent is set to describe an image in a unique style, but the chat should not exceed the specified max_rounds. """ llm = OpenAI( - model="gpt-4", + model="gpt-4o", temperature=0.0, api_key=openaiKey, ) diff --git a/test/agentchat/contrib/test_reasoning_agent.py b/test/agentchat/contrib/test_reasoning_agent.py index 323a661f76..ff732adc99 100644 --- a/test/agentchat/contrib/test_reasoning_agent.py +++ b/test/agentchat/contrib/test_reasoning_agent.py @@ -43,7 +43,7 @@ def think_node(): @pytest.fixture def reasoning_agent(): """Create a ReasoningAgent instance for testing""" - config_list = [{"model": "gpt-4", "api_key": "fake_key"}] + config_list = [{"model": "gpt-4o", "api_key": "fake_key"}] llm_config = {"config_list": config_list, "temperature": 0} return ReasoningAgent("reasoning_agent", llm_config=llm_config) @@ -164,7 +164,10 @@ def test_reasoning_agent_answer(): def helper_test_reasoning_agent_answer(max_depth, beam_size, answer_approach): """Test that ReasoningAgent properly terminates when TERMINATE is received""" - mock_config = {"config_list": [{"model": "gpt-4", "api_key": "fake", "base_url": "0.0.0.0:8000"}], "temperature": 0} + mock_config = { + "config_list": [{"model": "gpt-4o", "api_key": "fake", "base_url": "0.0.0.0:8000"}], + "temperature": 0, + } with patch("autogen.agentchat.conversable_agent.ConversableAgent.generate_oai_reply") as mock_oai_reply: agent = ReasoningAgent( "test_agent", diff --git a/test/agentchat/test_agent_logging.py b/test/agentchat/test_agent_logging.py index 4e17487382..c8418bd8a6 100644 --- a/test/agentchat/test_agent_logging.py +++ b/test/agentchat/test_agent_logging.py @@ -50,7 +50,7 @@ config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, filter_dict={ - "tags": ["gpt-3.5-turbo"], + "tags": ["gpt-4o-mini"], }, file_location=KEY_LOC, ) diff --git a/test/agentchat/test_agent_usage.py b/test/agentchat/test_agent_usage.py index 88b686a1a2..02df221a3f 100755 --- a/test/agentchat/test_agent_usage.py +++ b/test/agentchat/test_agent_usage.py @@ -32,7 +32,7 @@ def test_gathering(): system_message="You are a helpful assistant.", llm_config={ "config_list": config_list, - "model": "gpt-3.5-turbo-0613", + "model": "gpt-4o-mini", }, ) assistant2 = AssistantAgent( @@ -40,7 +40,7 @@ def test_gathering(): system_message="You are a helpful assistant.", llm_config={ "config_list": config_list, - "model": "gpt-3.5-turbo-0613", + "model": "gpt-4o-mini", }, ) assistant3 = AssistantAgent( @@ -48,28 +48,28 @@ def test_gathering(): system_message="You are a helpful assistant.", llm_config={ "config_list": config_list, - "model": "gpt-3.5-turbo-0613", + "model": "gpt-4o", }, ) assistant1.client.total_usage_summary = { "total_cost": 0.1, - "gpt-35-turbo": {"cost": 0.1, "prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}, + "gpt-4o-mini": {"cost": 0.1, "prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}, } assistant2.client.total_usage_summary = { "total_cost": 0.2, - "gpt-35-turbo": {"cost": 0.2, "prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}, + "gpt-4o-mini": {"cost": 0.2, "prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}, } assistant3.client.total_usage_summary = { "total_cost": 0.3, - "gpt-4": {"cost": 0.3, "prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}, + "gpt-4o": {"cost": 0.3, "prompt_tokens": 100, "completion_tokens": 200, "total_tokens": 300}, } total_usage = gather_usage_summary([assistant1, assistant2, assistant3]) assert round(total_usage["usage_including_cached_inference"]["total_cost"], 8) == 0.6 - assert round(total_usage["usage_including_cached_inference"]["gpt-35-turbo"]["cost"], 8) == 0.3 - assert round(total_usage["usage_including_cached_inference"]["gpt-4"]["cost"], 8) == 0.3 + assert round(total_usage["usage_including_cached_inference"]["gpt-4o-mini"]["cost"], 8) == 0.3 + assert round(total_usage["usage_including_cached_inference"]["gpt-4o"]["cost"], 8) == 0.3 # test when agent doesn't have client user_proxy = UserProxyAgent( @@ -91,7 +91,7 @@ def test_agent_usage(): config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) assistant = AssistantAgent( "assistant", diff --git a/test/agentchat/test_assistant_agent.py b/test/agentchat/test_assistant_agent.py index 672ff59bd6..ee7f5b88bd 100755 --- a/test/agentchat/test_assistant_agent.py +++ b/test/agentchat/test_assistant_agent.py @@ -33,7 +33,7 @@ def test_ai_user_proxy_agent(): config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) assistant = AssistantAgent( "assistant", @@ -72,7 +72,7 @@ def test_gpt35(human_input_mode="NEVER", max_consecutive_auto_reply=5): config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo", "gpt-3.5-turbo-16k"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) llm_config = { "cache_seed": 42, @@ -116,7 +116,7 @@ def test_create_execute_script(human_input_mode="NEVER", max_consecutive_auto_re config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) conversations = {} # autogen.ChatCompletion.start_logging(conversations) @@ -170,7 +170,7 @@ def test_tsp(human_input_mode="NEVER", max_consecutive_auto_reply=2): OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={ - "tags": ["gpt-4", "gpt-4-32k"], + "tags": ["gpt-4o"], }, ) hard_questions = [ diff --git a/test/agentchat/test_async_get_human_input.py b/test/agentchat/test_async_get_human_input.py index 555ed63866..e68c3c6892 100755 --- a/test/agentchat/test_async_get_human_input.py +++ b/test/agentchat/test_async_get_human_input.py @@ -23,7 +23,7 @@ @pytest.mark.skipif(skip_openai, reason=reason) @pytest.mark.asyncio async def test_async_get_human_input(): - config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-3.5-turbo"]}) + config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}) # create an AssistantAgent instance named "assistant" assistant = autogen.AssistantAgent( @@ -50,7 +50,7 @@ async def test_async_get_human_input(): @pytest.mark.skipif(skip_openai, reason=reason) @pytest.mark.asyncio async def test_async_max_turn(): - config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-3.5-turbo"]}) + config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}) # create an AssistantAgent instance named "assistant" assistant = autogen.AssistantAgent( diff --git a/test/agentchat/test_cache_agent.py b/test/agentchat/test_cache_agent.py index 723355b6e1..805a5be9f3 100644 --- a/test/agentchat/test_cache_agent.py +++ b/test/agentchat/test_cache_agent.py @@ -120,7 +120,7 @@ def run_conversation(cache_seed, human_input_mode="NEVER", max_consecutive_auto_ OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={ - "tags": ["gpt-3.5-turbo", "gpt-3.5-turbo-16k"], + "tags": ["gpt-4o-mini"], }, ) llm_config = { @@ -167,7 +167,7 @@ def run_groupchat_conversation(cache, human_input_mode="NEVER", max_consecutive_ OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={ - "tags": ["gpt-3.5-turbo", "gpt-3.5-turbo-16k"], + "tags": ["gpt-4o-mini"], }, ) llm_config = { diff --git a/test/agentchat/test_conversable_agent.py b/test/agentchat/test_conversable_agent.py index 320cfb324b..fd1f3bd3fb 100755 --- a/test/agentchat/test_conversable_agent.py +++ b/test/agentchat/test_conversable_agent.py @@ -32,9 +32,6 @@ here = os.path.abspath(os.path.dirname(__file__)) gpt4_config_list = [ - {"model": "gpt-4"}, - {"model": "gpt-4-turbo"}, - {"model": "gpt-4-32k"}, {"model": "gpt-4o"}, {"model": "gpt-4o-mini"}, ] @@ -856,7 +853,7 @@ def test_register_for_llm_without_model_name(): def test_register_for_execution(): with pytest.MonkeyPatch.context() as mp: mp.setenv("OPENAI_API_KEY", MOCK_OPEN_AI_API_KEY) - agent = ConversableAgent(name="agent", llm_config={"config_list": [{"model": "gpt-4"}]}) + agent = ConversableAgent(name="agent", llm_config={"config_list": [{"model": "gpt-4o"}]}) user_proxy_1 = UserProxyAgent(name="user_proxy_1") user_proxy_2 = UserProxyAgent(name="user_proxy_2") @@ -1015,7 +1012,7 @@ async def test_function_registration_e2e_async() -> None: config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, filter_dict={ - "tags": ["gpt-4", "gpt-4-0314", "gpt4", "gpt-4-32k", "gpt-4-32k-0314", "gpt-4-32k-v0314"], + "tags": ["gpt-4o"], }, file_location=KEY_LOC, ) @@ -1086,7 +1083,7 @@ def stopwatch(num_seconds: Annotated[str, "Number of seconds in the stopwatch."] @pytest.mark.skipif(skip_openai, reason=reason) def test_max_turn(): - config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-3.5-turbo"]}) + config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}) # create an AssistantAgent instance named "assistant" assistant = autogen.AssistantAgent( @@ -1174,7 +1171,7 @@ def get_random_number(self): return str(random.randint(0, 100)) config_list = autogen.config_list_from_json( - OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={"tags": ["gpt-3.5-turbo"]} + OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]} ) def my_message_play(sender, recipient, context): diff --git a/test/agentchat/test_function_call.py b/test/agentchat/test_function_call.py index 5dfcd839f3..1567a31fc4 100755 --- a/test/agentchat/test_function_call.py +++ b/test/agentchat/test_function_call.py @@ -33,7 +33,7 @@ def test_eval_math_responses(): config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, filter_dict={ - "tags": ["gpt-4", "gpt-3.5-turbo", "gpt-3.5-turbo-16k"], + "tags": ["gpt-4o-mini", "gpt-4o"], }, file_location=KEY_LOC, ) @@ -238,7 +238,7 @@ def test_update_function(): config_list_gpt4 = autogen.config_list_from_json( OAI_CONFIG_LIST, filter_dict={ - "tags": ["gpt-4", "gpt-4-32k", "gpt-4o", "gpt-4o-mini"], + "tags": ["gpt-4o", "gpt-4o-mini"], }, file_location=KEY_LOC, ) diff --git a/test/agentchat/test_function_call_groupchat.py b/test/agentchat/test_function_call_groupchat.py index 7e09bbd365..5639a86115 100755 --- a/test/agentchat/test_function_call_groupchat.py +++ b/test/agentchat/test_function_call_groupchat.py @@ -55,7 +55,7 @@ def get_random_number(self): config_list_35 = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo", "gpt-3.5-turbo-16k"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) llm_config_no_function = {"config_list": config_list_35} config_list_tool = autogen.filter_config(config_list_35, {"tags": ["tool"]}) diff --git a/test/agentchat/test_human_input.py b/test/agentchat/test_human_input.py index beca99033c..826aed609c 100755 --- a/test/agentchat/test_human_input.py +++ b/test/agentchat/test_human_input.py @@ -21,7 +21,7 @@ @pytest.mark.skipif(skip_openai, reason=reason) def test_get_human_input(): - config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-3.5-turbo"]}) + config_list = autogen.config_list_from_json(OAI_CONFIG_LIST, KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}) # create an AssistantAgent instance named "assistant" assistant = autogen.AssistantAgent( diff --git a/test/agentchat/test_math_user_proxy_agent.py b/test/agentchat/test_math_user_proxy_agent.py index 83c6662ce2..5248fac233 100755 --- a/test/agentchat/test_math_user_proxy_agent.py +++ b/test/agentchat/test_math_user_proxy_agent.py @@ -44,7 +44,7 @@ def test_math_user_proxy_agent(): OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={ - "tags": ["gpt-3.5-turbo"], + "tags": ["gpt-4o-mini"], }, ) assistant = AssistantAgent( diff --git a/test/agentchat/test_nested.py b/test/agentchat/test_nested.py index 9995aa6ed6..d095135b12 100755 --- a/test/agentchat/test_nested.py +++ b/test/agentchat/test_nested.py @@ -44,7 +44,7 @@ def test_nested(): config_list_35 = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, - filter_dict={"tags": ["gpt-3.5-turbo"]}, + filter_dict={"tags": ["gpt-4o-mini"]}, ) llm_config = {"config_list": config_list} diff --git a/test/agentchat/test_tool_calls.py b/test/agentchat/test_tool_calls.py index eb2cbe7c35..3583e541bc 100755 --- a/test/agentchat/test_tool_calls.py +++ b/test/agentchat/test_tool_calls.py @@ -150,7 +150,7 @@ def test_update_tool(): config_list_gpt4 = autogen.config_list_from_json( OAI_CONFIG_LIST, filter_dict={ - "tags": ["gpt-4"], + "tags": ["gpt-4o"], }, file_location=KEY_LOC, ) diff --git a/test/io/test_websockets.py b/test/io/test_websockets.py index c6d8494461..6c4b4662e3 100644 --- a/test/io/test_websockets.py +++ b/test/io/test_websockets.py @@ -103,14 +103,8 @@ def on_connect(iostream: IOWebsockets, success_dict: Dict[str, bool] = success_d OAI_CONFIG_LIST, filter_dict={ "model": [ - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-4", - "gpt-4-0314", - "gpt4", - "gpt-4-32k", - "gpt-4-32k-0314", - "gpt-4-32k-v0314", + "gpt-4o-mini", + "gpt-4o", ], }, file_location=KEY_LOC, diff --git a/test/oai/_test_completion.py b/test/oai/_test_completion.py index 5e92149d41..fece9ed42c 100755 --- a/test/oai/_test_completion.py +++ b/test/oai/_test_completion.py @@ -51,7 +51,7 @@ def test_filter(): print(exc) return config_list = autogen.config_list_from_models( - KEY_LOC, exclude="aoai", model_list=["text-ada-001", "gpt-3.5-turbo", "text-davinci-003"] + KEY_LOC, exclude="aoai", model_list=["text-ada-001", "gpt-4o-mini", "text-davinci-003"] ) response = autogen.Completion.create( context={"yes_or_no_choice": True}, @@ -95,7 +95,7 @@ def test_chatcompletion(): assert "messages" not in params params = autogen.Completion._construct_params( context=None, - config={"model": "gpt-4"}, + config={"model": "gpt-4o"}, prompt="hi", ) assert "messages" in params @@ -149,13 +149,8 @@ def test_nocontext(): file_location=KEY_LOC, filter_dict={ "model": { - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-16k-0613", - "gpt-3.5-turbo-0301", - "chatgpt-35-turbo-0301", - "gpt-35-turbo-v0301", - "gpt", + "gpt-4o-mini", + "gpt-4o", }, }, ), @@ -185,13 +180,8 @@ def test_humaneval(num_samples=1): env_or_file=OAI_CONFIG_LIST, filter_dict={ "model": { - "gpt-3.5-turbo", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-16k-0613", - "gpt-3.5-turbo-0301", - "chatgpt-35-turbo-0301", - "gpt-35-turbo-v0301", - "gpt", + "gpt-4o-mini", + "gpt-4o", }, }, file_location=KEY_LOC, @@ -233,7 +223,7 @@ def test_humaneval(num_samples=1): # no error should be raised response = autogen.Completion.create( context=test_data[0], - config_list=autogen.config_list_from_models(KEY_LOC, model_list=["gpt-3.5-turbo"]), + config_list=autogen.config_list_from_models(KEY_LOC, model_list=["gpt-4o-mini"]), prompt="", max_tokens=1, max_retry_period=0, diff --git a/test/test_code_utils.py b/test/test_code_utils.py index 8fb2f44a97..5871799d28 100755 --- a/test/test_code_utils.py +++ b/test/test_code_utils.py @@ -54,7 +54,7 @@ # OAI_CONFIG_LIST, # file_location=KEY_LOC, # filter_dict={ -# "model": ["gpt-4", "gpt4", "gpt-4-32k", "gpt-4-32k-0314"], +# "model": ["gpt-4o", "gpt4", "gpt-4-32k", "gpt-4-32k-0314"], # }, # ) # # config_list = autogen.config_list_from_json( diff --git a/test/test_logging.py b/test/test_logging.py index 0a27160e2d..ca2db497ee 100644 --- a/test/test_logging.py +++ b/test/test_logging.py @@ -35,7 +35,7 @@ "role": "user" } ], - "model": "gpt-4" + "model": "gpt-4o" } """ ) @@ -58,7 +58,7 @@ } ], "created": 1705993480, - "model": "gpt-4", + "model": "gpt-4o", "object": "chat.completion", "system_fingerprint": "fp_6d044fb900", "usage": { @@ -159,7 +159,7 @@ def test_log_new_agent(db_connection): cur = db_connection.cursor() agent_name = "some_assistant" - config_list = [{"model": "gpt-4", "api_key": "some_key"}] + config_list = [{"model": "gpt-4o", "api_key": "some_key"}] agent = AssistantAgent(agent_name, llm_config={"config_list": config_list}) init_args = {"foo": "bar", "baz": {"other_key": "other_val"}, "a": None} @@ -184,7 +184,7 @@ def test_log_oai_wrapper(db_connection): cur = db_connection.cursor() - llm_config = {"config_list": [{"model": "gpt-4", "api_key": "some_key", "base_url": "some url"}]} + llm_config = {"config_list": [{"model": "gpt-4o", "api_key": "some_key", "base_url": "some url"}]} init_args = {"llm_config": llm_config, "base_config": {}} wrapper = OpenAIWrapper(**llm_config) @@ -210,8 +210,8 @@ def test_log_oai_client(db_connection): openai_config = { "api_key": "some_key", - "api_version": "2024-02-01", - "azure_deployment": "gpt-4", + "api_version": "2024-08-06", + "azure_deployment": "gpt-4o", "azure_endpoint": "https://foobar.openai.azure.com/", } client = AzureOpenAI(**openai_config) diff --git a/test/test_token_count.py b/test/test_token_count.py index e37324932c..c009a65110 100755 --- a/test/test_token_count.py +++ b/test/test_token_count.py @@ -141,6 +141,8 @@ def test_model_aliases(): assert get_max_token_limit("gpt-35-turbo") == get_max_token_limit("gpt-3.5-turbo") assert get_max_token_limit("gpt4") == get_max_token_limit("gpt-4") assert get_max_token_limit("gpt4-32k") == get_max_token_limit("gpt-4-32k") + assert get_max_token_limit("gpt4o") == get_max_token_limit("gpt-4o") + assert get_max_token_limit("gpt4omini") == get_max_token_limit("gpt-4o-mini") if __name__ == "__main__": From 3b04874c678d0701a4b69c1163d6b4122ca8cf63 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 8 Dec 2024 22:54:22 +0000 Subject: [PATCH 22/40] Fix for gpt-4o-mini in token count test Signed-off-by: Mark Sze --- test/test_token_count.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_token_count.py b/test/test_token_count.py index c009a65110..de25b8a49d 100755 --- a/test/test_token_count.py +++ b/test/test_token_count.py @@ -142,7 +142,7 @@ def test_model_aliases(): assert get_max_token_limit("gpt4") == get_max_token_limit("gpt-4") assert get_max_token_limit("gpt4-32k") == get_max_token_limit("gpt-4-32k") assert get_max_token_limit("gpt4o") == get_max_token_limit("gpt-4o") - assert get_max_token_limit("gpt4omini") == get_max_token_limit("gpt-4o-mini") + assert get_max_token_limit("gpt4o-mini") == get_max_token_limit("gpt-4o-mini") if __name__ == "__main__": From fe18acb0ecf570d14ffe50352863dc9d1c9d9439 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 8 Dec 2024 23:56:20 +0000 Subject: [PATCH 23/40] Renaming and removal of tools filtering where not necessary Signed-off-by: Mark Sze --- test/agentchat/test_async_chats.py | 8 ++--- test/agentchat/test_chats.py | 30 +++++++++---------- .../agentchat/test_function_call_groupchat.py | 10 +++---- test/agentchat/test_nested.py | 8 ++--- 4 files changed, 26 insertions(+), 30 deletions(-) diff --git a/test/agentchat/test_async_chats.py b/test/agentchat/test_async_chats.py index 25f974d1b1..1167ff4d07 100755 --- a/test/agentchat/test_async_chats.py +++ b/test/agentchat/test_async_chats.py @@ -23,7 +23,7 @@ @pytest.mark.skipif(skip_openai, reason="requested to skip openai tests") @pytest.mark.asyncio async def test_async_chats(): - config_list_35 = autogen.config_list_from_json( + config_list_4omini = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}, @@ -39,16 +39,16 @@ async def test_async_chats(): financial_assistant_1 = AssistantAgent( name="Financial_assistant_1", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, system_message="You are a knowledgeable AI Assistant. Reply TERMINATE when everything is done.", ) financial_assistant_2 = AssistantAgent( name="Financial_assistant_2", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, ) writer = AssistantAgent( name="Writer", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, is_termination_msg=lambda x: x.get("content", "").find("TERMINATE") >= 0, system_message=""" You are a professional writer, known for diff --git a/test/agentchat/test_chats.py b/test/agentchat/test_chats.py index 9fb7512a35..a39162debf 100755 --- a/test/agentchat/test_chats.py +++ b/test/agentchat/test_chats.py @@ -30,7 +30,7 @@ ) ) -config_list_35 = ( +config_list_4omini = ( [] if skip_openai else autogen.config_list_from_json( @@ -40,8 +40,6 @@ ) ) -config_list_tool = filter_config(config_list_35, {"tags": ["tool"]}) - def test_chat_messages_for_summary(): assistant = UserProxyAgent(name="assistant", human_input_mode="NEVER", code_execution_config={"use_docker": False}) @@ -87,12 +85,12 @@ def test_chats_group(): financial_assistant = AssistantAgent( name="Financial_assistant", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, ) writer = AssistantAgent( name="Writer", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, system_message=""" You are a professional writer, known for your insightful and engaging articles. @@ -106,7 +104,7 @@ def test_chats_group(): system_message="""Critic. Double check plan, claims, code from other agents and provide feedback. Check whether the plan includes adding verifiable info such as source URL. Reply "TERMINATE" in the end when everything is done. """, - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, ) groupchat_1 = GroupChat(agents=[user_proxy, financial_assistant, critic], messages=[], max_round=3) @@ -116,7 +114,7 @@ def test_chats_group(): manager_1 = GroupChatManager( groupchat=groupchat_1, name="Research_manager", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, code_execution_config={ "last_n_messages": 1, "work_dir": "groupchat", @@ -127,7 +125,7 @@ def test_chats_group(): manager_2 = GroupChatManager( groupchat=groupchat_2, name="Writing_manager", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, code_execution_config={ "last_n_messages": 1, "work_dir": "groupchat", @@ -201,17 +199,17 @@ def luck_number_message(sender, recipient, context): func = Function() financial_assistant_1 = AssistantAgent( name="Financial_assistant_1", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, function_map={"get_random_number": func.get_random_number}, ) financial_assistant_2 = AssistantAgent( name="Financial_assistant_2", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, function_map={"get_random_number": func.get_random_number}, ) writer = AssistantAgent( name="Writer", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, is_termination_msg=lambda x: x.get("content", "").find("TERMINATE") >= 0, system_message=""" You are a professional writer, known for @@ -315,15 +313,15 @@ def test_chats_general(): financial_assistant_1 = AssistantAgent( name="Financial_assistant_1", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, ) financial_assistant_2 = AssistantAgent( name="Financial_assistant_2", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, ) writer = AssistantAgent( name="Writer", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, is_termination_msg=lambda x: x.get("content", "").find("TERMINATE") >= 0, system_message=""" You are a professional writer, known for @@ -494,7 +492,7 @@ def test_chats_exceptions(): @pytest.mark.skipif(skip_openai, reason=reason) def test_chats_w_func(): llm_config = { - "config_list": config_list_tool, + "config_list": config_list_4omini, "timeout": 120, } @@ -549,7 +547,7 @@ def currency_calculator( @pytest.mark.skipif(skip_openai, reason=reason) def test_udf_message_in_chats(): - llm_config_35 = {"config_list": config_list_35} + llm_config_35 = {"config_list": config_list_4omini} research_task = """ ## NVDA (NVIDIA Corporation) diff --git a/test/agentchat/test_function_call_groupchat.py b/test/agentchat/test_function_call_groupchat.py index 5639a86115..4a17221d77 100755 --- a/test/agentchat/test_function_call_groupchat.py +++ b/test/agentchat/test_function_call_groupchat.py @@ -52,15 +52,13 @@ def get_random_number(self): return random.randint(0, 100) # llm_config without functions - config_list_35 = autogen.config_list_from_json( + config_list_4omini = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}, ) - llm_config_no_function = {"config_list": config_list_35} - config_list_tool = autogen.filter_config(config_list_35, {"tags": ["tool"]}) llm_config = { - "config_list": config_list_tool, + "config_list": config_list_4omini, key: value, } @@ -81,7 +79,7 @@ def get_random_number(self): name="Observer", system_message="You observe the the player's actions and results. Summarize in 1 sentence.", description="An observer.", - llm_config=llm_config_no_function, + llm_config=llm_config, ) groupchat = autogen.GroupChat( agents=[player, user_proxy, observer], messages=[], max_round=7, speaker_selection_method="round_robin" @@ -94,7 +92,7 @@ def get_random_number(self): ): manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config) - manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config_no_function) + manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config) if sync: res = observer.initiate_chat(manager, message="Let's start the game!", summary_method="reflection_with_llm") diff --git a/test/agentchat/test_nested.py b/test/agentchat/test_nested.py index d095135b12..24c86a7fed 100755 --- a/test/agentchat/test_nested.py +++ b/test/agentchat/test_nested.py @@ -41,7 +41,7 @@ def mock_reply(recipient, messages, sender, config): @pytest.mark.skipif(skip_openai, reason=reason) def test_nested(): config_list = autogen.config_list_from_json(env_or_file=OAI_CONFIG_LIST, file_location=KEY_LOC) - config_list_35 = autogen.config_list_from_json( + config_list_4omini = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, filter_dict={"tags": ["gpt-4o-mini"]}, @@ -96,7 +96,7 @@ def test_nested(): assistant_2 = autogen.AssistantAgent( name="Assistant", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, # is_termination_msg=lambda x: x.get("content", "") == "", ) @@ -124,7 +124,7 @@ def test_nested(): writer = autogen.AssistantAgent( name="Writer", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, system_message=""" You are a professional writer, known for your insightful and engaging articles. @@ -135,7 +135,7 @@ def test_nested(): autogen.AssistantAgent( name="Reviewer", - llm_config={"config_list": config_list_35}, + llm_config={"config_list": config_list_4omini}, system_message=""" You are a compliance reviewer, known for your thoroughness and commitment to standards. Your task is to scrutinize content for any harmful elements or regulatory violations, ensuring From d625b093cf60f01db34cfa0cf2decda6950373ea Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Mon, 9 Dec 2024 00:51:19 +0000 Subject: [PATCH 24/40] Fix groupchat function test Signed-off-by: Mark Sze --- test/agentchat/test_function_call_groupchat.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/agentchat/test_function_call_groupchat.py b/test/agentchat/test_function_call_groupchat.py index 4a17221d77..8a45ea7c06 100755 --- a/test/agentchat/test_function_call_groupchat.py +++ b/test/agentchat/test_function_call_groupchat.py @@ -52,6 +52,14 @@ def get_random_number(self): return random.randint(0, 100) # llm_config without functions + config_list_4omini_no_tools = autogen.config_list_from_json( + OAI_CONFIG_LIST, + file_location=KEY_LOC, + filter_dict={"tags": ["gpt-4o-mini"]}, + ) + llm_config_no_function = {"config_list": config_list_4omini_no_tools} + + # llm_config with functions config_list_4omini = autogen.config_list_from_json( OAI_CONFIG_LIST, file_location=KEY_LOC, @@ -79,7 +87,7 @@ def get_random_number(self): name="Observer", system_message="You observe the the player's actions and results. Summarize in 1 sentence.", description="An observer.", - llm_config=llm_config, + llm_config=llm_config_no_function, ) groupchat = autogen.GroupChat( agents=[player, user_proxy, observer], messages=[], max_round=7, speaker_selection_method="round_robin" @@ -92,7 +100,7 @@ def get_random_number(self): ): manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config) - manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config) + manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config_no_function) if sync: res = observer.initiate_chat(manager, message="Let's start the game!", summary_method="reflection_with_llm") From 07759f3f011924976d26fa0a6ad62908817e011f Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Mon, 9 Dec 2024 03:24:56 +0000 Subject: [PATCH 25/40] Update tests for pydantic 2+, tool config set to 4o-mini Signed-off-by: Mark Sze --- test/agentchat/test_conversable_agent.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/agentchat/test_conversable_agent.py b/test/agentchat/test_conversable_agent.py index fd1f3bd3fb..93866c81a0 100755 --- a/test/agentchat/test_conversable_agent.py +++ b/test/agentchat/test_conversable_agent.py @@ -589,8 +589,8 @@ def test__wrap_function_sync(): CurrencySymbol = Literal["USD", "EUR"] class Currency(BaseModel): - currency: Annotated[CurrencySymbol, Field(..., description="Currency code")] - amount: Annotated[float, Field(100.0, description="Amount of money in the currency")] + currency: CurrencySymbol = Field(description="Currency code") + amount: Annotated[float, Field(default=100.0, description="Amount of money in the currency")] Currency(currency="USD", amount=100.0) @@ -627,8 +627,8 @@ async def test__wrap_function_async(): CurrencySymbol = Literal["USD", "EUR"] class Currency(BaseModel): - currency: Annotated[CurrencySymbol, Field(..., description="Currency code")] - amount: Annotated[float, Field(100.0, description="Amount of money in the currency")] + currency: CurrencySymbol = Field(description="Currency code") + amount: Annotated[float, Field(default=100.0, description="Amount of money in the currency")] Currency(currency="USD", amount=100.0) @@ -934,7 +934,7 @@ def test_function_registration_e2e_sync() -> None: config_list = autogen.config_list_from_json( OAI_CONFIG_LIST, filter_dict={ - "tags": ["tool"], + "tags": ["gpt-4o-mini"], }, file_location=KEY_LOC, ) From 847fb3aa6c429ac6c1c33c39b9e7c2605577debe Mon Sep 17 00:00:00 2001 From: Irshad Chohan Date: Mon, 9 Dec 2024 20:45:51 +0530 Subject: [PATCH 26/40] Updated bedrock.py to access Attached IAM Role with managed AWS Services. Current approach only consider providing access credentials as part of parameter. This approach have security concerns in managing access keys and secrets. AWS Best practices recommends to use Attached IAM Role with Managed AWS services like AWS Lambda, EC2, ECS Task etc. I have added condition to check if access_key is not present it should try accessing attached instance role directly to provide bedrock-runtime. --- autogen/oai/bedrock.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/autogen/oai/bedrock.py b/autogen/oai/bedrock.py index 21253b92d1..042ab1146a 100644 --- a/autogen/oai/bedrock.py +++ b/autogen/oai/bedrock.py @@ -96,7 +96,19 @@ def __init__(self, **kwargs: Any): if "response_format" in kwargs and kwargs["response_format"] is not None: warnings.warn("response_format is not supported for Bedrock, it will be ignored.", UserWarning) - self.bedrock_runtime = session.client(service_name="bedrock-runtime", config=bedrock_config) + #if haven't got any access_key or secret_key in environment variable or via arugments then + if self._aws_access_key is None or self._aws_access_key == "" or self._aws_secret_key is None or self._aws_secret_key == "": + + # attempts to get client from attached role of mananged service (lambda, ec2, ecs, etc.) + self.bedrock_runtime = boto3.client(service_name="bedrock-runtime", config=bedrock_config) + else: + session = boto3.Session( + aws_access_key_id=self._aws_access_key, + aws_secret_access_key=self._aws_secret_key, + aws_session_token=self._aws_session_token, + profile_name=self._aws_profile_name, + ) + self.bedrock_runtime = session.client(service_name="bedrock-runtime", config=bedrock_config) def message_retrieval(self, response): """Retrieve the messages from the response.""" From 5b1e0625988528ec67d20e338a1e8c6aeb277745 Mon Sep 17 00:00:00 2001 From: Robert Jambrecic Date: Wed, 11 Dec 2024 16:30:33 +0100 Subject: [PATCH 27/40] Upgrade openai version to >=1.57 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 64a4e7cee0..d753b17b7f 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ current_os = platform.system() install_requires = [ - "openai>=1.3", + "openai>=1.57", "diskcache", "termcolor", "flaml", From 183ba39d66672b3300968ea7436cbd07e314cf56 Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Wed, 11 Dec 2024 12:18:36 -0600 Subject: [PATCH 28/40] Initial commit upstream --- .../cloud-litellm-watsonx.ipynb | 99 +++++-------------- 1 file changed, 26 insertions(+), 73 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb index 0fa8288d2b..83c4685154 100644 --- a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb +++ b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb @@ -37,85 +37,38 @@ " - Verify access using the following commands:\n" ] }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'bash\\ncurl -L \"https://iam.cloud.ibm.com/identity/token?=null\" -H \"Content-Type: application/x-www-form-urlencoded\" -d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" -d \"apikey=\"\\n'" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "'''bash\n", - "curl -L \"https://iam.cloud.ibm.com/identity/token?=null\" -H \"Content-Type: application/x-www-form-urlencoded\" -d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" -d \"apikey=\"\n", - "'''" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "shellscript" - } - }, - "outputs": [], - "source": [] - }, { "cell_type": "markdown", "metadata": {}, "source": [ + "Tip: Verify access to watsonX APIs before installing LiteLLM\n", + "Get Session Token:\n", "\n", - " \n", - "\n", - " ```\n", - "\n", - " ```bash\n", - " curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/foundation_model_specs?version=2024-09-16&project_id=1eeb4112-5f6e-4a81-9b61-8eac7f9653b4&filters=function_text_generation%2C%21lifecycle_withdrawn%3Aand&limit=200\" \\\n", - " -H \"Authorization: Bearer \"\n", - "\n", - " ```\n", - "\n", - " ```bash\n", - " # Test querying the LLM\n", - " curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02\" \\\n", - " -H \"Content-Type: application/json\" \\\n", - " -H \"Accept: application/json\" \\\n", - " -H \"Authorization: Bearer \" \\\n", - " -d \"{\n", - " \\\"model_id\\\": \\\"google/flan-t5-xxl\\\",\n", - " \\\"input\\\": \\\"What is the capital of Arkansas?:\\\",\n", - " \\\"parameters\\\": {\n", - " \\\"max_new_tokens\\\": 100,\n", - " \\\"time_limit\\\": 1000\n", - " },\n", - " \\\"project_id\\\": \\\"\"\n", - " }\"\n", - "\n", - " ```\n", - "\n", - "3. **Install WatsonX Python SDK:**\n", - "\n", - " ```bash\n", - " pip install watsonx\n", - " ```\n", - "\n", - " For detailed instructions, visit the [WatsonX SDK documentation](https://ibm.github.io/watsonx-ai-python-sdk/install.html).\n", + "curl -L \"https://iam.cloud.ibm.com/identity/token?=null\" -H \"Content-Type: application/x-www-form-urlencoded\" -d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" -d \"apikey=\"\n", "\n", - "---" + "Get list of LLMs:\n", + " \n", + "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/foundation_model_specs?version=2024-09-16&project_id=1eeb4112-5f6e-4a81-9b61-8eac7f9653b4&filters=function_text_generation%2C%21lifecycle_withdrawn%3Aand&limit=200\" -H \"Authorization: Bearer \"\n", + "\n", + "\n", + "Ask the LLM a question:\n", + " \n", + "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02\" -H \"Content-Type: application/json\" -H \"Accept: application/json\" -H \"Authorization: Bearer \" \\\n", + "-d \"{\n", + " \\\"model_id\\\": \\\"google/flan-t5-xxl\\\",\n", + " \\\"input\\\": \\\"What is the capital of Arkansas?:\\\",\n", + " \\\"parameters\\\": {\n", + " \\\"max_new_tokens\\\": 100,\n", + " \\\"time_limit\\\": 1000\n", + " },\n", + " \\\"project_id\\\": \\\"\"\n", + "}\"\n", + "\n", + "\n", + "2.\tWith access to watsonX API’s validated you can install the python library\n", + " \n", + " \n", + "From \n" ] }, { From fdca90d6e15b961963420e8cfdb5b21e73cd8746 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 12 Dec 2024 13:40:52 -0600 Subject: [PATCH 29/40] Formatting fixes --- .../cloud-litellm-watsonx.ipynb | 122 +++++++++--------- 1 file changed, 64 insertions(+), 58 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb index 83c4685154..5f6f31b546 100644 --- a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb +++ b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb @@ -25,35 +25,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Installing WatsonX \n", + "## Installing WatsonX\n", "\n", "To set up WatsonX, follow these steps:\n", - "\n", "1. **Access WatsonX:**\n", - " - Sign up for [WatsonX.ai](https://www.ibm.com/watsonx).\n", - " - Create an API_KEY and PROJECT_ID.\n", - "\n", + " - Sign up for [WatsonX.ai](https://www.ibm.com/watsonx).\n", + " - Create an API_KEY and PROJECT_ID.\n", + "
\n", + "
\n", "2. **Validate WatsonX API Access:**\n", - " - Verify access using the following commands:\n" + " - Verify access using the following commands:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Tip: Verify access to watsonX APIs before installing LiteLLM\n", - "Get Session Token:\n", - "\n", - "curl -L \"https://iam.cloud.ibm.com/identity/token?=null\" -H \"Content-Type: application/x-www-form-urlencoded\" -d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" -d \"apikey=\"\n", - "\n", - "Get list of LLMs:\n", - " \n", - "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/foundation_model_specs?version=2024-09-16&project_id=1eeb4112-5f6e-4a81-9b61-8eac7f9653b4&filters=function_text_generation%2C%21lifecycle_withdrawn%3Aand&limit=200\" -H \"Authorization: Bearer \"\n", - "\n", - "\n", - "Ask the LLM a question:\n", - " \n", - "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02\" -H \"Content-Type: application/json\" -H \"Accept: application/json\" -H \"Authorization: Bearer \" \\\n", + "Tip: Verify access to watsonX APIs before installing LiteLLM.\n", + "

\n", + "Get Session Token:
\n", + "```bash\n", + "curl -L \"https://iam.cloud.ibm.com/identity/token?=null\" \n", + "-H \"Content-Type: application/x-www-form-urlencoded\" \n", + "-d \"grant_type=urn%3Aibm%3Aparams%3Aoauth%3Agrant-type%3Aapikey\" \n", + "-d \"apikey=\"\n", + "```\n", + "\n", + "Get list of LLMs:
\n", + "```bash\n", + "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/foundation_model_specs?version=2024-09-16&project_id=1eeb4112-5f6e-4a81-9b61-8eac7f9653b4&filters=function_text_generation%2C%21lifecycle_withdrawn%3Aand&limit=200\" \n", + "-H \"Authorization: Bearer \"\n", + "```\n", + "\n", + "Ask the LLM a question:
\n", + "```bash\n", + "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02\" \n", + "-H \"Content-Type: application/json\" \n", + "-H \"Accept: application/json\" \n", + "-H \"Authorization: Bearer \" \\\n", "-d \"{\n", " \\\"model_id\\\": \\\"google/flan-t5-xxl\\\",\n", " \\\"input\\\": \\\"What is the capital of Arkansas?:\\\",\n", @@ -61,72 +70,66 @@ " \\\"max_new_tokens\\\": 100,\n", " \\\"time_limit\\\": 1000\n", " },\n", - " \\\"project_id\\\": \\\"\"\n", - "}\"\n", + " \\\"project_id\\\": \\\"\"}\"\n", + "```\n", "\n", "\n", - "2.\tWith access to watsonX API’s validated you can install the python library\n", - " \n", - " \n", - "From \n" + "With access to watsonX API’s validated you can install the python library from \n", + "\n", + "---" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] - }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Installing LiteLLM \n", - "\n", + "To install LiteLLM, follow these steps:\n", "1. **Download LiteLLM Docker Image:**\n", "\n", " ```bash\n", " docker pull ghcr.io/berriai/litellm:main-latest\n", " ```\n", "\n", - " **(ALTERNATIVE). Install LiteLLM Python Library:**\n", + " OR\n", + "\n", + "\n", + " **Install LiteLLM Python Library:**\n", "\n", " ```bash\n", " pip install 'litellm[proxy]'\n", " ```\n", "\n", "\n", - "\n", - "---\n", - "\n", "2. **Create a LiteLLM Configuration File:**\n", "\n", " - Save as `litellm_config.yaml` in a local directory.\n", " - Example content for WatsonX:\n", "\n", - " ```yaml\n", - " model_list:\n", - " - model_name: llama-3-8b\n", - " litellm_params:\n", - " # all params accepted by litellm.completion()\n", - " model: watsonx/meta-llama/llama-3-8b-instruct\n", - " api_key: \"os.environ/WATSONX_API_KEY\" \n", - " project_id: \"os.environ/WX_PROJECT_ID\"\n", + " ```bash\n", + " model_list:\n", + " - model_name: llama-3-8b\n", + " litellm_params:\n", + " # all params accepted by litellm.completion()\n", + " model: watsonx/meta-llama/llama-3-8b-instruct\n", + " api_key: \"os.environ/WATSONX_API_KEY\" \n", + " project_id: \"os.environ/WX_PROJECT_ID\"\n", "\n", " ```\n", - "'''yaml\n", - " - model_name: \"llama_3_2_90\"\n", - " litellm_params:\n", - " model: watsonx/meta-llama/llama-3-2-90b-vision-instruct\n", - " api_key: os.environ[\"WATSONX_APIKEY\"] = \"\" # IBM cloud API key\n", - " max_new_tokens: 4000\n", - "'''\n", + " ```bash\n", + " - model_name: \"llama_3_2_90\"\n", + " litellm_params:\n", + " model: watsonx/meta-llama/llama-3-2-90b-vision-instruct\n", + " api_key: os.environ[\"WATSONX_APIKEY\"] = \"\" # IBM cloud API key\n", + " max_new_tokens: 4000\n", + " ```\n", "3. **Start LiteLLM Container:**\n", "\n", " ```bash\n", " docker run -v \\litellm_config.yaml:/app/config.yaml -e WATSONX_API_KEY= -e WATSONX_URL=https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02 -e WX_PROJECT_ID= -p 4000:4000 ghcr.io/berriai/litellm:main-latest --config /app/config.yaml --detailed_debug\n", " ```\n", "\n", - " ---" + "---" ] }, { @@ -147,12 +150,12 @@ "Once installed, AutoGen agents can leverage WatsonX APIs via LiteLLM.\n", "\n", "---\n", - "\n", + "```bash\n", "phi1 = {\n", " \"config_list\": [\n", " {\n", " \"model\": \"llama-3-8b\",\n", - " \"base_url\": \"http://localhost:4000\",\n", + " \"base_url\": \"http://localhost:4000\", #use http://0.0.0.0:4000 for Macs\n", " \"api_key\":\"watsonx\",\n", " \"price\" : [0,0]\n", " },\n", @@ -160,14 +163,11 @@ " \"cache_seed\": None, # Disable caching.\n", "}\n", "\n", - "\n", - "\n", - "\n", "phi2 = {\n", " \"config_list\": [\n", " {\n", " \"model\": \"llama-3-8b\",\n", - " \"base_url\": \"http://localhost:4000\",\n", + " \"base_url\": \"http://localhost:4000\", #use http://0.0.0.0:4000 for Macs\n", " \"api_key\":\"watsonx\",\n", " \"price\" : [0,0]\n", " },\n", @@ -190,8 +190,14 @@ ")\n", "\n", "#autogen\n", - "chat_result = jack.initiate_chat(emma, message=\"Emma, tell me a joke.\", max_turns=2)\n" + "chat_result = jack.initiate_chat(emma, message=\"Emma, tell me a joke.\", max_turns=2)\n", + "```" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] } ], "metadata": { From 1b1343e4f00046ef7384acb2bd742e2670cb1341 Mon Sep 17 00:00:00 2001 From: Lazaros Toumanidis Date: Thu, 12 Dec 2024 23:05:25 +0200 Subject: [PATCH 30/40] Update llamaindex_conversable_agent.py --- autogen/agentchat/contrib/llamaindex_conversable_agent.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/autogen/agentchat/contrib/llamaindex_conversable_agent.py b/autogen/agentchat/contrib/llamaindex_conversable_agent.py index 950b5995ec..c1a51cc491 100644 --- a/autogen/agentchat/contrib/llamaindex_conversable_agent.py +++ b/autogen/agentchat/contrib/llamaindex_conversable_agent.py @@ -16,12 +16,13 @@ from llama_index.core.agent.runner.base import AgentRunner from llama_index.core.base.llms.types import ChatMessage from llama_index.core.chat_engine.types import AgentChatResponse - from packaging import version from pydantic import BaseModel from pydantic import __version__ as pydantic_version # let's Avoid: AttributeError: type object 'Config' has no attribute 'copy' - if version.parse(pydantic_version) >= version.parse("2.0.0"): + # check for v1 like in autogen/_pydantic.py + is_pydantic_v1 = pydantic_version.startswith("1.") + if not is_pydantic_v1: from pydantic import ConfigDict Config = ConfigDict(arbitrary_types_allowed=True) From ab5947b63c4d778f4df5549f6fa0fd9e655784a0 Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Fri, 13 Dec 2024 10:18:47 -0600 Subject: [PATCH 31/40] Changed br to newline --- .../non-openai-models/cloud-litellm-watsonx.ipynb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb index 5f6f31b546..fc14743858 100644 --- a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb +++ b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb @@ -31,8 +31,8 @@ "1. **Access WatsonX:**\n", " - Sign up for [WatsonX.ai](https://www.ibm.com/watsonx).\n", " - Create an API_KEY and PROJECT_ID.\n", - "
\n", - "
\n", + "\n\n", + "\n\n", "2. **Validate WatsonX API Access:**\n", " - Verify access using the following commands:" ] @@ -42,8 +42,8 @@ "metadata": {}, "source": [ "Tip: Verify access to watsonX APIs before installing LiteLLM.\n", - "

\n", - "Get Session Token:
\n", + "\n\n\n", + "Get Session Token: \n\n", "```bash\n", "curl -L \"https://iam.cloud.ibm.com/identity/token?=null\" \n", "-H \"Content-Type: application/x-www-form-urlencoded\" \n", @@ -51,13 +51,13 @@ "-d \"apikey=\"\n", "```\n", "\n", - "Get list of LLMs:
\n", + "Get list of LLMs: \n\n", "```bash\n", "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/foundation_model_specs?version=2024-09-16&project_id=1eeb4112-5f6e-4a81-9b61-8eac7f9653b4&filters=function_text_generation%2C%21lifecycle_withdrawn%3Aand&limit=200\" \n", "-H \"Authorization: Bearer \"\n", "```\n", "\n", - "Ask the LLM a question:
\n", + "Ask the LLM a question: \n\n", "```bash\n", "curl -L \"https://us-south.ml.cloud.ibm.com/ml/v1/text/generation?version=2023-05-02\" \n", "-H \"Content-Type: application/json\" \n", From 1a30b9e7412bec5be04b17bb5cdf6db957fe280d Mon Sep 17 00:00:00 2001 From: "Moore, Eric" Date: Fri, 13 Dec 2024 10:25:32 -0600 Subject: [PATCH 32/40] Autogen to AG2 --- .../non-openai-models/cloud-litellm-watsonx.ipynb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb index fc14743858..42a3c388c0 100644 --- a/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb +++ b/website/docs/topics/non-openai-models/cloud-litellm-watsonx.ipynb @@ -6,11 +6,11 @@ "source": [ "# LiteLLM with WatsonX \n", "\n", - "LiteLLM is an open-source, locally run proxy server providing an OpenAI-compatible API. It supports various LLM providers, including IBM's WatsonX, enabling seamless integration with tools like AutoGen.\n", + "LiteLLM is an open-source, locally run proxy server providing an OpenAI-compatible API. It supports various LLM providers, including IBM's WatsonX, enabling seamless integration with tools like AG2.\n", "\n", "Running LiteLLM with WatsonX requires the following installations:\n", "\n", - "1. **AutoGen** – A framework for building and orchestrating AI agents.\n", + "1. **AG2** – A framework for building and orchestrating AI agents.\n", "2. **LiteLLM** – An OpenAI-compatible proxy for bridging non-compliant APIs.\n", "3. **IBM WatsonX** – LLM service requiring specific session token authentication.\n", "\n", @@ -136,9 +136,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Installing AutoGen \n", + "## Installing AG2 \n", "\n", - "AutoGen simplifies orchestration and communication between agents. To install:\n", + "AG2 simplifies orchestration and communication between agents. To install:\n", "\n", "1. Open a terminal with administrator rights.\n", "2. Run the following command:\n", @@ -147,7 +147,7 @@ " pip install ag2\n", " ```\n", "\n", - "Once installed, AutoGen agents can leverage WatsonX APIs via LiteLLM.\n", + "Once installed, AG2 agents can leverage WatsonX APIs via LiteLLM.\n", "\n", "---\n", "```bash\n", @@ -175,7 +175,7 @@ " \"cache_seed\": None, # Disable caching.\n", "}\n", "\n", - "from autogen import ConversableAgent, AssistantAgent\n", + "from AG2 import ConversableAgent, AssistantAgent\n", "\n", "jack = ConversableAgent(\n", " \"Jack (Phi-2)\",\n", @@ -189,7 +189,7 @@ " system_message=\"Your name is Emma and you are a comedian in two-person comedy show.\",\n", ")\n", "\n", - "#autogen\n", + "#AG2\n", "chat_result = jack.initiate_chat(emma, message=\"Emma, tell me a joke.\", max_turns=2)\n", "```" ] From bcafaeac876a662e943208f9c7193333912e8f50 Mon Sep 17 00:00:00 2001 From: Mark Sze <66362098+marklysze@users.noreply.github.com> Date: Sat, 14 Dec 2024 05:33:08 +1100 Subject: [PATCH 33/40] Update version.py 0.5.3b1 --- autogen/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen/version.py b/autogen/version.py index 6e2806f3f4..68b6d63101 100644 --- a/autogen/version.py +++ b/autogen/version.py @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: Apache-2.0 -__version__ = "0.5.2" +__version__ = "0.5.3b1" From dab7e169fe23e9ceb8e7924774ee0bcfcdbb9285 Mon Sep 17 00:00:00 2001 From: Mark Sze <66362098+marklysze@users.noreply.github.com> Date: Sat, 14 Dec 2024 06:37:43 +1100 Subject: [PATCH 34/40] Update version.py to 0.5.3 --- autogen/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen/version.py b/autogen/version.py index 68b6d63101..3b519defa1 100644 --- a/autogen/version.py +++ b/autogen/version.py @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: Apache-2.0 -__version__ = "0.5.3b1" +__version__ = "0.5.3" From f6308ce6f60aca977677d3db61399a6c9efba838 Mon Sep 17 00:00:00 2001 From: AgentGenie Date: Fri, 13 Dec 2024 11:50:03 -0800 Subject: [PATCH 35/40] Add Neo4j GraphRAG notebook to website --- notebook/agentchat_graph_rag_neo4j.ipynb | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/notebook/agentchat_graph_rag_neo4j.ipynb b/notebook/agentchat_graph_rag_neo4j.ipynb index d68ba8971d..00c4723aa5 100644 --- a/notebook/agentchat_graph_rag_neo4j.ipynb +++ b/notebook/agentchat_graph_rag_neo4j.ipynb @@ -39,7 +39,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -47,7 +47,7 @@ "\n", "import autogen\n", "\n", - "config_list = autogen.config_list_from_json(env_or_file=\"OAI_CONFIG_LIST\", file_location=\".\")\n", + "config_list = autogen.config_list_from_json(env_or_file=\"OAI_CONFIG_LIST\")\n", "\n", "# Put the OpenAI API key into the environment\n", "os.environ[\"OPENAI_API_KEY\"] = config_list[0][\"api_key\"]" @@ -446,8 +446,14 @@ } ], "metadata": { + "front_matter": { + "description": "Neo4j GraphRAG utilises a knowledge graph and can be added as a capability to agents.", + "tags": [ + "RAG" + ] + }, "kernelspec": { - "display_name": "ag2neo4j", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -461,7 +467,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.1" + "version": "3.11.10" } }, "nbformat": 4, From e607ab70635b8545d4675db715714b871cd1269f Mon Sep 17 00:00:00 2001 From: haard7 Date: Fri, 13 Dec 2024 16:25:51 -0800 Subject: [PATCH 36/40] Added a project in gallary --- website/src/data/gallery.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/website/src/data/gallery.json b/website/src/data/gallery.json index 02e9e5cdd6..ae60035ba8 100644 --- a/website/src/data/gallery.json +++ b/website/src/data/gallery.json @@ -235,5 +235,12 @@ "description": "Tracks personal finance income and expenses then helps the user to analyse it using AutoGen agents.", "image": "default.png", "tags": ["tools", "app"] + }, + { + "title": "Multimodal Ecommerce Retail Chatbot", + "link": "https://github.com/haard7/multi-agent-fullstack-project", + "description": "Chatbot handling recommendation, purchase, order tracking and fraud detection in an ecommerce retail", + "image": "default.png", + "tags": ["ui", "groupchat"] } ] From 2c3e0638d09fbfeca5e0db33255b975683d4c6bf Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 15 Dec 2024 21:20:17 +0000 Subject: [PATCH 37/40] Updated parameter name to update_agent_state_before_reply Signed-off-by: Mark Sze --- autogen/agentchat/contrib/swarm_agent.py | 6 +++--- autogen/agentchat/conversable_agent.py | 6 +++--- website/docs/topics/swarm.ipynb | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/autogen/agentchat/contrib/swarm_agent.py b/autogen/agentchat/contrib/swarm_agent.py index fcb6db08a1..c525c53db3 100644 --- a/autogen/agentchat/contrib/swarm_agent.py +++ b/autogen/agentchat/contrib/swarm_agent.py @@ -350,7 +350,7 @@ def __init__( human_input_mode: Literal["ALWAYS", "NEVER", "TERMINATE"] = "NEVER", description: Optional[str] = None, code_execution_config=False, - update_agent_before_reply: Optional[ + update_agent_state_before_reply: Optional[ Union[List[Union[Callable, UPDATE_SYSTEM_MESSAGE]], Callable, UPDATE_SYSTEM_MESSAGE] ] = None, **kwargs, @@ -385,9 +385,9 @@ def __init__( # List of Dictionaries containing the nested_chats and condition self._nested_chat_handoffs = [] - self.register_update_agent_before_reply(update_agent_before_reply) + self.register_update_agent_state_before_reply(update_agent_state_before_reply) - def register_update_agent_before_reply(self, functions: Optional[Union[List[Callable], Callable]]): + def register_update_agent_state_before_reply(self, functions: Optional[Union[List[Callable], Callable]]): """ Register functions that will be called when the agent is selected and before it speaks. You can add your own validation or precondition functions here. diff --git a/autogen/agentchat/conversable_agent.py b/autogen/agentchat/conversable_agent.py index db69574f96..ffd6923721 100644 --- a/autogen/agentchat/conversable_agent.py +++ b/autogen/agentchat/conversable_agent.py @@ -2093,7 +2093,7 @@ def generate_reply( messages = self._oai_messages[sender] # Call the hookable method that gives registered hooks a chance to update agent state, used for their context variables. - self.process_update_agent_states(messages) + self.update_agent_state_before_reply(messages) # Call the hookable method that gives registered hooks a chance to process the last message. # Message modifications do not affect the incoming messages or self._oai_messages. @@ -2166,7 +2166,7 @@ async def a_generate_reply( messages = self._oai_messages[sender] # Call the hookable method that gives registered hooks a chance to update agent state, used for their context variables. - self.process_update_agent_states(messages) + self.update_agent_state_before_reply(messages) # Call the hookable method that gives registered hooks a chance to process all messages. # Message modifications do not affect the incoming messages or self._oai_messages. @@ -2854,7 +2854,7 @@ def register_hook(self, hookable_method: str, hook: Callable): assert hook not in hook_list, f"{hook} is already registered as a hook." hook_list.append(hook) - def process_update_agent_states(self, messages: List[Dict]) -> None: + def update_agent_state_before_reply(self, messages: List[Dict]) -> None: """ Calls any registered capability hooks to update the agent's state. Primarily used to update context variables. diff --git a/website/docs/topics/swarm.ipynb b/website/docs/topics/swarm.ipynb index 2edd76fcde..82a0a3cc83 100644 --- a/website/docs/topics/swarm.ipynb +++ b/website/docs/topics/swarm.ipynb @@ -168,11 +168,11 @@ "source": [ "### Update Agent state before replying\n", "\n", - "It can be useful to update an agent's state before they reply, particularly their system message/prompt.\n", + "It can be useful to update a swarm agent's state before they reply. For example, using an agent's context variables you could change their system message based on the state of the workflow.\n", "\n", - "When initialising an agent you can use the `update_agent_before_reply` to register the updates run when the agent is selected, but before they reply.\n", + "When initialising a swarm agent use the `update_agent_state_before_reply` parameter to register updates that run after the agent is selected, but before they reply.\n", "\n", - "The `update_agent_before_reply` takes a list of any combination of the following (executing them in the provided order):\n", + "`update_agent_state_before_reply` takes a list of any combination of the following (executing them in the provided order):\n", "\n", "- `UPDATE_SYSTEM_MESSAGE` provides a simple way to update the agent's system message via an f-string that substitutes the values of context variables, or a Callable that returns a string\n", "- Callable with two parameters of type `ConversableAgent` for the agent and `List[Dict[str Any]]` for the messages, and does not return a value\n", @@ -198,7 +198,7 @@ "customer_service = SwarmAgent(\n", " name=\"CustomerServiceRep\",\n", " system_message=\"You are a customer service representative.\",\n", - " update_agent_before_reply=[\n", + " update_agent_state_before_reply=[\n", " UPDATE_SYSTEM_MESSAGE(\"You are a customer service representative. Quote passport number '{passport_number}'\"),\n", " UPDATE_SYSTEM_MESSAGE(create_system_prompt_function),\n", " my_callable_state_update_function]\n", From bf0de6407166662a93b8bc95f16e53c4b4aec035 Mon Sep 17 00:00:00 2001 From: Mark Sze Date: Sun, 15 Dec 2024 21:26:54 +0000 Subject: [PATCH 38/40] Update tests for update_agent_state_before_reply Signed-off-by: Mark Sze --- test/agentchat/contrib/test_swarm.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/agentchat/contrib/test_swarm.py b/test/agentchat/contrib/test_swarm.py index 85130baac2..ae2f3cf9b9 100644 --- a/test/agentchat/contrib/test_swarm.py +++ b/test/agentchat/contrib/test_swarm.py @@ -463,7 +463,7 @@ def test_initialization(): def test_update_system_message(): - """Tests the update_agent_before_reply functionality with multiple scenarios""" + """Tests the update_agent_state_before_reply functionality with multiple scenarios""" # Test container to capture system messages class MessageContainer: @@ -480,9 +480,9 @@ def custom_update_function(agent: ConversableAgent, messages: List[Dict]) -> str template_message = "Template message with {test_var}" # Create agents with different update configurations - agent1 = SwarmAgent("agent1", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(custom_update_function)) + agent1 = SwarmAgent("agent1", update_agent_state_before_reply=UPDATE_SYSTEM_MESSAGE(custom_update_function)) - agent2 = SwarmAgent("agent2", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(template_message)) + agent2 = SwarmAgent("agent2", update_agent_state_before_reply=UPDATE_SYSTEM_MESSAGE(template_message)) # Mock the reply function to capture the system message def mock_generate_oai_reply(*args, **kwargs): @@ -519,21 +519,21 @@ def mock_generate_oai_reply(*args, **kwargs): # Test invalid update function with pytest.raises(ValueError, match="Update function must be either a string or a callable"): - SwarmAgent("agent3", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(123)) + SwarmAgent("agent3", update_agent_state_before_reply=UPDATE_SYSTEM_MESSAGE(123)) # Test invalid callable (wrong number of parameters) def invalid_update_function(context_variables): return "Invalid function" with pytest.raises(ValueError, match="Update function must accept two parameters"): - SwarmAgent("agent4", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(invalid_update_function)) + SwarmAgent("agent4", update_agent_state_before_reply=UPDATE_SYSTEM_MESSAGE(invalid_update_function)) # Test invalid callable (wrong return type) def invalid_return_function(context_variables, messages) -> dict: return {} with pytest.raises(ValueError, match="Update function must return a string"): - SwarmAgent("agent5", update_agent_before_reply=UPDATE_SYSTEM_MESSAGE(invalid_return_function)) + SwarmAgent("agent5", update_agent_state_before_reply=UPDATE_SYSTEM_MESSAGE(invalid_return_function)) # Test multiple update functions def another_update_function(context_variables: Dict[str, Any], messages: List[Dict]) -> str: @@ -541,7 +541,7 @@ def another_update_function(context_variables: Dict[str, Any], messages: List[Di agent6 = SwarmAgent( "agent6", - update_agent_before_reply=[ + update_agent_state_before_reply=[ UPDATE_SYSTEM_MESSAGE(custom_update_function), UPDATE_SYSTEM_MESSAGE(another_update_function), ], From 6d98ea8ca75a1f81528052c3421127325418609f Mon Sep 17 00:00:00 2001 From: Mark Sze <66362098+marklysze@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:17:09 +1100 Subject: [PATCH 39/40] pre-commit run tidy --- autogen/oai/bedrock.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/autogen/oai/bedrock.py b/autogen/oai/bedrock.py index 042ab1146a..808aad5d76 100644 --- a/autogen/oai/bedrock.py +++ b/autogen/oai/bedrock.py @@ -96,10 +96,15 @@ def __init__(self, **kwargs: Any): if "response_format" in kwargs and kwargs["response_format"] is not None: warnings.warn("response_format is not supported for Bedrock, it will be ignored.", UserWarning) - #if haven't got any access_key or secret_key in environment variable or via arugments then - if self._aws_access_key is None or self._aws_access_key == "" or self._aws_secret_key is None or self._aws_secret_key == "": - - # attempts to get client from attached role of mananged service (lambda, ec2, ecs, etc.) + # if haven't got any access_key or secret_key in environment variable or via arguments then + if ( + self._aws_access_key is None + or self._aws_access_key == "" + or self._aws_secret_key is None + or self._aws_secret_key == "" + ): + + # attempts to get client from attached role of managed service (lambda, ec2, ecs, etc.) self.bedrock_runtime = boto3.client(service_name="bedrock-runtime", config=bedrock_config) else: session = boto3.Session( From 5a28894a6f756e0fc75ee262d6286be83f240741 Mon Sep 17 00:00:00 2001 From: Mark Sze <66362098+marklysze@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:18:30 +1100 Subject: [PATCH 40/40] Update bedrock documentation --- .../non-openai-models/cloud-bedrock.ipynb | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-bedrock.ipynb b/website/docs/topics/non-openai-models/cloud-bedrock.ipynb index 71c1e2e7ff..db792516c6 100644 --- a/website/docs/topics/non-openai-models/cloud-bedrock.ipynb +++ b/website/docs/topics/non-openai-models/cloud-bedrock.ipynb @@ -10,26 +10,26 @@ "source": [ "# Amazon Bedrock\n", "\n", - "AutoGen allows you to use Amazon's generative AI Bedrock service to run inference with a number of open-weight models and as well as their own models.\n", + "AG2 allows you to use Amazon's generative AI Bedrock service to run inference with a number of open-weight models and as well as their own models.\n", "\n", "Amazon Bedrock supports models from providers such as Meta, Anthropic, Cohere, and Mistral.\n", "\n", - "In this notebook, we demonstrate how to use Anthropic's Sonnet model for AgentChat in AutoGen.\n", + "In this notebook, we demonstrate how to use Anthropic's Sonnet model for AgentChat in AG2.\n", "\n", "## Model features / support\n", "\n", - "Amazon Bedrock supports a wide range of models, not only for text generation but also for image classification and generation. Not all features are supported by AutoGen or by the Converse API used. Please see [Amazon's documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html#conversation-inference-supported-models-features) on the features supported by the Converse API.\n", + "Amazon Bedrock supports a wide range of models, not only for text generation but also for image classification and generation. Not all features are supported by AG2 or by the Converse API used. Please see [Amazon's documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/conversation-inference.html#conversation-inference-supported-models-features) on the features supported by the Converse API.\n", "\n", - "At this point in time AutoGen supports text generation and image classification (passing images to the LLM).\n", + "At this point in time AG2 supports text generation and image classification (passing images to the LLM).\n", "\n", "It does not, yet, support image generation ([contribute](https://microsoft.github.io/autogen/docs/contributor-guide/contributing/)).\n", "\n", "## Requirements\n", - "To use Amazon Bedrock with AutoGen, first you need to install the `pyautogen[bedrock]` package.\n", + "To use Amazon Bedrock with AG2, first you need to install the `ag2[bedrock]` package.\n", "\n", "## Pricing\n", "\n", - "When we combine the number of models supported and costs being on a per-region basis, it's not feasible to maintain the costs for each model+region combination within the AutoGen implementation. Therefore, it's recommended that you add the following to your config with cost per 1,000 input and output tokens, respectively:\n", + "When we combine the number of models supported and costs being on a per-region basis, it's not feasible to maintain the costs for each model+region combination within the AG2 implementation. Therefore, it's recommended that you add the following to your config with cost per 1,000 input and output tokens, respectively:\n", "```\n", "{\n", " ...\n", @@ -125,6 +125,15 @@ "```" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using within an AWS Lambda function\n", + "\n", + "If you are using your AG2 code within an AWS Lambda function, you can utilise the attached role to access the Bedrock service and do not need to provide access, token, or profile values." + ] + }, { "cell_type": "markdown", "metadata": {},