feat(boards): Store gateway config per board
Move gateway configuration into board settings and wire agent\nprovisioning, heartbeat templates, and gateway status lookups\nto use board-specific gateway settings. Adds board_id on agents\nand UI updates for board-scoped selection.\n\nCo-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,6 @@ from uuid import uuid4
|
||||
|
||||
import websockets
|
||||
|
||||
from app.core.config import settings
|
||||
|
||||
|
||||
class OpenClawGatewayError(RuntimeError):
|
||||
@@ -21,9 +20,17 @@ class OpenClawResponse:
|
||||
payload: Any
|
||||
|
||||
|
||||
def _build_gateway_url() -> str:
|
||||
base_url = settings.openclaw_gateway_url or "ws://127.0.0.1:18789"
|
||||
token = settings.openclaw_gateway_token
|
||||
@dataclass(frozen=True)
|
||||
class GatewayConfig:
|
||||
url: str
|
||||
token: str | None = None
|
||||
|
||||
|
||||
def _build_gateway_url(config: GatewayConfig) -> str:
|
||||
base_url = (config.url or "").strip()
|
||||
if not base_url:
|
||||
raise OpenClawGatewayError("Gateway URL is not configured for this board.")
|
||||
token = config.token
|
||||
if not token:
|
||||
return base_url
|
||||
parsed = urlparse(base_url)
|
||||
@@ -58,7 +65,9 @@ async def _send_request(
|
||||
|
||||
|
||||
async def _handle_challenge(
|
||||
ws: websockets.WebSocketClientProtocol, first_message: str | bytes | None
|
||||
ws: websockets.WebSocketClientProtocol,
|
||||
first_message: str | bytes | None,
|
||||
config: GatewayConfig,
|
||||
) -> None:
|
||||
if not first_message:
|
||||
return
|
||||
@@ -69,28 +78,35 @@ async def _handle_challenge(
|
||||
return
|
||||
|
||||
connect_id = str(uuid4())
|
||||
params: dict[str, Any] = {
|
||||
"minProtocol": 3,
|
||||
"maxProtocol": 3,
|
||||
"client": {
|
||||
"id": "gateway-client",
|
||||
"version": "1.0.0",
|
||||
"platform": "web",
|
||||
"mode": "ui",
|
||||
},
|
||||
}
|
||||
if config.token:
|
||||
params["auth"] = {"token": config.token}
|
||||
response = {
|
||||
"type": "req",
|
||||
"id": connect_id,
|
||||
"method": "connect",
|
||||
"params": {
|
||||
"minProtocol": 3,
|
||||
"maxProtocol": 3,
|
||||
"client": {
|
||||
"id": "gateway-client",
|
||||
"version": "1.0.0",
|
||||
"platform": "web",
|
||||
"mode": "ui",
|
||||
},
|
||||
"auth": {"token": settings.openclaw_gateway_token},
|
||||
},
|
||||
"params": params,
|
||||
}
|
||||
await ws.send(json.dumps(response))
|
||||
await _await_response(ws, connect_id)
|
||||
|
||||
|
||||
async def openclaw_call(method: str, params: dict[str, Any] | None = None) -> Any:
|
||||
gateway_url = _build_gateway_url()
|
||||
async def openclaw_call(
|
||||
method: str,
|
||||
params: dict[str, Any] | None = None,
|
||||
*,
|
||||
config: GatewayConfig,
|
||||
) -> Any:
|
||||
gateway_url = _build_gateway_url(config)
|
||||
try:
|
||||
async with websockets.connect(gateway_url, ping_interval=None) as ws:
|
||||
first_message = None
|
||||
@@ -98,7 +114,7 @@ async def openclaw_call(method: str, params: dict[str, Any] | None = None) -> An
|
||||
first_message = await asyncio.wait_for(ws.recv(), timeout=2)
|
||||
except asyncio.TimeoutError:
|
||||
first_message = None
|
||||
await _handle_challenge(ws, first_message)
|
||||
await _handle_challenge(ws, first_message, config)
|
||||
return await _send_request(ws, method, params)
|
||||
except OpenClawGatewayError:
|
||||
raise
|
||||
@@ -110,6 +126,7 @@ async def send_message(
|
||||
message: str,
|
||||
*,
|
||||
session_key: str,
|
||||
config: GatewayConfig,
|
||||
deliver: bool = False,
|
||||
) -> Any:
|
||||
params: dict[str, Any] = {
|
||||
@@ -118,23 +135,31 @@ async def send_message(
|
||||
"deliver": deliver,
|
||||
"idempotencyKey": str(uuid4()),
|
||||
}
|
||||
return await openclaw_call("chat.send", params)
|
||||
return await openclaw_call("chat.send", params, config=config)
|
||||
|
||||
|
||||
async def get_chat_history(session_key: str, limit: int | None = None) -> Any:
|
||||
async def get_chat_history(
|
||||
session_key: str,
|
||||
config: GatewayConfig,
|
||||
limit: int | None = None,
|
||||
) -> Any:
|
||||
params: dict[str, Any] = {"sessionKey": session_key}
|
||||
if limit is not None:
|
||||
params["limit"] = limit
|
||||
return await openclaw_call("chat.history", params)
|
||||
return await openclaw_call("chat.history", params, config=config)
|
||||
|
||||
|
||||
async def delete_session(session_key: str) -> Any:
|
||||
return await openclaw_call("sessions.delete", {"key": session_key})
|
||||
async def delete_session(session_key: str, *, config: GatewayConfig) -> Any:
|
||||
return await openclaw_call("sessions.delete", {"key": session_key}, config=config)
|
||||
|
||||
|
||||
async def ensure_session(session_key: str, label: str | None = None) -> Any:
|
||||
async def ensure_session(
|
||||
session_key: str,
|
||||
*,
|
||||
config: GatewayConfig,
|
||||
label: str | None = None,
|
||||
) -> Any:
|
||||
params: dict[str, Any] = {"key": session_key}
|
||||
if label:
|
||||
params["label"] = label
|
||||
return await openclaw_call("sessions.patch", params)
|
||||
|
||||
return await openclaw_call("sessions.patch", params, config=config)
|
||||
|
||||
Reference in New Issue
Block a user