mirror of
https://github.com/msitarzewski/agency-agents.git
synced 2026-10-12 05:35:01 +00:00
105 lines
3.8 KiB
Python
105 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate the generated Hermes router plugin against Hermes' tool contract."""
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import json
|
|
import tempfile
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
BUILDER_PATH = REPO_ROOT / "scripts" / "build-hermes-plugin.py"
|
|
|
|
|
|
def load_module(name: str, path: Path):
|
|
spec = importlib.util.spec_from_file_location(name, path)
|
|
if spec is None or spec.loader is None:
|
|
raise RuntimeError(f"could not load {path}")
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
return module
|
|
|
|
|
|
class RecordingContext:
|
|
def __init__(self) -> None:
|
|
self.tools: dict[str, dict[str, Any]] = {}
|
|
|
|
def register_tool(self, **kwargs: Any) -> None:
|
|
self.tools[kwargs["name"]] = kwargs
|
|
|
|
|
|
def main() -> int:
|
|
builder = load_module("agency_agents_hermes_builder", BUILDER_PATH)
|
|
|
|
with tempfile.TemporaryDirectory() as tmp:
|
|
source = Path(tmp) / "engineering" / "engineering-multiline.md"
|
|
source.parent.mkdir()
|
|
source.write_text(
|
|
"---\n"
|
|
"name: Multiline Specialist\n"
|
|
"description: First part of the description\n"
|
|
" followed by essential context.\n"
|
|
"vibe: First part of the vibe\n"
|
|
" followed by the rest.\n"
|
|
"---\n\n# Multiline Specialist\n",
|
|
encoding="utf-8",
|
|
)
|
|
parsed = builder.parse_agent(source, Path(tmp))
|
|
assert parsed is not None
|
|
assert parsed["description"] == "First part of the description followed by essential context."
|
|
assert parsed["vibe"] == "First part of the vibe followed by the rest."
|
|
quoted_vibe = builder.parse_agent(
|
|
REPO_ROOT / "specialized" / "identity-graph-operator.md", REPO_ROOT
|
|
)
|
|
assert quoted_vibe is not None
|
|
assert quoted_vibe["vibe"].endswith('who is this?"')
|
|
|
|
out_dir = Path(tmp) / "hermes"
|
|
builder.build(REPO_ROOT, out_dir)
|
|
plugin = load_module(
|
|
"agency_agents_router_check",
|
|
out_dir / builder.PLUGIN_NAME / "__init__.py",
|
|
)
|
|
|
|
ctx = RecordingContext()
|
|
plugin.register(ctx)
|
|
|
|
expected_tools = {
|
|
"agency_agents_search",
|
|
"agency_agents_inspect",
|
|
"agency_agents_load",
|
|
"agency_agents_delegate",
|
|
}
|
|
assert set(ctx.tools) == expected_tools
|
|
|
|
for name, registration in ctx.tools.items():
|
|
schema = registration["schema"]
|
|
assert schema["name"] == name, f"{name}: schema name is missing"
|
|
assert schema.get("description"), f"{name}: schema description is missing"
|
|
parameters = schema.get("parameters")
|
|
assert isinstance(parameters, dict), f"{name}: schema.parameters is missing"
|
|
assert parameters.get("type") == "object", f"{name}: parameters must be an object"
|
|
assert isinstance(parameters.get("properties"), dict), f"{name}: properties are missing"
|
|
assert isinstance(parameters.get("required"), list), f"{name}: required must be a list"
|
|
|
|
search = json.loads(
|
|
ctx.tools["agency_agents_search"]["handler"]({"query": "backend architecture"})
|
|
)
|
|
assert search["success"] is True
|
|
assert search["results"], "search should return at least one specialist"
|
|
|
|
slug = search["results"][0]["slug"]
|
|
inspected = json.loads(
|
|
ctx.tools["agency_agents_inspect"]["handler"]({"slug": slug})
|
|
)
|
|
assert inspected["success"] is True
|
|
assert inspected["agent"]["slug"] == slug
|
|
|
|
print("PASSED: generated Hermes plugin schemas and routing behavior are valid.")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|