Skip to content

teff.tool.registry

teff.tool.registry

Tool registry and decorator.

Classes:

Name Description
ToolRegistry

Registry mapping tool names to tool classes.

Functions:

Name Description
tool

Decorator that registers a function as a tool.

ToolRegistry

Registry mapping tool names to tool classes.

Methods:

Name Description
create

Instantiate a tool by name.

list

Return all registered tool names.

register

Register a tool class.

Source code in teff/tool/registry.py
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class ToolRegistry:
    """Registry mapping tool names to tool classes."""

    def __init__(self) -> None:
        self._tools: dict[str, type[Tool]] = {}

    def register(self, tool_cls: type[Tool]) -> None:
        """Register a tool class.

        Raises:
            ValueError: If the class has no non-empty *name* attribute.
        """
        if not hasattr(tool_cls, "name") or not tool_cls.name:
            raise ValueError(
                f"Tool class {tool_cls.__name__} must have a non-empty 'name' attribute"
            )
        self._tools[tool_cls.name] = tool_cls

    def create(self, name: str, config: dict | None = None) -> Tool:
        """Instantiate a tool by name.

        If *config* is provided, it is passed to the tool's constructor as a
        dict when the constructor accepts one (a leading ``config``
        parameter); otherwise the config keys are passed as keyword
        arguments, and if the constructor rejects them the values are
        assigned as attributes on an argument-less instance.

        Raises:
            KeyError: If the name is not registered.
        """
        if name not in self._tools:
            msg = f"unknown tool: {name}"
            raise KeyError(msg)
        cls = self._tools[name]
        if config is None:
            return cls()
        if _accepts_config_dict(cls):
            return cls(config)  # type: ignore[call-arg]
        try:
            return cls(**config)
        except TypeError:
            tool = cls()
            for k, v in config.items():
                setattr(tool, k, v)
            return tool

    def list(self) -> list[str]:
        """Return all registered tool names."""
        return list(self._tools.keys())

create

create(name, config=None)

Instantiate a tool by name.

If config is provided, it is passed to the tool's constructor as a dict when the constructor accepts one (a leading config parameter); otherwise the config keys are passed as keyword arguments, and if the constructor rejects them the values are assigned as attributes on an argument-less instance.

Raises:

Type Description
KeyError

If the name is not registered.

Source code in teff/tool/registry.py
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def create(self, name: str, config: dict | None = None) -> Tool:
    """Instantiate a tool by name.

    If *config* is provided, it is passed to the tool's constructor as a
    dict when the constructor accepts one (a leading ``config``
    parameter); otherwise the config keys are passed as keyword
    arguments, and if the constructor rejects them the values are
    assigned as attributes on an argument-less instance.

    Raises:
        KeyError: If the name is not registered.
    """
    if name not in self._tools:
        msg = f"unknown tool: {name}"
        raise KeyError(msg)
    cls = self._tools[name]
    if config is None:
        return cls()
    if _accepts_config_dict(cls):
        return cls(config)  # type: ignore[call-arg]
    try:
        return cls(**config)
    except TypeError:
        tool = cls()
        for k, v in config.items():
            setattr(tool, k, v)
        return tool

list

list()

Return all registered tool names.

Source code in teff/tool/registry.py
69
70
71
def list(self) -> list[str]:
    """Return all registered tool names."""
    return list(self._tools.keys())

register

register(tool_cls)

Register a tool class.

Raises:

Type Description
ValueError

If the class has no non-empty name attribute.

Source code in teff/tool/registry.py
29
30
31
32
33
34
35
36
37
38
39
def register(self, tool_cls: type[Tool]) -> None:
    """Register a tool class.

    Raises:
        ValueError: If the class has no non-empty *name* attribute.
    """
    if not hasattr(tool_cls, "name") or not tool_cls.name:
        raise ValueError(
            f"Tool class {tool_cls.__name__} must have a non-empty 'name' attribute"
        )
    self._tools[tool_cls.name] = tool_cls

tool

tool(tool_name, description=None)

Decorator that registers a function as a tool.

The decorated function can be sync or async. An async function gets both run (with asyncio.run) and arun; a sync function gets only run.

Parameters:

Name Type Description Default
tool_name str

Unique tool name.

required
description str | None

Optional description (falls back to docstring).

None
Source code in teff/tool/registry.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
def tool(tool_name: str, description: str | None = None):
    """Decorator that registers a function as a tool.

    The decorated function can be sync or async.  An async function
    gets both *run* (with ``asyncio.run``) and *arun*; a sync function
    gets only *run*.

    Args:
        tool_name: Unique tool name.
        description: Optional description (falls back to docstring).
    """

    def decorator(fn):
        tool_desc = description or (fn.__doc__ or "").strip() or ""
        is_async = inspect.iscoroutinefunction(fn)

        if is_async:

            class AsyncTool(Tool):
                name = tool_name
                description = tool_desc

                async def arun(self, **kwargs):
                    return await fn(**kwargs)

                def run(self, **kwargs):
                    import asyncio

                    return asyncio.run(fn(**kwargs))

            tool_cls = AsyncTool
        else:

            class SyncTool(Tool):
                name = tool_name
                description = tool_desc

                def run(self, **kwargs):
                    return fn(**kwargs)

            tool_cls = SyncTool

        tool_cls.__name__ = fn.__name__
        tool_cls.__qualname__ = fn.__qualname__
        default_tool_registry.register(tool_cls)
        return fn

    return decorator