Skip to content

Instantly share code, notes, and snippets.

@chadbrewbaker
Created May 25, 2026 18:23
Show Gist options
  • Select an option

  • Save chadbrewbaker/8277662fc3701e4b076731318caa5133 to your computer and use it in GitHub Desktop.

Select an option

Save chadbrewbaker/8277662fc3701e4b076731318caa5133 to your computer and use it in GitHub Desktop.
Simple Hermes Agent profiler to diagnose API call hangs
uv run profile.py ~/.hermes/logs/agent.log
# /// script
# dependencies =[
# "pandas",
# "matplotlib",
# ]
# ///
import re
import pandas as pd
import matplotlib.pyplot as plt
import sys
import json
import glob
import os
from datetime import datetime
# Path where your sessions are stored
SESSION_DIR = os.path.expanduser("~/.hermes/sessions/")
def get_session_context(log_ts):
"""Finds the session file covering the log_ts and grabs the last message."""
for session_file in glob.glob(os.path.join(SESSION_DIR, "*.json")):
try:
with open(session_file, 'r') as f:
data = json.load(f)
start = datetime.fromisoformat(data.get('session_start', '1970-01-01T00:00:00'))
end = datetime.fromisoformat(data.get('last_updated', '1970-01-01T00:00:00'))
# Check if our log timestamp falls in this session
if start <= log_ts <= end:
# Replace 'messages' with 'history' if your JSON uses that key
messages = data.get('messages', [])
last_msg = messages[-1].get('content', 'No content') if messages else "Empty session"
return f"Model: {data.get('model', 'Unknown')}\nLast Context: {last_msg[:200]}..."
except Exception:
continue
return "No matching session found."
def parse_logs(log_file):
data =[]
# Regex to capture timestamp and duration from your log format
pattern = re.compile(r"(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}),\d+ INFO .*?(?:latency=|completed \()([\d\.]+)")
with open(log_file, 'r') as f:
for line in f:
match = pattern.search(line)
if match:
ts = pd.to_datetime(match.group(1))
duration = float(match.group(2))
task_type = "API" if "latency=" in line else "Tool"
data.append({'timestamp': ts, 'type': task_type, 'duration': duration})
return pd.DataFrame(data)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: uv run profile.py <path_to_agent.log>")
sys.exit(1)
df = parse_logs(sys.argv[1])
fig, ax = plt.subplots(figsize=(12, 6))
sc = ax.scatter(df['timestamp'], df['duration'],
c=df['type'].map({'API': 'red', 'Tool': 'blue'}),
picker=True, alpha=0.7)
ax.set_title("Click a dot to see LLM context")
ax.set_ylabel("Duration (s)")
ax.grid(True)
def on_pick(event):
ind = event.ind[0]
row = df.iloc[ind]
context = get_session_context(row['timestamp'])
print(f"\n{'='*40}\nSTALL DETAILS\n{'='*40}")
print(f"Time: {row['timestamp']}\nType: {row['type']} ({row['duration']}s)")
print(f"Context Snippet:\n{context}")
fig.canvas.mpl_connect('pick_event', on_pick)
plt.show()
@chadbrewbaker

Copy link
Copy Markdown
Author
Screenshot 2026-05-25 at 1 23 34 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment