55 lines
3.0 KiB
Python
55 lines
3.0 KiB
Python
"""Validation and entry shape for ``PluginContext.register_auxiliary_task``."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any, Dict, Optional
|
|
|
|
logger = logging.getLogger("hermes_cli.plugins")
|
|
|
|
|
|
def build_auxiliary_task_entry(
|
|
me: str, owner_id: str, key: str, *, display_name: str, description: str,
|
|
defaults: Optional[dict[str, Any]], inherit_from: Optional[str], registered: dict[str, dict[str, Any]],
|
|
) -> dict[str, Any]:
|
|
"""Registry entry for a plugin auxiliary task, or ``ValueError`` for a bad key.
|
|
|
|
``me`` is the manifest name (for messages); ``owner_id`` is the canonical id ``ctx.llm`` is
|
|
bound to, so agent/plugin_llm.py can match it. ``registered`` is the manager's current
|
|
``_aux_tasks`` (re-registration by the same owner is allowed).
|
|
"""
|
|
if not key or not isinstance(key, str):
|
|
raise ValueError(f"Plugin '{me}' tried to register auxiliary task with invalid key {key!r}")
|
|
if not all(c.isalnum() or c == "_" for c in key):
|
|
raise ValueError(f"Plugin '{me}' auxiliary task key {key!r} "
|
|
f"must contain only alphanumeric characters and underscores")
|
|
from hermes_cli.main_provider_setup import _AUX_TASKS as _BUILTIN_AUX_TASKS
|
|
builtin_aux_keys = {k for k, _name, _desc in _BUILTIN_AUX_TASKS}
|
|
if key in builtin_aux_keys:
|
|
raise ValueError(f"Plugin '{me}' cannot register auxiliary task {key!r} — that key is reserved "
|
|
f"for a built-in task. Pick a plugin-namespaced key (e.g. '{me}_{key}').")
|
|
existing = registered.get(key)
|
|
if existing is not None and existing.get("plugin") != owner_id:
|
|
raise ValueError(f"Plugin '{me}' cannot register auxiliary task {key!r} — already registered "
|
|
f"by plugin '{existing.get('plugin')}'")
|
|
# A bad base degrades to "no inheritance" rather than failing the whole plugin load; a
|
|
# self-reference would otherwise only surface at read time, as a cycle.
|
|
if inherit_from is not None and (
|
|
not isinstance(inherit_from, str) or inherit_from == key
|
|
or (inherit_from not in builtin_aux_keys and inherit_from not in registered)):
|
|
logger.warning("Plugin '%s' auxiliary task %r: ignoring inherit_from=%r — not a built-in "
|
|
"auxiliary task or one already registered by a plugin", me, key, inherit_from)
|
|
inherit_from = None
|
|
# Plugin owns the schema; routing fields are guaranteed present so consumers don't crash.
|
|
# With inheritance the base supplies the shape, so only the plugin's own overrides go here.
|
|
task_defaults = (dict(defaults or {}) if inherit_from else
|
|
{"provider": "auto", "model": "", "base_url": "", "api_key": "", "timeout": 60,
|
|
"extra_body": {}, **(defaults or {})})
|
|
entry = {
|
|
"key": key, "display_name": display_name, "description": description,
|
|
"defaults": task_defaults,
|
|
"inherit_from": inherit_from,
|
|
"plugin": owner_id, "plugin_key": owner_id,
|
|
}
|
|
return entry
|