From 2f208c91caf3dae4fba14bf4bb9b45be411cc61c0a06fc3dece8a763cf45c298 Mon Sep 17 00:00:00 2001 From: larssand Date: Mon, 6 Jul 2026 11:31:06 +0200 Subject: [PATCH] =?UTF-8?q?=C3=A4ndrar=20sattus=20ollama?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/fgai/dashboard.py | 1 + src/fgai/monitor.py | 8 +++++++- tests/test_dashboard.py | 4 ++++ tests/test_monitor.py | 5 +++-- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/fgai/dashboard.py b/src/fgai/dashboard.py index e73e341..4c9d511 100644 --- a/src/fgai/dashboard.py +++ b/src/fgai/dashboard.py @@ -628,6 +628,7 @@ async function refresh() { configuration.log_source === 'graylog_mcp' && mcp.status !== 'refreshing' && enabledStreams.length > 0 && displayedRawEvents === 0 ? `No raw events fetched from enabled streams. Check poll window, Graylog query, stream permissions, and Diagnostics -> Stream Coverage.` : '', enabledWithNoRawEvents.length && mcp.status !== 'refreshing' ? `${esc(enabledWithNoRawEvents.length)} enabled stream(s) returned zero raw events in ${esc(zeroRawWindow)}.` : '', mcp.coverage_warning ? `${esc(mcp.coverage_warning)}` : '', + advisor.status === 'heuristic_fallback' ? `Profile advisor: heuristic fallback (${esc(advisor.error || 'advisor unavailable')})` : '', advisor.status === 'error' ? `Profile advisor error: ${esc(advisor.error || 'unknown error')}` : '' ].filter(Boolean).join('
'); document.getElementById('health').innerHTML = [ diff --git a/src/fgai/monitor.py b/src/fgai/monitor.py index fb0ef55..420a9fe 100644 --- a/src/fgai/monitor.py +++ b/src/fgai/monitor.py @@ -432,7 +432,13 @@ def build_status( profile_suggestions = apply_profile_advice(profile_suggestions, advice) profile_advisor_status = {"enabled": True, "status": "ok" if advice else "empty", "profiles_returned": len(advice), "model": str(runtime_values.get("profile_advisor_model", "") or "qwen3:8b")} except Exception as exc: - profile_advisor_status = {"enabled": True, "status": "error", "error": str(exc), "model": str(runtime_values.get("profile_advisor_model", "") or "qwen3:8b")} + profile_advisor_status = { + "enabled": True, + "status": "heuristic_fallback", + "error": str(exc), + "model": str(runtime_values.get("profile_advisor_model", "") or "qwen3:8b"), + "candidates": len(advisor_candidates), + } for suggestion in profile_suggestions: suggestion.setdefault("profile_advisor", {"status": "heuristic", "error": str(exc)}) intel_ips = sorted( diff --git a/tests/test_dashboard.py b/tests/test_dashboard.py index 674815e..b78c470 100644 --- a/tests/test_dashboard.py +++ b/tests/test_dashboard.py @@ -66,6 +66,10 @@ class DashboardTests(unittest.TestCase): self.assertIn("No enabled streams were saved", HTML) self.assertIn("streams with existing profiles are selected for recovery", HTML) + def test_dashboard_shows_profile_advisor_fallback_as_notice(self): + self.assertIn("heuristic_fallback", HTML) + self.assertIn("Profile advisor: heuristic fallback", HTML) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_monitor.py b/tests/test_monitor.py index f32cb49..7543726 100644 --- a/tests/test_monitor.py +++ b/tests/test_monitor.py @@ -196,7 +196,7 @@ class MonitorTests(unittest.TestCase): self.assertEqual(status["llm_assessment"]["status"], "ok") self.assertEqual(status["llm_assessment"]["text"], "looks noisy") - def test_profile_advisor_status_records_error(self): + def test_profile_advisor_status_records_heuristic_fallback(self): with tempfile.TemporaryDirectory() as tmp: log_path = Path(tmp) / "events.log" log_path.write_text("fgai_stream_id=windows fgai_stream=Windows username=alice eventid=4625 action=failure\n", encoding="utf-8") @@ -207,8 +207,9 @@ class MonitorTests(unittest.TestCase): status = build_status(str(log_path), config_path=str(config_path), incident_path=str(Path(tmp) / "incidents.json")) advisor = status["capabilities"]["profile_advisor"] - self.assertEqual(advisor["status"], "error") + self.assertEqual(advisor["status"], "heuristic_fallback") self.assertIn("timeout", advisor["error"]) + self.assertEqual(advisor["candidates"], 1) self.assertEqual(status["profile_suggestions"][0]["profile_advisor"]["status"], "heuristic") self.assertIn("timeout", status["profile_suggestions"][0]["profile_advisor"]["error"])