diff --git a/bin/job-dispatch.py b/bin/job-dispatch.py index 1437d99..b6d3e45 100755 --- a/bin/job-dispatch.py +++ b/bin/job-dispatch.py @@ -119,6 +119,28 @@ def create_sidechat(sender_agent, dry_run=False): print(f"Sidechat creation failed: {e}", file=sys.stderr) return False +def find_sidechat(sender_agent, name, dry_run=False): + """Find existing sidechat by name and navigate to it. Returns True if found.""" + if dry_run: + return False + # List sidechats and check if name exists + cmd = [NETVM_EXEC, sender_agent, "--", "python3", str(CHAT_API), + "--account", sender_agent, "sidechat", "list"] + try: + result = subprocess.run(cmd, capture_output=True, text=True, timeout=30) + if name.lower() not in result.stdout.lower(): + return False + # Navigate to it + nav = [NETVM_EXEC, sender_agent, "--", "python3", str(CHAT_API), + "--account", sender_agent, "sidechat", "use", name] + nav_r = subprocess.run(nav, capture_output=True, text=True, timeout=30) + if nav_r.returncode == 0: + print(f"Reusing sidechat: {name}", file=sys.stderr) + return True + return False + except Exception: + return False + def send_to_current_chat(sender_agent, message, dry_run=False): """Send message to current chat via muse-chat-api.py (no navigation). Used after sidechat create - browser is already on the new chat.""" @@ -183,23 +205,23 @@ def main(): sidechat_created = False if use_sidechat: - # Create sidechat in sender's (opm's) context. - # Browser will be on the new sidechat; we send directly to it. - # No thread ID lookup needed - send_to_current_chat uses current page. - print(f"Creating sidechat for job {job_id}...", file=sys.stderr) - sidechat_created = create_sidechat("opm", dry_run=dry_run) - if sidechat_created: - name_tmpl = sidechat_cfg.get("name_template", "job-{job_name}-{date}") - sc_name = render_prompt(name_tmpl, variables) - log_event("job_sidechat_created", { - "job_id": job_id, - "sidechat_name": sc_name, - }) - print(f"Sidechat created: {sc_name}", file=sys.stderr) - target = "sidechat" # marker, not used for dm.py + name_tmpl = sidechat_cfg.get("name_template", "job-{job_name}-{date}") + sc_name = render_prompt(name_tmpl, variables) + # Try reuse first (for recurring jobs), then create + if find_sidechat("opm", sc_name, dry_run=dry_run): + log_event("job_sidechat_reused", {"job_id": job_id, "sidechat_name": sc_name}) + sidechat_created = True + target = "sidechat" else: - print(f"Warning: Failed to create sidechat, falling back to main", file=sys.stderr) - target = "main" + print(f"Creating sidechat for job {job_id}...", file=sys.stderr) + sidechat_created = create_sidechat("opm", dry_run=dry_run) + if sidechat_created: + log_event("job_sidechat_created", {"job_id": job_id, "sidechat_name": sc_name}) + print(f"Sidechat created: {sc_name}", file=sys.stderr) + target = "sidechat" + else: + print(f"Warning: Failed to create sidechat, falling back to main", file=sys.stderr) + target = "main" else: target = "main" diff --git a/jobs/heartbeat.json b/jobs/heartbeat.json index a722a31..40f3e39 100644 --- a/jobs/heartbeat.json +++ b/jobs/heartbeat.json @@ -1 +1 @@ -{"agent":"opm","chain_next":null,"description":"Heartbeat job - verifies DM system is working every 5 minutes","name":"heartbeat","on_failure":"alert","prompt_template":"Heartbeat check from job scheduler.\nJob ID: {job_id}\nTime: {datetime}\n\nThis is an automated heartbeat. Reply with [RESULT {job_id}] OK to confirm the DM pipeline is healthy.","schedule":"*/5 * * * *","sidechat":{"create":false},"timeout":300} \ No newline at end of file +{"agent":"opm","chain_next":null,"description":"Heartbeat job - verifies DM system is working every 5 minutes (goes to sidechat)","name":"heartbeat","on_failure":"alert","prompt_template":"Heartbeat check from job scheduler.\nJob ID: {job_id}\nTime: {datetime}\n\nThis is an automated heartbeat. Reply with [RESULT {job_id}] OK to confirm the DM pipeline is healthy.","schedule":"*/5 * * * *","sidechat":{"create":true,"name_template":"heartbeat"},"timeout":300} \ No newline at end of file