FN-7188: prevent agents from pausing failed tasks

Clarify agent heartbeat and tool guidance so failures surface through recovery paths instead of task pauses.

- Update heartbeat prompts to prohibit failure/blocker handling via fn_task_pause.
- Clarify fn_task_pause tool copy as explicit user-requested manual control only.
- Refresh generated Fusion skill docs and add regression coverage for the guidance.
- Add a patch changeset for the published CLI package.

Files changed:
 .changeset/FN-7188-no-pause-on-failure.md                    |  7 +++++++
 packages/cli/skill/fusion/references/best-practices.md       |  6 +++---
 packages/cli/skill/fusion/references/extension-tools.md      |  2 +-
 packages/cli/skill/fusion/references/fusion-capabilities.md  |  2 +-
 packages/cli/skill/fusion/workflows/task-management.md       |  2 +-
 packages/cli/src/__tests__/extension.test.ts                 |  8 ++++++++
 packages/cli/src/extension.ts                                | 10 ++++++++--
 .../engine/src/__tests__/heartbeat-session-prompt.test.ts    | 10 ++++++++++
 packages/engine/src/agent-heartbeat.ts                       | 12 ++++++++++--
 9 files changed, 49 insertions(+), 10 deletions(-)

Fusion-Task-Id: FN-7188
Fusion-Task-Lineage: 29df6168-7920-49d5-9c11-804727033721
Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-06-28 01:22:43 -07:00
parent 65abae26c6
commit 524c15c2fd
9 changed files with 49 additions and 10 deletions

View File

@@ -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).

View File

@@ -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

View File

@@ -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 |
|-----------|------|----------|-------------|

View File

@@ -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. |

View File

@@ -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 |

View File

@@ -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(

View File

@@ -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)" }),
}),

View File

@@ -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",

View File

@@ -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.