A simple AI agent built with DSPy that will chain tool use and provide common overlapping times between groups of users given some availability blocks.
This project is a sandbox project to work with DSPy to build a reasoning agent with a local model. In working with agentic frameworks like Microsoft Autogen and Google ADK, I realized that prompt engineering still has a major impact on performance and reliability of the agent. DSPy is a framework that takes a structured approach for prompting and simplifies the instruction prompt development.
In addition, this project was an exploration in the capabilities of small LLMs that can run on consumer hardware.
This project uses a local llama3.1:7b model hosted by Ollama. To run this project, make sure you have a machine that can run a small LLM. Alternatively, you can use a model hosted in the cloud if you adjust dspy.configure accordingly.
Use uv for this project:
uv syncThen
uv run main.pyUsing dspy.inspect_history() for visibility
System message:
Your input fields are:
1. `user_request` (str):
2. `trajectory` (str):
Your output fields are:
1. `reasoning` (str):
2. `process_result` (str): Message that summarizes the process result, and the information users need, e.g., the user IDs.
All interactions will be structured in the following way, with the appropriate values filled in.
[[ ## user_request ## ]]
{user_request}
[[ ## trajectory ## ]]
{trajectory}
[[ ## reasoning ## ]]
{reasoning}
[[ ## process_result ## ]]
{process_result}
[[ ## completed ## ]]
In adhering to this structure, your objective is:
You are a scheduling assistant that helps find common available times for groups of people to meet.
You are given a list of tools to handle user request, and you should decide the right tool to use in order to
fulfill users' requests. You may determine that you do not have the tools at your disposal to fulfill the
request, in which case you should ask the user to clarify their request.
User message:
[[ ## user_request ## ]]
Find common meet times for g3ppmldv and ctkrjycx
[[ ## trajectory ## ]]
[[ ## thought_0 ## ]]
To find common meet times for g3ppmldv and ctkrjycx, we need to fetch their time availabilities first.
[[ ## tool_name_0 ## ]]
fetch_time_availabilities
[[ ## tool_args_0 ## ]]
{"user_ids": ["g3ppmldv", "ctkrjycx"]}
[[ ## observation_0 ## ]]
{"status": "success", "result": {"g3ppmldv": [{"start": "2025-06-10T11:30:00", "end": "2025-06-10T13:00:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T15:30:00", "end": "2025-06-10T17:00:00"}], "ctkrjycx": [{"start": "2025-06-10T09:30:00", "end": "2025-06-10T12:30:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T15:00:00", "end": "2025-06-10T17:00:00"}]}}
[[ ## thought_1 ## ]]
Now that we have the time availabilities for both users, we can use this information to find common meet times.
[[ ## tool_name_1 ## ]]
get_meet_times
[[ ## tool_args_1 ## ]]
{"user_ids": [["g3ppmldv", "ctkrjycx"]], "user_availability": {"g3ppmldv": [{"start": "2025-06-10T11:30:00", "end": "2025-06-10T13:00:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T15:30:00", "end": "2025-06-10T17:00:00"}], "ctkrjycx": [{"start": "2025-06-10T09:30:00", "end": "2025-06-10T12:30:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T15:00:00", "end": "2025-06-10T17:00:00"}]}}
[[ ## observation_1 ## ]]
{"status": "success", "result": [[{"start": "2025-06-10T11:30:00", "end": "2025-06-10T12:00:00"}, {"start": "2025-06-10T12:00:00", "end": "2025-06-10T12:30:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T15:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:00:00", "end": "2025-06-10T16:30:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}]]}
[[ ## thought_2 ## ]]
The task is now complete. We have successfully found common meet times for g3ppmldv and ctkrjycx.
[[ ## tool_name_2 ## ]]
finish
[[ ## tool_args_2 ## ]]
{}
[[ ## observation_2 ## ]]
Completed.
Respond with the corresponding output fields, starting with the field `[[ ## reasoning ## ]]`, then `[[ ## process_result ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
Response:
[[ ## reasoning ## ]]
To find common meet times for g3ppmldv and ctkrjycx, we first fetched their time availabilities using the `fetch_time_availabilities` tool. Then, we used this information to find common meet times with the `get_meet_times` tool. Finally, we completed the task by calling the `finish` tool.
[[ ## process_result ## ]]
Common meet times for g3ppmldv and ctkrjycx:
- 2025-06-10T11:30:00 - 12:00:00
- 2025-06-10T13:30:00 - 14:00:00
[[ ## completed ## ]]
System message:
Your input fields are:
1. `user_request` (str):
2. `trajectory` (str):
Your output fields are:
1. `reasoning` (str):
2. `process_result` (str): Message that summarizes the process result, and the information users need, e.g., the user IDs.
All interactions will be structured in the following way, with the appropriate values filled in.
[[ ## user_request ## ]]
{user_request}
[[ ## trajectory ## ]]
{trajectory}
[[ ## reasoning ## ]]
{reasoning}
[[ ## process_result ## ]]
{process_result}
[[ ## completed ## ]]
In adhering to this structure, your objective is:
You are a scheduling assistant that helps find common available times for groups of people to meet.
You are given a list of tools to handle user request, and you should decide the right tool to use in order to
fulfill users' requests. You may determine that you do not have the tools at your disposal to fulfill the
request, in which case you should ask the user to clarify their request.
User message:
[[ ## user_request ## ]]
Find common meet times for g3ppmldv and ctkrjycx, and m711d3y2 and zi5qojlw
[[ ## trajectory ## ]]
[[ ## thought_0 ## ]]
To find common meet times for the given user pairs, we need to first fetch their individual time availability. We can use the 'fetch_time_availabilities' tool to get this information.
[[ ## tool_name_0 ## ]]
get_meet_times
[[ ## tool_args_0 ## ]]
{"user_ids": [["g3ppmldv", "ctkrjycx"], ["m711d3y2", "zi5qojlw"]]}
[[ ## observation_0 ## ]]
Execution error in get_meet_times:
Traceback (most recent call last):
...
TypeError: get_meet_times() missing 1 required positional argument: 'user_availability'
[[ ## thought_1 ## ]]
It seems that the get_meet_times tool requires two arguments: user_ids and user_availability. However, we only provided user_ids in our previous call. We need to fetch time availability data for the given user IDs first.
[[ ## tool_name_1 ## ]]
fetch_time_availabilities
[[ ## tool_args_1 ## ]]
{"user_ids": ["g3ppmldv", "ctkrjycx", "m711d3y2", "zi5qojlw"]}
[[ ## observation_1 ## ]]
{"status": "success", "result": {"g3ppmldv": [{"start": "2025-06-10T09:30:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T15:00:00"}, {"start": "2025-06-10T16:00:00", "end": "2025-06-10T17:00:00"}], "ctkrjycx": [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T17:00:00"}], "m711d3y2": [{"start": "2025-06-10T10:00:00", "end": "2025-06-10T13:00:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}], "zi5qojlw": [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T11:00:00"}, {"start": "2025-06-10T12:00:00", "end": "2025-06-10T17:00:00"}]}}
[[ ## thought_2 ## ]]
Now that we have fetched time availability data for each user, we can use this information to find common meet times. We will pass the user_ids and user_availability as arguments to the get_meet_times tool.
[[ ## tool_name_2 ## ]]
get_meet_times
[[ ## tool_args_2 ## ]]
{"user_ids": [["g3ppmldv", "ctkrjycx"], ["m711d3y2", "zi5qojlw"]], "user_availability": {"g3ppmldv": [{"start": "2025-06-10T09:30:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T15:00:00"}, {"start": "2025-06-10T16:00:00", "end": "2025-06-10T17:00:00"}], "ctkrjycx": [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T17:00:00"}], "m711d3y2": [{"start": "2025-06-10T10:00:00", "end": "2025-06-10T13:00:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}], "zi5qojlw": [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T11:00:00"}, {"start": "2025-06-10T12:00:00", "end": "2025-06-10T17:00:00"}]}}
[[ ## observation_2 ## ]]
{"status": "success", "result": [[{"start": "2025-06-10T09:30:00", "end": "2025-06-10T10:00:00"}, {"start": "2025-06-10T10:00:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T14:30:00"}, {"start": "2025-06-10T14:30:00", "end": "2025-06-10T15:00:00"}, {"start": "2025-06-10T16:00:00", "end": "2025-06-10T16:30:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}], [{"start": "2025-06-10T10:00:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T10:30:00", "end": "2025-06-10T11:00:00"}, {"start": "2025-06-10T12:00:00", "end": "2025-06-10T12:30:00"}, {"start": "2025-06-10T12:30:00", "end": "2025-06-10T13:00:00"}, {"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T14:30:00"}, {"start": "2025-06-10T14:30:00", "end": "2025-06-10T15:00:00"}, {"start": "2025-06-10T15:00:00", "end": "2025-06-10T15:30:00"}, {"start": "2025-06-10T15:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}]]}
[[ ## thought_3 ## ]]
We have successfully found common meet times for the given user pairs.
[[ ## tool_name_3 ## ]]
finish
[[ ## tool_args_3 ## ]]
{}
[[ ## observation_3 ## ]]
Completed.
Respond with the corresponding output fields, starting with the field `[[ ## reasoning ## ]]`, then `[[ ## process_result ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
Response:
[[ ## reasoning ## ]]
To find common meet times for the given user pairs, we first need to fetch their individual time availability using the 'fetch_time_availabilities' tool. Once we have this information, we can use it to find common meet times by passing the user_ids and user_availability as arguments to the get_meet_times tool.
[[ ## process_result ## ]]
Common meet times for the given user pairs are:
- g3ppmldv and ctkrjycx:
- 2025-06-10T09:30:00-10:00
- 2025-06-10T14:00:00-14:30
- 2025-06-10T16:00:00-17:00
- m711d3y2 and zi5qojlw:
- 2025-06-10T10:00:00-10:30
- 2025-06-10T12:00:00-12:30
- 2025-06-10T13:30:00-14:00
- 2025-06-10T14:00:00-15:00
- 2025-06-10T16:30:00-17:00
[[ ## completed ## ]]
System message:
Your input fields are:
1. `user_request` (str):
2. `trajectory` (str):
Your output fields are:
1. `reasoning` (str):
2. `process_result` (str): Message that summarizes the process result, and the information users need, e.g., the user IDs.
All interactions will be structured in the following way, with the appropriate values filled in.
[[ ## user_request ## ]]
{user_request}
[[ ## trajectory ## ]]
{trajectory}
[[ ## reasoning ## ]]
{reasoning}
[[ ## process_result ## ]]
{process_result}
[[ ## completed ## ]]
In adhering to this structure, your objective is:
You are a scheduling assistant that helps find common available times for groups of people to meet.
You are given a list of tools to handle user request, and you should decide the right tool to use in order to
fulfill users' requests. You may determine that you do not have the tools at your disposal to fulfill the
request, in which case you should ask the user to clarify their request.
User message:
[[ ## user_request ## ]]
Find common meet times for g3ppmldv, ctkrjycx, m711d3y2 and zi5qojlw
[[ ## trajectory ## ]]
[[ ## thought_0 ## ]]
To find common meet times for the given users, we need to first fetch their time availability data. We can use the `fetch_time_availabilities` tool to get this information.
[[ ## tool_name_0 ## ]]
get_meet_times
[[ ## tool_args_0 ## ]]
{"user_ids": [["g3ppmldv", "ctkrjycx", "m711d3y2"], ["zi5qojlw"]]}
[[ ## observation_0 ## ]]
Execution error in get_meet_times:
Traceback (most recent call last):
...
TypeError: get_meet_times() missing 1 required positional argument: 'user_availability'
[[ ## thought_1 ## ]]
It seems that we need to fetch time availability data before getting common meet times. We should use the `fetch_time_availabilities` tool to get this information.
[[ ## tool_name_1 ## ]]
fetch_time_availabilities
[[ ## tool_args_1 ## ]]
{"user_ids": ["g3ppmldv", "ctkrjycx", "m711d3y2", "zi5qojlw"]}
[[ ## observation_1 ## ]]
{"status": "success", "result": {"g3ppmldv": [{"start": "2025-06-10T11:30:00", "end": "2025-06-10T12:00:00"}, {"start": "2025-06-10T13:00:00", "end": "2025-06-10T14:30:00"}], "ctkrjycx": [{"start": "2025-06-10T13:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}], "m711d3y2": [{"start": "2025-06-10T13:00:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T14:30:00", "end": "2025-06-10T16:30:00"}], "zi5qojlw": [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T11:00:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T16:30:00"}]}}
[[ ## thought_2 ## ]]
Now that we have fetched the time availability data for all users, we can use the `get_meet_times` tool to find common meet times.
[[ ## tool_name_2 ## ]]
get_meet_times
[[ ## tool_args_2 ## ]]
{"user_ids": [["g3ppmldv", "ctkrjycx", "m711d3y2"], ["zi5qojlw"]], "user_availability": {"g3ppmldv": [{"start": "2025-06-10T11:30:00", "end": "2025-06-10T12:00:00"}, {"start": "2025-06-10T13:00:00", "end": "2025-06-10T14:30:00"}], "ctkrjycx": [{"start": "2025-06-10T13:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:30:00", "end": "2025-06-10T17:00:00"}], "m711d3y2": [{"start": "2025-06-10T13:00:00", "end": "2025-06-10T14:00:00"}, {"start": "2025-06-10T14:30:00", "end": "2025-06-10T16:30:00"}], "zi5qojlw": [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T11:00:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T16:30:00"}]}}
[[ ## observation_2 ## ]]
{"status": "success", "result": [[{"start": "2025-06-10T13:30:00", "end": "2025-06-10T14:00:00"}], [{"start": "2025-06-10T09:00:00", "end": "2025-06-10T09:30:00"}, {"start": "2025-06-10T09:30:00", "end": "2025-06-10T10:00:00"}, {"start": "2025-06-10T10:00:00", "end": "2025-06-10T10:30:00"}, {"start": "2025-06-10T10:30:00", "end": "2025-06-10T11:00:00"}, {"start": "2025-06-10T14:00:00", "end": "2025-06-10T14:30:00"}, {"start": "2025-06-10T14:30:00", "end": "2025-06-10T15:00:00"}, {"start": "2025-06-10T15:00:00", "end": "2025-06-10T15:30:00"}, {"start": "2025-06-10T15:30:00", "end": "2025-06-10T16:00:00"}, {"start": "2025-06-10T16:00:00", "end": "2025-06-10T16:30:00"}]]}
[[ ## thought_3 ## ]]
Now that we have found common meet times for the given users, we can use the `finish` tool to conclude the process.
[[ ## tool_name_3 ## ]]
finish
[[ ## tool_args_3 ## ]]
{}
[[ ## observation_3 ## ]]
Completed.
Respond with the corresponding output fields, starting with the field `[[ ## reasoning ## ]]`, then `[[ ## process_result ## ]]`, and then ending with the marker for `[[ ## completed ## ]]`.
Response:
[[ ## reasoning ## ]]
To find common meet times for the given users (g3ppmldv, ctkrjycx, m711d3y2 and zi5qojlw), we first fetched their time availability data using the `fetch_time_availabilities` tool. Then, we used the `get_meet_times` tool to find common meet times based on this availability data.
[[ ## process_result ## ]]
Common meet times for the given users are:
- 2025-06-10T09:00:00 - 09:30:00
- 2025-06-10T09:30:00 - 10:00:00
- 2025-06-10T10:00:00 - 10:30:00
- 2025-06-10T10:30:00 - 11:00:00
- 2025-06-10T13:30:00 - 14:00:00
- 2025-06-10T14:00:00 - 14:30:00
- 2025-06-10T14:30:00 - 15:00:00
- 2025-06-10T15:00:00 - 15:30:00
- 2025-06-10T15:30:00 - 16:00:00
- 2025-06-10T16:00:00 - 16:30:00
[[ ## completed ## ]]