From 0169483738f61f29ae0fe784c1c665751e61cc3c Mon Sep 17 00:00:00 2001 From: Spencer Date: Wed, 20 Aug 2025 12:06:11 -0500 Subject: [PATCH] Converted Responses to JSON, improved severity detection, and built a known issues feed --- PROGRESS.md | 4 +-- README.md | 26 ++++++++++++++ __pycache__/config.cpython-313.pyc | Bin 721 -> 721 bytes known_issues.json | 6 ++++ log_position.txt | 2 +- monitor_agent.py | 54 ++++++++++++++++++++++------- 6 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 known_issues.json diff --git a/PROGRESS.md b/PROGRESS.md index 5753287..f2eedc9 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -44,8 +44,8 @@ ## Keeping track of Current Objectives -[ ] Improve "high" priority detection by explicitly instructing LLM to output severity in structured JSON format. -[ ] Implement dynamic contextual information (Known/Resolved Issues Feed) for LLM to improve severity detection. +[x] Improve "high" priority detection by explicitly instructing LLM to output severity in structured JSON format. +[x] Implement dynamic contextual information (Known/Resolved Issues Feed) for LLM to improve severity detection. ## Network Scanning (Nmap Integration) diff --git a/README.md b/README.md index 4cf56dc..1936632 100644 --- a/README.md +++ b/README.md @@ -65,4 +65,30 @@ The script will start a continuous monitoring loop. Every 5 minutes, it will: The script will print its status and any detected anomalies to the console. +## 4. Features + +### Priority System + +The monitoring agent uses a priority system to classify anomalies. The LLM is instructed to return a severity level for each anomaly it detects. The possible severity levels are: + +- **high**: Indicates a critical issue that requires immediate attention. An alert is sent to Discord and Google Home. +- **medium**: Indicates a non-critical issue that should be investigated. No alert is sent. +- **low**: Indicates a minor issue or a potential false positive. No alert is sent. +- **none**: Indicates that no anomaly was detected. + +### Known Issues Feed + +The agent uses a `known_issues.json` file to provide the LLM with a list of known issues and their resolutions. This helps the LLM to avoid flagging resolved or expected issues as anomalies. + +You can add new issues to the `known_issues.json` file by following the existing format. Each issue should have an "issue" and a "resolution" key. For example: + +```json +[ + { + "issue": "CPU temperature spikes to 80C under heavy load", + "resolution": "This is normal behavior for this CPU model and is not a cause for concern." + } +] +``` + **Note on Mock Data:** The current version of the script uses mock data for system logs and network metrics. To use this in a real-world scenario, you would need to replace the mock data with actual data from your systems. diff --git a/__pycache__/config.cpython-313.pyc b/__pycache__/config.cpython-313.pyc index aaad336383c4ff7a69d55dd00d030e10b2ed67b0..968d95585fbbc957fc170f1cfa5b385a03dbe7a3 100644 GIT binary patch delta 38 rcmcb}dXbg)GcPX}0}vSfU7GP^BkvYQ#*od27}*&)1RFVvIDrxX<>v}j delta 38 rcmcb}dXbg)GcPX}0}w2_vn1o`M&2!qjBc9`F|spq2sLsRaRMa(?DGnj diff --git a/known_issues.json b/known_issues.json new file mode 100644 index 0000000..3c0e9a6 --- /dev/null +++ b/known_issues.json @@ -0,0 +1,6 @@ +[ + { + "issue": "CPU temperature spikes to 80C under heavy load", + "resolution": "This is normal behavior for this CPU model and is not a cause for concern." + } +] \ No newline at end of file diff --git a/log_position.txt b/log_position.txt index e3f7a05..b6aa92c 100644 --- a/log_position.txt +++ b/log_position.txt @@ -1 +1 @@ -12165512 \ No newline at end of file +22386620 \ No newline at end of file diff --git a/monitor_agent.py b/monitor_agent.py index 5f56c43..e728dbf 100644 --- a/monitor_agent.py +++ b/monitor_agent.py @@ -127,10 +127,13 @@ def analyze_data_with_llm(data, baselines): with open("CONSTRAINTS.md", "r") as f: constraints = f.read() + with open("known_issues.json", "r") as f: + known_issues = json.load(f) + prompt = f""" **Role:** You are a dedicated and expert system administrator. Your primary role is to identify anomalies and provide concise, actionable reports. - **Instruction:** Analyze the following system and network data for any activity that appears out of place or different. Consider unusual values, errors, or unexpected patterns as anomalies. Compare the current data with the historical baseline data to identify significant deviations. + **Instruction:** Analyze the following system and network data for any activity that appears out of place or different. Consider unusual values, errors, or unexpected patterns as anomalies. Compare the current data with the historical baseline data to identify significant deviations. Consult the known issues feed to avoid flagging resolved or expected issues. **Context:** Here is the system data in JSON format for your analysis: {json.dumps(data, indent=2)} @@ -138,16 +141,41 @@ def analyze_data_with_llm(data, baselines): **Historical Baseline Data:** {json.dumps(baselines, indent=2)} + **Known Issues Feed:** + {json.dumps(known_issues, indent=2)} + **Constraints and Guidelines:** {constraints} - **Output Request:** If you find an anomaly, provide a report as a single, coherent, natural language paragraph. The report must clearly state the anomaly, its potential cause, and its severity (e.g., high, medium, low). If no anomaly is found, respond with "OK". + **Output Request:** If you find an anomaly, provide a report as a single JSON object with two keys: "severity" and "reason". The "severity" must be one of "high", "medium", "low", or "none". The "reason" must be a natural language explanation of the anomaly. If no anomaly is found, return a single JSON object with "severity" set to "none" and "reason" as an empty string. Do not wrap the JSON in markdown or any other formatting. **Reasoning Hint:** Think step by step to come to your conclusion. This is very important. """ try: response = ollama.generate(model="llama3.1:8b", prompt=prompt) - return response['response'].strip() + # Sanitize the response to ensure it's valid JSON + sanitized_response = response['response'].strip() + # Find the first '{' and the last '}' to extract the JSON object + start_index = sanitized_response.find('{') + end_index = sanitized_response.rfind('}') + if start_index != -1 and end_index != -1: + json_string = sanitized_response[start_index:end_index+1] + try: + return json.loads(json_string) + except json.JSONDecodeError: + # If parsing a single object fails, try parsing as a list + try: + json_list = json.loads(json_string) + if isinstance(json_list, list) and json_list: + return json_list[0] # Return the first object in the list + except json.JSONDecodeError as e: + print(f"Error decoding LLM response: {e}") + # Fallback for invalid JSON + return {"severity": "low", "reason": response['response'].strip()} + else: + # Handle cases where the response is not valid JSON + print(f"LLM returned a non-JSON response: {sanitized_response}") + return {"severity": "low", "reason": sanitized_response} except Exception as e: print(f"Error interacting with LLM: {e}") return None @@ -222,11 +250,11 @@ if __name__ == "__main__": llm_response = analyze_data_with_llm(combined_data, data_storage.calculate_baselines()) - if llm_response and llm_response != "OK": - print(f"Anomaly detected: {llm_response}") - if "high" in llm_response.lower(): - send_discord_alert(llm_response) - send_google_home_alert(llm_response) + if llm_response and llm_response.get('severity') != "none": + print(f"Anomaly detected: {llm_response.get('reason')}") + if llm_response.get('severity') == "high": + send_discord_alert(llm_response.get('reason')) + send_google_home_alert(llm_response.get('reason')) else: print("No anomaly detected.") else: @@ -252,11 +280,11 @@ if __name__ == "__main__": llm_response = analyze_data_with_llm(combined_data, data_storage.calculate_baselines()) - if llm_response and llm_response != "OK": - daily_events.append(llm_response) - if "high" in llm_response.lower(): - send_discord_alert(llm_response) - send_google_home_alert(llm_response) + if llm_response and llm_response.get('severity') != "none": + daily_events.append(llm_response.get('reason')) + if llm_response.get('severity') == "high": + send_discord_alert(llm_response.get('reason')) + send_google_home_alert(llm_response.get('reason')) # Daily Recap Logic current_time = time.strftime("%H:%M")