mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-08-20 05:45:20 +00:00
feat: add caller context to plugin config hooks
This commit is contained in:
parent
6257f2cb3b
commit
1121758a6f
3 changed files with 77 additions and 3 deletions
|
|
@ -45,6 +45,7 @@ _META_TARGET_RE = re.compile(
|
|||
|
||||
|
||||
type ToggleState = Literal["enabled", "disabled"]
|
||||
type CallerContext = Literal["ui", "agent", "api"]
|
||||
|
||||
|
||||
class PluginAssetFile(TypedDict):
|
||||
|
|
@ -590,6 +591,7 @@ def get_plugin_config(
|
|||
agent: Agent | None = None,
|
||||
project_name: str | None = None,
|
||||
agent_profile: str | None = None,
|
||||
caller: CallerContext = "api",
|
||||
):
|
||||
|
||||
default_used = False
|
||||
|
|
@ -635,6 +637,7 @@ def get_plugin_config(
|
|||
agent=agent,
|
||||
project_name=project_name,
|
||||
agent_profile=agent_profile,
|
||||
hook_context={"caller": caller},
|
||||
)
|
||||
|
||||
return result
|
||||
|
|
@ -663,7 +666,11 @@ def get_default_plugin_config(plugin_name: str):
|
|||
|
||||
@extension.extensible
|
||||
def save_plugin_config(
|
||||
plugin_name: str, project_name: str, agent_profile: str, settings: dict
|
||||
plugin_name: str,
|
||||
project_name: str,
|
||||
agent_profile: str,
|
||||
settings: dict,
|
||||
caller: CallerContext = "api",
|
||||
):
|
||||
file_path = determine_plugin_asset_path(
|
||||
plugin_name, project_name, agent_profile, CONFIG_FILE_NAME
|
||||
|
|
@ -677,6 +684,7 @@ def save_plugin_config(
|
|||
project_name=project_name,
|
||||
agent_profile=agent_profile,
|
||||
settings=settings,
|
||||
hook_context={"caller": caller},
|
||||
)
|
||||
|
||||
# or do standard load
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@
|
|||
- `determined_toggle_from_paths(default: bool, paths: Iterator[str])`
|
||||
- `get_toggle_state(plugin_name: str) -> ToggleState`
|
||||
- `toggle_plugin(plugin_name: str, enabled: bool, project_name: str=..., agent_profile: str=..., clear_overrides: bool=...)`
|
||||
- `get_plugin_config(plugin_name: str, agent: Agent | None=..., project_name: str | None=..., agent_profile: str | None=...)`
|
||||
- `get_plugin_config(plugin_name: str, agent: Agent | None=..., project_name: str | None=..., agent_profile: str | None=..., caller: CallerContext=...)`
|
||||
- `get_default_plugin_config(plugin_name: str)`
|
||||
- `save_plugin_config(plugin_name: str, project_name: str, agent_profile: str, settings: dict)`
|
||||
- `save_plugin_config(plugin_name: str, project_name: str, agent_profile: str, settings: dict, caller: CallerContext=...)`
|
||||
- `find_plugin_asset(plugin_name: str, *subpaths, project_name=..., agent_profile=...)`
|
||||
- `find_plugin_assets(*subpaths, plugin_name: str=..., project_name: str=..., agent_profile: str=..., only_first: bool=...) -> list[PluginAssetFile]`
|
||||
- `determine_plugin_asset_path(plugin_name: str, project_name: str, agent_profile: str, *subpaths)`
|
||||
|
|
@ -51,6 +51,8 @@
|
|||
- Helper modules own reusable framework APIs and must preserve public callers unless all callers, tests, and docs are updated together.
|
||||
- Plugins marked `always_enabled` remain in runtime discovery regardless of
|
||||
stale global or scoped disable files, and disable attempts are rejected.
|
||||
- Config hooks receive `hook_context={"caller": caller}` with one of `ui`,
|
||||
`agent`, or `api`; this is behavioral context, not an authorization boundary.
|
||||
- Update this file whenever public functions, classes, persistence behavior, path/security assumptions, side effects, or cross-module contracts change.
|
||||
- Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion, WebSocket state, plugin state, settings/state persistence, secret handling.
|
||||
- Imported dependency areas include: `__future__`, `asyncio`, `glob`, `helpers`, `helpers.defer`, `helpers.watchdog`, `json`, `pathlib`, `pydantic`, `re`, `regex`, `time`, `typing`.
|
||||
|
|
|
|||
64
tests/test_plugin_hook_context.py
Normal file
64
tests/test_plugin_hook_context.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||
if str(PROJECT_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(PROJECT_ROOT))
|
||||
|
||||
from helpers import plugins
|
||||
|
||||
|
||||
def _capture_hook_context(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
def call_plugin_hook(plugin_name, hook_name, default=None, **kwargs):
|
||||
captured.update(
|
||||
plugin_name=plugin_name,
|
||||
hook_name=hook_name,
|
||||
hook_context=kwargs["hook_context"],
|
||||
)
|
||||
return default
|
||||
|
||||
monkeypatch.setattr(plugins, "call_plugin_hook", call_plugin_hook)
|
||||
return captured
|
||||
|
||||
|
||||
def test_get_plugin_config_forwards_caller_to_hook(monkeypatch):
|
||||
captured = _capture_hook_context(monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
plugins, "find_plugin_asset", lambda *_args, **_kwargs: {"path": "config.json"}
|
||||
)
|
||||
monkeypatch.setattr(plugins.files, "exists", lambda _path: True)
|
||||
monkeypatch.setattr(plugins.files, "read_file", lambda _path: '{"enabled": true}')
|
||||
|
||||
assert plugins.get_plugin_config.__wrapped__("example", caller="ui") == {
|
||||
"enabled": True
|
||||
}
|
||||
assert captured == {
|
||||
"plugin_name": "example",
|
||||
"hook_name": "get_plugin_config",
|
||||
"hook_context": {"caller": "ui"},
|
||||
}
|
||||
|
||||
|
||||
def test_save_plugin_config_forwards_caller_to_hook(monkeypatch):
|
||||
captured = _capture_hook_context(monkeypatch)
|
||||
saved = []
|
||||
monkeypatch.setattr(
|
||||
plugins, "determine_plugin_asset_path", lambda *_args, **_kwargs: "config.json"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
plugins.files, "write_file", lambda path, content: saved.append((path, content))
|
||||
)
|
||||
|
||||
plugins.save_plugin_config.__wrapped__(
|
||||
"example", "", "", {"enabled": True}, caller="agent"
|
||||
)
|
||||
|
||||
assert captured == {
|
||||
"plugin_name": "example",
|
||||
"hook_name": "save_plugin_config",
|
||||
"hook_context": {"caller": "agent"},
|
||||
}
|
||||
assert saved == [("config.json", '{"enabled": true}')]
|
||||
Loading…
Add table
Add a link
Reference in a new issue