summaryrefslogtreecommitdiff
path: root/internal/executor/executor.go
diff options
context:
space:
mode:
authorClaudomator Agent <agent@claudomator>2026-03-12 01:48:15 +0000
committerClaudomator Agent <agent@claudomator>2026-03-12 01:48:15 +0000
commitf28c22352aa1a8ede7552ee0277f7d60552d9094 (patch)
tree02e9085809462e09b7d2a68ebb754e247eaecd22 /internal/executor/executor.go
parent4f83d35fa47bc71b31e0f92a0927bea8910c01b6 (diff)
feat: add Resume support for CANCELLED, FAILED, and BUDGET_EXCEEDED tasks
Interrupted tasks (CANCELLED, FAILED, BUDGET_EXCEEDED) now support session resume in addition to restart. Both buttons are shown on the task card. - executor: extend resumablePoolStates to include CANCELLED, FAILED, BUDGET_EXCEEDED - api: extend handleResumeTimedOutTask to accept all resumable states with state-specific resume messages; replace hard-coded TIMED_OUT check with a resumableStates map - web: add RESUME_STATES set; render Resume + Restart buttons for interrupted states; TIMED_OUT keeps Resume only - tests: 5 new Go tests (TestResumeInterrupted_*); updated task-actions.test.mjs with 17 tests covering dual-button behaviour Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/executor/executor.go')
-rw-r--r--internal/executor/executor.go26
1 files changed, 23 insertions, 3 deletions
diff --git a/internal/executor/executor.go b/internal/executor/executor.go
index 76c8ac7..bafacd2 100644
--- a/internal/executor/executor.go
+++ b/internal/executor/executor.go
@@ -26,6 +26,8 @@ type Store interface {
UpdateExecution(e *storage.Execution) error
UpdateTaskState(id string, newState task.State) error
UpdateTaskQuestion(taskID, questionJSON string) error
+ UpdateTaskSummary(taskID, summary string) error
+ AppendTaskInteraction(taskID string, interaction task.Interaction) error
}
// LogPather is an optional interface runners can implement to provide the log
@@ -149,11 +151,20 @@ func (p *Pool) Cancel(taskID string) bool {
return true
}
-// SubmitResume re-queues a blocked task using the provided resume execution.
+// resumablePoolStates are the task states that may be submitted for session resume.
+var resumablePoolStates = map[task.State]bool{
+ task.StateBlocked: true,
+ task.StateTimedOut: true,
+ task.StateCancelled: true,
+ task.StateFailed: true,
+ task.StateBudgetExceeded: true,
+}
+
+// SubmitResume re-queues a blocked or interrupted task using the provided resume execution.
// The execution must have ResumeSessionID and ResumeAnswer set.
func (p *Pool) SubmitResume(ctx context.Context, t *task.Task, exec *storage.Execution) error {
- if t.State != task.StateBlocked && t.State != task.StateTimedOut {
- return fmt.Errorf("task %s must be in BLOCKED or TIMED_OUT state to resume (current: %s)", t.ID, t.State)
+ if !resumablePoolStates[t.State] {
+ return fmt.Errorf("task %s must be in a resumable state to resume (current: %s)", t.ID, t.State)
}
if exec.ResumeSessionID == "" {
return fmt.Errorf("resume execution for task %s must have a ResumeSessionID", t.ID)
@@ -331,6 +342,15 @@ func (p *Pool) handleRunResult(ctx context.Context, t *task.Task, exec *storage.
}
}
+ summary := exec.Summary
+ if summary == "" && exec.StdoutPath != "" {
+ summary = extractSummary(exec.StdoutPath)
+ }
+ if summary != "" {
+ if summaryErr := p.store.UpdateTaskSummary(t.ID, summary); summaryErr != nil {
+ p.logger.Error("failed to update task summary", "taskID", t.ID, "error", summaryErr)
+ }
+ }
if updateErr := p.store.UpdateExecution(exec); updateErr != nil {
p.logger.Error("failed to update execution", "error", updateErr)
}