feat: add openclaw_connect_metadata function and update compatibility check logic, fixes #156

This commit is contained in:
Abhimanyu Saharan
2026-02-22 13:37:01 +05:30
parent d3a61e106b
commit e39b2069fb
3 changed files with 108 additions and 3 deletions

View File

@@ -7,7 +7,12 @@ from dataclasses import dataclass
from typing import Any
from app.core.config import settings
from app.services.openclaw.gateway_rpc import GatewayConfig, OpenClawGatewayError, openclaw_call
from app.services.openclaw.gateway_rpc import (
GatewayConfig,
OpenClawGatewayError,
openclaw_call,
openclaw_connect_metadata,
)
_VERSION_PATTERN = re.compile(r"(?i)v?(?P<version>\d+(?:\.\d+)+)")
_PRIMARY_VERSION_PATHS: tuple[tuple[str, ...], ...] = (
@@ -192,12 +197,27 @@ async def _fetch_schema_metadata(config: GatewayConfig) -> object | None:
return None
async def _fetch_connect_metadata(config: GatewayConfig) -> object | None:
try:
return await openclaw_connect_metadata(config=config)
except OpenClawGatewayError:
return None
async def check_gateway_runtime_compatibility(
config: GatewayConfig,
*,
minimum_version: str | None = None,
) -> GatewayVersionCheckResult:
"""Fetch runtime metadata and evaluate gateway version compatibility."""
connect_payload = await _fetch_connect_metadata(config)
current_version = extract_gateway_version(connect_payload)
if current_version is not None:
return evaluate_gateway_version(
current_version=current_version,
minimum_version=minimum_version,
)
schema_payload = await _fetch_schema_metadata(config)
current_version = extract_gateway_version(schema_payload)
if current_version is not None:

View File

@@ -253,7 +253,7 @@ async def _ensure_connected(
ws: websockets.ClientConnection,
first_message: str | bytes | None,
config: GatewayConfig,
) -> None:
) -> object:
if first_message:
if isinstance(first_message, bytes):
first_message = first_message.decode("utf-8")
@@ -272,7 +272,7 @@ async def _ensure_connected(
"params": _build_connect_params(config),
}
await ws.send(json.dumps(response))
await _await_response(ws, connect_id)
return await _await_response(ws, connect_id)
async def openclaw_call(
@@ -327,6 +327,48 @@ async def openclaw_call(
raise OpenClawGatewayError(str(exc)) from exc
async def openclaw_connect_metadata(*, config: GatewayConfig) -> object:
"""Open a gateway connection and return the connect/hello payload."""
gateway_url = _build_gateway_url(config)
started_at = perf_counter()
logger.debug(
"gateway.rpc.connect_metadata.start gateway_url=%s",
_redacted_url_for_log(gateway_url),
)
try:
async with websockets.connect(gateway_url, ping_interval=None) as ws:
first_message = None
try:
first_message = await asyncio.wait_for(ws.recv(), timeout=2)
except TimeoutError:
first_message = None
metadata = await _ensure_connected(ws, first_message, config)
logger.debug(
"gateway.rpc.connect_metadata.success duration_ms=%s",
int((perf_counter() - started_at) * 1000),
)
return metadata
except OpenClawGatewayError:
logger.warning(
"gateway.rpc.connect_metadata.gateway_error duration_ms=%s",
int((perf_counter() - started_at) * 1000),
)
raise
except (
TimeoutError,
ConnectionError,
OSError,
ValueError,
WebSocketException,
) as exc: # pragma: no cover - network/protocol errors
logger.error(
"gateway.rpc.connect_metadata.transport_error duration_ms=%s error_type=%s",
int((perf_counter() - started_at) * 1000),
exc.__class__.__name__,
)
raise OpenClawGatewayError(str(exc)) from exc
async def send_message(
message: str,
*,