Task Management Assistant
Let’s create a Task Management Assistant with AIIDE. This assistant will help you manage your tasks, by creating, updating, and deleting them. Each task also has a custom schedule associated with it.
Prerequisites
Before we start, make sure you have pandas and aiide installed:
pip install pandas aiide
Imports
Let’s start by importing the necessary modules:
from aiide import AIIDE, TOOLfrom aiide.tools import TOOL_DEF, DICT, STRimport pandas as pd
AIIDE
is used to define and manage the chat instance.
Tool
is used to define the tools.
TOOL_DEF
, DICT
and STR
are some of the helpful abstractions for defining the JSON API for tool definition.
Pandas
is used to maintian the tasks in a DataFrame, and aiide is used to create the assistant.
Define the Tool
Since the heart of the assistant is task management, let’s define the tool first:
The tool class inherits TOOL
and has to have the following methods:
tool_def
: This method returns the tool’s JSON API. It is called multiple times during generation. You can return different JSON API based on the context. ex: change the enums of the fields etcmain
: This method is called when the tool is invoked. It takes the inputs defined in the JSON API and returns the output.
Let’s define the Tool
class TaskTool(TOOL): """ Tool to add, edit or delete a task to the list. """ def __init__(self, parent): """ Initialize the tool with the parent AIIDE chat instance. """ self.parent = parent # Initialize the environment with the current task list and timestamp self.ENV = [ "Current task list:\n" + self.parent.task_df.to_markdown(index=False) + "\nThe current timestamp is: " + str(pd.Timestamp.now()) ]
Here we are taking the parent instance(chat instance which will be defined below) as an argument and storing it in the self.parent
attribute.
It’s better to provide all the tools with the chat instance as the parent, so that they can access the environment and functions of other tools if and when needed.
Environment
Technically, the environment ENV
is a list of strings that are associated with each tool.
We can use the environment to provide the LLM with the last couple of snapshots of any data the tool is acting upon.
This way, we won’t overload the llm with the entire history of the data, which might only have slight modifications.
It is also good for cost savings.
In this tutorial, we are only going to provide the current task list and the current timestamp as the single(latest) element in the environment.
Tool Definition
tool_def
expects OpenAI’s JSON API for the tool definition. We have created a helper function TOOL_DEF
to make it easier to define the JSON API.
class TaskTool(TOOL): ... def tool_def(self): """ Tool definition for the task_management tool. """ return TOOL_DEF( name="task_management", description="Add, edit or delete a task to the list. task_description and cron_schedule_expression are mandatory for add or edit operation but are optional for delete operation.", properties=[ STR(name="task_id", description="The name of the task. Must be unique"), STR( name="operation_type", enums=["add", "edit", "delete"], description="The operation to perform on the task", ), STR( name="task_description", description="The description of the task. Must be in markdown", ), STR( name="cron_schedule_expression", description="The cron schedule expression for the task. Format is 'minute hour day month day_of_week'", ), ], required=["task_id", "operation_type"], )
Here we are defining the tool with the name task_management
and providing a description of what the tool does.
We are defining the properties of the tool:
task_id
: The name of the task. It must be unique.operation_type
: The operation to perform on the task. It can be eitheradd
,edit
, ordelete
.task_description
: The description of the task. It must be in markdown.cron_schedule_expression
: The cron schedule expression for the task. The format is ‘minute hour day month day_of_week’.
We are also defining the required properties of the tool: task_id
and operation_type
.
Main Function
The main
function is the function that is called when the tool is invoked. It takes the inputs defined in the JSON API, performs the operation on the dataframe, updates the ENV and returns the output.
class TaskTool(TOOL): ... def main( self, task_id, operation_type, task_description=None, cron_schedule_expression=None, ): """ Tool invokation function for the modify_item tool. """ if operation_type == "delete": if task_id in self.parent.task_df["item_id"].values: self.parent.task_df = self.parent.task_df[ self.parent.task_df["item_id"] != task_id ] self.ENV = [ "Current task list:\n" + self.parent.task_df.to_markdown(index=False) + "\nThe current timestamp is: " + str(pd.Timestamp.now()) ] return "Task " + task_id + " has been deleted." else: return "Task " + task_id + " does not exist in the list." else: if task_id in self.parent.task_df["item_id"].values: self.parent.task_df.loc[ self.parent.task_df["item_id"] == task_id, "item_details" ] = task_description self.parent.task_df.loc[ self.parent.task_df["item_id"] == task_id, "cron" ] = cron_schedule_expression else: self.parent.task_df.loc[len(self.parent.task_df.index)] = [ task_id, task_description, cron_schedule_expression, ] self.ENV = [ "Current task list:\n" + self.parent.task_df.to_markdown(index=False) + "\nThe current timestamp is: " + str(pd.Timestamp.now()) ] return "Task " + task_id + " has been added/edited."
Here we are checking the operation_type
and performing the operation on the dataframe accordingly.
Define the Chat Instance
Now that we have defined the tool, let’s define the chat instance:
class Agent(AIIDE): """ AIIDE chat instance for task management. """ def __init__(self, task_df): self.task_df = task_df # Create an instance of the ItemTool self.task_tool = TaskTool(self) self.setup( messages=[ { "role": "system", "content": "You are a helpful assistant. You are to assist the user in managing their tasks.", } ], model="gpt-4o", )
Here we are defining the chat instance Agent
which inherits AIIDE
.
We are taking the task dataframe as an argument and storing it in the self.task_df
attribute.
We are creating an instance of the TaskTool
and storing it in the self.task_tool
attribute.
We are setting up the chat instance with a system message and the model type.
Main Loop
Now that we have defined the chat instance, let’s run the main loop:
# Creating a task dataframe with some initial taskstask_df = pd.DataFrame( data={ "item_id": ["Buy Groceries", "Work on AIIDE"], "item_details": ["1. Bread\n2.Veggies\n3.Fruits", "Write unit tests"], "cron": ["0 10 * * 6", "0 20 * * 0,2,4,6"], })agent = Agent(task_df)
Here we are creating a task dataframe with some initial tasks.
We are creating an instance of the Agent
and passing the task dataframe as an argument.
Let’s create a loop to take user input and chat with the assistant:
while True: user_message = input("User: ") for each in agent.chat(user_message, tools=[agent.task_tool]): # Check the type of message and print the response accordingly if each["type"] == "text": print(each["delta"], end="") if each["type"] == "tool_call": print(each["name"], each["arguments"]) if each["type"] == "tool_response": print(each["response"]) print(agent.task_df) print("\n")
We call the chat
method of the agent instance with the user message and the tools we wish to enable for that interaction.
We are iterating over the response and printing the response accordingly.
AIIDE only supports streaming currently and we iterate over it to get the responses and parse them based on type of response.
- For response type of
text
: The LLM is talking to the user, which hasdelta
andcontent
as attributes. - For response type of
tool_call
: The LLM is calling a tool, which hasname
andarguments
as attributes. - For response type of
tool_response
: Response from the tool, which hasresponse
as an attribute along withname
andarguments
.
Complete code for reference
from aiide import AIIDE, TOOLfrom aiide.tools import DICT, STR, TOOL_DEFimport pandas as pd
class ItemTool(TOOL): """ Tool to add, edit or delete a task to the list. """ def __init__(self, parent): """ Initialize the tool with the parent AIIDE chat instance. """ self.parent = parent # Initialize the environment with the current task list and timestamp self.ENV = [ "Current task list:\n" + self.parent.task_df.to_markdown(index=False) + "\nThe current timestamp is: " + str(pd.Timestamp.now()) ]
def tool_def(self): """ Tool definition for the modify_item tool. """ return TOOL_DEF( name="modify_item", description="Add, edit or delete a task to the list. task_description and cron_schedule_expression are mandatory for add or edit operation but are optional for delete operation.", properties=[ STR(name="task_id", description="The name of the task. Must be unique"), STR( name="operation_type", enums=["add", "edit", "delete"], description="The operation to perform on the task", ), STR( name="task_description", description="The description of the task. Must be in markdown", ), STR( name="cron_schedule_expression", description="The cron schedule expression for the task. Format is 'minute hour day month day_of_week'", ), ], required=["task_id", "operation_type"], )
def main( self, task_id, operation_type, task_description=None, cron_schedule_expression=None, ): """ Tool invokation function for the modify_item tool. """ if operation_type == "delete": if task_id in self.parent.task_df["item_id"].values: self.parent.task_df = self.parent.task_df[ self.parent.task_df["item_id"] != task_id ] self.ENV = [ "Current task list:\n" + self.parent.task_df.to_markdown(index=False) + "\nThe current timestamp is: " + str(pd.Timestamp.now()) ] return "Task " + task_id + " has been deleted." else: return "Task " + task_id + " does not exist in the list." else: if task_id in self.parent.task_df["item_id"].values: self.parent.task_df.loc[ self.parent.task_df["item_id"] == task_id, "item_details" ] = task_description self.parent.task_df.loc[ self.parent.task_df["item_id"] == task_id, "cron" ] = cron_schedule_expression else: self.parent.task_df.loc[len(self.parent.task_df.index)] = [ task_id, task_description, cron_schedule_expression, ] self.ENV = [ "Current task list:\n" + self.parent.task_df.to_markdown(index=False) + "\nThe current timestamp is: " + str(pd.Timestamp.now()) ] return "Task " + task_id + " has been added/edited."
class Agent(AIIDE): """ AIIDE chat instance for task management. """ def __init__(self, task_df): self.task_df = task_df # Create an instance of the ItemTool self.item_tool = ItemTool(self) self.setup( messages=[ { "role": "system", "content": "You are a helpful assistant. You are to assist the user in managing their tasks.", } ], model="gpt-4o", )
# Creating a task dataframe with some initial taskstask_df = pd.DataFrame( data={ "item_id": ["Buy Groceries", "Work on AIIDE"], "item_details": ["1. Bread\n2.Veggies\n3.Fruits", "Write unit tests"], "cron": ["0 10 * * 6", "0 20 * * 0,2,4,6"], })agent = Agent(task_df)while True: user_message = input("User: ") for each in agent.chat(user_message, tools=[agent.item_tool]): # Check the type of message and print the response accordingly if each["type"] == "text": print(each["delta"], end="") if each["type"] == "tool_call": print(each["name"], each["arguments"]) if each["type"] == "tool_response": print(each["response"]) print(agent.task_df) print("\n")
Conclusion
In this tutorial, we created a Task Management Assistant with AIIDE. We defined a tool to add, edit, or delete tasks to the list and created a chat instance to manage the tasks. We also created a loop to take user input and chat with the assistant.