Merge #4055 into stage-ml

This commit is contained in:
nesquena-hermes 2026-06-12 23:43:28 +00:00
commit 0fdfa4b9fa
4 changed files with 102 additions and 33 deletions

View file

@ -4744,44 +4744,56 @@ function _sidebarRowHasVisibleMessages(s, activeSidForSidebar){
}
function _partitionSidebarSessionRows(allMatched, activeSidForSidebar){
let webuiSessionCount=0;
let cliSessionCount=0;
for(const s of allMatched){
if(!_sidebarRowHasVisibleMessages(s, activeSidForSidebar)) continue;
if(_isCliSession(s)) cliSessionCount++;
else webuiSessionCount++;
}
if(_sessionSourceFilter==='cli' && !window._showCliSessions && cliSessionCount===0){
_sessionSourceFilter='webui';
}
const showCliOnly=_sessionSourceFilter==='cli';
const profileFiltered=[];
const sessionsRaw=[];
let archivedCount=0;
const webuiProfileFiltered=[];
const cliProfileFiltered=[];
const webuiSessionsRaw=[];
const cliSessionsRaw=[];
let webuiArchivedCount=0;
let cliArchivedCount=0;
for(const s of allMatched){
if(!_sidebarRowHasVisibleMessages(s, activeSidForSidebar)) continue;
const isCli=_isCliSession(s);
if(showCliOnly ? !isCli : isCli) continue;
if(isCli) cliSessionCount++;
if(s.default_hidden&&!(_activeProject&&_activeProject!==NO_PROJECT_FILTER&&s.project_id===_activeProject)) continue;
const profileFiltered=isCli ? cliProfileFiltered : webuiProfileFiltered;
const sessionsRaw=isCli ? cliSessionsRaw : webuiSessionsRaw;
profileFiltered.push(s);
if(_activeProject===NO_PROJECT_FILTER){
if(s.project_id) continue;
} else if(_activeProject){
if(s.project_id!==_activeProject) continue;
}
if(s.archived) archivedCount++;
if(s.archived){
if(isCli) cliArchivedCount++;
else webuiArchivedCount++;
}
if(!_showArchived&&s.archived) continue;
sessionsRaw.push(s);
}
if(_sessionSourceFilter==='cli' && !window._showCliSessions && cliSessionCount===0){
_sessionSourceFilter='webui';
}
const showCliOnly=_sessionSourceFilter==='cli';
return {
webuiSessionCount,
cliSessionCount,
profileFiltered,
sessionsRaw,
archivedCount,
profileFiltered: showCliOnly ? cliProfileFiltered : webuiProfileFiltered,
sessionsRaw: showCliOnly ? cliSessionsRaw : webuiSessionsRaw,
archivedCount: showCliOnly ? cliArchivedCount : webuiArchivedCount,
webuiSessionsRaw,
cliSessionsRaw,
};
}
function _renderSidebarRowsFromRawSessions(sessionsRaw){
return _attachChildSessionsToSidebarRows(_collapseSessionLineageForSidebar(sessionsRaw), sessionsRaw);
}
function _countRenderedSidebarRowsFromRawSessions(sessionsRaw){
// Keep inactive-tab chip counts on the exact same top-level row path as render.
return _renderSidebarRowsFromRawSessions(sessionsRaw).length;
}
function renderSessionListFromCache(){
// Don't re-render while user is actively renaming a session (would destroy the input)
if(_renamingSid) return;
@ -4805,13 +4817,20 @@ function renderSessionListFromCache(){
const searchMatches=_sessionSearchMergeMatches(sidebarRows,searchQueryRaw,_contentSearchResults);
const allMatched=_ensureActiveSessionRowPresent(searchMatches,sidebarRows);
const {
webuiSessionCount,
cliSessionCount,
profileFiltered,
sessionsRaw,
archivedCount,
webuiSessionsRaw,
cliSessionsRaw,
}=_partitionSidebarSessionRows(allMatched, activeSidForSidebar);
const sessions=_attachChildSessionsToSidebarRows(_collapseSessionLineageForSidebar(sessionsRaw), sessionsRaw);
const sessions=_renderSidebarRowsFromRawSessions(sessionsRaw);
const renderedWebuiSessionCount=_sessionSourceFilter==='webui'
? sessions.length
: _countRenderedSidebarRowsFromRawSessions(webuiSessionsRaw);
const renderedCliSessionCount=_sessionSourceFilter==='cli'
? sessions.length
: _countRenderedSidebarRowsFromRawSessions(cliSessionsRaw);
_syncSidebarExpansionForActiveSession(sessions, activeSidForSidebar);
const list=$('sessionList');
const animateRefresh=_sessionListRefreshAnimationPending;
@ -4846,7 +4865,7 @@ function renderSessionListFromCache(){
const sourceTabs=document.createElement('div');
sourceTabs.className='session-source-tabs';
for(const filter of ['webui','cli']){
const count=filter==='cli'?cliSessionCount:webuiSessionCount;
const count=filter==='cli'?renderedCliSessionCount:renderedWebuiSessionCount;
const btn=document.createElement('button');
btn.type='button';
btn.className='session-source-tab'+(_sessionSourceFilter===filter?' active':'');

View file

@ -238,6 +238,19 @@ def pytest_configure(config):
config.addinivalue_line("markers", "requires_agent_modules: skip when hermes-agent Python modules are not importable")
@pytest.hookimpl(hookwrapper=True, tryfirst=True)
def pytest_report_collectionfinish(config, items):
"""Avoid pytest-shard's giant nodeid dump on sharded `-v` CI runs."""
verbose = getattr(config.option, "verbose", 0)
shard_total = getattr(config.option, "num_shards", 1)
if shard_total > 1 and verbose > 0:
config.option.verbose = 0
try:
yield
finally:
config.option.verbose = verbose
# ── Disable AWS IMDS probing for the pytest session ────────────────────────
# Background: when hermes-agent's bedrock_adapter / botocore credential chain
# runs during test execution (e.g. provider catalog enumeration triggered by

View file

@ -19,10 +19,14 @@ def test_sidebar_has_separate_webui_and_cli_session_source_tabs():
def test_cli_filter_keeps_cli_rows_out_of_default_webui_list():
src = SESSIONS_JS.read_text(encoding="utf-8")
assert "function _partitionSidebarSessionRows(allMatched, activeSidForSidebar)" in src
assert "webuiSessionCount" in src
assert "cliSessionCount" in src
assert "const showCliOnly=_sessionSourceFilter==='cli';" in src
assert "if(showCliOnly ? !isCli : isCli) continue;" in src
assert "const webuiProfileFiltered=[];" in src
assert "const cliProfileFiltered=[];" in src
assert "const webuiSessionsRaw=[];" in src
assert "const cliSessionsRaw=[];" in src
assert "profileFiltered: showCliOnly ? cliProfileFiltered : webuiProfileFiltered," in src
assert "sessionsRaw: showCliOnly ? cliSessionsRaw : webuiSessionsRaw," in src
def test_session_source_tabs_have_dedicated_sidebar_styles():

View file

@ -8,18 +8,35 @@ ROOT = Path(__file__).resolve().parents[1]
SESSIONS_JS = (ROOT / "static" / "sessions.js").read_text(encoding="utf-8")
def _function_block(name: str) -> str:
start = SESSIONS_JS.index(f"function {name}(")
brace = SESSIONS_JS.index("{", start)
depth = 0
for idx in range(brace, len(SESSIONS_JS)):
char = SESSIONS_JS[idx]
if char == "{":
depth += 1
elif char == "}":
depth -= 1
if depth == 0:
return SESSIONS_JS[start : idx + 1]
raise AssertionError(f"unbalanced braces in {name}")
def _partition_block() -> str:
start = SESSIONS_JS.index("function _partitionSidebarSessionRows(")
end = SESSIONS_JS.index("function renderSessionListFromCache()", start)
return SESSIONS_JS[start:end]
return _function_block("_partitionSidebarSessionRows")
def test_render_uses_single_pass_partition_helper():
render_start = SESSIONS_JS.index("function renderSessionListFromCache()")
render_end = SESSIONS_JS.index("function _showProjectPicker", render_start)
render_body = SESSIONS_JS[render_start:render_end]
render_body = _function_block("renderSessionListFromCache")
assert "_partitionSidebarSessionRows(allMatched, activeSidForSidebar)" in render_body
assert "_renderSidebarRowsFromRawSessions(sessionsRaw)" in render_body
assert "? sessions.length" in render_body
assert ": _countRenderedSidebarRowsFromRawSessions(webuiSessionsRaw);" in render_body
assert ": _countRenderedSidebarRowsFromRawSessions(cliSessionsRaw);" in render_body
assert "const count=filter==='cli'?renderedCliSessionCount:renderedWebuiSessionCount;" in render_body
assert "const count=filter==='cli'?cliSessionCount:webuiSessionCount;" not in render_body
assert "withMessages.filter(" not in render_body
@ -31,7 +48,23 @@ def test_partition_helper_applies_message_source_project_and_archive_gates():
assert "if(_sessionSourceFilter==='cli' && !window._showCliSessions && cliSessionCount===0)" in block
assert "const showCliOnly=_sessionSourceFilter==='cli';" in block
assert "if(!_showArchived&&s.archived) continue;" in block
assert "if(s.archived) archivedCount++;" in block
assert "if(s.archived){" in block
assert "archivedCount: showCliOnly ? cliArchivedCount : webuiArchivedCount," in block
assert "return {" in block
assert "profileFiltered," in block
assert "sessionsRaw," in block
assert "profileFiltered: showCliOnly ? cliProfileFiltered : webuiProfileFiltered," in block
assert "sessionsRaw: showCliOnly ? cliSessionsRaw : webuiSessionsRaw," in block
def test_partition_helper_keeps_raw_source_counts_while_render_owns_visible_counts():
render_body = _function_block("renderSessionListFromCache")
assert "webuiSessionCount," not in _partition_block()
assert "cliSessionCount," in _partition_block()
assert "webuiSessionsRaw," in _partition_block()
assert "cliSessionsRaw," in _partition_block()
assert "const renderedWebuiSessionCount=" in render_body
assert "const renderedCliSessionCount=" in render_body
helper_body = _function_block("_countRenderedSidebarRowsFromRawSessions")
assert "_renderSidebarRowsFromRawSessions(sessionsRaw).length;" in helper_body
assert "function _renderSidebarRowsFromRawSessions(sessionsRaw){" in SESSIONS_JS
assert "_attachChildSessionsToSidebarRows(_collapseSessionLineageForSidebar(sessionsRaw), sessionsRaw)" in SESSIONS_JS