diff --git a/poc-grpc-agent/.nfs00000000006c16c80000003a b/poc-grpc-agent/.nfs00000000006c16c80000003a deleted file mode 100644 index be501d1..0000000 --- a/poc-grpc-agent/.nfs00000000006c16c80000003a +++ /dev/null @@ -1,33 +0,0 @@ -[🛡️] Boss Plane Orchestrator Starting on [::]:50051... -[🛡️] Boss Plane Refactored & Online. -[📋] Registered Agent Node: agent-node-007 -[📶] Stream Online for agent-node-007 - [📦] Task shared-001 Claimed by agent-node-007 - [📦] Task shared-002 Claimed by agent-node-007 - [🚀] Streamed message to agent-node-007 - [🚀] Streamed message to agent-node-007 - -[🧠] AI Simulation Start... -[📤] Dispatching shell task-1772514336015 to agent-node-007 - [🚀] Streamed message to agent-node-007 - Uname Output: {'stdout': 'Linux d1ceb63b86a7 6.10.11-linuxkit #1 SMP Thu Oct 3 10:17:28 UTC 2024 aarch64 GNU/Linux\n', 'status': 0} - -[🧠] AI Phase 4: Navigating Browser (Antigravity Bridge)... -[🌐📤] Dispatching browser br-1772514336028 to agent-node-007 - [🚀] Streamed message to agent-node-007 - [🌐] Net Inspect: GET https://example.com/ - Nav Result: {'stdout': '', 'status': 0, 'browser': {'url': 'https://example.com/', 'title': 'Example Domain', 'has_snapshot': False, 'a11y': None, 'eval': ''}} - -[🧠] AI Phase 4 Pro: Perception & Advanced Logic... -[🌐📤] Dispatching browser br-1772514336293 to agent-node-007 - [🚀] Streamed message to agent-node-007 - A11y Result: {"role": "WebArea", "name": "Example Domain", "children": [{"role": "heading", "name": "Example Doma... -[🌐📤] Dispatching browser br-1772514336300 to agent-node-007 - [🚀] Streamed message to agent-node-007 - Eval Result: 115.89999997615814 - -[🧠] AI Phase 4 Pro: Triggering Real-time Events (Tunneling)... -[🌐📤] Dispatching browser br-1772514336305 to agent-node-007 - [🚀] Streamed message to agent-node-007 - [🖥️] Live Console: Refactored Hello! - [🖥️] Live Console: Failed to load resource: the server responded with a status of 404 () diff --git a/poc-grpc-agent/.nfs00000000006c16c900000039 b/poc-grpc-agent/.nfs00000000006c16c900000039 deleted file mode 100644 index 9d3246b..0000000 --- a/poc-grpc-agent/.nfs00000000006c16c900000039 +++ /dev/null @@ -1,51 +0,0 @@ -[*] Starting Antigravity Agent Node: agent-node-007... -[🌐] Browser Actor Starting... -[*] Handshake with Orchestrator: agent-node-007 -[OK] Sandbox Policy Synced. -[*] Task Stream Online: agent-node-007 -[🌐] Browser Engine Online. - [📥] Received from Stream: work_pool_update -[*] Inbound: work_pool_update - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: shared-001 -[✅] Validated task shared-001 - [🐚] Executing Shell: uname -a - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: shared-002 -[✅] Validated task shared-002 -[*] Completion: shared-002 - [🐚] Shell Done: uname -a | Stdout Size: 90 -[*] Completion: shared-001 - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: task-1772514336015 -[✅] Validated task task-1772514336015 - [🐚] Executing Shell: uname -a - [🐚] Shell Done: uname -a | Stdout Size: 90 -[*] Completion: task-1772514336015 - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: br-1772514336028 -[✅] Validated task br-1772514336028 - [🌐] Browser Actor Processing: NAVIGATE | Session: antigravity-session-1 -[*] Completion: br-1772514336028 - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: br-1772514336293 -[✅] Validated task br-1772514336293 - [🌐] Browser Actor Processing: GET_A11Y | Session: antigravity-session-1 -[*] Completion: br-1772514336293 - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: br-1772514336300 -[✅] Validated task br-1772514336300 - [🌐] Browser Actor Processing: EVAL | Session: antigravity-session-1 -[*] Completion: br-1772514336300 - [📥] Received from Stream: task_request -[*] Inbound: task_request -[*] Task Launch: br-1772514336305 -[✅] Validated task br-1772514336305 - [🌐] Browser Actor Processing: EVAL | Session: antigravity-session-1 -[*] Completion: br-1772514336305 diff --git a/poc-grpc-agent/.nfs00000000006c17bd0000003f b/poc-grpc-agent/.nfs00000000006c17bd0000003f new file mode 100644 index 0000000..fbc49e2 --- /dev/null +++ b/poc-grpc-agent/.nfs00000000006c17bd0000003f @@ -0,0 +1,52 @@ +[🛡️] Boss Plane Orchestrator Starting on [::]:50051... +[🛡️] Boss Plane Refactored & Online. +[📋] Registered Agent Node: agent-node-007 +[📶] Stream Online for agent-node-007 + [📦] Task shared-001 Claimed by agent-node-007 + [📦] Task shared-002 Claimed by agent-node-007 + [🚀] Streamed message to agent-node-007 + [🚀] Streamed message to agent-node-007 + +[🧠] AI Simulation Start... +[📤] Dispatching shell task-1772515596627 to agent-node-007 + [🚀] Streamed message to agent-node-007 + Uname Output: {'stdout': 'Linux d1ceb63b86a7 6.10.11-linuxkit #1 SMP Thu Oct 3 10:17:28 UTC 2024 aarch64 GNU/Linux\n', 'status': 0} + +[🧠] AI Phase 4: Navigating Browser (Antigravity Bridge)... +[🌐📤] Dispatching browser br-1772515596633 to agent-node-007 + [🚀] Streamed message to agent-node-007 + [🌐] Net Inspect: GET https://example.com/ + Nav Result: {'stdout': '', 'status': 0, 'browser': {'url': 'https://example.com/', 'title': 'Example Domain', 'has_snapshot': False, 'a11y': None, 'eval': ''}} + +[🧠] AI Phase 4 Pro: Perception & Advanced Logic... +[🌐📤] Dispatching browser br-1772515596761 to agent-node-007 + [🚀] Streamed message to agent-node-007 + A11y Result: {"role": "WebArea", "name": "Example Domain", "children": [{"role": "heading", "name": "Example Doma... +[🌐📤] Dispatching browser br-1772515596767 to agent-node-007 + [🚀] Streamed message to agent-node-007 + Eval Result: 92.89999997615814 + +[🧠] AI Phase 4 Pro: Triggering Real-time Events (Tunneling)... +[🌐📤] Dispatching browser br-1772515596772 to agent-node-007 + [🚀] Streamed message to agent-node-007 + [🖥️] Live Console: Refactored Hello! + [🖥️] Live Console: Failed to load resource: the server responded with a status of 404 () +Exception in thread Results-agent-node-007: +Traceback (most recent call last): + File "/usr/local/lib/python3.11/threading.py", line 1045, in _bootstrap_inner + self.run() + File "/usr/local/lib/python3.11/threading.py", line 982, in run + self._target(*self._args, **self._kwargs) + File "/app/poc-grpc-agent/orchestrator/services/grpc_server.py", line 55, in _read_results + for msg in request_iterator: + File "/home/vscode/.local/lib/python3.11/site-packages/grpc/_server.py", line 488, in __next__ + return self._next() + ^^^^^^^^^^^^ + File "/home/vscode/.local/lib/python3.11/site-packages/grpc/_server.py", line 480, in _next + request = self._look_for_request() + ^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/vscode/.local/lib/python3.11/site-packages/grpc/_server.py", line 462, in _look_for_request + _raise_rpc_error(self._state) + File "/home/vscode/.local/lib/python3.11/site-packages/grpc/_server.py", line 162, in _raise_rpc_error + raise rpc_error +grpc.RpcError diff --git a/poc-grpc-agent/agent_node/main.py b/poc-grpc-agent/agent_node/main.py index a39c687..6fa4eb0 100644 --- a/poc-grpc-agent/agent_node/main.py +++ b/poc-grpc-agent/agent_node/main.py @@ -4,6 +4,7 @@ # Add root to path to find protos and other packages sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +import signal from agent_node.node import AgentNode from agent_node.config import NODE_ID @@ -13,7 +14,15 @@ # 1. Initialization node = AgentNode() - # 2. Handshake: Sync configuration and Sandbox Policy + # 2. Signal Handling for Graceful Shutdown + def handle_exit(sig, frame): + node.stop() + sys.exit(0) + + signal.signal(signal.SIGINT, handle_exit) + signal.signal(signal.SIGTERM, handle_exit) + + # Handshake: Sync configuration and Sandbox Policy node.sync_configuration() # 3. Background: Start health reporting (Heartbeats) @@ -23,8 +32,4 @@ node.run_task_stream() if __name__ == '__main__': - try: - main() - except KeyboardInterrupt: - print("\n[🛑] Agent Node Shutdown.") - sys.exit(0) + main() diff --git a/poc-grpc-agent/agent_node/node.py b/poc-grpc-agent/agent_node/node.py index 59a1e2c..0500e5c 100644 --- a/poc-grpc-agent/agent_node/node.py +++ b/poc-grpc-agent/agent_node/node.py @@ -139,3 +139,10 @@ self.task_queue.put(agent_pb2.ClientTaskMessage( task_response=agent_pb2.TaskResponse(task_id=tid, status=status) )) + + def stop(self): + """Gracefully stops all background services and skills.""" + print(f"\n[🛑] Stopping Agent Node: {self.node_id}") + self.skills.shutdown() + # Optionally close gRPC channel if we want to be very clean + # self.channel.close() diff --git a/poc-grpc-agent/agent_node/skills/base.py b/poc-grpc-agent/agent_node/skills/base.py index 7df6e34..33c88ec 100644 --- a/poc-grpc-agent/agent_node/skills/base.py +++ b/poc-grpc-agent/agent_node/skills/base.py @@ -7,3 +7,7 @@ def cancel(self, task_id: str) -> bool: """Attempts to cancel the task and returns success status.""" return False + + def shutdown(self): + """Cleanup resources on node exit.""" + pass diff --git a/poc-grpc-agent/agent_node/skills/browser.py b/poc-grpc-agent/agent_node/skills/browser.py index ea957d3..32ded63 100644 --- a/poc-grpc-agent/agent_node/skills/browser.py +++ b/poc-grpc-agent/agent_node/skills/browser.py @@ -36,6 +36,8 @@ def _browser_actor(self): """Serializes all Playwright operations on a single dedicated thread.""" print("[🌐] Browser Actor Starting...", flush=True) + pw = None + browser = None try: pw = sync_playwright().start() # 12-Factor/Container Optimization: Standard non-sandbox arguments @@ -45,11 +47,17 @@ print("[🌐] Browser Engine Online.", flush=True) except Exception as e: print(f"[!] Browser Actor Startup Fail: {e}", flush=True) + if pw: pw.stop() return while True: try: - task, sandbox, on_complete, on_event = self.task_queue.get() + item = self.task_queue.get() + if item is None: # Sentinel for shutdown + print("[🌐] Browser Actor Shutting Down...", flush=True) + break + + task, sandbox, on_complete, on_event = item action = task.browser_action sid = action.session_id or "default" @@ -101,7 +109,21 @@ print(f" [!] Browser Actor Error: {e}", flush=True) on_complete(task.task_id, {"stderr": str(e), "status": 2}, task.trace_id) + # Cleanup on loop exit + print("[🌐] Cleaning up Browser Engine...", flush=True) + with self.lock: + for s in self.sessions.values(): + try: s["context"].close() + except: pass + self.sessions.clear() + if browser: browser.close() + if pw: pw.stop() + def execute(self, task, sandbox, on_complete, on_event=None): self.task_queue.put((task, sandbox, on_complete, on_event)) def cancel(self, task_id): return False + + def shutdown(self): + """Triggers graceful shutdown of the browser engine.""" + self.task_queue.put(None) diff --git a/poc-grpc-agent/agent_node/skills/manager.py b/poc-grpc-agent/agent_node/skills/manager.py index a1a93e7..616a4ea 100644 --- a/poc-grpc-agent/agent_node/skills/manager.py +++ b/poc-grpc-agent/agent_node/skills/manager.py @@ -51,3 +51,13 @@ """Internal callback to release capacity when a task finishes.""" with self.lock: self.active_tasks.pop(task_id, None) + + def shutdown(self): + """Triggers shutdown for all skills and the worker pool.""" + print("[🔧] Shutting down Skill Manager...") + with self.lock: + for name, skill in self.skills.items(): + print(f" [🔧] Shutting down skill: {name}") + skill.shutdown() + # Shutdown thread pool + self.executor.shutdown(wait=True)