#3020: Sync viewed-count in the polling path for actively-viewed sessions so navigating away doesn't show a stale unread dot. Defensive clear of completion-unread marker in _setSessionViewedCount. #2973: Clear elapsed-timer attributes and interval when a live compression card transitions from running to done, preventing the orphan timer from overwriting the completed card state. Guarded by active-session check. Tool card duplication: Route tool_complete result to tc.snippet (detail) instead of tc.preview (header) to prevent identical content appearing in both the card header and expanded detail section. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
c8afb37ae7
commit
0002cda23d
3 files changed
+32
-3
No files matched your search
+9
-1
@@ -1673,7 +1673,15 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
|
||||
tc={name:d.name||'tool', preview:d.preview||'', args:d.args||{}, snippet:'', done:true};
|
||||
inflight.toolCalls.push(tc);
|
||||
}
|
||||
tc.preview=d.preview||tc.preview||'';
|
||||
// Route result to .snippet (detail) instead of overwriting .preview
|
||||
// (header). During streaming .preview already holds the last progress
|
||||
// text — replacing it with the same content caused header/detail
|
||||
// duplication. Fallback: if no progress events were sent, use the
|
||||
// result as preview so the header is not blank.
|
||||
if(d.preview){
|
||||
tc.snippet=tc.snippet||d.preview;
|
||||
if(!tc.preview) tc.preview=d.preview;
|
||||
}
|
||||
tc.args=d.args||tc.args||{};
|
||||
tc.done=true;
|
||||
tc.is_error=!!d.is_error;
|
||||
|
||||
+10
-2
@@ -142,6 +142,9 @@ function _setSessionViewedCount(sid, messageCount = 0) {
|
||||
const next = Number.isFinite(messageCount) ? Number(messageCount) : 0;
|
||||
counts[sid] = next;
|
||||
_saveSessionViewedCounts();
|
||||
// If the viewed count is now current, any prior completion-unread marker is
|
||||
// stale — clear it so _hasUnreadForSession doesn't short-circuit (#3020).
|
||||
_clearSessionCompletionUnread(sid);
|
||||
}
|
||||
|
||||
function _getSessionCompletionUnread() {
|
||||
@@ -407,8 +410,13 @@ function _markPollingCompletionUnreadTransitions(sessions) {
|
||||
)
|
||||
);
|
||||
const completedPersistedObservedStream = Boolean(observedStreaming && !isStreaming);
|
||||
if ((completedObservedStream || completedPersistedObservedStream || completedWithNewMessages) && !_isSessionActivelyViewedForList(sid)) {
|
||||
_markSessionCompletionUnread(sid, s.message_count);
|
||||
if (completedObservedStream || completedPersistedObservedStream || completedWithNewMessages) {
|
||||
if (!_isSessionActivelyViewedForList(sid)) {
|
||||
_markSessionCompletionUnread(sid, s.message_count);
|
||||
} else {
|
||||
// Sync viewed count so we don't flag stale unread on tab switch (#3020)
|
||||
_setSessionViewedCount(sid, messageCount);
|
||||
}
|
||||
}
|
||||
_sessionStreamingById.set(sid, isStreaming);
|
||||
if (isStreaming) {
|
||||
|
||||
@@ -5682,6 +5682,19 @@ function appendLiveCompressionCard(state){
|
||||
node.setAttribute('data-compression-started-at',String(started));
|
||||
node.setAttribute('data-compression-message',String(state.message||'Auto-compressing context...'));
|
||||
_startCompressionElapsedTimer();
|
||||
} else {
|
||||
// Completion or error: clear the elapsed-timer attributes so the
|
||||
// interval reader (_compressionLiveCardState) doesn't keep treating
|
||||
// the replaced card as a running compression (#2973).
|
||||
node.removeAttribute('data-compression-started-at');
|
||||
node.removeAttribute('data-compression-message');
|
||||
// Only clear the global timer when the *active* session has no running
|
||||
// compression. An SSE completion for a background session must not
|
||||
// kill the timer that's driving the current session's display.
|
||||
const _activeCompState = _compressionStateForCurrentSession();
|
||||
if (!_activeCompState || !_activeCompState.automatic || _activeCompState.phase !== 'running') {
|
||||
_clearCompressionElapsedTimer();
|
||||
}
|
||||
}
|
||||
const existing=inner.querySelector('[data-live-compression-card="1"]');
|
||||
if(existing) existing.replaceWith(node);
|
||||
|
||||
Reference in new issue
Block a user