fix(agents): recognize active OpenClaw coder sessions dynamically from rollouts
This commit is contained in:
@@ -213,65 +213,88 @@ class RealtimeRPGHandler(http.server.SimpleHTTPRequestHandler):
|
|||||||
status["gitea"]["connected"] = False
|
status["gitea"]["connected"] = False
|
||||||
status["gitea"]["error"] = str(e)
|
status["gitea"]["error"] = str(e)
|
||||||
|
|
||||||
# 3. Check OpenClaw Lead Session Activity STRICTLY for target_project
|
# 3. Check OpenClaw Active Session Activity for target_project (Lead, Coder, Reviewer)
|
||||||
lead_heartbeat_active = False
|
lead_heartbeat_active = False
|
||||||
lead_task_desc = ""
|
lead_task_desc = ""
|
||||||
lead_last_pulse_seconds = 999
|
lead_last_pulse_seconds = 999
|
||||||
lead_recent_logs = []
|
lead_recent_logs = []
|
||||||
|
|
||||||
|
coder_session_active = False
|
||||||
|
coder_task_desc = ""
|
||||||
|
coder_recent_logs = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rollout_files = sorted(
|
search_patterns = [
|
||||||
glob.glob(f'/home/christoph/openclaw/data/openclaw/agents/{target_project}-lead/agent/codex-home/sessions/**/rollout-*.jsonl', recursive=True),
|
f'/home/christoph/openclaw/data/openclaw/agents/{target_project}-coder/agent/codex-home/sessions/**/rollout-*.jsonl',
|
||||||
key=os.path.getmtime,
|
f'/home/christoph/openclaw/data/openclaw/agents/{target_project}-lead/agent/codex-home/sessions/**/rollout-*.jsonl',
|
||||||
reverse=True
|
f'/home/christoph/openclaw/data/openclaw/agents/projekt-lead/agent/codex-home/sessions/**/rollout-*.jsonl'
|
||||||
)
|
]
|
||||||
if rollout_files:
|
all_rollout_files = []
|
||||||
newest_rollout = rollout_files[0]
|
for p in search_patterns:
|
||||||
lead_last_pulse_seconds = round(time.time() - os.path.getmtime(newest_rollout), 1)
|
all_rollout_files.extend(glob.glob(p, recursive=True))
|
||||||
|
|
||||||
with open(newest_rollout, 'r') as fp:
|
rollout_files = sorted(all_rollout_files, key=os.path.getmtime, reverse=True)
|
||||||
|
|
||||||
|
for rf in rollout_files[:10]:
|
||||||
|
age_seconds = round(time.time() - os.path.getmtime(rf), 1)
|
||||||
|
with open(rf, 'r') as fp:
|
||||||
lines = fp.readlines()
|
lines = fp.readlines()
|
||||||
if lines:
|
if not lines:
|
||||||
last_line_data = json.loads(lines[-1])
|
continue
|
||||||
last_payload_type = last_line_data.get('payload', {}).get('type')
|
last_line_data = json.loads(lines[-1])
|
||||||
is_completed = (last_payload_type in ['task_complete', 'turn_complete', 'stop'])
|
last_payload_type = last_line_data.get('payload', {}).get('type')
|
||||||
|
is_completed = (last_payload_type in ['task_complete', 'turn_complete', 'stop'])
|
||||||
# Extract recent live logs
|
|
||||||
for l in lines[-8:]:
|
# Extract logs
|
||||||
try:
|
recent_logs = []
|
||||||
item = json.loads(l)
|
session_prompt = ""
|
||||||
p_type = item.get('type')
|
session_role = "lead"
|
||||||
p_payload = item.get('payload', {})
|
|
||||||
if p_payload.get('type') == 'message' and p_payload.get('role') == 'assistant':
|
|
||||||
t = p_payload.get('content', [{}])[0].get('text', '')
|
|
||||||
if t: lead_recent_logs.append(f"🤖 {t[:90]}...")
|
|
||||||
elif p_payload.get('type') == 'item_completed':
|
|
||||||
i_name = p_payload.get('item', {}).get('type')
|
|
||||||
if i_name: lead_recent_logs.append(f"⚙️ Step: {i_name}")
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if not is_completed and lead_last_pulse_seconds < 45:
|
for l in lines[-8:]:
|
||||||
|
try:
|
||||||
|
item = json.loads(l)
|
||||||
|
p_payload = item.get('payload', {})
|
||||||
|
if p_payload.get('type') == 'message' and p_payload.get('role') == 'assistant':
|
||||||
|
t = p_payload.get('content', [{}])[0].get('text', '')
|
||||||
|
if t: recent_logs.append(f"🤖 {t[:90]}...")
|
||||||
|
elif p_payload.get('type') == 'item_completed':
|
||||||
|
i_name = p_payload.get('item', {}).get('type')
|
||||||
|
if i_name: recent_logs.append(f"⚙️ Step: {i_name}")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
for l in lines:
|
||||||
|
try:
|
||||||
|
p = json.loads(l)
|
||||||
|
if p.get('payload', {}).get('type') == 'message' and p.get('payload', {}).get('role') == 'user':
|
||||||
|
txt = p.get('payload', {}).get('content', [{}])[0].get('text', '')
|
||||||
|
if not txt.startswith("<recommended_plugins>"):
|
||||||
|
session_prompt = txt
|
||||||
|
if "coder für issue" in txt.lower() or "du bist der coder" in txt.lower() or "openclaw-coder" in txt.lower():
|
||||||
|
session_role = "coder"
|
||||||
|
elif "review" in txt.lower() and ("du bist der" in txt.lower() or "qa" in txt.lower()):
|
||||||
|
session_role = "reviewer"
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Map to specific agent
|
||||||
|
if session_role == "coder" and not coder_session_active:
|
||||||
|
if not is_completed and age_seconds < 60:
|
||||||
|
coder_session_active = True
|
||||||
|
coder_task_desc = session_prompt[:120]
|
||||||
|
coder_recent_logs = recent_logs
|
||||||
|
elif session_role == "lead" and not lead_heartbeat_active:
|
||||||
|
lead_last_pulse_seconds = age_seconds
|
||||||
|
if not is_completed and age_seconds < 60:
|
||||||
lead_heartbeat_active = True
|
lead_heartbeat_active = True
|
||||||
for l in reversed(lines[-10:]):
|
lead_task_desc = session_prompt[:120]
|
||||||
p = json.loads(l)
|
lead_recent_logs = recent_logs
|
||||||
if p.get('payload', {}).get('type') == 'message' and p.get('payload', {}).get('role') == 'user':
|
|
||||||
lead_task_desc = p.get('payload', {}).get('content', [{}])[0].get('text', '')[:120]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
lead_heartbeat_active = False
|
|
||||||
|
|
||||||
status["lead_heartbeat"] = {
|
status["lead_heartbeat"] = {
|
||||||
"last_pulse_seconds_ago": lead_last_pulse_seconds,
|
"last_pulse_seconds_ago": lead_last_pulse_seconds,
|
||||||
"project": target_project,
|
"project": target_project,
|
||||||
"is_beating": lead_heartbeat_active
|
"is_beating": lead_heartbeat_active
|
||||||
}
|
}
|
||||||
else:
|
|
||||||
status["lead_heartbeat"] = {
|
|
||||||
"last_pulse_seconds_ago": 999,
|
|
||||||
"project": target_project,
|
|
||||||
"is_beating": False
|
|
||||||
}
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
status["lead_heartbeat"] = {"error": str(e), "is_beating": False, "last_pulse_seconds_ago": 999}
|
status["lead_heartbeat"] = {"error": str(e), "is_beating": False, "last_pulse_seconds_ago": 999}
|
||||||
|
|
||||||
@@ -283,6 +306,11 @@ class RealtimeRPGHandler(http.server.SimpleHTTPRequestHandler):
|
|||||||
status["agents"]["coder1"]["currentTask"] = f"Task #{task.get('issueNumber', '')}: {task.get('title', 'Coding')}"
|
status["agents"]["coder1"]["currentTask"] = f"Task #{task.get('issueNumber', '')}: {task.get('title', 'Coding')}"
|
||||||
status["agents"]["coder1"]["lastAction"] = "BullMQ: Active Code Session"
|
status["agents"]["coder1"]["lastAction"] = "BullMQ: Active Code Session"
|
||||||
status["agents"]["coder1"]["liveLog"] = ["git checkout feature-branch", "npm run test", "git commit -m 'feat: implementation'"]
|
status["agents"]["coder1"]["liveLog"] = ["git checkout feature-branch", "npm run test", "git commit -m 'feat: implementation'"]
|
||||||
|
elif coder_session_active:
|
||||||
|
status["agents"]["coder1"]["state"] = "WORKING"
|
||||||
|
status["agents"]["coder1"]["currentTask"] = f"Aktiv: {coder_task_desc or 'Coding Session'}"
|
||||||
|
status["agents"]["coder1"]["lastAction"] = "OpenClaw Coder Turn Active"
|
||||||
|
status["agents"]["coder1"]["liveLog"] = coder_recent_logs or ["Implementing feature / bugfix..."]
|
||||||
else:
|
else:
|
||||||
status["agents"]["coder1"]["state"] = "IDLE"
|
status["agents"]["coder1"]["state"] = "IDLE"
|
||||||
status["agents"]["coder1"]["currentTask"] = f"Keine offenen Tasks in {target_project}"
|
status["agents"]["coder1"]["currentTask"] = f"Keine offenen Tasks in {target_project}"
|
||||||
|
|||||||
Reference in New Issue
Block a user