🛠️ 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
"""