fix: show readable live activity progress

This commit is contained in:
Michael Lam committed 2026-05-15 14:11:58 -07:00
1 parent 7ac4bf4f4a
commit 2e039ab7f7
3 files changed
+43 -2

No files matched your search

+2
View File
@@ -8,6 +8,8 @@
### Fixed
- **PR #2331** by @Michaelyklam (closes #2310) — Live compact Activity rows now show transient user-readable progress such as "Searching workspace", "Reading files", "Updating files", or "Running command" while a long tool-only turn is still working. The label is derived from the current tool category, uses the existing non-persistent Activity summary/duration slot, and does not add synthetic assistant content to the transcript.
- **PR #2315** by @Michaelyklam (closes #2305, refs #749) — WebUI profile creation now seeds bundled profile skills for newly-created non-cloned profiles, matching the CLI's `hermes profile create` behaviour. Pre-fix, creating a profile via Settings → New Profile (without checking "Clone from active profile") left the profile's `skills/` directory empty, which was inconsistent with CLI-created profiles that get the full bundled-skills overlay. The fix calls `seed_profile_skills(profile_path, quiet=True)` after `profile_path.mkdir()` when `clone_from is None`. Cloned profiles still inherit skills from their source — they don't get a second bundled-skills overlay. Seed failures (e.g. `hermes_cli` unavailable in Docker fallback) are logged as warnings, not fatal — profile creation still succeeds.
- **PR #2317** by @Michaelyklam (refs #2312 follow-up #2) — Appearance boot reconciliation now treats explicit `light`, `dark`, and `system` localStorage theme values as user selections when a prior Settings autosave failed. Pre-fix, the predicate `lsHasExplicitTheme = lsTheme === 'system'` only treated 'system' as explicit, so a user who picked `light` on a server defaulted to `dark` (or vice versa) with a failed autosave still reverted to the server default on refresh. Now broadened to `['system','light','dark'].includes(lsTheme)`. Skin handling was already correct (`lsSkin !== 'default'`). Closes follow-up item #2 from the v0.51.66 review (#2312).
+22 -2
View File
@@ -5929,10 +5929,11 @@ function _syncToolCallGroupSummary(group){
if(durationEl){
if(group.getAttribute('data-live-tool-call-group')==='1'){
const activeText=_activityElapsedLabel(group);
const progressText=_activityLiveProgressLabel(group);
if(activeText) group.setAttribute('data-active-turn-elapsed',activeText);
else group.removeAttribute('data-active-turn-elapsed');
durationEl.textContent=activeText?`Working ${activeText}`:'';
durationEl.style.display=activeText?'':'none';
durationEl.textContent=[progressText, activeText].filter(Boolean).join(' · ');
durationEl.style.display=durationEl.textContent?'':'none';
}else{
const durationText=_formatTurnDuration(group.dataset.turnDuration);
durationEl.textContent=durationText?`Done in ${durationText}`:'';
@@ -5941,6 +5942,25 @@ function _syncToolCallGroupSummary(group){
}
}
function _activityProgressLabelForToolName(name){
const key=String(name||'').toLowerCase().replace(/[^a-z0-9]+/g,'_');
if(!key) return 'Working';
if(key.includes('search')||key.includes('grep')) return 'Searching workspace';
if(key.includes('read')||key.includes('view')||key.includes('open')) return 'Reading files';
if(key.includes('write')||key.includes('patch')||key.includes('edit')) return 'Updating files';
if(key.includes('terminal')||key.includes('shell')||key.includes('command')||key.includes('process')) return 'Running command';
if(key.includes('web')||key.includes('fetch')||key.includes('curl')) return 'Checking web data';
if(key.includes('todo')||key.includes('plan')) return 'Planning next steps';
return 'Working';
}
function _activityLiveProgressLabel(group){
if(!group||group.getAttribute('data-live-tool-call-group')!=='1') return '';
const running=group.querySelector('.tool-card.tool-card-running .tool-card-name');
const latest=running || Array.from(group.querySelectorAll('.tool-card-name')).pop();
return _activityProgressLabelForToolName(latest?latest.textContent:'');
}
// ── Live tool card helpers (called during SSE streaming) ──
// Live cards are inserted INLINE inside #msgInner (tagged with data-live-tid)
// so the streaming layout matches the settled layout produced by renderMessages
+19
View File
@@ -214,6 +214,25 @@ class TestToolCallGroupingStatic:
"A previously-open Activity group should still restore open from persisted state."
)
def test_live_activity_summary_shows_readable_progress_without_persisted_content(self):
sync_fn = _function_body(UI_JS, "_syncToolCallGroupSummary")
progress_fn = _function_body(UI_JS, "_activityProgressLabelForToolName")
live_progress_fn = _function_body(UI_JS, "_activityLiveProgressLabel")
assert "_activityLiveProgressLabel" in sync_fn, (
"Live compact Activity rows should expose a readable transient progress label."
)
assert "durationEl.textContent" in sync_fn and "filter(Boolean).join(' · ')" in sync_fn, (
"Progress should share the existing non-persistent summary/duration slot, not become transcript text."
)
for label in ("Searching workspace", "Reading files", "Updating files", "Running command"):
assert label in progress_fn
assert "tool-card-running" in live_progress_fn, (
"The live progress label should prefer the currently running tool over older completed tools."
)
assert "tool-call-group-list" not in sync_fn, (
"Readable progress must not reintroduce the noisy secondary tool-name list."
)
def test_tools_and_thinking_share_one_collapsed_activity_dropdown(self):
ui_min = re.sub(r"\s+", "", UI_JS)
assert "functionensureActivityGroup(" in ui_min, (