Skip to main content

🛠️ Development

Writing A Custom Toolkit

Toolkits are defined in a single Python file, with a top level docstring with metadata and a Tools class.

Example Top-Level Docstring

"""
title: String Inverse
author: Your Name
author_url: https://website.com
git_url: https://github.com/username/string-reverse.git
description: This tool calculates the inverse of a string
required_open_webui_version: 0.4.0
requirements: langchain-openai, langgraph, ollama, langchain_ollama
version: 0.4.0
licence: MIT
"""

Tools Class

Tools have to be defined as methods within a class called Tools, with optional subclasses called Valves and UserValves, for example:

class Tools:
def __init__(self):
"""Initialize the Tool."""
self.valves = self.Valves()

class Valves(BaseModel):
api_key: str = Field("", description="Your API key here")

def reverse_string(self, string: str) -> str:
"""
Reverses the input string.
:param string: The string to reverse
"""
# example usage of valves
if self.valves.api_key != "42":
return "Wrong API key"
return string[::-1]

Type Hints

Each tool must have type hints for arguments. The types may also be nested, such as queries_and_docs: list[tuple[str, int]]. Those type hints are used to generate the JSON schema that is sent to the model. Tools without type hints will work with a lot less consistency.

Valves and UserValves - (optional, but HIGHLY encouraged)

Valves and UserValves are used for specifying customizable settings of the Tool, you can read more on the dedicated Valves & UserValves page.

Citations

This type is used to provide citations or references in the chat. You can utilize it to specify the content, the source, and any relevant metadata. Below is an example of how to emit a citation event:

await __event_emitter__(
{
"type": "citation",
"data": {
"document": [content],
"metadata": [
{
"date_accessed": datetime.now().isoformat(),
"source": title,
}
],
"source": {"name": title, "url": url},
},
}
)

If you are sending multiple citations, you can iterate over citations and call the emitter multiple times. When implementing custom citations, ensure that you set self.citation = False in your Tools class __init__ method. Otherwise, the built-in citations will override the ones you have pushed in. For example:

def __init__(self):
self.citation = False

Warning: if you set self.citation = True, this will replace any custom citations you send with the automatically generated return citation. By disabling it, you can fully manage your own citation references.

Example
class Tools:
class UserValves(BaseModel):
test: bool = Field(
default=True, description="test"
)

def __init__(self):
self.citation = False

async def test_function(
self, prompt: str, __user__: dict, __event_emitter__=None
) -> str:
"""
This is a demo that just creates a citation

:param test: this is a test parameter
"""

await __event_emitter__(
{
"type": "citation",
"data": {
"document": ["This message will be appended to the chat as a citation when clicked into"],
"metadata": [
{
"date_accessed": datetime.now().isoformat(),
"source": title,
}
],
"source": {"name": "Title of the content", "url": "http://link-to-citation"},
},
}
)

External packages

In the Tools definition metadata you can specify custom packages. When you click Save the line will be parsed and pip install will be run on all requirements at once.

Keep in mind that as pip is used in the same process as Open WebUI, the UI will be completely unresponsive during the installation.

No measures are taken to handle package conflicts with Open WebUI's requirements. That means that specifying requirements can break Open WebUI if you're not careful. You might be able to work around this by specifying open-webui itself as a requirement.

Example
"""
title: myToolName
author: myName
funding_url: [any link here will be shown behind a `Heart` button for users to show their support to you]
version: 1.0.0
# the version is displayed in the UI to help users keep track of updates.
license: GPLv3
description: [recommended]
requirements: package1>=2.7.0,package2,package3
"""