From 91c5b325d3973a5842271122e20a34fd6a261767 Mon Sep 17 00:00:00 2001 From: olegbrok Date: Fri, 26 Jun 2026 01:05:53 -0700 Subject: [PATCH] feat(frontend): make heartbeat_interval editable in agent detail panel (#271, completes #826) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #826 added heartbeat_interval to PUT /agents/{name}, but the dashboard only set it in the register wizard — there was no control to change it on an existing agent (the gap that made a dashboard edit of murzik's heartbeat silently not stick). Adds a Heartbeat field to the detail meta row that PUTs {heartbeat_interval}, mirroring the working-dir control (saveWorkingDir) and loading agent.heartbeat_interval on open. Reuses the existing agents_extra.wiz_summary_heartbeat label — no new i18n keys. 0 = demand-woken (no idle heartbeat). Co-Authored-By: Claude Opus 4.8 --- frontend-svelte/src/pages/Agents.svelte | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/frontend-svelte/src/pages/Agents.svelte b/frontend-svelte/src/pages/Agents.svelte index 5883723f..f0cc387d 100644 --- a/frontend-svelte/src/pages/Agents.svelte +++ b/frontend-svelte/src/pages/Agents.svelte @@ -55,6 +55,7 @@ let detailMaxSessions = '--'; let detailGroups = '--'; let detailWorkingDir = ''; + let detailHeartbeatInterval = 0; let detailSoul = ''; let detailUsers = ''; let detailBoundaries = ''; @@ -692,6 +693,7 @@ detailMaxSessions = agent.max_sessions; detailGroups = agent.groups.length ? agent.groups.join(', ') : '--'; detailWorkingDir = agent.working_dir; + detailHeartbeatInterval = agent.heartbeat_interval ?? 0; // Prefer CLAUDE.md on disk (agent may have edited it) over DB soul try { const file = await api('GET', `/agents/${agent.name}/files/CLAUDE.md`); @@ -828,6 +830,7 @@ toast('Thinking effort saved — restart session to apply'); } async function saveWorkingDir() { if (!detailWorkingDir) { toast('Enter a path', 'error'); return; } await api('PUT', `/agents/${currentAgent}`, { working_dir: detailWorkingDir }); toast('Working directory saved'); refreshAgents(); } + async function saveHeartbeat() { const hb = Math.max(0, Math.floor(Number(detailHeartbeatInterval) || 0)); await api('PUT', `/agents/${currentAgent}`, { heartbeat_interval: hb }); detailHeartbeatInterval = hb; toast('Heartbeat interval saved'); refreshAgents(); } async function loadDirectives() { const req = openDetailSeq; const data = await api('GET', `/agents/${currentAgent}/directives?active_only=false`); if (req !== openDetailSeq) return; directives = data.directives || []; } async function addDirective() { if (!newDirective.trim()) { toast('Enter a directive', 'error'); return; } await api('POST', `/agents/${currentAgent}/directives`, { directive: newDirective.trim(), priority: newDirectivePriority }); newDirective = ''; toast('Directive added'); loadDirectives(); } @@ -1789,6 +1792,11 @@ {$_('agents.meta_max')}: {detailMaxSessions} {$_('agents.meta_effort')}: {thinkingEffort} {$_('agents.meta_groups')}: {detailGroups} + + {$_('agents_extra.wiz_summary_heartbeat')} + + + {$_('agents.meta_dir')}: