a digital entity named phi that roams bsky phi.zzstoatzz.io
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

add service health monitoring tool and reflection integration

check_services tool hits the evergreen proxy to batch-check 13 services.
integrated into daily reflection so phi sees service status and can alert
nate when something's down.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

zzstoatzz 976b85c1 f8d1120b

+85 -1
+1 -1
loq.toml
··· 13 13 14 14 [[rules]] 15 15 path = "src/bot/agent.py" 16 - max_lines = 854 16 + max_lines = 938 17 17 18 18 [[rules]] 19 19 path = "src/bot/memory/namespace_memory.py"
+84
src/bot/agent.py
··· 30 30 31 31 logger = logging.getLogger("bot.agent") 32 32 33 + EVERGREEN_PROXY = "https://evergreen-proxy.nate-8fe.workers.dev" 34 + SERVICE_CHECKS = [ 35 + {"url": "https://api.plyr.fm/health", "name": "plyr api"}, 36 + {"url": "https://plyr.fm", "name": "plyr frontend"}, 37 + {"url": "https://pds.zzstoatzz.io/xrpc/_health", "name": "PDS"}, 38 + {"url": "https://prefect-server.waow.tech/api/health", "name": "prefect"}, 39 + {"url": "https://prefect-metrics.waow.tech/api/health", "name": "grafana"}, 40 + {"url": "https://relay.waow.tech/xrpc/_health", "name": "indigo relay"}, 41 + {"url": "https://zlay.waow.tech/_health", "name": "zlay"}, 42 + {"url": "https://coral.fly.dev/health", "name": "trending"}, 43 + { 44 + "url": "https://leaflet-search-backend.fly.dev/health", 45 + "name": "standard.site backend", 46 + }, 47 + {"url": "https://pub-search.waow.tech", "name": "pub-search"}, 48 + {"url": "https://typeahead.waow.tech/stats", "name": "typeahead"}, 49 + {"url": "https://zig-bsky-feed.fly.dev/health", "name": "music-feed"}, 50 + {"url": "https://pollz-backend.fly.dev/health", "name": "pollz"}, 51 + ] 52 + 53 + 54 + async def _check_services_impl() -> str: 55 + """Hit the evergreen proxy with all service checks. Returns formatted status.""" 56 + async with httpx.AsyncClient(timeout=30) as client: 57 + try: 58 + r = await client.post( 59 + EVERGREEN_PROXY, 60 + json={"checks": SERVICE_CHECKS}, 61 + ) 62 + r.raise_for_status() 63 + results = r.json() 64 + except Exception as e: 65 + return f"evergreen proxy unreachable: {e}" 66 + 67 + failures: list[str] = [] 68 + healthy: list[str] = [] 69 + 70 + checks = results if isinstance(results, list) else results.get("results", []) 71 + # build name lookup from our request 72 + name_by_url = {c["url"]: c["name"] for c in SERVICE_CHECKS} 73 + 74 + for check in checks: 75 + url = check.get("url", "") 76 + name = name_by_url.get(url, url) 77 + status = check.get("status") 78 + ms = check.get("ms", "?") 79 + ok = check.get("ok", False) 80 + 81 + if ok: 82 + healthy.append(f"{name}: ok ({ms}ms)") 83 + else: 84 + error = check.get("error", f"status {status}") 85 + failures.append(f"{name}: DOWN ({error})") 86 + 87 + parts: list[str] = [] 88 + if failures: 89 + parts.append("FAILURES:\n" + "\n".join(failures)) 90 + parts.append(f"{len(healthy)}/{len(healthy) + len(failures)} services healthy") 91 + if not failures: 92 + parts.append("\n".join(healthy)) 93 + 94 + return "\n".join(parts) 95 + 33 96 34 97 def _build_operational_instructions() -> str: 35 98 """Build operational instructions with the current owner handle interpolated.""" ··· 72 135 73 136 your own posts: 74 137 - get_own_posts: read your own recent top-level posts. use this when you need to review what you've posted — do NOT use list_records for your own posts. 138 + 139 + service health: 140 + - check_services: check health of nate's services (plyr, PDS, prefect, relays, etc). 141 + use during daily reflection. if something is down, post about it and tag @{settings.owner_handle}. 75 142 76 143 IMPORTANT: never paginate through list_records repeatedly. if you need more data than one call returns, work with what you have. endless pagination wastes your request budget and produces no response. 77 144 """.strip() ··· 667 734 except Exception as e: 668 735 return f"failed to get own posts: {e}" 669 736 737 + @self.agent.tool 738 + async def check_services(ctx: RunContext[PhiDeps]) -> str: 739 + """Check health of nate's services via the evergreen status proxy. 740 + Returns status, response time, and any failures. Use during daily 741 + reflection or when asked about service health.""" 742 + return await _check_services_impl() 743 + 670 744 logger.info("phi agent initialized with pdsx + pub-search mcp tools") 671 745 672 746 def _mcp_toolsets(self) -> list[MCPServerStreamableHTTP]: ··· 804 878 except Exception as e: 805 879 logger.warning(f"failed to get episodic context for reflection: {e}") 806 880 881 + # Check service health for reflection context 882 + service_status = "" 883 + try: 884 + service_status = await _check_services_impl() 885 + except Exception: 886 + pass 887 + 807 888 # Build the reflection prompt 808 889 prompt_parts = [f"[TODAY]: {date.today().isoformat()}"] 809 890 ··· 825 906 826 907 if episodic_context: 827 908 prompt_parts.append(episodic_context) 909 + 910 + if service_status: 911 + prompt_parts.append(f"[SERVICE HEALTH]:\n{service_status}") 828 912 829 913 prompt_parts.append( 830 914 "[REFLECTION TASK]: you're posting a short top-level reflection on your day. "