fix(plugin-runtime): propagate send capability failure details to tools

This commit is contained in:
Losita
2026-05-12 21:31:53 +08:00
parent 074ca4147f
commit fd50f33662
2 changed files with 119 additions and 1 deletions

View File

@@ -542,6 +542,101 @@ class TestSDK:
assert await plugin.ctx.llm.get_available_models() == ["utils", "replyer"]
@pytest.mark.asyncio
async def test_runner_injected_context_raises_send_capability_error_details(self):
"""Runner 应将 send.* 能力失败的底层错误透传为异常。"""
from src.plugin_runtime.runner.runner_main import PluginRunner
class DummyRPCClient:
async def send_request(self, method, plugin_id="", payload=None, timeout_ms=30000):
assert method == "cap.call"
assert plugin_id == "owner_plugin"
assert payload == {
"capability": "send.custom",
"args": {
"message_type": "poke",
"content": {"qq_id": "1"},
"custom_type": "poke",
"data": {"qq_id": "1"},
"stream_id": "当前聊天流",
},
}
return SimpleNamespace(
error=None,
payload={"success": True, "result": {"success": False, "error": "未找到聊天流: 当前聊天流"}},
)
class DummyPlugin:
def _set_context(self, ctx):
self.ctx = ctx
runner = PluginRunner(host_address="dummy", session_token="token", plugin_dirs=[])
runner._rpc_client = DummyRPCClient()
plugin = DummyPlugin()
runner._inject_context("owner_plugin", plugin)
with pytest.raises(RuntimeError, match="未找到聊天流: 当前聊天流"):
await plugin.ctx.send.custom(
custom_type="poke",
data={"qq_id": "1"},
stream_id="当前聊天流",
)
@pytest.mark.asyncio
async def test_runner_invoke_tool_propagates_send_failure_details(self):
"""插件工具捕获 send.* 失败时,应能拿到底层错误详情。"""
from src.plugin_runtime.protocol.envelope import Envelope, MessageType
from src.plugin_runtime.runner.runner_main import PluginRunner
class DummyRPCClient:
async def send_request(self, method, plugin_id="", payload=None, timeout_ms=30000):
assert method == "cap.call"
return SimpleNamespace(
error=None,
payload={"success": True, "result": {"success": False, "error": "未找到聊天流: 当前聊天流"}},
)
class DummyPlugin:
def _set_context(self, ctx):
self.ctx = ctx
async def handle_poke(self, **kwargs):
try:
await self.ctx.send.custom(
custom_type="poke",
data={"qq_id": "1"},
stream_id=str(kwargs.get("stream_id", "")),
)
except Exception as exc:
return {"success": False, "message": f"戳一戳失败: {exc}"}
return {"success": True, "message": "戳一戳成功"}
runner = PluginRunner(host_address="dummy", session_token="token", plugin_dirs=[])
runner._rpc_client = DummyRPCClient()
plugin = DummyPlugin()
runner._inject_context("demo_plugin", plugin)
meta = SimpleNamespace(
plugin_id="demo_plugin",
instance=plugin,
component_handlers={"poke": "handle_poke"},
)
runner._loader._loaded_plugins["demo_plugin"] = meta
envelope = Envelope(
request_id=1,
message_type=MessageType.REQUEST,
method="plugin.invoke_tool",
plugin_id="demo_plugin",
payload={"component_name": "poke", "args": {"stream_id": "当前聊天流"}},
)
response = await runner._handle_invoke(envelope)
assert response.payload["success"] is True
assert response.payload["result"] == {"success": False, "message": "戳一戳失败: 未找到聊天流: 当前聊天流"}
@pytest.mark.asyncio
async def test_runner_applies_initial_plugin_config(self, tmp_path):
"""Runner 应在 on_load 前为支持的插件实例注入 config.toml。"""