Module livekit.agents.llm.function_context
Functions
def ai_callable(*,
name: str | None = None,
description: str | _UseDocMarker = <livekit.agents.llm.function_context._UseDocMarker object>,
auto_retry: bool = False) ‑> Callable-
Expand source code
def ai_callable( *, name: str | None = None, description: str | _UseDocMarker = USE_DOCSTRING, auto_retry: bool = False, ) -> Callable: def deco(f): _set_metadata(f, name=name, desc=description, auto_retry=auto_retry) return f return deco
def is_type_supported(t: type) ‑> bool
-
Expand source code
def is_type_supported(t: type) -> bool: if t in (str, int, float, bool): return True if typing.get_origin(t) is list: in_type = typing.get_args(t)[0] return is_type_supported(in_type) is_optional, ty = _is_optional_type(t) if is_optional: return is_type_supported(ty) if issubclass(t, enum.Enum): initial_type = None for e in t: if initial_type is None: initial_type = type(e.value) if type(e.value) is not initial_type: return False return initial_type in (str, int) return False
Classes
class CalledFunction (call_info: FunctionCallInfo,
task: asyncio.Task[Any],
result: Any | None = None,
exception: BaseException | None = None)-
Expand source code
@dataclass class CalledFunction: call_info: FunctionCallInfo task: asyncio.Task[Any] result: Any | None = None exception: BaseException | None = None
CalledFunction(call_info: 'FunctionCallInfo', task: 'asyncio.Task[Any]', result: 'Any | None' = None, exception: 'BaseException | None' = None)
Class variables
var call_info : FunctionCallInfo
var exception : BaseException | None
var result : typing.Any | None
var task : _asyncio.Task[typing.Any]
class FunctionArgInfo (name: str, description: str, type: type, default: Any, choices: tuple | None)
-
Expand source code
@dataclass(frozen=True) class FunctionArgInfo: name: str description: str type: type default: Any choices: tuple | None
FunctionArgInfo(name: 'str', description: 'str', type: 'type', default: 'Any', choices: 'tuple | None')
Class variables
var choices : tuple | None
var default : Any
var description : str
var name : str
var type : type
class FunctionCallInfo (tool_call_id: str,
function_info: FunctionInfo,
raw_arguments: str,
arguments: dict[str, Any])-
Expand source code
@dataclass(frozen=True) class FunctionCallInfo: tool_call_id: str function_info: FunctionInfo raw_arguments: str arguments: dict[str, Any] def execute(self) -> CalledFunction: function_info = self.function_info func = functools.partial(function_info.callable, **self.arguments) if asyncio.iscoroutinefunction(function_info.callable): task = asyncio.create_task(func()) else: task = asyncio.create_task(asyncio.to_thread(func)) called_fnc = CalledFunction(call_info=self, task=task) def _on_done(fut): try: called_fnc.result = fut.result() except BaseException as e: called_fnc.exception = e task.add_done_callback(_on_done) return called_fnc
FunctionCallInfo(tool_call_id: 'str', function_info: 'FunctionInfo', raw_arguments: 'str', arguments: 'dict[str, Any]')
Class variables
var arguments : dict[str, typing.Any]
var function_info : FunctionInfo
var raw_arguments : str
var tool_call_id : str
Methods
def execute(self) ‑> CalledFunction
-
Expand source code
def execute(self) -> CalledFunction: function_info = self.function_info func = functools.partial(function_info.callable, **self.arguments) if asyncio.iscoroutinefunction(function_info.callable): task = asyncio.create_task(func()) else: task = asyncio.create_task(asyncio.to_thread(func)) called_fnc = CalledFunction(call_info=self, task=task) def _on_done(fut): try: called_fnc.result = fut.result() except BaseException as e: called_fnc.exception = e task.add_done_callback(_on_done) return called_fnc
class FunctionContext
-
Expand source code
class FunctionContext: def __init__(self) -> None: self._fncs = dict[str, FunctionInfo]() for _, member in inspect.getmembers(self, predicate=inspect.ismethod): if hasattr(member, METADATA_ATTR): self._register_ai_function(member) def ai_callable( self, *, name: str | None = None, description: str | _UseDocMarker = USE_DOCSTRING, auto_retry: bool = True, ) -> Callable: def deco(f): _set_metadata(f, name=name, desc=description, auto_retry=auto_retry) self._register_ai_function(f) return deco def _register_ai_function(self, fnc: Callable) -> None: if not hasattr(fnc, METADATA_ATTR): logger.warning(f"function {fnc.__name__} does not have ai metadata") return metadata: _AIFncMetadata = getattr(fnc, METADATA_ATTR) fnc_name = metadata.name if fnc_name in self._fncs: raise ValueError(f"duplicate ai_callable name: {fnc_name}") sig = inspect.signature(fnc) # get_type_hints with include_extra=True is needed when using Annotated # using typing.get_args with param.Annotated is returning an empty tuple for some reason type_hints = typing.get_type_hints( fnc, include_extras=True ) # Annotated[T, ...] -> T args = dict[str, FunctionArgInfo]() for name, param in sig.parameters.items(): if param.kind not in ( inspect.Parameter.POSITIONAL_OR_KEYWORD, inspect.Parameter.KEYWORD_ONLY, ): raise ValueError(f"{fnc_name}: unsupported parameter kind {param.kind}") inner_th, type_info = _extract_types(type_hints[name]) if not is_type_supported(inner_th): raise ValueError( f"{fnc_name}: unsupported type {inner_th} for parameter {name}" ) desc = type_info.description if type_info else "" choices = type_info.choices if type_info else () if ( isinstance(inner_th, type) and issubclass(inner_th, enum.Enum) and not choices ): # the enum must be a str or int (and at least one value) # this is verified by is_type_supported choices = tuple([item.value for item in inner_th]) inner_th = type(choices[0]) args[name] = FunctionArgInfo( name=name, description=desc, type=inner_th, default=param.default, choices=choices, ) self._fncs[metadata.name] = FunctionInfo( name=metadata.name, description=metadata.description, auto_retry=metadata.auto_retry, callable=fnc, arguments=args, ) @property def ai_functions(self) -> dict[str, FunctionInfo]: return self._fncs
Instance variables
prop ai_functions : dict[str, FunctionInfo]
-
Expand source code
@property def ai_functions(self) -> dict[str, FunctionInfo]: return self._fncs
Methods
def ai_callable(self,
*,
name: str | None = None,
description: str | _UseDocMarker = <livekit.agents.llm.function_context._UseDocMarker object>,
auto_retry: bool = True) ‑> Callable-
Expand source code
def ai_callable( self, *, name: str | None = None, description: str | _UseDocMarker = USE_DOCSTRING, auto_retry: bool = True, ) -> Callable: def deco(f): _set_metadata(f, name=name, desc=description, auto_retry=auto_retry) self._register_ai_function(f) return deco
class FunctionInfo (name: str,
description: str,
auto_retry: bool,
callable: Callable,
arguments: dict[str, FunctionArgInfo])-
Expand source code
@dataclass(frozen=True) class FunctionInfo: name: str description: str auto_retry: bool callable: Callable arguments: dict[str, FunctionArgInfo]
FunctionInfo(name: 'str', description: 'str', auto_retry: 'bool', callable: 'Callable', arguments: 'dict[str, FunctionArgInfo]')
Class variables
var arguments : dict[str, FunctionArgInfo]
var auto_retry : bool
var callable : Callable
var description : str
var name : str
class TypeInfo (description: str, choices: tuple | list[Any] = ())
-
Expand source code
@dataclass(frozen=True, init=False) class TypeInfo: description: str choices: tuple def __init__(self, description: str, choices: tuple | list[Any] = tuple()) -> None: object.__setattr__(self, "description", description) if isinstance(choices, list): choices = tuple(choices) object.__setattr__(self, "choices", choices)
TypeInfo(description: 'str', choices: 'tuple | list[Any]' = ()) -> 'None'
Class variables
var choices : tuple
var description : str