We use cookies on our website.
Docs
API Reference
Core
Tool

Tool

The general meaning of a tool is "something that gets controlled by someone to accomplish a particular task". There are three parts of this definition that are related to Embedia:

  • The tool itself
  • The "someone" that controls the tool
  • The task to accomplish

In a real world example,

  • The tool is a hammer
  • The "someone" controlling the tool is you
  • The task is "driving a nail into the wall"

In the context of Embedia,

  • The tool is any python function abstracted through the Tool class
  • The "someone" controlling the tool is an Agent (Learn more about: Agents)
  • The task is whatever the Agent has to accomplish

Tool is an abstract class. Inherit from this class and define the _run method. The _run method can take any number of arguments, runs the internal logic of the tool and returns an output. Although most of the time, an Agent will be calling the Tool instance, you can also use the Tool instance directly by calling it like a function with the expected arguments that you've defined.

ℹ️

Any python function in the entire world can become a tool if you put its contents inside the _run method.

Attributes

  1. docs (ToolDocumentation): The documentation of the tool's usage and its arguments. (Learn more about: ToolDocumentation)

Methods

  1. _run (abstract): Implement this method to run the internal logic of the tool. Do not call this method directly. Instead, use the __call__ method.
  • Input: *args, **kwargs
  • Output: ToolReturn (Learn more about: ToolReturn)
  1. __call__: Internally calls the _run method. Use this method by calling the class instance like a function with the expected arguments.
  • Input: *args, **kwargs
  • Output: ToolReturn
  • Publishes a ToolStart event before calling _run and a ToolEnd event after _run returns.
  1. human_confirmation: Use this method to ask for human confirmation at any point in the _run function.
  • Input: dict: The details to be displayed while asking for confirmation.
  • Output: None
  • Asks for an input from the user. If the user inputs y, the code moves forward. If the user inputs anything else, it raises UserDeniedError.

Usage

Basic Usage

A Tool is created so that it can be used by an Agent. For an Agent to understand how to use a Tool, it needs to know two things about the tool:

  • What does this tool do?
  • What are the input parameters of this tool?

To give a structure to these two questions, Embedia provides the ToolDocumentation model. (Learn more about: ToolDocumentation). The first question is solved by the name and desc attributes of the model. The second question is solved by the params attribute of the model.

To understand whether the tool ran successfully or not, we provide the ToolReturn model. (Learn more about: ToolReturn). This is useful when we are defining different logical paths based on the fact that the tool ran successfully or not.

Let's create a simple print tool to understand how to use the Tool class.

import asyncio
from embedia import Tool, ToolDocumentation, ParamDocumentation, ToolReturn
 
 
class PrintTool(Tool):
    def __init__(self):
        super().__init__(docs=ToolDocumentation(
            name="Print Tool",
            desc="Prints whatever you want",
            params=[ParamDocumentation(name="text", desc="The text to be printed. Type: String")]
        ))
 
    async def _run(self, text: str):
        print(text)
        return ToolReturn(output='done', exit_code=0)
 
 
if __name__ == '__main__':
    printer = PrintTool()
    resp = asyncio.run(printer('Hello World!!!!!!'))

Running this code gives the following output:

[time: 2023-10-01T02:43:20.350426+00:00] [id: 140149931670096] [event: Tool Start]
Tool: PrintTool
Args: ('Hello World!!!!!!',)
Kwargs: {}
Hello World!!!!!!
 
[time: 2023-10-01T02:43:20.350558+00:00] [id: 140149931670096] [event: Tool End]
Tool: PrintTool
ExitCode: 0
Output:
done

To make it easier to code, Embedia can convert python dictionaries to pydantic models (like ToolDocumentation, ParamDocumentation and ToolReturn) internally. So the above code can be simplified as follows:

import asyncio
from embedia import Tool
 
 
class PrintTool(Tool):
    def __init__(self):
        super().__init__(docs={
            "name": "Print Tool",
            "desc": "Prints whatever you want",
            "params": [{"name": "text", "desc": "The text to be printed. Type: String"}]
        })
 
    async def _run(self, text: str):
        print(text)
        return {'output': 'done'}
 
 
if __name__ == '__main__':
    printer = PrintTool()
    resp = asyncio.run(printer('Hello World!!!!!!'))

It results in the same output as before:

[time: 2023-10-01T02:43:20.350426+00:00] [id: 140149931670096] [event: Tool Start]
Tool: PrintTool
Args: ('Hello World!!!!!!',)
Kwargs: {}
Hello World!!!!!!
 
[time: 2023-10-01T02:43:20.350558+00:00] [id: 140149931670096] [event: Tool End]
Tool: PrintTool
ExitCode: 0
Output:
done

Adding human confirmation inside _run function

You can ask for human confirmation at any point in your _run function by calling the self.human_confirmation method. It takes in a details parameter (type: dict) that will be displayed to the end user while asking for confirmation.

This is useful when the tool is about to do something that can't be undone (eg: deleting a file). Adding human confirmation to the PrintTool would look something like this:

import asyncio
from embedia import Tool
 
 
class PrintTool(Tool):
    def __init__(self):
        super().__init__(docs={
            "name": "Print Tool",
            "desc": "Prints whatever you want",
            "params": [{"name": "text", "desc": "The text to be printed. Type: String"}]
        })
 
    async def _run(self, text: str):
        await self.human_confirmation(details={"text": text})
        print(text)
        return {'output': 'done'}
 
 
if __name__ == '__main__':
    printer = PrintTool()
    resp = asyncio.run(printer('Hello World!!!!!!'))

Running this code gives the following output:

[time: 2023-10-01T11:14:14.151069+00:00] [id: 140182104013264] [event: Tool Start]
Tool: PrintTool
Args: ('Hello World!!!!!!',)
Kwargs: {}
 
Tool: PrintTool
Details: {'text': 'Hello World!!!!!!'} Confirm (y/n):

If the user inputs y, the code successfully moves forward like so:

Hello World!!!!!!
 
[time: 2023-10-01T11:14:18.693709+00:00] [id: 140182104013264] [event: Tool End]
Tool: PrintTool
ExitCode: 0
Output:
done

If the user inputs anything else, it raises UserDeniedError:

embedia.utils.exceptions.UserDeniedError: Tool: PrintTool Details: {'text': 'Hello World!!!!!!'}

Try it out yourself