mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 15:37:55 +08:00
core/config: top-level [plugins] enable/disable allowlist
This commit is contained in:
@@ -212,17 +212,15 @@ class ReplState:
|
||||
from plyngent.tools.danger import classify_danger
|
||||
from plyngent.tools.plugins import load_plugin_tools
|
||||
|
||||
agent_cfg = self.config.agent_config
|
||||
plugins_cfg = self.config.plugins_config
|
||||
catalog = register_builtin_tools()
|
||||
# Allowlisted entry points (plugin ids); disable is plugin-id only, not tool names.
|
||||
_ = load_plugin_tools(
|
||||
agent_cfg.tool_plugins,
|
||||
disable=agent_cfg.tool_plugins_disable,
|
||||
plugins_cfg.enable,
|
||||
disable=plugins_cfg.disable,
|
||||
)
|
||||
# Local surface: builtins + allowlisted plugins (import registers into catalog).
|
||||
tools = catalog.select(surface="local")
|
||||
disable = {name.strip() for name in agent_cfg.tool_plugins_disable if name.strip()}
|
||||
if disable:
|
||||
tools = [tool for tool in tools if tool.name not in disable]
|
||||
yolo = self.effective_yolo() != "off"
|
||||
# Always attach soft-confirm path so non-YOLO tools still prompt under YOLO mode.
|
||||
return ToolRegistry(
|
||||
|
||||
@@ -15,6 +15,7 @@ from .models import HttpTimeoutConfig as HttpTimeoutConfig
|
||||
from .models import ModelConfig as ModelConfig
|
||||
from .models import OpenAICompatibleProvider as OpenAICompatibleProvider
|
||||
from .models import OpenAIProvider as OpenAIProvider
|
||||
from .models import PluginsConfig as PluginsConfig
|
||||
from .models import ProviderConfig as ProviderConfig
|
||||
from .models import compose_agent_system_content as compose_agent_system_content
|
||||
from .path import get_default_path as _get_default_path
|
||||
|
||||
@@ -87,12 +87,6 @@ class AgentConfig(Struct, omit_defaults=True):
|
||||
path_denylist: list[str] = field(default_factory=list)
|
||||
max_context_tokens: int = 200_000
|
||||
|
||||
# Third-party tool plugins (entry-point group ``plyngent.tools``).
|
||||
# Default empty = load none. Use ``["*"]`` to load all discovered plugins.
|
||||
tool_plugins: list[str] = field(default_factory=list)
|
||||
# Entry-point names never loaded even when listed / ``*``.
|
||||
tool_plugins_disable: list[str] = field(default_factory=list)
|
||||
|
||||
# How to inject todo stack nags into model context (see agent/todo_nag.py).
|
||||
# developer | user | synthetic_tool | none (legacy "system" → developer)
|
||||
todo_nag_strategy: str = "developer"
|
||||
@@ -103,6 +97,21 @@ class AgentConfig(Struct, omit_defaults=True):
|
||||
compact_seed_text: str = ""
|
||||
|
||||
|
||||
class PluginsConfig(Struct, omit_defaults=True):
|
||||
"""Third-party plugins (not tool-specific config).
|
||||
|
||||
Hosts allowlist plugin **entry-point names** (today: group ``plyngent.tools``;
|
||||
other extension points may reuse the same allowlist later).
|
||||
|
||||
- ``enable`` empty / omitted → load **no** plugins (safe default).
|
||||
- ``enable = ["*"]`` → load every discovered entry point for that group.
|
||||
- ``disable`` always wins over ``enable`` / ``*``.
|
||||
"""
|
||||
|
||||
enable: list[str] = field(default_factory=list)
|
||||
disable: list[str] = field(default_factory=list)
|
||||
|
||||
|
||||
class ModelConfig(Struct, omit_defaults=True):
|
||||
"""Capability flags for a model within a provider."""
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, cast
|
||||
import msgspec
|
||||
import tomlkit
|
||||
|
||||
from .models import AgentConfig, DatabaseConfig, ModelConfig, Provider
|
||||
from .models import AgentConfig, DatabaseConfig, ModelConfig, PluginsConfig, Provider
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Mapping, MutableMapping, Sequence
|
||||
@@ -33,6 +33,14 @@ def _parse_agent(raw: dict[str, object]) -> AgentConfig:
|
||||
return AgentConfig()
|
||||
|
||||
|
||||
def _parse_plugins(raw: dict[str, object]) -> PluginsConfig:
|
||||
"""Parse the ``[plugins]`` section, falling back to defaults."""
|
||||
try:
|
||||
return msgspec.convert(raw, PluginsConfig)
|
||||
except msgspec.ValidationError:
|
||||
return PluginsConfig()
|
||||
|
||||
|
||||
def _parse_providers(
|
||||
document: tomlkit.TOMLDocument,
|
||||
) -> tuple[dict[str, Provider], dict[str, object], dict[str, Provider]]:
|
||||
@@ -100,6 +108,7 @@ class ConfigStore:
|
||||
_document: tomlkit.TOMLDocument
|
||||
_database: DatabaseConfig
|
||||
_agent: AgentConfig
|
||||
_plugins: PluginsConfig
|
||||
_providers: dict[str, Provider]
|
||||
_bad_providers: dict[str, object]
|
||||
_recoverable_providers: dict[str, Provider]
|
||||
@@ -110,6 +119,7 @@ class ConfigStore:
|
||||
raw: dict[str, object] = document.unwrap()
|
||||
self._database = _parse_database(cast("dict[str, object]", raw.get("database", {})))
|
||||
self._agent = _parse_agent(cast("dict[str, object]", raw.get("agent", {})))
|
||||
self._plugins = _parse_plugins(cast("dict[str, object]", raw.get("plugins", {})))
|
||||
self._providers, self._bad_providers, self._recoverable_providers = _parse_providers(document)
|
||||
|
||||
@property
|
||||
@@ -136,6 +146,18 @@ class ConfigStore:
|
||||
"""Typed agent profile (system prompt, tool budgets, etc.)."""
|
||||
return self._agent
|
||||
|
||||
# -- plugins (read-only) --
|
||||
|
||||
@property
|
||||
def plugins(self) -> MappingProxyType[str, object]:
|
||||
"""Read-only mapping view of plugin allowlist configuration."""
|
||||
return MappingProxyType(msgspec.structs.asdict(self._plugins))
|
||||
|
||||
@property
|
||||
def plugins_config(self) -> PluginsConfig:
|
||||
"""Typed plugin allowlist (enable / disable entry-point names)."""
|
||||
return self._plugins
|
||||
|
||||
# -- providers (read/write) --
|
||||
|
||||
@property
|
||||
@@ -269,6 +291,7 @@ class ConfigStore:
|
||||
raw: dict[str, object] = self._document.unwrap()
|
||||
self._database = _parse_database(cast("dict[str, object]", raw.get("database", {})))
|
||||
self._agent = _parse_agent(cast("dict[str, object]", raw.get("agent", {})))
|
||||
self._plugins = _parse_plugins(cast("dict[str, object]", raw.get("plugins", {})))
|
||||
self._providers, self._bad_providers, self._recoverable_providers = _parse_providers(self._document)
|
||||
|
||||
# -- internal sync helpers --
|
||||
@@ -300,6 +323,10 @@ class ConfigStore:
|
||||
"""Sync ``[agent]`` to the document."""
|
||||
self._sync_section("agent", self._agent)
|
||||
|
||||
def _sync_plugins_section(self) -> None:
|
||||
"""Sync ``[plugins]`` to the document."""
|
||||
self._sync_section("plugins", self._plugins)
|
||||
|
||||
def _sync_providers_section(self) -> None:
|
||||
"""Sync ``[providers]`` to the document (ready + recoverable)."""
|
||||
section = self._toml_table("providers")
|
||||
@@ -323,4 +350,5 @@ class ConfigStore:
|
||||
"""Incrementally sync all sections into the document."""
|
||||
self._sync_database_section()
|
||||
self._sync_agent_section()
|
||||
self._sync_plugins_section()
|
||||
self._sync_providers_section()
|
||||
|
||||
Reference in New Issue
Block a user