98 lines
4.1 KiB
Python
98 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
||
import json, os, subprocess, sys, time, urllib.request
|
||
|
||
INTERRUPTED_FILE = "/tmp/openclaw-interrupted-turns.json"
|
||
|
||
if not os.path.exists(INTERRUPTED_FILE):
|
||
sys.exit(0)
|
||
|
||
try:
|
||
with open(INTERRUPTED_FILE, "r") as f:
|
||
turns = json.load(f)
|
||
except Exception as e:
|
||
print(f"[replay_interrupted_turns] Failed to read {INTERRUPTED_FILE}: {e}", file=sys.stderr)
|
||
sys.exit(0)
|
||
|
||
if not turns:
|
||
sys.exit(0)
|
||
|
||
print(f"[replay_interrupted_turns] Found {len(turns)} interrupted turn(s). Waiting for gateway /healthz...")
|
||
|
||
gateway_ready = False
|
||
for _ in range(60):
|
||
try:
|
||
with urllib.request.urlopen("http://127.0.0.1:18790/healthz", timeout=3) as resp:
|
||
if resp.status == 200:
|
||
gateway_ready = True
|
||
break
|
||
except Exception:
|
||
pass
|
||
time.sleep(2)
|
||
|
||
if not gateway_ready:
|
||
print("[replay_interrupted_turns] Gateway did not become healthy in 120s. Aborting.", file=sys.stderr)
|
||
sys.exit(1)
|
||
|
||
# Allow 5s for Telegram ingress to bind
|
||
time.sleep(5)
|
||
|
||
for turn in turns:
|
||
sk = turn.get("session_key")
|
||
sid = turn.get("session_id")
|
||
agent_id = turn.get("agent")
|
||
ctx = turn.get("context") or {}
|
||
prompt = turn.get("prompt") or ""
|
||
|
||
channel = ctx.get("channel") or "telegram"
|
||
to_target = ctx.get("to") or ""
|
||
thread_id = ctx.get("threadId")
|
||
|
||
target = to_target
|
||
if target.startswith("telegram:"):
|
||
parts = target.split(":")
|
||
target = parts[1] if len(parts) > 1 else target
|
||
|
||
print(f"[replay_interrupted_turns] Processing agent '{agent_id}' on session '{sk}' target='{target}' thread='{thread_id}'")
|
||
|
||
# 1. Send status notification to Telegram if target exists
|
||
if target:
|
||
notice = "⚠️ OpenClaw wurde während der Bearbeitung neu gestartet – deine Anfrage wird jetzt nachgeholt..."
|
||
notify_cmd = [
|
||
"openclaw", "message", "send",
|
||
"--channel", channel,
|
||
"--target", str(target),
|
||
"-m", notice
|
||
]
|
||
if thread_id is not None:
|
||
notify_cmd.extend(["--thread-id", str(thread_id)])
|
||
try:
|
||
subprocess.run(notify_cmd, check=False, timeout=30)
|
||
print(f"[replay_interrupted_turns] Sent recovery notice to {target}")
|
||
except Exception as e:
|
||
print(f"[replay_interrupted_turns] Notice failed: {e}", file=sys.stderr)
|
||
|
||
# 2. Replay agent turn
|
||
if sk and prompt:
|
||
p_short = (prompt[:60] + "...") if len(prompt) > 60 else prompt
|
||
print(f"[replay_interrupted_turns] Replaying agent turn: {p_short}")
|
||
agent_cmd = [
|
||
"openclaw", "agent",
|
||
"--session-key", sk,
|
||
"-m", prompt,
|
||
"--deliver"
|
||
]
|
||
try:
|
||
res = subprocess.run(agent_cmd, capture_output=True, text=True, timeout=300)
|
||
if res.returncode == 0:
|
||
print(f"[replay_interrupted_turns] Turn replay succeeded for {sk}")
|
||
else:
|
||
print(f"[replay_interrupted_turns] Turn replay exited with code {res.returncode}: {res.stderr[:200]}", file=sys.stderr)
|
||
except Exception as e:
|
||
print(f"[replay_interrupted_turns] Replay execution error: {e}", file=sys.stderr)
|
||
|
||
try:
|
||
os.remove(INTERRUPTED_FILE)
|
||
print(f"[replay_interrupted_turns] Cleaned up {INTERRUPTED_FILE}")
|
||
except Exception:
|
||
pass
|