mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-29 19:35:20 +02:00
- Added support for @-mentions in agent tasks, allowing users to reference documents, folders, and connectors directly in their queries. - Updated `run_agent_task` to resolve mentions and include them in the context passed to the agent. - Introduced new parameters in `AgentTaskActionParams` for handling mentioned document and connector IDs. - Refactored the automation edit and new components to utilize the new `AutomationBuilderForm` for a more streamlined user experience. - Removed deprecated JSON forms to simplify the automation creation process.
132 lines
4.4 KiB
TypeScript
132 lines
4.4 KiB
TypeScript
/**
|
|
* Bidirectional bridge between a friendly schedule model and the 5-field cron
|
|
* expression the backend ``schedule`` trigger expects (see
|
|
* ``app/automations/triggers/schedule/params.py``).
|
|
*
|
|
* The form builder never asks users to type cron. They pick a frequency + time
|
|
* (+ days), which ``toCron`` compiles. On edit we ``fromCron`` an existing
|
|
* expression back into the model; anything we don't recognize returns ``null``
|
|
* so the caller can fall back to a raw-cron escape hatch instead of silently
|
|
* losing the user's schedule.
|
|
*
|
|
* The recognized patterns are intentionally the same family that
|
|
* ``describe-cron.ts`` humanizes, keeping the picker and the label in sync.
|
|
*/
|
|
|
|
export type ScheduleFrequency = "hourly" | "daily" | "weekdays" | "weekly" | "monthly";
|
|
|
|
export interface ScheduleModel {
|
|
frequency: ScheduleFrequency;
|
|
/** 0-23. Ignored for ``hourly``. */
|
|
hour: number;
|
|
/** 0-59. */
|
|
minute: number;
|
|
/** 0 (Sun) - 6 (Sat). Used by ``weekly``. */
|
|
daysOfWeek: number[];
|
|
/** 1-31. Used by ``monthly``. */
|
|
dayOfMonth: number;
|
|
}
|
|
|
|
/** Sunday-first, matching cron's 0-6 day-of-week numbering. */
|
|
export const WEEKDAY_OPTIONS: ReadonlyArray<{ value: number; short: string; long: string }> = [
|
|
{ value: 1, short: "Mon", long: "Monday" },
|
|
{ value: 2, short: "Tue", long: "Tuesday" },
|
|
{ value: 3, short: "Wed", long: "Wednesday" },
|
|
{ value: 4, short: "Thu", long: "Thursday" },
|
|
{ value: 5, short: "Fri", long: "Friday" },
|
|
{ value: 6, short: "Sat", long: "Saturday" },
|
|
{ value: 0, short: "Sun", long: "Sunday" },
|
|
];
|
|
|
|
export const FREQUENCY_OPTIONS: ReadonlyArray<{ value: ScheduleFrequency; label: string }> = [
|
|
{ value: "hourly", label: "Every hour" },
|
|
{ value: "daily", label: "Every day" },
|
|
{ value: "weekdays", label: "Every weekday (Mon\u2013Fri)" },
|
|
{ value: "weekly", label: "Specific days of the week" },
|
|
{ value: "monthly", label: "Once a month" },
|
|
];
|
|
|
|
export const DEFAULT_SCHEDULE: ScheduleModel = {
|
|
frequency: "weekdays",
|
|
hour: 9,
|
|
minute: 0,
|
|
daysOfWeek: [1],
|
|
dayOfMonth: 1,
|
|
};
|
|
|
|
function isInt(value: string): boolean {
|
|
return /^\d+$/.test(value);
|
|
}
|
|
|
|
function clamp(value: number, min: number, max: number): number {
|
|
if (Number.isNaN(value)) return min;
|
|
return Math.min(max, Math.max(min, value));
|
|
}
|
|
|
|
/** Compile a schedule model into a 5-field cron expression. */
|
|
export function toCron(model: ScheduleModel): string {
|
|
const minute = clamp(model.minute, 0, 59);
|
|
const hour = clamp(model.hour, 0, 23);
|
|
|
|
switch (model.frequency) {
|
|
case "hourly":
|
|
return `${minute} * * * *`;
|
|
case "daily":
|
|
return `${minute} ${hour} * * *`;
|
|
case "weekdays":
|
|
return `${minute} ${hour} * * 1-5`;
|
|
case "weekly": {
|
|
const days = [...new Set(model.daysOfWeek)].sort((a, b) => a - b);
|
|
// Guard against an empty selection producing an invalid cron.
|
|
const dow = days.length > 0 ? days.join(",") : "1";
|
|
return `${minute} ${hour} * * ${dow}`;
|
|
}
|
|
case "monthly":
|
|
return `${minute} ${hour} ${clamp(model.dayOfMonth, 1, 31)} * *`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse a 5-field cron expression back into a schedule model. Returns ``null``
|
|
* for anything outside the recognized pattern family so callers can fall back
|
|
* to the raw-cron field.
|
|
*/
|
|
export function fromCron(cron: string): ScheduleModel | null {
|
|
const parts = cron.trim().split(/\s+/);
|
|
if (parts.length !== 5) return null;
|
|
|
|
const [minute, hour, dom, month, dow] = parts;
|
|
|
|
// Hourly: "M * * * *"
|
|
if (month === "*" && dom === "*" && dow === "*" && hour === "*" && isInt(minute)) {
|
|
return { ...DEFAULT_SCHEDULE, frequency: "hourly", minute: Number(minute) };
|
|
}
|
|
|
|
// Everything below requires concrete minute + hour.
|
|
if (!isInt(minute) || !isInt(hour)) return null;
|
|
|
|
const base = { hour: Number(hour), minute: Number(minute) };
|
|
|
|
// Daily: "M H * * *"
|
|
if (month === "*" && dom === "*" && dow === "*") {
|
|
return { ...DEFAULT_SCHEDULE, ...base, frequency: "daily" };
|
|
}
|
|
|
|
// Weekdays: "M H * * 1-5"
|
|
if (month === "*" && dom === "*" && dow === "1-5") {
|
|
return { ...DEFAULT_SCHEDULE, ...base, frequency: "weekdays" };
|
|
}
|
|
|
|
// Weekly: "M H * * 1,3,5"
|
|
if (month === "*" && dom === "*" && /^[0-6](,[0-6])*$/.test(dow)) {
|
|
const daysOfWeek = [...new Set(dow.split(",").map(Number))].sort((a, b) => a - b);
|
|
return { ...DEFAULT_SCHEDULE, ...base, frequency: "weekly", daysOfWeek };
|
|
}
|
|
|
|
// Monthly: "M H D * *"
|
|
if (month === "*" && dow === "*" && isInt(dom)) {
|
|
return { ...DEFAULT_SCHEDULE, ...base, frequency: "monthly", dayOfMonth: Number(dom) };
|
|
}
|
|
|
|
return null;
|
|
}
|