From fe8a56499d07231c23a3e6ffc5356f97516f6d63 Mon Sep 17 00:00:00 2001 From: levscaut Date: Sun, 7 Apr 2024 00:25:20 -0400 Subject: [PATCH 1/4] add support for function call --- .../non-openai-models/cloud-anthropic.ipynb | 249 ++++++++++++++---- 1 file changed, 204 insertions(+), 45 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb index 4d15a0e06d9b..0e6ed6e1eb92 100644 --- a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb +++ b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb @@ -1,7 +1,6 @@ { "cells": [ { - "attachments": {}, "cell_type": "markdown", "metadata": { "slideshow": { @@ -14,16 +13,51 @@ "In this notebook, we demonstrate how a to use Anthropic Claude model for AgentChat.\n", "\n", "## Requirements\n", - "To use Anthropic Claude with AutoGen, first you need to install the `pyautogen` and `anthropic` package.\n" + "To use Anthropic Claude with AutoGen, first you need to install the `pyautogen` and `anthropic` package.\n", + "\n", + "To try out the function call feature of Claude model, you need to install `anthropic>=0.23.1`.\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: anthropic>=0.23.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (0.23.1)\n", + "Requirement already satisfied: sniffio in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (1.2.0)\n", + "Requirement already satisfied: pydantic<3,>=1.9.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (2.6.4)\n", + "Requirement already satisfied: anyio<5,>=3.5.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (4.3.0)\n", + "Requirement already satisfied: distro<2,>=1.7.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (1.9.0)\n", + "Requirement already satisfied: typing-extensions<5,>=4.7 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (4.10.0)\n", + "Requirement already satisfied: httpx<1,>=0.23.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (0.27.0)\n", + "Requirement already satisfied: tokenizers>=0.13.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (0.15.2)\n", + "Requirement already satisfied: exceptiongroup>=1.0.2 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anyio<5,>=3.5.0->anthropic>=0.23.1) (1.2.0)\n", + "Requirement already satisfied: idna>=2.8 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anyio<5,>=3.5.0->anthropic>=0.23.1) (3.2)\n", + "Requirement already satisfied: httpcore==1.* in /home/levscaut/anaconda3/lib/python3.9/site-packages (from httpx<1,>=0.23.0->anthropic>=0.23.1) (1.0.5)\n", + "Requirement already satisfied: certifi in /home/levscaut/anaconda3/lib/python3.9/site-packages (from httpx<1,>=0.23.0->anthropic>=0.23.1) (2021.10.8)\n", + "Requirement already satisfied: h11<0.15,>=0.13 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->anthropic>=0.23.1) (0.14.0)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.23.1) (0.6.0)\n", + "Requirement already satisfied: pydantic-core==2.16.3 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.23.1) (2.16.3)\n", + "Requirement already satisfied: huggingface_hub<1.0,>=0.16.4 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from tokenizers>=0.13.0->anthropic>=0.23.1) (0.22.2)\n", + "Requirement already satisfied: packaging>=20.9 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (21.0)\n", + "Requirement already satisfied: filelock in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (3.13.3)\n", + "Requirement already satisfied: tqdm>=4.42.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (4.62.3)\n", + "Requirement already satisfied: fsspec>=2023.5.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (2024.3.1)\n", + "Requirement already satisfied: pyyaml>=5.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (6.0)\n", + "Requirement already satisfied: requests in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (2.30.0)\n", + "Requirement already satisfied: pyparsing>=2.0.2 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from packaging>=20.9->huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (3.0.4)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (1.26.7)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (2.0.4)\n" + ] + } + ], "source": [ - "!pip install pyautogen anthropic" + "# !pip install pyautogen\n", + "!pip install \"anthropic>=0.23.1\"" ] }, { @@ -33,14 +67,24 @@ "outputs": [], "source": [ "import inspect\n", + "import json\n", "from typing import Any, Dict, List, Union\n", "\n", "from anthropic import Anthropic\n", + "from anthropic import __version__ as anthropic_version\n", "from anthropic.types import Completion, Message\n", + "from openai.types.chat.chat_completion import ChatCompletionMessage\n", + "from typing_extensions import Annotated\n", "\n", "import autogen\n", "from autogen import AssistantAgent, UserProxyAgent\n", - "from autogen.oai.openai_utils import OAI_PRICE1K" + "from autogen.oai.openai_utils import OAI_PRICE1K\n", + "\n", + "TOOL_ENABLED = anthropic_version >= \"0.23.1\"\n", + "if TOOL_ENABLED:\n", + " from anthropic.types.beta.tools import ToolsBetaMessage\n", + "else:\n", + " ToolsBetaMessage = object" ] }, { @@ -132,39 +176,79 @@ " filter_dict = {k: v for k, v in config.items() if k in anthropic_kwargs}\n", " self._client = Anthropic(**filter_dict)\n", "\n", - " def message_retrieval(self, response: Message) -> Union[List[str], List]:\n", + " self._last_tooluse_status = {}\n", + "\n", + " def message_retrieval(\n", + " self, response: Union[Message, ToolsBetaMessage]\n", + " ) -> Union[List[str], List[ChatCompletionMessage]]:\n", " \"\"\"Retrieve the messages from the response.\"\"\"\n", - " choices = response.content\n", - " if isinstance(response, Message):\n", - " return [choice.text for choice in choices] # type: ignore [union-attr]\n", + " messages = response.content\n", + " if len(messages) == 0:\n", + " return [None]\n", + " res = []\n", + " if TOOL_ENABLED:\n", + " for choice in messages:\n", + " if choice.type == \"tool_use\":\n", + " res.insert(0, self.response_to_openai_message(choice))\n", + " self._last_tooluse_status[\"tool_use\"] = choice.model_dump()\n", + " else:\n", + " res.append(choice.text)\n", + " self._last_tooluse_status[\"think\"] = choice.text\n", + "\n", + " return res\n", "\n", - " # claude python SDK and API not yet support function calls\n", + " else:\n", + " return [ # type: ignore [return-value]\n", + " choice.text if choice.message.function_call is not None else choice.message.content # type: ignore [union-attr]\n", + " for choice in messages\n", + " ]\n", "\n", " def create(self, params: Dict[str, Any]) -> Completion:\n", - " \"\"\"Create a completion for a given config using openai's client.\n", + " \"\"\"Create a completion for a given config.\n", "\n", " Args:\n", - " client: The openai client.\n", " params: The params for the completion.\n", "\n", " Returns:\n", " The completion.\n", " \"\"\"\n", - " if \"messages\" in params:\n", - " raw_contents = params[\"messages\"]\n", - " if raw_contents[0][\"role\"] == \"system\":\n", - " system_message = raw_contents[0][\"content\"]\n", - " raw_contents = raw_contents[1:]\n", - " params[\"messages\"] = raw_contents\n", - " params[\"system\"] = system_message\n", - " completions: Completion = self._client.messages # type: ignore [attr-defined]\n", + " if \"tools\" in params:\n", + " raise ValueError(\n", + " \"Anthropic does not support api_style='tool' yet. Please register your functions as api_style='function'\"\n", + " )\n", + "\n", + " raw_contents = params[\"messages\"]\n", + " processed_messages = []\n", + " for message in raw_contents:\n", + "\n", + " if message[\"role\"] == \"system\":\n", + " params[\"system\"] = message[\"content\"]\n", + " elif message[\"role\"] == \"function\":\n", + " processed_messages.append(self.return_function_call_result(message[\"content\"]))\n", + " elif \"function_call\" in message:\n", + " processed_messages.append(self.restore_last_tooluse_status())\n", + " elif message[\"content\"] == \"\":\n", + " # I'm not sure how to elegantly terminate the conversation, please give me some advice about this.\n", + " pass\n", + " else:\n", + " processed_messages.append(message)\n", + "\n", + " params[\"messages\"] = processed_messages\n", + "\n", + " if TOOL_ENABLED and \"functions\" in params:\n", + " completions: Completion = self._client.beta.tools.messages\n", " else:\n", - " completions: Completion = self._client.completions\n", + " completions: Completion = self._client.messages # type: ignore [attr-defined]\n", "\n", " # Not yet support stream\n", " params = params.copy()\n", " params[\"stream\"] = False\n", " params.pop(\"model_client_cls\")\n", + " params[\"max_tokens\"] = params.get(\"max_tokens\", 4096)\n", + " if \"functions\" in params:\n", + " tools_configs = params.pop(\"functions\")\n", + " tools_configs = [self.openai_func_to_anthropic(tool) for tool in tools_configs]\n", + " params[\"tools\"] = tools_configs\n", " response = completions.create(**params)\n", "\n", " return response\n", @@ -185,6 +269,40 @@ "\n", " return total\n", "\n", + " def response_to_openai_message(self, response) -> ChatCompletionMessage:\n", + " dict_response = response.model_dump()\n", + " return ChatCompletionMessage(\n", + " content=None,\n", + " role=\"assistant\",\n", + " function_call={\"name\": dict_response[\"name\"], \"arguments\": json.dumps(dict_response[\"input\"])},\n", + " )\n", + "\n", + " def restore_last_tooluse_status(self) -> Dict:\n", + " cached_content = []\n", + " if \"think\" in self._last_tooluse_status:\n", + " cached_content.append({\"type\": \"text\", \"text\": self._last_tooluse_status[\"think\"]})\n", + " cached_content.append(self._last_tooluse_status[\"tool_use\"])\n", + " res = {\"role\": \"assistant\", \"content\": cached_content}\n", + " return res\n", + "\n", + " def return_function_call_result(self, result: str) -> Dict:\n", + " return {\n", + " \"role\": \"user\",\n", + " \"content\": [\n", + " {\n", + " \"type\": \"tool_result\",\n", + " \"tool_use_id\": self._last_tooluse_status[\"tool_use\"][\"id\"],\n", + " \"content\": result,\n", + " }\n", + " ],\n", + " }\n", + "\n", + " @staticmethod\n", + " def openai_func_to_anthropic(openai_func: dict) -> dict:\n", + " res = openai_func.copy()\n", + " res[\"input_schema\"] = res.pop(\"parameters\")\n", + " return res\n", + "\n", " @staticmethod\n", " def get_usage(response: Completion) -> Dict:\n", " return {\n", @@ -220,7 +338,7 @@ "config_list_claude = [\n", " {\n", " # Choose your model name.\n", - " \"model\": \"claude-3-opus-20240229\",\n", + " \"model\": \"claude-3-sonnet-20240229\",\n", " # You need to provide your API key here.\n", " \"api_key\": os.getenv(\"ANTHROPIC_API_KEY\"),\n", " \"base_url\": \"https://api.anthropic.com\",\n", @@ -237,22 +355,19 @@ "source": [ "## Construct Agents\n", "\n", - "Construct a simple conversation between a User proxy and an ConversableAgent based on Claude-3 model.\n", - "\n", - "\n", - "`max_tokens` argument is mandatory in the `llm_config`." + "Construct a simple conversation between a User proxy and an ConversableAgent based on Claude-3 model.\n" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[autogen.oai.client: 04-04 18:06:52] {418} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" + "[autogen.oai.client: 04-07 00:23:23] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" ] } ], @@ -261,19 +376,52 @@ " \"assistant\",\n", " llm_config={\n", " \"config_list\": config_list_claude,\n", - " \"max_tokens\": 100,\n", " },\n", - " system_message=\"\"\"\n", - " You are an AI cat based on the AI model you used.\n", - " Anyone ask you who you are, just introduce yourself.\n", - " \"\"\",\n", ")\n", + "\n", "user_proxy = UserProxyAgent(\n", " \"user_proxy\",\n", - " code_execution_config=False,\n", + " human_input_mode=\"NEVER\",\n", + " code_execution_config={\n", + " \"work_dir\": \"coding\",\n", + " \"use_docker\": False,\n", + " },\n", + " is_termination_msg=lambda x: x.get(\"content\", \"\") and x.get(\"content\", \"\").rstrip().endswith(\"TERMINATE\"),\n", + " max_consecutive_auto_reply=1,\n", ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Function Call in Latest Anthropic API \n", + "Anthropic just announced that tool use is now in public beta in the Anthropic API. To use this feature, please install `anthropic>=0.23.1`." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[autogen.oai.client: 04-07 00:23:23] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" + ] + } + ], + "source": [ + "@user_proxy.register_for_execution()\n", + "@assistant.register_for_llm(\n", + " name=\"get_weather\", description=\"Get the current weather in a given location.\", api_style=\"function\"\n", + ")\n", + "def preprocess(location: Annotated[str, \"The city and state, e.g. Toronto, ON.\"]) -> str:\n", + " if location:\n", + " return \"Absolutely cloudy and rainy\"" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -283,7 +431,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -292,32 +440,43 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\u001b[33muser_proxy\u001b[0m (to assistant):\n", + "user_proxy (to assistant):\n", "\n", - "Who are you?\n", + "What's the weather in Toronto?\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001b[33massistant\u001b[0m (to user_proxy):\n", + "assistant (to user_proxy):\n", "\n", - "*meows* Hello there! I'm Claude, an AI assistant created by Anthropic. I'm not a real cat, but rather an artificial intelligence that has been trained to engage in conversation and help with various tasks. It's a pleasure to meet you! Let me know if there is anything I can assist you with.\n", + "***** Suggested function call: get_weather *****\n", + "Arguments: \n", + "{\"location\": \"Toronto, ON\"}\n", + "************************************************\n", "\n", "--------------------------------------------------------------------------------\n" ] }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/levscaut/autogen/autogen/agentchat/conversable_agent.py:1125: UserWarning: Cannot extract summary using last_msg: 'NoneType' object has no attribute 'replace'. Using an empty str as summary.\n", + " warnings.warn(f\"Cannot extract summary using last_msg: {e}. Using an empty str as summary.\", UserWarning)\n" + ] + }, { "data": { "text/plain": [ - "ChatResult(chat_id=None, chat_history=[{'content': 'Who are you?', 'role': 'assistant'}, {'content': \"*meows* Hello there! I'm Claude, an AI assistant created by Anthropic. I'm not a real cat, but rather an artificial intelligence that has been trained to engage in conversation and help with various tasks. It's a pleasure to meet you! Let me know if there is anything I can assist you with.\", 'role': 'user'}], summary=\"*meows* Hello there! I'm Claude, an AI assistant created by Anthropic. I'm not a real cat, but rather an artificial intelligence that has been trained to engage in conversation and help with various tasks. It's a pleasure to meet you! Let me know if there is anything I can assist you with.\", cost=({'total_cost': 0.0058200000000000005, 'claude-3-opus-20240229': {'cost': 0.0058200000000000005, 'prompt_tokens': 38, 'completion_tokens': 70, 'total_tokens': 108}}, {'total_cost': 0.0058200000000000005, 'claude-3-opus-20240229': {'cost': 0.0058200000000000005, 'prompt_tokens': 38, 'completion_tokens': 70, 'total_tokens': 108}}), human_input=['exit'])" + "ChatResult(chat_id=None, chat_history=[{'content': \"What's the weather in Toronto?\", 'role': 'assistant'}, {'function_call': {'arguments': '{\"location\": \"Toronto, ON\"}', 'name': 'get_weather'}, 'content': None, 'role': 'assistant'}], summary='', cost=({'total_cost': 0.01656, 'claude-3-sonnet-20240229': {'cost': 0.01656, 'prompt_tokens': 719, 'completion_tokens': 77, 'total_tokens': 796}}, {'total_cost': 0}), human_input=[])" ] }, - "execution_count": 7, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -325,7 +484,7 @@ "source": [ "user_proxy.initiate_chat(\n", " assistant,\n", - " message=\"Who are you?\",\n", + " message=\"What's the weather in Toronto?\",\n", ")" ] } @@ -352,7 +511,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.17" + "version": "3.9.7" }, "vscode": { "interpreter": { From ac0b97823a6fb67ca418fc2e376a5256d2e9fc6a Mon Sep 17 00:00:00 2001 From: levscaut Date: Sun, 7 Apr 2024 00:26:54 -0400 Subject: [PATCH 2/4] clear pip install output --- .../non-openai-models/cloud-anthropic.ipynb | 36 ++----------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb index 0e6ed6e1eb92..1946b522a545 100644 --- a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb +++ b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb @@ -20,41 +20,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: anthropic>=0.23.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (0.23.1)\n", - "Requirement already satisfied: sniffio in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (1.2.0)\n", - "Requirement already satisfied: pydantic<3,>=1.9.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (2.6.4)\n", - "Requirement already satisfied: anyio<5,>=3.5.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (4.3.0)\n", - "Requirement already satisfied: distro<2,>=1.7.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (1.9.0)\n", - "Requirement already satisfied: typing-extensions<5,>=4.7 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (4.10.0)\n", - "Requirement already satisfied: httpx<1,>=0.23.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (0.27.0)\n", - "Requirement already satisfied: tokenizers>=0.13.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anthropic>=0.23.1) (0.15.2)\n", - "Requirement already satisfied: exceptiongroup>=1.0.2 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anyio<5,>=3.5.0->anthropic>=0.23.1) (1.2.0)\n", - "Requirement already satisfied: idna>=2.8 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from anyio<5,>=3.5.0->anthropic>=0.23.1) (3.2)\n", - "Requirement already satisfied: httpcore==1.* in /home/levscaut/anaconda3/lib/python3.9/site-packages (from httpx<1,>=0.23.0->anthropic>=0.23.1) (1.0.5)\n", - "Requirement already satisfied: certifi in /home/levscaut/anaconda3/lib/python3.9/site-packages (from httpx<1,>=0.23.0->anthropic>=0.23.1) (2021.10.8)\n", - "Requirement already satisfied: h11<0.15,>=0.13 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->anthropic>=0.23.1) (0.14.0)\n", - "Requirement already satisfied: annotated-types>=0.4.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.23.1) (0.6.0)\n", - "Requirement already satisfied: pydantic-core==2.16.3 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from pydantic<3,>=1.9.0->anthropic>=0.23.1) (2.16.3)\n", - "Requirement already satisfied: huggingface_hub<1.0,>=0.16.4 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from tokenizers>=0.13.0->anthropic>=0.23.1) (0.22.2)\n", - "Requirement already satisfied: packaging>=20.9 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (21.0)\n", - "Requirement already satisfied: filelock in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (3.13.3)\n", - "Requirement already satisfied: tqdm>=4.42.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (4.62.3)\n", - "Requirement already satisfied: fsspec>=2023.5.0 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (2024.3.1)\n", - "Requirement already satisfied: pyyaml>=5.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (6.0)\n", - "Requirement already satisfied: requests in /home/levscaut/anaconda3/lib/python3.9/site-packages (from huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (2.30.0)\n", - "Requirement already satisfied: pyparsing>=2.0.2 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from packaging>=20.9->huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (3.0.4)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (1.26.7)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /home/levscaut/anaconda3/lib/python3.9/site-packages (from requests->huggingface_hub<1.0,>=0.16.4->tokenizers>=0.13.0->anthropic>=0.23.1) (2.0.4)\n" - ] - } - ], + "outputs": [], "source": [ "# !pip install pyautogen\n", "!pip install \"anthropic>=0.23.1\"" From 9e870137f4bee6ed7c3205bfee24850f3f2b9650 Mon Sep 17 00:00:00 2001 From: levscaut Date: Mon, 8 Apr 2024 22:15:12 -0400 Subject: [PATCH 3/4] add convert function from `tools` to `functions` --- .../non-openai-models/cloud-anthropic.ipynb | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb index 1946b522a545..470e659cafa4 100644 --- a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb +++ b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb @@ -46,7 +46,6 @@ "\n", "import autogen\n", "from autogen import AssistantAgent, UserProxyAgent\n", - "from autogen.oai.openai_utils import OAI_PRICE1K\n", "\n", "TOOL_ENABLED = anthropic_version >= \"0.23.1\"\n", "if TOOL_ENABLED:\n", @@ -181,9 +180,8 @@ " The completion.\n", " \"\"\"\n", " if \"tools\" in params:\n", - " raise ValueError(\n", - " \"Anthropic does not support api_style='tool' yet. Please register your functions as api_style='function'\"\n", - " )\n", + " converted_functions = self.convert_tools_to_functions(params[\"tools\"])\n", + " params[\"functions\"] = params.get(\"functions\", []) + converted_functions\n", "\n", " raw_contents = params[\"messages\"]\n", " processed_messages = []\n", @@ -281,7 +279,16 @@ " ),\n", " \"cost\": response.cost if hasattr(response, \"cost\") else 0,\n", " \"model\": response.model,\n", - " }" + " }\n", + "\n", + " @staticmethod\n", + " def convert_tools_to_functions(tools: List) -> List:\n", + " functions = []\n", + " for tool in tools:\n", + " if tool.get(\"type\") == \"function\" and \"function\" in tool:\n", + " functions.append(tool[\"function\"])\n", + "\n", + " return functions" ] }, { @@ -328,14 +335,14 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[autogen.oai.client: 04-07 00:23:23] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" + "[autogen.oai.client: 04-08 22:05:57] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" ] } ], @@ -369,25 +376,22 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[autogen.oai.client: 04-07 00:23:23] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" + "[autogen.oai.client: 04-08 22:05:57] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" ] } ], "source": [ "@user_proxy.register_for_execution()\n", - "@assistant.register_for_llm(\n", - " name=\"get_weather\", description=\"Get the current weather in a given location.\", api_style=\"function\"\n", - ")\n", + "@assistant.register_for_llm(name=\"get_weather\", description=\"Get the current weather in a given location.\")\n", "def preprocess(location: Annotated[str, \"The city and state, e.g. Toronto, ON.\"]) -> str:\n", - " if location:\n", - " return \"Absolutely cloudy and rainy\"" + " return \"Absolutely cloudy and rainy\"" ] }, { @@ -399,7 +403,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -408,7 +412,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -427,24 +431,30 @@ "{\"location\": \"Toronto, ON\"}\n", "************************************************\n", "\n", + "--------------------------------------------------------------------------------\n", + "\n", + ">>>>>>>> EXECUTING FUNCTION get_weather...\n", + "user_proxy (to assistant):\n", + "\n", + "***** Response from calling function (get_weather) *****\n", + "Absolutely cloudy and rainy\n", + "********************************************************\n", + "\n", + "--------------------------------------------------------------------------------\n", + "assistant (to user_proxy):\n", + "\n", + "The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.\n", + "\n", "--------------------------------------------------------------------------------\n" ] }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/levscaut/autogen/autogen/agentchat/conversable_agent.py:1125: UserWarning: Cannot extract summary using last_msg: 'NoneType' object has no attribute 'replace'. Using an empty str as summary.\n", - " warnings.warn(f\"Cannot extract summary using last_msg: {e}. Using an empty str as summary.\", UserWarning)\n" - ] - }, { "data": { "text/plain": [ - "ChatResult(chat_id=None, chat_history=[{'content': \"What's the weather in Toronto?\", 'role': 'assistant'}, {'function_call': {'arguments': '{\"location\": \"Toronto, ON\"}', 'name': 'get_weather'}, 'content': None, 'role': 'assistant'}], summary='', cost=({'total_cost': 0.01656, 'claude-3-sonnet-20240229': {'cost': 0.01656, 'prompt_tokens': 719, 'completion_tokens': 77, 'total_tokens': 796}}, {'total_cost': 0}), human_input=[])" + "ChatResult(chat_id=None, chat_history=[{'content': \"What's the weather in Toronto?\", 'role': 'assistant'}, {'function_call': {'arguments': '{\"location\": \"Toronto, ON\"}', 'name': 'get_weather'}, 'content': None, 'role': 'assistant'}, {'content': 'Absolutely cloudy and rainy', 'name': 'get_weather', 'role': 'function'}, {'content': 'The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.', 'role': 'user'}], summary='The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.', cost=({'total_cost': 0.030494999999999998, 'claude-3-sonnet-20240229': {'cost': 0.030494999999999998, 'prompt_tokens': 1533, 'completion_tokens': 100, 'total_tokens': 1633}}, {'total_cost': 0.030494999999999998, 'claude-3-sonnet-20240229': {'cost': 0.030494999999999998, 'prompt_tokens': 1533, 'completion_tokens': 100, 'total_tokens': 1633}}), human_input=[])" ] }, - "execution_count": 12, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" } From 460592b12f6ef9935a1664d9116f6ef7e1ca2118 Mon Sep 17 00:00:00 2001 From: levscaut Date: Mon, 8 Apr 2024 22:17:12 -0400 Subject: [PATCH 4/4] fix empty user input error(temporary) --- .../non-openai-models/cloud-anthropic.ipynb | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb index 470e659cafa4..ec8793be4bcb 100644 --- a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb +++ b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb @@ -30,7 +30,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -131,7 +131,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -195,7 +195,8 @@ " processed_messages.append(self.restore_last_tooluse_status())\n", " elif message[\"content\"] == \"\":\n", " # I'm not sure how to elegantly terminate the conversation, please give me some advice about this.\n", - " pass\n", + " message[\"content\"] = \"I'm done. Please send TERMINATE\"\n", + " processed_messages.append(message)\n", " else:\n", " processed_messages.append(message)\n", "\n", @@ -304,7 +305,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -335,14 +336,14 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[autogen.oai.client: 04-08 22:05:57] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" + "[autogen.oai.client: 04-08 22:15:59] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" ] } ], @@ -376,14 +377,14 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "[autogen.oai.client: 04-08 22:05:57] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" + "[autogen.oai.client: 04-08 22:15:59] {419} INFO - Detected custom model client in config: AnthropicClient, model client can not be used until register_model_client is called.\n" ] } ], @@ -403,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -412,7 +413,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 16, "metadata": {}, "outputs": [ { @@ -451,10 +452,10 @@ { "data": { "text/plain": [ - "ChatResult(chat_id=None, chat_history=[{'content': \"What's the weather in Toronto?\", 'role': 'assistant'}, {'function_call': {'arguments': '{\"location\": \"Toronto, ON\"}', 'name': 'get_weather'}, 'content': None, 'role': 'assistant'}, {'content': 'Absolutely cloudy and rainy', 'name': 'get_weather', 'role': 'function'}, {'content': 'The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.', 'role': 'user'}], summary='The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.', cost=({'total_cost': 0.030494999999999998, 'claude-3-sonnet-20240229': {'cost': 0.030494999999999998, 'prompt_tokens': 1533, 'completion_tokens': 100, 'total_tokens': 1633}}, {'total_cost': 0.030494999999999998, 'claude-3-sonnet-20240229': {'cost': 0.030494999999999998, 'prompt_tokens': 1533, 'completion_tokens': 100, 'total_tokens': 1633}}), human_input=[])" + "ChatResult(chat_id=None, chat_history=[{'content': \"What's the weather in Toronto?\", 'role': 'assistant'}, {'function_call': {'arguments': '{\"location\": \"Toronto, ON\"}', 'name': 'get_weather'}, 'content': None, 'role': 'assistant'}, {'content': 'Absolutely cloudy and rainy', 'name': 'get_weather', 'role': 'function'}, {'content': 'The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.', 'role': 'user'}], summary='The tool returned that the current weather in Toronto, ON is absolutely cloudy and rainy.', cost=({'total_cost': 0.030494999999999998, 'claude-3-sonnet-20240229': {'cost': 0.030494999999999998, 'prompt_tokens': 1533, 'completion_tokens': 100, 'total_tokens': 1633}}, {'total_cost': 0}), human_input=[])" ] }, - "execution_count": 8, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" }