- 新增 pam_deploy_graph 包,包含 agent、action router、runner、parser 和配置加载能力 - 支持 hybrid_node_mcp 路由策略:PAM_HOME 走脚本 action,PAM_NODE 走 MCP - 新增 fake runner 和 CLI 预演/全局流程验证入口 - 新增路由、输出解析、配置加载、脚本命令构造、Skill 策略加载测试 - 在 README 中记录当前代码骨架、实现进度、使用方式和下一步建议
94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
"""Runner wrapper for PAM_NODE MCP tools."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any, Protocol
|
|
|
|
from .models import ActionResult
|
|
from .output_parser import parse_mcp_result
|
|
|
|
|
|
class McpToolClient(Protocol):
|
|
def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> Any:
|
|
...
|
|
|
|
|
|
DEFAULT_NODE_MCP_TOOLS = {
|
|
"get-online-ips": "pam_get_online_ips",
|
|
"create-download-task": "pam_create_download_task",
|
|
"poll-download-progress": "pam_poll_download_progress",
|
|
"upgrade-ip": "pam_upgrade_ip",
|
|
"poll-upgrade-progress": "pam_poll_upgrade_progress",
|
|
"start-ip": "pam_start_ip",
|
|
"stop-ip": "pam_stop_ip",
|
|
"verify-ip": "pam_verify_ip",
|
|
"download-log": "pam_download_log",
|
|
"rollback-ip": "pam_rollback_ip",
|
|
}
|
|
|
|
|
|
class McpActionRunner:
|
|
def __init__(
|
|
self,
|
|
client: McpToolClient | None = None,
|
|
tool_names: dict[str, str] | None = None,
|
|
) -> None:
|
|
self.client = client
|
|
self.tool_names = tool_names or DEFAULT_NODE_MCP_TOOLS.copy()
|
|
|
|
def run(
|
|
self,
|
|
action: str,
|
|
*,
|
|
params: dict[str, Any],
|
|
ip: str | None = None,
|
|
hash_code: str | None = None,
|
|
stop_first: bool = False,
|
|
**_: Any,
|
|
) -> ActionResult:
|
|
if self.client is None:
|
|
raise RuntimeError("MCP client is not configured")
|
|
tool_name = self.tool_names.get(action)
|
|
if not tool_name:
|
|
raise ValueError(f"No MCP tool mapped for action: {action}")
|
|
arguments = self._build_arguments(
|
|
action,
|
|
params=params,
|
|
ip=ip,
|
|
hash_code=hash_code,
|
|
stop_first=stop_first,
|
|
)
|
|
try:
|
|
payload = self.client.call_tool(tool_name, arguments)
|
|
except Exception as exc: # pragma: no cover - defensive wrapper
|
|
return parse_mcp_result(action, {}, ok=False, tool_name=tool_name, error=str(exc))
|
|
return parse_mcp_result(action, payload, ok=True, tool_name=tool_name)
|
|
|
|
def _build_arguments(
|
|
self,
|
|
action: str,
|
|
*,
|
|
params: dict[str, Any],
|
|
ip: str | None,
|
|
hash_code: str | None,
|
|
stop_first: bool,
|
|
) -> dict[str, Any]:
|
|
arguments = {
|
|
"homeBaseUrl": params.get("HOME_BASE_URL"),
|
|
"airportCode": params.get("AIRPORT_CODE"),
|
|
"applicationName": params.get("APP_NAME"),
|
|
"moduleName": params.get("MODULE_NAME"),
|
|
"versionNumber": params.get("VERSION_NUMBER"),
|
|
"actionType": params.get("ACTION_TYPE"),
|
|
"timeOut": params.get("TIMEOUT"),
|
|
"logName": params.get("LOG_NAME"),
|
|
}
|
|
if ip:
|
|
arguments["targetIp"] = ip
|
|
if hash_code:
|
|
arguments["hashCode"] = hash_code
|
|
if action == "rollback-ip":
|
|
arguments["stopFirst"] = stop_first
|
|
return {key: value for key, value in arguments.items() if value not in (None, "")}
|
|
|