oclaw/runtime/tools/experts/network_ops/netx_http.py
oliver efa72df362 Remove plan mode, skill toolcall path, and inline netx tools.
Wave C subtraction: keep skills as prompt-only, route netx via MCP with a shared netx_http client for xlsx/context inject, and delete plan_agent_v2 from the gateway.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-11 01:17:39 +08:00

104 lines
3.6 KiB
Python

"""Shared netx REST client for oclaw (context inject + ume_alarm_xlsx_report).
Aligns base URL with netx-mcp: ``NETX_API_URL`` then ``OCLAW_NETX_BASE_URL``.
"""
from __future__ import annotations
import contextvars
import os
from typing import Any
import httpx
# Set by ToolExecutor so responses match session language.
NETX_TOOL_LANG: contextvars.ContextVar[str] = contextvars.ContextVar("netx_tool_lang", default="zh")
_PROTOCOL_KEY_ZH_TO_EN: dict[str, str] = {
"其他": "Other",
"时钟": "Clock",
"OTN/光": "OTN/Optical",
"电源": "Power",
}
def _netx_base_url() -> str:
return (
os.getenv("NETX_API_URL") or os.getenv("OCLAW_NETX_BASE_URL") or "http://127.0.0.1:8890"
).strip().rstrip("/")
def _netx_headers() -> dict[str, str]:
h = {"accept": "application/json"}
tok = (os.getenv("OCLAW_NETX_API_TOKEN") or os.getenv("NETX_API_TOKEN") or "").strip()
if tok:
h["authorization"] = f"Bearer {tok}"
return h
def _netx_lang_query_params() -> dict[str, str]:
lang = str(NETX_TOOL_LANG.get() or "zh").strip().lower()
if lang.startswith("en"):
return {"lang": "en"}
return {}
def _localize_netx_payload(data: dict[str, Any], *, lang: str) -> dict[str, Any]:
"""Map legacy Chinese protocol bucket labels to English for en sessions."""
if not str(lang or "").strip().lower().startswith("en"):
return data
proto = data.get("protocol_summary")
if isinstance(proto, list):
for row in proto:
if isinstance(row, dict):
k = str(row.get("key") or "")
if k in _PROTOCOL_KEY_ZH_TO_EN:
row["key"] = _PROTOCOL_KEY_ZH_TO_EN[k]
return data
def _http_post_json(path: str, body: dict[str, Any], *, timeout: float = 180.0) -> dict[str, Any]:
base = _netx_base_url()
url = f"{base}{path}"
try:
with httpx.Client(timeout=timeout, trust_env=False) as client:
resp = client.post(url, json=body, headers=_netx_headers())
text = resp.text
if not resp.is_success:
return {"ok": False, "error": f"netx_http_{resp.status_code}", "detail": text[:800]}
data = resp.json() if text else {}
if isinstance(data, dict):
data = _localize_netx_payload(data, lang=str(NETX_TOOL_LANG.get() or "zh"))
return {"ok": True, "data": data if isinstance(data, dict) else {"raw": data}}
except Exception as exc:
return {"ok": False, "error": "netx_request_failed", "detail": str(exc)[:800]}
def _http_json(method: str, path: str, *, params: dict[str, Any] | None = None) -> dict[str, Any]:
base = _netx_base_url()
url = f"{base}{path}"
merged: dict[str, Any] = dict(_netx_lang_query_params())
if params:
merged.update(params)
try:
with httpx.Client(timeout=45.0, trust_env=False) as client:
resp = client.request(method, url, params=merged or None, headers=_netx_headers())
text = resp.text
if not resp.is_success:
return {"ok": False, "error": f"netx_http_{resp.status_code}", "detail": text[:800]}
data = resp.json() if text else {}
if isinstance(data, dict):
data = _localize_netx_payload(data, lang=str(NETX_TOOL_LANG.get() or "zh"))
return {"ok": True, "data": data if isinstance(data, dict) else {"raw": data}}
except Exception as exc:
return {"ok": False, "error": "netx_request_failed", "detail": str(exc)[:800]}
__all__ = [
"NETX_TOOL_LANG",
"_http_json",
"_http_post_json",
"_localize_netx_payload",
"_netx_base_url",
"_netx_headers",
]