diff --git a/index.html b/index.html index 5226c95..f438230 100644 --- a/index.html +++ b/index.html @@ -722,6 +722,7 @@ agents[key].state = agentData.state; agents[key].currentTask = agentData.currentTask; agents[key].lastAction = agentData.lastAction; + agents[key].parallelCount = agentData.parallelCount || 0; if (agentData.liveLog && agentData.liveLog.length > 0) { agents[key].liveLog = agentData.liveLog; } @@ -1416,15 +1417,23 @@ ctx.fillText("💾 DELEGATE", x - 6, y + 3 + bounce); } else if (agent.state === 'WORKING') { + const count = agent.parallelCount || 1; + const bubbleW = (count > 1) ? 54 : 40; ctx.fillStyle = "#064e3b"; - ctx.fillRect(x - 10, y - 10, 40, 20); - ctx.strokeStyle = "#34d399"; + ctx.fillRect(x - 10, y - 10, bubbleW, 20); + ctx.strokeStyle = (count > 1) ? "#facc15" : "#34d399"; ctx.lineWidth = 1.5; - ctx.strokeRect(x - 10, y - 10, 40, 20); + ctx.strokeRect(x - 10, y - 10, bubbleW, 20); ctx.font = "10px 'Press Start 2P'"; ctx.fillStyle = "#34d399"; ctx.fillText("", x - 4, y + 4); + if (count > 1) { + ctx.font = "10px 'Press Start 2P'"; + ctx.fillStyle = "#facc15"; + ctx.fillText(`x${count}`, x + 24, y + 4); + } + } else if (agent.state === 'THINKING') { const bob = Math.sin(time * 0.01) * 2; ctx.fillStyle = "#713f12"; diff --git a/server.py b/server.py index 46ec1d1..768e59f 100644 --- a/server.py +++ b/server.py @@ -232,9 +232,8 @@ class RealtimeRPGHandler(http.server.SimpleHTTPRequestHandler): lead_last_pulse_seconds = 999 lead_recent_logs = [] - coder_session_active = False - coder_task_desc = "" - coder_recent_logs = [] + coder_sessions = [] + active_coder_count = 0 try: search_patterns = [ @@ -248,7 +247,7 @@ class RealtimeRPGHandler(http.server.SimpleHTTPRequestHandler): rollout_files = sorted(all_rollout_files, key=os.path.getmtime, reverse=True) - for rf in rollout_files[:10]: + for rf in rollout_files[:15]: age_seconds = round(time.time() - os.path.getmtime(rf), 1) with open(rf, 'r') as fp: lines = fp.readlines() @@ -300,11 +299,14 @@ class RealtimeRPGHandler(http.server.SimpleHTTPRequestHandler): session_prompt = first_prompt or "Heartbeat / Backlog Monitoring" # Map to specific agent - if session_role == "coder" and not coder_session_active: + if session_role == "coder": if not is_completed and age_seconds < 60: - coder_session_active = True - coder_task_desc = session_prompt[:120] - coder_recent_logs = recent_logs + active_coder_count += 1 + coder_sessions.append({ + "task": session_prompt[:120], + "logs": recent_logs, + "age": age_seconds + }) elif session_role == "lead" and not lead_heartbeat_active: lead_last_pulse_seconds = age_seconds if not is_completed and age_seconds < 60: @@ -321,23 +323,27 @@ class RealtimeRPGHandler(http.server.SimpleHTTPRequestHandler): status["lead_heartbeat"] = {"error": str(e), "is_beating": False, "last_pulse_seconds_ago": 999} # 4. Derive Agent RPG States STRICTLY for target_project - # Coder 1 + # Coder 1 (supports multi-instance count x2, x3) if "coder-tasks" in latest_active_tasks: task = latest_active_tasks["coder-tasks"] status["agents"]["coder1"]["state"] = "WORKING" status["agents"]["coder1"]["currentTask"] = f"Task #{task.get('issueNumber', '')}: {task.get('title', 'Coding')}" status["agents"]["coder1"]["lastAction"] = "BullMQ: Active Code Session" status["agents"]["coder1"]["liveLog"] = ["git checkout feature-branch", "npm run test", "git commit -m 'feat: implementation'"] - elif coder_session_active: + status["agents"]["coder1"]["parallelCount"] = max(1, active_coder_count) + elif active_coder_count > 0: 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..."] + primary_coder = coder_sessions[0] + status["agents"]["coder1"]["currentTask"] = f"Aktiv ({active_coder_count}x): {primary_coder['task'] or 'Coding Session'}" + status["agents"]["coder1"]["lastAction"] = f"OpenClaw Coder Turn ({active_coder_count} parallel)" + status["agents"]["coder1"]["liveLog"] = primary_coder["logs"] or ["Implementing feature / bugfix..."] + status["agents"]["coder1"]["parallelCount"] = active_coder_count else: status["agents"]["coder1"]["state"] = "IDLE" status["agents"]["coder1"]["currentTask"] = f"Keine offenen Tasks in {target_project}" status["agents"]["coder1"]["lastAction"] = "Idle / Bereit" status["agents"]["coder1"]["liveLog"] = ["Wartet auf neue Queue-Aufgaben..."] + status["agents"]["coder1"]["parallelCount"] = 0 # Coder 2 (Tester / Staging) if "tester-tasks" in latest_active_tasks or "deployments" in latest_active_tasks: