Skip to content

Declarative

declarative

Versioned, frontend-independent declarative tool contracts.

DeclarativeTool

Common AXMTool adapter, unavailable without an explicit host binding.

Source code in packages/axm/src/axm/tools/declarative.py
Python
class DeclarativeTool:
    """Common AXMTool adapter, unavailable without an explicit host binding."""

    expose_directly = True
    tags = frozenset({"ui", "declarative"})

    def __init__(
        self,
        definition: DeclarativeToolDefinition,
        invoke: Callable[[str, dict[str, object]], ToolResult] | None = None,
    ) -> None:
        self.definition = definition
        self._invoke = invoke
        self.__doc__ = definition.description

    @property
    def name(self) -> str:
        """Canonical name shared by CLI, nodes and MCP."""
        return self.definition.name

    def execute(self, **kwargs: object) -> ToolResult:
        """Validate and invoke the host binding, never an ambient view."""
        try:
            self.definition.validate_input(kwargs)
            if self._invoke is None:
                return ToolResult(
                    success=False,
                    data={"status": "unavailable"},
                    error="UI tool unavailable: no host view binding",
                )
            return self.definition.validate_result(self._invoke(self.name, kwargs))
        except (ValidationError, ValueError, TypeError) as exc:
            return ToolResult(success=False, error=f"invalid UI tool contract: {exc}")
name property

Canonical name shared by CLI, nodes and MCP.

execute(**kwargs)

Validate and invoke the host binding, never an ambient view.

Source code in packages/axm/src/axm/tools/declarative.py
Python
def execute(self, **kwargs: object) -> ToolResult:
    """Validate and invoke the host binding, never an ambient view."""
    try:
        self.definition.validate_input(kwargs)
        if self._invoke is None:
            return ToolResult(
                success=False,
                data={"status": "unavailable"},
                error="UI tool unavailable: no host view binding",
            )
        return self.definition.validate_result(self._invoke(self.name, kwargs))
    except (ValidationError, ValueError, TypeError) as exc:
        return ToolResult(success=False, error=f"invalid UI tool contract: {exc}")

DeclarativeToolDefinition dataclass

Immutable tool metadata; schemas are detached on every access.

Source code in packages/axm/src/axm/tools/declarative.py
Python
@dataclass(frozen=True, init=False)
class DeclarativeToolDefinition:
    """Immutable tool metadata; schemas are detached on every access."""

    name: str
    description: str
    handler: str
    execution: str
    _input_json: str
    _output_json: str

    def __init__(
        self,
        name: str,
        description: str,
        input_schema: Mapping[str, object],
        output_schema: Mapping[str, object],
        handler: str,
    ) -> None:
        if not _NAME.fullmatch(name) or name in _RESERVED:
            raise ValueError(f"invalid or reserved declarative tool name: {name}")
        if not description.strip() or handler != name:
            raise ValueError("description is required and handler must equal tool name")
        for key, value in (
            ("name", name),
            ("description", description),
            ("handler", handler),
            ("execution", "ui"),
            ("_input_json", _schema_json(input_schema)),
            ("_output_json", _schema_json(output_schema)),
        ):
            object.__setattr__(self, key, value)

    @property
    def input_schema(self) -> dict[str, object]:
        """Detached JSON Schema for functional arguments, without routing fields."""
        return cast(dict[str, object], json.loads(self._input_json))

    @property
    def output_schema(self) -> dict[str, object]:
        """Detached JSON Schema for successful ToolResult.data."""
        return cast(dict[str, object], json.loads(self._output_json))

    def validate_input(self, arguments: Mapping[str, object]) -> None:
        """Reject malformed/non-JSON arguments before contacting any view."""
        detached = json.loads(json.dumps(dict(arguments), allow_nan=False))
        Draft202012Validator(self.input_schema).validate(detached)

    def validate_result(self, result: ToolResult) -> ToolResult:
        """Validate successful data; failures retain their structural signal."""
        if not isinstance(result.success, bool):
            raise ValueError("malformed ToolResult: success must be a boolean")
        if result.success:
            detached = json.loads(json.dumps(result.data, allow_nan=False))
            Draft202012Validator(self.output_schema).validate(detached)
        return result
