ai-lsc/src/ai_lsc/registry/loader.py

87 lines
2.6 KiB
Python
Executable File

"""Registry loader -- discovers and merges per-layer registry modules.
On startup the loader scans ``ai_lsc.registry.layers`` for every
``.py`` file that exports a ``TOOLS`` dict, and merges them into a
single unified registry dict.
This replaces the monolithic ``DEFAULT_REGISTRY`` dict with a
zero-merge-conflict modular approach: each layer lives in its own
file and is independently editable.
"""
from __future__ import annotations
import importlib
import pkgutil
from typing import Any
def load_merged_registry() -> dict[str, dict[str, Any]]:
"""Discover and merge all layer TOOLS dicts into one registry dict.
Each layer module should export ``TOOLS: dict[str, dict]`` where
keys are tool IDs and values are the full metadata dicts.
Returns the merged ``{tool_id: metadata}`` dictionary, with later
files overriding earlier ones on key collision (which should never
happen if layers are well-separated).
"""
merged: dict[str, dict[str, Any]] = {}
# Import the layers package
try:
layers_pkg = importlib.import_module("ai_lsc.registry.layers")
except ImportError:
return merged
for importer, modname, ispkg in pkgutil.iter_modules(
layers_pkg.__path__, prefix=layers_pkg.__name__ + "."
):
if ispkg:
continue
try:
mod = importlib.import_module(modname)
except ImportError:
continue
tools = getattr(mod, "TOOLS", None)
if isinstance(tools, dict):
# Dict format: {tool_id: metadata, ...}
_merge_tools_dict(merged, tools)
elif isinstance(tools, list):
# Legacy list format: [{...}, ...]
_merge_tools_list(merged, tools)
return merged
def _merge_tools_dict(
target: dict[str, dict[str, Any]],
tools: dict[str, dict[str, Any]],
) -> None:
"""Merge a ``TOOLS`` dict into the target registry dict."""
for tool_id, entry in tools.items():
if not isinstance(entry, dict):
continue
# Inject tool_id into entry if missing
if "tool_id" not in entry:
entry = {**entry, "tool_id": tool_id}
target[tool_id] = entry
def _merge_tools_list(
target: dict[str, dict[str, Any]],
tools: list[dict[str, Any]],
) -> None:
"""Merge a legacy ``TOOLS`` list into the target registry dict."""
for entry in tools:
if not isinstance(entry, dict):
continue
tool_id = entry.get("tool_id")
if tool_id is None:
name = entry.get("name", "")
tool_id = name.lower().replace(" ", "_").replace("/", "_")
entry["tool_id"] = tool_id
target[tool_id] = entry