From 97bcb55aaa7e9fef9e8c605c0a8b1a2c9525e8f9 Mon Sep 17 00:00:00 2001 From: Lee Smet Date: Fri, 5 Sep 2025 11:10:04 +0200 Subject: [PATCH] Start python runner through demo script Signed-off-by: Lee Smet --- scripts/supervisor_flow_demo.py | 66 ++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/scripts/supervisor_flow_demo.py b/scripts/supervisor_flow_demo.py index c4c43a0..0f48695 100644 --- a/scripts/supervisor_flow_demo.py +++ b/scripts/supervisor_flow_demo.py @@ -3,7 +3,7 @@ Supervisor flow demo for HeroCoordinator. This script: -- Optionally pre-registers a Python runner on the target Supervisor over Mycelium using an admin secret (--admin-secret). If the flag is not set, this step is skipped. +- Optionally pre-registers and starts a Python runner on the target Supervisor over Mycelium using an admin secret (--admin-secret). If the flag is not set, this step is skipped. - Creates an actor - Creates a context granting the actor admin/reader/executor privileges - Registers a Runner in the context targeting a Supervisor reachable via Mycelium (by public key or IP) @@ -149,6 +149,54 @@ def mycelium_register_runner( # raise RuntimeError("No reply received from supervisor for register_runner (timeout)") +def mycelium_start_runner( + myc: "JsonRpcClient", + dst_pk: Optional[str], + dst_ip: Optional[str], + topic: str, + secret: str, + actor_id: str = "python", + timeout: int = 15, +) -> Any: + """ + Send supervisor.start_runner over Mycelium using pushMessage and wait for the reply. + - actor_id is set to the static name "python" by default to start the registered python runner. + Returns the JSON-RPC 'result' or raises on error/timeout. + """ + envelope = { + "jsonrpc": JSONRPC_VERSION, + "id": 1, + "method": "start_runner", + "params": [actor_id], + } + payload_b64 = base64.b64encode(json.dumps(envelope).encode("utf-8")).decode("ascii") + topic_b64 = base64.b64encode(topic.encode("utf-8")).decode("ascii") + + if dst_pk: + dst = {"pk": dst_pk} + elif dst_ip: + dst = {"ip": dst_ip} + else: + raise RuntimeError("Either dst_pk or dst_ip must be provided for Mycelium destination") + + params = { + "message": {"dst": dst, "topic": topic_b64, "payload": payload_b64}, + } + resp = myc.call("pushMessage", params) + + time.sleep(15) + # if isinstance(resp, dict) and "payload" in resp: + # try: + # reply = json.loads(base64.b64decode(resp["payload"]).decode("utf-8")) + # except Exception as e: + # raise RuntimeError(f"Invalid supervisor reply payload (start_runner): {e}") + # if isinstance(reply, dict) and reply.get("error"): + # raise RuntimeError(f"Supervisor start_runner error: {json.dumps(reply['error'])}") + # return reply.get("result") + # + # raise RuntimeError("No reply received from supervisor for start_runner (timeout)") + + def try_create_or_load(client: JsonRpcClient, create_method: str, create_params: Dict[str, Any], load_method: str, load_params: Dict[str, Any]) -> Any: """Attempt a create; if it fails due to existence, try load.""" @@ -273,6 +321,22 @@ def main(): print(f"ERROR: Supervisor pre-registration failed: {e}", file=sys.stderr) sys.exit(1) + print_header("supervisor.start_runner (start via Mycelium)") + try: + mycelium_result = mycelium_start_runner( + mycelium_client, + args.dst_pk if args.dst_pk else None, + args.dst_ip if args.dst_ip else None, + topic, + args.admin_secret, + actor_id="Python", + timeout=15, + ) + print("Supervisor start_runner ->", mycelium_result) + except Exception as e: + print(f"ERROR: Supervisor start failed: {e}", file=sys.stderr) + sys.exit(1) + print_header("runner.create (or load)") # runner.load requires both context_id and id try: