perf(plugins): cache tool index in PluginRegistry for O(1) find_tool
load_all() now builds a _tools: dict[str, Tool] index at startup. get_all_tools() returns list(_tools.values()) and find_tool() is a direct dict.get() instead of rebuilding the full tool list from every plugin on every tool call during a session. Updated test helper to populate _tools alongside _plugins to match the actual load_all() behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ class PluginRegistry:
|
|||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self._plugins: dict[str, PyraPlugin] = {}
|
self._plugins: dict[str, PyraPlugin] = {}
|
||||||
|
self._tools: dict[str, Tool] = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def instance(cls) -> PluginRegistry:
|
def instance(cls) -> PluginRegistry:
|
||||||
@@ -28,11 +29,14 @@ class PluginRegistry:
|
|||||||
def load_all(self, plugins_dir: Path, enabled_names: list[str]) -> None:
|
def load_all(self, plugins_dir: Path, enabled_names: list[str]) -> None:
|
||||||
all_plugins = load_plugins(plugins_dir)
|
all_plugins = load_plugins(plugins_dir)
|
||||||
self._plugins = {}
|
self._plugins = {}
|
||||||
|
self._tools = {}
|
||||||
for plugin in all_plugins:
|
for plugin in all_plugins:
|
||||||
if plugin.name in enabled_names:
|
if plugin.name in enabled_names:
|
||||||
try:
|
try:
|
||||||
plugin.on_load(get_key)
|
plugin.on_load(get_key)
|
||||||
self._plugins[plugin.name] = plugin
|
self._plugins[plugin.name] = plugin
|
||||||
|
for tool in plugin.tools():
|
||||||
|
self._tools[tool.name] = tool
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
_log_error(plugin.name, exc)
|
_log_error(plugin.name, exc)
|
||||||
|
|
||||||
@@ -40,13 +44,7 @@ class PluginRegistry:
|
|||||||
return list(self._plugins.values())
|
return list(self._plugins.values())
|
||||||
|
|
||||||
def get_all_tools(self) -> list[Tool]:
|
def get_all_tools(self) -> list[Tool]:
|
||||||
tools: list[Tool] = []
|
return list(self._tools.values())
|
||||||
for plugin in self._plugins.values():
|
|
||||||
try:
|
|
||||||
tools.extend(plugin.tools())
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return tools
|
|
||||||
|
|
||||||
def get_slash_commands(self) -> dict[str, Callable[[], None]]:
|
def get_slash_commands(self) -> dict[str, Callable[[], None]]:
|
||||||
cmds: dict[str, Callable[[], None]] = {}
|
cmds: dict[str, Callable[[], None]] = {}
|
||||||
@@ -78,7 +76,4 @@ class PluginRegistry:
|
|||||||
return tasks
|
return tasks
|
||||||
|
|
||||||
def find_tool(self, name: str) -> Tool | None:
|
def find_tool(self, name: str) -> Tool | None:
|
||||||
for tool in self.get_all_tools():
|
return self._tools.get(name)
|
||||||
if tool.name == name:
|
|
||||||
return tool
|
|
||||||
return None
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ def _make_registry_with_tools(*tools: Tool) -> PluginRegistry:
|
|||||||
fake_plugin.system_prompt_addition.return_value = ""
|
fake_plugin.system_prompt_addition.return_value = ""
|
||||||
fake_plugin.daemon_tasks.return_value = []
|
fake_plugin.daemon_tasks.return_value = []
|
||||||
registry._plugins = {"mock_plugin": fake_plugin}
|
registry._plugins = {"mock_plugin": fake_plugin}
|
||||||
|
registry._tools = {tool.name: tool for tool in tools}
|
||||||
return registry
|
return registry
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user