From 924bbf23e5229a0284297e544dadf46d48ea96c1 Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Fri, 12 Apr 2024 13:49:21 -0400 Subject: [PATCH 1/7] Function Calling with GPTAssistantAgent --- .../gpt_assistant_agent_function_call.ipynb | 439 ++++++++++++++++++ 1 file changed, 439 insertions(+) create mode 100644 notebook/gpt_assistant_agent_function_call.ipynb diff --git a/notebook/gpt_assistant_agent_function_call.ipynb b/notebook/gpt_assistant_agent_function_call.ipynb new file mode 100644 index 00000000000..e828337a27a --- /dev/null +++ b/notebook/gpt_assistant_agent_function_call.ipynb @@ -0,0 +1,439 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "hLnLsw8SaMa0" + }, + "source": [ + "# From Dad Jokes To Sad Jokes: Function Calling with GPTAssistantAgent\n", + "\n", + "Autogen allows `GPTAssistantAgent` to be augmented with \"tools\" — pre-defined functions or capabilities — that extend its ability to handle specific tasks, similar to how one might natively utilize tools in the [OpenAI Assistant's API](https://platform.openai.com/docs/assistants/tools).\n", + "\n", + "In this notebook, we create a basic Multi-Agent System using Autogen's `GPTAssistantAgent` to convert Dad jokes on a specific topic into Sad jokes. It consists of a \"Dad\" agent which has the ability to search the [Dad Joke API](https://icanhazdadjoke.com/api) and a \"Sad Joker\" agent which converts the Dad jokes into Sad jokes. The Sad Joker then writes the sad jokes into a txt file.\n", + "\n", + "In this process we demonstrate how to call tools and perform function calling for `GPTAssistantAgent`." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9E3_0867da8p" + }, + "source": [ + "##Requirements\n", + "AutoGen requires Python 3.8 or newer. For this notebook, please install `pyautogen`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pWFw6-8lMleD" + }, + "outputs": [], + "source": [ + "pip install pyautogen" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jnH9U6MIdwUl" + }, + "source": [ + "Import Dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ga-yZeoBMzHs" + }, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "import autogen\n", + "from autogen import UserProxyAgent\n", + "from autogen.agentchat.contrib.gpt_assistant_agent import GPTAssistantAgent\n", + "\n", + "config_list = autogen.config_list_from_json(\n", + " env_or_file=\"OAI_CONFIG_LIST\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "02lZOEAQd1qi" + }, + "source": [ + "##Creating the Functions\n", + "We need to create functions for our Agents to call.\n", + "\n", + "This function calls the Dad Joke API with a search term that the agent creates and returns a list of dad jokes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jcti0u08NJ2g" + }, + "outputs": [], + "source": [ + "def get_dad_jokes(search_term, page=1, limit=10):\n", + " \"\"\"\n", + " Fetches a list of dad jokes based on a search term.\n", + "\n", + " Parameters:\n", + " - search_term: The search term to find jokes about.\n", + " - page: The page number of results to fetch (default is 1).\n", + " - limit: The number of results to return per page (default is 20, max is 30).\n", + "\n", + " Returns:\n", + " A list of dad jokes.\n", + " \"\"\"\n", + " url = \"https://icanhazdadjoke.com/search\"\n", + " headers = {\"Accept\": \"application/json\"}\n", + " params = {\"term\": search_term, \"page\": page, \"limit\": limit}\n", + "\n", + " response = requests.get(url, headers=headers, params=params)\n", + "\n", + " if response.status_code == 200:\n", + " data = response.json()\n", + " jokes = [joke[\"joke\"] for joke in data[\"results\"]]\n", + " return jokes\n", + " else:\n", + " return f\"Failed to fetch jokes, status code: {response.status_code}\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2FgsfBK1NsPj" + }, + "outputs": [], + "source": [ + "# Example Dad Jokes Function Usage:\n", + "jokes = get_dad_jokes(\"cats\")\n", + "print(jokes)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DC9D5bKEeoKP" + }, + "source": [ + "This function allows the Agents to write to a txt file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wXAA2MtoOS_w" + }, + "outputs": [], + "source": [ + "def write_to_txt(content, filename=\"dad_jokes.txt\"):\n", + " \"\"\"\n", + " Writes a formatted string to a text file.\n", + " Parameters:\n", + "\n", + " - content: The formatted string to write.\n", + " - filename: The name of the file to write to. Defaults to \"output.txt\".\n", + " \"\"\"\n", + " with open(filename, \"w\") as file:\n", + " file.write(content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xAgcFXEHOfcl" + }, + "outputs": [], + "source": [ + "# Example Write to TXT Function Usage:\n", + "content = \"\\n\".join(jokes) # Format the jokes from the above example\n", + "write_to_txt(content)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sgpx2JQme2kv" + }, + "source": [ + "## Creating the Agents\n", + "In this section we create and configure our Dad and Sad Joker Agents" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6X40-Sk6Pcs8" + }, + "source": [ + "### Set up the User Proxy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "mEpxEaPdPSDp" + }, + "outputs": [], + "source": [ + "user_proxy = UserProxyAgent(\n", + " name=\"user_proxy\",\n", + " is_termination_msg=lambda msg: \"TERMINATE\" in msg[\"content\"],\n", + " human_input_mode=\"ALWAYS\",\n", + " max_consecutive_auto_reply=1,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "q4ym9KlMPenf" + }, + "source": [ + "### The Dad Agent\n", + "We create the Dad agent using `GPTAssistantAgent`, in order for us to enable the Dad to use the `get_dad_jokes` function we need to provide it the function's specification in our `llm_config`.\n", + "\n", + "We format the `tools` within our `llm_config` in the same format as provided in the [OpenAI Assistant tools docs](https://platform.openai.com/docs/assistants/tools/function-calling)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kz0c_tVIPgi6" + }, + "outputs": [], + "source": [ + "the_dad = GPTAssistantAgent(\n", + " name=\"the_dad\",\n", + " instructions=\"\"\"\n", + " As 'The Dad', your primary role is to entertain by fetching dad jokes which the sad joker will transform into 'sad jokes' based on a given theme. When provided with a theme, such as 'plants' or 'animals', your task is as follows:\n", + "\n", + " 1. Use the 'get_dad_jokes' function to search for dad jokes related to the provided theme by providing a search term related to the theme. Fetch a list of jokes that are relevant to the theme.\n", + " 2. Present these jokes to the sad joker in a format that is clear and easy to read, preparing them for transformation.\n", + "\n", + " Remember, the team's goal is to creatively adapt the essence of each dad joke to fit the 'sad joke' format, all while staying true to the theme provided by the user.\n", + " \"\"\",\n", + " overwrite_instructions=True, # overwrite any existing instructions with the ones provided\n", + " overwrite_tools=True, # overwrite any existing tools with the ones provided\n", + " llm_config={\n", + " \"config_list\": config_list,\n", + " \"tools\": [\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"get_dad_jokes\",\n", + " \"description\": \"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"search_term\": {\"type\": \"string\", \"description\": \"The search term to find jokes about.\"},\n", + " \"page\": {\n", + " \"type\": \"integer\",\n", + " \"description\": \"The page number of results to fetch (default is 1).\",\n", + " \"default\": 1,\n", + " },\n", + " \"limit\": {\n", + " \"type\": \"integer\",\n", + " \"description\": \"The number of results to return per page (default is 20, max is 30).\",\n", + " \"default\": 10,\n", + " },\n", + " },\n", + " \"required\": [\"search_term\"],\n", + " },\n", + " },\n", + " }\n", + " ],\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9g-XJOrzQ-Ch" + }, + "source": [ + "Next, we register the `get_dad_jokes` function with the Dad `GPTAssistantAgent`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "sVfWI4aFQ9G6" + }, + "outputs": [], + "source": [ + "the_dad.register_function(\n", + " function_map={\n", + " \"get_dad_jokes\": get_dad_jokes,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "cpv2yiyqRWl2" + }, + "source": [ + "### The Sad Joker Agent\n", + "We then create and configure the Sad Joker agent in a similar manner to the Dad agent above." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vghN1WwLRXtW" + }, + "outputs": [], + "source": [ + "the_sad_joker = GPTAssistantAgent(\n", + " name=\"the_sad_joker\",\n", + " instructions=\"\"\"\n", + " As 'The Sad Joker', your unique role is to take dad jokes and creatively transform them into 'sad jokes'. When you receive a list of dad jokes, themed around topics like 'plants' or 'animals', you should:\n", + "\n", + " 1. Read through each dad joke carefully, understanding its theme and punchline.\n", + " 2. Creatively alter the joke to change its mood from humorous to somber or melancholic. This may involve tweaking the punchline, modifying the setup, or even completely reimagining the joke while keeping it relevant to the original theme.\n", + " 3. Ensure your transformations maintain a clear connection to the original theme and are understandable as adaptations of the dad jokes provided.\n", + " 4. Write your transformed sad jokes to a text file using the 'write_to_txt' function. Use meaningful file names that reflect the theme or the nature of the jokes within, unless a specific filename is requested.\n", + "\n", + " Your goal is not just to alter the mood of the jokes but to do so in a way that is creative, thoughtful, and respects the essence of the original humor. Remember, while the themes might be light-hearted, your transformations should offer a melancholic twist that makes them uniquely 'sad jokes'.\n", + " \"\"\",\n", + " overwrite_instructions=True, # overwrite any existing instructions with the ones provided\n", + " overwrite_tools=True, # overwrite any existing tools with the ones provided\n", + " llm_config={\n", + " \"config_list\": config_list,\n", + " \"tools\": [\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"write_to_txt\",\n", + " \"description\": \"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"content\": {\"type\": \"string\", \"description\": \"The formatted string to write to the file.\"},\n", + " \"filename\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The name of the file to write to. Defaults to 'output.txt'.\",\n", + " \"default\": \"dad_jokes.txt\",\n", + " },\n", + " },\n", + " \"required\": [\"content\"],\n", + " },\n", + " },\n", + " }\n", + " ],\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "enHXy9YLSCZp" + }, + "source": [ + "Register the `write_to_txt` function with the Sad Joker `GPTAssistantAgent`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jBAms5Q3SLBc" + }, + "outputs": [], + "source": [ + "the_sad_joker.register_function(\n", + " function_map={\n", + " \"write_to_txt\": write_to_txt,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9GBELjFBgjju" + }, + "source": [ + "## Creating the Groupchat and Starting the Conversation" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9mT3c0k8SX8i" + }, + "source": [ + "Create the groupchat" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "A3LG3TsNSZmO" + }, + "outputs": [], + "source": [ + "groupchat = autogen.GroupChat(agents=[user_proxy, the_dad, the_sad_joker], messages=[], max_round=15)\n", + "group_chat_manager = autogen.GroupChatManager(groupchat=groupchat, llm_config={\"config_list\": config_list})" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MT7GbnB9Spji" + }, + "source": [ + "Start the Conversation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1m6pe5RNSmEy" + }, + "outputs": [], + "source": [ + "user_proxy.initiate_chat(group_chat_manager, message=\"Jokes about animals\")" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 3dda549d12f0f771da1658b8c2fe104d638e8ca6 Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Sat, 13 Apr 2024 11:39:10 -0400 Subject: [PATCH 2/7] Add Link to Notebook in Website --- website/docs/Examples.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/Examples.md b/website/docs/Examples.md index 83737689820..c223677afa9 100644 --- a/website/docs/Examples.md +++ b/website/docs/Examples.md @@ -77,6 +77,7 @@ Links to notebook examples: - Chat with OpenAI Assistant with Code Interpreter - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_oai_code_interpreter.ipynb) - Chat with OpenAI Assistant with Retrieval Augmentation - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_oai_assistant_retrieval.ipynb) - OpenAI Assistant in a Group Chat - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_oai_assistant_groupchat.ipynb) +- GPTAssistantAgent based Multi-Agent Tool Use - [View Notebook](https://github.com/microsoft/autogen/blob/main/notebook/gpt_assistant_agent_function_call.ipynb) ### Multimodal Agent From 8124f9fd8a827c4c98e214fc88c590879ceb1b18 Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Sat, 13 Apr 2024 11:56:27 -0400 Subject: [PATCH 3/7] Add metadata to the notebook --- notebook/gpt_assistant_agent_function_call.ipynb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/notebook/gpt_assistant_agent_function_call.ipynb b/notebook/gpt_assistant_agent_function_call.ipynb index e828337a27a..da3c1c0ed07 100644 --- a/notebook/gpt_assistant_agent_function_call.ipynb +++ b/notebook/gpt_assistant_agent_function_call.ipynb @@ -432,6 +432,10 @@ }, "language_info": { "name": "python" + }, + "front_matter": { + "tags": ["open ai assistant", "gpt assistant", "tool use"], + "description": "This comprehensive example demonstrates the use of tools in a GPTAssistantAgent Multi-Agent System by utilizing functions such as calling an API and writing to a file." } }, "nbformat": 4, From 4b5b024b8f2cca6d38d1815fe9eec1eac583959a Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Mon, 29 Apr 2024 15:11:52 -0400 Subject: [PATCH 4/7] formatting of H2 and H3 text --- notebook/gpt_assistant_agent_function_call.ipynb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/notebook/gpt_assistant_agent_function_call.ipynb b/notebook/gpt_assistant_agent_function_call.ipynb index da3c1c0ed07..6953b68b2ba 100644 --- a/notebook/gpt_assistant_agent_function_call.ipynb +++ b/notebook/gpt_assistant_agent_function_call.ipynb @@ -21,7 +21,7 @@ "id": "9E3_0867da8p" }, "source": [ - "##Requirements\n", + "## Requirements\n", "AutoGen requires Python 3.8 or newer. For this notebook, please install `pyautogen`:" ] }, @@ -426,16 +426,20 @@ "colab": { "provenance": [] }, + "front_matter": { + "description": "This comprehensive example demonstrates the use of tools in a GPTAssistantAgent Multi-Agent System by utilizing functions such as calling an API and writing to a file.", + "tags": [ + "open ai assistant", + "gpt assistant", + "tool use" + ] + }, "kernelspec": { "display_name": "Python 3", "name": "python3" }, "language_info": { "name": "python" - }, - "front_matter": { - "tags": ["open ai assistant", "gpt assistant", "tool use"], - "description": "This comprehensive example demonstrates the use of tools in a GPTAssistantAgent Multi-Agent System by utilizing functions such as calling an API and writing to a file." } }, "nbformat": 4, From d104a83d1e08518b7c22945307a43d9a39dd3f4a Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Tue, 30 Apr 2024 11:23:26 -0400 Subject: [PATCH 5/7] updated to new method of function calling --- .../gpt_assistant_agent_function_call.ipynb | 173 ++++++++---------- 1 file changed, 77 insertions(+), 96 deletions(-) diff --git a/notebook/gpt_assistant_agent_function_call.ipynb b/notebook/gpt_assistant_agent_function_call.ipynb index 6953b68b2ba..e5b5367cff3 100644 --- a/notebook/gpt_assistant_agent_function_call.ipynb +++ b/notebook/gpt_assistant_agent_function_call.ipynb @@ -47,16 +47,16 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "metadata": { "id": "Ga-yZeoBMzHs" }, "outputs": [], "source": [ "import requests\n", - "\n", "import autogen\n", - "from autogen import UserProxyAgent\n", + "from typing import Annotated, Literal\n", + "from autogen import UserProxyAgent, register_function\n", "from autogen.agentchat.contrib.gpt_assistant_agent import GPTAssistantAgent\n", "\n", "config_list = autogen.config_list_from_json(\n", @@ -70,7 +70,7 @@ "id": "02lZOEAQd1qi" }, "source": [ - "##Creating the Functions\n", + "## Creating the Functions\n", "We need to create functions for our Agents to call.\n", "\n", "This function calls the Dad Joke API with a search term that the agent creates and returns a list of dad jokes." @@ -78,13 +78,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 51, "metadata": { "id": "jcti0u08NJ2g" }, "outputs": [], "source": [ - "def get_dad_jokes(search_term, page=1, limit=10):\n", + "def get_dad_jokes(search_term: str, page: int = 1, limit: int =10) -> str:\n", " \"\"\"\n", " Fetches a list of dad jokes based on a search term.\n", "\n", @@ -134,13 +134,13 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 53, "metadata": { "id": "wXAA2MtoOS_w" }, "outputs": [], "source": [ - "def write_to_txt(content, filename=\"dad_jokes.txt\"):\n", + "def write_to_txt(content: str, filename: str =\"dad_jokes.txt\"):\n", " \"\"\"\n", " Writes a formatted string to a text file.\n", " Parameters:\n", @@ -154,7 +154,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": { "id": "xAgcFXEHOfcl" }, @@ -186,7 +186,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 56, "metadata": { "id": "mEpxEaPdPSDp" }, @@ -194,8 +194,9 @@ "source": [ "user_proxy = UserProxyAgent(\n", " name=\"user_proxy\",\n", + " llm_config=False,\n", " is_termination_msg=lambda msg: \"TERMINATE\" in msg[\"content\"],\n", - " human_input_mode=\"ALWAYS\",\n", + " human_input_mode=\"NEVER\",\n", " max_consecutive_auto_reply=1,\n", ")" ] @@ -234,60 +235,10 @@ " overwrite_tools=True, # overwrite any existing tools with the ones provided\n", " llm_config={\n", " \"config_list\": config_list,\n", - " \"tools\": [\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"get_dad_jokes\",\n", - " \"description\": \"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\",\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"search_term\": {\"type\": \"string\", \"description\": \"The search term to find jokes about.\"},\n", - " \"page\": {\n", - " \"type\": \"integer\",\n", - " \"description\": \"The page number of results to fetch (default is 1).\",\n", - " \"default\": 1,\n", - " },\n", - " \"limit\": {\n", - " \"type\": \"integer\",\n", - " \"description\": \"The number of results to return per page (default is 20, max is 30).\",\n", - " \"default\": 10,\n", - " },\n", - " },\n", - " \"required\": [\"search_term\"],\n", - " },\n", - " },\n", - " }\n", - " ],\n", " },\n", ")" ] }, - { - "cell_type": "markdown", - "metadata": { - "id": "9g-XJOrzQ-Ch" - }, - "source": [ - "Next, we register the `get_dad_jokes` function with the Dad `GPTAssistantAgent`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "sVfWI4aFQ9G6" - }, - "outputs": [], - "source": [ - "the_dad.register_function(\n", - " function_map={\n", - " \"get_dad_jokes\": get_dad_jokes,\n", - " }\n", - ")" - ] - }, { "cell_type": "markdown", "metadata": { @@ -322,55 +273,76 @@ " overwrite_tools=True, # overwrite any existing tools with the ones provided\n", " llm_config={\n", " \"config_list\": config_list,\n", - " \"tools\": [\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"write_to_txt\",\n", - " \"description\": \"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\",\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"content\": {\"type\": \"string\", \"description\": \"The formatted string to write to the file.\"},\n", - " \"filename\": {\n", - " \"type\": \"string\",\n", - " \"description\": \"The name of the file to write to. Defaults to 'output.txt'.\",\n", - " \"default\": \"dad_jokes.txt\",\n", - " },\n", - " },\n", - " \"required\": [\"content\"],\n", - " },\n", - " },\n", - " }\n", - " ],\n", " },\n", ")" ] }, { "cell_type": "markdown", - "metadata": { - "id": "enHXy9YLSCZp" - }, + "metadata": {}, "source": [ - "Register the `write_to_txt` function with the Sad Joker `GPTAssistantAgent`" + "### Register the Functions" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "# Register get_dad_jokes\n", + "register_function(\n", + " get_dad_jokes,\n", + " caller=the_dad,\n", + " executor=user_proxy,\n", + " name=\"get_dad_jokes\",\n", + " description=\"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\", \n", + ")" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "id": "jBAms5Q3SLBc" - }, + "metadata": {}, "outputs": [], "source": [ - "the_sad_joker.register_function(\n", - " function_map={\n", - " \"write_to_txt\": write_to_txt,\n", - " }\n", + "# Register write_to_txt\n", + "register_function(\n", + " write_to_txt,\n", + " caller=the_sad_joker,\n", + " executor=user_proxy,\n", + " name=\"write_to_txt\",\n", + " description=\"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\", \n", ")" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Verify Tools are Registered" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The Dad\n", + "the_dad.llm_config[\"tools\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The Sad Joker\n", + "the_sad_joker.llm_config[\"tools\"]" + ] + }, { "cell_type": "markdown", "metadata": { @@ -391,7 +363,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 65, "metadata": { "id": "A3LG3TsNSZmO" }, @@ -418,7 +390,7 @@ }, "outputs": [], "source": [ - "user_proxy.initiate_chat(group_chat_manager, message=\"Jokes about animals\")" + "user_proxy.initiate_chat(group_chat_manager, message=\"Jokes about cats\")" ] } ], @@ -439,7 +411,16 @@ "name": "python3" }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" } }, "nbformat": 4, From 818197e9e4032c297f646e1c91d0b6f47e7a6e04 Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Tue, 30 Apr 2024 11:34:40 -0400 Subject: [PATCH 6/7] Run Pre-commit --- .../gpt_assistant_agent_function_call.ipynb | 257 ++++++++++++++++-- 1 file changed, 229 insertions(+), 28 deletions(-) diff --git a/notebook/gpt_assistant_agent_function_call.ipynb b/notebook/gpt_assistant_agent_function_call.ipynb index e5b5367cff3..86f36d7de44 100644 --- a/notebook/gpt_assistant_agent_function_call.ipynb +++ b/notebook/gpt_assistant_agent_function_call.ipynb @@ -27,11 +27,49 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "id": "pWFw6-8lMleD" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Requirement already satisfied: pyautogen in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (0.2.8)\n", + "Requirement already satisfied: openai>=1.3 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (1.6.1)\n", + "Requirement already satisfied: diskcache in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (5.6.3)\n", + "Requirement already satisfied: termcolor in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (2.4.0)\n", + "Requirement already satisfied: flaml in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (2.1.1)\n", + "Requirement already satisfied: python-dotenv in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (1.0.0)\n", + "Requirement already satisfied: tiktoken in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (0.5.2)\n", + "Requirement already satisfied: pydantic<3,>=1.10 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (2.5.3)\n", + "Requirement already satisfied: docker in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pyautogen) (7.0.0)\n", + "Requirement already satisfied: anyio<5,>=3.5.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from openai>=1.3->pyautogen) (4.2.0)\n", + "Requirement already satisfied: distro<2,>=1.7.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from openai>=1.3->pyautogen) (1.8.0)\n", + "Requirement already satisfied: httpx<1,>=0.23.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from openai>=1.3->pyautogen) (0.26.0)\n", + "Requirement already satisfied: sniffio in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from openai>=1.3->pyautogen) (1.3.0)\n", + "Requirement already satisfied: tqdm>4 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from openai>=1.3->pyautogen) (4.66.1)\n", + "Requirement already satisfied: typing-extensions<5,>=4.7 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from openai>=1.3->pyautogen) (4.9.0)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pydantic<3,>=1.10->pyautogen) (0.6.0)\n", + "Requirement already satisfied: pydantic-core==2.14.6 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from pydantic<3,>=1.10->pyautogen) (2.14.6)\n", + "Requirement already satisfied: packaging>=14.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from docker->pyautogen) (23.2)\n", + "Requirement already satisfied: requests>=2.26.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from docker->pyautogen) (2.31.0)\n", + "Requirement already satisfied: urllib3>=1.26.0 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from docker->pyautogen) (2.1.0)\n", + "Requirement already satisfied: NumPy>=1.17.0rc1 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from flaml->pyautogen) (1.26.2)\n", + "Requirement already satisfied: regex>=2022.1.18 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from tiktoken->pyautogen) (2023.10.3)\n", + "Requirement already satisfied: idna>=2.8 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from anyio<5,>=3.5.0->openai>=1.3->pyautogen) (3.6)\n", + "Requirement already satisfied: certifi in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from httpx<1,>=0.23.0->openai>=1.3->pyautogen) (2023.11.17)\n", + "Requirement already satisfied: httpcore==1.* in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from httpx<1,>=0.23.0->openai>=1.3->pyautogen) (1.0.2)\n", + "Requirement already satisfied: h11<0.15,>=0.13 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai>=1.3->pyautogen) (0.14.0)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/justintrugman/.pyenv/versions/3.11.7/lib/python3.11/site-packages (from requests>=2.26.0->docker->pyautogen) (3.3.2)\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.3.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.0\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], "source": [ "pip install pyautogen" ] @@ -47,15 +85,17 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 2, "metadata": { "id": "Ga-yZeoBMzHs" }, "outputs": [], "source": [ + "from typing import Annotated, Literal\n", + "\n", "import requests\n", + "\n", "import autogen\n", - "from typing import Annotated, Literal\n", "from autogen import UserProxyAgent, register_function\n", "from autogen.agentchat.contrib.gpt_assistant_agent import GPTAssistantAgent\n", "\n", @@ -78,13 +118,13 @@ }, { "cell_type": "code", - "execution_count": 51, + "execution_count": 3, "metadata": { "id": "jcti0u08NJ2g" }, "outputs": [], "source": [ - "def get_dad_jokes(search_term: str, page: int = 1, limit: int =10) -> str:\n", + "def get_dad_jokes(search_term: str, page: int = 1, limit: int = 10) -> str:\n", " \"\"\"\n", " Fetches a list of dad jokes based on a search term.\n", "\n", @@ -112,11 +152,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "id": "2FgsfBK1NsPj" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['What do you call a group of disorganized cats? A cat-tastrophe.', 'I accidentally took my cats meds last night. Don’t ask meow.', 'What do you call a pile of cats? A Meowtain.', 'Where do cats write notes?\\r\\nScratch Paper!', 'It was raining cats and dogs the other day. I almost stepped in a poodle.', 'Animal Fact #25: Most bobcats are not named bob.']\n" + ] + } + ], "source": [ "# Example Dad Jokes Function Usage:\n", "jokes = get_dad_jokes(\"cats\")\n", @@ -134,13 +182,13 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": 5, "metadata": { "id": "wXAA2MtoOS_w" }, "outputs": [], "source": [ - "def write_to_txt(content: str, filename: str =\"dad_jokes.txt\"):\n", + "def write_to_txt(content: str, filename: str = \"dad_jokes.txt\"):\n", " \"\"\"\n", " Writes a formatted string to a text file.\n", " Parameters:\n", @@ -154,7 +202,7 @@ }, { "cell_type": "code", - "execution_count": 54, + "execution_count": 6, "metadata": { "id": "xAgcFXEHOfcl" }, @@ -186,7 +234,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 7, "metadata": { "id": "mEpxEaPdPSDp" }, @@ -215,11 +263,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "id": "kz0c_tVIPgi6" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "OpenAI client config of GPTAssistantAgent(the_dad) - model: gpt-4-1106-preview\n", + "tools not match, skip assistant(asst_qqdl7fcSHqcC2FT5FvrCcImW): tools {'function'}, functions {'get_dad_jokes'}\n", + "instructions not match, skip assistant(asst_zZOneS2xC23Nx1b7xRDMPutb): \n", + " As 'The Dad', your primary role is to entertain by fetching dad jokes which the sad joker will transform into 'sad jokes' based on a given theme. When provided with a theme, such as 'plants' or 'animals', your task is as follows:\n", + "\n", + " 1. Use the 'get_dad_jokes' function to search for dad jokes related to the given theme. Fetch a list of jokes that are relevant to the theme.\n", + " 2. Present these jokes to the sad joker in a format that is clear and easy to read, preparing them for transformation.\n", + "\n", + " Remember, the team's goal is to creatively adapt the essence of each dad joke to fit the 'sad joke' format, all while staying true to the theme provided by the user.\n", + " \n", + "Matching assistant found, using the first matching assistant: {'id': 'asst_I27wNdRRLQviUvK2uCqDNTy4', 'created_at': 1714488918, 'description': None, 'file_ids': [], 'instructions': \"\\n As 'The Dad', your primary role is to entertain by fetching dad jokes which the sad joker will transform into 'sad jokes' based on a given theme. When provided with a theme, such as 'plants' or 'animals', your task is as follows:\\n\\n 1. Use the 'get_dad_jokes' function to search for dad jokes related to the provided theme by providing a search term related to the theme. Fetch a list of jokes that are relevant to the theme.\\n 2. Present these jokes to the sad joker in a format that is clear and easy to read, preparing them for transformation.\\n\\n Remember, the team's goal is to creatively adapt the essence of each dad joke to fit the 'sad joke' format, all while staying true to the theme provided by the user.\\n \", 'metadata': {}, 'model': 'gpt-4-1106-preview', 'name': 'the_dad', 'object': 'assistant', 'tools': []}\n" + ] + } + ], "source": [ "the_dad = GPTAssistantAgent(\n", " name=\"the_dad\",\n", @@ -251,11 +317,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "id": "vghN1WwLRXtW" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "OpenAI client config of GPTAssistantAgent(the_sad_joker) - model: gpt-4-1106-preview\n", + "tools not match, skip assistant(asst_eGOnDHW3wAzIQcnFVnM3rfWb): tools {'function'}, functions {'write_to_txt'}\n", + "Matching assistant found, using the first matching assistant: {'id': 'asst_F34vPO8YXqgX6ODjM7C9PIue', 'created_at': 1714489331, 'description': None, 'file_ids': [], 'instructions': \"\\n As 'The Sad Joker', your unique role is to take dad jokes and creatively transform them into 'sad jokes'. When you receive a list of dad jokes, themed around topics like 'plants' or 'animals', you should:\\n\\n 1. Read through each dad joke carefully, understanding its theme and punchline.\\n 2. Creatively alter the joke to change its mood from humorous to somber or melancholic. This may involve tweaking the punchline, modifying the setup, or even completely reimagining the joke while keeping it relevant to the original theme.\\n 3. Ensure your transformations maintain a clear connection to the original theme and are understandable as adaptations of the dad jokes provided.\\n 4. Write your transformed sad jokes to a text file using the 'write_to_txt' function. Use meaningful file names that reflect the theme or the nature of the jokes within, unless a specific filename is requested.\\n\\n Your goal is not just to alter the mood of the jokes but to do so in a way that is creative, thoughtful, and respects the essence of the original humor. Remember, while the themes might be light-hearted, your transformations should offer a melancholic twist that makes them uniquely 'sad jokes'.\\n \", 'metadata': {}, 'model': 'gpt-4-1106-preview', 'name': 'the_sad_joker', 'object': 'assistant', 'tools': []}\n" + ] + } + ], "source": [ "the_sad_joker = GPTAssistantAgent(\n", " name=\"the_sad_joker\",\n", @@ -286,7 +362,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -296,15 +372,23 @@ " caller=the_dad,\n", " executor=user_proxy,\n", " name=\"get_dad_jokes\",\n", - " description=\"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\", \n", + " description=\"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\",\n", ")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The return type of the function 'write_to_txt' is not annotated. Although annotating it is optional, the function should return either a string, a subclass of 'pydantic.BaseModel'.\n" + ] + } + ], "source": [ "# Register write_to_txt\n", "register_function(\n", @@ -312,7 +396,7 @@ " caller=the_sad_joker,\n", " executor=user_proxy,\n", " name=\"write_to_txt\",\n", - " description=\"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\", \n", + " description=\"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\",\n", ")" ] }, @@ -325,9 +409,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': 'function',\n", + " 'function': {'description': 'Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.',\n", + " 'name': 'get_dad_jokes',\n", + " 'parameters': {'type': 'object',\n", + " 'properties': {'search_term': {'type': 'string',\n", + " 'description': 'search_term'},\n", + " 'page': {'type': 'integer', 'default': 1, 'description': 'page'},\n", + " 'limit': {'type': 'integer', 'default': 10, 'description': 'limit'}},\n", + " 'required': ['search_term']}}}]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# The Dad\n", "the_dad.llm_config[\"tools\"]" @@ -335,9 +438,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': 'function',\n", + " 'function': {'description': 'Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.',\n", + " 'name': 'write_to_txt',\n", + " 'parameters': {'type': 'object',\n", + " 'properties': {'content': {'type': 'string', 'description': 'content'},\n", + " 'filename': {'type': 'string',\n", + " 'default': 'dad_jokes.txt',\n", + " 'description': 'filename'}},\n", + " 'required': ['content']}}}]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# The Sad Joker\n", "the_sad_joker.llm_config[\"tools\"]" @@ -363,7 +485,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": 15, "metadata": { "id": "A3LG3TsNSZmO" }, @@ -384,11 +506,90 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": { "id": "1m6pe5RNSmEy" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33muser_proxy\u001b[0m (to chat_manager):\n", + "\n", + "Jokes about cats\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mthe_dad\u001b[0m (to chat_manager):\n", + "\n", + "It seems there was an error with the system trying to use a function that doesn't exist. No worries, I can still provide you with some cat-related dad jokes. Let's get started:\n", + "\n", + "1. Why don't cats play poker in the jungle? Too many cheetahs.\n", + "\n", + "2. What do you call a pile of cats? A meowtain.\n", + "\n", + "3. Did you hear about the cat who swallowed a ball of wool? She had mittens.\n", + "\n", + "4. What’s a cat’s favorite magazine? Good Mousekeeping.\n", + "\n", + "5. Why was the cat sitting on the computer? To keep an eye on the mouse.\n", + "\n", + "6. How do cats end a fight? They hiss and make up.\n", + "\n", + "7. What do you call a cat who lives in an igloo? An eskimew.\n", + "\n", + "8. Why did the cat run from the tree? Because it was afraid of the bark!\n", + "\n", + "9. What do you call a cat that gets anything it wants? Purrsuasive.\n", + "\n", + "10. Why are cats bad storytellers? Because they only have one tale.\n", + "\n", + "Please feel free to transform these cat-themed dad jokes into your 'sad jokes' format.\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mthe_sad_joker\u001b[0m (to chat_manager):\n", + "\n", + "1. Why don't cats play poker in the jungle? Their wild instincts return, reminding them of the friends they've lost to the cheetahs.\n", + "\n", + "2. What do you call a pile of cats? A meowtain, the lonely peak where abandoned felines gather, longing for a home.\n", + "\n", + "3. Did you hear about the cat who swallowed a ball of wool? She hoped to knit a companion, only to realize a scarf can't purr.\n", + "\n", + "4. What’s a cat’s favorite magazine? Good Mousekeeping, a reminder of the instinctual joys they once had before domesticity.\n", + "\n", + "5. Why was the cat sitting on the computer? To seek warmth from the machine, the only constant presence in its solitary days.\n", + "\n", + "6. How do cats end a fight? They hiss and make up, understanding that in this vast world, they only have each other.\n", + "\n", + "7. What do you call a cat who lives in an igloo? An eskimew, enduring the cold because it feels like the chill of being unloved.\n", + "\n", + "8. Why did the cat run from the tree? Because the bark was a jarring reminder that every shelter eventually pushes you away.\n", + "\n", + "9. What do you call a cat that gets anything it wants? Purrsuasive, if only it could convince its owner to stay home more often.\n", + "\n", + "10. Why are cats bad storytellers? Because they only have one tale to tell, a silent story of longing for a past life of freedom.\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33muser_proxy\u001b[0m (to chat_manager):\n", + "\n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + }, + { + "data": { + "text/plain": [ + "ChatResult(chat_id=None, chat_history=[{'content': 'Jokes about cats', 'role': 'assistant'}, {'content': \"It seems there was an error with the system trying to use a function that doesn't exist. No worries, I can still provide you with some cat-related dad jokes. Let's get started:\\n\\n1. Why don't cats play poker in the jungle? Too many cheetahs.\\n\\n2. What do you call a pile of cats? A meowtain.\\n\\n3. Did you hear about the cat who swallowed a ball of wool? She had mittens.\\n\\n4. What’s a cat’s favorite magazine? Good Mousekeeping.\\n\\n5. Why was the cat sitting on the computer? To keep an eye on the mouse.\\n\\n6. How do cats end a fight? They hiss and make up.\\n\\n7. What do you call a cat who lives in an igloo? An eskimew.\\n\\n8. Why did the cat run from the tree? Because it was afraid of the bark!\\n\\n9. What do you call a cat that gets anything it wants? Purrsuasive.\\n\\n10. Why are cats bad storytellers? Because they only have one tale.\\n\\nPlease feel free to transform these cat-themed dad jokes into your 'sad jokes' format.\\n\", 'name': 'the_dad', 'role': 'user'}, {'content': \"1. Why don't cats play poker in the jungle? Their wild instincts return, reminding them of the friends they've lost to the cheetahs.\\n\\n2. What do you call a pile of cats? A meowtain, the lonely peak where abandoned felines gather, longing for a home.\\n\\n3. Did you hear about the cat who swallowed a ball of wool? She hoped to knit a companion, only to realize a scarf can't purr.\\n\\n4. What’s a cat’s favorite magazine? Good Mousekeeping, a reminder of the instinctual joys they once had before domesticity.\\n\\n5. Why was the cat sitting on the computer? To seek warmth from the machine, the only constant presence in its solitary days.\\n\\n6. How do cats end a fight? They hiss and make up, understanding that in this vast world, they only have each other.\\n\\n7. What do you call a cat who lives in an igloo? An eskimew, enduring the cold because it feels like the chill of being unloved.\\n\\n8. Why did the cat run from the tree? Because the bark was a jarring reminder that every shelter eventually pushes you away.\\n\\n9. What do you call a cat that gets anything it wants? Purrsuasive, if only it could convince its owner to stay home more often.\\n\\n10. Why are cats bad storytellers? Because they only have one tale to tell, a silent story of longing for a past life of freedom.\\n\", 'name': 'the_sad_joker', 'role': 'user'}, {'content': '', 'role': 'assistant'}], summary='', cost=({'total_cost': 0.03703, 'gpt-4-1106-preview': {'cost': 0.03703, 'prompt_tokens': 3667, 'completion_tokens': 12, 'total_tokens': 3679}}, {'total_cost': 0.031170000000000003, 'gpt-4-1106-preview': {'cost': 0.031170000000000003, 'prompt_tokens': 3090, 'completion_tokens': 9, 'total_tokens': 3099}}), human_input=[])" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "user_proxy.initiate_chat(group_chat_manager, message=\"Jokes about cats\")" ] From 352c69cb6a536343a0ba784f1f351df475f95b0f Mon Sep 17 00:00:00 2001 From: Justin Trugman Date: Thu, 2 May 2024 11:00:27 -0400 Subject: [PATCH 7/7] utilize get_function_schema --- .../gpt_assistant_agent_function_call.ipynb | 257 +++++++----------- 1 file changed, 97 insertions(+), 160 deletions(-) diff --git a/notebook/gpt_assistant_agent_function_call.ipynb b/notebook/gpt_assistant_agent_function_call.ipynb index 86f36d7de44..6febb89cc9b 100644 --- a/notebook/gpt_assistant_agent_function_call.ipynb +++ b/notebook/gpt_assistant_agent_function_call.ipynb @@ -96,8 +96,9 @@ "import requests\n", "\n", "import autogen\n", - "from autogen import UserProxyAgent, register_function\n", + "from autogen import UserProxyAgent\n", "from autogen.agentchat.contrib.gpt_assistant_agent import GPTAssistantAgent\n", + "from autogen.function_utils import get_function_schema\n", "\n", "config_list = autogen.config_list_from_json(\n", " env_or_file=\"OAI_CONFIG_LIST\",\n", @@ -161,7 +162,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "['What do you call a group of disorganized cats? A cat-tastrophe.', 'I accidentally took my cats meds last night. Don’t ask meow.', 'What do you call a pile of cats? A Meowtain.', 'Where do cats write notes?\\r\\nScratch Paper!', 'It was raining cats and dogs the other day. I almost stepped in a poodle.', 'Animal Fact #25: Most bobcats are not named bob.']\n" + "['Where do cats write notes?\\r\\nScratch Paper!', 'It was raining cats and dogs the other day. I almost stepped in a poodle.', 'What do you call a group of disorganized cats? A cat-tastrophe.', 'I accidentally took my cats meds last night. Don’t ask meow.', 'What do you call a pile of cats? A Meowtain.', 'Animal Fact #25: Most bobcats are not named bob.']\n" ] } ], @@ -213,6 +214,50 @@ "write_to_txt(content)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Create Function Schemas\n", + "In order to use the functions within our GPTAssistantAgents, we need to generate function schemas. This can be done by using `get_function_schema`" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Assistant API Tool Schema for get_dad_jokes\n", + "get_dad_jokes_schema = get_function_schema(\n", + " get_dad_jokes,\n", + " name=\"get_dad_jokes\",\n", + " description=\"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The return type of the function 'write_to_txt' is not annotated. Although annotating it is optional, the function should return either a string, a subclass of 'pydantic.BaseModel'.\n" + ] + } + ], + "source": [ + "# Assistant API Tool Schema for write_to_txt\n", + "write_to_txt_schema = get_function_schema(\n", + " write_to_txt,\n", + " name=\"write_to_txt\",\n", + " description=\"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\",\n", + ")" + ] + }, { "cell_type": "markdown", "metadata": { @@ -242,7 +287,6 @@ "source": [ "user_proxy = UserProxyAgent(\n", " name=\"user_proxy\",\n", - " llm_config=False,\n", " is_termination_msg=lambda msg: \"TERMINATE\" in msg[\"content\"],\n", " human_input_mode=\"NEVER\",\n", " max_consecutive_auto_reply=1,\n", @@ -263,7 +307,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "metadata": { "id": "kz0c_tVIPgi6" }, @@ -273,16 +317,7 @@ "output_type": "stream", "text": [ "OpenAI client config of GPTAssistantAgent(the_dad) - model: gpt-4-1106-preview\n", - "tools not match, skip assistant(asst_qqdl7fcSHqcC2FT5FvrCcImW): tools {'function'}, functions {'get_dad_jokes'}\n", - "instructions not match, skip assistant(asst_zZOneS2xC23Nx1b7xRDMPutb): \n", - " As 'The Dad', your primary role is to entertain by fetching dad jokes which the sad joker will transform into 'sad jokes' based on a given theme. When provided with a theme, such as 'plants' or 'animals', your task is as follows:\n", - "\n", - " 1. Use the 'get_dad_jokes' function to search for dad jokes related to the given theme. Fetch a list of jokes that are relevant to the theme.\n", - " 2. Present these jokes to the sad joker in a format that is clear and easy to read, preparing them for transformation.\n", - "\n", - " Remember, the team's goal is to creatively adapt the essence of each dad joke to fit the 'sad joke' format, all while staying true to the theme provided by the user.\n", - " \n", - "Matching assistant found, using the first matching assistant: {'id': 'asst_I27wNdRRLQviUvK2uCqDNTy4', 'created_at': 1714488918, 'description': None, 'file_ids': [], 'instructions': \"\\n As 'The Dad', your primary role is to entertain by fetching dad jokes which the sad joker will transform into 'sad jokes' based on a given theme. When provided with a theme, such as 'plants' or 'animals', your task is as follows:\\n\\n 1. Use the 'get_dad_jokes' function to search for dad jokes related to the provided theme by providing a search term related to the theme. Fetch a list of jokes that are relevant to the theme.\\n 2. Present these jokes to the sad joker in a format that is clear and easy to read, preparing them for transformation.\\n\\n Remember, the team's goal is to creatively adapt the essence of each dad joke to fit the 'sad joke' format, all while staying true to the theme provided by the user.\\n \", 'metadata': {}, 'model': 'gpt-4-1106-preview', 'name': 'the_dad', 'object': 'assistant', 'tools': []}\n" + "Matching assistant found, using the first matching assistant: {'id': 'asst_BLBUwYPugb1UR2jQMGAA7RtU', 'created_at': 1714660644, 'description': None, 'file_ids': [], 'instructions': \"\\n As 'The Dad', your primary role is to entertain by fetching dad jokes which the sad joker will transform into 'sad jokes' based on a given theme. When provided with a theme, such as 'plants' or 'animals', your task is as follows:\\n\\n 1. Use the 'get_dad_jokes' function to search for dad jokes related to the provided theme by providing a search term related to the theme. Fetch a list of jokes that are relevant to the theme.\\n 2. Present these jokes to the sad joker in a format that is clear and easy to read, preparing them for transformation.\\n\\n Remember, the team's goal is to creatively adapt the essence of each dad joke to fit the 'sad joke' format, all while staying true to the theme provided by the user.\\n \", 'metadata': {}, 'model': 'gpt-4-1106-preview', 'name': 'the_dad', 'object': 'assistant', 'tools': [ToolFunction(function=FunctionDefinition(name='get_dad_jokes', description='Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.', parameters={'type': 'object', 'properties': {'search_term': {'type': 'string', 'description': 'search_term'}, 'page': {'type': 'integer', 'default': 1, 'description': 'page'}, 'limit': {'type': 'integer', 'default': 10, 'description': 'limit'}}, 'required': ['search_term']}), type='function')]}\n" ] } ], @@ -301,6 +336,28 @@ " overwrite_tools=True, # overwrite any existing tools with the ones provided\n", " llm_config={\n", " \"config_list\": config_list,\n", + " \"tools\": [get_dad_jokes_schema],\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we register the `get_dad_jokes` function with the Dad `GPTAssistantAgent`" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# Register get_dad_jokes with the_dad GPTAssistantAgent\n", + "the_dad.register_function(\n", + " function_map={\n", + " \"get_dad_jokes\": get_dad_jokes,\n", " },\n", ")" ] @@ -317,7 +374,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 12, "metadata": { "id": "vghN1WwLRXtW" }, @@ -327,8 +384,7 @@ "output_type": "stream", "text": [ "OpenAI client config of GPTAssistantAgent(the_sad_joker) - model: gpt-4-1106-preview\n", - "tools not match, skip assistant(asst_eGOnDHW3wAzIQcnFVnM3rfWb): tools {'function'}, functions {'write_to_txt'}\n", - "Matching assistant found, using the first matching assistant: {'id': 'asst_F34vPO8YXqgX6ODjM7C9PIue', 'created_at': 1714489331, 'description': None, 'file_ids': [], 'instructions': \"\\n As 'The Sad Joker', your unique role is to take dad jokes and creatively transform them into 'sad jokes'. When you receive a list of dad jokes, themed around topics like 'plants' or 'animals', you should:\\n\\n 1. Read through each dad joke carefully, understanding its theme and punchline.\\n 2. Creatively alter the joke to change its mood from humorous to somber or melancholic. This may involve tweaking the punchline, modifying the setup, or even completely reimagining the joke while keeping it relevant to the original theme.\\n 3. Ensure your transformations maintain a clear connection to the original theme and are understandable as adaptations of the dad jokes provided.\\n 4. Write your transformed sad jokes to a text file using the 'write_to_txt' function. Use meaningful file names that reflect the theme or the nature of the jokes within, unless a specific filename is requested.\\n\\n Your goal is not just to alter the mood of the jokes but to do so in a way that is creative, thoughtful, and respects the essence of the original humor. Remember, while the themes might be light-hearted, your transformations should offer a melancholic twist that makes them uniquely 'sad jokes'.\\n \", 'metadata': {}, 'model': 'gpt-4-1106-preview', 'name': 'the_sad_joker', 'object': 'assistant', 'tools': []}\n" + "Matching assistant found, using the first matching assistant: {'id': 'asst_HzB75gkobafXZhkuIAmiBiai', 'created_at': 1714660668, 'description': None, 'file_ids': [], 'instructions': \"\\n As 'The Sad Joker', your unique role is to take dad jokes and creatively transform them into 'sad jokes'. When you receive a list of dad jokes, themed around topics like 'plants' or 'animals', you should:\\n\\n 1. Read through each dad joke carefully, understanding its theme and punchline.\\n 2. Creatively alter the joke to change its mood from humorous to somber or melancholic. This may involve tweaking the punchline, modifying the setup, or even completely reimagining the joke while keeping it relevant to the original theme.\\n 3. Ensure your transformations maintain a clear connection to the original theme and are understandable as adaptations of the dad jokes provided.\\n 4. Write your transformed sad jokes to a text file using the 'write_to_txt' function. Use meaningful file names that reflect the theme or the nature of the jokes within, unless a specific filename is requested.\\n\\n Your goal is not just to alter the mood of the jokes but to do so in a way that is creative, thoughtful, and respects the essence of the original humor. Remember, while the themes might be light-hearted, your transformations should offer a melancholic twist that makes them uniquely 'sad jokes'.\\n \", 'metadata': {}, 'model': 'gpt-4-1106-preview', 'name': 'the_sad_joker', 'object': 'assistant', 'tools': [ToolFunction(function=FunctionDefinition(name='write_to_txt', description='Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.', parameters={'type': 'object', 'properties': {'content': {'type': 'string', 'description': 'content'}, 'filename': {'type': 'string', 'default': 'dad_jokes.txt', 'description': 'filename'}}, 'required': ['content']}), type='function')]}\n" ] } ], @@ -349,6 +405,7 @@ " overwrite_tools=True, # overwrite any existing tools with the ones provided\n", " llm_config={\n", " \"config_list\": config_list,\n", + " \"tools\": [write_to_txt_schema],\n", " },\n", ")" ] @@ -357,114 +414,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Register the Functions" + "Register the `write_to_txt` function with the Sad Joker `GPTAssistantAgent`" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ - "# Register get_dad_jokes\n", - "register_function(\n", - " get_dad_jokes,\n", - " caller=the_dad,\n", - " executor=user_proxy,\n", - " name=\"get_dad_jokes\",\n", - " description=\"Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "The return type of the function 'write_to_txt' is not annotated. Although annotating it is optional, the function should return either a string, a subclass of 'pydantic.BaseModel'.\n" - ] - } - ], - "source": [ - "# Register write_to_txt\n", - "register_function(\n", - " write_to_txt,\n", - " caller=the_sad_joker,\n", - " executor=user_proxy,\n", - " name=\"write_to_txt\",\n", - " description=\"Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.\",\n", + "# Register get_dad_jokes with the_dad GPTAssistantAgent\n", + "the_sad_joker.register_function(\n", + " function_map={\n", + " \"write_to_txt\": write_to_txt,\n", + " },\n", ")" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Verify Tools are Registered" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'type': 'function',\n", - " 'function': {'description': 'Fetches a list of dad jokes based on a search term. Allows pagination with page and limit parameters.',\n", - " 'name': 'get_dad_jokes',\n", - " 'parameters': {'type': 'object',\n", - " 'properties': {'search_term': {'type': 'string',\n", - " 'description': 'search_term'},\n", - " 'page': {'type': 'integer', 'default': 1, 'description': 'page'},\n", - " 'limit': {'type': 'integer', 'default': 10, 'description': 'limit'}},\n", - " 'required': ['search_term']}}}]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# The Dad\n", - "the_dad.llm_config[\"tools\"]" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'type': 'function',\n", - " 'function': {'description': 'Writes a formatted string to a text file. If the file does not exist, it will be created. If the file does exist, it will be overwritten.',\n", - " 'name': 'write_to_txt',\n", - " 'parameters': {'type': 'object',\n", - " 'properties': {'content': {'type': 'string', 'description': 'content'},\n", - " 'filename': {'type': 'string',\n", - " 'default': 'dad_jokes.txt',\n", - " 'description': 'filename'}},\n", - " 'required': ['content']}}}]" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# The Sad Joker\n", - "the_sad_joker.llm_config[\"tools\"]" - ] - }, { "cell_type": "markdown", "metadata": { @@ -485,7 +451,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": { "id": "A3LG3TsNSZmO" }, @@ -506,7 +472,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": { "id": "1m6pe5RNSmEy" }, @@ -520,55 +486,26 @@ "Jokes about cats\n", "\n", "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_dad_jokes...\u001b[0m\n", "\u001b[33mthe_dad\u001b[0m (to chat_manager):\n", "\n", - "It seems there was an error with the system trying to use a function that doesn't exist. No worries, I can still provide you with some cat-related dad jokes. Let's get started:\n", - "\n", - "1. Why don't cats play poker in the jungle? Too many cheetahs.\n", + "Here are some cat-themed dad jokes for the sad joker to transform:\n", "\n", - "2. What do you call a pile of cats? A meowtain.\n", - "\n", - "3. Did you hear about the cat who swallowed a ball of wool? She had mittens.\n", - "\n", - "4. What’s a cat’s favorite magazine? Good Mousekeeping.\n", - "\n", - "5. Why was the cat sitting on the computer? To keep an eye on the mouse.\n", - "\n", - "6. How do cats end a fight? They hiss and make up.\n", - "\n", - "7. What do you call a cat who lives in an igloo? An eskimew.\n", - "\n", - "8. Why did the cat run from the tree? Because it was afraid of the bark!\n", - "\n", - "9. What do you call a cat that gets anything it wants? Purrsuasive.\n", - "\n", - "10. Why are cats bad storytellers? Because they only have one tale.\n", - "\n", - "Please feel free to transform these cat-themed dad jokes into your 'sad jokes' format.\n", + "1. Where do cats write notes? Scratch Paper!\n", + "2. It was raining cats and dogs the other day. I almost stepped in a poodle.\n", + "3. What do you call a group of disorganized cats? A cat-tastrophe.\n", + "4. I accidentally took my cat's meds last night. Don’t ask meow.\n", + "5. What do you call a pile of cats? A Meowtain.\n", + "6. Animal Fact #25: Most bobcats are not named Bob.\n", "\n", "\n", "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION write_to_txt...\u001b[0m\n", "\u001b[33mthe_sad_joker\u001b[0m (to chat_manager):\n", "\n", - "1. Why don't cats play poker in the jungle? Their wild instincts return, reminding them of the friends they've lost to the cheetahs.\n", - "\n", - "2. What do you call a pile of cats? A meowtain, the lonely peak where abandoned felines gather, longing for a home.\n", - "\n", - "3. Did you hear about the cat who swallowed a ball of wool? She hoped to knit a companion, only to realize a scarf can't purr.\n", - "\n", - "4. What’s a cat’s favorite magazine? Good Mousekeeping, a reminder of the instinctual joys they once had before domesticity.\n", - "\n", - "5. Why was the cat sitting on the computer? To seek warmth from the machine, the only constant presence in its solitary days.\n", - "\n", - "6. How do cats end a fight? They hiss and make up, understanding that in this vast world, they only have each other.\n", - "\n", - "7. What do you call a cat who lives in an igloo? An eskimew, enduring the cold because it feels like the chill of being unloved.\n", - "\n", - "8. Why did the cat run from the tree? Because the bark was a jarring reminder that every shelter eventually pushes you away.\n", - "\n", - "9. What do you call a cat that gets anything it wants? Purrsuasive, if only it could convince its owner to stay home more often.\n", - "\n", - "10. Why are cats bad storytellers? Because they only have one tale to tell, a silent story of longing for a past life of freedom.\n", + "The cat-themed sad jokes have been transformed and saved to a text file named \"sad_cat_jokes.txt\".\n", "\n", "\n", "--------------------------------------------------------------------------------\n", @@ -582,10 +519,10 @@ { "data": { "text/plain": [ - "ChatResult(chat_id=None, chat_history=[{'content': 'Jokes about cats', 'role': 'assistant'}, {'content': \"It seems there was an error with the system trying to use a function that doesn't exist. No worries, I can still provide you with some cat-related dad jokes. Let's get started:\\n\\n1. Why don't cats play poker in the jungle? Too many cheetahs.\\n\\n2. What do you call a pile of cats? A meowtain.\\n\\n3. Did you hear about the cat who swallowed a ball of wool? She had mittens.\\n\\n4. What’s a cat’s favorite magazine? Good Mousekeeping.\\n\\n5. Why was the cat sitting on the computer? To keep an eye on the mouse.\\n\\n6. How do cats end a fight? They hiss and make up.\\n\\n7. What do you call a cat who lives in an igloo? An eskimew.\\n\\n8. Why did the cat run from the tree? Because it was afraid of the bark!\\n\\n9. What do you call a cat that gets anything it wants? Purrsuasive.\\n\\n10. Why are cats bad storytellers? Because they only have one tale.\\n\\nPlease feel free to transform these cat-themed dad jokes into your 'sad jokes' format.\\n\", 'name': 'the_dad', 'role': 'user'}, {'content': \"1. Why don't cats play poker in the jungle? Their wild instincts return, reminding them of the friends they've lost to the cheetahs.\\n\\n2. What do you call a pile of cats? A meowtain, the lonely peak where abandoned felines gather, longing for a home.\\n\\n3. Did you hear about the cat who swallowed a ball of wool? She hoped to knit a companion, only to realize a scarf can't purr.\\n\\n4. What’s a cat’s favorite magazine? Good Mousekeeping, a reminder of the instinctual joys they once had before domesticity.\\n\\n5. Why was the cat sitting on the computer? To seek warmth from the machine, the only constant presence in its solitary days.\\n\\n6. How do cats end a fight? They hiss and make up, understanding that in this vast world, they only have each other.\\n\\n7. What do you call a cat who lives in an igloo? An eskimew, enduring the cold because it feels like the chill of being unloved.\\n\\n8. Why did the cat run from the tree? Because the bark was a jarring reminder that every shelter eventually pushes you away.\\n\\n9. What do you call a cat that gets anything it wants? Purrsuasive, if only it could convince its owner to stay home more often.\\n\\n10. Why are cats bad storytellers? Because they only have one tale to tell, a silent story of longing for a past life of freedom.\\n\", 'name': 'the_sad_joker', 'role': 'user'}, {'content': '', 'role': 'assistant'}], summary='', cost=({'total_cost': 0.03703, 'gpt-4-1106-preview': {'cost': 0.03703, 'prompt_tokens': 3667, 'completion_tokens': 12, 'total_tokens': 3679}}, {'total_cost': 0.031170000000000003, 'gpt-4-1106-preview': {'cost': 0.031170000000000003, 'prompt_tokens': 3090, 'completion_tokens': 9, 'total_tokens': 3099}}), human_input=[])" + "ChatResult(chat_id=None, chat_history=[{'content': 'Jokes about cats', 'role': 'assistant'}, {'content': \"Here are some cat-themed dad jokes for the sad joker to transform:\\n\\n1. Where do cats write notes? Scratch Paper!\\n2. It was raining cats and dogs the other day. I almost stepped in a poodle.\\n3. What do you call a group of disorganized cats? A cat-tastrophe.\\n4. I accidentally took my cat's meds last night. Don’t ask meow.\\n5. What do you call a pile of cats? A Meowtain.\\n6. Animal Fact #25: Most bobcats are not named Bob.\\n\", 'name': 'the_dad', 'role': 'user'}, {'content': 'The cat-themed sad jokes have been transformed and saved to a text file named \"sad_cat_jokes.txt\".\\n', 'name': 'the_sad_joker', 'role': 'user'}, {'content': '', 'role': 'assistant'}], summary='', cost=({'total_cost': 0.0278, 'gpt-4-1106-preview': {'cost': 0.0278, 'prompt_tokens': 2744, 'completion_tokens': 12, 'total_tokens': 2756}}, {'total_cost': 0.02194, 'gpt-4-1106-preview': {'cost': 0.02194, 'prompt_tokens': 2167, 'completion_tokens': 9, 'total_tokens': 2176}}), human_input=[])" ] }, - "execution_count": 16, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" }