feat(worker): allow update_task_status to set Cancelled
This commit is contained in:
+11
-4
@@ -262,9 +262,10 @@ public sealed class ExternalMcpService
|
||||
}
|
||||
|
||||
[McpServerTool, Description(
|
||||
"Update a task's status. Only 'Idle' and 'Queued' are permitted externally — " +
|
||||
"use run_task_now or cancel_task for execution control, and review_task to act on a WaitingForReview task. " +
|
||||
"Settable: Idle (reset to editable), Queued (enqueue for execution). " +
|
||||
"Update a task's status. Only 'Idle', 'Queued' and 'Cancelled' are permitted externally — " +
|
||||
"use run_task_now for execution control, and review_task to act on a WaitingForReview task. " +
|
||||
"Settable: Idle (reset to editable), Queued (enqueue for execution), " +
|
||||
"Cancelled (retire the task without deleting it; it can be reset to Idle later). " +
|
||||
"Full lifecycle: Idle → Queued → Running → WaitingForReview → Done | Failed | Cancelled.")]
|
||||
public async Task<TaskDto> UpdateTaskStatus(
|
||||
string taskId,
|
||||
@@ -291,9 +292,15 @@ public sealed class ExternalMcpService
|
||||
throw new InvalidOperationException(enqueueResult.Reason ?? "Cannot enqueue task.");
|
||||
break;
|
||||
|
||||
case TaskStatus.Cancelled:
|
||||
var cancelResult = await _state.CancelAsync(taskId, DateTime.UtcNow, cancellationToken, allowFromIdle: true);
|
||||
if (!cancelResult.Ok)
|
||||
throw new InvalidOperationException(cancelResult.Reason ?? "Cannot cancel task.");
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
$"Status '{target}' is not settable externally. Use run_task_now or cancel_task.");
|
||||
$"Status '{target}' is not settable externally. Use run_task_now or review_task.");
|
||||
}
|
||||
|
||||
var reload = (await _tasks.GetByIdAsync(taskId, cancellationToken))!;
|
||||
|
||||
@@ -9,7 +9,7 @@ public interface ITaskStateService
|
||||
Task<TransitionResult> SubmitInteractiveForReviewAsync(string taskId, DateTime finishedAt, CancellationToken ct);
|
||||
Task<TransitionResult> SubmitForChildrenAsync(string taskId, DateTime finishedAt, string? result, CancellationToken ct);
|
||||
Task<TransitionResult> FailAsync(string taskId, DateTime finishedAt, string? error, CancellationToken ct);
|
||||
Task<TransitionResult> CancelAsync(string taskId, DateTime finishedAt, CancellationToken ct);
|
||||
Task<TransitionResult> CancelAsync(string taskId, DateTime finishedAt, CancellationToken ct, bool allowFromIdle = false);
|
||||
Task<TransitionResult> ResetToIdleAsync(string taskId, CancellationToken ct);
|
||||
|
||||
Task<TransitionResult> ApproveReviewAsync(string taskId, CancellationToken ct);
|
||||
|
||||
@@ -241,7 +241,13 @@ public sealed class TaskStateService : ITaskStateService
|
||||
return new TransitionResult(true, null);
|
||||
}
|
||||
|
||||
public async Task<TransitionResult> CancelAsync(string taskId, DateTime finishedAt, CancellationToken ct)
|
||||
// allowFromIdle: only the external update_task_status(Cancelled) path sets this — it lets
|
||||
// an Idle task be retired without deleting it. Every other caller (hub CancelReview,
|
||||
// PlanningChainCoordinator's chain-walk, batch cancel) relies on Idle staying a no-op here;
|
||||
// PlanningChainCoordinator specifically uses "parked back to Idle" as a deliberate opt-out
|
||||
// signal, so do not flip this default.
|
||||
public async Task<TransitionResult> CancelAsync(
|
||||
string taskId, DateTime finishedAt, CancellationToken ct, bool allowFromIdle = false)
|
||||
{
|
||||
List<string> cancelledChildIds;
|
||||
await using (var ctx = await _dbFactory.CreateDbContextAsync(ct))
|
||||
@@ -250,7 +256,8 @@ public sealed class TaskStateService : ITaskStateService
|
||||
.Where(t => t.Id == taskId &&
|
||||
(t.Status == TaskStatus.Running || t.Status == TaskStatus.Queued
|
||||
|| t.Status == TaskStatus.WaitingForReview
|
||||
|| t.Status == TaskStatus.WaitingForChildren))
|
||||
|| t.Status == TaskStatus.WaitingForChildren
|
||||
|| (allowFromIdle && t.Status == TaskStatus.Idle)))
|
||||
.ExecuteUpdateAsync(s => s
|
||||
.SetProperty(t => t.Status, TaskStatus.Cancelled)
|
||||
.SetProperty(t => t.FinishedAt, finishedAt), ct);
|
||||
|
||||
Reference in New Issue
Block a user