feat(plugin-runtime): add plugin isolation IPC infrastructure
- Protocol layer: Envelope model with Pydantic schema, MsgPack/JSON codecs, unified error codes - Transport layer: cross-platform IPC abstraction with 4-byte length-prefixed framing (UDS + TCP fallback) - Host: RPC server, policy engine, circuit breaker, capability service, supervisor with hot-reload - Runner: RPC client, plugin loader, process entry point - Tests: 16 passing tests covering protocol, transport, host, and E2E handshake
This commit is contained in:
108
src/plugin_runtime/host/capability_service.py
Normal file
108
src/plugin_runtime/host/capability_service.py
Normal file
@@ -0,0 +1,108 @@
|
||||
"""能力服务层
|
||||
|
||||
Host 端实现的能力服务,处理来自插件的 cap.* 请求。
|
||||
每个能力方法被注册到 RPC Server,接收 Runner 转发的请求并执行实际操作。
|
||||
"""
|
||||
|
||||
from typing import Any, Callable, Awaitable
|
||||
|
||||
import logging
|
||||
|
||||
from src.plugin_runtime.protocol.envelope import (
|
||||
CapabilityRequestPayload,
|
||||
CapabilityResponsePayload,
|
||||
Envelope,
|
||||
)
|
||||
from src.plugin_runtime.protocol.errors import ErrorCode, RPCError
|
||||
from src.plugin_runtime.host.policy_engine import PolicyEngine
|
||||
|
||||
logger = logging.getLogger("plugin_runtime.host.capability_service")
|
||||
|
||||
# 能力实现函数类型: (plugin_id, capability, args) -> result
|
||||
CapabilityImpl = Callable[[str, str, dict[str, Any]], Awaitable[Any]]
|
||||
|
||||
|
||||
class CapabilityService:
|
||||
"""能力服务
|
||||
|
||||
负责:
|
||||
1. 注册能力实现
|
||||
2. 接收插件的能力调用请求
|
||||
3. 通过策略引擎校验权限和限流
|
||||
4. 执行实际操作并返回结果
|
||||
"""
|
||||
|
||||
def __init__(self, policy_engine: PolicyEngine):
|
||||
self._policy = policy_engine
|
||||
# capability_name -> implementation
|
||||
self._implementations: dict[str, CapabilityImpl] = {}
|
||||
|
||||
def register_capability(self, name: str, impl: CapabilityImpl) -> None:
|
||||
"""注册一个能力实现
|
||||
|
||||
Args:
|
||||
name: 能力名称,如 "send.text", "db.query", "llm.generate"
|
||||
impl: 实现函数
|
||||
"""
|
||||
self._implementations[name] = impl
|
||||
logger.debug(f"注册能力实现: {name}")
|
||||
|
||||
async def handle_capability_request(self, envelope: Envelope) -> Envelope:
|
||||
"""处理能力调用请求(作为 RPC Server 的 method handler)
|
||||
|
||||
从 envelope 中提取 capability 名称和参数,
|
||||
校验权限后调用对应实现。
|
||||
"""
|
||||
plugin_id = envelope.plugin_id
|
||||
|
||||
try:
|
||||
req = CapabilityRequestPayload.model_validate(envelope.payload)
|
||||
except Exception as e:
|
||||
return envelope.make_error_response(
|
||||
ErrorCode.E_BAD_PAYLOAD.value,
|
||||
f"能力调用 payload 格式错误: {e}",
|
||||
)
|
||||
|
||||
capability = req.capability
|
||||
|
||||
# 1. 权限校验
|
||||
allowed, reason = self._policy.check_capability(plugin_id, capability)
|
||||
if not allowed:
|
||||
return envelope.make_error_response(
|
||||
ErrorCode.E_CAPABILITY_DENIED.value,
|
||||
reason,
|
||||
)
|
||||
|
||||
# 2. 限流校验
|
||||
allowed, reason = self._policy.check_rate_limit(plugin_id)
|
||||
if not allowed:
|
||||
return envelope.make_error_response(
|
||||
ErrorCode.E_BACKPRESSURE.value,
|
||||
reason,
|
||||
)
|
||||
|
||||
# 3. 查找实现
|
||||
impl = self._implementations.get(capability)
|
||||
if impl is None:
|
||||
return envelope.make_error_response(
|
||||
ErrorCode.E_METHOD_NOT_ALLOWED.value,
|
||||
f"未注册的能力: {capability}",
|
||||
)
|
||||
|
||||
# 4. 执行
|
||||
try:
|
||||
result = await impl(plugin_id, capability, req.args)
|
||||
resp_payload = CapabilityResponsePayload(success=True, result=result)
|
||||
return envelope.make_response(payload=resp_payload.model_dump())
|
||||
except RPCError as e:
|
||||
return envelope.make_error_response(e.code.value, e.message, e.details)
|
||||
except Exception as e:
|
||||
logger.error(f"能力 {capability} 执行异常: {e}", exc_info=True)
|
||||
return envelope.make_error_response(
|
||||
ErrorCode.E_CAPABILITY_FAILED.value,
|
||||
str(e),
|
||||
)
|
||||
|
||||
def list_capabilities(self) -> list[str]:
|
||||
"""列出所有已注册的能力"""
|
||||
return list(self._implementations.keys())
|
||||
Reference in New Issue
Block a user