recurring.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package cmd
  2. import (
  3. "fmt"
  4. "os"
  5. "github.com/fatih/color"
  6. "github.com/letta/letta-schedules-cli/internal/client"
  7. "github.com/letta/letta-schedules-cli/internal/config"
  8. "github.com/letta/letta-schedules-cli/internal/parser"
  9. "github.com/olekukonko/tablewriter"
  10. "github.com/spf13/cobra"
  11. )
  12. var recurringCmd = &cobra.Command{
  13. Use: "recurring",
  14. Short: "Manage recurring schedules",
  15. Long: "Create, list, view, and delete recurring schedules for Letta agents",
  16. }
  17. var recurringCreateCmd = &cobra.Command{
  18. Use: "create",
  19. Short: "Create a new recurring schedule",
  20. RunE: func(cmd *cobra.Command, args []string) error {
  21. agentID, _ := cmd.Flags().GetString("agent-id")
  22. message, _ := cmd.Flags().GetString("message")
  23. role, _ := cmd.Flags().GetString("role")
  24. cronString, _ := cmd.Flags().GetString("cron")
  25. if agentID == "" || message == "" || cronString == "" {
  26. return fmt.Errorf("agent-id, message, and cron are required")
  27. }
  28. // Parse natural language to cron expression
  29. parsedCron, err := parser.ParseCron(cronString)
  30. if err != nil {
  31. return fmt.Errorf("failed to parse cron: %w", err)
  32. }
  33. cfg, err := config.Load()
  34. if err != nil {
  35. return err
  36. }
  37. if err := cfg.Validate(); err != nil {
  38. return err
  39. }
  40. apiClient := client.NewClient(cfg.BaseURL, cfg.APIKey)
  41. schedule, err := apiClient.CreateRecurringSchedule(client.RecurringScheduleCreate{
  42. AgentID: agentID,
  43. Message: message,
  44. Role: role,
  45. CronString: parsedCron,
  46. })
  47. if err != nil {
  48. return fmt.Errorf("failed to create schedule: %w", err)
  49. }
  50. color.Green("✓ Recurring schedule created successfully")
  51. fmt.Printf("\nSchedule ID: %s\n", schedule.ID)
  52. fmt.Printf("Agent ID: %s\n", schedule.AgentID)
  53. fmt.Printf("Cron: %s\n", schedule.CronString)
  54. fmt.Printf("Message: %s\n", schedule.Message)
  55. return nil
  56. },
  57. }
  58. var recurringListCmd = &cobra.Command{
  59. Use: "list",
  60. Short: "List all recurring schedules",
  61. RunE: func(cmd *cobra.Command, args []string) error {
  62. cfg, err := config.Load()
  63. if err != nil {
  64. return err
  65. }
  66. if err := cfg.Validate(); err != nil {
  67. return err
  68. }
  69. apiClient := client.NewClient(cfg.BaseURL, cfg.APIKey)
  70. schedules, err := apiClient.ListRecurringSchedules()
  71. if err != nil {
  72. return fmt.Errorf("failed to list schedules: %w", err)
  73. }
  74. if len(schedules) == 0 {
  75. fmt.Println("No recurring schedules found")
  76. return nil
  77. }
  78. table := tablewriter.NewWriter(os.Stdout)
  79. table.SetHeader([]string{"Schedule ID", "Agent ID", "Cron", "Message", "Last Run"})
  80. table.SetAutoWrapText(false)
  81. table.SetAutoFormatHeaders(true)
  82. table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
  83. table.SetAlignment(tablewriter.ALIGN_LEFT)
  84. table.SetCenterSeparator("")
  85. table.SetColumnSeparator("")
  86. table.SetRowSeparator("")
  87. table.SetHeaderLine(false)
  88. table.SetBorder(false)
  89. table.SetTablePadding("\t")
  90. table.SetNoWhiteSpace(true)
  91. for _, s := range schedules {
  92. lastRun := "never"
  93. if s.LastRun != nil && *s.LastRun != "" {
  94. lastRun = *s.LastRun
  95. }
  96. table.Append([]string{
  97. s.ID,
  98. s.AgentID,
  99. s.CronString,
  100. truncate(s.Message, 50),
  101. lastRun,
  102. })
  103. }
  104. table.Render()
  105. return nil
  106. },
  107. }
  108. var recurringGetCmd = &cobra.Command{
  109. Use: "get [schedule-id]",
  110. Short: "Get details of a recurring schedule",
  111. Args: cobra.ExactArgs(1),
  112. RunE: func(cmd *cobra.Command, args []string) error {
  113. scheduleID := args[0]
  114. cfg, err := config.Load()
  115. if err != nil {
  116. return err
  117. }
  118. if err := cfg.Validate(); err != nil {
  119. return err
  120. }
  121. apiClient := client.NewClient(cfg.BaseURL, cfg.APIKey)
  122. schedule, err := apiClient.GetRecurringSchedule(scheduleID)
  123. if err != nil {
  124. return fmt.Errorf("failed to get schedule: %w", err)
  125. }
  126. fmt.Printf("Schedule ID: %s\n", schedule.ID)
  127. fmt.Printf("Agent ID: %s\n", schedule.AgentID)
  128. fmt.Printf("Cron: %s\n", schedule.CronString)
  129. fmt.Printf("Message: %s\n", schedule.Message)
  130. fmt.Printf("Role: %s\n", schedule.Role)
  131. if schedule.LastRun != nil {
  132. fmt.Printf("Last Run: %s\n", *schedule.LastRun)
  133. } else {
  134. fmt.Printf("Last Run: never\n")
  135. }
  136. fmt.Printf("Created At: %s\n", schedule.CreatedAt.Format("2006-01-02 15:04:05"))
  137. return nil
  138. },
  139. }
  140. var recurringDeleteCmd = &cobra.Command{
  141. Use: "delete [schedule-id]",
  142. Short: "Delete a recurring schedule",
  143. Args: cobra.ExactArgs(1),
  144. RunE: func(cmd *cobra.Command, args []string) error {
  145. scheduleID := args[0]
  146. cfg, err := config.Load()
  147. if err != nil {
  148. return err
  149. }
  150. if err := cfg.Validate(); err != nil {
  151. return err
  152. }
  153. apiClient := client.NewClient(cfg.BaseURL, cfg.APIKey)
  154. if err := apiClient.DeleteRecurringSchedule(scheduleID); err != nil {
  155. return fmt.Errorf("failed to delete schedule: %w", err)
  156. }
  157. color.Green("✓ Schedule deleted successfully")
  158. return nil
  159. },
  160. }
  161. func init() {
  162. rootCmd.AddCommand(recurringCmd)
  163. recurringCmd.AddCommand(recurringCreateCmd)
  164. recurringCreateCmd.Flags().String("agent-id", "", "Agent ID (required)")
  165. recurringCreateCmd.Flags().String("message", "", "Message to send (required)")
  166. recurringCreateCmd.Flags().String("role", "user", "Message role (default: user)")
  167. recurringCreateCmd.Flags().String("cron", "", "Schedule pattern (required)\n Examples: 'every 5 minutes', 'daily at 9am', 'every monday at 3pm', '*/5 * * * *'")
  168. recurringCmd.AddCommand(recurringListCmd)
  169. recurringCmd.AddCommand(recurringGetCmd)
  170. recurringCmd.AddCommand(recurringDeleteCmd)
  171. }
  172. func truncate(s string, maxLen int) string {
  173. if len(s) <= maxLen {
  174. return s
  175. }
  176. return s[:maxLen-3] + "..."
  177. }