diff --git a/bridge/aria_bridge.py b/bridge/aria_bridge.py index e08833b..68b4edd 100644 --- a/bridge/aria_bridge.py +++ b/bridge/aria_bridge.py @@ -1677,8 +1677,14 @@ class ARIABridge: return if msg_type == "cancel_request": - logger.info("[rvs] Cancel-Request von App — rufe Diagnostic /api/cancel auf") - await self._cancel_via_diagnostic() + hard = bool(payload.get("hard")) + if hard: + logger.warning("[rvs] NOT-AUS — hard cancel: Diagnostic /api/cancel + Proxy /cancel-all") + await self._cancel_via_diagnostic() + await self._cancel_proxy_subprocesses() + else: + logger.info("[rvs] Cancel-Request von App — rufe Diagnostic /api/cancel auf") + await self._cancel_via_diagnostic() await self._emit_activity("idle", "") return @@ -2709,6 +2715,24 @@ class ARIABridge: status = await asyncio.get_event_loop().run_in_executor(None, _do_request) logger.info("[cancel] Diagnostic /api/cancel: %s", status) + async def _cancel_proxy_subprocesses(self) -> None: + """Not-Aus: ruft den proxy-internen /cancel-all Side-Channel auf + (siehe proxy-patches/routes.js). Killt alle aktiven Claude-Code- + Subprocesses sofort. Bridge ist auf aria-net, Proxy auch — also + per Container-Name + Side-Channel-Port (Default 3457) erreichbar.""" + url = os.environ.get("PROXY_INTERNAL_URL", "http://aria-proxy:3457") + "/cancel-all" + + def _do_request(): + try: + req = urllib.request.Request(url, method="POST", data=b"") + with urllib.request.urlopen(req, timeout=3) as resp: + return resp.status, resp.read().decode("utf-8", "ignore")[:200] + except Exception as e: + return f"error: {e}", "" + + status, body = await asyncio.get_event_loop().run_in_executor(None, _do_request) + logger.warning("[NOT-AUS] proxy /cancel-all: %s %s", status, body) + async def _emit_activity(self, activity: str, tool: str = "", force: bool = False) -> None: """Sendet agent_activity an die App — nur wenn sich der State geaendert hat. @@ -2890,6 +2914,24 @@ class ARIABridge: # selbst wenn derselbe Name zweimal in Folge kommt. asyncio.create_task(self._emit_activity("tool", tool, force=True)) await _send_response(writer, 200, {"ok": True}) + elif method == "POST" and path == "/internal/agent-stream": + # Vom Proxy gefeuert: voller Live-Stream der Claude-Code- + # Session (assistant_text, tool_use mit Input, tool_result + # mit truncated Output, start/end Markers). Wir leiten 1:1 + # als RVS agent_stream an Diagnostic (ARIA-Live-View) und + # App weiter — read-only Mirror der gerade laufenden + # ARIA-Aktivitaet. + try: + data = json.loads(body.decode("utf-8", "ignore")) + except Exception as exc: + await _send_response(writer, 400, {"error": f"bad json: {exc}"}) + return + asyncio.create_task(self._send_to_rvs({ + "type": "agent_stream", + "payload": data, + "timestamp": int(time.time() * 1000), + })) + await _send_response(writer, 200, {"ok": True}) elif method == "POST" and path == "/internal/flux-generate": # Vom Brain (flux_generate-Tool) gefeuert. Wir routen den # Render-Request via RVS an die flux-bridge (Gamebox), diff --git a/diagnostic/index.html b/diagnostic/index.html index 29580c5..201558d 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -395,18 +395,29 @@
- +
- -
-
- - Nicht verbunden + +
+
+ Idle — warte auf ARIA-Aktivitaet + + + +
+
+
Sobald ARIA denkt oder ein Tool nutzt, taucht es hier in Echtzeit auf.
-