From f125364f8e8976c651a830792ec8860c879a9444 Mon Sep 17 00:00:00 2001 From: Jaixii Date: Wed, 5 Aug 2026 21:26:25 -0400 Subject: [PATCH] feat: show version in dashboard settings and startup banner - Settings panel (both dashboards): add Version row in Engine section that fetches from /api/info and displays the running version - Startup banner: print 'Engraphis WebUI v{version}' and Version line - Both static/ and classic_assets/ dashboards updated (byte-identical JS) - Uses existing /api/info endpoint (already returns version) Users can now see their Engraphis version in: - CLI: engraphis --version - Python: from engraphis import __version__ - pip: pip show engraphis - REST API: GET /api/info - Dashboard: Settings > Appearance & Engine > Version - Startup: terminal banner when launching engraphis-dashboard --- engraphis/classic_assets/dashboard.js | 2 +- engraphis/classic_assets/index.html | 1 + engraphis/static/dashboard.js | 2 +- engraphis/static/index.html | 1 + scripts/start_dashboard.py | 7 ++++++- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/engraphis/classic_assets/dashboard.js b/engraphis/classic_assets/dashboard.js index 1011e4f6..a25bdc38 100644 --- a/engraphis/classic_assets/dashboard.js +++ b/engraphis/classic_assets/dashboard.js @@ -563,7 +563,7 @@ async function loadTeam(){const el=document.getElementById('team-body'),teamCta= /* health + settings */ function connectionContext(){const host=(location.hostname||'').toLowerCase();return host==='localhost'||host==='127.0.0.1'||host==='::1'||host.endsWith('.localhost')?'Local engine':'Remote customer node'} async function checkHealth(){const label=connectionContext();try{await api('/health');const d=document.getElementById('health-dot'),t=document.getElementById('health-text');if(d){d.classList.add('health-ok');d.classList.remove('health-error')}if(t)t.textContent=label+' connected'}catch(e){const d=document.getElementById('health-dot'),t=document.getElementById('health-text');if(d){d.classList.add('health-error');d.classList.remove('health-ok')}if(t)t.textContent=label+' unavailable'}} -function loadSettings(){loadLicense();loadSyncStatus();loadHostedAgentAccess();loadLlmStatus();const s=document.getElementById('cfg-store');if(s)s.textContent=location.host} +function loadSettings(){loadLicense();loadSyncStatus();loadHostedAgentAccess();loadLlmStatus();const s=document.getElementById('cfg-store');if(s)s.textContent=location.host;api('/info').then(function(d){var v=document.getElementById('cfg-version');if(v&&d&&d.version)v.textContent=d.version}).catch(function(){})} async function loadLlmStatus(){const el=document.getElementById('llm-body');if(!el)return;try{const st=await api('/llm/status');const ok=st.configured;const badge=ok?'configured':'not configured';const keyLine=st.key_set?'API key set ✓':'No API key set';let modelSel='';let provSel='';el.innerHTML=`
Provider · Model${badge}
${provSel}${modelSel}
${keyLine} · extractor: ${esc(st.extractor)}
Add this to your .env and restart Engraphis:
LLM extraction${st.extractor_enabled?'ON':'OFF'}
While ON, ingested memory content is sent to your LLM provider for schema-validated extraction. OFF disables extraction transfers only; retention supervision is configured separately.
`}catch(e){el.innerHTML='
'+esc(e.message)+'
'}} function onLlmProvChange(){const p=document.getElementById('llm-prov').value;const sel=document.getElementById('llm-model');const defs={openai:'gpt-4o-mini',anthropic:'claude-3-5-sonnet-20241022',google:'gemini-1.5-flash',openrouter:'openai/gpt-4o-mini'};if(sel&&defs[p]){sel.value=defs[p]}updateLlmSnippet()} diff --git a/engraphis/classic_assets/index.html b/engraphis/classic_assets/index.html index 4630a2b0..d5a44f24 100644 --- a/engraphis/classic_assets/index.html +++ b/engraphis/classic_assets/index.html @@ -286,6 +286,7 @@
Dashboard
Enginev2 (bi-temporal)
Store
+
Version
diff --git a/engraphis/static/dashboard.js b/engraphis/static/dashboard.js index 1011e4f6..a25bdc38 100644 --- a/engraphis/static/dashboard.js +++ b/engraphis/static/dashboard.js @@ -563,7 +563,7 @@ async function loadTeam(){const el=document.getElementById('team-body'),teamCta= /* health + settings */ function connectionContext(){const host=(location.hostname||'').toLowerCase();return host==='localhost'||host==='127.0.0.1'||host==='::1'||host.endsWith('.localhost')?'Local engine':'Remote customer node'} async function checkHealth(){const label=connectionContext();try{await api('/health');const d=document.getElementById('health-dot'),t=document.getElementById('health-text');if(d){d.classList.add('health-ok');d.classList.remove('health-error')}if(t)t.textContent=label+' connected'}catch(e){const d=document.getElementById('health-dot'),t=document.getElementById('health-text');if(d){d.classList.add('health-error');d.classList.remove('health-ok')}if(t)t.textContent=label+' unavailable'}} -function loadSettings(){loadLicense();loadSyncStatus();loadHostedAgentAccess();loadLlmStatus();const s=document.getElementById('cfg-store');if(s)s.textContent=location.host} +function loadSettings(){loadLicense();loadSyncStatus();loadHostedAgentAccess();loadLlmStatus();const s=document.getElementById('cfg-store');if(s)s.textContent=location.host;api('/info').then(function(d){var v=document.getElementById('cfg-version');if(v&&d&&d.version)v.textContent=d.version}).catch(function(){})} async function loadLlmStatus(){const el=document.getElementById('llm-body');if(!el)return;try{const st=await api('/llm/status');const ok=st.configured;const badge=ok?'configured':'not configured';const keyLine=st.key_set?'API key set ✓':'No API key set';let modelSel='';let provSel='';el.innerHTML=`
Provider · Model${badge}
${provSel}${modelSel}
${keyLine} · extractor: ${esc(st.extractor)}
Add this to your .env and restart Engraphis:
LLM extraction${st.extractor_enabled?'ON':'OFF'}
While ON, ingested memory content is sent to your LLM provider for schema-validated extraction. OFF disables extraction transfers only; retention supervision is configured separately.
`}catch(e){el.innerHTML='
'+esc(e.message)+'
'}} function onLlmProvChange(){const p=document.getElementById('llm-prov').value;const sel=document.getElementById('llm-model');const defs={openai:'gpt-4o-mini',anthropic:'claude-3-5-sonnet-20241022',google:'gemini-1.5-flash',openrouter:'openai/gpt-4o-mini'};if(sel&&defs[p]){sel.value=defs[p]}updateLlmSnippet()} diff --git a/engraphis/static/index.html b/engraphis/static/index.html index 8ea441a9..2c30595e 100644 --- a/engraphis/static/index.html +++ b/engraphis/static/index.html @@ -286,6 +286,7 @@
Theme
Enginev2 (bi-temporal)
Store
+
Version
diff --git a/scripts/start_dashboard.py b/scripts/start_dashboard.py index 43fc4779..d68423af 100644 --- a/scripts/start_dashboard.py +++ b/scripts/start_dashboard.py @@ -190,6 +190,10 @@ def main(argv=None) -> None: os.environ["ENGRAPHIS_HOST"] = args.host os.environ["ENGRAPHIS_PORT"] = str(args.port) + try: + from engraphis import __version__ as _engraphis_version + except Exception: + _engraphis_version = "unknown" try: # Imported AFTER the env writes above: this snapshot and uvicorn's in-process # import of the app see the same values, so the banner reports the RESOLVED DB @@ -208,10 +212,11 @@ def main(argv=None) -> None: except (Exception, SystemExit) as exc: # noqa: BLE001 - convert startup failures to UX ap.exit(1, "Error: %s\n" % _startup_error(exc, db)) - print(f"Engraphis WebUI - {url}") + print(f"Engraphis WebUI v{_engraphis_version} - {url}") print(f" Dashboard : {url}/") print(f" REST API : {url}/api") print(f" Database : {db}") + print(f" Version : {_engraphis_version}") print(" Press Ctrl+C to stop.") sys.stdout.flush()