Skip to main content

hematite/agent/
diagnose.rs

1/// Staged triage engine for /diagnose.
2///
3/// Phase 1 (harness): runs health_report deterministically and identifies
4/// which follow-up topics are warranted based on the findings.
5/// Phase 2 (agent): receives a pre-built instruction naming the exact topics
6/// to investigate, so the model synthesizes rather than orchestrates.
7
8/// Parse health_report text and return the follow-up inspect_host topics
9/// that the harness determined are worth drilling into. Skips dev-environment
10/// "not installed" warnings (those aren't system health issues).
11pub fn triage_follow_up_topics(health_output: &str) -> Vec<&'static str> {
12    let lower = health_output.to_ascii_lowercase();
13    let mut topics: Vec<&'static str> = Vec::new();
14
15    let action_required = lower.contains("action required");
16    let worth_a_look = lower.contains("worth a look");
17    if !action_required && !worth_a_look {
18        return topics; // ALL GOOD — no follow-up needed
19    }
20
21    // Disk / storage — flag when disk appears in needs_fix or watch tier
22    if lower.contains("[!]") && (lower.contains("disk") || lower.contains("drive")) {
23        topics.push("storage");
24        topics.push("disk_health");
25    } else if lower.contains("[-]") && (lower.contains("disk") || lower.contains("drive")) {
26        topics.push("storage");
27    }
28
29    // RAM / memory pressure
30    if (lower.contains("[!]") || lower.contains("[-]")) && lower.contains("ram") {
31        topics.push("resource_load");
32        topics.push("processes");
33    }
34
35    // Windows event log errors — always worth drilling into
36    if lower.contains("critical") || lower.contains("error event") {
37        if lower.contains("event") {
38            topics.push("log_check");
39        }
40    }
41
42    // Critical services stopped
43    if lower.contains("[!]") && lower.contains("service") {
44        topics.push("services");
45    } else if lower.contains("[-]") && lower.contains("service") {
46        topics.push("services");
47    }
48
49    // Security / Defender issues
50    if (lower.contains("[!]") || lower.contains("[-]"))
51        && (lower.contains("defender") || lower.contains("firewall") || lower.contains("security"))
52    {
53        topics.push("security");
54    }
55
56    // Network unreachable or high latency
57    if lower.contains("[!]") && lower.contains("internet connectivity") {
58        topics.push("connectivity");
59        topics.push("network");
60    } else if lower.contains("[-]") && lower.contains("internet connectivity") {
61        topics.push("connectivity");
62    }
63
64    // Pending reboot
65    if lower.contains("pending reboot") {
66        topics.push("pending_reboot");
67    }
68
69    // Thermal elevated or very high
70    if (lower.contains("[!]") || lower.contains("[-]"))
71        && (lower.contains("thermal") || lower.contains("°c"))
72    {
73        topics.push("thermal");
74        topics.push("overclocker");
75    }
76
77    // Deduplicate while preserving order
78    let mut seen = std::collections::HashSet::new();
79    topics.retain(|t| seen.insert(*t));
80
81    topics
82}
83
84/// Build the agent instruction for phase 2 of /diagnose.
85/// The harness has already run health_report; this tells the agent exactly
86/// which topics to investigate and how to synthesize the results.
87pub fn build_diagnose_instruction(health_output: &str, follow_up_topics: &[&str]) -> String {
88    if follow_up_topics.is_empty() {
89        return format!(
90            "DIAGNOSE MODE — triage complete.\n\n\
91             Health report:\n{}\n\n\
92             The machine is in good health. Summarize the key findings for the user \
93             in 2-3 sentences and confirm no action is needed.",
94            health_output
95        );
96    }
97
98    let topic_list = follow_up_topics
99        .iter()
100        .enumerate()
101        .map(|(i, t)| format!("{}. inspect_host(topic=\"{}\")", i + 1, t))
102        .collect::<Vec<_>>()
103        .join("\n");
104
105    format!(
106        "DIAGNOSE MODE — harness triage identified {} area(s) to investigate.\n\n\
107         Health report (already run by harness):\n{}\n\n\
108         PROTOCOL — follow this exactly:\n\
109         Call each topic below in order:\n{}\n\n\
110         After all calls complete:\n\
111         - Write a numbered fix plan grounded in the tool output\n\
112         - Lead with the most critical issue first\n\
113         - Every step must reference specific data from the results (exact path, count, service name, etc.)\n\
114         - No generic advice — only steps that address what the tools actually found\n\
115         - If a finding needs a restart or elevated privileges, say so explicitly",
116        follow_up_topics.len(),
117        health_output,
118        topic_list
119    )
120}