SkillAgentSearch skills...

LlmFunctionDecorator

A Python package designed to simplify the process of creating and managing function calls to OpenAI's API, as well as models using LiteLLM's API framework. Includes rigorous error handling.

Install / Use

/learn @A-M-D-R-3-W/LlmFunctionDecorator
About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

Custom tools are fully supported as of 5/25/2025, but built-in OpenAI tools (Web Search, Remote MCP Servers, File Search, Image Generation, Code Interpreter, Computer Use) do not yet have an improved implementation in this project. This does not affect LiteLLM users. On the to-do list!

llmFunctionDecorator

https://pypi.org/project/llmFunctionDecorator

A Python package designed to simplify the process of creating and managing function calls to OpenAI's API, as well as models using LiteLLM's API framework. Includes rigorous error handling.

Demo_llmFunctionDecorator

Examples

Examples (A separate readme and project files) are located in the examples/ folder here

Installation

llmFunctionDecorator is available on PyPi, so installation is easy.

pip install llmFunctionDecorator

Upon installation, make sure to import the package into your project.

from llmFunctionDecorator import tool, FunctionRegistry

Note: Not required, but I also recommend using print from Rich for nice JSON formatting among other things. Rich is used in the attached example.

from rich import print

Quickstart

1. Defining Functions

First, define your functions following standard Python syntax. This function will be available to the API for use. For example:

def an_awesome_function(variable1, variable2="A default value for variable2"):
    # ...
    return desiredVariable

2. Decorating your Functions

Use the @tool decorator to create your function descriptions which will be passed to the API. Add relevant details such as purpose, parameters, and descriptions. Make sure the decorator is directly above your function as shown.

The description will look something like this:

@tool(
    enabled=True,
    purpose="An awesome function that does something amazing.",
    variable1=int,
    variable1_description="The first variable that will be used to do some awesome thing.",
    variable2=["option1", "option2"], # This is an enum of strings. A mix of any data type below is permissible.
    variable2_description="The second variable that will be used to do another awesome thing.",
    required=["variable1", "variable2"]
)
def an_awesome_function(variable1, variable2="A default value for variable2"):
    # ...
    return desiredVariable

3. Submitting Your Functions to the API

Using the functions is very simple. In your request, under the tools key, set it to FunctionRegistry.tools().

Also, you must set the tool_choice key to FunctionRegistry.tool_choice(). More information on FunctionRegistry.tool_choice() is provided in the FunctionRegistry Class section of this readme.

response = litellm.completion(
            model="gpt-3.5-turbo-1106",
            messages=messages,
            tools=FunctionRegistry.tools(),
            tool_choice=FunctionRegistry.tool_choice(),
)

Note: If you'd prefer to avoid using FunctionRegistry.tool_choice() and would rather manually input values for tool_choice, you will need to format your response as below, otherwise you will experience undefined behavior.

if FunctionRegistry.tools():
    response = litellm.completion(
        model="gpt-3.5-turbo-1106",
        messages=messages,
        tools=FunctionRegistry.tools(),
        tool_choice="auto",
    )
else:
    response = litellm.completion(
        model="gpt-3.5-turbo-1106",
        messages=messages,
    )
)

This will maintain your access to tool_choice if there are functions enabled, and if there are no functions, it will use the second response format.

Detailed Look at Creating Your @tool Decorator Function Descriptions

Required and Optional Parameters:

  • purpose (Required, str): A brief description of what the wrapped function does. This should be a human-readable string that clearly communicates the function's purpose.

    purpose="Get the current weather in a given location"
    
  • enabled (Optional, bool): Flag indicating if the function is enabled. If not present, will default to True.

    enabled=False
    
  • required (Optional, list of str): A list of parameter names that are required for the function to operate. This is useful for specifying which parameters cannot be omitted when calling the function.

    required=["location", "unit"]
    

