SyntheticMDProductions's picture
Some of Adams structure
e0265b9 verified
Raw
History Blame Contribute Delete
6.08 kB
from __future__ import annotations
import json
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any
class RegistryError(RuntimeError):
pass
@dataclass(frozen=True, slots=True)
class ToolSpec:
id: str
name: str
description: str
category: str
entry_function: str
arguments: tuple[str, ...] = ()
required_arguments: tuple[str, ...] = ()
capabilities: tuple[str, ...] = ()
model_trainers: tuple[str, ...] = ()
generation_options: dict[str, Any] = field(default_factory=dict)
requires_confirmation: bool = False
enabled: bool = True
demo: bool = False
backend: dict[str, Any] = field(default_factory=dict)
@classmethod
def from_dict(cls, data: dict[str, Any]) -> "ToolSpec":
required = {"id", "name", "description", "category", "backend"}
missing = required - data.keys()
if missing:
raise RegistryError(f"Tool entry is missing: {', '.join(sorted(missing))}")
return cls(
id=str(data["id"]),
name=str(data["name"]),
description=str(data["description"]),
category=str(data["category"]),
entry_function=str(data.get("entry_function", "")),
arguments=tuple(str(item) for item in data.get("arguments", [])),
required_arguments=tuple(
str(item) for item in data.get("required_arguments", [])
),
capabilities=tuple(str(item) for item in data.get("capabilities", [])),
model_trainers=tuple(
str(item) for item in data.get("model_trainers", [])
),
generation_options=dict(data.get("generation_options", {})),
requires_confirmation=bool(data.get("requires_confirmation", False)),
enabled=bool(data.get("enabled", True)),
demo=bool(data.get("demo", False)),
backend=dict(data["backend"]),
)
class ToolRegistry:
def __init__(self, root: Path) -> None:
self.root = root.resolve()
self.path = self.root / "config" / "tools.json"
self._tools: dict[str, ToolSpec] = {}
self.load()
def load(self) -> None:
try:
payload = json.loads(self.path.read_text(encoding="utf-8"))
except FileNotFoundError as exc:
raise RegistryError(f"Tool registry not found: {self.path}") from exc
except json.JSONDecodeError as exc:
raise RegistryError(f"Tool registry is invalid JSON: {exc}") from exc
entries = payload.get("tools")
if not isinstance(entries, list):
raise RegistryError("Tool registry must contain a 'tools' list.")
loaded: dict[str, ToolSpec] = {}
for entry in entries:
spec = ToolSpec.from_dict(entry)
if spec.id in loaded:
raise RegistryError(f"Duplicate tool id: {spec.id}")
loaded[spec.id] = spec
external_path = self.root / "config" / "external_tools.json"
try:
external_payload = json.loads(external_path.read_text(encoding="utf-8"))
external_entries = external_payload.get("tools", [])
except FileNotFoundError:
external_entries = []
except json.JSONDecodeError as exc:
raise RegistryError(f"External tool registry is invalid JSON: {exc}") from exc
if not isinstance(external_entries, list):
raise RegistryError("External tool registry must contain a 'tools' list.")
for entry in external_entries:
if not isinstance(entry, dict):
raise RegistryError("External tool entry must be an object.")
safe_entry = dict(entry)
tool_id = str(safe_entry.get("id", ""))
backend = dict(safe_entry.get("backend", {}))
path = Path(str(backend.get("path", ""))).expanduser()
root = Path(str(backend.get("root", ""))).expanduser()
if not tool_id.startswith("external_"):
raise RegistryError("External tool ids must start with 'external_'.")
if tool_id in loaded:
raise RegistryError(f"External tool cannot replace registered tool: {tool_id}")
if backend.get("type") != "script" or not path.is_absolute() or not root.is_absolute():
raise RegistryError(f"External tool {tool_id} has an invalid script backend.")
try:
path.resolve().relative_to(root.resolve())
except ValueError as exc:
raise RegistryError(f"External tool {tool_id} script is outside its folder.") from exc
safe_entry["requires_confirmation"] = True
safe_entry["demo"] = False
spec = ToolSpec.from_dict(safe_entry)
loaded[spec.id] = spec
self._tools = loaded
def get(self, tool_id: str, *, require_enabled: bool = True) -> ToolSpec:
try:
tool = self._tools[tool_id]
except KeyError as exc:
raise RegistryError(f"Unregistered tool: {tool_id}") from exc
if require_enabled and not tool.enabled:
raise RegistryError(f"Tool is not configured: {tool.name}")
return tool
def all(self) -> list[ToolSpec]:
return list(self._tools.values())
def enabled(self) -> list[ToolSpec]:
return [tool for tool in self._tools.values() if tool.enabled]
def safe_llm_catalog(self) -> list[dict[str, Any]]:
return [
{
"id": tool.id,
"name": tool.name,
"description": tool.description,
"arguments": list(tool.arguments),
"required_arguments": list(tool.required_arguments),
"capabilities": list(tool.capabilities),
"model_trainers": list(tool.model_trainers),
"generation_options": dict(tool.generation_options),
"requires_confirmation": tool.requires_confirmation,
}
for tool in self.enabled()
]