From 3839a75c0e0036977d856de8eb5503f49431d661 Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 2 Jun 2026 13:52:50 +0200 Subject: [PATCH] feat(assignments): Rename assignments to scheduled tasks and make the timezone param optional Signed-off-by: Marcel Klehr --- ex_app/lib/agent.py | 2 +- ex_app/lib/all_tools/assignments.py | 21 +++++++++++++-------- ex_app/lib/all_tools/contacts.py | 2 +- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/ex_app/lib/agent.py b/ex_app/lib/agent.py index 544f6c0..a99a7d6 100644 --- a/ex_app/lib/agent.py +++ b/ex_app/lib/agent.py @@ -137,7 +137,7 @@ async def call_model( if tool_enabled("find_person_in_users"): system_prompt_text += "Use the find_person_in_users tool to find a person's userId and user details.\n" if tool_enabled("find_details_of_current_user"): - system_prompt_text += "Use the find_details_of_current_user tool to find the current user's location.\n" + system_prompt_text += "Use the find_details_of_current_user tool to find the current user's location and timezone.\n" if task['input'].get('memories', None) is not None: system_prompt_text += "You can remember things from other conversations with the user. If relevant, take into account the following memories:\n\n" + "\n".join(task['input']['memories']) + "\n\n" diff --git a/ex_app/lib/all_tools/assignments.py b/ex_app/lib/all_tools/assignments.py index 8475459..3a82d45 100644 --- a/ex_app/lib/all_tools/assignments.py +++ b/ex_app/lib/all_tools/assignments.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later import datetime +import pytz from langchain_core.tools import tool from nc_py_api import AsyncNextcloudApp @@ -12,17 +13,18 @@ async def get_tools(nc: AsyncNextcloudApp): @tool @dangerous_tool - async def create_scheduled_task(title: str, prompt: str, recurrence_rule: str, starts_at: None|str = None): + async def create_scheduled_task(title: str, prompt: str, recurrence_rule: str, timezone: str|None = None, starts_at: None|str = None): """ - Create a recurring Scheduled Task for the assistant that will be carried out autonomously. + Create a Scheduled Task for the assistant that will be carried out autonomously. The user will still have to approve sensitive actions. For example, the user could ask to transcribe new files in a certain folder every hour. Then the prompt argument for this tool would be "Transcribe new files in folder /Audio" and the recurrence_rule would be "FREQ=HOURLY". After having created the Scheduled Task, let the user know that the Scheduled Task will run in a newly created chat session. :param title: A title for the Scheduled Task, e.g. "Transcribe audio files" -- This is only for the user's reference and has no effect on the execution of the Scheduled Task. :param prompt: The instructions for the AI carrying out the Scheduled Task - :param recurrence_rule: An RRule compliant with RFC 5545 that defines the recurrence rule for the Scheduled Task. For example "FREQ=DAILY;INTERVAL=1" to run the Scheduled Task every day. - :param starts_at: A date time string in ISO 8601 format that defines when the Scheduled Task should start. For example "2025-01-01T09:00:00Z". If not provided, the Scheduled Task will start immediately. + :param recurrence_rule: An RRule compliant with RFC 5545 that defines the recurrence rule for the Scheduled Task. For example "FREQ=DAILY;INTERVAL=1" to run the Scheduled Task every day, an empty string as the recurrence_rule means the task does not repeat. + :param starts_at: A date time string in ISO 8601 format that defines when the Scheduled Task should start. For example "2025-01-01T09:00:00Z". If not provided, the Scheduled Task will start immediately. Make sure to use the user's timezone for this, obtainable with find_details_of_current_user + :param timezone: Timezone (e.g., 'America/New_York') defaults to the user's current time zone :return: """ @@ -31,6 +33,7 @@ async def create_scheduled_task(title: str, prompt: str, recurrence_rule: str, s 'prompt': prompt, 'recurrence': recurrence_rule, 'startsAt': int(datetime.datetime.fromisoformat(starts_at.replace('Z', '+00:00')).timestamp()) if starts_at is not None else datetime.datetime.now(datetime.UTC).timestamp(), + 'timezone': pytz.timezone(timezone).zone if timezone is not None else None }) return True @@ -39,7 +42,7 @@ async def create_scheduled_task(title: str, prompt: str, recurrence_rule: str, s @safe_tool async def list_scheduled_tasks(): """ - List all recurring assistant Scheduled Tasks by the current user. + List all assistant Scheduled Tasks by the current user. :return: """ @@ -47,12 +50,13 @@ async def list_scheduled_tasks(): @tool @dangerous_tool - async def update_scheduled_task(id: int, prompt: None|str = None, recurrence_rule: None|str = None, starts_at: None|str = None): + async def update_scheduled_task(id: int, prompt: None|str = None, recurrence_rule: None|str = None, timezone: str|None = None, starts_at: None|str = None): """ - Update a recurring assistant Scheduled Task + Update a assistant Scheduled Task :param id: The ID of the Scheduled Task to update, you can obtain this from the list_scheduled_tasks tool :param prompt: The instructions for the AI carrying out the Scheduled Task. Pass `None` to leave this unchanged. - :param recurrence_rule: An RRule compliant with RFC 5545 that defines the recurrence rule for the Scheduled Task. For example "FREQ=DAILY;INTERVAL=1" to run the Scheduled Task every day. Pass `None` to leave this unchanged. + :param recurrence_rule: An RRule compliant with RFC 5545 that defines the recurrence rule for the Scheduled Task. For example "FREQ=DAILY;INTERVAL=1" to run the Scheduled Task every day. An empty string means, it does not repeat. Pass `None` to leave this unchanged. + :param timezone A timezone for the scheduled task, set to None to leave this as is. :param starts_at: A date time string in ISO 8601 format that defines when the Scheduled Task should start. For example "2025-01-01T09:00:00Z". If not provided, the Scheduled Task will start immediately. Pass `None` to leave this unchanged. :return: """ @@ -61,6 +65,7 @@ async def update_scheduled_task(id: int, prompt: None|str = None, recurrence_rul 'prompt': prompt, 'recurrence': recurrence_rule, 'startsAt': int(datetime.datetime.fromisoformat(starts_at.replace('Z', '+00:00')).timestamp()) if starts_at is not None else None, + 'timezone': pytz.timezone(timezone).zone if timezone is not None else None }) @tool diff --git a/ex_app/lib/all_tools/contacts.py b/ex_app/lib/all_tools/contacts.py index 09c1a10..33fd01e 100644 --- a/ex_app/lib/all_tools/contacts.py +++ b/ex_app/lib/all_tools/contacts.py @@ -98,7 +98,7 @@ async def find_person_in_contacts(name: str) -> list[dict[str, typing.Any]]: @safe_tool async def find_details_of_current_user() -> dict[str, typing.Any]: """ - Find the current user's personal information + Find the current user's personal information, such as name, location, timezone, language :return: a dictionary with the person's personal information """