Spaces:
Runtime error
Runtime error
Create utils/logging.py
Browse files- agents/utils/logging.py +137 -0
agents/utils/logging.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Logging utilities for pharmaceutical data management agents.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import json
|
| 7 |
+
import time
|
| 8 |
+
from datetime import datetime
|
| 9 |
+
from typing import Dict, Any, Optional
|
| 10 |
+
|
| 11 |
+
def log_agent_activity(agent_type: str, state: Dict[str, Any], log_dir: str = "./logs/agent_activity"):
|
| 12 |
+
"""
|
| 13 |
+
Enhanced agent activity logging with detailed state information.
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
agent_type: The type of agent or component being logged
|
| 17 |
+
state: The current state of the agent workflow
|
| 18 |
+
log_dir: Directory to store logs
|
| 19 |
+
"""
|
| 20 |
+
# Ensure log directory exists
|
| 21 |
+
os.makedirs(log_dir, exist_ok=True)
|
| 22 |
+
|
| 23 |
+
# Create log timestamp
|
| 24 |
+
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
| 25 |
+
|
| 26 |
+
# Extract key state information for logging
|
| 27 |
+
current_agent = state.get("current_agent", "unknown")
|
| 28 |
+
|
| 29 |
+
# Create log entry
|
| 30 |
+
log_entry = {
|
| 31 |
+
"timestamp": timestamp,
|
| 32 |
+
"agent_type": agent_type,
|
| 33 |
+
"current_agent": current_agent,
|
| 34 |
+
"user_intent_available": "user_intent" in state and bool(state.get("user_intent")),
|
| 35 |
+
"pipeline_plan_available": "pipeline_plan" in state and bool(state.get("pipeline_plan")),
|
| 36 |
+
"sql_queries_available": "sql_queries" in state and bool(state.get("sql_queries")),
|
| 37 |
+
"execution_status": state.get("status", "unknown"),
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
# Generate log file name based on date
|
| 41 |
+
log_file = os.path.join(log_dir, f"agent_log_{datetime.now().strftime('%Y%m%d')}.jsonl")
|
| 42 |
+
|
| 43 |
+
# Append to log file
|
| 44 |
+
with open(log_file, "a") as f:
|
| 45 |
+
f.write(json.dumps(log_entry) + "\n")
|
| 46 |
+
|
| 47 |
+
def log_ai_function(response: str, file_name: str, log: bool = True, log_path: str = './logs/', overwrite: bool = True):
|
| 48 |
+
"""
|
| 49 |
+
Logs the response of an AI function to a file.
|
| 50 |
+
|
| 51 |
+
Parameters
|
| 52 |
+
----------
|
| 53 |
+
response : str
|
| 54 |
+
The response of the AI function.
|
| 55 |
+
file_name : str
|
| 56 |
+
The name of the file to save the response to.
|
| 57 |
+
log : bool, optional
|
| 58 |
+
Whether to log the response or not. The default is True.
|
| 59 |
+
log_path : str, optional
|
| 60 |
+
The path to save the log file. The default is './logs/'.
|
| 61 |
+
overwrite : bool, optional
|
| 62 |
+
Whether to overwrite the file if it already exists. The default is True.
|
| 63 |
+
- If True, the file will be overwritten.
|
| 64 |
+
- If False, a unique file name will be created.
|
| 65 |
+
|
| 66 |
+
Returns
|
| 67 |
+
-------
|
| 68 |
+
tuple
|
| 69 |
+
The path and name of the log file.
|
| 70 |
+
"""
|
| 71 |
+
|
| 72 |
+
if log:
|
| 73 |
+
# Ensure the directory exists
|
| 74 |
+
os.makedirs(log_path, exist_ok=True)
|
| 75 |
+
|
| 76 |
+
# file_name = 'data_wrangler.py'
|
| 77 |
+
file_path = os.path.join(log_path, file_name)
|
| 78 |
+
|
| 79 |
+
if not overwrite:
|
| 80 |
+
# If file already exists and we're NOT overwriting, we create a new name
|
| 81 |
+
if os.path.exists(file_path):
|
| 82 |
+
# Use an incremental suffix (e.g., data_wrangler_1.py, data_wrangler_2.py, etc.)
|
| 83 |
+
# or a time-based suffix if you prefer.
|
| 84 |
+
base_name, ext = os.path.splitext(file_name)
|
| 85 |
+
i = 1
|
| 86 |
+
while True:
|
| 87 |
+
new_file_name = f"{base_name}_{i}{ext}"
|
| 88 |
+
new_file_path = os.path.join(log_path, new_file_name)
|
| 89 |
+
if not os.path.exists(new_file_path):
|
| 90 |
+
file_path = new_file_path
|
| 91 |
+
file_name = new_file_name
|
| 92 |
+
break
|
| 93 |
+
i += 1
|
| 94 |
+
|
| 95 |
+
# Write the file
|
| 96 |
+
with open(file_path, 'w', encoding='utf-8') as file:
|
| 97 |
+
file.write(response)
|
| 98 |
+
|
| 99 |
+
print(f" File saved to: {file_path}")
|
| 100 |
+
|
| 101 |
+
return (file_path, file_name)
|
| 102 |
+
|
| 103 |
+
else:
|
| 104 |
+
return (None, None)
|
| 105 |
+
|
| 106 |
+
def get_execution_metrics(state: Dict[str, Any]) -> Dict[str, Any]:
|
| 107 |
+
"""
|
| 108 |
+
Collects execution metrics from the agent workflow state.
|
| 109 |
+
|
| 110 |
+
Args:
|
| 111 |
+
state: The current state of the agent workflow
|
| 112 |
+
|
| 113 |
+
Returns:
|
| 114 |
+
Dictionary containing execution metrics
|
| 115 |
+
"""
|
| 116 |
+
execution_results = state.get("execution_results", {})
|
| 117 |
+
metrics = {
|
| 118 |
+
"success_rate": execution_results.get("success_rate", 0),
|
| 119 |
+
"queries_executed": execution_results.get("queries_executed", 0),
|
| 120 |
+
"time_taken": 0, # Placeholder for actual timing
|
| 121 |
+
"confidence_scores": state.get("confidence_scores", {})
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
# Calculate time taken if we have timestamps
|
| 125 |
+
if "execution_results" in state and "completed_at" in state["execution_results"]:
|
| 126 |
+
# Find the earliest timestamp in the state
|
| 127 |
+
start_time = None
|
| 128 |
+
if "user_intent" in state and "time" in state["user_intent"]:
|
| 129 |
+
start_time = state["user_intent"]["time"]
|
| 130 |
+
elif "pipeline_plan" in state and "created_at" in state["pipeline_plan"]:
|
| 131 |
+
start_time = state["pipeline_plan"]["created_at"]
|
| 132 |
+
|
| 133 |
+
if start_time:
|
| 134 |
+
end_time = state["execution_results"]["completed_at"]
|
| 135 |
+
metrics["time_taken"] = round(end_time - start_time, 2)
|
| 136 |
+
|
| 137 |
+
return metrics
|