77 lines
3.5 KiB
Python
77 lines
3.5 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""Apply Atlas baseline UI policy patches to the pinned Hermes WebUI."""
|
||
|
|
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
config = Path("/opt/hermes-webui/api/config.py")
|
||
|
|
source = config.read_text(encoding="utf-8")
|
||
|
|
before = (
|
||
|
|
'VALID_REASONING_EFFORTS = ("minimal", "low", "medium", "high", "xhigh", "max")'
|
||
|
|
)
|
||
|
|
after = 'VALID_REASONING_EFFORTS = ("minimal", "low", "medium", "high", "xhigh")'
|
||
|
|
if source.count(before) != 1:
|
||
|
|
raise SystemExit("Hermes WebUI reasoning-effort patch context changed")
|
||
|
|
config.write_text(source.replace(before, after, 1), encoding="utf-8")
|
||
|
|
|
||
|
|
index = Path("/opt/hermes-webui/static/index.html")
|
||
|
|
source = index.read_text(encoding="utf-8")
|
||
|
|
before = ' <div class="reasoning-option" data-effort="max">Max</div>\n'
|
||
|
|
if source.count(before) != 1:
|
||
|
|
raise SystemExit("Hermes WebUI xhigh UI patch context changed")
|
||
|
|
index.write_text(source.replace(before, "", 1), encoding="utf-8")
|
||
|
|
|
||
|
|
# oauth2-proxy returns 401 for browser API and health probes when the secure
|
||
|
|
# session expires. Re-enter OIDC with the complete return path.
|
||
|
|
ui = Path("/opt/hermes-webui/static/ui.js")
|
||
|
|
source = ui.read_text(encoding="utf-8")
|
||
|
|
before = """ const res=await fetcher(_offlineHealthUrl(),opts);
|
||
|
|
return !!(res&&res.ok);
|
||
|
|
"""
|
||
|
|
after = """ const res=await fetcher(_offlineHealthUrl(),opts);
|
||
|
|
if(res&&(res.status===401||res.status===403)){
|
||
|
|
const rd=window.location.pathname+window.location.search+window.location.hash;
|
||
|
|
window.location.assign('/oauth2/start?rd='+encodeURIComponent(rd));
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return !!(res&&res.ok);
|
||
|
|
"""
|
||
|
|
if source.count(before) != 1:
|
||
|
|
raise SystemExit("Hermes WebUI auth-recovery patch context changed")
|
||
|
|
ui.write_text(source.replace(before, after, 1), encoding="utf-8")
|
||
|
|
|
||
|
|
# Make delegated session hierarchy obvious and collapsible in the sidebar.
|
||
|
|
sessions = Path("/opt/hermes-webui/static/sessions.js")
|
||
|
|
source = sessions.read_text(encoding="utf-8")
|
||
|
|
before = """ const childLabel=t('session_meta_children', childCount);
|
||
|
|
childCountEl.textContent=childLabel;
|
||
|
|
childCountEl.title=_sessionChildBadgeTooltip(childLabel);
|
||
|
|
"""
|
||
|
|
after = """ const childLabel=t('session_meta_children', childCount);
|
||
|
|
const childrenExpanded=_expandedChildSessionKeys.has(lineageKey)||!!searchQueryRaw;
|
||
|
|
childCountEl.textContent=(childrenExpanded?'▾ ':'▸ ')+childLabel;
|
||
|
|
childCountEl.setAttribute('aria-expanded',childrenExpanded?'true':'false');
|
||
|
|
childCountEl.title=_sessionChildBadgeTooltip(childLabel);
|
||
|
|
"""
|
||
|
|
if source.count(before) != 1:
|
||
|
|
raise SystemExit("Hermes WebUI child-session toggle patch context changed")
|
||
|
|
sessions.write_text(source.replace(before, after, 1), encoding="utf-8")
|
||
|
|
|
||
|
|
# A profile's model is only its default; label that scope in both render paths.
|
||
|
|
panels = Path("/opt/hermes-webui/static/panels.js")
|
||
|
|
source = panels.read_text(encoding="utf-8")
|
||
|
|
before = " if (typeof p.model === 'string' && p.model) meta.push(p.model.split('/').pop());\n"
|
||
|
|
after = """ if (typeof p.model === 'string' && p.model) {
|
||
|
|
const routeLabels = {
|
||
|
|
'atlas/auto/fast': 'Automatic · Fast',
|
||
|
|
'atlas/auto/balanced': 'Automatic · Balanced',
|
||
|
|
'atlas/auto/deep': 'Automatic · Deep',
|
||
|
|
'atlas/auto/maximum': 'Automatic · Maximum',
|
||
|
|
};
|
||
|
|
meta.push('profile default: ' + (routeLabels[p.model] || p.model.split('/').pop()));
|
||
|
|
}
|
||
|
|
"""
|
||
|
|
if source.count(before) != 2:
|
||
|
|
raise SystemExit("Hermes WebUI profile-model label patch context changed")
|
||
|
|
panels.write_text(source.replace(before, after, 2), encoding="utf-8")
|