diff --git a/.changeset/FN-7188-no-pause-on-failure.md b/.changeset/FN-7188-no-pause-on-failure.md new file mode 100644 index 0000000000..ef4265db36 --- /dev/null +++ b/.changeset/FN-7188-no-pause-on-failure.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Agents no longer pause tasks on failure — pausing is reserved for explicit user requests. +category: fix +dev: Adds a no-pause-on-failure standing rule to HEARTBEAT_SYSTEM_PROMPT / HEARTBEAT_NO_TASK_SYSTEM_PROMPT, clarifies the fn_task_pause tool description, and regenerates the fusion skill docs (sync:fusion-skill). diff --git a/packages/cli/skill/fusion/references/best-practices.md b/packages/cli/skill/fusion/references/best-practices.md index 4429fbb9b6..2cddbd0cce 100644 --- a/packages/cli/skill/fusion/references/best-practices.md +++ b/packages/cli/skill/fusion/references/best-practices.md @@ -33,7 +33,7 @@ For work larger than L, use missions to break it into phases. | Vague idea needing refinement | `fn_task_plan` | | Large project with phases | `fn_mission_create` + hierarchy | | Task failed, needs retry | `fn_task_retry` | -| Task needs manual intervention | `fn_task_pause` | +| User explicitly requests manual control | `fn_task_pause` | | Completed task needs follow-up | `fn_task_refine` | | Clean up done tasks | `fn_task_archive` | | Import external work | `fn_task_import_github*` | @@ -49,10 +49,10 @@ For work larger than L, use missions to break it into phases. ## Working with the AI Engine - **Don't fight the automation** — let triage, scheduler, and executor do their jobs -- **Pause if needed** — use `fn_task_pause` when you want manual control +- **Pause only on explicit user request** — use `fn_task_pause` for user-driven manual control, never as agent failure or blocker handling - **Steer don't micromanage** — use steering comments (via CLI `fn task steer`) to guide the AI without rewriting the spec - **Check progress** — use `fn_task_show` to monitor step completion -- **Let it fail and retry** — if a task fails, check the log, then `fn_task_retry` +- **Let it fail and retry** — if a task fails, check the log, then `fn_task_retry` or create a focused follow-up task instead of pausing it ## Mission Planning Tips diff --git a/packages/cli/skill/fusion/references/extension-tools.md b/packages/cli/skill/fusion/references/extension-tools.md index 1ef669d999..8c1721d2ae 100644 --- a/packages/cli/skill/fusion/references/extension-tools.md +++ b/packages/cli/skill/fusion/references/extension-tools.md @@ -63,7 +63,7 @@ Attach a file to a task. Supports images (png, jpg, gif, webp) and text files (t ### fn_task_pause -Pause a task — stops all automated agent and scheduler interaction for this task. +Pause a task for explicit user-requested manual control — stops all automated agent and scheduler interaction. Agents should not pause tasks to handle failures or blockers; use retry, create/delegate follow-up work, or let the task surface as failed instead. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| diff --git a/packages/cli/skill/fusion/references/fusion-capabilities.md b/packages/cli/skill/fusion/references/fusion-capabilities.md index 0671b074e8..7690f866f9 100644 --- a/packages/cli/skill/fusion/references/fusion-capabilities.md +++ b/packages/cli/skill/fusion/references/fusion-capabilities.md @@ -17,7 +17,7 @@ All skill/extension tool invocations in this catalog use the public `fn_*` names | `fn_task_list` | List all tasks on the Fusion board, grouped by column. | | `fn_task_show` | Show full details for a task including steps, progress, and log entries. | | `fn_task_attach` | Attach a file to a task. Supports images (png, jpg, gif, webp) and text files (txt, log, json, yaml, yml, toml, csv, xml). | -| `fn_task_pause` | Pause a task — stops all automated agent and scheduler interaction for this task. | +| `fn_task_pause` | Pause a task for explicit user-requested manual control — stops all automated agent and scheduler interaction. Agents should not pause tasks to handle failures or blockers; use retry, create/delegate follow-up work, or let the task surface as failed instead. | | `fn_task_unpause` | Unpause a task — resumes automated agent and scheduler interaction. | | `fn_task_retry` | Retry a failed task — clears the error state. Non-review failures move to todo; in-review execution failures move to todo preserving progress; in-review merge failures stay in-place for auto-merge retry. | | `fn_task_duplicate` | Duplicate an existing task, creating a fresh copy in planning. Copies the title and description but resets all execution state. The AI planning agent will replan the new task. | diff --git a/packages/cli/skill/fusion/workflows/task-management.md b/packages/cli/skill/fusion/workflows/task-management.md index c827136465..e9b45289a9 100644 --- a/packages/cli/skill/fusion/workflows/task-management.md +++ b/packages/cli/skill/fusion/workflows/task-management.md @@ -60,7 +60,7 @@ Use `fn_task_show` with the task ID: | Action | Tool | Notes | |--------|------|-------| -| Pause automation | `fn_task_pause` | Stops scheduler and executor from touching the task | +| Pause automation | `fn_task_pause` | Stops scheduler and executor from touching the task; use only when the user explicitly requests manual control, not for failure/blocker handling | | Resume automation | `fn_task_unpause` | Re-enables automated processing | | Retry failed task | `fn_task_retry` | Clears error, moves back to todo | | Duplicate task | `fn_task_duplicate` | Creates fresh copy in triage | diff --git a/packages/cli/src/__tests__/extension.test.ts b/packages/cli/src/__tests__/extension.test.ts index 2ba1aea82a..38072c0258 100644 --- a/packages/cli/src/__tests__/extension.test.ts +++ b/packages/cli/src/__tests__/extension.test.ts @@ -1197,6 +1197,14 @@ describe.skipIf(!SHOULD_RUN_LEGACY_EXTENSION_INTEGRATION)("fn pi extension (lega }); describe("fn_task_pause / unpause", () => { + it("FN-7188 describes pause as user-requested manual control, not failure handling", () => { + const pauseTool = api.tools.get("fn_task_pause")!; + + expect(pauseTool.description).toContain("explicit user-requested manual control"); + expect(pauseTool.description).toContain("should not pause tasks to handle failures or blockers"); + expect(pauseTool.description).toContain("let the task surface as failed"); + }); + it("pauses and unpauses a task", async () => { const createTool = api.tools.get("fn_task_create")!; await createTool.execute( diff --git a/packages/cli/src/extension.ts b/packages/cli/src/extension.ts index 9ea0f1178d..f0bc620f9b 100644 --- a/packages/cli/src/extension.ts +++ b/packages/cli/src/extension.ts @@ -1043,12 +1043,18 @@ export default function kbExtension(pi: ExtensionAPI) { // ── fn_task_pause ──────────────────────────────────────────────── + /* + * FNXC:AgentPauseGuidance 2026-06-28-00:05: + * Pause is a user-requested manual-control lever, not an agent failure-handling response. + * Tool guidance must steer agents toward retry, follow-up work, or normal failure surfacing instead of stranding tasks in paused state. + */ pi.registerTool({ name: "fn_task_pause", label: "fn: Pause Task", description: - "Pause a task — stops all automated agent and scheduler interaction for this task.", - promptSnippet: "Pause a Fusion task (stops automation)", + "Pause a task for explicit user-requested manual control — stops all automated agent and scheduler interaction. Agents should not pause tasks to handle failures or blockers; use retry, create/delegate follow-up work, or let the task surface as failed instead.", + promptSnippet: + "Pause a Fusion task only for explicit user-requested manual control; do not use for failure/blocker handling", parameters: Type.Object({ id: Type.String({ description: "Task ID (e.g. FN-001)" }), }), diff --git a/packages/engine/src/__tests__/heartbeat-session-prompt.test.ts b/packages/engine/src/__tests__/heartbeat-session-prompt.test.ts index 294ffb5218..ab45d7987a 100644 --- a/packages/engine/src/__tests__/heartbeat-session-prompt.test.ts +++ b/packages/engine/src/__tests__/heartbeat-session-prompt.test.ts @@ -102,6 +102,16 @@ describe("createHeartbeatTools", () => { expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("coding-capable workspace tools"); }); + it.each([ + ["task-scoped", HEARTBEAT_SYSTEM_PROMPT], + ["no-task", HEARTBEAT_NO_TASK_SYSTEM_PROMPT], + ])("FN-7188 keeps no-pause-on-failure guidance in %s heartbeat prompt", (_variant, promptText) => { + expect(promptText).toMatch(/do NOT call fn_task_pause to handle/i); + expect(promptText).toContain("Pausing is reserved for explicit user requests for manual control"); + expect(promptText).toMatch(/failed or blocked|failure or blocker/); + expect(promptText).not.toContain("fn_task_retry"); + }); + describe("FN-5053 no-task heartbeat prompt/tool alignment", () => { const FORBIDDEN_NO_TASK_TOOLS = [ "fn_task_log", diff --git a/packages/engine/src/agent-heartbeat.ts b/packages/engine/src/agent-heartbeat.ts index f62b217676..97c476a15b 100644 --- a/packages/engine/src/agent-heartbeat.ts +++ b/packages/engine/src/agent-heartbeat.ts @@ -370,6 +370,11 @@ export function taskRelevanceScore(agent: Agent, task: RelevanceScorableTask): n * This is an ambient heartbeat: task implementation runs in a separate executor path. * The heartbeat handles coordination, communication, memory, and routing only. */ +/* +FNXC:AgentPauseGuidance 2026-06-28-00:05: +Coordination agents must not pause tasks to handle failures or blockers because a pause suppresses scheduler and self-healing recovery. +Only use task pause when the user explicitly requests manual control; otherwise log blockers, route follow-up work, or let the task surface as failed. +*/ export const HEARTBEAT_SYSTEM_PROMPT = `You are a heartbeat agent running in a short execution window. ## Your Role @@ -392,6 +397,8 @@ Your job: - Surface the blocker concretely with fn_task_log. - Chase the dependency: comment on the blocking task, send a message to the responsible agent, or ping an owner. - Look for unblocking work you can spawn or delegate right now. +- Do NOT call fn_task_pause to handle a failed or blocked task. Pausing is reserved for explicit user requests for manual control. +- If the task needs recovery, create/delegate focused follow-up work with fn_task_create or fn_delegate_task, log the needed operator action, or let the task surface as failed. - Pivot to other relevant coordination work if the blocker cannot be immediately resolved. **If your bound task is not blocked:** @@ -428,8 +435,8 @@ Prefer fn_delegate_task when immediate ownership by a specific agent materially ## Common Patterns -- **Blocked task:** log the concrete blocker, chase the dependency via fn_send_message, create a narrowly scoped unblocker task if needed. -- **Stuck task with no blockedBy:** log the observation and create a follow-up task to investigate the root cause. +- **Blocked task:** log the concrete blocker, chase the dependency via fn_send_message, create a narrowly scoped unblocker task if needed; do not pause it unless the user explicitly requested manual control. +- **Stuck task with no blockedBy:** log the observation and create a follow-up task to investigate the root cause; do not use fn_task_pause as failure handling. - **Completed task with follow-up risk:** create explicit follow-up task(s) for residual risk instead of burying notes in a long log. - **New user/agent comments:** summarize what changed, identify required action, and route via task creation/delegation. - **Dependency drift:** log the mismatch and create reconciliation tasks with clear dependencies. @@ -526,6 +533,7 @@ If unsure who should do the work, prefer fn_task_create and let scheduler routin ## Common Patterns +- **Failed or blocked task:** do NOT call fn_task_pause to handle the failure or blocker. Pausing is reserved for explicit user requests for manual control; instead surface the blocker through available task or message context, create/delegate follow-up work, or let the task surface as failed. - **Unowned risk discovered:** create one focused task with concrete acceptance language. - **Known specialist needed:** list agents, then delegate to matching role/capability. - **Repeated confusion across runs:** append a concise memory entry so future agents avoid the same mistake.