Merge pull request #4199 from nesquena/stage-od3

Release OD (v0.51.417): preserve sidebar issue numbers (#4193) + guard external-refresh poll (#4195)
This commit is contained in:
nesquena-hermes
2026-06-14 12:36:32 -07:00
committed by GitHub
4 changed files with 101 additions and 2 deletions
+7
View File
@@ -3,6 +3,13 @@
## [Unreleased]
## [v0.51.417] — 2026-06-14 — Release OD (sidebar issue-number + external-refresh fixes, #4154/#3916)
### Fixed
- **GitHub issue numbers in session titles are no longer stripped from the sidebar (#4154).** The sidebar tag extractor treated any `#word` as an attention tag and removed it from the displayed title, so a title like "Fix #1234" lost its issue reference. Purely-numeric `#NNNN` patterns are now preserved while real attention tags (`#approval`, `#clarify`, …) still extract. (#4154)
- **The 30-second external-refresh poll no longer fires for non-external sessions (#3916).** `refreshActiveSessionIfExternallyUpdated` now early-returns for WebUI-native sessions, which don't need the external-update reconciliation, avoiding needless reload churn. (#3916)
## [v0.51.416] — 2026-06-14 — Release OC (cache + single-flight /api/sessions payloads, #3791)
### Fixed
+3 -2
View File
@@ -3650,6 +3650,7 @@ async function refreshActiveSessionIfExternallyUpdated(reason){
if(_activeSessionExternalRefreshInFlight) return;
if(!S.session || !S.session.session_id) return;
if(S.busy || S.activeStreamId) return;
if(!_isExternalSession(S.session)) return;
// Cooldown: don't force-reload immediately after streaming ends — the
// "done" event already delivered the final messages. Reloading here would
// clear S.toolCalls and lose Activity.
@@ -4726,7 +4727,7 @@ function _sessionTitleIsDefaultWebUI(rawTitle){
function _sessionTitleTags(rawTitle){
if(_sessionTitleIsDefaultWebUI(rawTitle)) return [];
return String(rawTitle||'').match(/#[\w-]+/g)||[];
return String(rawTitle||'').match(/#(?!\d+\b)[\w-]+/g)||[];
}
function _activeSessionIdForSidebar(){
@@ -5427,7 +5428,7 @@ function renderSessionListFromCache(){
if(isActive&&S.session&&S.session._flash)delete S.session._flash;
const rawTitle=_sessionDisplayTitle(s);
const tags=_sessionTitleTags(rawTitle);
let cleanTitle=tags.length?rawTitle.replace(/#[\w-]+/g,'').trim():rawTitle;
let cleanTitle=tags.length?rawTitle.replace(/#(?!\d+\b)[\w-]+/g,'').trim():rawTitle;
// Guard: system prompt content must never surface as a visible session title
if(cleanTitle.startsWith('[SYSTEM:')){
cleanTitle='Session';
@@ -0,0 +1,24 @@
import re
from pathlib import Path
SESSIONS_JS = Path(__file__).resolve().parent.parent / "static" / "sessions.js"
def test_refreshActiveSessionIfExternallyUpdated_exists():
src = SESSIONS_JS.read_text(encoding="utf-8")
assert "async function refreshActiveSessionIfExternallyUpdated" in src
def test_isExternalSession_guard_present():
src = SESSIONS_JS.read_text(encoding="utf-8")
m = re.search(
r"async function refreshActiveSessionIfExternallyUpdated\b.*?^}",
src,
re.DOTALL | re.MULTILINE,
)
assert m, "refreshActiveSessionIfExternallyUpdated function not found"
body = m.group(0)
assert re.search(r"if\s*\(\s*!\s*_isExternalSession\s*\(", body), (
"refreshActiveSessionIfExternallyUpdated must have an early-return "
"guard: if(!_isExternalSession(...))"
)
@@ -0,0 +1,67 @@
"""Regression tests for #4154: sidebar strips GitHub issue numbers from titles.
The _sessionTitleTags regex must NOT treat purely numeric #NNNN patterns as
tags. Only known attention/session-control tags like #approval, #clarify,
#attention should be extracted.
"""
import re
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SESSIONS_JS = ROOT / "static" / "sessions.js"
def _read_sessions_js():
return SESSIONS_JS.read_text(encoding="utf-8")
def test_sessionTitleTags_function_exists():
"""The _sessionTitleTags function must be present in sessions.js."""
src = _read_sessions_js()
assert "function _sessionTitleTags" in src
def test_regex_excludes_numeric_issue_numbers():
"""The regex in _sessionTitleTags must use a negative lookahead to skip
purely numeric #NNNN patterns (GitHub issue references)."""
src = _read_sessions_js()
# The fix replaces /#[\w-]+/g with /#(?!\d+\b)[\w-]+/g
assert r"#(?!\d+\b)[\w-]+" in src, (
"Expected negative lookahead regex /#(??!\\d+\\b)[\\w-]+/ in _sessionTitleTags"
)
# The old broad pattern must NOT be the only pattern present
# (the negative lookahead variant must exist)
def test_old_broad_regex_not_still_present():
r"""The old /#[\w-]+/g pattern (without negative lookahead) must not appear
in _sessionTitleTags or _renderOneSession tag-stripping code."""
src = _read_sessions_js()
# Find _sessionTitleTags function body
match = re.search(
r"function _sessionTitleTags\(rawTitle\)\{(.*?)\n\}",
src,
re.DOTALL,
)
assert match, "Could not locate _sessionTitleTags function body"
body = match.group(1)
# The function body must not contain the old broad regex
assert "/#[\\w-]+/g" not in body.replace(" ", ""), (
"_sessionTitleTags still uses the old broad /#[\\w-]+/g regex"
)
def test_regex_applied_in_renderOneSession_too():
"""The tag-stripping regex in _renderOneSession must also use the
negative lookahead so visible titles keep issue numbers."""
src = _read_sessions_js()
# Find the cleanTitle line
assert r"#(?!\d+\b)[\w-]+" in src
# Confirm it appears at least twice (once in _sessionTitleTags, once in
# _renderOneSession)
count = src.count(r"#(?!\d+\b)[\w-]+")
assert count >= 2, (
f"Expected negative lookahead regex in at least 2 locations "
f"(_sessionTitleTags + _renderOneSession), found {count}"
)