From 47d2d176ef42e896a73f5e678b7d307d493f5fb5 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 23 Jul 2026 13:04:17 -0700 Subject: [PATCH] FN-8552: add disabled heartbeat scheduling option Allow agent heartbeat scheduling to be paused and resumed without losing its configured cadence. - Add a Disabled heartbeat interval dropdown option that persists runtime enablement. - Re-enable scheduling when preset or custom intervals are selected. - Cover disabled, legacy, desktop/mobile, and configuration-preservation flows. - Document the heartbeat control and add a patch changeset. Files changed: .changeset/fn-8552-heartbeat-disabled-option.md | 7 ++ README.md | 2 +- packages/dashboard/app/components/AgentsView.tsx | 41 +++++++- .../app/components/__tests__/AgentsView.test.tsx | 115 +++++++++++++++++++++ 4 files changed, 162 insertions(+), 3 deletions(-) Fusion-Task-Id: FN-8552 Fusion-Task-Lineage: 07f78005-4ac0-4210-9dd3-6c5b06ab7bc5 Co-authored-by: Fusion (runfusion.ai) --- .../fn-8552-heartbeat-disabled-option.md | 7 ++ README.md | 2 +- .../dashboard/app/components/AgentsView.tsx | 41 ++++++- .../components/__tests__/AgentsView.test.tsx | 115 ++++++++++++++++++ 4 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 .changeset/fn-8552-heartbeat-disabled-option.md diff --git a/.changeset/fn-8552-heartbeat-disabled-option.md b/.changeset/fn-8552-heartbeat-disabled-option.md new file mode 100644 index 0000000000..44a355166c --- /dev/null +++ b/.changeset/fn-8552-heartbeat-disabled-option.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Let agent-card heartbeat controls disable and re-enable scheduling. +category: feature +dev: The interval dropdown now preserves runtime configuration while updating runtimeConfig.enabled. diff --git a/README.md b/README.md index 68ccc30103..2e60ba2e17 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ Here is the same fleet re-skinned into the **Ember** theme (dark graphite with a -Import a team and every agent shows up here — role, reports-to chain, heartbeat, and token share. The **Agents** roster in Ember: +Import a team and every agent shows up here — role, reports-to chain, heartbeat, and token share. Each agent card's heartbeat dropdown shows **Disabled** when scheduling is persisted off; choose Disabled to pause heartbeats while retaining its cadence, or select an interval to re-enable them. The **Agents** roster in Ember:
Fusion Agents view in the Ember theme diff --git a/packages/dashboard/app/components/AgentsView.tsx b/packages/dashboard/app/components/AgentsView.tsx index 16c9ecd327..18bed18ce7 100644 --- a/packages/dashboard/app/components/AgentsView.tsx +++ b/packages/dashboard/app/components/AgentsView.tsx @@ -60,6 +60,7 @@ function getAgentRoles(t: TFunction<"app">): { value: AgentCapability; label: st } const HEARTBEAT_MULTIPLIER_PRESETS = [0.1, 0.25, 0.5, 1, 2, 3, 5, 10] as const; +const HEARTBEAT_DISABLED_OPTION_VALUE = "__disabled__"; const ORG_CHART_SCALE_MIN = 0.25; const ORG_CHART_SCALE_MAX = 3; @@ -935,6 +936,7 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin { runtimeConfig: { ...(agent.runtimeConfig ?? {}), + enabled: true, heartbeatIntervalMs: newIntervalMs, }, }, @@ -949,6 +951,28 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin } }; + const handleHeartbeatDisabled = async (agent: Agent) => { + setUpdatingHeartbeatAgentId(agent.id); + try { + await updateAgent( + agent.id, + { + runtimeConfig: { + ...(agent.runtimeConfig ?? {}), + enabled: false, + }, + }, + projectId, + ); + addToast(t("agents.heartbeatDisabled", "Heartbeat disabled for {{name}}", { name: agent.name }), "success"); + void loadAgents(); + } catch (err) { + addToast(t("agents.heartbeatIntervalUpdateFailed", "Failed to update heartbeat interval: {{error}}", { error: getErrorMessage(err) }), "error"); + } finally { + setUpdatingHeartbeatAgentId(null); + } + }; + /** * Handle saving custom heartbeat interval from typed minutes input. * Validation behavior: @@ -989,6 +1013,7 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin { runtimeConfig: { ...(agent.runtimeConfig ?? {}), + enabled: true, heartbeatIntervalMs: MIN_HEARTBEAT_INTERVAL_MS, }, }, @@ -1019,6 +1044,7 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin { runtimeConfig: { ...(agent.runtimeConfig ?? {}), + enabled: true, heartbeatIntervalMs: intervalMs, }, }, @@ -1855,6 +1881,14 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin const stateCardClass = getStateCardClass("agent-card", agent.state); const configuredIntervalMs = resolveHeartbeatIntervalMs(agent.runtimeConfig?.heartbeatIntervalMs); const heartbeatOptions = getHeartbeatIntervalOptions(configuredIntervalMs); + /* + * FNXC:AgentHeartbeatControls 2026-07-23-12:43: + * The list-card select is the scheduling control: an explicit false wins over its saved cadence, + * while absent enabled remains backwards-compatible as enabled. Interval changes always persist + * enabled: true; disabling retains the complete runtime configuration and saved cadence. + */ + const isHeartbeatDisabled = agent.runtimeConfig?.enabled === false; + const heartbeatSelectValue = isHeartbeatDisabled ? HEARTBEAT_DISABLED_OPTION_VALUE : String(configuredIntervalMs); const isUpdatingHeartbeat = updatingHeartbeatAgentId === agent.id; const modelLabel = getAgentModelLabel(agent); return ( @@ -2056,10 +2090,12 @@ export function AgentsView({ addToast, projectId, onOpenTaskLogs, agentOnboardin <>