From 2c5acb97257247b99c2dfe196590b67c327f6ff0 Mon Sep 17 00:00:00 2001 From: Michael Lam Date: Tue, 5 May 2026 13:42:47 -0700 Subject: [PATCH] feat: show active elapsed timer in compact activity --- api/routes.py | 6 +- docs/pr-media/1716/active-elapsed-timer.png | Bin 0 -> 43759 bytes static/messages.js | 3 + static/ui.js | 89 +++++++++++++++++++- tests/test_turn_duration_display.py | 27 ++++++ 5 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 docs/pr-media/1716/active-elapsed-timer.png diff --git a/api/routes.py b/api/routes.py index e2139a0c..3e6dd65c 100644 --- a/api/routes.py +++ b/api/routes.py @@ -5986,7 +5986,11 @@ def _handle_chat_start(handler, body): daemon=True, ) thr.start() - response = {"stream_id": stream_id, "session_id": s.session_id} + response = { + "stream_id": stream_id, + "session_id": s.session_id, + "pending_started_at": s.pending_started_at, + } if normalized_model: response["effective_model"] = model if model_provider: diff --git a/docs/pr-media/1716/active-elapsed-timer.png b/docs/pr-media/1716/active-elapsed-timer.png new file mode 100644 index 0000000000000000000000000000000000000000..59f468e9e18cf4379661bda13a81f88f969f8973 GIT binary patch literal 43759 zcmb@tWmH>T7cNQ#XiI^&#Y(YKT3lM(Y0(yUw>G%D%Ui*%NN{%x!9wt~IHb4}0!31a z1WzF73H{D@&K={7Gwv97-2Df#_u6aCJ=dIbJ!{TqMQN%lkv@3(fPjF2^!+<|Z2|&9 zG6I6z{`YRev{$xy>DZ(dkUG)BJY*6 zM}Ksktud@YSNa7{JN|IoBP8LBGh5W zG&(>33BD(Xx1f68$g!`dE#C1HUe4eVK0&Up`xyN_4M8SlLF?Z}2_+_~zXd?dR*SI; z7UnaG>DZ8yGbujjSdjq#t|0YnHJPZFC`LlzLVwJ=jNp$i@1haGk$YOIi0n&^d`!kYgtkrlB z0ViJe+4R2d+^7jPzn&nPUt({q zZ!teiCMEcelh>mq_&1<_9xYtep&qki;xXo4>9uY>I{Jj(jL{eJ<560?qebH9IK^au zaoxXtp%(%Ij4ka-R@gq@ybyE&ANI+Oj`wcNc`CV@6JBdtrjTSX9PH{|x|X?~Wiglj z%5}NVb=4>2>PP@k=ve)@3JHmS;w<>v+FoM$RZV}zo;&Xlobz#42OK286mV4X`o@Up zZ~O%F!n1zZ7+TI99Up@I4oJ4R2y{(tFCd9~NOged#C=q2uM58_t%liL)=H|JVq4Cx zZH`~{FtAJdC%g_k-ytNnN^BYa1$W5`$-ui9X#`))ZG!yV-KUN;4|-`-@N(NdKCNdb zAQ+Ko8+M`bQ6I-Y#xdU*iUv`#+LZS_Cjx>oO1Im>Hy)a=P=0xTE?a=;=EwivevI$( ze?hFC-V8!ux0{r_<}j}V1OnNgl4c<2rm+M(aY3XrSLmCdVYl`9^K(y+Bn{V% zyLd_Qm+3!1yyFoNxV_c=E9Q4XE!vyk1T;6%0Dt`-4Z^m5`f?$6c8%Mzx@vSEKs_U; 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

)0tI=lGAz-tM-) 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 XQOUgZooLwK|Ea2^rC2Wi>g|63mv3K! literal 0 HcmV?d00001 diff --git a/static/messages.js b/static/messages.js index c32d8fdc..b54212ce 100644 --- a/static/messages.js +++ b/static/messages.js @@ -243,6 +243,9 @@ async function send(){ } streamId=startData.stream_id; S.activeStreamId = streamId; + if(S.session&&typeof startData.pending_started_at==='number'){ + S.session.pending_started_at=startData.pending_started_at; + } if(S.session&&S.session.session_id===activeSid){ S.session.active_stream_id = streamId; } diff --git a/static/ui.js b/static/ui.js index 72adb997..af499ba8 100644 --- a/static/ui.js +++ b/static/ui.js @@ -1420,6 +1420,72 @@ function _formatTurnDuration(seconds){ if(h)return`${h}h ${m}m`; return`${m}m ${s}s`; } +function _formatActiveElapsedTimer(seconds){ + const n=Number(seconds); + if(!Number.isFinite(n)||n<0)return''; + const total=Math.max(0,Math.floor(n)); + const m=Math.floor(total/60); + const s=total%60; + return`${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}`; +} +let _activityElapsedTimer=null; +let _activityElapsedTimerGroup=null; +function _activityElapsedStartedAt(group){ + if(!group)return null; + const raw=(group.dataset&&group.dataset.turnStartedAt!==undefined&&group.dataset.turnStartedAt!=='') + ?group.dataset.turnStartedAt + :(S.session&&S.session.pending_started_at); + const started=Number(raw); + return Number.isFinite(started)&&started>0?started:null; +} +function _activityElapsedLabel(group){ + const started=_activityElapsedStartedAt(group); + if(!started)return''; + return _formatActiveElapsedTimer((Date.now()/1000)-started); +} +function _setActivityElapsedStartedAt(group){ + if(!group||group.getAttribute('data-live-tool-call-group')!=='1')return; + const started=_activityElapsedStartedAt(group); + if(started)group.setAttribute('data-turn-started-at',String(started)); +} +function _updateActiveActivityElapsedTimer(){ + const group=_activityElapsedTimerGroup; + if(!group||!group.isConnected||group.getAttribute('data-live-tool-call-group')!=='1'){ + _clearActivityElapsedTimer(); + return; + } + const durationEl=group.querySelector('.tool-call-group-duration'); + const label=_activityElapsedLabel(group); + if(label){ + group.setAttribute('data-active-turn-elapsed',label); + }else{ + group.removeAttribute('data-active-turn-elapsed'); + } + if(durationEl){ + durationEl.textContent=label?`Working ${label}`:''; + durationEl.style.display=label?'':'none'; + } +} +function _startActivityElapsedTimer(group){ + if(!group||group.getAttribute('data-live-tool-call-group')!=='1')return; + _setActivityElapsedStartedAt(group); + if(_activityElapsedTimerGroup&&_activityElapsedTimerGroup!==group)_clearActivityElapsedTimer(); + _activityElapsedTimerGroup=group; + _updateActiveActivityElapsedTimer(); + if(!_activityElapsedTimer)_activityElapsedTimer=setInterval(_updateActiveActivityElapsedTimer,1000); +} +function _clearActivityElapsedTimer(){ + if(_activityElapsedTimer){ + clearInterval(_activityElapsedTimer); + _activityElapsedTimer=null; + } + if(_activityElapsedTimerGroup&&_activityElapsedTimerGroup.isConnected){ + _activityElapsedTimerGroup.removeAttribute('data-active-turn-elapsed'); + const durationEl=_activityElapsedTimerGroup.querySelector('.tool-call-group-duration'); + if(durationEl){durationEl.textContent='';durationEl.style.display='none';} + } + _activityElapsedTimerGroup=null; +} const _MOBILE_CONFIG_BASE_LABEL='Workspace, model, reasoning, and context settings'; @@ -2438,6 +2504,7 @@ function setBusy(v){ S.busy=v; updateSendBtn(); if(!v){ + if(typeof _clearActivityElapsedTimer==='function') _clearActivityElapsedTimer(); setStatus(''); setComposerStatus(''); const sid=_queueDrainSid||(S.session&&S.session.session_id); @@ -3727,7 +3794,9 @@ function ensureActivityGroup(inner, opts){ if(anchor&&anchor.parentElement===inner) anchor.insertAdjacentElement('afterend', group); else inner.appendChild(group); } + if(live) _setActivityElapsedStartedAt(group); _syncToolCallGroupSummary(group); + if(live) _startActivityElapsedTimer(group); return group; } function _compressionStateForCurrentSession(){ @@ -4807,9 +4876,17 @@ function _syncToolCallGroupSummary(group){ } if(list) list.textContent=parts.join(' · ')||'tools / thinking'; if(durationEl){ - const durationText=_formatTurnDuration(group.dataset.turnDuration); - durationEl.textContent=durationText?`Done in ${durationText}`:''; - durationEl.style.display=durationText?'':'none'; + if(group.getAttribute('data-live-tool-call-group')==='1'){ + const activeText=_activityElapsedLabel(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'; + }else{ + const durationText=_formatTurnDuration(group.dataset.turnDuration); + durationEl.textContent=durationText?`Done in ${durationText}`:''; + durationEl.style.display=durationText?'':'none'; + } } if(badge) badge.textContent=String(total); } @@ -4896,6 +4973,7 @@ function appendLiveToolCard(tc){ } function clearLiveToolCards(){ + if(typeof _clearActivityElapsedTimer==='function') _clearActivityElapsedTimer(); const inner=_assistantTurnBlocks($('liveAssistantTurn')); if(inner) inner.querySelectorAll('.tool-call-group[data-live-tool-call-group],.tool-card-row[data-live-tid]').forEach(el=>el.remove()); // Reset the per-turn user expand intent so the next turn starts at the @@ -5699,7 +5777,10 @@ function removeThinking(){ if(blocks) blocks.querySelectorAll('.agent-activity-thinking').forEach(el=>el.remove()); if(blocks) blocks.querySelectorAll('.tool-call-group[data-agent-activity-group="1"]').forEach(group=>{ _syncToolCallGroupSummary(group); - if(!group.querySelector('.tool-card-row,.agent-activity-thinking')) group.remove(); + if(!group.querySelector('.tool-card-row,.agent-activity-thinking')){ + if(typeof _clearActivityElapsedTimer==='function') _clearActivityElapsedTimer(); + group.remove(); + } }); if(turn&&blocks&&!blocks.children.length) turn.remove(); } diff --git a/tests/test_turn_duration_display.py b/tests/test_turn_duration_display.py index b87deb74..2bd1aef5 100644 --- a/tests/test_turn_duration_display.py +++ b/tests/test_turn_duration_display.py @@ -8,6 +8,7 @@ from pathlib import Path REPO = Path(__file__).resolve().parent.parent STREAMING_PY = (REPO / "api" / "streaming.py").read_text(encoding="utf-8") MESSAGES_JS = (REPO / "static" / "messages.js").read_text(encoding="utf-8") +ROUTES_PY = (REPO / "api" / "routes.py").read_text(encoding="utf-8") UI_JS = (REPO / "static" / "ui.js").read_text(encoding="utf-8") CSS = (REPO / "static" / "style.css").read_text(encoding="utf-8") @@ -61,3 +62,29 @@ def test_ui_formats_and_renders_turn_duration_in_footer_and_activity_summary(): assert ".msg-duration-inline" in CSS and ".tool-call-group-duration" in CSS, ( "Duration UI should have explicit CSS hooks for the footer chip and compact activity summary." ) + + +def test_active_compact_activity_elapsed_timer_uses_persisted_start_time(): + assert '"pending_started_at": s.pending_started_at' in ROUTES_PY, ( + "/api/chat/start should return the persisted pending_started_at timestamp " + "so the live timer starts from backend/session truth." + ) + assert "startData.pending_started_at" in MESSAGES_JS, ( + "send() should copy chat-start pending_started_at into S.session before " + "attaching the live stream." + ) + assert "function _formatActiveElapsedTimer" in UI_JS and "padStart(2,'0')" in UI_JS, ( + "ui.js should format the running timer in MM:SS form." + ) + assert "data-turn-started-at" in UI_JS and "data-active-turn-elapsed" in UI_JS, ( + "Live compact Activity groups need stable start-time and active-elapsed " + "hooks for browser QA and reconnect/rerender safety." + ) + assert "Working " in UI_JS, ( + "The in-progress Activity summary should distinguish the live counter " + "from the settled 'Done in …' duration." + ) + assert "setInterval" in UI_JS and "_clearActivityElapsedTimer" in UI_JS, ( + "The active elapsed label should tick while running and clear its interval " + "on terminal/error/session-switch cleanup paths." + )