input_schema property

Detached JSON Schema for functional arguments, without routing fields.

output_schema property

Detached JSON Schema for successful ToolResult.data.

validate_input(arguments)

Reject malformed/non-JSON arguments before contacting any view.

Source code in packages/axm/src/axm/tools/declarative.py
Python
def validate_input(self, arguments: Mapping[str, object]) -> None:
    """Reject malformed/non-JSON arguments before contacting any view."""
    detached = json.loads(json.dumps(dict(arguments), allow_nan=False))
    Draft202012Validator(self.input_schema).validate(detached)
validate_result(result)

Validate successful data; failures retain their structural signal.

Source code in packages/axm/src/axm/tools/declarative.py
Python
def validate_result(self, result: ToolResult) -> ToolResult:
    """Validate successful data; failures retain their structural signal."""
    if not isinstance(result.success, bool):
        raise ValueError("malformed ToolResult: success must be a boolean")
    if result.success:
        detached = json.loads(json.dumps(result.data, allow_nan=False))
        Draft202012Validator(self.output_schema).validate(detached)
    return result

DeclarativeToolManifest dataclass

One addon bundle's closed tool declarations.

Source code in packages/axm/src/axm/tools/declarative.py
Python
@dataclass(frozen=True)
class DeclarativeToolManifest:
    """One addon bundle's closed tool declarations."""

    schema_version: int
    addon_id: str
    bundle_sha256: str
    tools: tuple[DeclarativeToolDefinition, ...]

    def __post_init__(self) -> None:
        _validate_manifest(self)

load_declarative_manifest(raw)

Validate a JSON manifest from a trusted installed package.

Extra fields, remote schema references, versions and collisions are refused. This validates metadata only: the host verifies the mounted bundle.

Source code in packages/axm/src/axm/tools/declarative.py
Python
def load_declarative_manifest(raw: Mapping[str, object]) -> DeclarativeToolManifest:
    """Validate a JSON manifest from a trusted installed package.

    Extra fields, remote schema references, versions and collisions are refused.
    This validates metadata only: the host verifies the mounted bundle.
    """
    data = _object(dict(raw), {"schema_version", "addon_id", "bundle_sha256", "tools"})
    if not isinstance(data["tools"], list):
        raise ValueError("manifest tools must be a list")
    version = data["schema_version"]
    if type(version) is not int:
        raise ValueError("schema_version must be an integer")
    return DeclarativeToolManifest(
        schema_version=version,
        addon_id=_string(data["addon_id"]),
        bundle_sha256=_string(data["bundle_sha256"]),
        tools=tuple(_definition(tool) for tool in data["tools"]),
    )

tool_scope_sha256(names)

Fingerprint a positive tool list; no provider-specific spelling.

Source code in packages/axm/src/axm/tools/declarative.py
Python
def tool_scope_sha256(names: frozenset[str]) -> str:
    """Fingerprint a positive tool list; no provider-specific spelling."""
    wire = json.dumps(sorted(names), ensure_ascii=False, separators=(",", ":"))
    return hashlib.sha256(wire.encode()).hexdigest()

validate_declarative_schema(schema)

Return a detached object schema validated offline for tools or snapshots.

Only the supported 2020-12 dialect and local references are accepted. Remote IDs/vocabularies and legacy recursive dialect keywords cannot weaken it.

Source code in packages/axm/src/axm/tools/declarative.py
Python
def validate_declarative_schema(schema: Mapping[str, object]) -> dict[str, object]:
    """Return a detached object schema validated offline for tools or snapshots.

    Only the supported 2020-12 dialect and local references are accepted. Remote
    IDs/vocabularies and legacy recursive dialect keywords cannot weaken it.
    """
    encoded = json.dumps(dict(schema), allow_nan=False)
    detached = json.loads(encoded)
    if detached.get("type") != "object":
        raise ValueError("tool schema root must be an object")
    _local_references(detached)
    try:
        Draft202012Validator.check_schema(detached)
    except SchemaError as exc:
        raise ValueError(f"invalid tool schema: {exc.message}") from exc
    return cast(dict[str, object], detached)