atlasbot: answer jetson nodes from knowledge

This commit is contained in:
Brad Stein 2026-01-26 12:06:48 -03:00
parent 2c3ffdbf95
commit 28570a1f5c
8 changed files with 66 additions and 6 deletions

View File

@ -1057,7 +1057,7 @@
"node-role.kubernetes.io/worker": "true"
},
"images": [
"registry.bstein.dev/bstein/ariadne:0.1.0-48"
"registry.bstein.dev/bstein/ariadne:0.1.0-49"
]
},
{

View File

@ -711,7 +711,7 @@ workloads:
kubernetes.io/arch: arm64
node-role.kubernetes.io/worker: 'true'
images:
- registry.bstein.dev/bstein/ariadne:0.1.0-48
- registry.bstein.dev/bstein/ariadne:0.1.0-49
- kind: Deployment
namespace: maintenance
name: maintenance-vault-sync

File diff suppressed because one or more lines are too long

View File

@ -529,9 +529,14 @@ def main() -> int:
diagram_path.write_text(diagram, encoding="utf-8")
# Render runbooks into JSON for lightweight, dependency-free consumption in-cluster.
runbooks_dir = out_dir / "runbooks"
runbook_dirs = [
out_dir / "runbooks",
out_dir / "software",
]
runbooks: list[dict[str, Any]] = []
if runbooks_dir.exists():
for runbooks_dir in runbook_dirs:
if not runbooks_dir.exists():
continue
for md_file in sorted(runbooks_dir.glob("*.md")):
raw = md_file.read_text(encoding="utf-8")
fm: dict[str, Any] = {}

View File

@ -1057,7 +1057,7 @@
"node-role.kubernetes.io/worker": "true"
},
"images": [
"registry.bstein.dev/bstein/ariadne:0.1.0-48"
"registry.bstein.dev/bstein/ariadne:0.1.0-49"
]
},
{

View File

@ -711,7 +711,7 @@ workloads:
kubernetes.io/arch: arm64
node-role.kubernetes.io/worker: 'true'
images:
- registry.bstein.dev/bstein/ariadne:0.1.0-48
- registry.bstein.dev/bstein/ariadne:0.1.0-49
- kind: Deployment
namespace: maintenance
name: maintenance-vault-sync

File diff suppressed because one or more lines are too long

View File

@ -75,6 +75,8 @@ METRIC_HINT_WORDS = {
}
CODE_FENCE_RE = re.compile(r"^```(?:json)?\\s*(.*?)\\s*```$", re.DOTALL)
TITAN_NODE_RE = re.compile(r"\\btitan-[0-9a-z]{2}\\b", re.IGNORECASE)
TITAN_RANGE_RE = re.compile(r"\\btitan-([0-9a-z]{2})/([0-9a-z]{2})\\b", re.IGNORECASE)
def _tokens(text: str) -> list[str]:
toks = [t.lower() for t in TOKEN_RE.findall(text or "")]
@ -233,6 +235,35 @@ def kb_retrieve(query: str, *, limit: int = 3) -> str:
used += len(chunk)
return "\n".join(parts).strip()
def _extract_titan_nodes(text: str) -> list[str]:
names = {n.lower() for n in TITAN_NODE_RE.findall(text or "") if n}
for match in TITAN_RANGE_RE.finditer(text or ""):
left, right = match.groups()
if left:
names.add(f"titan-{left.lower()}")
if right:
names.add(f"titan-{right.lower()}")
return sorted(names)
def jetson_nodes_from_kb() -> list[str]:
for doc in KB.get("runbooks", []):
if not isinstance(doc, dict):
continue
body = str(doc.get("body") or "")
for line in body.splitlines():
if "jetson" not in line.lower():
continue
names = _extract_titan_nodes(line)
if names:
return names
return []
def jetson_nodes_summary(cluster_name: str) -> str:
names = jetson_nodes_from_kb()
if names:
return f"{cluster_name} has {len(names)} Jetson nodes: {', '.join(names)}."
return ""
def catalog_hints(query: str) -> tuple[str, list[tuple[str, str]]]:
q = (query or "").strip()
if not q or not KB.get("catalog"):
@ -729,6 +760,14 @@ def sync_loop(token: str, room_id: str):
continue
send_msg(token, rid, summary)
continue
if "jetson" in lower_body:
if any(word in lower_body for word in ("cluster", "atlas", "titan", "node", "nodes")):
summary = jetson_nodes_summary("Atlas")
if summary:
send_msg(token, rid, summary)
else:
send_msg(token, rid, "Jetson inventory is not available in the knowledge base yet.")
continue
if re.search(r"\bnode names?\b|\bnodes? named\b|\bnaming\b", lower_body):
if any(word in lower_body for word in ("cluster", "atlas", "titan")):
names_summary = nodes_names_summary("Atlas")