Source code for pipecat.workers.llm.tool_decorator

#
# Copyright (c) 2026, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#

"""Decorator for marking methods as LLM tools."""

import warnings

from pipecat.adapters.schemas.direct_function import tool_options


[docs] def tool(fn=None, *, cancel_on_interruption=True, timeout_secs=None, timeout=None): """Mark a method as a tool. On ``LLMWorker`` subclasses, decorated methods are automatically registered with the LLM via ``register_direct_function`` and included in ``build_tools()``. This is the worker-flavored variant of ``@tool_options``: it attaches the same ``cancel_on_interruption`` / ``timeout_secs`` call options and additionally marks the method (with ``_pipecat_is_llm_tool``) so the worker collects it from the MRO. Can be used with or without arguments:: @tool async def my_tool(self, params, arg: str): ... @tool(cancel_on_interruption=False, timeout_secs=60) async def my_tool(self, params, arg: str): ... Args: fn: The function to decorate (when used without arguments). cancel_on_interruption: Whether to cancel this tool call when an interruption occurs. Defaults to True. Only applies to ``LLMWorker`` tools. timeout_secs: Optional timeout in seconds for this tool call. Defaults to None (uses the LLM service default). Only applies to ``LLMWorker`` tools. timeout: Deprecated alias for ``timeout_secs``. .. deprecated:: 1.4.0 Use ``timeout_secs`` instead. Will be removed in 2.0.0. """ if timeout is not None: with warnings.catch_warnings(): warnings.simplefilter("always") warnings.warn( "The `timeout` argument to `@tool` is deprecated since 1.4.0, " "use `timeout_secs` instead.", DeprecationWarning, stacklevel=2, ) # An explicit timeout_secs wins over the deprecated alias. if timeout_secs is None: timeout_secs = timeout def decorator(fn): fn = tool_options(cancel_on_interruption=cancel_on_interruption, timeout_secs=timeout_secs)( fn ) fn._pipecat_is_llm_tool = True return fn if fn is not None: return decorator(fn) return decorator
def _collect_tools(obj) -> list: """Collect all ``@tool`` decorated bound methods from an object. Walks the MRO so that overridden methods in subclasses take precedence over base-class definitions. """ seen: set[str] = set() tools = [] for cls in type(obj).__mro__: for name, val in cls.__dict__.items(): if name in seen: continue seen.add(name) if callable(val) and getattr(val, "_pipecat_is_llm_tool", False): tools.append(getattr(obj, name)) return tools