diff --git a/services/comms/atlasbot-deployment.yaml b/services/comms/atlasbot-deployment.yaml index e1ff2bb..4ac3582 100644 --- a/services/comms/atlasbot-deployment.yaml +++ b/services/comms/atlasbot-deployment.yaml @@ -16,7 +16,7 @@ spec: labels: app: atlasbot annotations: - checksum/atlasbot-configmap: manual-atlasbot-66 + checksum/atlasbot-configmap: manual-atlasbot-67 vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "comms" vault.hashicorp.com/agent-inject-secret-turn-secret: "kv/data/atlas/comms/turn-shared-secret" diff --git a/services/comms/scripts/atlasbot/bot.py b/services/comms/scripts/atlasbot/bot.py index abdcbf2..0d0f92b 100644 --- a/services/comms/scripts/atlasbot/bot.py +++ b/services/comms/scripts/atlasbot/bot.py @@ -579,6 +579,10 @@ def _detect_entity(q: str) -> str | None: or "architecture" in q or "machine" in q or "machines" in q + or "host" in q + or "hosts" in q + or "hostname" in q + or "hostnames" in q or TITAN_NODE_RE.search(q) ): return "node" @@ -1775,20 +1779,29 @@ def _format_insight_text(key: str, text: str) -> str: .strip() .strip(".") ) + has_jetson = "jetson=" in counts + has_amd64 = "amd64=" in counts detail = f"mixed hardware stack ({counts})" - flavor = "It blends low-power Pis with Jetson accelerators and a couple of AMD64 nodes." + if has_jetson and has_amd64: + flavor = "It blends low-power Pis with Jetson accelerators and a couple of AMD64 boxes." + elif has_jetson: + flavor = "It pairs low-power Pis with Jetson accelerators for edge and AI workloads." + elif has_amd64: + flavor = "It mixes low-power Pis with a couple of heavier AMD64 nodes." + else: + flavor = "It is a pretty uniform hardware stack, which is rare for a homelab." return f"{detail}. {flavor}" if key == "postgres": detail = cleaned.replace("Postgres is at ", "") - return f"Postgres is at {detail}; that suggests moderate load." + return f"Postgres is at {detail}; that feels like healthy, steady load rather than strain." if key == "pods": detail = cleaned.replace("There are ", "") - return f"Pods look steady ({detail}); the workload mix looks healthy." + return f"Pods look steady ({detail}); nothing looks stuck or unhealthy." if key == "availability": - return cleaned + " That suggests the cluster is stable right now." + return cleaned + " That is the kind of stability I like to see." if key in ("cpu", "ram"): suffix = ( - " If you're chasing hotspots, that's the busiest workload right now." + " If you're chasing hotspots, that's the node I'd watch first." if key == "cpu" else " That box is carrying the heaviest memory load right now." ) @@ -1799,19 +1812,19 @@ def _format_insight_text(key: str, text: str) -> str: def _insight_prefix(prompt: str) -> str: q = normalize_query(prompt) if "coolest" in q: - return "If I had to pick the coolest detail: " + return "If I had to pick the coolest detail, I'd say " if "favorite" in q or "favourite" in q: - return "My favorite detail: " + return "My favorite detail is " if "trivia" in q: return "A bit of trivia I like: " if "most interesting" in q: - return "The most interesting detail to me: " + return "The most interesting detail to me is " if any(word in q for word in ("another", "else", "different", "other")): return "Another interesting detail: " if any(word in q for word in ("unconventional", "weird", "odd", "unique", "surprising")): - return "What stands out is that " + return "What stands out to me is that " if any(word in q for word in ("interesting", "notable", "fun", "cool")): - return "One thing I'd highlight: " + return "One thing I'd call out is " return "" @@ -2389,6 +2402,21 @@ def _normalize_reply(value: Any) -> str: return _ensure_confidence(text) +def _history_payload_lines(history_payload: list[Any]) -> list[str]: + lines: list[str] = [] + if not isinstance(history_payload, list): + return lines + for item in history_payload[-12:]: + if isinstance(item, dict): + for key in ("content", "message", "text", "prompt", "question", "body", "answer", "reply", "response"): + val = item.get(key) + if isinstance(val, str) and val.strip(): + lines.append(val.strip()) + elif isinstance(item, str) and item.strip(): + lines.append(item.strip()) + return [line for line in lines if line] + + # Internal HTTP endpoint for cluster answers (website uses this). class _AtlasbotHandler(BaseHTTPRequestHandler): server_version = "AtlasbotHTTP/1.0" @@ -2439,15 +2467,7 @@ class _AtlasbotHandler(BaseHTTPRequestHandler): inventory = _snapshot_inventory(snapshot) or node_inventory_live() workloads = _snapshot_workloads(snapshot) history_payload = payload.get("history") or [] - history_lines: list[str] = [] - if isinstance(history_payload, list): - for item in history_payload[-10:]: - if isinstance(item, dict): - content = item.get("content") or item.get("message") or "" - if isinstance(content, str) and content.strip(): - history_lines.append(content.strip()) - elif isinstance(item, str) and item.strip(): - history_lines.append(item.strip()) + history_lines = _history_payload_lines(history_payload) history_cluster = _history_mentions_cluster( history_lines, inventory=inventory,