From 832d5acf6847512986b0fc896ef17050df1fde19 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Tue, 27 Jan 2026 21:27:19 -0300 Subject: [PATCH] atlasbot: improve metric parsing and cluster intent --- services/comms/scripts/atlasbot/bot.py | 48 +++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/services/comms/scripts/atlasbot/bot.py b/services/comms/scripts/atlasbot/bot.py index 2c93b75..b9bc0e6 100644 --- a/services/comms/scripts/atlasbot/bot.py +++ b/services/comms/scripts/atlasbot/bot.py @@ -190,6 +190,8 @@ _INSIGHT_HINT_WORDS = { "surprising", "weird", "odd", + "unusual", + "outlier", "fun", "cool", "unique", @@ -540,6 +542,13 @@ def _detect_operation(q: str) -> str | None: def _detect_metric(q: str) -> str | None: tokens = set(_tokens(q)) + expanded: set[str] = set(tokens) + for token in list(tokens): + for part in re.split(r"[-_]", token): + part = part.strip() + if len(part) >= 2: + expanded.add(part) + tokens = expanded for metric, phrases in METRIC_HINTS.items(): for phrase in phrases: if " " in phrase: @@ -1271,6 +1280,19 @@ def snapshot_metric_answer( pending = metrics.get("pods_pending") failed = metrics.get("pods_failed") succeeded = metrics.get("pods_succeeded") + status_terms = ("running", "pending", "failed", "succeeded", "completed") + if sum(1 for term in status_terms if term in q) > 1: + parts = [] + if running is not None: + parts.append(f"running {running:.0f}") + if pending is not None: + parts.append(f"pending {pending:.0f}") + if failed is not None: + parts.append(f"failed {failed:.0f}") + if succeeded is not None: + parts.append(f"succeeded {succeeded:.0f}") + if parts: + return _format_confidence(f"Pods: {', '.join(parts)}.", "high") if "pending" in q and pending is not None: return _format_confidence(f"Pending pods: {pending:.0f}.", "high") if "failed" in q and failed is not None: @@ -1345,7 +1367,17 @@ def structured_answer( if hw_line: return _format_confidence(hw_line, "high") - if op == "top" and metric is None: + if entity == "node" and op == "status" and metric is None: + summary = _nodes_summary_line(inventory, snapshot) + if summary: + return _format_confidence(summary, "high") + + if entity == "node" and metric is None and any(word in q for word in ("hardware", "architecture", "class", "mix")): + hw_line = _hardware_mix_line(inventory) + if hw_line: + return _format_confidence(hw_line, "medium") + + if op == "top" and metric is None and not any(word in q for word in ("hardware", "architecture", "class")): metric = "cpu" # Metrics-first when a metric or top operation is requested. @@ -2807,8 +2839,11 @@ class _AtlasbotHandler(BaseHTTPRequestHandler): inventory=inventory, workloads=workloads, ) - cluster_query = _is_cluster_query(cleaned, inventory=inventory, workloads=workloads) or ( - _is_subjective_query(cleaned) and history_cluster + cluster_query = ( + _is_cluster_query(cleaned, inventory=inventory, workloads=workloads) + or history_cluster + or _knowledge_intent(cleaned) + or _is_subjective_query(cleaned) ) context = "" if cluster_query: @@ -3347,8 +3382,11 @@ def sync_loop(token: str, room_id: str): inventory=inventory, workloads=workloads, ) - cluster_query = _is_cluster_query(cleaned_body, inventory=inventory, workloads=workloads) or ( - _is_subjective_query(cleaned_body) and history_cluster + cluster_query = ( + _is_cluster_query(cleaned_body, inventory=inventory, workloads=workloads) + or history_cluster + or _knowledge_intent(cleaned_body) + or _is_subjective_query(cleaned_body) ) context = "" if cluster_query: