Files
wehub-resource-sync 4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

84 lines
2.7 KiB
Python

"""Validated registry/runtime metadata for ``BaseTool`` subclasses.
``BaseToolRegistryMetadata`` covers fields the tool registry uses to decide
where a tool is exposed and how it executes, separate from the planner/evidence
contract in ``ToolMetadata``.
"""
from __future__ import annotations
from collections.abc import Iterable
from typing import cast, get_args
from pydantic import Field, field_validator
from config.strict_config import StrictConfigModel
from core.domain.types.tools import ToolSurface
_DEFAULT_SURFACES: tuple[ToolSurface, ...] = ("investigation",)
_VALID_SURFACES = set(get_args(ToolSurface))
def normalize_surfaces(surfaces: Iterable[str] | None) -> tuple[ToolSurface, ...]:
"""Normalize and validate tool surface names."""
if surfaces is None:
return _DEFAULT_SURFACES
normalized: list[ToolSurface] = []
for raw_surface in surfaces:
surface = str(raw_surface).strip().lower()
if surface not in _VALID_SURFACES:
valid = ", ".join(sorted(_VALID_SURFACES))
raise ValueError(f"Unsupported tool surface '{surface}'. Expected one of: {valid}.")
typed_surface = cast(ToolSurface, surface)
if typed_surface not in normalized:
normalized.append(typed_surface)
return tuple(normalized) or _DEFAULT_SURFACES
def normalize_tags(tags: Iterable[str] | None) -> tuple[str, ...]:
"""Normalize optional planner tags into a deduplicated tuple."""
if tags is None:
return ()
normalized: list[str] = []
for raw_tag in tags:
tag = str(raw_tag).strip()
if tag and tag not in normalized:
normalized.append(tag)
return tuple(normalized)
class BaseToolRegistryMetadata(StrictConfigModel):
"""Registry/runtime metadata declared on ``BaseTool`` subclasses."""
surfaces: tuple[ToolSurface, ...] = Field(default=_DEFAULT_SURFACES)
tags: tuple[str, ...] = ()
parallel_safe: bool = True
@field_validator("surfaces", mode="before")
@classmethod
def _coerce_surfaces(cls, value: object) -> tuple[ToolSurface, ...]:
if value is None:
return normalize_surfaces(None)
if isinstance(value, str):
return normalize_surfaces((value,))
return normalize_surfaces(cast(Iterable[str], value))
@field_validator("tags", mode="before")
@classmethod
def _coerce_tags(cls, value: object) -> tuple[str, ...]:
if value is None:
return ()
if isinstance(value, str):
return normalize_tags((value,))
return normalize_tags(cast(Iterable[str], value))
__all__ = [
"BaseToolRegistryMetadata",
"normalize_surfaces",
"normalize_tags",
]