mirror of
https://github.com/NCBM/plyngent.git
synced 2026-07-25 08:04:57 +08:00
core/cli: plugins list/enable/disable commands and /plugins slash
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""CLI ``plyngent plugins`` and slash ``/plugins``."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
import tomlkit
|
||||
from click.testing import CliRunner
|
||||
|
||||
from plyngent.cli.app import main
|
||||
from plyngent.cli.slash import handle_slash
|
||||
from plyngent.cli.state import ReplState
|
||||
from plyngent.config.models import DatabaseConfig, OpenAIProvider
|
||||
from plyngent.config.store import ConfigStore
|
||||
from plyngent.memory import MemoryStore
|
||||
from plyngent.tools.plugins import DiscoveredPlugin, PluginStatus
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import AsyncIterator
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def state(tmp_path: Path) -> AsyncIterator[ReplState]:
|
||||
memory = await MemoryStore.open(DatabaseConfig())
|
||||
provider = OpenAIProvider(access_key_or_token="sk-test")
|
||||
config = ConfigStore(path=tmp_path / "plyngent.toml", document=tomlkit.document())
|
||||
config.providers = {"local": provider}
|
||||
st = ReplState(
|
||||
config=config,
|
||||
memory=memory,
|
||||
workspace=tmp_path,
|
||||
provider_name="local",
|
||||
provider=provider,
|
||||
model="gpt-test",
|
||||
tools_enabled=False,
|
||||
)
|
||||
# ReplState builds a real client; slash plugin tests only need config + agent.
|
||||
await st.new_session("t")
|
||||
yield st
|
||||
await memory.close()
|
||||
|
||||
|
||||
def _fake_statuses(*, enable: list[str], disable: list[str]) -> list[PluginStatus]:
|
||||
del enable, disable
|
||||
return [
|
||||
PluginStatus(
|
||||
plugin=DiscoveredPlugin(id="acme", value="acme_pkg:load", package="acme-pkg", version="1.0"),
|
||||
enabled=True,
|
||||
disabled=False,
|
||||
),
|
||||
PluginStatus(
|
||||
plugin=DiscoveredPlugin(id="other", value="other:load", package=None, version=None),
|
||||
enabled=False,
|
||||
disabled=True,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def test_plugins_list_cmd(tmp_path: Path) -> None:
|
||||
config = tmp_path / "plyngent.toml"
|
||||
_ = config.write_text(
|
||||
"""
|
||||
[plugins]
|
||||
enable = ["acme"]
|
||||
disable = ["other"]
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
runner = CliRunner()
|
||||
with patch("plyngent.tools.plugins.list_plugin_statuses", side_effect=_fake_statuses):
|
||||
result = runner.invoke(main, ["plugins", "list", "--config", str(config)])
|
||||
assert result.exit_code == 0
|
||||
assert "acme" in result.output
|
||||
assert "enabled" in result.output
|
||||
assert "other" in result.output
|
||||
assert "disabled" in result.output
|
||||
|
||||
|
||||
def test_plugins_enable_disable_write(tmp_path: Path) -> None:
|
||||
config = tmp_path / "plyngent.toml"
|
||||
_ = config.write_text("", encoding="utf-8")
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(main, ["plugins", "enable", "acme", "--config", str(config)])
|
||||
assert result.exit_code == 0
|
||||
text = config.read_text(encoding="utf-8")
|
||||
assert "acme" in text
|
||||
result = runner.invoke(main, ["plugins", "disable", "acme", "--config", str(config)])
|
||||
assert result.exit_code == 0
|
||||
text = config.read_text(encoding="utf-8")
|
||||
assert "disable" in text
|
||||
|
||||
|
||||
async def test_slash_plugins_enable_reload(state: ReplState) -> None:
|
||||
with patch("plyngent.tools.plugins.list_plugin_statuses", return_value=[]):
|
||||
assert await handle_slash(state, "/plugins list") is True
|
||||
assert await handle_slash(state, "/plugins enable acme") is True
|
||||
assert "acme" in state.config.plugins_config.enable
|
||||
assert await handle_slash(state, "/plugins disable acme") is True
|
||||
assert "acme" in state.config.plugins_config.disable
|
||||
assert await handle_slash(state, "/plugins undeny acme") is True
|
||||
assert "acme" not in state.config.plugins_config.disable
|
||||
assert await handle_slash(state, "/plugins reload") is True
|
||||
Reference in New Issue
Block a user