@fusion/core
Minor Changes
-
e658e8e: Decouple permanent agent heartbeats from task state, and add per-agent
allowParallelExecutionsetting.Heartbeats now run for permanent agents regardless of bound-task block state — the prior early-exit on
queued + blockedByis removed along with its dead state-tracking machinery.HEARTBEAT_SYSTEM_PROMPTis rewritten to scope heartbeats to ambient coordination (messaging, memory, finding work, delegation, surfacing/chasing blockers, status); task body work continues to run via the executor path. Ephemeral agents are unchanged — they don't run heartbeats and their blocked-task gating in the scheduler is untouched.New
allowParallelExecutionflag (defaulttrue, permanent agents only) onAgentHeartbeatConfig. Whenfalse, the heartbeat and task executor paths serialize symmetrically: a heartbeat will not start while the agent's bound task has an active executor session, and an executor session will not start while the agent has an active heartbeat run. Either side re-dispatches the other's deferred work on completion viaresumeTaskForAgentand the in-process runtime'sonRunCompletedhook.UI toggle surfaces in the agent's Heartbeat Settings tab alongside
runMissedHeartbeatOnStartup.
Patch Changes
-
aecc050: Make the merger's autostash recovery robust against silent data loss. When
rootDiris the developer's primary checkout, the merger stashes uncommitted edits before running its hard resets and applies them back at the end. Previously a pop conflict logged a single warning and silently left the stash in place — and a subsequent merge would push another autostash on top, burying the first.Three changes:
- AI auto-resolve on apply conflict. When the autostash apply hits a conflict, the merger now spawns a focused fix-agent (same
createResolvedAgentSessionpath used for the in-merge verification fix-agent) to resolve conflict markers in the working tree. On success the stash is dropped and the resolution is recorded inMergeResult.autostash. On failure the stash is left intact for manual recovery. - Outcome surfaced on
MergeResult.autostash(new field of typeAutostashOutcome). Consumers (dashboard, CLI, daemon) can now show the developer whether their work was reapplied cleanly, AI-resolved, or needs manual recovery — instead of relying on a buried log warning. - Deterministic stash identity via
git stash create+git stash store. Replaces the previousgit stash push+ label-grep flow that raced against any other tool stashing concurrently. The stash SHA is captured atomically with snapshot creation and used for apply/drop, so the operation is robust to stash list reordering.
Also: orphaned
fusion-merger-autostash:*entries from prior failed runs are now detected at merge entry and surfaced as a warning so they cannot be silently buried again. - AI auto-resolve on apply conflict. When the autostash apply hits a conflict, the merger now spawns a focused fix-agent (same
@fusion/dashboard
Minor Changes
-
e658e8e: Decouple permanent agent heartbeats from task state, and add per-agent
allowParallelExecutionsetting.Heartbeats now run for permanent agents regardless of bound-task block state — the prior early-exit on
queued + blockedByis removed along with its dead state-tracking machinery.HEARTBEAT_SYSTEM_PROMPTis rewritten to scope heartbeats to ambient coordination (messaging, memory, finding work, delegation, surfacing/chasing blockers, status); task body work continues to run via the executor path. Ephemeral agents are unchanged — they don't run heartbeats and their blocked-task gating in the scheduler is untouched.New
allowParallelExecutionflag (defaulttrue, permanent agents only) onAgentHeartbeatConfig. Whenfalse, the heartbeat and task executor paths serialize symmetrically: a heartbeat will not start while the agent's bound task has an active executor session, and an executor session will not start while the agent has an active heartbeat run. Either side re-dispatches the other's deferred work on completion viaresumeTaskForAgentand the in-process runtime'sonRunCompletedhook.UI toggle surfaces in the agent's Heartbeat Settings tab alongside
runMissedHeartbeatOnStartup. -
bb32765: Add a "Tools: On/Off" toggle next to the existing "Markdown/Plain" toggle in the agent log viewer (used by both agent logs and task agent logs). When tool output is off, entries of type
tool/tool_result/tool_errorare hidden — only agent text and thinking are shown. Both toggles now persist globally across sessions vialocalStorage(fn-agent-log-markdown,fn-agent-log-tool-output).
Patch Changes
- 9d13295: Move the agent Import button to the global agents header, next to "New Agent", and remove it from individual agent detail pages and the controls panel.
- 11e5f69: Show provider icons in chat: small icon next to the model name in the sidebar session list, and replace the generic robot icon in the chat thread header and assistant message avatars with the active provider icon.
- 24017b8: Drop residual
terminatedAgentState references that the merger autostash dropped during FN-3530 cleanup:[data-state="terminated"]selectors inAgentListModal.css,--terminatedCSS-class assertions inagent-css-classes.test.ts, and astate: "terminated"test fixture inroutes-agents.test.ts(nowpaused, which is correctly rejected as paused→paused is not a valid transition). - Updated dependencies [e658e8e]
- Updated dependencies [aecc050]
- Updated dependencies [6ee3225]
- Updated dependencies [81bf882]
- @fusion/core@0.22.0
- @fusion/engine@0.22.0
- @fusion-plugin-examples/dependency-graph@0.1.11
- @fusion-plugin-examples/droid-runtime@0.1.6
- @fusion-plugin-examples/hermes-runtime@0.2.30
- @fusion-plugin-examples/openclaw-runtime@0.2.30
- @fusion-plugin-examples/paperclip-runtime@0.2.30
@fusion/engine
Minor Changes
-
e658e8e: Decouple permanent agent heartbeats from task state, and add per-agent
allowParallelExecutionsetting.Heartbeats now run for permanent agents regardless of bound-task block state — the prior early-exit on
queued + blockedByis removed along with its dead state-tracking machinery.HEARTBEAT_SYSTEM_PROMPTis rewritten to scope heartbeats to ambient coordination (messaging, memory, finding work, delegation, surfacing/chasing blockers, status); task body work continues to run via the executor path. Ephemeral agents are unchanged — they don't run heartbeats and their blocked-task gating in the scheduler is untouched.New
allowParallelExecutionflag (defaulttrue, permanent agents only) onAgentHeartbeatConfig. Whenfalse, the heartbeat and task executor paths serialize symmetrically: a heartbeat will not start while the agent's bound task has an active executor session, and an executor session will not start while the agent has an active heartbeat run. Either side re-dispatches the other's deferred work on completion viaresumeTaskForAgentand the in-process runtime'sonRunCompletedhook.UI toggle surfaces in the agent's Heartbeat Settings tab alongside
runMissedHeartbeatOnStartup.
Patch Changes
-
aecc050: Make the merger's autostash recovery robust against silent data loss. When
rootDiris the developer's primary checkout, the merger stashes uncommitted edits before running its hard resets and applies them back at the end. Previously a pop conflict logged a single warning and silently left the stash in place — and a subsequent merge would push another autostash on top, burying the first.Three changes:
- AI auto-resolve on apply conflict. When the autostash apply hits a conflict, the merger now spawns a focused fix-agent (same
createResolvedAgentSessionpath used for the in-merge verification fix-agent) to resolve conflict markers in the working tree. On success the stash is dropped and the resolution is recorded inMergeResult.autostash. On failure the stash is left intact for manual recovery. - Outcome surfaced on
MergeResult.autostash(new field of typeAutostashOutcome). Consumers (dashboard, CLI, daemon) can now show the developer whether their work was reapplied cleanly, AI-resolved, or needs manual recovery — instead of relying on a buried log warning. - Deterministic stash identity via
git stash create+git stash store. Replaces the previousgit stash push+ label-grep flow that raced against any other tool stashing concurrently. The stash SHA is captured atomically with snapshot creation and used for apply/drop, so the operation is robust to stash list reordering.
Also: orphaned
fusion-merger-autostash:*entries from prior failed runs are now detected at merge entry and surfaced as a warning so they cannot be silently buried again. - AI auto-resolve on apply conflict. When the autostash apply hits a conflict, the merger now spawns a focused fix-agent (same
-
6ee3225: Fix agents stuck in
state="running"after a missed-heartbeat termination.The unresponsive-agent recovery path disposed the session and called
pauseAgent, but never explicitly ended the run viacompleteRun— relying on the in-flight execution to self-complete via its catch handler, which doesn't happen when the run is genuinely hung. The run record could still be terminated through other paths (safety-net or supersede-on-startRun), but those bypass the agent-state transition, leaving the agent permanently displayed as "running" with no active run.Two fixes:
recoverUnresponsiveAgentnow callscompleteRun(..., status: "terminated")so the canonical state transition runs alongside the existingpauseAgent/resumeAgentsequence.reconcileOrphanedRunningAgentsis broadened to also catch agents with stalelastHeartbeatAt(> 3× timeout) that aren't in the in-memory tracked set, terminating their stale run record. It now runs every poll instead of only at monitor start, so any pre-existing stuck rows from older versions self-heal within one poll interval after upgrade.
-
81bf882: Route skill-selection diagnostics by their declared severity instead of always logging at warn. Info-level messages like "Requested skill: " now log at info level.
-
Updated dependencies [e658e8e]
-
Updated dependencies [aecc050]
- @fusion/core@0.22.0
- @fusion/pi-claude-cli@0.22.0
@fusion/plugin-sdk
Patch Changes
@runfusion/fusion
Minor Changes
-
e658e8e: Decouple permanent agent heartbeats from task state, and add per-agent
allowParallelExecutionsetting.Heartbeats now run for permanent agents regardless of bound-task block state — the prior early-exit on
queued + blockedByis removed along with its dead state-tracking machinery.HEARTBEAT_SYSTEM_PROMPTis rewritten to scope heartbeats to ambient coordination (messaging, memory, finding work, delegation, surfacing/chasing blockers, status); task body work continues to run via the executor path. Ephemeral agents are unchanged — they don't run heartbeats and their blocked-task gating in the scheduler is untouched.New
allowParallelExecutionflag (defaulttrue, permanent agents only) onAgentHeartbeatConfig. Whenfalse, the heartbeat and task executor paths serialize symmetrically: a heartbeat will not start while the agent's bound task has an active executor session, and an executor session will not start while the agent has an active heartbeat run. Either side re-dispatches the other's deferred work on completion viaresumeTaskForAgentand the in-process runtime'sonRunCompletedhook.UI toggle surfaces in the agent's Heartbeat Settings tab alongside
runMissedHeartbeatOnStartup. -
041eb89: Per-agent setting
runMissedHeartbeatOnStartup(default off): when enabled, the engine fires a single catch-up heartbeat at server startup if the agent'slastHeartbeatAtis older than its configured interval — i.e. a scheduled tick was missed because the server was down.The check runs in the same startup pass that arms heartbeat timers (
packages/cli/src/commands/dashboard.ts), so agents whose state isn'tactive/runningor who have heartbeats disabled never trigger. Catch-up runs use the existingexecuteHeartbeatpath withsource="timer"andtriggerDetail="startup-missed-heartbeat-catchup"so per-agent serialization, budget enforcement, and missed/recovered tracking continue to apply. UI toggle lives in the agent's Heartbeat Settings tab. -
8eb5c3d: Remove the
terminatedAgentState. The agent lifecycle now runs throughidle | active | running | paused | error, withpaused(carrying apauseReason) absorbing every formerterminateduse case (manual stop, heartbeat run termination, spawned-child cleanup). Run status is unchanged — heartbeat runs still reportterminatedindependently of the agent state.Migration: existing
agentsrows wherestate = 'terminated'are rewritten tostate = 'paused'withpauseReason: 'migrated-from-terminated'on first store init (__metakeyremoveTerminatedAgentState). The dashboard "Terminated" filter option, badge, and CSS rules are gone; "Stop" buttons now transition the agent topaused. Thedashboard.READMEs"Terminated agent filtering" behavior in the agents list is also dropped — paused/error agents are visible by default, and AgentListModal/AgentsView no longer hide them in "All States."
Patch Changes
-
7d41271: Three small UX fixes on the agent list card.
- Optimistic Run Now: clicking the Run Now button now flips the card's state badge to
runningimmediately. ThestartAgentRunAPI call can take several seconds, and the prior code awaited it before any visual feedback, leaving users unsure whether the click registered. Mirrors the existinghandleStateChangepattern — stamp the override, await the API, refresh on success, roll back on failure. - Whole-card clickable: the entire
.agent-cardbody opens the agent detail view, not just the name/icon area. Clicks on action buttons (Run Now, Pause, Details, Delete), the role-edit select, and the role-icon button keep their dedicated behaviors via a target check that bails on interactive descendants.role="button",tabIndex, and Enter/Space handling preserve keyboard access; a--focus-ringoutline shows the focus state. - Single-row card actions: renamed "View Details" → "Details" and switched
.agent-card-actionstoflex-wrap: nowrapwith per-buttonflex-shrink: 0; white-space: nowrapso Run Now / Pause / Details stay on one row regardless of card width.
- Optimistic Run Now: clicking the Run Now button now flips the card's state badge to
-
c76db06: Agent list color now signals run status only:
runningis green,erroris red, andidle/active/pausedall use the neutral gray. Previouslyactiveshared green withrunningandpausedwas yellow, which made the list visually busy and obscured which agents were actually executing. Applies to the badge, list card border, board card border, and org-chart node card across all agent views. -
b2aed0f: Engine stop now tears down in-progress merger and triager agent sessions
that previously kept streaming past shutdown.Triager:
TriageProcessor.stop()previously only halted the polling
loop, leaving any in-flight specify session and its reviewer subagents
streaming LLM tokens and tool calls past shutdown. It now aborts and
disposes them via the same path the global-pause handler uses.Merger:
aiMergeTaskcreates up to three distinct agent sessions
during a merge — autostash conflict resolver, in-merge verification fix
agent, and pull-rebase conflict resolver — but only the autostash session
was registered viaonSessionfor the engine to track. The fix-agent and
rebase-resolver sessions are now also registered, so
ProjectEngine.stop()actually disposes whichever merger session is
running when shutdown lands. -
d47501f: Fix two related agent-lifecycle leaks and extract the coordinator into a reusable class.
Stuck-in-running bug.
executeHeartbeat's governance-skip paths (budget exhausted, budget threshold, global pause, engine paused) calledstartRunfirst — flipping the agent torunning— then short-circuited withskipStateTransition: true, leaving the agent permanently stuck atrunningwith no active run. Removed theskipStateTransitionflag from those four paths so they flow through the normalrunning → activetransition. AddedHeartbeatMonitor.reconcileOrphanedRunningAgents()on startup to recover any agents already trapped in this state from older versions.Ephemeral task-worker pile-up. Runtime-spawned
executor-FN-XXXXworkers leaked across runtime restarts because the in-memorytaskAgentMapreset every process and there was no on-disk fallback. A task started in one session and completed in another would orphan its worker; over time hundreds piled up. The startup sweep also only deleted ephemerals in halt states, ignoring the no-taskIdcase that accounted for nearly every zombie. Now: spawn dedup viafindAgentByNamelookup before create, on-disk fallback in completion/error paths, and the startup sweep deletes any ephemeral not bound to an in-progress task.EphemeralWorkerManagerextraction. The lifecycle logic is now a single class (packages/engine/src/ephemeral-worker-manager.ts) owningtaskAgentMap,pendingDeletions, the halt-state listener, and the startup sweep.InProcessRuntimeshrinks by ~140 lines and delegates viaworkerManager.onTaskStart/.onTaskComplete/.onTaskError/.attachStateChangeListener/.reconcileOrphaned. Future runtimes that driveTaskExecutordirectly inherit the same lifecycle. Durable assigned agents now return toactiveafter task completion (wasterminatedin the old contract). -
12193d2: Auto-install bundled runtime plugins (Hermes / OpenClaw / Paperclip) on first Save in Settings, and ship them inside the published CLI so npx-installed Fusion can load them. Previously the runtime cards rendered but
Save/Save and Testfailed withPlugin "fusion-plugin-…-runtime" not found, and the plugins were unavailable when the CLI was installed via npm/npx because their workspace@fusion/plugin-sdkdependency wasn't bundled. Each runtime plugin is now bundled at CLI build time into a self-containeddist/plugins/<id>/bundled.js, andPUT /api/plugins/:id/settingslazily registers a bundled runtime via the newServerOptions.ensureBundledPluginInstalledhook the first time the user saves. -
ff66c20: Clarify runtime memory guidance so agents explicitly distinguish private
scope="agent"memory from sharedscope="project"memory in prompts and tool metadata. -
bb6169a: Improve dashboard agent error UX by replacing inline stack-trace dumps with compact error indicators that open a shared details modal, including copy-to-clipboard and a prefilled GitHub issue shortcut.
-
12b4a4a: Expose task creator provenance in agent-facing task tools by adding source summaries to
fn_task_showand concise[via: …]labels infn_task_list, including agent-name preference fromsourceMetadata.agentNamewithsourceAgentIdfallback. -
89fd7a9: Mission sidebar follow-ups for card density and CTA prominence.
- Wider title in the sidebar: stack mission cards vertically inside the
sidebar so the title row spans the full card width instead of competing
with the action buttons. Action buttons now sit on their own row below. - Activity on its own row: the
Activity X agolabel moved out of the
cramped stats line into its own row. - Full-width progress bar: the completion bar moved out of the stats
row onto its own line and now scales to the full card width instead of
competing with stat labels for horizontal space. - Centered "Plan New Mission" CTA: the sidebar header now hosts a
full-width primary-styled button (matches the chat sidebar's "New Chat"
affordance) with the Sparkles icon and "Plan New Mission" text — replacing
the dashed-outline icon-only buttons. Mobile footer uses the same label. - Auto-select first mission (inline desktop): the inline mission view
now opens with the first mission preloaded into the detail pane instead
of an empty placeholder. Falls back to the existing empty-pane copy when
no missions exist. Standalone-modal usage is unchanged. - Richer empty state: when no missions exist, the list now explains
what missions are and surfaces a primary "Plan New Mission" CTA inline.
- Wider title in the sidebar: stack mission cards vertically inside the
-
f04ade0: Mission view sidebar and list-card UX fixes.
- Resizable mission sidebar: the desktop split sidebar is now drag-resizable via a vertical handle (also keyboard-accessible with arrow keys). Width persists to
localStorage(fusion:mission-sidebar-width), bounded 220–560px, default 300px. Previously fixed at ~284px withflex-shrink: 0. - Mission card title no longer truncates aggressively: tags (autopilot zap, health badge, status pill) moved to a second row below the title so the title can use the full card width. Removed the redundant overflow-prone
Active: …line that was sometimes spilling outside the card. - Single AI-driven create flow: removed the manual
+ New Missionbutton from the sidebar header and bottom footer. The Sparkles button (now labeled "Create New Mission") is the only entry point — the deadhandleCreateMissioncallback and unusedactiveSliceLabelwere removed too.
- Resizable mission sidebar: the desktop split sidebar is now drag-resizable via a vertical handle (also keyboard-accessible with arrow keys). Width persists to
-
b312ca4: Fix terminal input/output doubling triggered by creating a new tab. The connect-effect's
contextChangeddependency flips true→false in the same render cycle as the new connection, re-running the effect and closing the still-CONNECTING WebSocket. Becausecleanup()andconnect()'s pre-close paths weren't nullingws.onopen/onmessage/onclose/onerror, the ghost socket'sonmessagecontinued to fire on the shared callback Set, delivering each pty data chunk (including keystroke echo) twice to xterm.
runfusion.ai
Patch Changes
- Updated dependencies [e658e8e]
- Updated dependencies [7d41271]
- Updated dependencies [041eb89]
- Updated dependencies [c76db06]
- Updated dependencies [b2aed0f]
- Updated dependencies [d47501f]
- Updated dependencies [12193d2]
- Updated dependencies [ff66c20]
- Updated dependencies [bb6169a]
- Updated dependencies [12b4a4a]
- Updated dependencies [89fd7a9]
- Updated dependencies [f04ade0]
- Updated dependencies [8eb5c3d]
- Updated dependencies [b312ca4]
- @runfusion/fusion@0.22.0