diff --git a/.changeset/fn-6875-allow-unpause-assigned.md b/.changeset/fn-6875-allow-unpause-assigned.md new file mode 100644 index 0000000000..dd46c7c5da --- /dev/null +++ b/.changeset/fn-6875-allow-unpause-assigned.md @@ -0,0 +1,5 @@ +--- +"@runfusion/fusion": minor +--- + +Allow users to manually pause and unpause agent-assigned tasks from the dashboard task detail view and API. diff --git a/docs/agents.md b/docs/agents.md index e506d82beb..94c89dad47 100644 --- a/docs/agents.md +++ b/docs/agents.md @@ -152,7 +152,7 @@ Approval pause/resume lifecycle (FN-3548): - Permanent-agent gating short-circuits `block` and `require-approval` actions before tool execution and returns structured non-success tool results. - For `require-approval`, the engine creates/reuses a durable approval request and pauses execution with canonical `pauseReason: "awaiting-approval"`. -- If task-backed, the owning task is paused (`Task.paused=true`, `pausedByAgentId=`); the requesting agent is paused (`state="paused"`, `pauseReason="awaiting-approval"`). +- If task-backed, the owning task is paused (`Task.paused=true`, `pausedByAgentId=`); the requesting agent is paused (`state="paused"`, `pauseReason="awaiting-approval"`). The task-detail **Paused by agent** indicator is context only: operators may still manually pause or unpause an agent-assigned task, and unpause clears the task pause latch. - Dedupe semantics by `approvalDedupeKey`: `pending` reuses the same request, `approved` allows exactly one execution and then marks request `completed`, `denied` stays blocked, `completed` requires a fresh request. - HTTP decision endpoint resumes best-effort: `POST /api/approvals/:id/decision` with `{ decision: "approve" | "deny", comment? }` unpauses matching task/agent when they are paused for `awaiting-approval`. - Approval API surface: `GET /api/approvals` (supports status/limit/offset and returns `{ requests, total, pendingCount }`), `GET /api/approvals/:id` (includes request context + audit/history), `POST /api/approvals/:id/decision`. diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md index 0eb5393afd..34d12d69b2 100644 --- a/docs/dashboard-guide.md +++ b/docs/dashboard-guide.md @@ -813,6 +813,7 @@ Inspect task definition, logs, review feedback, comments, documents, workflow ou - Execution mode has a read-mode inline lightning-bolt toggle for Fast mode on/off without opening the full edit form. - These two metadata controls share matched sizing/alignment in read mode (including mobile wrapping) so they behave like a single polished control group. - Task metadata keeps priority, execution mode, provenance, optional PR context, and compact `Created` / `Updated` timestamps in one wrapping row across desktop and mobile widths; recent timestamps render as relative time (`just now`, `Xm`, `Xh`, `Xd`) and older values switch to short month/day dates. +- The **Actions** menu exposes **Pause** / **Unpause** for eligible non-terminal tasks, including tasks assigned to agents. If a task was paused by an agent, the **Paused by agent** note is informational; users can still unpause it manually from the same menu. - Eligible existing tasks (triage, todo, in-progress, in-review) expose a **GitHub tracking** section directly in Task Detail, even when tracking is currently disabled. - The GitHub tracking section now defaults to a compact summary row; use the disclosure arrow to expand linked-issue details plus tracking edit controls. - Backstop reconciliation runs every 15 minutes to close tracked GitHub issues for soft-deleted and archived tasks even after restart; the sweep is paginated so large archive backlogs are eventually drained. diff --git a/packages/dashboard/app/components/TaskDetailModal.tsx b/packages/dashboard/app/components/TaskDetailModal.tsx index 90b7546338..861f3661c3 100644 --- a/packages/dashboard/app/components/TaskDetailModal.tsx +++ b/packages/dashboard/app/components/TaskDetailModal.tsx @@ -4281,7 +4281,13 @@ export function TaskDetailContent({ )} {/* Actions dropdown — less common operations */} - {(task.column !== "triage" || task.status === "awaiting-approval" || canRetryTask || isTaskPaused) && ( + {( + task.column !== "triage" + || task.status === "awaiting-approval" + || canRetryTask + || isTaskPaused + || Boolean(task.assignedAgentId) + ) && (