fix: show readable live activity progress
This commit is contained in:
1 parent
7ac4bf4f4a
commit
2e039ab7f7
3 files changed
+43
-2
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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, (
|
||||
|
||||
Reference in new issue
Block a user