# retoor from __future__ import annotations from ..actions.spec import Action, Param from .schedule import MAX_LIFETIME_DAYS, MAX_MAX_RUNS, MIN_INTERVAL_SECONDS def field( name: str, description: str, required: bool = False, kind: str = "string" ) -> Param: return Param( name=name, location="body", description=description, required=required, type=kind, ) SCHEDULE_FIELDS: tuple[Param, ...] = ( field( "kind", "Schedule type: 'once' (run a single time), 'interval' (repeat every N seconds), " "or 'cron' (5-field cron expression).", required=True, ), field( "run_at", "For kind=once: absolute UTC time in ISO 8601, e.g. 2026-06-09T14:30:00.", ), field( "delay_seconds", "For kind=once: run this many seconds from now.", kind="integer", ), field( "every_seconds", f"For kind=interval: number of seconds between runs. Minimum {MIN_INTERVAL_SECONDS}.", kind="integer", ), field( "start_at", "For kind=interval: optional ISO 8601 UTC time of the first run. " "Defaults to one interval from now.", ), field( "cron", "For kind=cron: a 5-field cron expression 'minute hour day-of-month month day-of-week'. " "Supports *, ranges (1-5), lists (1,3,5) and steps (*/15). Two consecutive fires must be " f"at least {MIN_INTERVAL_SECONDS} seconds apart.", ), field( "max_runs", "Maximum number of executions; the task disables itself afterwards. A recurring task " f"without one gets a default, and the ceiling is {MAX_MAX_RUNS}.", kind="integer", ), field( "expires_at", "Absolute UTC time in ISO 8601 after which the task stops for good. Defaults to " f"{MAX_LIFETIME_DAYS} days after the first run, which is also the maximum.", ), ) TASK_ACTIONS: tuple[Action, ...] = ( Action( name="current_time", method="LOCAL", path="", summary="Get the exact current UTC time, to the second", description=( "The CURRENT TIME line in the system prompt is rounded to the hour to stay " "cache-friendly. Call this tool first whenever you need the precise current time - " "in particular before computing any absolute run_at for create_task/update_task from " "a relative phrase you cannot express via delay_seconds. For an ordinary relative " "delay ('in 40 seconds', 'in 2 hours'), you do not need this: delay_seconds is applied " "against the server's own clock at creation time and is always exact regardless." ), handler="task", requires_auth=False, params=(), ), Action( name="create_task", method="LOCAL", path="", summary="Queue a prompt to run autonomously on a schedule with full tool access", description=( "The prompt is executed later by a fresh agent that has every tool available, " "running inside the current authenticated session. Two rolling 24-hour quotas apply " "per account: how many tasks may be created, and how many task runs may execute. " "Every recurring task also stops by itself. While a task run is executing, members " "may not schedule further work from inside it; administrators may." ), handler="task", requires_auth=True, params=( field( "prompt", "A complete, self-contained instruction the future agent will execute when the " "task fires (it has no other context). Write an imperative command, not a " "description: e.g. 'Create a post in the fun topic about raccoons with a short " "funny text, then verify it appears.'", required=True, ), field("label", "Optional short human-readable label for the task."), field( "notify", "Set true for a REMINDER: when the task fires, the user is sent an in-app " "notification and live toast carrying the result, so it reaches them even when " "the Devii terminal is closed. Leave false for silent background automation.", kind="boolean", ), *SCHEDULE_FIELDS, ), ), Action( name="list_tasks", method="LOCAL", path="", summary="List queued tasks and their schedules and last results", handler="task", requires_auth=False, params=( field("enabled_only", "Only return enabled tasks.", kind="boolean"), field( "status", "Filter by status: pending, running, done, error, disabled." ), ), ), Action( name="get_task", method="LOCAL", path="", summary="Get a single task including its full last result", handler="task", requires_auth=False, params=(field("uid", "Uid of the task.", required=True),), ), Action( name="update_task", method="LOCAL", path="", summary="Update a task's prompt, label, enabled state, or schedule", description=( "Provide schedule fields together with kind to reschedule the task. Enabling a task " "from inside a running task is refused for members." ), handler="task", requires_auth=True, params=( field("uid", "Uid of the task.", required=True), field("prompt", "New prompt."), field("label", "New label."), field("enabled", "Enable or disable the task.", kind="boolean"), field( "notify", "Enable or disable the in-app reminder notification when this task fires.", kind="boolean", ), field("kind", "New schedule type when rescheduling."), field("run_at", "New absolute run time for kind=once."), field("delay_seconds", "New relative delay for kind=once.", kind="integer"), field("every_seconds", "New interval for kind=interval.", kind="integer"), field("start_at", "New first-run time for kind=interval."), field("cron", "New cron expression for kind=cron."), field("max_runs", "New maximum number of executions.", kind="integer"), field("expires_at", "New absolute UTC expiry in ISO 8601."), ), ), Action( name="delete_task", method="LOCAL", path="", summary="Delete a queued task", handler="task", requires_auth=False, params=(field("uid", "Uid of the task.", required=True),), ), Action( name="run_task_now", method="LOCAL", path="", summary="Trigger a task to execute immediately on the next scheduler tick", description=( "The run still consumes a slot of the account's rolling 24-hour run quota, and is " "postponed when that quota is spent." ), handler="task", requires_auth=True, params=(field("uid", "Uid of the task.", required=True),), ), )