diff --git a/src/ria_toolkit_oss/agent.py b/src/ria_toolkit_oss/agent.py index 4bb152c..bd4b3fc 100644 --- a/src/ria_toolkit_oss/agent.py +++ b/src/ria_toolkit_oss/agent.py @@ -226,8 +226,11 @@ class NodeAgent: result = executor.run() logger.info("Campaign %s completed — uploading recordings", campaign_id[:8]) self._upload_recordings(campaign_id, config, result) + result_dict = result.to_dict() if hasattr(result, "to_dict") else None + self._report_campaign_status(campaign_id, "completed", result=result_dict) except Exception as exc: logger.error("Campaign %s failed: %s", campaign_id[:8], exc) + self._report_campaign_status(campaign_id, "failed", error=str(exc)) # ------------------------------------------------------------------ # Recording upload (chunked for large files) @@ -268,6 +271,30 @@ class NodeAgent: except Exception as exc: logger.warning("Campaign %s: upload of %s failed: %s", campaign_id[:8], filename, exc) + def _report_campaign_status( + self, + campaign_id: str, + status: str, + result: "dict | None" = None, + error: "str | None" = None, + ) -> None: + """POST campaign completion/failure back to the hub so GET /status/{id} resolves.""" + payload: dict = {"campaign_id": campaign_id, "status": status} + if result is not None: + payload["result"] = result + if error is not None: + payload["error"] = error + try: + resp = self._post( + f"/orchestrator/nodes/{self.node_id}/campaign-status", + json=payload, + timeout=15, + ) + resp.raise_for_status() + logger.info("Campaign %s: reported status=%s to hub", campaign_id[:8], status) + except Exception as exc: + logger.warning("Campaign %s: failed to report status to hub: %s", campaign_id[:8], exc) + def _upload_file(self, base_url: str, file_path: str, metadata: dict) -> dict: """Upload *file_path*, choosing chunked or direct path based on file size.""" import requests as _requests