merge: 同步 upstream/r-dev 并解决冲突

This commit is contained in:
DawnARC
2026-04-03 19:56:45 +08:00
186 changed files with 14212 additions and 6705 deletions

View File

@@ -1,9 +1,11 @@
from .components import RuntimeComponentCapabilityMixin
from .core import RuntimeCoreCapabilityMixin
from .data import RuntimeDataCapabilityMixin
from .render import RuntimeRenderCapabilityMixin
__all__ = [
"RuntimeComponentCapabilityMixin",
"RuntimeCoreCapabilityMixin",
"RuntimeDataCapabilityMixin",
"RuntimeRenderCapabilityMixin",
]

View File

@@ -458,6 +458,17 @@ class RuntimeComponentCapabilityMixin:
async def _cap_component_get_plugin_info(
self: _RuntimeComponentManagerProtocol, plugin_id: str, capability: str, args: Dict[str, Any]
) -> Any:
"""获取指定插件的基础信息。
Args:
plugin_id: 当前调用方插件 ID。
capability: 当前能力名称。
args: 能力调用参数。
Returns:
Any: 插件基础信息响应。
"""
plugin_name: str = args.get("plugin_name", plugin_id)
try:
sv = self._get_supervisor_for_plugin(plugin_name)
@@ -473,10 +484,46 @@ class RuntimeComponentCapabilityMixin:
"description": "",
"author": "",
"enabled": True,
"default_config": reg.default_config,
"config_schema": reg.config_schema,
},
}
return {"success": False, "error": f"未找到插件: {plugin_name}"}
async def _cap_component_get_plugin_config_schema(
self: _RuntimeComponentManagerProtocol, plugin_id: str, capability: str, args: Dict[str, Any]
) -> Any:
"""获取指定插件注册时上报的配置 Schema。
Args:
plugin_id: 当前调用方插件 ID。
capability: 当前能力名称。
args: 能力调用参数。
Returns:
Any: 包含配置 Schema 与默认配置的响应。
"""
plugin_name: str = args.get("plugin_name", plugin_id)
try:
sv = self._get_supervisor_for_plugin(plugin_name)
except RuntimeError as exc:
return {"success": False, "error": str(exc)}
if sv is None:
return {"success": False, "error": f"未找到插件: {plugin_name}"}
registration = sv._registered_plugins.get(plugin_name)
if registration is None:
return {"success": False, "error": f"未找到插件: {plugin_name}"}
return {
"success": True,
"plugin_id": plugin_name,
"schema": registration.config_schema,
"default_config": registration.default_config,
}
async def _cap_component_list_loaded_plugins(
self: _RuntimeComponentManagerProtocol, plugin_id: str, capability: str, args: Dict[str, Any]
) -> Any:

View File

@@ -81,6 +81,7 @@ def register_capability_impls(manager: "PluginRuntimeManager", supervisor: Plugi
_register("component.get_all_plugins", manager._cap_component_get_all_plugins)
_register("component.get_plugin_info", manager._cap_component_get_plugin_info)
_register("component.get_plugin_config_schema", manager._cap_component_get_plugin_config_schema)
_register("component.list_loaded_plugins", manager._cap_component_list_loaded_plugins)
_register("component.list_registered_plugins", manager._cap_component_list_registered_plugins)
_register("component.enable", manager._cap_component_enable)
@@ -90,4 +91,5 @@ def register_capability_impls(manager: "PluginRuntimeManager", supervisor: Plugi
_register("component.reload_plugin", manager._cap_component_reload_plugin)
_register("knowledge.search", manager._cap_knowledge_search)
_register("render.html2png", manager._cap_render_html2png)
logger.debug("已注册全部主程序能力实现")

View File

@@ -0,0 +1,121 @@
"""插件运行时的浏览器渲染能力。"""
from typing import Any, Dict
from src.common.logger import get_logger
from src.services.html_render_service import HtmlRenderRequest, get_html_render_service
logger = get_logger("plugin_runtime.integration")
class RuntimeRenderCapabilityMixin:
"""插件运行时的浏览器渲染能力混入。"""
@staticmethod
def _coerce_int(value: Any, default: int) -> int:
"""将任意值尽量转换为整数。
Args:
value: 原始输入值。
default: 转换失败时返回的默认值。
Returns:
int: 规范化后的整数结果。
"""
try:
return int(value)
except (TypeError, ValueError):
return default
@staticmethod
def _coerce_float(value: Any, default: float) -> float:
"""将任意值尽量转换为浮点数。
Args:
value: 原始输入值。
default: 转换失败时返回的默认值。
Returns:
float: 规范化后的浮点结果。
"""
try:
return float(value)
except (TypeError, ValueError):
return default
@staticmethod
def _coerce_bool(value: Any, default: bool = False) -> bool:
"""将任意值转换为布尔值。
Args:
value: 原始输入值。
default: 输入为空时返回的默认值。
Returns:
bool: 规范化后的布尔结果。
"""
if value is None:
return default
if isinstance(value, str):
normalized_value = value.strip().lower()
if normalized_value in {"0", "false", "no", "off"}:
return False
if normalized_value in {"1", "true", "yes", "on"}:
return True
return bool(value)
def _build_html_render_request(self, args: Dict[str, Any]) -> HtmlRenderRequest:
"""根据 capability 调用参数构造渲染请求。
Args:
args: capability 调用参数。
Returns:
HtmlRenderRequest: 结构化后的渲染请求。
"""
viewport = args.get("viewport", {})
viewport_width = 900
viewport_height = 500
if isinstance(viewport, dict):
viewport_width = self._coerce_int(viewport.get("width"), viewport_width)
viewport_height = self._coerce_int(viewport.get("height"), viewport_height)
return HtmlRenderRequest(
html=str(args.get("html", "") or ""),
selector=str(args.get("selector", "body") or "body"),
viewport_width=viewport_width,
viewport_height=viewport_height,
device_scale_factor=self._coerce_float(args.get("device_scale_factor"), 2.0),
full_page=self._coerce_bool(args.get("full_page"), False),
omit_background=self._coerce_bool(args.get("omit_background"), False),
wait_until=str(args.get("wait_until", "load") or "load"),
wait_for_selector=str(args.get("wait_for_selector", "") or ""),
wait_for_timeout_ms=self._coerce_int(args.get("wait_for_timeout_ms"), 0),
timeout_ms=self._coerce_int(args.get("timeout_ms"), 0),
allow_network=self._coerce_bool(args.get("allow_network"), False),
)
async def _cap_render_html2png(self, plugin_id: str, capability: str, args: Dict[str, Any]) -> Any:
"""将 HTML 内容渲染为 PNG 图片。
Args:
plugin_id: 调用该能力的插件 ID。
capability: 当前能力名称。
args: 能力调用参数。
Returns:
Any: 标准化后的能力返回结构。
"""
del plugin_id, capability
try:
request = self._build_html_render_request(args)
result = await get_html_render_service().render_html_to_png(request)
return {"success": True, "result": result.to_payload()}
except Exception as exc:
logger.error(f"[cap.render.html2png] 执行失败: {exc}", exc_info=True)
return {"success": False, "error": str(exc)}