Parameter Keyword Arguments (Dynamic):

  • **kwargs: In addition to the parameters mentioned above, you can specify any number of additional keyword arguments. These are used to define the parameters (variables) that the decorated function takes as input. The keys should be the names of the parameters, and the values should define their types or allowable values (for enums).

    For each parameter of the function, you can provide:

    • The parameter type by simply specifying a Python type (e.g., str, int, etc.) as the value that the parameter expects as input.

      location=str
      
    • For enum parameters, instead of a single type, you provide a list of allowable values (e.g., ["celsius", "fahrenheit"] for a temperature unit parameter).

      unit=["celsius", "fahrenheit"]
      
    • You can also append _description to any parameter name (e.g., location_description) as an additional key to provide a human-readable description of what that parameter is for. ⚠️Every parameter should have an accompanying description key.⚠️

      location_description="The city and state, e.g. San Francisco, CA"
      

      Putting this all together, we get our function description.

@tool(
    enabled=True,                                                               # optional enabled argument
    purpose="Get the current weather in a given location.",                     # description of the function
    location=str,                                                               # type of the location argument
    location_description="The city and state, e.g. San Francisco, CA",          # description of the location argument
    unit=["celsius", "fahrenheit"],                                             # possible values for the unit argument
    unit_description="The unit of temperature, e.g. celsius or fahrenheit",     # description of the unit argument
    required=["location"],                                                      # required arguments
)

Permissible Data Types

The following is a list of data types that can be assigned to a parameter (variable).

  • variable1=int
  • variable1=float
  • variable1=str
  • variable1=bool
  • variable1=list
  • variable1=tuple
  • variable1=dict
  • variable1=None

In addition, enums can be assigned int, float, str, or bool. For example,

  • variable1=[12, 19, 17]
  • variable1=[18.6, 78.2, 97.0]
  • variable1=["first", "second", "last"]
  • variable1=[True, False]

Enums can also have various data types. For example,

  • variable1=[15, 17.2, "hello", True]

FunctionRegistry Class

The FunctionRegistry class acts as a storage and management system for all registered functions, enabling the dynamic invocation of these functions with arguments specified at runtime.

Overview

The FunctionRegistry provides several class methods for managing functions, their metadata, and invocation:

  • register_function(name, tool_instance): Automatically called by the ToolWrapper when a function is decorated with @tool. It registers a function with its metadata in the registry. This will never* need to be called directly as it is automatically handled.

  • get_registry(): Returns a dictionary of all enabled function instances that are registered. Useful for inspecting which functions are available for invocation.

  • tools(): Retrieves registered ToolWrapper instances, converts them to their dictionary representations, and returns a list of these dictionaries. This is the method you will pass to the tools key when creating your response, i.e., this will replace the JSON in your API call.

  • registry_status(): Returns a string summary of all registered functions along with their enabled status. This is helpful for debugging purposes to ensure that the intended functions are enabled and correctly registered.

  • call_function(name, **kwargs): Tries to invoke a registered function by its name, passing the provided keyword arguments. I.e., it dynamically invokes functions based on LLM requests. See the Parallel Function Call example to see it in action, and understand how to implement it.

Usage

Although most interaction with FunctionRegistry is automated through the use of the @tool decorator, a few of these methods can be very useful, especially for debugging or extending the capabilities of your LLM integration. Here are some examples:

Checking Registered Functions:

from llmFunctionDecorator import FunctionRegistry

# List all registered functions and their enabled statuses
print(FunctionRegistry.registry_status())

Directly Invoking a Registered Function:

This example demonstrates how you might directly invoke a function that has been registered with the FunctionRegistry.

result = FunctionRegistry.call_function('get_current_weather', location="Tokyo, Japan")
print(result)

This would attempt to call the get_current_weather function (assuming it's registered and enabled) with the specified location parameter. As you'll see in the Parallel Function Call example, this is handled by the LLM and will not require manual entry.

Listing Functions for LLM Integration:

When preparing a request to an LLM, you will need to include the list of functions. Here's how you can retrieve this list in the format expected by the LLM:

View on GitHub
GitHub Stars17
CategoryDesign
Updated8mo ago
Forks1

Languages

Python

Security Score

82/100

Audited on Jul 4, 2025

No findings