"""Room daemon: a human comments on a room issue -> a seat answers, now, not at the next Tick. python3 -m phastacp.room (long-running; LaunchAgent xyz.teahub.room on hb-5) A room is an open issue whose body contains `", "", "" not in (i.get("body") or "")] def agenda_of(issue: dict) -> str: m = re.search(r"(?m)^agenda:\s*(.+)$", issue.get("body") or "") return m.group(1).strip() if m else issue.get("title", "") def serve_room(clients: dict[str, Gitea], issue: dict, st: dict) -> None: number = int(issue["number"]) g = clients[SEATS[0]] comments = [c for c in g.comments(number) if conversational(c)] if not comments: return last = comments[-1] who = last["user"]["login"] if who in SEATS or last["id"] in st["handled"]: return # picked up try: g.post(f"/repos/{REPO}/issues/comments/{last['id']}/reactions", {"content": "eyes"}) except GiteaError: pass st["handled"].append(last["id"]); save_state(st) transcript = [(speaker_label(c["user"]["login"], SEATS), (c.get("body") or "").strip()) for c in comments] agenda = agenda_of(issue) speaker = next((s for s in SEATS if re.search(rf"@{re.escape(s)}\b", last.get("body") or "")), SEATS[0]) for _ in range(1 + FOLLOW): others = [s for s in SEATS if s != speaker] t0 = time.time() try: text = ask(speaker, turn_prompt(speaker, agenda, transcript, others)) except subprocess.TimeoutExpired: text = "!pass (timed out)" posted = clients[speaker].comment(number, text) transcript.append((speaker, text)) log(f"#{number} {speaker} replied to {who} ({len(text.split())}w, {time.time()-t0:.0f}s)") try: for r in file_cards(clients[speaker], clients[SEATS[0]], number, int(posted["id"]), text): log(f"#{number} {speaker} {r}") for r in second_cards(clients[speaker], clients[SEATS[0]], number, text): log(f"#{number} {speaker} {r}") except Exception as e: # noqa: BLE001 log(f"#{number} card filing failed: {e!r}") nxt = next((s for s in others if re.search(rf"@{re.escape(s)}\b", text)), None) if not nxt: break speaker = nxt def main() -> int: clients = {s: Gitea.seat(s) for s in SEATS} st = load_state() log(f"room daemon: seats={SEATS} poll={POLL}s") while True: try: for issue in rooms(clients[SEATS[0]]): serve_room(clients, issue, st) except Exception as e: # noqa: BLE001 - keep serving; the ledger is the record log("error:", repr(e)[:300]) time.sleep(POLL) if __name__ == "__main__": raise SystemExit(main())