mirror of
https://github.com/open-webui/docs
synced 2025-05-19 18:58:41 +00:00
tools
This commit is contained in:
parent
75b5971eba
commit
8719fd7b12
336
docs/features/plugin/tools/development.mdx
Normal file
336
docs/features/plugin/tools/development.mdx
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
---
|
||||||
|
sidebar_position: 2
|
||||||
|
title: "🛠️ 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
|
||||||
|
|
||||||
|
```python
|
||||||
|
"""
|
||||||
|
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:
|
||||||
|
|
||||||
|
```python
|
||||||
|
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. As of version OpenWebUI version 0.4.3, 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 to allow users to provide dynamic details such as an API key or a configuration option. These will create a fillable field or a bool switch in the GUI menu for the given function.
|
||||||
|
|
||||||
|
Valves are configurable by admins alone and UserValves are configurable by any users.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Commented example</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
class Tools:
|
||||||
|
# Notice the current indentation: Valves and UserValves must be declared as
|
||||||
|
# attributes of a Tools, Filter or Pipe class. Here we take the
|
||||||
|
# example of a Tool.
|
||||||
|
class Valves(BaseModel):
|
||||||
|
# Valves and UserValves inherit from pydantic's BaseModel. This
|
||||||
|
# enables complex use cases like model validators etc.
|
||||||
|
test_valve: int = Field( # Notice the type hint: it is used to
|
||||||
|
# choose the kind of UI element to show the user (buttons,
|
||||||
|
# texts, etc).
|
||||||
|
default=4,
|
||||||
|
description="A valve controlling a numberical value"
|
||||||
|
# required=False, # you can enforce fields using True
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
# Note that this 'pass' helps for parsing and is recommended.
|
||||||
|
|
||||||
|
# UserValves are defined the same way.
|
||||||
|
class UserValves(BaseModel):
|
||||||
|
test_user_valve: bool = Field(
|
||||||
|
default=False, description="A user valve controlling a True/False (on/off) switch"
|
||||||
|
)
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.valves = self.Valves()
|
||||||
|
# Because they are set by the admin, they are accessible directly
|
||||||
|
# upon code execution.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# The __user__ handling is the same for Filters, Tools and Functions.
|
||||||
|
def test_the_tool(self, message: str, __user__: dict):
|
||||||
|
"""
|
||||||
|
This is a test tool. If the user asks you to test the tools, put any
|
||||||
|
string you want in the message argument.
|
||||||
|
|
||||||
|
:param message: Any string you want.
|
||||||
|
:return: The same string as input.
|
||||||
|
"""
|
||||||
|
# Because UserValves are defined per user they are only available
|
||||||
|
# on use.
|
||||||
|
# Note that although __user__ is a dict, __user__["valves"] is a
|
||||||
|
# UserValves object. Hence you can access values like that:
|
||||||
|
test_user_valve = __user__["valves"].test_user_valve
|
||||||
|
# Or:
|
||||||
|
test_user_valve = dict(__user__["valves"])["test_user_valve"]
|
||||||
|
# But this will return the default value instead of the actual value:
|
||||||
|
# test_user_valve = __user__["valves"]["test_user_valve"] # Do not do that!
|
||||||
|
|
||||||
|
return message + f"\nThe user valve set value is: {test_user_valve}"
|
||||||
|
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Optional Arguments
|
||||||
|
Below is a list of optional arguments your tools can depend on:
|
||||||
|
- `__event_emitter__`: Emit events (see following section)
|
||||||
|
- `__event_call__`: Same as event emitter but can be used for user interactions
|
||||||
|
- `__user__`: A dictionary with user information. It also contains the `UserValves` object in `__user__["valves"]`.
|
||||||
|
- `__metadata__`: Dictionary with chat metadata
|
||||||
|
- `__messages__`: List of previous messages
|
||||||
|
- `__files__`: Attached files
|
||||||
|
- `__model__`: Model name
|
||||||
|
|
||||||
|
Just add them as argument to any method of your Tool class just like `__user__` in the example above.
|
||||||
|
|
||||||
|
### Event Emitters
|
||||||
|
Event Emitters are used to add additional information to the chat interface. Similarly to Filter Outlets, Event Emitters are capable of appending content to the chat. Unlike Filter Outlets, they are not capable of stripping information. Additionally, emitters can be activated at any stage during the Tool.
|
||||||
|
|
||||||
|
There are two different types of Event Emitters:
|
||||||
|
|
||||||
|
If the model seems to be unable to call the tool, make sure it is enabled (either via the Model page or via the `+` sign next to the chat input field). You can also turn the `Function Calling` argument of the `Advanced Params` section of the Model page from `Default` to `Native`.
|
||||||
|
|
||||||
|
#### Status
|
||||||
|
This is used to add statuses to a message while it is performing steps. These can be done at any stage during the Tool. These statuses appear right above the message content. These are very useful for Tools that delay the LLM response or process large amounts of information. This allows you to inform users what is being processed in real-time.
|
||||||
|
|
||||||
|
```
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "status", # We set the type here
|
||||||
|
"data": {"description": "Message that shows up in the chat", "done": False, "hidden": False},
|
||||||
|
# Note done is False here indicating we are still emitting statuses
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
async def test_function(
|
||||||
|
self, prompt: str, __user__: dict, __event_emitter__=None
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
This is a demo
|
||||||
|
|
||||||
|
:param test: this is a test parameter
|
||||||
|
"""
|
||||||
|
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "status", # We set the type here
|
||||||
|
"data": {"description": "Message that shows up in the chat", "done": False},
|
||||||
|
# Note done is False here indicating we are still emitting statuses
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Do some other logic here
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "status",
|
||||||
|
"data": {"description": "Completed a task message", "done": True, "hidden": False},
|
||||||
|
# Note done is True here indicating we are done emitting statuses
|
||||||
|
# You can also set "hidden": True if you want to remove the status once the message is returned
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "status",
|
||||||
|
"data": {"description": f"An error occured: {e}", "done": True},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Tell the user: {e}"
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
#### Message
|
||||||
|
This type is used to append a message to the LLM at any stage in the Tool. This means that you can append messages, embed images, and even render web pages before, or after, or during the LLM response.
|
||||||
|
|
||||||
|
```
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "message", # We set the type here
|
||||||
|
"data": {"content": "This message will be appended to the chat."},
|
||||||
|
# Note that with message types we do NOT have to set a done condition
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
async def test_function(
|
||||||
|
self, prompt: str, __user__: dict, __event_emitter__=None
|
||||||
|
) -> str:
|
||||||
|
"""
|
||||||
|
This is a demo
|
||||||
|
|
||||||
|
:param test: this is a test parameter
|
||||||
|
"""
|
||||||
|
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "message", # We set the type here
|
||||||
|
"data": {"content": "This message will be appended to the chat."},
|
||||||
|
# Note that with message types we do NOT have to set a done condition
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
await __event_emitter__(
|
||||||
|
{
|
||||||
|
"type": "status",
|
||||||
|
"data": {"description": f"An error occured: {e}", "done": True},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return f"Tell the user: {e}"
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
#### 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:
|
||||||
|
|
||||||
|
```python
|
||||||
|
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.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
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"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## 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 OpenWebUI if you're not careful. You might be able to work around this by specifying `open-webui` itself as a requirement.
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example</summary>
|
||||||
|
|
||||||
|
```
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
@ -1,377 +1,78 @@
|
|||||||
---
|
---
|
||||||
sidebar_position: 2
|
sidebar_position: 2
|
||||||
title: "⚙️ Tools"
|
title: "⚙️ Tools"
|
||||||
---
|
---
|
||||||
|
|
||||||
## What are Tools?
|
# ⚙️ What are Tools?
|
||||||
Tools are python scripts that are provided to an LLM at the time of the request. Tools allow LLMs to perform actions and receive additional context as a result. Generally speaking, your LLM of choice will need to support function calling for tools to be reliably utilized.
|
|
||||||
|
|
||||||
Tools enable many use cases for chats, including web search, web scraping, and API interactions within the chat.
|
Tools are small Python scripts that add superpowers to your LLM. When enabled, they allow your chatbot to do amazing things — like search the web, scrape data, generate images, talk back using AI voices, and more.
|
||||||
|
|
||||||
Many Tools are available to use on the [Community Website](https://openwebui.com/tools) and can easily be imported into your Open WebUI instance.
|
To use Tools, your chosen LLM must support "function calling". Think of Tools as useful plugins that your AI can use when chatting with you.
|
||||||
|
|
||||||
## How can I use Tools?
|
---
|
||||||
[Once installed](#how-to-install-tools), Tools can be used by assigning them to any LLM that supports function calling and then enabling that Tool. To assign a Tool to a model, you need to navigate to Workspace => Models. Here you can select the model for which you’d like to enable any Tools.
|
|
||||||
|
|
||||||
Once you click the pencil icon to edit the model settings, scroll down to the Tools section and check any Tools you wish to enable. Once done you must click save.
|
# 🚀 What Can Tools Help Me Do?
|
||||||
|
|
||||||
Now that Tools are enabled for the model, you can click the “+” icon when chatting with an LLM to use various Tools. Please keep in mind that enabling a Tool does not force it to be used. It means the LLM will be provided the option to call this Tool.
|
Here are just a few examples of what Tools let your AI assistant do:
|
||||||
|
|
||||||
Lastly, we do provide a filter function on the community site that allows LLMs to autoselect Tools without you needing to enable them in the “+” icon menu: https://openwebui.com/f/hub/autotool_filter/
|
- 🌍 Web Search: Get real-time answers by searching the internet.
|
||||||
|
- 🖼️ Image Generation: Create images from your prompts.
|
||||||
|
- 🔊 Voice Output: Generate AI voices using ElevenLabs.
|
||||||
|
|
||||||
Please note: when using the AutoTool Filter, you will still need to take the steps above to enable the Tools per model.
|
Explore ready-to-use tools here:
|
||||||
|
🧰 [Tools Showcase](https://openwebui.com/tools)
|
||||||
|
|
||||||
## How to install Tools
|
---
|
||||||
The Tools import process is quite simple. You will have two options:
|
|
||||||
|
|
||||||
### Download and import manually
|
# 🔧 How to Use Tools in Open WebUI
|
||||||
Navigate to the community site: https://openwebui.com/tools/
|
|
||||||
1) Click on the Tool you wish to import
|
|
||||||
2) Click the blue “Get” button in the top right-hand corner of the page
|
|
||||||
3) Click “Download as JSON export”
|
|
||||||
4) You can now upload the Tool into Open WebUI by navigating to Workspace => Tools and clicking “Import Tools”
|
|
||||||
|
|
||||||
### Import via your Open WebUI URL
|
Once you've installed Tools (we’ll show you how below), here’s how to use them:
|
||||||
1) Navigate to the community site: https://openwebui.com/tools/
|
|
||||||
2) Click on the Tool you wish to import
|
|
||||||
3) Click the blue “Get” button in the top right-hand corner of the page
|
|
||||||
4) Enter the IP address of your Open WebUI instance and click “Import to WebUI” which will automatically open your instance and allow you to import the Tool.
|
|
||||||
|
|
||||||
Note: You can install your own Tools and other Tools not tracked on the community site using the manual import method. Please do not import Tools you do not understand or are not from a trustworthy source. Running unknown code is ALWAYS a risk.
|
1. Go to: Workspace ➡️ Models
|
||||||
|
2. Pick the model (like GPT-4 or LLaMa2) and click the ✏️ pencil icon to edit it.
|
||||||
|
3. Scroll down to the “Tools” section.
|
||||||
|
4. ✅ Check the Tools you want to enable and click Save.
|
||||||
|
|
||||||
## What sorts of things can Tools do?
|
Now, open a chat and click the ➕ plus icon to use Tools with your conversation!
|
||||||
Tools enable diverse use cases for interactive conversations by providing a wide range of functionality such as:
|
|
||||||
|
|
||||||
- [**Web Search**](https://openwebui.com/t/constliakos/web_search/): Perform live web searches to fetch real-time information.
|
💡 Tip: Enabling a Tool doesn't mean it will always be used — your AI will choose when it’s helpful. You can also use something called the AutoTool Filter to let the LLM pick the right Tool automatically.
|
||||||
- [**Image Generation**](https://openwebui.com/t/justinrahb/image_gen/): Generate images based on the user prompt
|
|
||||||
- [**External Voice Synthesis**](https://openwebui.com/t/justinrahb/elevenlabs_tts/): Make API requests within the chat to integrate external voice synthesis service ElevenLabs and generate audio based on the LLM output.
|
|
||||||
|
|
||||||
## Writing A Custom Toolkit
|
🔗 [AutoTool Filter](https://openwebui.com/f/hub/autotool_filter/)
|
||||||
|
|
||||||
Toolkits are defined in a single Python file, with a top level docstring with metadata and a `Tools` class.
|
🎯 Remember: Even when using AutoTool, you still have to enable Tools from the Model Settings!
|
||||||
|
|
||||||
### Example Top-Level Docstring
|
---
|
||||||
|
|
||||||
```python
|
# 📦 How to Install Tools
|
||||||
"""
|
|
||||||
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
|
There are two easy ways to install Tools in Open WebUI:
|
||||||
|
|
||||||
Tools have to be defined as methods within a class called `Tools`, with optional subclasses called `Valves` and `UserValves`, for example:
|
### Option 1: Manual Download & Import
|
||||||
|
|
||||||
```python
|
1. Visit the [Community Tool Library](https://openwebui.com/tools)
|
||||||
class Tools:
|
2. Click on a Tool you like.
|
||||||
def __init__(self):
|
3. Click the blue Get button > “Download as JSON export.”
|
||||||
"""Initialize the Tool."""
|
4. Go to Workspace ➡️ Tools in Open WebUI.
|
||||||
self.valves = self.Valves()
|
5. Click “Import Tools” and upload the downloaded file.
|
||||||
|
|
||||||
class Valves(BaseModel):
|
### Option 2: One-Click Import from the Web
|
||||||
api_key: str = Field("", description="Your API key here")
|
|
||||||
|
|
||||||
def reverse_string(self, string: str) -> str:
|
1. Go to [Community Tool Library](https://openwebui.com/tools)
|
||||||
"""
|
2. Choose a Tool, then click the blue Get button.
|
||||||
Reverses the input string.
|
3. Enter your Open WebUI instance’s IP address or URL.
|
||||||
:param string: The string to reverse
|
4. Click “Import to WebUI” — done!
|
||||||
"""
|
|
||||||
# example usage of valves
|
|
||||||
if self.valves.api_key != "42":
|
|
||||||
return "Wrong API key"
|
|
||||||
return string[::-1]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Type Hints
|
🛑 Safety Tip: Never import a Tool you don’t recognize or trust. These are Python scripts and might run unsafe code.
|
||||||
Each tool must have type hints for arguments. As of version OpenWebUI version 0.4.3, 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 to allow users to provide dynamic details such as an API key or a configuration option. These will create a fillable field or a bool switch in the GUI menu for the given function.
|
# 🧠 Summary
|
||||||
|
|
||||||
Valves are configurable by admins alone and UserValves are configurable by any users.
|
Tools are add-ons that help your AI model do much more than just chat. From answering real-time questions to generating images or speaking out loud — Tools bring your AI to life.
|
||||||
|
|
||||||
<details>
|
- Visit: [https://openwebui.com/tools](https://openwebui.com/tools) to discover new Tools.
|
||||||
<summary>Commented example</summary>
|
- Install them manually or with one-click.
|
||||||
|
- Enable them per model from Workspace ➡️ Models.
|
||||||
```
|
- Use them in chat by clicking ➕
|
||||||
from pydantic import BaseModel, Field
|
|
||||||
|
|
||||||
class Tools:
|
Now go make your AI waaaaay smarter 🤖✨
|
||||||
# Notice the current indentation: Valves and UserValves must be declared as
|
|
||||||
# attributes of a Tools, Filter or Pipe class. Here we take the
|
|
||||||
# example of a Tool.
|
|
||||||
class Valves(BaseModel):
|
|
||||||
# Valves and UserValves inherit from pydantic's BaseModel. This
|
|
||||||
# enables complex use cases like model validators etc.
|
|
||||||
test_valve: int = Field( # Notice the type hint: it is used to
|
|
||||||
# choose the kind of UI element to show the user (buttons,
|
|
||||||
# texts, etc).
|
|
||||||
default=4,
|
|
||||||
description="A valve controlling a numberical value"
|
|
||||||
# required=False, # you can enforce fields using True
|
|
||||||
)
|
|
||||||
pass
|
|
||||||
# Note that this 'pass' helps for parsing and is recommended.
|
|
||||||
|
|
||||||
# UserValves are defined the same way.
|
|
||||||
class UserValves(BaseModel):
|
|
||||||
test_user_valve: bool = Field(
|
|
||||||
default=False, description="A user valve controlling a True/False (on/off) switch"
|
|
||||||
)
|
|
||||||
pass
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.valves = self.Valves()
|
|
||||||
# Because they are set by the admin, they are accessible directly
|
|
||||||
# upon code execution.
|
|
||||||
pass
|
|
||||||
|
|
||||||
# The __user__ handling is the same for Filters, Tools and Functions.
|
|
||||||
def test_the_tool(self, message: str, __user__: dict):
|
|
||||||
"""
|
|
||||||
This is a test tool. If the user asks you to test the tools, put any
|
|
||||||
string you want in the message argument.
|
|
||||||
|
|
||||||
:param message: Any string you want.
|
|
||||||
:return: The same string as input.
|
|
||||||
"""
|
|
||||||
# Because UserValves are defined per user they are only available
|
|
||||||
# on use.
|
|
||||||
# Note that although __user__ is a dict, __user__["valves"] is a
|
|
||||||
# UserValves object. Hence you can access values like that:
|
|
||||||
test_user_valve = __user__["valves"].test_user_valve
|
|
||||||
# Or:
|
|
||||||
test_user_valve = dict(__user__["valves"])["test_user_valve"]
|
|
||||||
# But this will return the default value instead of the actual value:
|
|
||||||
# test_user_valve = __user__["valves"]["test_user_valve"] # Do not do that!
|
|
||||||
|
|
||||||
return message + f"\nThe user valve set value is: {test_user_valve}"
|
|
||||||
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Optional Arguments
|
|
||||||
Below is a list of optional arguments your tools can depend on:
|
|
||||||
- `__event_emitter__`: Emit events (see following section)
|
|
||||||
- `__event_call__`: Same as event emitter but can be used for user interactions
|
|
||||||
- `__user__`: A dictionary with user information. It also contains the `UserValves` object in `__user__["valves"]`.
|
|
||||||
- `__metadata__`: Dictionary with chat metadata
|
|
||||||
- `__messages__`: List of previous messages
|
|
||||||
- `__files__`: Attached files
|
|
||||||
- `__model__`: Model name
|
|
||||||
|
|
||||||
Just add them as argument to any method of your Tool class just like `__user__` in the example above.
|
|
||||||
|
|
||||||
### Event Emitters
|
|
||||||
Event Emitters are used to add additional information to the chat interface. Similarly to Filter Outlets, Event Emitters are capable of appending content to the chat. Unlike Filter Outlets, they are not capable of stripping information. Additionally, emitters can be activated at any stage during the Tool.
|
|
||||||
|
|
||||||
There are two different types of Event Emitters:
|
|
||||||
|
|
||||||
If the model seems to be unable to call the tool, make sure it is enabled (either via the Model page or via the `+` sign next to the chat input field). You can also turn the `Function Calling` argument of the `Advanced Params` section of the Model page from `Default` to `Native`.
|
|
||||||
|
|
||||||
#### Status
|
|
||||||
This is used to add statuses to a message while it is performing steps. These can be done at any stage during the Tool. These statuses appear right above the message content. These are very useful for Tools that delay the LLM response or process large amounts of information. This allows you to inform users what is being processed in real-time.
|
|
||||||
|
|
||||||
```
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "status", # We set the type here
|
|
||||||
"data": {"description": "Message that shows up in the chat", "done": False, "hidden": False},
|
|
||||||
# Note done is False here indicating we are still emitting statuses
|
|
||||||
}
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Example</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
async def test_function(
|
|
||||||
self, prompt: str, __user__: dict, __event_emitter__=None
|
|
||||||
) -> str:
|
|
||||||
"""
|
|
||||||
This is a demo
|
|
||||||
|
|
||||||
:param test: this is a test parameter
|
|
||||||
"""
|
|
||||||
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "status", # We set the type here
|
|
||||||
"data": {"description": "Message that shows up in the chat", "done": False},
|
|
||||||
# Note done is False here indicating we are still emitting statuses
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Do some other logic here
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "status",
|
|
||||||
"data": {"description": "Completed a task message", "done": True, "hidden": False},
|
|
||||||
# Note done is True here indicating we are done emitting statuses
|
|
||||||
# You can also set "hidden": True if you want to remove the status once the message is returned
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "status",
|
|
||||||
"data": {"description": f"An error occured: {e}", "done": True},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return f"Tell the user: {e}"
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
#### Message
|
|
||||||
This type is used to append a message to the LLM at any stage in the Tool. This means that you can append messages, embed images, and even render web pages before, or after, or during the LLM response.
|
|
||||||
|
|
||||||
```
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "message", # We set the type here
|
|
||||||
"data": {"content": "This message will be appended to the chat."},
|
|
||||||
# Note that with message types we do NOT have to set a done condition
|
|
||||||
}
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Example</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
async def test_function(
|
|
||||||
self, prompt: str, __user__: dict, __event_emitter__=None
|
|
||||||
) -> str:
|
|
||||||
"""
|
|
||||||
This is a demo
|
|
||||||
|
|
||||||
:param test: this is a test parameter
|
|
||||||
"""
|
|
||||||
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "message", # We set the type here
|
|
||||||
"data": {"content": "This message will be appended to the chat."},
|
|
||||||
# Note that with message types we do NOT have to set a done condition
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
await __event_emitter__(
|
|
||||||
{
|
|
||||||
"type": "status",
|
|
||||||
"data": {"description": f"An error occured: {e}", "done": True},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return f"Tell the user: {e}"
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
#### 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:
|
|
||||||
|
|
||||||
```python
|
|
||||||
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.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Example</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
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"},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## 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 OpenWebUI if you're not careful. You might be able to work around this by specifying `open-webui` itself as a requirement.
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Example</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
"""
|
|
||||||
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
|
|
||||||
"""
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
Loading…
Reference in New Issue
Block a user