New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

tool2schema

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tool2schema - pypi Package Compare versions

Comparing version
1.3.1
to
2.0.0
+164
-113
PKG-INFO
Metadata-Version: 2.1
Name: tool2schema
Version: 1.3.1
Version: 2.0.0
Summary: A library to generate function schemas for use in the OpenAI API.

@@ -20,17 +20,23 @@ Home-page: https://github.com/cadifyai/tool2schema

# tool2schema
<div align="center">
<img src="media/logo.jpg" height=200>
<h1>
tool2schema
</h1>
Inspired by [janekb04/py2gpt](https://github.com/janekb04/py2gpt) and [fastai/lm-hackers](https://github.com/fastai/lm-hackers)
[![Check Code](https://github.com/cadifyai/tool2schema/actions/workflows/python-package.yml/badge.svg?branch=main)](https://github.com/cadifyai/tool2schema/actions/workflows/python-package.yml)
[![Downloads](https://static.pepy.tech/badge/tool2schema)](https://pepy.tech/project/tool2schema)
![Stars](https://img.shields.io/github/stars/cadifyai/tool2schema)
A library to convert Python functions to schemas supported by the OpenAI API.
</div>
Inspired by [janekb04/py2gpt](https://github.com/janekb04/py2gpt) and [fastai/lm-hackers](https://github.com/fastai/lm-hackers).
# Why tool2schema?
## Why tool2schema?
Sometimes you can provide a large language model (LLM) with functions for it to call, but it needs to follow a specific schema. `tool2schema` is a small depedency-free library that converts your functions into that specific schema. So yeah, it's in the name!
The OpenAI API supports [function calling](https://platform.openai.com/docs/guides/function-calling). However, to tell GPT what functions it can call, you must send the functions [in a JSON format](https://platform.openai.com/docs/api-reference/chat/create#chat-create-tools). With `tool2schema`, functions can be automatically converted to the correct JSON schema!
# Installation
## Installation
You can install `tool2schema` using `pip`.

@@ -42,11 +48,10 @@

## Usage
# Usage
On all functions that you would like to get JSON schema for, simply add the `GPTEnabled` decorator.
On all functions that you would like to get the schema for, simply add the `EnableTool` decorator. Then use the return value of `FindToolEnabledSchemas` method directly in your requests to whatever LLM you are using.
```python
# my_functions.py
from tool2schema import GPTEnabled
from tool2schema import EnableTool
@GPTEnabled
@EnableTool
def my_function1(a: int, b: str = "Hello"):

@@ -60,90 +65,119 @@ """

# Function code here...
```
@GPTEnabled(tags=["tag1"])
def my_function2(a: int, b: str = "Hello"):
"""
Example function description.
**Note**: To understand the appropriate format required for `tool2schema` to generate the appropriate schema, see the ['How it Works' section](#how-it-works).
:param a: First parameter
:param b: Second parameter
"""
# Function code here...
## OpenAI
```python
import my_tools # Module with your functions
from openai import OpenAI
from tool2schema import FindToolEnabledSchemas
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4-turbo",
tools=FindToolEnabledSchemas(my_tools) # <-- As easy as that!
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
)
```
`tool2schema` provides some methods to easily retrieve your functions.
<details>
<summary><b>If finetuning an OpenAI model, then the schema is slightly different.</b></summary>
```python
import my_functions # Module containing your functions
import tool2schema
import my_tools # Module with your functions
# Return functions with GPTEnabled decorator
gpt_enable = tool2schema.FindGPTEnabled(my_functions)
from openai import OpenAI
from tool2schema import FindToolEnabledSchemas, SchemaType
# Return all function schemas
schemas = tool2schema.FindGPTEnabledSchemas(my_functions)
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4-turbo",
tools=FindToolEnabledSchemas(my_tools, SchemaType.OPENAI_TUNE) # <-- As easy as that!
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
)
```
# Return function with given name
f = tool2schema.FindGPTEnabledByName(my_functions, "my_function1")
</details>
# Returns all functions with given tag
fs = tool2schema.FindGPTEnabledByTag(my_functions, "tag1")
## Anthropic
# Saves function schemas to JSON file
json_path = # Path to JSON file
tool2schema.SaveGPTEnabled(my_functions, json_path)
```python
import my_tools # Module with your functions
import anthropic
from tool2schema import FindToolEnabledSchemas, SchemaType
client = anthropic.Anthropic()
response = client.beta.tools.messages.create(
model="claude-3-opus-20240229",
tools=FindToolEnabledSchemas(my_tools, SchemaType.ANTHROPIC_CLAUDE), # <-- As easy as that!
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
)
```
## How it Works
## Mistral
`tool2schema` uses certain features of your function to correctly populate the schema.
Currently the same as OpenAI.
- Parameter type hints
- Parameter default values
- Docstring with parameter descriptions
# Public API
The docstring must be of a specific format. An example function is defined below that utilises all of the above features.
In this section we describe in more detail how to utilise this library to its fullest extent.
```python
def my_function(a: int, b: str = "Hello"):
"""
Example function description.
## Configuration
:param a: First parameter
:param b: Second parameter
"""
```
There are a number of setting available for you to tweak.
To get the schema for this function, simply use the `GPTEnabled` decorator. The decorator will return a class with some additional attributes but can still be called as a function.
| Name | Description | Default Value |
|----------|----------|--------------|
| `ignore_parameters` | A list of parameter names to exclude from the schema | `[]`
| `ignore_all_parameters` | A boolean value indicating whether to exclude all parameters from the schema. When set to true, `ignore_parameters` and `ignore_parameter_descriptions` will be ignored. | `False` |
| `ignore_function_description` | A boolean value indicating whether to exclude the function description from the schema. | `False` |
| `ignore_parameter_descriptions` | A boolean value indicating whether to exclude all parameter descriptions from the schema | `False` |
| `schema_type` | Default schema type to use. | `SchemaType.OPENAI_API` |
The schema of the function be accessed using the `schema` attribute.
### Decorator Configuration
You can provide the `EnableTool` decorator with the settings listed above.
For example, to omit parameters `b` and `c`:
```python
my_function.schema.to_json()
@GPTEnabled(ignore_parameters=["b", "c"])
def my_function(a: int, b: str, c: float):
# Function code here...
```
This returns the function schema in JSON format.
### Global Configuration
### Supported Parameter Types
It is also possible to specify the settings globally, so that they apply to all functions
unless explicitly overridden. It can be done by editing the global configuration as follows:
The following parameter types are supported:
```python
import tool2schema
- `int`
- `float`
- `str`
- `bool`
- `list`
# Ignore all parameters named "a" or "b" by default
tool2schema.CONFIG.ignore_parameters = ["a", "b"]
```
Any other parameter types will be listed as `object` in the schema.
## Module Operations
### Enumerations
`tool2schema` has methods available to get functions from a module. See below for example usage of each of the public API methods that `tool2schema` exposes.
If you want to limit the possible values of a parameter, you can use a `typing.Literal` type hint or a
subclass of `enum.Enum`. For example, using `typing.Literal`:
<details>
<summary><b>The examples assume the existance of this my_functions module.</b></summary>
```python
import typing
from tool2schema import GPTEnabled
@GPTEnabled
def my_function(a: int, b: typing.Literal["yes", "no"]):
def my_function1(a: int, b: str = "Hello"):
"""

@@ -156,16 +190,6 @@ Example function description.

# Function code here...
```
Equivalent example using `enum.Enum`:
```python
from enum import Enum
class MyEnum(Enum):
YES = 0
NO = 1
@GPTEnabled
def my_function(a: int, b: MyEnum):
@GPTEnabled(tags=["tag1"])
def my_function2(a: int, b: str = "Hello"):
"""

@@ -179,15 +203,34 @@ Example function description.

```
</details>
In the case of `Enum` subclasses, note that the schema will include the enumeration names rather than the values.
In the example above, the schema will include `["YES", "NO"]` rather than `[0, 1]`.
<br>
The `@GPTEnabled` decorator also allows to invoke the function using the name of the enum member rather than an
instance of the class. For example, you may invoke `my_function(1, MyEnum.YES)` as `my_function(1, "YES")`.
```python
import my_functions
import tool2schema
If the enumeration values are not known at the time of defining the function,
you can add them later using the `add_enum` method.
# Return all functions with the ToolEnable decorator
functions = tool2schema.FindToolEnabled(my_functions)
schemas = tool2schema.FindToolEnabledSchemas(my_functions)
# Return the function with a ToolEnable decorator and the given name
function = tool2schema.FindToolEnabledByName(my_functions, "my_function1")
schema = tool2schema.FindToolEnabledByNameSchema(my_functions, "my_function1")
# Return all functions with a ToolEnable decorator and the given tag
functions = tool2schema.FindToolEnabledByTag(my_functions, "tag1")
schemas = tool2schema.FindToolEnabledByTagSchemas(my_functions, "tag1")
# Save the schemas of all functions with a ToolEnable decorator to a JSON file
json_path = "path/to/json/file"
tool2schema.SaveToolEnabled(my_functions, json_path)
```
## Function Schema
To get the schema (in JSON format) for a function with the `EnableTool` decorator, either use the methods in the [Method Operations](#module-operations) section, or call the `to_json()` method on the function directly.
```python
@GPTEnabled
def my_function(a: int, b: str,):
def my_function(a: int):
"""

@@ -197,13 +240,14 @@ Example function description.

:param a: First parameter
:param b: Second parameter
"""
# Function code here...
my_function.schema.add_enum("b", ["yes", "no"])
my_function.to_json() # <-- returns the function schema
```
### Tags
**Note**: that the decorator returns a new `ToolEnabled` object with additional attributes, but can be called just like the original function.
The `GPTEnabled` decorator also supports the `tags` keyword argument. This allows you to add tags to your function schema.
## Function Tags
The `EnableTool` decorator also supports the `tags` keyword argument. This allows you to add tags to your function schema.
```python

@@ -233,32 +277,39 @@ @GPTEnabled(tags=["tag1", "tag2"])

### Disable parts of the schema
# How it Works
You can provide `GPTEnabled` with a number of settings to selectively disable parts of the schema.
For example, to omit certain parameters:
`tool2schema` uses certain features of your function definition to correctly populate the schema.
```python
@GPTEnabled(ignore_parameters=["b", "c"]) # b and c will not be included in the schema
def my_function(a: int, b: str, c: float):
# Function code here...
```
- Parameter type hints
- Parameter default values
- Docstring with parameter descriptions
The available settings are:
- `ignore_parameters`: A list of parameter names to exclude from the schema (defaults to `[]`).
- `ignore_all_parameters`: A boolean value indicating whether to exclude all parameters from the schema
(defaults to `False`). When set to true, all other parameter-related settings (`ignore_parameters` and
`ignore_parameter_descriptions`) will be ignored.
- `ignore_function_description`: A boolean value indicating whether to exclude the function description from
the schema (defaults to `False`).
- `ignore_parameter_descriptions`: A boolean value indicating whether to exclude all parameter descriptions
from the schema (defaults to `False`).
The docstring must be using the [Sphinx docstring](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) format.
**Note**: We use the parameter type hints instead of the docstring for parameter types.
It is also possible to specify the settings globally, so that they apply to all functions
unless explicitly overridden. It can be done by editing the global configuration as follows:
## Supported Parameter Types
Most of the common types are supported. See [type_schema.py](./tool2schema/type_schema.py) for more details.
Any parameter types not supported will be listed as `object` in the schema.
## Enumerations
Enumeration in the schema are listed as strings of the enumeration names rather than the values. This was a design choice we felt made more sense for use with LLMs. We introduce some additional pre-processing to ensure that the enumeration name strings are mapped back to the correct enum value. Therefore, `@EnableTool` decorator allows to invoke the function using the name of the enum member rather than an instance of the class. For example, you may invoke `my_function(1, MyEnum.YES)` as `my_function(1, "YES")`. See the code for more details.
> Enumerations are used to explcitly indicate what values are permitted for the parameter value.
If the enumeration values are not known at the time of defining the function, you can add them later using the `add_enum` method.
```python
import tool2schema
@GPTEnabled
def my_function(a: int, b: str):
"""
Example function description.
# Ignore all parameters named "a" or "b" by default
tool2schema.CONFIG.ignore_parameters = ["a", "b"]
:param a: First parameter
:param b: Second parameter
"""
# Function code here...
my_function.schema.add_enum("b", ["yes", "no"]) # <-- Add enum values for parameter 'b'
```

@@ -1,5 +0,1 @@

[tool.black]
line-length = 100
target-version = ['py311']
[tool.isort]

@@ -13,5 +9,15 @@ profile = "black"

[tool.pyright]
include = ["tool2schema"]
reportMissingImports = true
reportMissingModuleSource = false
pythonVersion = "3.11"
pythonPlatform = "Windows"
executionEnvironments = [
{ root = "tool2schema" }
]
[tool.poetry]
name = "tool2schema"
version = "v1.3.1"
version = "v2.0.0"
description = "A library to generate function schemas for use in the OpenAI API."

@@ -18,0 +24,0 @@ authors = ["Angus Stewart <siliconlad@protonmail.com>"]

+164
-112

@@ -1,16 +0,22 @@

# tool2schema
<div align="center">
<img src="media/logo.jpg" height=200>
<h1>
tool2schema
</h1>
Inspired by [janekb04/py2gpt](https://github.com/janekb04/py2gpt) and [fastai/lm-hackers](https://github.com/fastai/lm-hackers)
[![Check Code](https://github.com/cadifyai/tool2schema/actions/workflows/python-package.yml/badge.svg?branch=main)](https://github.com/cadifyai/tool2schema/actions/workflows/python-package.yml)
[![Downloads](https://static.pepy.tech/badge/tool2schema)](https://pepy.tech/project/tool2schema)
![Stars](https://img.shields.io/github/stars/cadifyai/tool2schema)
A library to convert Python functions to schemas supported by the OpenAI API.
</div>
Inspired by [janekb04/py2gpt](https://github.com/janekb04/py2gpt) and [fastai/lm-hackers](https://github.com/fastai/lm-hackers).
# Why tool2schema?
## Why tool2schema?
Sometimes you can provide a large language model (LLM) with functions for it to call, but it needs to follow a specific schema. `tool2schema` is a small depedency-free library that converts your functions into that specific schema. So yeah, it's in the name!
The OpenAI API supports [function calling](https://platform.openai.com/docs/guides/function-calling). However, to tell GPT what functions it can call, you must send the functions [in a JSON format](https://platform.openai.com/docs/api-reference/chat/create#chat-create-tools). With `tool2schema`, functions can be automatically converted to the correct JSON schema!
# Installation
## Installation
You can install `tool2schema` using `pip`.

@@ -22,11 +28,10 @@

## Usage
# Usage
On all functions that you would like to get JSON schema for, simply add the `GPTEnabled` decorator.
On all functions that you would like to get the schema for, simply add the `EnableTool` decorator. Then use the return value of `FindToolEnabledSchemas` method directly in your requests to whatever LLM you are using.
```python
# my_functions.py
from tool2schema import GPTEnabled
from tool2schema import EnableTool
@GPTEnabled
@EnableTool
def my_function1(a: int, b: str = "Hello"):

@@ -40,90 +45,119 @@ """

# Function code here...
```
@GPTEnabled(tags=["tag1"])
def my_function2(a: int, b: str = "Hello"):
"""
Example function description.
**Note**: To understand the appropriate format required for `tool2schema` to generate the appropriate schema, see the ['How it Works' section](#how-it-works).
:param a: First parameter
:param b: Second parameter
"""
# Function code here...
## OpenAI
```python
import my_tools # Module with your functions
from openai import OpenAI
from tool2schema import FindToolEnabledSchemas
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4-turbo",
tools=FindToolEnabledSchemas(my_tools) # <-- As easy as that!
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
)
```
`tool2schema` provides some methods to easily retrieve your functions.
<details>
<summary><b>If finetuning an OpenAI model, then the schema is slightly different.</b></summary>
```python
import my_functions # Module containing your functions
import tool2schema
import my_tools # Module with your functions
# Return functions with GPTEnabled decorator
gpt_enable = tool2schema.FindGPTEnabled(my_functions)
from openai import OpenAI
from tool2schema import FindToolEnabledSchemas, SchemaType
# Return all function schemas
schemas = tool2schema.FindGPTEnabledSchemas(my_functions)
client = OpenAI()
completion = client.chat.completions.create(
model="gpt-4-turbo",
tools=FindToolEnabledSchemas(my_tools, SchemaType.OPENAI_TUNE) # <-- As easy as that!
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
)
```
# Return function with given name
f = tool2schema.FindGPTEnabledByName(my_functions, "my_function1")
</details>
# Returns all functions with given tag
fs = tool2schema.FindGPTEnabledByTag(my_functions, "tag1")
## Anthropic
# Saves function schemas to JSON file
json_path = # Path to JSON file
tool2schema.SaveGPTEnabled(my_functions, json_path)
```python
import my_tools # Module with your functions
import anthropic
from tool2schema import FindToolEnabledSchemas, SchemaType
client = anthropic.Anthropic()
response = client.beta.tools.messages.create(
model="claude-3-opus-20240229",
tools=FindToolEnabledSchemas(my_tools, SchemaType.ANTHROPIC_CLAUDE), # <-- As easy as that!
messages=[{"role": "user", "content": "What's the weather like in San Francisco?"}],
)
```
## How it Works
## Mistral
`tool2schema` uses certain features of your function to correctly populate the schema.
Currently the same as OpenAI.
- Parameter type hints
- Parameter default values
- Docstring with parameter descriptions
# Public API
The docstring must be of a specific format. An example function is defined below that utilises all of the above features.
In this section we describe in more detail how to utilise this library to its fullest extent.
```python
def my_function(a: int, b: str = "Hello"):
"""
Example function description.
## Configuration
:param a: First parameter
:param b: Second parameter
"""
```
There are a number of setting available for you to tweak.
To get the schema for this function, simply use the `GPTEnabled` decorator. The decorator will return a class with some additional attributes but can still be called as a function.
| Name | Description | Default Value |
|----------|----------|--------------|
| `ignore_parameters` | A list of parameter names to exclude from the schema | `[]`
| `ignore_all_parameters` | A boolean value indicating whether to exclude all parameters from the schema. When set to true, `ignore_parameters` and `ignore_parameter_descriptions` will be ignored. | `False` |
| `ignore_function_description` | A boolean value indicating whether to exclude the function description from the schema. | `False` |
| `ignore_parameter_descriptions` | A boolean value indicating whether to exclude all parameter descriptions from the schema | `False` |
| `schema_type` | Default schema type to use. | `SchemaType.OPENAI_API` |
The schema of the function be accessed using the `schema` attribute.
### Decorator Configuration
You can provide the `EnableTool` decorator with the settings listed above.
For example, to omit parameters `b` and `c`:
```python
my_function.schema.to_json()
@GPTEnabled(ignore_parameters=["b", "c"])
def my_function(a: int, b: str, c: float):
# Function code here...
```
This returns the function schema in JSON format.
### Global Configuration
### Supported Parameter Types
It is also possible to specify the settings globally, so that they apply to all functions
unless explicitly overridden. It can be done by editing the global configuration as follows:
The following parameter types are supported:
```python
import tool2schema
- `int`
- `float`
- `str`
- `bool`
- `list`
# Ignore all parameters named "a" or "b" by default
tool2schema.CONFIG.ignore_parameters = ["a", "b"]
```
Any other parameter types will be listed as `object` in the schema.
## Module Operations
### Enumerations
`tool2schema` has methods available to get functions from a module. See below for example usage of each of the public API methods that `tool2schema` exposes.
If you want to limit the possible values of a parameter, you can use a `typing.Literal` type hint or a
subclass of `enum.Enum`. For example, using `typing.Literal`:
<details>
<summary><b>The examples assume the existance of this my_functions module.</b></summary>
```python
import typing
from tool2schema import GPTEnabled
@GPTEnabled
def my_function(a: int, b: typing.Literal["yes", "no"]):
def my_function1(a: int, b: str = "Hello"):
"""

@@ -136,16 +170,6 @@ Example function description.

# Function code here...
```
Equivalent example using `enum.Enum`:
```python
from enum import Enum
class MyEnum(Enum):
YES = 0
NO = 1
@GPTEnabled
def my_function(a: int, b: MyEnum):
@GPTEnabled(tags=["tag1"])
def my_function2(a: int, b: str = "Hello"):
"""

@@ -159,15 +183,34 @@ Example function description.

```
</details>
In the case of `Enum` subclasses, note that the schema will include the enumeration names rather than the values.
In the example above, the schema will include `["YES", "NO"]` rather than `[0, 1]`.
<br>
The `@GPTEnabled` decorator also allows to invoke the function using the name of the enum member rather than an
instance of the class. For example, you may invoke `my_function(1, MyEnum.YES)` as `my_function(1, "YES")`.
```python
import my_functions
import tool2schema
If the enumeration values are not known at the time of defining the function,
you can add them later using the `add_enum` method.
# Return all functions with the ToolEnable decorator
functions = tool2schema.FindToolEnabled(my_functions)
schemas = tool2schema.FindToolEnabledSchemas(my_functions)
# Return the function with a ToolEnable decorator and the given name
function = tool2schema.FindToolEnabledByName(my_functions, "my_function1")
schema = tool2schema.FindToolEnabledByNameSchema(my_functions, "my_function1")
# Return all functions with a ToolEnable decorator and the given tag
functions = tool2schema.FindToolEnabledByTag(my_functions, "tag1")
schemas = tool2schema.FindToolEnabledByTagSchemas(my_functions, "tag1")
# Save the schemas of all functions with a ToolEnable decorator to a JSON file
json_path = "path/to/json/file"
tool2schema.SaveToolEnabled(my_functions, json_path)
```
## Function Schema
To get the schema (in JSON format) for a function with the `EnableTool` decorator, either use the methods in the [Method Operations](#module-operations) section, or call the `to_json()` method on the function directly.
```python
@GPTEnabled
def my_function(a: int, b: str,):
def my_function(a: int):
"""

@@ -177,13 +220,14 @@ Example function description.

:param a: First parameter
:param b: Second parameter
"""
# Function code here...
my_function.schema.add_enum("b", ["yes", "no"])
my_function.to_json() # <-- returns the function schema
```
### Tags
**Note**: that the decorator returns a new `ToolEnabled` object with additional attributes, but can be called just like the original function.
The `GPTEnabled` decorator also supports the `tags` keyword argument. This allows you to add tags to your function schema.
## Function Tags
The `EnableTool` decorator also supports the `tags` keyword argument. This allows you to add tags to your function schema.
```python

@@ -213,31 +257,39 @@ @GPTEnabled(tags=["tag1", "tag2"])

### Disable parts of the schema
# How it Works
You can provide `GPTEnabled` with a number of settings to selectively disable parts of the schema.
For example, to omit certain parameters:
`tool2schema` uses certain features of your function definition to correctly populate the schema.
```python
@GPTEnabled(ignore_parameters=["b", "c"]) # b and c will not be included in the schema
def my_function(a: int, b: str, c: float):
# Function code here...
```
- Parameter type hints
- Parameter default values
- Docstring with parameter descriptions
The available settings are:
- `ignore_parameters`: A list of parameter names to exclude from the schema (defaults to `[]`).
- `ignore_all_parameters`: A boolean value indicating whether to exclude all parameters from the schema
(defaults to `False`). When set to true, all other parameter-related settings (`ignore_parameters` and
`ignore_parameter_descriptions`) will be ignored.
- `ignore_function_description`: A boolean value indicating whether to exclude the function description from
the schema (defaults to `False`).
- `ignore_parameter_descriptions`: A boolean value indicating whether to exclude all parameter descriptions
from the schema (defaults to `False`).
The docstring must be using the [Sphinx docstring](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) format.
**Note**: We use the parameter type hints instead of the docstring for parameter types.
It is also possible to specify the settings globally, so that they apply to all functions
unless explicitly overridden. It can be done by editing the global configuration as follows:
## Supported Parameter Types
Most of the common types are supported. See [type_schema.py](./tool2schema/type_schema.py) for more details.
Any parameter types not supported will be listed as `object` in the schema.
## Enumerations
Enumeration in the schema are listed as strings of the enumeration names rather than the values. This was a design choice we felt made more sense for use with LLMs. We introduce some additional pre-processing to ensure that the enumeration name strings are mapped back to the correct enum value. Therefore, `@EnableTool` decorator allows to invoke the function using the name of the enum member rather than an instance of the class. For example, you may invoke `my_function(1, MyEnum.YES)` as `my_function(1, "YES")`. See the code for more details.
> Enumerations are used to explcitly indicate what values are permitted for the parameter value.
If the enumeration values are not known at the time of defining the function, you can add them later using the `add_enum` method.
```python
import tool2schema
@GPTEnabled
def my_function(a: int, b: str):
"""
Example function description.
# Ignore all parameters named "a" or "b" by default
tool2schema.CONFIG.ignore_parameters = ["a", "b"]
```
:param a: First parameter
:param b: Second parameter
"""
# Function code here...
my_function.schema.add_enum("b", ["yes", "no"]) # <-- Add enum values for parameter 'b'
```
# flake8: noqa
__version__ = "v1.3.1"
__version__ = "v2.0.0"
from .config import Config
from .config import Config, SchemaType
from .schema import (
FindGPTEnabled,
FindGPTEnabledByName,
FindGPTEnabledByTag,
FindGPTEnabledSchemas,
GPTEnabled,
LoadGPTEnabled,
SaveGPTEnabled,
SchemaType,
EnableTool,
FindToolEnabled,
FindToolEnabledByName,
FindToolEnabledByNameSchema,
FindToolEnabledByTag,
FindToolEnabledByTagSchemas,
FindToolEnabledSchemas,
LoadToolEnabled,
SaveToolEnabled,
)

@@ -15,0 +16,0 @@

from __future__ import annotations
import copy
from enum import Enum
from typing import Optional
class SchemaType(Enum):
"""Enum for schema types."""
OPENAI_API = 0
OPENAI_TUNE = 1
ANTHROPIC_CLAUDE = 2
class Config:

@@ -18,2 +27,13 @@ """

@property
def schema_type(self) -> SchemaType:
"""
Type of the schema to create.
"""
return self._get_setting(Config.schema_type.fget.__name__, SchemaType.OPENAI_API)
@schema_type.setter
def schema_type(self, value: SchemaType):
self._set_setting(Config.schema_type.fget.__name__, value)
@property
def ignore_parameters(self) -> list[str]:

@@ -20,0 +40,0 @@ """

@@ -0,1 +1,3 @@

from __future__ import annotations
import copy

@@ -6,48 +8,46 @@ import functools

import re
from enum import Enum
import sys
from inspect import Parameter
from types import ModuleType
from typing import Any, Callable, Optional
from typing import Any, Callable, Generic, Optional, TypeVar, overload
import tool2schema
from tool2schema.config import Config
from tool2schema.config import Config, SchemaType
from tool2schema.parameter_schema import ParameterSchema
if sys.version_info < (3, 10):
from typing_extensions import ParamSpec
else:
from typing import ParamSpec
class SchemaType(Enum):
"""Enum for schema types."""
API = 0
TUNE = 1
def FindGPTEnabled(module: ModuleType) -> list[Callable]:
def FindToolEnabled(module: ModuleType) -> list[ToolEnabled]:
"""
Find all functions with the GPTEnabled decorator.
Find all functions with the EnableTool decorator.
:param module: Module to search for GPTEnabled functions
:param module: Module to search for ToolEnabled functions
"""
return [x for x in module.__dict__.values() if hasattr(x, "gpt_enabled")]
return [x for x in module.__dict__.values() if hasattr(x, "tool_enabled")]
def FindGPTEnabledSchemas(
module: ModuleType, schema_type: SchemaType = SchemaType.API
def FindToolEnabledSchemas(
module: ModuleType, schema_type: Optional[SchemaType] = None
) -> list[dict]:
"""
Find all function schemas with the GPTEnabled decorator.
Find all function schemas with the EnableTool decorator.
:param module: Module to search for GPTEnabled functions
:param schema_type: Type of schema to return
:param module: Module to search for ToolEnabled functions
:param schema_type: Type of schema to return (None indicates default)
"""
return [x.schema.to_json(schema_type) for x in FindGPTEnabled(module)]
return [x.to_json(schema_type) for x in FindToolEnabled(module)]
def FindGPTEnabledByName(module: ModuleType, name: str) -> Optional[Callable]:
def FindToolEnabledByName(module: ModuleType, name: str) -> Optional[ToolEnabled]:
"""
Find a function with the GPTEnabled decorator by name.
Find a function with the EnableTool decorator by name.
:param module: Module to search for GPTEnabled functions
:param module: Module to search for ToolEnabled functions
:param name: Name of the function to find
"""
for func in FindGPTEnabled(module):
for func in FindToolEnabled(module):
if func.__name__ == name:

@@ -58,21 +58,49 @@ return func

def FindGPTEnabledByTag(module: ModuleType, tag: str) -> list[Callable]:
def FindToolEnabledByNameSchema(
module: ModuleType, name: str, schema_type: Optional[SchemaType] = None
) -> Optional[dict]:
"""
Find all functions with the GPTEnabled decorator by tag.
Find a function schema with the EnableTool decorator by name.
:param module: Module to search for GPTEnabled functions
:param module: Module to search for ToolEnabled functions
:param name: Name of the function to find
:param schema_type: Type of schema to return (None indicates default)
"""
if (func := FindToolEnabledByName(module, name)) is None:
return None
return func.to_json(schema_type)
def FindToolEnabledByTag(module: ModuleType, tag: str) -> list[ToolEnabled]:
"""
Find all functions with the EnableTool decorator by tag.
:param module: Module to search for ToolEnabled functions
:param tag: Tag to search for
"""
return [x for x in FindGPTEnabled(module) if x.has(tag)]
return [x for x in FindToolEnabled(module) if x.has(tag)]
def SaveGPTEnabled(module: ModuleType, path: str, schema_type: SchemaType = SchemaType.API):
def FindToolEnabledByTagSchemas(
module: ModuleType, tag: str, schema_type: Optional[SchemaType] = None
) -> list[dict]:
"""
Save all function schemas with the GPTEnabled decorator to a file.
Find all function schemas with the EnableTool decorator by tag.
:param module: Module to search for GPTEnabled functions
:param module: Module to search for ToolEnabled functions
:param tag: Tag to search for
:param schema_type: Type of schema to return (None indicates default)
"""
return [x.to_json(schema_type) for x in FindToolEnabledByTag(module, tag)]
def SaveToolEnabled(module: ModuleType, path: str, schema_type: Optional[SchemaType] = None):
"""
Save all function schemas with the EnableTool decorator to a file.
:param module: Module to search for ToolEnabled functions
:param path: Path to save the schemas to
:param schema_type: Type of schema to return
:param schema_type: Type of schema to return (None indicates default)
"""
schemas = FindGPTEnabledSchemas(module, schema_type)
schemas = FindToolEnabledSchemas(module, schema_type)
json.dump(schemas, open(path, "w"))

@@ -83,7 +111,6 @@

"""Exception for schema parsing errors."""
pass
def LoadGPTEnabled(
def LoadToolEnabled(
module: ModuleType,

@@ -96,3 +123,3 @@ function: dict,

Given a function dictionary containing the name of a function and the arguments to pass to it,
retrieve the corresponding function among those with the `GPTEnabled` decorator defined in
retrieve the corresponding function among those with the `EnableTool` decorator defined in
`module`. When `validate` is true, validate the arguments and raise `ParseException` if the

@@ -110,3 +137,3 @@ arguments are not valid (see more information below).

:raises ParseException: Thrown when any of the following conditions is met:
- Function isn't defined in the given module, or is not decorated with `GPTEnabled`
- Function isn't defined in the given module, or is not decorated with `EnableTool`
- The arguments are given as string and the string is not valid, meaning it is:

@@ -146,3 +173,3 @@ - Not parsable as JSON, or;

f = FindGPTEnabledByName(module, name)
f = FindToolEnabledByName(module, name)

@@ -153,3 +180,3 @@ if not f:

f"Function with name '{name}' is not defined in given module "
f"'{module.__name__}' or is missing 'GPTEnabled' decorator"
f"'{module.__name__}' or is missing 'EnableTool' decorator"
)

@@ -163,3 +190,3 @@

def _validate_arguments(f: Callable, arguments: dict, ignore_hallucinations: bool) -> dict:
def _validate_arguments(f: ToolEnabled, arguments: dict, ignore_hallucinations: bool) -> dict:
"""

@@ -170,3 +197,3 @@ Verify that all required arguments are present, and the arguments are of the expected type.

:param f: A GPTEnabled-decorated function
:param f: A EnableTool-decorated function
:param arguments: Arguments to validate

@@ -199,4 +226,8 @@ :param ignore_hallucinations: Whether to ignore hallucinated arguments or throw an exception

class _GPTEnabled:
def __init__(self, func, **kwargs) -> None:
P = ParamSpec("P") # User-provided function parameters type
T = TypeVar("T") # User-provided function return type
class ToolEnabled(Generic[P, T]):
def __init__(self, func: Callable[P, T], **kwargs) -> None:
self.func = func

@@ -208,3 +239,3 @@ self.tags = kwargs.pop("tags", [])

def __call__(self, *args, **kwargs):
def __call__(self, *args: P.args, **kwargs: P.kwargs) -> T:

@@ -226,5 +257,14 @@ args = list(args) # Tuple is immutable, thus convert to list

def gpt_enabled(self) -> bool:
def tool_enabled(self) -> bool:
return True
def to_json(self, schema_type: Optional[SchemaType] = None) -> dict:
"""
Return JSON schema for the function.
:param schema_type: None indicates default schema type
:return: JSON schema
"""
return self.schema.to_json(schema_type)
def has(self, tag: str) -> bool:

@@ -234,10 +274,18 @@ return tag in self.tags

def GPTEnabled(func=None, **kwargs):
@overload
def EnableTool(func: Callable[P, T], **kwargs) -> ToolEnabled[P, T]: ...
@overload
def EnableTool(**kwargs) -> Callable[[Callable[P, T]], ToolEnabled[P, T]]: ...
def EnableTool(func=None, **kwargs):
"""Decorator to generate a function schema for OpenAI."""
if func:
return _GPTEnabled(func, **kwargs)
if func is not None:
return ToolEnabled(func, **kwargs)
else:
def wrapper(function):
return _GPTEnabled(function, **kwargs)
def wrapper(function: Callable[P, T]) -> ToolEnabled[P, T]:
return ToolEnabled(function, **kwargs)

@@ -261,3 +309,3 @@ return wrapper

def to_json(self, schema_type: SchemaType = SchemaType.API) -> dict:
def to_json(self, schema_type: Optional[SchemaType] = None) -> dict:
"""

@@ -267,8 +315,11 @@ Convert schema to JSON.

"""
if schema_type == SchemaType.TUNE:
schema_type = schema_type or self.config.schema_type
if schema_type == SchemaType.OPENAI_TUNE:
return self._get_function_schema(schema_type)
elif schema_type == SchemaType.ANTHROPIC_CLAUDE:
return self._get_function_schema(schema_type)
return self._get_schema()
def add_enum(self, n: str, enum: list) -> "FunctionSchema":
def add_enum(self, n: str, enum: list) -> FunctionSchema:
"""

@@ -279,2 +330,3 @@ Add enum property to a particular function parameter.

:param enum: The list of values for the enum parameter
:return: This function schema
"""

@@ -289,3 +341,3 @@ self._all_parameter_schemas[n].add_enum(enum)

# This dictionary is only used with the API schema type
return {"type": "function", "function": self._get_function_schema(SchemaType.API)}
return {"type": "function", "function": self._get_function_schema(SchemaType.OPENAI_API)}

@@ -296,7 +348,13 @@ def _get_function_schema(self, schema_type: SchemaType) -> dict:

"""
schema = {"name": self.f.__name__}
schema: dict[str, Any] = {"name": self.f.__name__}
if self.parameter_schemas or schema_type == SchemaType.TUNE:
need_empty_param = schema_type in [
SchemaType.OPENAI_TUNE,
SchemaType.ANTHROPIC_CLAUDE]
if self.parameter_schemas or need_empty_param:
# If the schema type is tune, add the dictionary even if there are no parameters
schema["parameters"] = self._get_parameters_schema()
if schema_type == SchemaType.ANTHROPIC_CLAUDE:
schema["input_schema"] = self._get_parameters_schema()
else:
schema["parameters"] = self._get_parameters_schema()

@@ -303,0 +361,0 @@ if (description := self._get_description()) is not None:

@@ -13,3 +13,3 @@ from __future__ import annotations

def GPTTypeSchema(cls: Type[TypeSchema]):
def ToolTypeSchema(cls: Type[TypeSchema]):
"""

@@ -124,3 +124,3 @@ Decorator to register a type schema class.

@GPTTypeSchema
@ToolTypeSchema
class ValueTypeSchema(TypeSchema):

@@ -144,2 +144,5 @@ """

def validate(self, value) -> bool:
# Allow implicit conversion from int to float
if self.type is float and type(value) is int:
return True
return self.type == type(value)

@@ -172,3 +175,3 @@

@GPTTypeSchema
@ToolTypeSchema
class ListTypeSchema(GenericTypeSchema):

@@ -214,3 +217,3 @@ """

@GPTTypeSchema
@ToolTypeSchema
class UnionTypeSchema(GenericTypeSchema):

@@ -274,3 +277,3 @@ """

@GPTTypeSchema
@ToolTypeSchema
class EnumClassTypeSchema(EnumTypeSchema):

@@ -310,3 +313,3 @@ """

@GPTTypeSchema
@ToolTypeSchema
class LiteralTypeSchema(EnumTypeSchema):

@@ -313,0 +316,0 @@ """