Skip to content

Commit c70323a

Browse files
committed
fix: match plugin tool module prefixes
1 parent 7e22a07 commit c70323a

2 files changed

Lines changed: 118 additions & 2 deletions

File tree

astrbot/core/star/star_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,7 @@ async def turn_off_plugin(self, plugin_name: str) -> None:
17311731
if (
17321732
plugin.module_path
17331733
and mp
1734-
and plugin.module_path.startswith(mp)
1734+
and mp.startswith(plugin.module_path)
17351735
and not mp.endswith(("astrbot.builtin_stars", "data.plugins"))
17361736
):
17371737
func_tool.active = False
@@ -1806,7 +1806,7 @@ async def turn_on_plugin(self, plugin_name: str) -> None:
18061806
if (
18071807
plugin.module_path
18081808
and mp
1809-
and plugin.module_path.startswith(mp)
1809+
and mp.startswith(plugin.module_path)
18101810
and not mp.endswith(("astrbot.builtin_stars", "data.plugins"))
18111811
and func_tool.name in inactivated_llm_tools
18121812
):

tests/test_plugin_manager.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import os
44
from pathlib import Path
55
from typing import Any, cast
6+
from unittest.mock import AsyncMock
67

78
import pytest
89
import yaml
910

11+
from astrbot.core.agent.tool import FunctionTool
1012
from astrbot.core.star import star_manager as star_manager_module
1113
from astrbot.core.star.star_manager import PluginDependencyInstallError, PluginManager
1214
from astrbot.core.utils.pip_installer import PipInstallError
@@ -162,6 +164,120 @@ def _clear_star_runtime_state():
162164
star_manager_module.star_handlers_registry.clear()
163165

164166

167+
def _plugin_toggle_manager(plugin):
168+
manager = object.__new__(PluginManager)
169+
manager.context = type(
170+
"Context",
171+
(),
172+
{"get_registered_star": lambda self, name: plugin if name == plugin.name else None},
173+
)()
174+
manager._pm_lock = asyncio.Lock()
175+
manager._terminate_plugin = AsyncMock()
176+
manager.reload = AsyncMock(return_value=(True, ""))
177+
return manager
178+
179+
180+
def _tool(name: str, module_path: str, active: bool = True) -> FunctionTool:
181+
return FunctionTool(
182+
name=name,
183+
description=name,
184+
parameters={"type": "object", "properties": {}},
185+
handler_module_path=module_path,
186+
active=active,
187+
)
188+
189+
190+
@pytest.fixture
191+
def plugin_toggle_preferences(monkeypatch):
192+
values = {
193+
"inactivated_plugins": [],
194+
"inactivated_llm_tools": [],
195+
}
196+
197+
async def global_get(key, default):
198+
return values.get(key, default)
199+
200+
async def global_put(key, value):
201+
values[key] = value
202+
203+
monkeypatch.setattr(star_manager_module.sp, "global_get", global_get)
204+
monkeypatch.setattr(star_manager_module.sp, "global_put", global_put)
205+
return values
206+
207+
208+
@pytest.mark.asyncio
209+
async def test_turn_off_plugin_deactivates_tools_under_plugin_module(
210+
monkeypatch,
211+
plugin_toggle_preferences,
212+
):
213+
plugin = star_manager_module.StarMetadata(
214+
name="demo",
215+
module_path="data.plugins.demo.main",
216+
activated=True,
217+
)
218+
plugin_tool = _tool(
219+
"demo_tool",
220+
"data.plugins.demo.main.tools",
221+
)
222+
other_tool = _tool(
223+
"other_tool",
224+
"data.plugins.other.main.tools",
225+
)
226+
monkeypatch.setattr(
227+
star_manager_module.llm_tools,
228+
"func_list",
229+
[plugin_tool, other_tool],
230+
)
231+
manager = _plugin_toggle_manager(plugin)
232+
233+
await manager.turn_off_plugin("demo")
234+
235+
assert plugin_tool.active is False
236+
assert other_tool.active is True
237+
assert plugin_toggle_preferences["inactivated_plugins"] == [
238+
"data.plugins.demo.main"
239+
]
240+
assert plugin_toggle_preferences["inactivated_llm_tools"] == ["demo_tool"]
241+
242+
243+
@pytest.mark.asyncio
244+
async def test_turn_on_plugin_reactivates_tools_under_plugin_module(
245+
monkeypatch,
246+
plugin_toggle_preferences,
247+
):
248+
plugin = star_manager_module.StarMetadata(
249+
name="demo",
250+
module_path="data.plugins.demo.main",
251+
activated=False,
252+
)
253+
plugin_toggle_preferences["inactivated_plugins"] = ["data.plugins.demo.main"]
254+
plugin_toggle_preferences["inactivated_llm_tools"] = ["demo_tool", "manual_tool"]
255+
plugin_tool = _tool(
256+
"demo_tool",
257+
"data.plugins.demo.main.tools",
258+
active=False,
259+
)
260+
manual_tool = _tool(
261+
"manual_tool",
262+
"data.plugins.other.main.tools",
263+
active=False,
264+
)
265+
monkeypatch.setattr(
266+
star_manager_module.llm_tools,
267+
"func_list",
268+
[plugin_tool, manual_tool],
269+
)
270+
manager = _plugin_toggle_manager(plugin)
271+
272+
await manager.turn_on_plugin("demo")
273+
274+
assert plugin_tool.active is True
275+
assert manual_tool.active is False
276+
assert plugin_toggle_preferences["inactivated_plugins"] == []
277+
assert plugin_toggle_preferences["inactivated_llm_tools"] == ["manual_tool"]
278+
manager.reload.assert_awaited_once_with("demo")
279+
280+
165281
def _build_load_mock(events):
166282
async def mock_load(specified_dir_name=None, ignore_version_check=False):
167283
del ignore_version_check

0 commit comments

Comments
 (0)