recurring.go 5.2 KB

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