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:
7
.changeset/FN-7188-no-pause-on-failure.md
Normal file
7
.changeset/FN-7188-no-pause-on-failure.md
Normal 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).
|
||||||
@@ -33,7 +33,7 @@ For work larger than L, use missions to break it into phases.
|
|||||||
| Vague idea needing refinement | `fn_task_plan` |
|
| Vague idea needing refinement | `fn_task_plan` |
|
||||||
| Large project with phases | `fn_mission_create` + hierarchy |
|
| Large project with phases | `fn_mission_create` + hierarchy |
|
||||||
| Task failed, needs retry | `fn_task_retry` |
|
| 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` |
|
| Completed task needs follow-up | `fn_task_refine` |
|
||||||
| Clean up done tasks | `fn_task_archive` |
|
| Clean up done tasks | `fn_task_archive` |
|
||||||
| Import external work | `fn_task_import_github*` |
|
| 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
|
## Working with the AI Engine
|
||||||
|
|
||||||
- **Don't fight the automation** — let triage, scheduler, and executor do their jobs
|
- **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
|
- **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
|
- **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
|
## Mission Planning Tips
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ Attach a file to a task. Supports images (png, jpg, gif, webp) and text files (t
|
|||||||
|
|
||||||
### fn_task_pause
|
### 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 |
|
| Parameter | Type | Required | Description |
|
||||||
|-----------|------|----------|-------------|
|
|-----------|------|----------|-------------|
|
||||||
|
|||||||
@@ -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_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_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_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_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_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. |
|
| `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. |
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ Use `fn_task_show` with the task ID:
|
|||||||
|
|
||||||
| Action | Tool | Notes |
|
| 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 |
|
| Resume automation | `fn_task_unpause` | Re-enables automated processing |
|
||||||
| Retry failed task | `fn_task_retry` | Clears error, moves back to todo |
|
| Retry failed task | `fn_task_retry` | Clears error, moves back to todo |
|
||||||
| Duplicate task | `fn_task_duplicate` | Creates fresh copy in triage |
|
| Duplicate task | `fn_task_duplicate` | Creates fresh copy in triage |
|
||||||
|
|||||||
@@ -1197,6 +1197,14 @@ describe.skipIf(!SHOULD_RUN_LEGACY_EXTENSION_INTEGRATION)("fn pi extension (lega
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("fn_task_pause / unpause", () => {
|
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 () => {
|
it("pauses and unpauses a task", async () => {
|
||||||
const createTool = api.tools.get("fn_task_create")!;
|
const createTool = api.tools.get("fn_task_create")!;
|
||||||
await createTool.execute(
|
await createTool.execute(
|
||||||
|
|||||||
@@ -1043,12 +1043,18 @@ export default function kbExtension(pi: ExtensionAPI) {
|
|||||||
|
|
||||||
// ── fn_task_pause ────────────────────────────────────────────────
|
// ── 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({
|
pi.registerTool({
|
||||||
name: "fn_task_pause",
|
name: "fn_task_pause",
|
||||||
label: "fn: Pause Task",
|
label: "fn: Pause Task",
|
||||||
description:
|
description:
|
||||||
"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.",
|
||||||
promptSnippet: "Pause a Fusion task (stops automation)",
|
promptSnippet:
|
||||||
|
"Pause a Fusion task only for explicit user-requested manual control; do not use for failure/blocker handling",
|
||||||
parameters: Type.Object({
|
parameters: Type.Object({
|
||||||
id: Type.String({ description: "Task ID (e.g. FN-001)" }),
|
id: Type.String({ description: "Task ID (e.g. FN-001)" }),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -102,6 +102,16 @@ describe("createHeartbeatTools", () => {
|
|||||||
expect(HEARTBEAT_NO_TASK_SYSTEM_PROMPT).toContain("coding-capable workspace tools");
|
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", () => {
|
describe("FN-5053 no-task heartbeat prompt/tool alignment", () => {
|
||||||
const FORBIDDEN_NO_TASK_TOOLS = [
|
const FORBIDDEN_NO_TASK_TOOLS = [
|
||||||
"fn_task_log",
|
"fn_task_log",
|
||||||
|
|||||||
@@ -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.
|
* This is an ambient heartbeat: task implementation runs in a separate executor path.
|
||||||
* The heartbeat handles coordination, communication, memory, and routing only.
|
* 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.
|
export const HEARTBEAT_SYSTEM_PROMPT = `You are a heartbeat agent running in a short execution window.
|
||||||
|
|
||||||
## Your Role
|
## Your Role
|
||||||
@@ -392,6 +397,8 @@ Your job:
|
|||||||
- Surface the blocker concretely with fn_task_log.
|
- 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.
|
- 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.
|
- 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.
|
- Pivot to other relevant coordination work if the blocker cannot be immediately resolved.
|
||||||
|
|
||||||
**If your bound task is not blocked:**
|
**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
|
## Common Patterns
|
||||||
|
|
||||||
- **Blocked task:** log the concrete blocker, chase the dependency via fn_send_message, create a narrowly scoped unblocker task if needed.
|
- **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.
|
- **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.
|
- **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.
|
- **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.
|
- **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
|
## 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.
|
- **Unowned risk discovered:** create one focused task with concrete acceptance language.
|
||||||
- **Known specialist needed:** list agents, then delegate to matching role/capability.
|
- **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.
|
- **Repeated confusion across runs:** append a concise memory entry so future agents avoid the same mistake.
|
||||||
|
|||||||
Reference in New Issue
Block a user