mirror of
https://github.com/mudler/LocalAGI.git
synced 2026-07-23 18:55:52 -04:00
269 lines
7.5 KiB
Go
269 lines
7.5 KiB
Go
package action
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mudler/LocalAGI/core/scheduler"
|
|
"github.com/mudler/LocalAGI/core/types"
|
|
"github.com/sashabaranov/go-openai/jsonschema"
|
|
)
|
|
|
|
const (
|
|
RecurringReminderActionName = "set_recurring_task"
|
|
OneTimeReminderActionName = "set_onetime_task"
|
|
ListRemindersName = "list_tasks"
|
|
RemoveReminderName = "remove_task"
|
|
)
|
|
|
|
func NewRecurringReminder() *RecurringReminderAction {
|
|
return &RecurringReminderAction{}
|
|
}
|
|
|
|
func NewOneTimeReminder() *OneTimeReminderAction {
|
|
return &OneTimeReminderAction{}
|
|
}
|
|
|
|
func NewListReminders() *ListRemindersAction {
|
|
return &ListRemindersAction{}
|
|
}
|
|
|
|
func NewRemoveReminder() *RemoveReminderAction {
|
|
return &RemoveReminderAction{}
|
|
}
|
|
|
|
type RecurringReminderAction struct{}
|
|
type OneTimeReminderAction struct{}
|
|
type ListRemindersAction struct{}
|
|
type RemoveReminderAction struct{}
|
|
|
|
type RemoveReminderParams struct {
|
|
Index int `json:"index"`
|
|
}
|
|
|
|
func (a *RecurringReminderAction) Run(ctx context.Context, sharedState *types.AgentSharedState, params types.ActionParams) (types.ActionResult, error) {
|
|
result := types.RecurringReminderParams{}
|
|
err := params.Unmarshal(&result)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
task, err := scheduler.NewTask(
|
|
sharedState.AgentName,
|
|
result.Message,
|
|
scheduler.ScheduleTypeCron,
|
|
result.CronExpr,
|
|
)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
task.Metadata["reminder_type"] = "user_created"
|
|
|
|
err = sharedState.Scheduler.CreateTask(task)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
return types.ActionResult{
|
|
Result: fmt.Sprintf("Recurring reminder set successfully (ID: %s). Next run: %s", task.ID, task.NextRun.Format(time.RFC3339)),
|
|
Metadata: map[string]interface{}{
|
|
"task_id": task.ID,
|
|
"message": result.Message,
|
|
"next_run": task.NextRun,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (a *OneTimeReminderAction) Run(ctx context.Context, sharedState *types.AgentSharedState, params types.ActionParams) (types.ActionResult, error) {
|
|
result := types.OneTimeReminderParams{}
|
|
err := params.Unmarshal(&result)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
// Validate the delay parses correctly before creating the task
|
|
_, err = scheduler.ParseDuration(result.Delay)
|
|
if err != nil {
|
|
return types.ActionResult{}, fmt.Errorf("invalid delay format, expected a duration like '30m', '2h', '1d', '1d12h': %w", err)
|
|
}
|
|
|
|
task, err := scheduler.NewTask(
|
|
sharedState.AgentName,
|
|
result.Message,
|
|
scheduler.ScheduleTypeOnce,
|
|
result.Delay,
|
|
)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
task.Metadata["reminder_type"] = "user_created"
|
|
|
|
err = sharedState.Scheduler.CreateTask(task)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
return types.ActionResult{
|
|
Result: fmt.Sprintf("One-time reminder set in %s (at %s, ID: %s)", result.Delay, task.NextRun.Format(time.RFC3339), task.ID),
|
|
Metadata: map[string]interface{}{
|
|
"task_id": task.ID,
|
|
"message": result.Message,
|
|
"next_run": task.NextRun,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (a *ListRemindersAction) Run(ctx context.Context, sharedState *types.AgentSharedState, params types.ActionParams) (types.ActionResult, error) {
|
|
tasks, err := sharedState.Scheduler.GetAllTasks()
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
if len(tasks) == 0 {
|
|
return types.ActionResult{
|
|
Result: "No reminders set",
|
|
}, nil
|
|
}
|
|
|
|
var result strings.Builder
|
|
result.WriteString("Current reminders:\n")
|
|
|
|
for i, task := range tasks {
|
|
status := "one-time"
|
|
if task.ScheduleType == scheduler.ScheduleTypeCron || task.ScheduleType == scheduler.ScheduleTypeInterval {
|
|
status = "recurring"
|
|
}
|
|
|
|
result.WriteString(fmt.Sprintf("%d. %s (Next run: %s, Status: %s, ID: %s)\n",
|
|
i+1,
|
|
task.Prompt,
|
|
task.NextRun.Format(time.RFC3339),
|
|
status,
|
|
task.ID))
|
|
}
|
|
|
|
return types.ActionResult{
|
|
Result: result.String(),
|
|
Metadata: map[string]interface{}{
|
|
"tasks": tasks,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (a *RemoveReminderAction) Run(ctx context.Context, sharedState *types.AgentSharedState, params types.ActionParams) (types.ActionResult, error) {
|
|
var removeParams RemoveReminderParams
|
|
err := params.Unmarshal(&removeParams)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
tasks, err := sharedState.Scheduler.GetAllTasks()
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
if len(tasks) == 0 {
|
|
return types.ActionResult{
|
|
Result: "No reminders to remove",
|
|
}, nil
|
|
}
|
|
|
|
// Convert from 1-based index to 0-based
|
|
index := removeParams.Index - 1
|
|
if index < 0 || index >= len(tasks) {
|
|
return types.ActionResult{}, fmt.Errorf("invalid reminder index: %d", removeParams.Index)
|
|
}
|
|
|
|
task := tasks[index]
|
|
err = sharedState.Scheduler.DeleteTask(task.ID)
|
|
if err != nil {
|
|
return types.ActionResult{}, err
|
|
}
|
|
|
|
return types.ActionResult{
|
|
Result: fmt.Sprintf("Removed reminder: %s", task.Prompt),
|
|
Metadata: map[string]interface{}{
|
|
"removed_task_id": task.ID,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (a *RecurringReminderAction) Plannable() bool {
|
|
return true
|
|
}
|
|
|
|
func (a *OneTimeReminderAction) Plannable() bool {
|
|
return true
|
|
}
|
|
|
|
func (a *ListRemindersAction) Plannable() bool {
|
|
return true
|
|
}
|
|
|
|
func (a *RemoveReminderAction) Plannable() bool {
|
|
return true
|
|
}
|
|
|
|
func (a *RecurringReminderAction) Definition() types.ActionDefinition {
|
|
return types.ActionDefinition{
|
|
Name: RecurringReminderActionName,
|
|
Description: "Set a recurring reminder for the agent to wake up and perform a task on a cron schedule. The reminder will keep repeating. Examples: '0 0 * * *' (daily at midnight), '0 */2 * * *' (every 2 hours), '0 0 * * 1' (every Monday at midnight)",
|
|
Properties: map[string]jsonschema.Definition{
|
|
"message": {
|
|
Type: jsonschema.String,
|
|
Description: "The message or task to be reminded about",
|
|
},
|
|
"cron_expr": {
|
|
Type: jsonschema.String,
|
|
Description: "Cron expression for scheduling (e.g. '0 0 * * *' for daily at midnight). Format: 'minute hour day month weekday'",
|
|
},
|
|
},
|
|
Required: []string{"message", "cron_expr"},
|
|
}
|
|
}
|
|
|
|
func (a *OneTimeReminderAction) Definition() types.ActionDefinition {
|
|
return types.ActionDefinition{
|
|
Name: OneTimeReminderActionName,
|
|
Description: "Set a one-time reminder for the agent to wake up and perform a task after a delay. The reminder triggers only once and is then automatically removed. Use this when asked to do something 'in X minutes/hours/days'. Examples: '30m' (30 minutes), '2h' (2 hours), '1d' (1 day), '1d12h' (1.5 days), '2h30m' (2.5 hours)",
|
|
Properties: map[string]jsonschema.Definition{
|
|
"message": {
|
|
Type: jsonschema.String,
|
|
Description: "The message or task to be reminded about",
|
|
},
|
|
"delay": {
|
|
Type: jsonschema.String,
|
|
Description: "How long to wait before triggering. Use Go duration format: '30m' (30 minutes), '2h' (2 hours), '1d' (1 day), '1d12h' (1.5 days), '2h30m' (2.5 hours)",
|
|
},
|
|
},
|
|
Required: []string{"message", "delay"},
|
|
}
|
|
}
|
|
|
|
func (a *ListRemindersAction) Definition() types.ActionDefinition {
|
|
return types.ActionDefinition{
|
|
Name: ListRemindersName,
|
|
Description: "List all currently set reminders with their next scheduled run times",
|
|
Properties: map[string]jsonschema.Definition{},
|
|
Required: []string{},
|
|
}
|
|
}
|
|
|
|
func (a *RemoveReminderAction) Definition() types.ActionDefinition {
|
|
return types.ActionDefinition{
|
|
Name: RemoveReminderName,
|
|
Description: "Remove a reminder by its index number (use list_reminders to see the index)",
|
|
Properties: map[string]jsonschema.Definition{
|
|
"index": {
|
|
Type: jsonschema.Integer,
|
|
Description: "The index number of the reminder to remove (1-based)",
|
|
},
|
|
},
|
|
Required: []string{"index"},
|
|
}
|
|
}
|