# -*- coding: utf-8 -*- """OpenClaw WebSocket handlers — gateway calls OpenClaw Gateway via WebSocket.""" from __future__ import annotations import json import logging from typing import TYPE_CHECKING if TYPE_CHECKING: from backend.services.gateway import Gateway logger = logging.getLogger(__name__) def _get_ws_client(gateway) -> "OpenClawWebSocketClient": """Get the OpenClaw WebSocket client from gateway.""" from shared.client.openclaw_websocket_client import OpenClawWebSocketClient client = gateway._openclaw_ws if client is None: raise RuntimeError("OpenClaw Gateway not connected") return client async def _ws_call(gateway, method: str, params: dict | None = None) -> dict: """Call OpenClaw Gateway via WebSocket and return result.""" try: client = _get_ws_client(gateway) return await client.call_method(method, params) except Exception as exc: logger.warning("OpenClaw Gateway call failed for %s: %s", method, exc) return {"error": str(exc)[:200]} async def handle_get_openclaw_status(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "status") await websocket.send(json.dumps({"type": "openclaw_status_loaded", "data": result})) async def handle_get_openclaw_sessions(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "sessions.list", {"limit": 50, "includeLastMessage": True}) await websocket.send(json.dumps({"type": "openclaw_sessions_loaded", "data": result})) async def handle_get_openclaw_session_detail(gateway, websocket, data: dict) -> None: session_key = data.get("session_key", "") result = await _ws_call(gateway, "sessions.list", {"limit": 1, "agentId": session_key.split(":")[1] if session_key else None}) await websocket.send(json.dumps({ "type": "openclaw_session_detail_loaded", "data": result, "session_key": session_key, })) async def handle_get_openclaw_session_history(gateway, websocket, data: dict) -> None: session_key = data.get("session_key", "") limit = data.get("limit", 20) result = await _ws_call(gateway, "sessions.list", {"limit": limit}) await websocket.send(json.dumps({ "type": "openclaw_session_history_loaded", "data": result, "session_key": session_key, })) async def handle_get_openclaw_cron(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "cron.list") await websocket.send(json.dumps({"type": "openclaw_cron_loaded", "data": result})) async def handle_get_openclaw_approvals(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "exec.approvals.get") await websocket.send(json.dumps({"type": "openclaw_approvals_loaded", "data": result})) async def handle_get_openclaw_agents(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "agents.list") await websocket.send(json.dumps({"type": "openclaw_agents_loaded", "data": result})) async def handle_get_openclaw_agents_presence(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "node.list") await websocket.send(json.dumps({"type": "openclaw_agents_presence_loaded", "data": result})) async def handle_get_openclaw_skills(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "skills.status") await websocket.send(json.dumps({"type": "openclaw_skills_loaded", "data": result})) async def handle_get_openclaw_models(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "models.list") await websocket.send(json.dumps({"type": "openclaw_models_loaded", "data": result})) async def handle_get_openclaw_hooks(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "tools.catalog") await websocket.send(json.dumps({"type": "openclaw_hooks_loaded", "data": result})) async def handle_get_openclaw_plugins(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "config.get") await websocket.send(json.dumps({"type": "openclaw_plugins_loaded", "data": result})) async def handle_get_openclaw_secrets_audit(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "secrets.reload") await websocket.send(json.dumps({"type": "openclaw_secrets_audit_loaded", "data": result})) async def handle_get_openclaw_security_audit(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "gateway.identity.get") await websocket.send(json.dumps({"type": "openclaw_security_audit_loaded", "data": result})) async def handle_get_openclaw_daemon_status(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "doctor.memory.status") await websocket.send(json.dumps({"type": "openclaw_daemon_status_loaded", "data": result})) async def handle_get_openclaw_pairing(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "device.pair.list") await websocket.send(json.dumps({"type": "openclaw_pairing_loaded", "data": result})) async def handle_get_openclaw_qr(gateway, websocket, data: dict) -> None: await websocket.send(json.dumps({"type": "openclaw_qr_loaded", "data": {"error": "QR code not available via WebSocket"}})) async def handle_get_openclaw_update_status(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "update.run") await websocket.send(json.dumps({"type": "openclaw_update_status_loaded", "data": result})) async def handle_get_openclaw_models_aliases(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "models.list") await websocket.send(json.dumps({"type": "openclaw_models_aliases_loaded", "data": result})) async def handle_get_openclaw_models_fallbacks(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "models.list") await websocket.send(json.dumps({"type": "openclaw_models_fallbacks_loaded", "data": result})) async def handle_get_openclaw_models_image_fallbacks(gateway, websocket, data: dict) -> None: result = await _ws_call(gateway, "models.list") await websocket.send(json.dumps({"type": "openclaw_models_image_fallbacks_loaded", "data": result})) async def handle_get_openclaw_skill_update(gateway, websocket, data: dict) -> None: slug = data.get("slug") all_flag = data.get("all", False) params = {} if slug is not None: params["slug"] = slug if all_flag: params["all"] = "true" result = await _ws_call(gateway, "skills.update", params) await websocket.send(json.dumps({"type": "openclaw_skill_update_loaded", "data": result})) async def handle_get_openclaw_workspace_files(gateway, websocket, data: dict) -> None: raw_workspace = data.get("workspace", "") # Use the workspace param (which is actually the agent.id from frontend) as agent_id agent_id = raw_workspace or "main" result = await _ws_call(gateway, "agents.files.list", {"agentId": agent_id}) if isinstance(result, dict): result["workspace"] = agent_id await websocket.send(json.dumps({"type": "openclaw_workspace_files_loaded", "data": result})) async def handle_get_openclaw_workspace_file(gateway, websocket, data: dict) -> None: agent_id = data.get("agent_id", "main") file_name = data.get("file_name", "") if not file_name: await websocket.send(json.dumps({"type": "openclaw_workspace_file_loaded", "data": {"error": "file_name is required"}})) return result = await _ws_call(gateway, "agents.files.get", {"agentId": agent_id, "name": file_name}) await websocket.send(json.dumps({"type": "openclaw_workspace_file_loaded", "data": result}))