From 34a8031e2cc3a586181e510e23dfe0bab78da864 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 11 Oct 2026 19:46:48 +0200 Subject: [PATCH 1/8] Fix the outlet note for direct API calls The API endpoints page still said released versions never run outlet filters for direct API calls. They have run them by default since v0.10.0, so the page now describes that as current behaviour and keeps the older behaviour as a short note. --- docs/reference/api-endpoints.md | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/docs/reference/api-endpoints.md b/docs/reference/api-endpoints.md index 375f91017b..7edee4f11a 100644 --- a/docs/reference/api-endpoints.md +++ b/docs/reference/api-endpoints.md @@ -349,11 +349,11 @@ Open WebUI accepts both **API keys** (prefixed with `sk-`) and **JWT tokens** fo #### Filter Execution -| Filter Function | WebUI Request | Direct API, stable (`main`) | Direct API, pre-release (`dev`) | -|----------------|--------------|------------------------------|-----------------------------------| -| `inlet()` | ✅ Runs | ✅ Runs | ✅ Runs | -| `stream()` | ✅ Runs | ✅ Runs | ✅ Runs | -| `outlet()` | ✅ Runs | ❌ Not called by `/api/chat/completions`, use `/api/chat/completed` | ✅ Runs inline by default, gated by `ENABLE_API_OUTLET_FILTERS` (see below) | +| Filter Function | WebUI Request | Direct API | +|----------------|--------------|------------| +| `inlet()` | ✅ Runs | ✅ Runs | +| `stream()` | ✅ Runs | ✅ Runs | +| `outlet()` | ✅ Runs | ✅ Runs inline by default, gated by `ENABLE_API_OUTLET_FILTERS` (see below) | The `inlet()` function always executes, making it ideal for: - **Rate limiting**: Track and limit requests per user @@ -361,20 +361,18 @@ The `inlet()` function always executes, making it ideal for: - **Input validation**: Reject invalid requests before they reach the model :::danger Outlet Behavior for Direct API Calls, Read Carefully -**On tagged releases / `main`:** `outlet()` is **not** invoked inline by `/api/chat/completions` at all. It only runs if the caller performs the second POST to `/api/chat/completed`. For now, if your integration needs `outlet()`, you must still do that second call. - -**On `dev` / pre-release builds:** `outlet()` runs inline after `/api/chat/completions` **by default**, on **both** the streaming and non-streaming paths, gated by [`ENABLE_API_OUTLET_FILTERS`](/reference/env-configuration#enable_api_outlet_filters) (default `True`). A `chat_id` and a message `id` are **not** required: when neither is in the request body, the conversation is reconstructed from the `messages` you sent plus the assistant reply, and a message ID is generated for it. Set `ENABLE_API_OUTLET_FILTERS=False` to turn inline execution off for direct API traffic. +Since v0.10.0, `outlet()` runs inline after `/api/chat/completions` **by default**, on **both** the streaming and non-streaming paths, gated by [`ENABLE_API_OUTLET_FILTERS`](/reference/env-configuration#enable_api_outlet_filters) (default `True`). A `chat_id` and a message `id` are **not** required: when neither is in the request body, the conversation is reconstructed from the `messages` you sent plus the assistant reply, and a message ID is generated for it. Set `ENABLE_API_OUTLET_FILTERS=False` to turn inline execution off for direct API traffic. Before v0.10.0, `outlet()` only ran when the caller sent the second POST to `/api/chat/completed`. What `chat_id` and `id` decide is where the response goes. Send both and the request takes the path built for the WebUI: the server consumes the upstream stream itself and routes the content to the user's WebSocket, so the HTTP response to a streaming caller is effectively empty. Omit them and the upstream stream is relayed to you over HTTP as usual, with `outlet()` running once it has finished. In every case, **`outlet()` does not rewrite the HTTP response body**. It updates the persisted chat message and emits a `chat:outlet` WebSocket event, but the JSON your client receives is the pre-outlet content. If you need the outlet-filtered text, read it back from the chat record, subscribe to the WebSocket, or keep using `/api/chat/completed`. -**Practical guidance:** if you are a pure API consumer (Continue.dev, Claude Code, custom scripts, Langfuse pipelines, etc.) and you need `outlet()`'s output back over HTTP, follow the completion with `/api/chat/completed`. Inline execution still runs your outlet filters and their side effects; it just does not hand you the filtered payload. +**Practical guidance:** if you are a pure API consumer (Continue.dev, Claude Code, custom scripts, etc.) and you need `outlet()`'s output back over HTTP, follow the completion with `/api/chat/completed`. Inline execution still runs your outlet filters and their side effects; it just does not hand you the filtered payload. ::: #### Legacy / Supported-for-API Endpoint: `/api/chat/completed` -`POST /api/chat/completed` is the endpoint that reliably runs `outlet()` for direct API integrations. On `dev` it is marked deprecated in favor of inline execution, but as described above, inline execution does not currently return the filtered payload to pure API callers, so in practice `/api/chat/completed` remains the right call for most API integrations today. +`POST /api/chat/completed` is the endpoint that reliably runs `outlet()` for direct API integrations. It is marked deprecated since v0.10.0, when inline execution arrived, but as described above, inline execution does not currently return the filtered payload to pure API callers, so in practice `/api/chat/completed` remains the right call for most API integrations today. - **Endpoint**: `POST /api/chat/completed` - **Description**: Runs `outlet()` filters (and pipeline outlet filters) unconditionally over a completed chat payload. Returns the filtered payload. @@ -403,11 +401,10 @@ In every case, **`outlet()` does not rewrite the HTTP response body**. It update def complete_chat_with_outlet(token, model, messages, chat_id=None): """ - Second-step call that actually runs outlet() for direct API callers. - On tagged releases /api/chat/completions does not run outlet inline at all. - On dev it runs inline by default but does not rewrite the HTTP response - body, so this endpoint is still the right call for most API integrations - that want outlet's output over HTTP. + Second-step call that returns outlet()'s output to direct API callers. + /api/chat/completions runs outlet inline by default but does not rewrite + the HTTP response body, so this endpoint is still the right call for API + integrations that want outlet's output over HTTP. """ url = 'http://localhost:3000/api/chat/completed' headers = { From 842e52f78ffe65fc69a36cd0c9953a9da4dcbd4b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 12 Oct 2026 10:38:20 +0400 Subject: [PATCH 2/8] refac --- docs/alternatives/onyx.mdx | 8 +-- .../advanced-topics/scaling.md | 58 ++++++++++++++----- docs/intro.mdx | 4 +- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/docs/alternatives/onyx.mdx b/docs/alternatives/onyx.mdx index c56558f0fc..d599c82814 100644 --- a/docs/alternatives/onyx.mdx +++ b/docs/alternatives/onyx.mdx @@ -19,13 +19,7 @@ import Head from '@docusaurus/Head'; [Onyx](https://onyx.app/) (formerly Danswer) focuses on a specific and important problem: connecting AI to your organization's internal knowledge across Slack, Google Drive, Confluence, Jira, GitHub, and dozens of other tools, with permission-aware retrieval. If your team's knowledge is scattered across many tools and you need AI to search across all of them while respecting access controls, that's Onyx's sweet spot. -:::info How to check this page - -Everything claimed here about Open WebUI is verifiable in our own documentation, linked throughout. Everything about Onyx comes from Onyx's own documentation, repository and licence terms, all linked below, and describes their project as of the date above. Onyx ships quickly, so treat anything undated as possibly out of date and check their sources before deciding. - -If something here is wrong or has aged badly, including in Onyx's favour, [tell us](https://github.com/open-webui/docs/issues) and we will correct it. - -::: +Spotted an error or outdated information? [Let us know](https://github.com/open-webui/docs/issues). [GitHub](https://github.com/onyx-dot-app/onyx) · [Source Available](https://github.com/onyx-dot-app/onyx/blob/main/LICENSE) (MIT core + Onyx Enterprise License for `ee/` directories) · [Self-Host Terms](https://onyx.app/legal/self-host) diff --git a/docs/getting-started/advanced-topics/scaling.md b/docs/getting-started/advanced-topics/scaling.md index 728032ae05..f56ab9fe19 100644 --- a/docs/getting-started/advanced-topics/scaling.md +++ b/docs/getting-started/advanced-topics/scaling.md @@ -19,12 +19,17 @@ Open WebUI defaults to a **self-contained, single-instance deployment**. The sta - **Embedded SQLite** for application data on a persistent volume - **Embedded ChromaDB** (also backed by SQLite) for RAG embeddings +- **Local file storage** (`STORAGE_PROVIDER=local`) for uploads under `DATA_DIR/uploads` - **A single Uvicorn worker**, with no external database or Redis required This approach was chosen to **minimize time to deployment and operational overhead**: you can start using Open WebUI without first provisioning separate database or coordination services. Keeping these dependencies local also simplifies **air-gapped deployment** when models and required assets are provisioned within the isolated environment. **Horizontal scaling requires shared persistence and coordination**, so every replica operates on the same data. Before adding replicas or workers, replace the embedded database configuration with PostgreSQL and a client-server vector database, configure shared file storage, and add Redis for coordination. This separates state from individual instances, allowing the **stateless application tier** to scale independently behind a load balancer. +:::warning External databases do not share uploaded files +PostgreSQL stores file metadata and storage paths, while the vector database stores embeddings. Neither replaces file storage. Before adding replicas, configure **external object storage (S3, GCS, or Azure Blob)** or a **shared filesystem** accessible to every replica. Separate local volumes leave attachments unavailable when a request reaches another instance. See [Step 5](#step-5-share-file-storage-across-instances). +::: + --- ## Step 1: Switch to PostgreSQL @@ -315,28 +320,28 @@ For maximum scalability in self-hosted environments, **Milvus** and **Qdrant** b ## Step 5: Share File Storage Across Instances -**When:** You're running multiple instances that need to share uploaded files, generated images, and other user data. +**When:** You're running multiple instances. **Shared access to uploaded files is required** for attachments, knowledge documents, and generated images to work across replicas. By default, Open WebUI stores uploaded files on the local filesystem under `DATA_DIR` (typically `/app/backend/data`). In a multi-instance setup, each instance needs access to the same files. Without shared storage, you will see [uploaded files and RAG knowledge become inaccessible](/troubleshooting/multi-replica#5-uploaded-files-or-rag-knowledge-inaccessible) when requests hit different replicas. ### Do I need cloud storage (S3)? -**Not necessarily.** Open WebUI stores all uploaded files with **UUID-based unique filenames**. Multiple processes and replicas only ever **create new files** or **read existing ones**: they never write to the same file simultaneously. This means a simple **shared filesystem mount** works correctly without write conflicts under normal operation. Though you have to ensure, that all workers/replicas have access to the very same shared DATA_DIR directory in a shared storage. +**External object storage is one option; shared file access is the requirement.** Use S3, GCS, or Azure Blob to keep uploaded files independent of individual containers, or keep `STORAGE_PROVIDER=local` and mount the same shared filesystem at the same path on every replica. UUID-based upload names avoid collisions between new uploads, but do not eliminate concurrent access to existing files or local working copies. **Your options:** | Approach | When to Use | |---|---| -| **Shared filesystem** (NFS, AWS EFS, CephFS, GlusterFS, or a simple shared Docker volume) | The simplest option for most deployments. Mount the same directory to `/app/backend/data` on all instances. Works well for on-prem, Docker Swarm, and Kubernetes with ReadWriteMany (RWX) volumes. | -| **Cloud object storage** (S3, GCS, Azure Blob) | Better for cloud-native deployments at very large scale, or when you want managed durability (11 nines) and don't want to manage shared filesystems. Requires setting `STORAGE_PROVIDER`. | +| **Shared filesystem** (NFS, AWS EFS, CephFS, or a shared volume on one host) | Use when you already operate shared storage. Mount the same directory at the same path on all instances; multi-node Kubernetes deployments need storage supporting ReadWriteMany (RWX). | +| **External object storage** (S3, GCS, Azure Blob) | Use when replicas run on separate hosts or need uploaded files to survive container replacement without a shared upload volume. Configure `STORAGE_PROVIDER` and the same bucket/container on every replica. | :::info What does STORAGE_PROVIDER actually control? -`STORAGE_PROVIDER` only controls where **uploaded files** are stored (documents, images, etc.). It does **not** affect the main database (use `DATABASE_URL` for that) or the vector database (use `VECTOR_DB` for that). When left unset, files are stored on the local filesystem under `DATA_DIR`. +`STORAGE_PROVIDER` controls files saved through Open WebUI's file upload API, including documents, attachments, and generated images. It does **not** move the main database (use `DATABASE_URL`), the vector database (use `VECTOR_DB`), or the entire `DATA_DIR` to object storage. Files served directly from `/cache/`, such as some tool outputs, still use the filesystem and need shared access if another replica must serve them. ::: ### Option A: Shared Filesystem (Simplest) -No configuration changes needed, just ensure all instances mount the same directory: +Keep `STORAGE_PROVIDER=local` and ensure all instances mount the same directory at the same path: **Example Kubernetes:** ```yaml @@ -352,6 +357,8 @@ volumes: - /opt/data/openwebui-data:/app/backend/data ``` +This bind mount shares files only between containers on the **same host**. On separate hosts, the source directory must itself be backed by shared storage. Giving Docker volumes the same name on different hosts does not share their contents. + :::warning Do **not** store the SQLite database on a network filesystem. SQLite's file locking does not work reliably over NFS. This is another reason to switch to PostgreSQL (Step 1) before scaling to multiple instances. ::: @@ -360,7 +367,7 @@ Once your data directory is shared, lock down what can land in it: see [File upl ### Option B: Cloud Object Storage -Set `STORAGE_PROVIDER` and the corresponding credentials: +Set `STORAGE_PROVIDER` and the corresponding bucket/container and credentials on **every replica**. All replicas must use the same storage destination, including the same `S3_KEY_PREFIX` if configured, with permission to read, write, and delete files. **Supported providers:** @@ -370,13 +377,31 @@ Set `STORAGE_PROVIDER` and the corresponding credentials: | Google Cloud Storage | `gcs` | | Microsoft Azure Blob Storage | `azure` | -``` +```bash STORAGE_PROVIDER=s3 S3_BUCKET_NAME=my-openwebui-bucket S3_REGION_NAME=us-east-1 + +# For an S3-compatible service, also set its endpoint: +# S3_ENDPOINT_URL=https://s3.example.com +# S3_ADDRESSING_STYLE=path ``` -Each provider has its own set of environment variables for credentials and bucket configuration. See the [Environment Variable Reference](/reference/env-configuration#cloud-storage) for details. +For S3, omit `S3_ACCESS_KEY_ID` and `S3_SECRET_ACCESS_KEY` to use the default AWS credential chain (for example, an IAM role), or supply both through your deployment's secret management. GCS uses `GCS_BUCKET_NAME` with application default credentials or `GOOGLE_APPLICATION_CREDENTIALS_JSON`. Azure uses `AZURE_STORAGE_ENDPOINT` and `AZURE_STORAGE_CONTAINER_NAME`, with `AZURE_STORAGE_KEY` or the default Azure credential. The slim image supports only `local` and `s3`; use the standard image for GCS or Azure. + +See the [Environment Variable Reference](/reference/env-configuration#cloud-storage) for all provider settings and the [S3 Storage tutorial](/tutorials/maintenance/s3-storage) for a worked example. + +:::warning Object storage still needs local disk +Cloud providers first write uploads to `DATA_DIR/uploads`, then upload them to the bucket/container. Reads download files there before Open WebUI processes or serves them. Give every replica a writable data directory with enough disk space and I/O capacity for concurrent uploads and downloads. + +`STORAGE_LOCAL_CACHE=false` removes cloud-backed local copies after the file-processing handler finishes. It does **not** eliminate temporary disk use or clean up every download and unprocessed upload. Plan local disk capacity even with this setting enabled. +::: + +### Switching an Existing Deployment + +Changing `STORAGE_PROVIDER` does **not** migrate existing files or rewrite their stored paths. Plan the transfer of existing objects and corresponding file records before switching providers; simply copying files into a bucket is insufficient. Back up both the application database and files before the move. + +Before sending production traffic to multiple replicas, upload a file through one replica and download it through another. Verify knowledge-document access and generated images too, then repeat after replacing the uploading replica. This catches configurations that appear to work only because the original local files are still present. --- @@ -492,12 +517,15 @@ REDIS_URL=redis://redis-host:6379/0 WEBSOCKET_MANAGER=redis ENABLE_WEBSOCKET_SUPPORT=true -# Storage — pick ONE: -# Option A: shared filesystem (no env vars needed, just mount the same volume) -# Option B: cloud storage +# File storage — REQUIRED across replicas; configure ONE option on all of them: +# Option A: STORAGE_PROVIDER=local with the same shared filesystem and mount path +# Separate per-host Docker volumes do not share files. +# Option B: external object storage (same bucket and any key prefix on all replicas) # STORAGE_PROVIDER=s3 # S3_BUCKET_NAME=my-openwebui-bucket # S3_REGION_NAME=us-east-1 +# Supply credentials via an IAM role or your deployment's secret management. +# Object storage still needs writable local disk; see Step 5. # Content Extraction (do NOT use default pypdf in production) CONTENT_EXTRACTION_ENGINE=tika @@ -573,8 +601,8 @@ Beyond this short list, the Hardening guide groups the same concerns by topic so | Single user / evaluation | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ | | Small team (< 50 users, single instance) | Recommended | Recommended† | ✗ | Recommended | ✗ | ✗ | | Multiple Uvicorn workers | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | ✗ (same filesystem) | -| Multiple instances / HA | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | **Optional** (NFS or S3) | -| Large scale (1000+ users) | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | **Optional** (NFS or S3) | +| Multiple instances / HA | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | **Required** (shared filesystem or object storage) | +| Large scale (1000+ users) | **Required** | **Required** | **Required** | **Strongly Recommended** | **Strongly Recommended** | **Required across replicas** | @@ -585,5 +613,5 @@ The default ChromaDB uses a local SQLite backend that crashes under multi-proces ::: :::note About "Shared Storage" -For multiple instances, all replicas need access to the same uploaded files. A **shared filesystem mount** (local drive, NFS, EFS, CephFS) is sufficient. Cloud object storage (S3/GCS/Azure) is a scalable alternative, but not a requirement. Files use UUID-based unique names, so there are no write conflicts. See [Step 5](#step-5-share-file-storage-across-instances) for details. +For multiple instances, all replicas must access the same uploaded files through **external object storage** (S3/GCS/Azure) or a **shared filesystem** (NFS, EFS, CephFS, or a volume shared on one host). External object storage is optional; shared file access is not. Object storage still needs local working space and does not cover files served directly from `/cache/`. See [Step 5](#step-5-share-file-storage-across-instances) for configuration and migration guidance. ::: diff --git a/docs/intro.mdx b/docs/intro.mdx index 194f2d18a8..cfa54bcd02 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -55,9 +55,7 @@ Then open [http://localhost:3000](http://localhost:3000). For GPU support, Docker Compose, and more → [Quick Start](/getting-started/quick-start) and [Docker images and tags](/getting-started/quick-start#image-variants) :::tip Pick the right image -`:main` above is the batteries-included one: it carries the embedding, speech and reranking models, document extraction and every database client, so retrieval, uploads and voice work the moment it starts. - -**`:slim` is 196 MB instead of 1.62 GB, 88% less to download, with the same chat experience.** Choose it when your models run through a hosted API, your own model server or a separate Ollama instance. Change the tag above to `:slim` (also called `:main-slim`) and connect your provider; the default database and file storage work as usual. Features such as knowledge search and voice need external services. These are compressed Linux/amd64 sizes, checked on October 10, 2026; see [Why choose slim?](/getting-started/quick-start#what-slim-leaves-out) for details. +Use `:main` for built-in embeddings, document extraction and speech recognition. For chat through an API or a separate Ollama instance, switch to `:slim`—**about 88% smaller**. Knowledge search and voice require external services. [Why choose slim?](/getting-started/quick-start#what-slim-leaves-out) ::: From b3d4535cb331ee35d82fb17954b13c2cbc2e9f1c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 12 Oct 2026 10:41:47 +0400 Subject: [PATCH 3/8] refac --- docs/intro.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/intro.mdx b/docs/intro.mdx index cfa54bcd02..202b6caa55 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -55,7 +55,7 @@ Then open [http://localhost:3000](http://localhost:3000). For GPU support, Docker Compose, and more → [Quick Start](/getting-started/quick-start) and [Docker images and tags](/getting-started/quick-start#image-variants) :::tip Pick the right image -Use `:main` for built-in embeddings, document extraction and speech recognition. For chat through an API or a separate Ollama instance, switch to `:slim`—**about 88% smaller**. Knowledge search and voice require external services. [Why choose slim?](/getting-started/quick-start#what-slim-leaves-out) +Use `:main` for built-in embeddings, document extraction and speech recognition. Choose `:slim` for a smaller download: **196 MB instead of 1.62 GB (88% smaller)**. It relies on external services for those features. [Why choose slim?](/getting-started/quick-start#what-slim-leaves-out) ::: From 486110e9a215a1c76735a31c896ad2d540a72ffd Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 12 Oct 2026 08:19:43 +0200 Subject: [PATCH 4/8] Document the Tool Search backend requirement Tool Search has the model call deferred tools that are not in the tool list sent to the provider. Backends that only allow calls to listed tools, such as the llama.cpp server, can never make those calls, so the docs now say so and name the two settings that work there. --- docs/features/extensibility/plugin/tools/index.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/features/extensibility/plugin/tools/index.mdx b/docs/features/extensibility/plugin/tools/index.mdx index b4a71ae3a2..b6aec6f712 100644 --- a/docs/features/extensibility/plugin/tools/index.mdx +++ b/docs/features/extensibility/plugin/tools/index.mdx @@ -317,6 +317,7 @@ How it works: - **How the model loads a tool.** The model calls `search_tools` with a few keywords or an exact tool name, plus an optional `count` (default `5`, at most `20`). It gets back the full definitions of the best matches and then calls the tool by name like any other. An exact tool name returns that tool alone. Otherwise each deferred tool is ranked by how well the query matches its name, description and parameter names. - **Prompt caching.** Loading a tool through search leaves the tool list sent to the provider as it was. The tool list and the `` block only change when the set of enabled tools changes, so the cached prefix holds across tool rounds and turns. See [Prompt Caching](/features/chat-conversations/prompt-caching). - **Tool approval.** With **Ask for approval** on, `search_tools` asks for approval like any other tool, so using a deferred tool typically takes two approvals: one for the search and one for the tool itself. +- **Backend requirement.** The model calls deferred tools that are not in the tool list sent to the provider, so Tool Search needs a backend that accepts such calls. A backend that limits tool calls to the tools in that list, such as the llama.cpp server, can only call the tools sent in full. On such a backend, add the tools you need to **Always Loaded Tools** or turn Tool Search off. Write Always Loaded patterns against the [tool names the model sees](/features/extensibility/mcp#tool-names-the-model-sees). MCP tools carry their server's ID as a prefix (a `get_issue` tool on a server with the ID `github` is named `github_get_issue`), so `github_*` keeps every tool of that server loaded. From 631d524006390fdcc9e55e4e99622270a8a3124c Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 12 Oct 2026 08:42:10 +0200 Subject: [PATCH 5/8] Name the backends that Tool Search does not work on Testing against real providers showed that the OpenAI API, on both Chat Completions and Responses, and xAI also never call tools missing from the tool list, the same as the llama.cpp server. The Tool Search backend note now names them. --- docs/features/extensibility/plugin/tools/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/extensibility/plugin/tools/index.mdx b/docs/features/extensibility/plugin/tools/index.mdx index b6aec6f712..61ab8ce739 100644 --- a/docs/features/extensibility/plugin/tools/index.mdx +++ b/docs/features/extensibility/plugin/tools/index.mdx @@ -317,7 +317,7 @@ How it works: - **How the model loads a tool.** The model calls `search_tools` with a few keywords or an exact tool name, plus an optional `count` (default `5`, at most `20`). It gets back the full definitions of the best matches and then calls the tool by name like any other. An exact tool name returns that tool alone. Otherwise each deferred tool is ranked by how well the query matches its name, description and parameter names. - **Prompt caching.** Loading a tool through search leaves the tool list sent to the provider as it was. The tool list and the `` block only change when the set of enabled tools changes, so the cached prefix holds across tool rounds and turns. See [Prompt Caching](/features/chat-conversations/prompt-caching). - **Tool approval.** With **Ask for approval** on, `search_tools` asks for approval like any other tool, so using a deferred tool typically takes two approvals: one for the search and one for the tool itself. -- **Backend requirement.** The model calls deferred tools that are not in the tool list sent to the provider, so Tool Search needs a backend that accepts such calls. A backend that limits tool calls to the tools in that list, such as the llama.cpp server, can only call the tools sent in full. On such a backend, add the tools you need to **Always Loaded Tools** or turn Tool Search off. +- **Backend requirement.** The model calls deferred tools that are not in the tool list sent to the provider, so Tool Search needs a backend that accepts such calls. A backend that limits tool calls to the tools in that list, such as the OpenAI API (both Chat Completions and Responses), xAI and the llama.cpp server, can only call the tools sent in full. On such a backend, add the tools you need to **Always Loaded Tools** or turn Tool Search off. Write Always Loaded patterns against the [tool names the model sees](/features/extensibility/mcp#tool-names-the-model-sees). MCP tools carry their server's ID as a prefix (a `get_issue` tool on a server with the ID `github` is named `github_get_issue`), so `github_*` keeps every tool of that server loaded. From 2e67d208cdb9ca2c49d458c29b9e2ed1704ff84d Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 12 Oct 2026 08:47:23 +0200 Subject: [PATCH 6/8] Name the backends Tool Search was tested to work on The Tool Search backend note now also lists the providers where the model does call deferred tools: Anthropic, Google Gemini, Mistral, Alibaba (Qwen) and CoreWeave (Llama 3.3). Through OpenRouter the result follows the provider the request is routed to. --- docs/features/extensibility/plugin/tools/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/features/extensibility/plugin/tools/index.mdx b/docs/features/extensibility/plugin/tools/index.mdx index 61ab8ce739..785d1d1807 100644 --- a/docs/features/extensibility/plugin/tools/index.mdx +++ b/docs/features/extensibility/plugin/tools/index.mdx @@ -317,7 +317,7 @@ How it works: - **How the model loads a tool.** The model calls `search_tools` with a few keywords or an exact tool name, plus an optional `count` (default `5`, at most `20`). It gets back the full definitions of the best matches and then calls the tool by name like any other. An exact tool name returns that tool alone. Otherwise each deferred tool is ranked by how well the query matches its name, description and parameter names. - **Prompt caching.** Loading a tool through search leaves the tool list sent to the provider as it was. The tool list and the `` block only change when the set of enabled tools changes, so the cached prefix holds across tool rounds and turns. See [Prompt Caching](/features/chat-conversations/prompt-caching). - **Tool approval.** With **Ask for approval** on, `search_tools` asks for approval like any other tool, so using a deferred tool typically takes two approvals: one for the search and one for the tool itself. -- **Backend requirement.** The model calls deferred tools that are not in the tool list sent to the provider, so Tool Search needs a backend that accepts such calls. A backend that limits tool calls to the tools in that list, such as the OpenAI API (both Chat Completions and Responses), xAI and the llama.cpp server, can only call the tools sent in full. On such a backend, add the tools you need to **Always Loaded Tools** or turn Tool Search off. +- **Backend requirement.** The model calls deferred tools that are not in the tool list sent to the provider, so Tool Search needs a backend that accepts such calls. Anthropic, Google Gemini, Mistral, Alibaba (Qwen) and CoreWeave (Llama 3.3) do. Through OpenRouter, it depends on the provider the request is routed to. A backend that limits tool calls to the tools in that list, such as the OpenAI API (both Chat Completions and Responses), xAI and the llama.cpp server, can only call the tools sent in full. On such a backend, add the tools you need to **Always Loaded Tools** or turn Tool Search off. Write Always Loaded patterns against the [tool names the model sees](/features/extensibility/mcp#tool-names-the-model-sees). MCP tools carry their server's ID as a prefix (a `get_issue` tool on a server with the ID `github` is named `github_get_issue`), so `github_*` keeps every tool of that server loaded. From ff5c796562e458c73a80028a1ba382ab4490c589 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 12 Oct 2026 10:53:30 +0400 Subject: [PATCH 7/8] refac --- docs/intro.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/intro.mdx b/docs/intro.mdx index 202b6caa55..4b907c14c3 100644 --- a/docs/intro.mdx +++ b/docs/intro.mdx @@ -40,6 +40,12 @@ Open WebUI is **a home for AI**, a self-hosted AI platform that's **[extensible] docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data -e WEBUI_SECRET_KEY=your-secret-key --name open-webui --restart always ghcr.io/open-webui/open-webui:main ``` +For GPU support, Docker Compose, and more → [Quick Start](/getting-started/quick-start) and [Docker images and tags](/getting-started/quick-start#image-variants) + +:::tip Pick the right image +Use `:main` for built-in embeddings, document extraction and speech recognition. Choose `:slim` for a smaller download: **196 MB instead of 1.62 GB (88% smaller)**. It relies on external services for those features. [Why choose slim?](/getting-started/quick-start#what-slim-leaves-out) +::: + Then open [http://localhost:3000](http://localhost:3000). Open Terminal and some of our amazing community built plugins.

-For GPU support, Docker Compose, and more → [Quick Start](/getting-started/quick-start) and [Docker images and tags](/getting-started/quick-start#image-variants) - -:::tip Pick the right image -Use `:main` for built-in embeddings, document extraction and speech recognition. Choose `:slim` for a smaller download: **196 MB instead of 1.62 GB (88% smaller)**. It relies on external services for those features. [Why choose slim?](/getting-started/quick-start#what-slim-leaves-out) -::: - From 4f79ba8ad407dfaf4fa8e83a682b044b3867cec4 Mon Sep 17 00:00:00 2001 From: noamp09 Date: Mon, 12 Oct 2026 11:47:27 +0300 Subject: [PATCH 8/8] refix a padding code duplication error --- src/css/custom.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/css/custom.css b/src/css/custom.css index 4be8ec22b9..cb43478423 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -214,7 +214,7 @@ code { .shiki-code-block pre { margin: 0; - padding: 14px 16px 10px; + padding: 14px 16px; line-height: 1.35; }