{"id":13456036,"url":"https://github.com/anthropics/anthropic-tools","last_synced_at":"2025-05-15T20:00:42.242Z","repository":{"id":212366958,"uuid":"701080081","full_name":"anthropics/anthropic-tools","owner":"anthropics","description":null,"archived":false,"fork":false,"pushed_at":"2024-11-04T23:34:50.000Z","size":1991,"stargazers_count":299,"open_issues_count":13,"forks_count":34,"subscribers_count":76,"default_branch":"main","last_synced_at":"2025-05-13T13:59:05.794Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/anthropics.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-05T21:52:17.000Z","updated_at":"2025-04-26T22:57:28.000Z","dependencies_parsed_at":"2023-12-27T05:33:28.783Z","dependency_job_id":"7e4d9617-0d79-424c-a892-f112b33449f2","html_url":"https://github.com/anthropics/anthropic-tools","commit_stats":{"total_commits":68,"total_committers":5,"mean_commits":13.6,"dds":0.4558823529411765,"last_synced_commit":"795f706ddaabd2dc71f6c6d47ba087e7df03205a"},"previous_names":["anthropics/anthropic-tools"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthropics%2Fanthropic-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthropics%2Fanthropic-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthropics%2Fanthropic-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/anthropics%2Fanthropic-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/anthropics","download_url":"https://codeload.github.com/anthropics/anthropic-tools/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253958076,"owners_count":21990548,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T08:01:15.238Z","updated_at":"2025-05-15T20:00:41.824Z","avatar_url":"https://github.com/anthropics.png","language":"Python","funding_links":[],"categories":["Frameworks \u0026 Libraries","📦 Legacy \u0026 Inactive Projects","Python"],"sub_categories":["Browser Agents"],"readme":"\u003e **⚠️ DEPRECATION NOTICE**\n\u003e\n\u003e This repository is deprecated and no longer maintained. For up-to-date information on using tools with Claude, please refer to our official documentation at:\n\u003e https://docs.anthropic.com/en/docs/build-with-claude/tool-use\n\u003e\n\u003e The official API provides a more robust, supported, and production-ready implementation of tool use functionality.\n\n# anthropic-tools\nA repo for using tools/function calling with Anthropic models.\n### This SDK is Currently in Alpha and meant ONLY AS A RESEARCH PREVIEW. We promise no ongoing support. It is not intended for production use. Production-ready function calling support is coming to the Anthropic API soon.\n\n## Setup\nSet your Anthropic API key as an environment variable:  \n```bash\n# MacOS\nexport ANTHROPIC_API_KEY={your_anthropic_api_key}\n```\n\nIf you are accessing Claude through AWS Bedrock, set the following enviroment variables instead:\n```bash\n# MacOS\nexport AWS_ACCESS_KEY_ID={your_AWS_access_key_id}\nexport AWS_SECRET_ACCESS_KEY={your_AWS_secret_access_key}\nexport AWS_SESSION_TOKEN={your_AWS_session_token}\n```\n\n[Optional] If you want to test the Brave search tool, set your Brave API key as an enviroment variable (get a key [here](https://api.search.brave.com/register)):\n```bash\n# MacOS\nexport BRAVE_API_KEY={your_brave_api_key}\n```\n\nCreate a Python Virtual Environment:  \n```bash\n# MacOS\npython3 -m venv anthropictools\nsource anthropictools/bin/activate\n```\n\nInstall Requirements:\n```bash\npip install -r requirements.txt\n```\n\n## Getting Started\nanthropic-tools follows a very simple architecture that lets users define and use tools with Claude. There are two classes users should be familiar with: `BaseTool` and `ToolUser`.\n\nAdditionally, anthropic-tools introduces a new *structured* prompt format that you will want to pay close attention to. This should make for easier prompt construction and parsing.\n\nanthropic-tools also supports a number of pre-built tools out of the box, built on top of the same primitives available to you. These are here in case you want even easier tool use for some of our most common tools, such as search or SQL.\n\n### BaseTool\nBaseTool is the class that should be used to define individual tools. All you need to do to create a tool is inherit `BaseTool` and define the `use_tool()` method for the tool.\n```python\nimport datetime, zoneinfo\nfrom tool_use_package.tools.base_tool import BaseTool\n\nclass TimeOfDayTool(BaseTool):\n    \"\"\"Tool to get the current time of day.\"\"\"\n    def use_tool(self, time_zone):\n        # Get the current time\n        now = datetime.datetime.now()\n\n        # Convert to the specified time zone\n        tz = zoneinfo.ZoneInfo(time_zone)\n        localized_time = now.astimezone(tz)\n\n        return localized_time.strftime(\"%H:%M:%S\")\n```\n\nThen, you simply instantiate your custom tool with `name` (the name of the tool), `description` (the description Claude reads of what the tool does), and `parameters` (the parameters that the tool accepts). Pay attention to the formatting of each.\n```python\ntool_name = \"get_time_of_day\"\ntool_description = \"Retrieve the current time of day in Hour-Minute-Second format for a specified time zone. Time zones should be written in standard formats such as UTC, US/Pacific, Europe/London.\"\ntool_parameters = [\n    {\"name\": \"time_zone\", \"type\": \"str\", \"description\": \"The time zone to get the current time for, such as UTC, US/Pacific, Europe/London.\"}\n]\n\ntime_of_day_tool = TimeOfDayTool(tool_name, tool_description, tool_parameters)\n```\n### ToolUser\nToolUser is passed a list of tools (child classes of BaseTool) and allows you to use Claude with those tools. To create a ToolUser instance simply pass it a list of one or more tools.\n```python\nfrom tool_use_package.tool_user import ToolUser\ntime_tool_user = ToolUser([time_of_day_tool])\n```\n\nYou can then make use of your ToolUser by calling its `use_tools()` method and passing in your desired prompt. Setting execution mode to \"automatic\" makes it execute the function; in the default \"manual\" mode it returns the function arguments back to the client to be executed there.\n```python\nmessages = [{'role': 'user', 'content': 'What time is it in Los Angeles?'}]\ntime_tool_user.use_tools(messages, execution_mode='automatic')\n```\n\nIf you are accesing Claude through AWS Bedrock, set the parameter `first_party` to `False` (it is by default set to `True`):\n```python\ntime_tool_user = ToolUser([time_of_day_tool], first_party=False)\n```\nNOTE: If using bedrock, this SDK only supports claude 2.1 (anthropic.claude-v2:1).\n\nNotice that new `messages` format instead of passing in a simple prompt string? Never seen it before? Don't worry, we are about to walk through it.\n\n### Prompt Format\nAnthropic-tools uses a *structured* prompt input and output format, coming as a list of messages, intending to mimic our Messages API format. Let's take a quick tour of how to work with this list.\n\n`messages` is a python list of message dictionaries. A single message dictionary object can contain these fields but will never contain all of them (see the field comments below for more detail on what this means):\n```python\n{\n    \"role\": str, # The role of the message. 'user' for a message from the user, 'assistant' for a message from the assistant, 'tool_inputs' for a request from the assistant to use tools, 'tool_outputs' for a response to a tool_inputs message containing the results of using the specified tools in the specified ways.\n    \"content\": str, # The (non tool use) content of the message, which must be present for messages where role=(user, assistant, tool_inputs) and can not be present for messages where role=tool_outputs.\n    \"tool_inputs\": list[dict], # A list of dictionaries (see below). Must be specified in messages where role=tool_inputs.\n    \"tool_outputs\": list[dict], # A list of tool_output dictionaries (see below). One of tool_outputs or tool_error must be specified in messages where role=tool_outputs, but the other must be specified as None.\n    \"tool_error\": str # A tool error message corresponding to the first tool that errored to help Claude understand what it did wrong. One of tool_error or tool_outputs must be specified when role=tool_outputs, but the other must be specified as None.\n}\n```\n\n`tool_inputs` is a list of dictionaries, where each dictionary represents a tool to use (at the 'tool_name' key), and the arguments to pass to that tool (at the 'tool_arguments' key). A tool_inputs message might look something like this:\n```python\n{\n    'role': 'tool_inputs',\n    'content': '',\n    'tool_inputs': [\n        {\n            'tool_name': 'perform_addition',\n            'tool_arguments': {'a': 9, 'b': 1}\n        },\n        {\n            'tool_name': 'perform_subtraction',\n            'tool_arguments': {'a': 6, 'b': 4}\n        }\n    ]\n}\n```\nNotice above that `tool_inputs` messages also have `content` attached to them, which can be the empty string but can also be content from the assistant that precedes the tool use request. These messages are rendered to Claude in the order `{content}{tool_inputs}`\n\nThe format of `tool_name` and `tool_arguments` is such that you can easily get results for the desired tool use by running the following code:\n```python\ntool = next((t for t in your_ToolUser_instance.tools if t.name == tool_name), None) # replace your_ToolUser_instance with your ToolUser instance\nif tool is None:\n    return \"No tool named \u003ctool_name\u003e{tool_name}\u003c/tool_name\u003e available.\"\n\nreturn tool.use_tool(**tool_arguments)\n```\n\u003e NOTE: While we have attempted to validate tool_arguments before returning them to you, you may still want to do some additional checks of tool_arguments before executing the function to check for things like malicious or invalid parameters. You can also do this inside of your use_tools method.\n\n`tool_outputs` is also a list of dictionaries, where each dictionary represents the result of using the tool at the 'tool_name' key. The result is included at the 'tool_result' key. If we were responding to our above `tool_inputs` example, it might look something like this:\n```python\n{\n    'role': 'tool_outputs',\n    'tool_outputs': [ \n        {\n            \"tool_name\": 'perform_addition',\n            'tool_result': 10\n        },\n        {\n            \"tool_name\": 'perform_subtraction',\n            'tool_result': 2\n        }\n    ],\n    'tool_error': None\n}\n```\n\u003e NOTE: It is highly recommended, but not required, that you provide tool_outputs *only for requested tool_inputs*, and that you provide them *in the same order as the tool_inputs*.  \n\u003e SECOND NOTE: Notice that `tool_outputs` messages do not have `content`. Trying to pass in content with a `tool_outputs` message will return an error.\n\nSometimes when Claude responds with a `tool_inputs` message it makes a mistake and either requests tools that do not exist or does not provide a valid set of parameters. While we try to catch this for you, it sometimes slips through the cracks. If any of Claude's `tool_inputs` are invalid you should stop parsing and send Claude back a message with a descriptive `tool_error` *instead of sending it `tool_outputs`*. Here is what a response message to an invalid `tool_inputs` message might look like.\n```python\n{\n    'role': 'tool_outputs',\n    'tool_outputs': None,\n    'tool_error': 'Missing required parameter \"b\" in tool perform_addition.'\n}\n```\n\nSo, what might `messages` look like in practice?  \nHere is a user message:\n```python\nuser_message = {'role': 'user', 'content': 'Hi Claude, what US states start with C?'}\nmessages = [user_message]\n```\nHere is a user message and an assistant response, with no tool use involved.\n```python\nuser_message = {'role': 'humuseran', 'content': 'Hi Claude, what US states start with C?'}\nassistant_message = {'role': 'assistant', 'content': 'California, Colorado, and Connecticut are the US states that start with the letter C.'}\nmessages = [user_message, assistant_message]\n```\n\nHere is a user message, followed by a tool_inputs message, followed by a successful tool_outputs message:\n```python\nuser_message = {'role': 'user', 'content': 'If Maggie has 3 apples and eats 1, how many apples does maggie have left?'}\ntool_inputs_message = {\n    'role': 'tool_inputs',\n    'content': \"Let's think this through. Maggie had 3 apples, she ate one so:\",\n    'tool_inputs': [{'tool_name': 'perform_subtraction', 'tool_arguments': {'a': 3, 'b': 1}}]\n}\ntool_outputs_message = {\n    'role': 'tool_outputs',\n    'tool_outputs': [{\"tool_name\": 'perform_subtraction', 'tool_result': 2}],\n    'tool_error': None\n}\nmessages = [user_message, tool_inputs_message, tool_outputs_message]\n```\n\nAnd here is what it would look like instead if Claude made a mistake and `perform_subtraction` failed.\n```python\nuser_message = {'role': 'user', 'content': 'If Maggie has 3 apples and eats 1, how many apples does maggie have left?'}\ntool_inputs_message = {\n    'role': 'tool_inputs',\n    'content': \"Let's think this through. Maggie had 3 apples, she ate one so:\",\n    'tool_inputs': [{'tool_name': 'perform_subtraction', 'tool_arguments': {'a': 3}}]\n}\ntool_outputs_message = {\n    'role': 'tool_outputs',\n    'tool_outputs': None,\n    'tool_error': 'Missing required parameter \"b\" in tool perform_subtraction.'\n}\nmessages = [user_message, tool_inputs_message, tool_outputs_message]\n```\n\nThat's it for the new messages format. To help wrap your head around this concept, at the end of the \"Putting it Together\" section below, we will build a python function to handle these sorts of requests.\n\n### Putting it Together\nPutting concepts one, two, and three together above, a full implementation with multiple tools might look something like this:\n```python\nfrom tool_use_package.base_tool import BaseTool\nfrom tool_use_package.tool_user import ToolUser\n\n# Create Tools\nclass AdditionTool(BaseTool):\n    \"\"\"Tool to add two numbers together.\"\"\"\n    def use_tool(self, a, b):\n        return a + b\n\nclass SubtractionTool(BaseTool):\n    \"\"\"Tool to subtract one number from another.\"\"\"\n    def use_tool(self, a, b):\n        return a - b\n\n# Instantiate Each Tool\naddition_tool_name = \"perform_addition\"\naddition_tool_description = \"Add two numbers, a and b, together. For example, add_numbers(a=10, b=12) -\u003e 22. Numbers can be any rational number.\"\naddition_tool_parameters = [\n    {\"name\": \"a\", \"type\": \"float\", \"description\": \"The first number to add, such as 5\"},\n    {\"name\": \"b\", \"type\": \"float\", \"description\": \"The second number to add, such as 4.6\"}\n]\n\nsubtraction_tool_name = \"perform_subtraction\"\nsubtraction_tool_description = \"Perform subtraction of one number (b) from another (a) yielding a-b. For example, subtract_numbers(a=8, b=5) -\u003e 3. Numbers can be any rational number.\"\nsubtraction_tool_parameters = [\n    {\"name\": \"a\", \"type\": \"float\", \"description\": \"The minuend, such as 5\"},\n    {\"name\": \"b\", \"type\": \"float\", \"description\": \"The subtrahend, such as 9\"}\n]\n\naddition_tool = AdditionTool(addition_tool_name, addition_tool_description, addition_tool_parameters)\nsubtraction_tool = SubtractionTool(subtraction_tool_name, subtraction_tool_description, subtraction_tool_parameters)\n\n# Instantiate ToolUser by Passing it Tool Instances \nmath_tool_user = ToolUser([addition_tool, subtraction_tool])\n\n# Build messages\nuser_message = {\n    \"role\": \"user\",\n    \"content\": \"Sally has 17 apples. She gives 9 to Jim. Later that day, Peter gives 6 Bananas to Sally. How many pieces of fruit does Sally have at the end of the day?\"\n}\n\nmessages = [user_message]\n\n# Use Claude With the Provided Tools\nmath_tool_user.use_tools(messages, execution_mode='automatic')\n```\nThis should return something like:\n```python\n{\n    \"role\": \"assistant\",\n    \"content\": \"At the end of the day Sally has 14 pieces of fruit.\"\n}\n```\n\nAstute observers may have noticed that they didn't see any of the function calling happen! That's because we used the `execution_mode='automatic'` argument when we called `use_tools()`. When this parameter is set to automatic, `use_tools` will handle all of the work of managing Claude's tool_inputs messages, executing your tools on the inputs, passing Claude errors, etc. It will only stop and return you a next message when it reaches a point that Claude does not make a tool use request (basically when it sends back a message with `role='assistant'`). This is a great mode for getting started with tool use, but abstracts away some customizability. Namely, using `execution_mode='automatic'` takes away your ability to do your own validation of the arguments Claude passes to your tools before calling use_tool() on them, your ability to finely control the errors you give back to Claude, and your ability to see the intermediate `tool_inputs` and `tool_outputs` messages that Claude and your tools are producing.\n\nIf you want all those things, you should instead call `use_tools()` with `execution_mode='manual'`.\n```python\nmath_tool_user.use_tools(messages, execution_mode='manual')\n```\nThis should return something like:\n```python\n{\n    \"role\": \"tool_inputs\",\n    \"content\": \"Ok. Let's think through this in steps.\\nSally has 17 apples.\\nSally gives 9 apples to jim.\\nso:\\n\",\n    \"tool_inputs\": [\n        {\n            \"tool_name\": \"perform_subtraction\",\n            \"tool_arguments\": {'a': 17, 'b': 9}\n        }\n    ]\n}\n```\n\nNotice how this stops at the next message (in this case a `tool_inputs` message), and requires you to provide the `tool_outputs` message and pass in the new set of messages to keep going. Your next code would probably look something like this:\n```python\nclaude_res = {\n    \"role\": \"tool_inputs\",\n    \"content\": \"Ok. Let's think through this in steps.\\nSally has 17 apples.\\nSally gives 9 apples to jim.\\nso:\\n\",\n    \"tool_inputs\": [\n        {\n            \"tool_name\": \"perform_subtraction\",\n            \"tool_arguments\": {'a': 17, 'b': 9}\n        }\n    ]\n}\n\nmessages.append(claude_res)\n\nnext_message = {\n    \"role\": \"tool_outputs\",\n    \"tool_outputs\": [\n        {\n            \"tool_name\": \"perform_subtraction\",\n            \"tool_result\": 8\n        }\n    ],\n    \"tool_error\": None\n}\n\nmessages.append(next_message)\n\nmath_tool_user.use_tools(messages, execution_mode='manual')\n```\n\nTo wrap everything up, let's build a lightweight function that could automatically parse a response from Claude in manual mode, and generate the new messages list we want to pass to `use_tools()`. We will return a dictionary with two keys: `next_action`, which indicates if the next action should be to ask the user for input or to automatically respond to Claude with the results of its tool use request, and `messages`, which is the most up to date messages list.\n```python\ndef handle_manual_claude_res(messages, claude_res, tool_user):\n    \"\"\"\n    - messages does not include claude_res\n    - tool_user should be the ToolUser instance you have been using for previous messages\n    \"\"\"\n    # Append Claude's response to messages.\n    messages.append(claude_res)\n    \n    if claude_res['role'] == \"assistant\":\n        # If the message is not trying to use a tool we should not automatically respnd to Claude, and instead we should ask the user for input.\n        return {\"next_action\": \"user_input\", \"messages\": messages}\n    elif claude_res['role'] == \"tool_inputs\":\n        # If the message is trying to use a tool we should parse the tool and arguments, use the tool, create the tool_outputs message with the results, and append that message to messages.\n        tool_outputs = []\n        for tool_input in claude_res['tool_inputs']:\n            tool = next((t for t in tool_user.tools if t.name == tool_input['tool_name']), None)\n            if tool is None:\n                messages.append({\"role\": \"tool_outputs\", \"tool_outputs\": None, \"tool_error\": f\"No tool named \u003ctool_name\u003e{tool_name}\u003c/tool_name\u003e available.\"})\n                return {\"next_action\": \"auto_respond\", \"messages\": messages}\n\n            tool_result = tool.use_tool(**tool_input['tool_arguments'])\n            tool_outputs.append({\"tool_name\": tool_input['tool_name'], \"tool_result\": tool_result})\n        \n        messages.append({\"role\": \"tool_outputs\", \"tool_outputs\": tool_outputs, \"tool_error\": None})\n        return {\"next_action\": \"auto_respond\", \"messages\": messages}\n    else:\n        raise ValueError(f\"Provided role should be assistant or tool_inputs, got {claude_res['role']}\")\n```\n\nAnd that's it. You now know everything you need to know to give Claude tool use! For some more advanced techniques, exposure to some of our pre-built tools, and general inspiration check out our examples!\n\n## Examples\nNow that you know about `BaseTool`, `ToolUser`, and the new `messages` format, we recommend going through some examples of common use cases and more advanced usage patterns, which can be found in the `examples` folder. Head over to [EXAMPLES.md](tool_use_package/EXAMPLES.md) for a walkthrough:  \n- [Give Claude access to an API](tool_use_package/EXAMPLES.md#api-example)\n- [Let Claude call a SQL database](tool_use_package/EXAMPLES.md#sql-example)\n- [Let Claude search across a variety of data sources](tool_use_package/EXAMPLES.md#search-example)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanthropics%2Fanthropic-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fanthropics%2Fanthropic-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fanthropics%2Fanthropic-tools/lists"}