mirror of
https://github.com/cheikh2shift/godex.git
synced 2026-10-21 02:29:56 -05:00
Implement schedule command enhancements and output handling for scheduled tasks
This commit is contained in:
1 parent
6e1398fd8f
commit
f71e0c5931
5 files changed
+116
-30
No files matched your search
+2
-1
@@ -985,7 +985,8 @@ promptLoop:
|
||||
|
||||
fmt.Printf("[Round %d/%d] Got %d tool calls, isToolCallResponse=%v\n", round+1, maxToolRounds, len(toolCalls), isToolCallResponse)
|
||||
|
||||
if len(toolCalls) > 0 && isToolCallResponse {
|
||||
totalToolCalls := len(toolCalls) + len(missingTools)
|
||||
if totalToolCalls > 0 && isToolCallResponse {
|
||||
prevNoTool = false
|
||||
}
|
||||
if !isToolCallResponse || len(toolCalls) == 0 {
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/cheikh2shift/godex/internal/history"
|
||||
"github.com/cheikh2shift/godex/internal/hive"
|
||||
"github.com/cheikh2shift/godex/internal/scheduler"
|
||||
)
|
||||
|
||||
var ErrPromptAborted = errors.New("prompt aborted")
|
||||
@@ -74,6 +75,7 @@ type promptModel struct {
|
||||
searchResults []string
|
||||
statusMessage string
|
||||
commitList []string
|
||||
scheduleList []string
|
||||
statusCh <-chan string
|
||||
delegateCh <-chan hive.HiveStats
|
||||
delegateCount int
|
||||
@@ -550,6 +552,11 @@ func (m *promptModel) handleTab() {
|
||||
return
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(value, "/schedule ") && strings.Contains(value, " ") {
|
||||
if m.handleScheduleTab(value) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if value != "" && !strings.HasPrefix(value, "/") {
|
||||
return
|
||||
}
|
||||
@@ -589,6 +596,46 @@ func (m *promptModel) handleTab() {
|
||||
m.showCompletions = true
|
||||
}
|
||||
|
||||
func (m *promptModel) handleScheduleTab(value string) bool {
|
||||
parts := strings.Fields(value)
|
||||
if len(parts) != 2 {
|
||||
return false
|
||||
}
|
||||
prefix := strings.ToUpper(parts[1])
|
||||
if sched == nil {
|
||||
return false
|
||||
}
|
||||
tasks := sched.ListTasks()
|
||||
if len(tasks) == 0 {
|
||||
return false
|
||||
}
|
||||
var matches []string
|
||||
for _, t := range tasks {
|
||||
task, ok := t.(*scheduler.ScheduledTask)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(task.ID, prefix) {
|
||||
matches = append(matches, task.ID)
|
||||
}
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
return false
|
||||
}
|
||||
if len(matches) == 1 && prefix != "" {
|
||||
m.input.SetValue("/schedule " + matches[0])
|
||||
m.input.SetCursor(len([]rune(m.input.Value())))
|
||||
m.resetCompletion()
|
||||
return true
|
||||
}
|
||||
m.scheduleList = nil
|
||||
for _, id := range matches {
|
||||
m.scheduleList = append(m.scheduleList, id)
|
||||
}
|
||||
m.resetCompletion()
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *promptModel) handleCommitPullTab(value string) bool {
|
||||
if m.historyDB == nil {
|
||||
return false
|
||||
|
||||
+35
-11
@@ -23,7 +23,7 @@ func (s *schedulerProviderGetter) GetProvider(cfg interface{}) (interface{}, err
|
||||
providerName, _ := cfgMap["name"].(string)
|
||||
providerModel, _ := cfgMap["model"].(string)
|
||||
|
||||
if providerType == "unknown" && s.provider != nil {
|
||||
if (providerType == "unknown" || providerType == "current") && s.provider != nil {
|
||||
providerType = s.provider.Type
|
||||
providerName = s.provider.Name
|
||||
providerModel = s.provider.Model
|
||||
@@ -37,7 +37,6 @@ func (s *schedulerProviderGetter) GetProvider(cfg interface{}) (interface{}, err
|
||||
}
|
||||
|
||||
func handleSchedule(input string) {
|
||||
|
||||
if sched == nil {
|
||||
fmt.Println("[Scheduler] Not initialized")
|
||||
return
|
||||
@@ -49,11 +48,32 @@ func handleSchedule(input string) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(parts) == 2 && len(parts[1]) == 4 {
|
||||
id := strings.ToUpper(parts[1])
|
||||
task := sched.GetTask(id)
|
||||
if task == nil {
|
||||
fmt.Printf("Task %s not found\n", id)
|
||||
return
|
||||
}
|
||||
st, ok := task.(*scheduler.ScheduledTask)
|
||||
if !ok {
|
||||
fmt.Printf("Task %s not found\n", id)
|
||||
return
|
||||
}
|
||||
if st.LastOutput == "" {
|
||||
fmt.Printf("No output for task %s\n", id)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Output for task %s:\n%s\n", id, st.LastOutput)
|
||||
return
|
||||
}
|
||||
|
||||
if len(parts) >= 2 && (parts[1] == "help" || parts[1] == "-h" || parts[1] == "--help") {
|
||||
fmt.Println("Scheduler - Schedule prompts to run at specific times or intervals")
|
||||
fmt.Println("")
|
||||
fmt.Println("Usage:")
|
||||
fmt.Println(" /schedule - List all scheduled tasks")
|
||||
fmt.Println(" /schedule <id> - Show last output of a task")
|
||||
fmt.Println(" /schedule stop <id> - Stop a running task by 4-char ID")
|
||||
fmt.Println(" /schedule remove <id> - Remove a task from the schedule by 4-char ID")
|
||||
fmt.Println(" /schedule help - Show this help message")
|
||||
@@ -100,6 +120,7 @@ func handleSchedule(input string) {
|
||||
|
||||
fmt.Println("Usage:")
|
||||
fmt.Println(" /schedule - List all scheduled tasks")
|
||||
fmt.Println(" /schedule <id> - Show last output of a task")
|
||||
fmt.Println(" /schedule stop <id> - Stop a task by 4-char ID")
|
||||
fmt.Println(" /schedule remove <id> - Remove a task by 4-char ID")
|
||||
}
|
||||
@@ -111,8 +132,8 @@ func listScheduledTasks() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\n%-6s %-12s %-10s %-8s %-8s %s\n", "ID", "Created", "Interval", "Runs", "Last Run", "Status")
|
||||
fmt.Println(strings.Repeat("-", 80))
|
||||
fmt.Printf("\n%-6s %-8s %-8s %-8s %s\n", "ID", "Runs", "Interval", "Last Run", "Output")
|
||||
fmt.Println(strings.Repeat("-", 70))
|
||||
|
||||
for _, t := range tasks {
|
||||
task, ok := t.(*scheduler.ScheduledTask)
|
||||
@@ -127,21 +148,24 @@ func listScheduledTasks() {
|
||||
|
||||
lastRun := "Never"
|
||||
if !task.LastRun.IsZero() {
|
||||
lastRun = task.LastRun.Format("2006-01-02 15:04")
|
||||
lastRun = task.LastRun.Format("15:04")
|
||||
}
|
||||
|
||||
status := "OK"
|
||||
output := "OK"
|
||||
if task.LastError != "" {
|
||||
status = truncate(task.LastError, 30)
|
||||
output = truncate(task.LastError, 40)
|
||||
} else if task.LastOutput != "" {
|
||||
lines := strings.Split(task.LastOutput, "\n")
|
||||
lastLine := strings.TrimSpace(lines[len(lines)-1])
|
||||
output = truncate(lastLine, 40)
|
||||
}
|
||||
|
||||
fmt.Printf("%-6s %-12s %-10s %-8d %-8s %s\n",
|
||||
fmt.Printf("%-6s %-8d %-8s %-8s %s\n",
|
||||
task.ID,
|
||||
task.CreatedAt.Format("2006-01-02"),
|
||||
interval,
|
||||
task.RunCount,
|
||||
interval,
|
||||
lastRun,
|
||||
status,
|
||||
output,
|
||||
)
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
@@ -71,7 +71,7 @@ func (s *SchedulerServer) Tools() []Tool {
|
||||
currentTime := time.Now().Format("2006-01-02 15:04:05")
|
||||
return []Tool{
|
||||
{
|
||||
Name: "schedule_task",
|
||||
Name: "scheduler",
|
||||
Description: fmt.Sprintf("Schedule a task to run a prompt at a specific time or at regular intervals. Current time: %s. Use interval_sec for repeating tasks (e.g., 60 for every minute, 3600 for every hour), or run_at for specific times (e.g., \"14:30\" for 2:30 PM daily, or \"now\" to execute immediately).", currentTime),
|
||||
InputSchema: json.RawMessage(`{
|
||||
"type": "object",
|
||||
@@ -96,7 +96,7 @@ func (s *SchedulerServer) Tools() []Tool {
|
||||
}
|
||||
|
||||
func (s *SchedulerServer) CallTool(ctx context.Context, name string, args map[string]interface{}) (string, error) {
|
||||
if name != "schedule_task" {
|
||||
if name != "scheduler" {
|
||||
return "", fmt.Errorf("unknown tool: %s", name)
|
||||
}
|
||||
|
||||
@@ -108,6 +108,8 @@ func (s *SchedulerServer) CallTool(ctx context.Context, name string, args map[st
|
||||
intervalSec := 0
|
||||
if iv, ok := args["interval_sec"].(float64); ok {
|
||||
intervalSec = int(iv)
|
||||
} else if iv, ok := args["run_every"].(float64); ok {
|
||||
intervalSec = int(iv)
|
||||
}
|
||||
|
||||
runAt := ""
|
||||
@@ -122,14 +124,14 @@ func (s *SchedulerServer) CallTool(ctx context.Context, name string, args map[st
|
||||
}
|
||||
|
||||
if isNow {
|
||||
result, err := s.scheduler.scheduler.RunNow(prompt, "unknown", "unknown", "unknown")
|
||||
result, err := s.scheduler.scheduler.RunNow(prompt, "current", "current", "current")
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error running task: %v", err), nil
|
||||
}
|
||||
return fmt.Sprintf("Task executed immediately.\n\nResult:\n%s", result), nil
|
||||
}
|
||||
|
||||
task, err := s.scheduler.scheduler.AddTask(prompt, intervalSec, runAt, "unknown", "unknown", "unknown")
|
||||
task, err := s.scheduler.scheduler.AddTask(prompt, intervalSec, runAt, "current", "current", "current")
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Error scheduling task: %v", err), nil
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ type ScheduledTask struct {
|
||||
LastRun time.Time `json:"last_run"`
|
||||
RunCount int `json:"run_count"`
|
||||
LastError string `json:"last_error"`
|
||||
LastOutput string `json:"last_output"`
|
||||
ProviderType string `json:"provider_type"`
|
||||
ProviderName string `json:"provider_name"`
|
||||
ProviderModel string `json:"provider_model"`
|
||||
@@ -112,6 +113,7 @@ func (s *Scheduler) initSchema() error {
|
||||
last_run TEXT,
|
||||
run_count INTEGER DEFAULT 0,
|
||||
last_error TEXT,
|
||||
last_output TEXT,
|
||||
provider_type TEXT NOT NULL,
|
||||
provider_name TEXT NOT NULL,
|
||||
provider_model TEXT NOT NULL
|
||||
@@ -125,7 +127,7 @@ func (s *Scheduler) initSchema() error {
|
||||
func (s *Scheduler) loadTasks() error {
|
||||
rows, err := s.db.Query(`
|
||||
SELECT id, prompt, interval_sec, run_at, is_repeating, created_at,
|
||||
last_run, run_count, last_error, provider_type, provider_name, provider_model
|
||||
last_run, run_count, last_error, last_output, provider_type, provider_name, provider_model
|
||||
FROM scheduled_tasks
|
||||
`)
|
||||
if err != nil {
|
||||
@@ -135,10 +137,10 @@ func (s *Scheduler) loadTasks() error {
|
||||
|
||||
for rows.Next() {
|
||||
var task ScheduledTask
|
||||
var lastRun, createdAt, runAt sql.NullString
|
||||
var lastRun, createdAt, runAt, lastOutput sql.NullString
|
||||
err := rows.Scan(
|
||||
&task.ID, &task.Prompt, &task.IntervalSec, &runAt, &task.IsRepeating,
|
||||
&createdAt, &lastRun, &task.RunCount, &task.LastError,
|
||||
&createdAt, &lastRun, &task.RunCount, &task.LastError, &lastOutput,
|
||||
&task.ProviderType, &task.ProviderName, &task.ProviderModel,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -153,6 +155,9 @@ func (s *Scheduler) loadTasks() error {
|
||||
if runAt.Valid {
|
||||
task.RunAt = runAt.String
|
||||
}
|
||||
if lastOutput.Valid {
|
||||
task.LastOutput = lastOutput.String
|
||||
}
|
||||
s.tasks[task.ID] = &task
|
||||
}
|
||||
return rows.Err()
|
||||
@@ -257,11 +262,11 @@ func (s *Scheduler) RunNow(prompt string, providerType, providerName, providerMo
|
||||
func (s *Scheduler) saveTask(task *ScheduledTask) error {
|
||||
_, err := s.db.Exec(`
|
||||
INSERT OR REPLACE INTO scheduled_tasks
|
||||
(id, prompt, interval_sec, run_at, is_repeating, created_at, last_run, run_count, last_error, provider_type, provider_name, provider_model)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
(id, prompt, interval_sec, run_at, is_repeating, created_at, last_run, run_count, last_error, last_output, provider_type, provider_name, provider_model)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`, task.ID, task.Prompt, task.IntervalSec, task.RunAt, task.IsRepeating,
|
||||
task.CreatedAt.Format(time.RFC3339), task.LastRun.Format(time.RFC3339),
|
||||
task.RunCount, task.LastError, task.ProviderType, task.ProviderName, task.ProviderModel)
|
||||
task.RunCount, task.LastError, task.LastOutput, task.ProviderType, task.ProviderName, task.ProviderModel)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -321,14 +326,19 @@ func (s *Scheduler) executeTask(task *ScheduledTask) {
|
||||
return
|
||||
}
|
||||
|
||||
cfg := &struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Model string `json:"model"`
|
||||
}{
|
||||
Type: task.ProviderType,
|
||||
Name: task.ProviderName,
|
||||
Model: task.ProviderModel,
|
||||
var cfg interface{}
|
||||
if task.ProviderType == "unknown" || task.ProviderType == "" {
|
||||
cfg = map[string]interface{}{
|
||||
"type": "current",
|
||||
"name": "current",
|
||||
"model": "current",
|
||||
}
|
||||
} else {
|
||||
cfg = map[string]interface{}{
|
||||
"type": task.ProviderType,
|
||||
"name": task.ProviderName,
|
||||
"model": task.ProviderModel,
|
||||
}
|
||||
}
|
||||
|
||||
prov, err := s.provider.GetProvider(cfg)
|
||||
@@ -355,8 +365,10 @@ func (s *Scheduler) executeTask(task *ScheduledTask) {
|
||||
result, err := provInterface.Send(taskCtx, task.Prompt)
|
||||
if err != nil {
|
||||
task.LastError = fmt.Sprintf("execution error: %v", err)
|
||||
task.LastOutput = ""
|
||||
} else {
|
||||
task.LastError = ""
|
||||
task.LastOutput = result
|
||||
fmt.Printf("[Scheduler %s] Result: %s\n", task.ID, truncate(result, 200))
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user