From 7555f83c9e92aff82ef2e210232608e2c178c6e8 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 9 Aug 2026 00:01:59 +0200 Subject: [PATCH 001/132] Document terminal contexts for API callers Orchestrator-backed terminals can now be scoped per context: shared, scoped to a single chat, or switched off in chats entirely. An API caller that picks a terminal without checking gets a 503 it has no way to interpret, and the server-side tool calling page previously said terminal_id was unconditional. The page now explains the three states, reads the contexts field in the discovery snippet, and records the two new 503 causes with their fixes. It also notes that a chat-scoped terminal cannot be used from the single-request path, which never creates a chat to scope to. This describes behaviour on dev that is not in any release yet. Connections that are not orchestrator-backed carry no contexts entry and behave exactly as every released version does, which the page states explicitly. --- docs/reference/server-side-tool-calling.md | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/reference/server-side-tool-calling.md b/docs/reference/server-side-tool-calling.md index e2310cb35..6bdd8f715 100644 --- a/docs/reference/server-side-tool-calling.md +++ b/docs/reference/server-side-tool-calling.md @@ -64,7 +64,7 @@ curl -s -H "Authorization: Bearer $OWUI_KEY" $OWUI_URL/api/models | jq '.data[]. curl -s -H "Authorization: Bearer $OWUI_KEY" $OWUI_URL/api/v1/tools/ | jq '.[] | {id, name}' # Terminal servers you have access to (use .id as terminal_id) -curl -s -H "Authorization: Bearer $OWUI_KEY" $OWUI_URL/api/v1/terminals/ | jq '.[] | {id, name}' +curl -s -H "Authorization: Bearer $OWUI_KEY" $OWUI_URL/api/v1/terminals/ | jq '.[] | {id, name, contexts}' ``` MCP servers are addressed as tool IDs of the form `server:mcp:`. See [Using Open WebUI tools, including MCP, from the API](/reference/api-endpoints#using-open-webui-tools-including-mcp-from-the-api). @@ -75,6 +75,22 @@ When you pick a model in the browser, the frontend reads `meta.terminalId` off t You can read a model's configured terminal with `GET /api/v1/models/model?id=` and use `meta.terminalId`, or just pick one from `/api/v1/terminals/`, which already lists only the terminals your user is allowed to use. ::: +### Terminal contexts + +Terminals backed by the orchestrator (a connection with `server_type: orchestrator`, or any connection carrying a `policy_id`) can be scoped per context by an administrator. That scoping is returned in the `contexts` field of `/api/v1/terminals/`, and it decides whether your request can use the terminal at all: + +| `contexts.chat` | Meaning for an API caller | +| :--- | :--- | +| absent, or `{}` | Shared terminal. Usable from any request, including one with no chat. | +| `{"context_id": "chat_id"}` | Scoped per chat. The request **must** carry a saved `chat_id`, and each chat gets its own runtime context upstream. | +| `false` | Not available in chats at all. Requesting it fails. | + +An automation-initiated request is scoped the same way through `contexts.automation`, keyed on `automation_id` instead. + +Connections that are not orchestrator-backed have no `contexts` entry and are always usable, which is the behaviour every earlier release had. + +Practically: read `contexts.chat` before choosing a terminal. If it is `false`, pick another. If it is `{"context_id": "chat_id"}`, you have to use [Path A](#path-a-full-agentic-loop) with a real saved chat, because [Path B](#path-b-one-request-answer-in-the-body) never creates one. + --- ## Path A: full agentic loop @@ -145,7 +161,7 @@ Field by field: | `session_id` | **The built-in tools switch.** Any non-empty string works. Without it, built-in tools are not offered to the model. It also makes the request asynchronous (you get `task_ids` instead of blocking). | | `features` | Turns on the four togglable built-in groups: `web_search`, `code_interpreter`, `image_generation`, `memory`. The other built-ins (knowledge, files, notes, channels, calendar, automations, chats, time, tasks, sub-agents) need no flag and are offered whenever their global setting, your permission and the model's category allow it. | | `tool_ids` | Workspace tools and MCP servers. Optional. | -| `terminal_id` | Open Terminal server. Optional, and independent of `session_id`. | +| `terminal_id` | Open Terminal server. Optional, and independent of `session_id`. A chat-scoped orchestrator terminal additionally requires that `chat_id` be a saved chat, which Path A already satisfies. | | `background_tasks` | Turn title, tag and follow-up generation off unless you want the extra model calls. | :::danger Do not send your own `tools` array @@ -214,6 +230,7 @@ Limits, in exchange for the simplicity: - **One round of tool calls.** The model cannot look at a result and decide to call something else. - **No built-in tools.** No web search, no code interpreter, no knowledge browsing, no terminal-driven agentic work. +- **No chat-scoped terminals.** A request in this mode carries no `chat_id`, so an orchestrator terminal configured with `contexts.chat.context_id = "chat_id"` cannot be used. Shared terminals work normally. - Legacy mode is **deprecated** and depends on a task model that reliably emits JSON. See [Tool Calling Modes](/features/extensibility/plugin/tools#tool-calling-modes-default-vs-native). --- @@ -422,6 +439,8 @@ To adapt it: | `execute_code` returns "WebSocket connection required" | The code interpreter engine is `pyodide`, which runs in the browser | Switch the engine to **Jupyter** in **Settings > Admin > Tools > Code Interpreter**, or drop `code_interpreter` from `features` | | File tools (`view_file`, `grep_chat_files`, ...) missing | They need `files` in the request body, the model's **File Upload** capability on, and **File Context** off | See [Prompt Caching and Context Optimization](/features/chat-conversations/prompt-caching) | | `503 Terminal unavailable` | The terminal server is unreachable, disabled, or your user has no access grant | Confirm the ID appears in `GET /api/v1/terminals/` for that key | +| `503`, terminal not available for chat | The terminal's `contexts.chat` is `false`, so an administrator has taken it out of chats | Pick a terminal whose `contexts.chat` is not `false` | +| `503`, terminal requires a saved chat context | The terminal is scoped with `contexts.chat.context_id = "chat_id"` and the request had no saved `chat_id` | Use Path A with a saved chat, or pick a shared terminal | | MCP tool connection fails | An OAuth-protected MCP server the API key's user has not authorised | Complete the OAuth flow once in the browser as that user | | The chat is created but stays empty in the UI | Broken message tree | `currentId` is camelCase, and every message needs `parentId` and `childrenIds`. See [Backend-Controlled API Flow](/reference/api-flow) | From 31e98de56b83dcb0befc82a587f7a08a7a9263e1 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 11 Aug 2026 09:02:07 +0000 Subject: [PATCH 002/132] Document the new configuration surface for the upcoming release Covers the settings and behaviour changes that administrators and operators need to know about before upgrading, written against the code rather than the changelog. ENABLE_ORJSON now reaches the database JSON columns, outbound Ollama and Anthropic request bodies, built-in tool results, the permission lookup and Valkey and Oracle 23ai chunk metadata, so the reference entry, the scaling guide and both performance pages describe what the flag actually covers today. Non-ASCII is written raw rather than escaped, and both encoders read each other's output, so switching it on or off needs no migration. TASK_MODEL_PARAMS gives administrators the generation parameters used for titles, tags, follow-ups, search queries and conversation summaries, replacing the fixed token limit that could cut a summary short. ENABLE_RAG_CSV_SUMMARY prefixes CSV content with its row count, data row count and column names so the model sees the shape of the table alongside its contents. DEFAULT_INTERFACE_SETTINGS sets system-wide defaults for the interface options in Settings, with each person's own choices still taking precedence, alongside the new setting for switching off sidebar chat previews. AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER returns to system name resolution by default, which removes the intermittent lookup failures that surfaced as a misleading model not found message, and WEBSOCKET_EVENT_CALLER_TIMEOUT now reports a timeout for an unanswered tool prompt instead of an empty reply. Single sign-on settings supplied through the environment are shown as read-only in the admin panel with the setting that controls them named, and sign-in through providers that add vendor-specific claims to the token completes instead of failing as a bad email or password. OpenSERP can be selected as the web search engine from the admin panel, and a link that cannot be read now names the link while a refused YouTube transcript explains why and points at the proxy setting. --- docs/faq.mdx | 1 + .../authentication-access/auth/sso/index.mdx | 32 +++++- .../authentication-access/rbac/permissions.md | 6 ++ .../chat-features/autocomplete.md | 2 +- .../chat-features/chat-params.md | 6 ++ .../chat-features/history-search.mdx | 1 + .../chat-features/index.mdx | 2 +- docs/features/chat-conversations/rag/index.md | 31 +++++- .../web-search/providers/openserp.md | 2 +- .../plugin/development/events.mdx | 31 ++++-- .../plugin/development/reserved-args.mdx | 2 + docs/features/workspace/models.md | 2 + .../advanced-topics/scaling.md | 2 +- docs/getting-started/essentials.mdx | 2 + docs/getting-started/quick-start/settings.md | 42 ++++++++ docs/reference/env-configuration.mdx | 102 +++++++++++++++--- docs/troubleshooting/connection-error.mdx | 28 +++++ docs/troubleshooting/context-window.mdx | 4 +- docs/troubleshooting/index.mdx | 5 +- docs/troubleshooting/multi-replica.mdx | 10 +- docs/troubleshooting/performance.md | 26 ++++- docs/troubleshooting/rag.mdx | 52 +++++++++ docs/troubleshooting/sso.mdx | 27 ++++- 23 files changed, 382 insertions(+), 36 deletions(-) diff --git a/docs/faq.mdx b/docs/faq.mdx index 0e001c2f1..ab52d1986 100644 --- a/docs/faq.mdx +++ b/docs/faq.mdx @@ -243,6 +243,7 @@ By default, these tasks use the **same model** you're chatting with. If you're u 1. Go to **Settings > Admin > Experience > Interface** (for title/tag generation settings) 2. Configure a **Task Model** under **Settings > Admin > Experience > Interface > Tasks** to use a smaller, cheaper model (like GPT-4o-mini) or a local model for background tasks 3. Disable features you don't need (auto-title, auto-tags, etc.) +4. Bound what those requests can spend with **Task Model Parameters > Configure** in the same **Tasks** section ([`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params)). Setting `max_tokens` there caps the output of every background request, including tag, follow-up and search query generation, which otherwise send no limit at all :::tip Cost-Saving Recommendation Set your Task Model to a fast, inexpensive model (or a local model via Ollama) while keeping your primary chat model as a more capable one. This gives you the best of both worlds: smart responses for your conversations, cheap/free processing for background tasks. diff --git a/docs/features/authentication-access/auth/sso/index.mdx b/docs/features/authentication-access/auth/sso/index.mdx index e223032ce..4869f6edc 100644 --- a/docs/features/authentication-access/auth/sso/index.mdx +++ b/docs/features/authentication-access/auth/sso/index.mdx @@ -29,7 +29,7 @@ You cannot have Microsoft **and** Google as OIDC providers simultaneously. | Environment Variable | Default | Description | |---------------------------------------|-----------|-----------------------------------------------------------------------------------------------------------------------------------------| | `WEBUI_URL` | *(none)* | **Required.** Your public WebUI address, e.g., `http://localhost:8080`. | -| `ENABLE_OAUTH_PERSISTENT_CONFIG` | `false` | Load OAuth settings from the database (when persistent config is on). Default `false` keeps environment variables authoritative for OAuth; set `true` to manage OAuth in the Admin Panel. | +| `ENABLE_OAUTH_PERSISTENT_CONFIG` | `false` | Load OAuth settings from the database (when persistent config is on). Default `false` keeps environment variables authoritative for OAuth and shows the OAuth section of the Admin Panel read-only; set `true` to manage OAuth in the Admin Panel. | | `ENABLE_OAUTH` | `true` | Master switch for provider sign-in. Set `false` to turn SSO off while keeping the client ID, secret and endpoints configured. Also a toggle in **Settings > Admin > System > Authentication**, next to the LDAP one. | | `ENABLE_OAUTH_SIGNUP` | `false` | Allows account creation upon OAuth login (separate from `ENABLE_SIGNUP`). | | `OAUTH_AUTO_REDIRECT` | `false` | Send unauthenticated users at `/auth` straight to the provider login, skipping the "Continue with SSO" screen. Requires exactly one provider, `ENABLE_LOGIN_FORM=false` and no LDAP; visit `/auth?form=true` for the local login form. | @@ -57,10 +57,30 @@ You cannot have Microsoft **and** Google as OIDC providers simultaneously. - Set `ENABLE_OAUTH_PERSISTENT_CONFIG=false` to always read from environment variables - Update settings through the Admin Panel instead of environment variables + With the default `ENABLE_OAUTH_PERSISTENT_CONFIG=false`, the **OAuth / OIDC** section of **Settings > Admin > Authentication** is read-only, so the Admin Panel is not an option until you set the variable to `true`. See [Read-only OAuth settings in the Admin Panel](#read-only-oauth-settings-in-the-admin-panel). + 3. **Required Variables**: Always verify you're using the exact variable names from the [environment configuration documentation](https://docs.openwebui.com/reference/env-configuration/). Common mistakes include using non-existent variables like `OIDC_CONFIG`. ::: +### Read-only OAuth settings in the Admin Panel + +`ENABLE_OAUTH_PERSISTENT_CONFIG` decides where the OAuth settings live, and the Admin Panel follows it. With the default `false`, everything under `oauth.` comes from the environment on every start, so the **OAuth / OIDC** section of **Settings > Admin > Authentication** is shown read-only: + +- All values remain visible, and the section is dimmed with every field and switch inert, including the **OAuth / OIDC** master toggle. +- A note above the section explains that the settings are read from environment variables and names `ENABLE_OAUTH_PERSISTENT_CONFIG`. +- Saving the Authentication page leaves the OAuth settings untouched. Other sections on that page, such as LDAP, save as usual. + +This replaces the older behavior, where the fields were editable, a save appeared to succeed and the values reverted to the environment on the next restart. + +Set `ENABLE_OAUTH_PERSISTENT_CONFIG=true` to make the section editable and have saved values persist in the database. To keep the environment authoritative, leave it at `false` and change your environment variables instead, then restart. + +:::info + +While the section is read-only, the client secret cannot be revealed (it stays masked) and the field values cannot be selected for copying. Read them from your environment configuration instead. + +::: + ### Server-Side OAuth Session Management To solve issues related to large tokens (e.g., with AD FS group claims exceeding cookie size limits) and to enable automatic token refreshing, Open WebUI now supports a robust server-side session management system. @@ -227,6 +247,16 @@ The following environment variables are used: ::: +:::info Providers that add their own ID token header parameters + +Some providers put a vendor-specific parameter in the JOSE header of the ID token, outside the set of header parameters the standards register. Apereo CAS sends `client_id`, CyberArk Identity sends `app_id`. Open WebUI ignores header parameters it does not recognize, so sign-in through those providers completes normally. + +The checks that protect the token are unaffected: the signature is still verified against the provider's keys, the signing algorithm is still restricted to the allowed list, `crit` is still honored and the registered header parameters are still validated. + +Earlier versions rejected the whole token, which ended the login at the callback with `OAuth callback failed: Unsupported {'app_id'} in header` in the server log and the misleading message `The email or password provided is incorrect` in the browser. If you see that pair, update Open WebUI. + +::: + :::tip Community Workaround: Multi-Provider OAuth If you need to support both Microsoft and Google simultaneously, check out our **[Dual OAuth Configuration Tutorial](/tutorials/auth-sso/dual-oauth-configuration)**. ::: diff --git a/docs/features/authentication-access/rbac/permissions.md b/docs/features/authentication-access/rbac/permissions.md index 44d48ec17..2532a906e 100644 --- a/docs/features/authentication-access/rbac/permissions.md +++ b/docs/features/authentication-access/rbac/permissions.md @@ -169,6 +169,12 @@ Controls access to user settings areas. | :--- | :--- | | **Interface Settings Access** | Ability to access and modify interface settings in user settings. | +:::info Interface Settings Access and instance defaults + +Taking this permission away hides the **Interface** tab and rejects any attempt to save personal settings, so the people affected stay on whatever [Default Interface Settings](/getting-started/quick-start/settings#default-interface-settings-admin) you have configured. Leave it on, and those defaults are only a starting point that each person can change. Admins are exempt. + +::: + :::info API Keys Permission Scope For API key creation: diff --git a/docs/features/chat-conversations/chat-features/autocomplete.md b/docs/features/chat-conversations/chat-features/autocomplete.md index 3cff882aa..38dce458d 100644 --- a/docs/features/chat-conversations/chat-features/autocomplete.md +++ b/docs/features/chat-conversations/chat-features/autocomplete.md @@ -58,7 +58,7 @@ If the Admin has disabled Autocomplete globally, users will **not** be able to e 1. **Check Settings**: Ensure it is enabled in **both** Admin and User settings. 2. **Task Model**: Go to **Admin Settings > Interface** and verify a **Task Model** is selected. If no model is selected, the feature cannot generate predictions. 3. **Latency**: If your Task Model is large or running on slow hardware, predictions might arrive too late to be useful. Switch to a smaller model. -4. **Reasoning Models**: Ensure you are **not** using a "Reasoning" model (like o1 or o3), as their internal thought process creates excessive latency that breaks real-time autocomplete. +4. **Reasoning Models**: Ensure you are **not** using a "Reasoning" model (like o1 or o3), as their internal thought process creates excessive latency that breaks real-time autocomplete. If you are stuck with one, **Admin Settings > Interface > Tasks > Task Model Parameters** ([`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params)) lets you turn its `reasoning_effort` down. That setting is shared by every background task, so whatever you put there also applies to titles, tags and context compaction summaries. ### Performance Impact Autocomplete sends a request to your LLM essentially every time you pause typing (debounced). diff --git a/docs/features/chat-conversations/chat-features/chat-params.md b/docs/features/chat-conversations/chat-features/chat-params.md index a422cf77a..f354e339a 100644 --- a/docs/features/chat-conversations/chat-features/chat-params.md +++ b/docs/features/chat-conversations/chat-features/chat-params.md @@ -78,6 +78,12 @@ Suppose an administrator wants to set a default system prompt for a specific mod ::: +:::note Background tasks have their own parameters + +These three levels shape the requests a chat sends. Background tasks (chat titles, tags, follow-up suggestions, image prompts, retrieval and web search queries, autocomplete and context compaction summaries) never see the per-chat or per-account levels. They run on the task model, with the advanced parameters an administrator sets once in **Settings > Admin > Experience > Interface** under **Tasks** > **Task Model Parameters**, or through [`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params). + +::: + ## **Optimize System Prompt Settings for Maximum Flexibility** :::tip diff --git a/docs/features/chat-conversations/chat-features/history-search.mdx b/docs/features/chat-conversations/chat-features/history-search.mdx index b7913e3be..50ad82220 100644 --- a/docs/features/chat-conversations/chat-features/history-search.mdx +++ b/docs/features/chat-conversations/chat-features/history-search.mdx @@ -15,6 +15,7 @@ All your conversations are automatically saved in the **Sidebar**. * **Persistence**: Chats are saved to the internal database (`webui.db`) and are available across all your devices. * **Organization**: Chats are grouped by time period (Today, Yesterday, Previous 7 Days, etc.). +* **Hover Preview**: Resting the pointer on a chat opens a small card with its most recent messages, so you can tell conversations apart without opening them. The card loads the chat the moment it opens. Switch it off with **Chat Hover Previews** in **Settings > Interface > Chat** if you want a quieter sidebar, are sharing your screen, or are on a slow connection. * **Unread Indicator**: Chats with new activity show an unread dot in the sidebar until you open them. A chat's three-dot menu has **Mark as unread** to put the dot back; a folder's menu, and the **Chats** section header's own menu, both have **Mark all as read** to clear a folder or your whole chat list in one go. * **Renaming**: Titles are automatically generated by a task model, but you can manually rename any chat by clicking the pencil icon next to its title. The automatic title is written without counting as activity, so a chat is not pushed back to the top of the list, or marked unread again, just for being named. * **Archivial**: Instead of deleting, you can **Archive** chats to remove them from the main list while keeping them downloadable and searchable. diff --git a/docs/features/chat-conversations/chat-features/index.mdx b/docs/features/chat-conversations/chat-features/index.mdx index 292a81d67..8b912baed 100644 --- a/docs/features/chat-conversations/chat-features/index.mdx +++ b/docs/features/chat-conversations/chat-features/index.mdx @@ -47,7 +47,7 @@ Open WebUI provides a comprehensive set of chat features designed to enhance you - **[🔍 History & Search](./history-search.mdx)**: Navigate and search your previous conversations, or allow models to search them autonomously via native tools. -- **👁️ Sidebar Hover Previews**: Resting the pointer on a chat in the sidebar opens a small preview of its most recent messages, scrolled to the end, so you can identify a conversation without opening it. Only one preview is shown at a time, and moving to another row replaces it. +- **👁️ Sidebar Hover Previews**: Resting the pointer on a chat in the sidebar opens a small preview of its most recent messages, scrolled to the end, so you can identify a conversation without opening it. Only one preview is shown at a time, and moving to another row replaces it. Turn it off with **Chat Hover Previews** in **Settings > Interface > Chat** if you would rather have a quiet sidebar, are sharing your screen, or are on a slow connection, since each preview fetches the chat when it opens. - **[🕒 Temporal Awareness](./temporal-awareness.mdx)**: How models understand time and date, including native tools for precise time calculations. diff --git a/docs/features/chat-conversations/rag/index.md b/docs/features/chat-conversations/rag/index.md index b8148a9ce..d5d36dca7 100644 --- a/docs/features/chat-conversations/rag/index.md +++ b/docs/features/chat-conversations/rag/index.md @@ -230,10 +230,15 @@ After changing the embedding model in `Settings` > `Admin` > `Tools` > `Document The re-index process performs the following steps for each knowledge base: 1. **Deletes** the existing vector collection for the knowledge base. -2. **Re-chunks** all files using the current chunk size, overlap, and text splitter settings. -3. **Re-embeds** all chunks using the currently configured embedding model. +2. **Deletes** the per-file collection of every file in it. Each file has a vector collection of its own, which is what gets searched when you attach that single file to a chat instead of the whole knowledge base. +3. **Re-chunks** every file from its stored extracted text, using the current chunk size, overlap, and text splitter settings. +4. **Re-embeds** all chunks with the currently configured embedding model, writing them to the knowledge base collection and to the file's own collection. -This means a single re-index applies both chunking setting changes and embedding model changes simultaneously. +This means a single re-index applies both chunking setting changes and embedding model changes simultaneously, and it leaves every file in a knowledge base retrievable both through its knowledge base and on its own. + +:::note Re-indexing does not parse the file again +Re-indexing starts from the text Open WebUI extracted when the file was first processed and stored alongside it, not from the original document. Changing the content extraction engine, or any other parsing setting, therefore has no effect on files that are already in a knowledge base. Re-upload them if you need them parsed again. +::: :::warning Re-indexing does not cover chat files The re-index operation only processes files that belong to **knowledge bases**. Files that were uploaded directly into a chat (without being added to a knowledge base) have their own per-file vector collections that are not touched by re-indexing. @@ -326,6 +331,8 @@ For an even more capable, agentic experience, set `ENABLE_KB_EXEC=True`. This gi The dedicated RAG pipeline for summarizing YouTube videos via video URLs enables smooth interaction with video transcriptions directly. This innovative feature allows you to incorporate video content into your chats, further enriching your conversation experience. +Attaching a video works from its transcript, so a video that YouTube returns no transcript for cannot be attached. The error says which case it is: captions disabled by the uploader, an age restricted or unavailable video, no transcript in the requested languages or a request YouTube blocked because of the address it came from. [`YOUTUBE_LOADER_LANGUAGE`](/reference/env-configuration#youtube_loader_language) sets which languages are tried and in what order, with English appended to the end of the list when it is not already in it. A blocked request can be routed through a proxy, set in **Settings > Admin > Tools > Web Search > Youtube Proxy URL** ([`YOUTUBE_LOADER_PROXY_URL`](/reference/env-configuration#youtube_loader_proxy_url)). The individual messages are listed under [Attaching a link or a YouTube video fails](/troubleshooting/rag#14-attaching-a-link-or-a-youtube-video-fails). + ## Document Parsing A variety of parsers extract content from local and remote documents. For more, see the [`get_loader`](https://github.com/open-webui/open-webui/blob/2fa94956f4e500bf5c42263124c758d8613ee05e/backend/apps/rag/main.py#L328) function. @@ -334,6 +341,24 @@ A variety of parsers extract content from local and remote documents. For more, When using **Temporary Chat**, document processing is restricted to **frontend-only** operations to ensure your data stays private and is not stored on the server. Consequently, advanced backend parsing (used for formats like complex DOCX files) is disabled, which may result in raw data being seen instead of parsed text. For full document support, use a standard chat session. ::: +### CSV Table Summary + +The built-in CSV parser turns each data row into a document of its own, so nothing in the parsed text states how big the table is or which columns it has. Ask a model how many orders a spreadsheet contains and it can only count the rows that happened to be retrieved. + +Setting [`ENABLE_RAG_CSV_SUMMARY=true`](/reference/env-configuration#enable_rag_csv_summary) puts one line describing the shape of the table in front of the parsed rows of every `.csv` file: + +``` +Table: 501 rows incl. header; 500 data rows; 4 columns: id, name, region, revenue. +``` + +The column names come from the first row, the column count is that of the widest row, and the delimiter is detected from the start of the file (falling back to a comma). The line becomes the first part of the file's extracted content, so it is indexed as a chunk like any other and is always present when the file is used with **Using Entire Document**. It is off by default. + +:::info Which files get a summary +The summary comes from Open WebUI's own CSV parser, so it does not apply when the content extraction engine handles the CSV itself: `external`, `tika` and `docling` all read CSVs their own way. Every other engine leaves CSVs to the built-in parser, so the summary applies there. + +Only files parsed after you turn the setting on get a summary line. Re-indexing reuses the text that was already extracted, so existing CSVs must be re-uploaded. +::: + ## Google Drive Integration When paired with a Google Cloud project that has the Google Picker API and Google Drive API enabled, this feature allows users to directly access their Drive files from the chat interface and upload documents, slides, sheets and more and uploads them as context to your chat. Can be enabled `Settings` > `Admin` > `Tools` > `Documents` menu. Must set [`GOOGLE_DRIVE_API_KEY and GOOGLE_DRIVE_CLIENT_ID`](/reference/env-configuration) environment variables to use. diff --git a/docs/features/chat-conversations/web-search/providers/openserp.md b/docs/features/chat-conversations/web-search/providers/openserp.md index 916987ea4..1483820e3 100644 --- a/docs/features/chat-conversations/web-search/providers/openserp.md +++ b/docs/features/chat-conversations/web-search/providers/openserp.md @@ -26,7 +26,7 @@ If Open WebUI itself runs in Docker, `localhost` points at the Open WebUI contai 1. Go to **Settings > Admin > Tools > Web Search**. 2. Enable **Web Search**. 3. Set **Web Search Engine** to `openserp`. -4. Set **OpenSERP Base URL** to your instance, for example `http://localhost:7000`. +4. Set **OpenSERP URL** to your instance, for example `http://localhost:7000`. The field only appears once `openserp` is selected. 5. Save. The base URL can also be set with [`OPENSERP_BASE_URL`](/reference/env-configuration#openserp_base_url), which defaults to `http://localhost:7000`. A trailing slash is fine, it is stripped before the request. diff --git a/docs/features/extensibility/plugin/development/events.mdx b/docs/features/extensibility/plugin/development/events.mdx index 4579f6d2e..ebb15dc70 100644 --- a/docs/features/extensibility/plugin/development/events.mdx +++ b/docs/features/extensibility/plugin/development/events.mdx @@ -88,7 +88,26 @@ result = await __event_call__( ``` :::tip Configurable Timeout -By default `__event_call__` waits **forever** for a user response, so a prompt nobody answers holds that call open indefinitely. Set [`WEBSOCKET_EVENT_CALLER_TIMEOUT`](/reference/env-configuration#websocket_event_caller_timeout) to a number of seconds to bound it, and wrap the call in `try`/`except`, because a timeout raises. A call to a browser that has already disconnected is different: it returns `{"error": "Client session disconnected."}` instead, so check the result as well. +By default `__event_call__` waits **forever** for a user response, so a prompt nobody answers holds that call open indefinitely. Set [`WEBSOCKET_EVENT_CALLER_TIMEOUT`](/reference/env-configuration#websocket_event_caller_timeout) to a number of seconds to bound it. Both failure modes come back as ordinary return values, never as exceptions, so check the result for an `error` key: + +| Situation | What `__event_call__` returns | +|-----------|-------------------------------| +| The browser already disconnected | `{"error": "Client session disconnected."}`, straight away | +| Nobody answered before the timeout elapsed | `{"error": "Event call timed out. The browser tab may be inactive or closed."}` | + +A timeout does not disconnect the tab. If the user simply had not answered yet, their session stays live and you can prompt them again. + +```python +result = await __event_call__( + { + "type": "confirmation", + "data": {"title": "Delete the file?", "message": "This cannot be undone."}, + } +) + +if isinstance(result, dict) and result.get("error"): + return f"Could not ask the user: {result['error']}" +``` ::: --- @@ -979,16 +998,16 @@ This does **not** affect Tools, Actions, or Filters, where events supplement the If your pipe or tool needs to call an LLM and have the result persist even when the browser is closed, you can import and use `generate_chat_completion` from Open WebUI's internals instead of emitting `chat:completion` events. The completion flows through the normal chat pipeline and its result is saved to the database like any other assistant message. ::: -#### ⚠️ Requires live connection (raises or errors on tab close) +#### ⚠️ Requires live connection (errors on tab close) | Type | Why | |------|-----| -| `confirmation` | Uses `sio.call()`, waits for a client response and raises if the timeout elapses | -| `input` | Uses `sio.call()`, waits for a client response and raises if the timeout elapses | -| `execute` via `__event_call__` | Uses `sio.call()`, waits for a client response and raises if the timeout elapses | +| `confirmation` | Uses `sio.call()`, waits for a client response and returns an error dictionary if the timeout elapses | +| `input` | Uses `sio.call()`, waits for a client response and returns an error dictionary if the timeout elapses | +| `execute` via `__event_call__` | Uses `sio.call()`, waits for a client response and returns an error dictionary if the timeout elapses | | `execute` via `__event_emitter__` | Fires and forgets, **will not error**, but JS may not run if no browser is connected | -`confirmation` and `input` fundamentally require a live browser connection via `__event_call__`. If the tab is closed the session is gone, so the call returns `{"error": "Client session disconnected."}` straight away. If the tab is merely inactive the call waits for [`WEBSOCKET_EVENT_CALLER_TIMEOUT`](/reference/env-configuration#websocket_event_caller_timeout). That is unset by default, so it waits indefinitely; set it to a number of seconds and the call raises once it elapses. +`confirmation` and `input` fundamentally require a live browser connection via `__event_call__`. If the tab is closed the session is gone, so the call returns `{"error": "Client session disconnected."}` straight away. If the tab is merely inactive the call waits for [`WEBSOCKET_EVENT_CALLER_TIMEOUT`](/reference/env-configuration#websocket_event_caller_timeout). That is unset by default, so it waits indefinitely; set it to a number of seconds and once it elapses the call returns `{"error": "Event call timed out. The browser tab may be inactive or closed."}`. Neither case raises, so test the return value instead of relying on `try`/`except`, and note that a timeout leaves the browser session connected: a user who was slow to answer can still be prompted again. `execute` is more flexible: when used via `__event_emitter__`, it fires without waiting for a response, so it won't error on tab close (though the JS won't execute if no browser is listening). This makes `__event_emitter__` the safer choice for `execute` calls where you don't need the return value, particularly for file downloads on iOS PWA, where the two-way channel can fail with `"TypeError: Load failed"`. diff --git a/docs/features/extensibility/plugin/development/reserved-args.mdx b/docs/features/extensibility/plugin/development/reserved-args.mdx index 7e59938ed..e18bc1c34 100644 --- a/docs/features/extensibility/plugin/development/reserved-args.mdx +++ b/docs/features/extensibility/plugin/development/reserved-args.mdx @@ -319,6 +319,8 @@ await __event_emitter__({ A `Callable` that sends an event and waits for the browser to answer it. Available to Pipes, Filters, Tools and Actions alike. +It returns whatever the browser sent back. When it cannot get an answer it returns a `dict` with an `error` key instead of raising: `{"error": "Client session disconnected."}` if the tab is already gone, or `{"error": "Event call timed out. The browser tab may be inactive or closed."}` if [`WEBSOCKET_EVENT_CALLER_TIMEOUT`](/reference/env-configuration#websocket_event_caller_timeout) is set and elapses. Without that variable there is no timeout at all and the call waits indefinitely. + ### `__files__` A `list` of files sent via the chat. Note that images are not considered files and are sent directly to the model as part of the `body["messages"]` list. diff --git a/docs/features/workspace/models.md b/docs/features/workspace/models.md index 743d2bbfd..0c32abde3 100644 --- a/docs/features/workspace/models.md +++ b/docs/features/workspace/models.md @@ -166,6 +166,8 @@ Administrators can set baseline capabilities and parameters that apply to all mo - **Default Model Metadata** (`DEFAULT_MODEL_METADATA`): Baseline capabilities (vision, web search, file context, code interpreter, builtin tools). Per-model overrides always win on conflicts. - **Default Model Params** (`DEFAULT_MODEL_PARAMS`): Baseline inference parameters (temperature, top_p, max_tokens, function_calling). Per-model values take precedence when explicitly set. This value is loaded from the environment as JSON; invalid JSON is ignored and falls back to `{}`. +These cover chat completions. Background task requests (titles, tags, follow-ups, search queries, autocomplete, context compaction summaries) do not go through them; their parameters come from **Task Model Parameters** in **Settings > Admin > Experience > Interface**, or [`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params). + ### Merge behavior | Setting type | Strategy | Example | diff --git a/docs/getting-started/advanced-topics/scaling.md b/docs/getting-started/advanced-topics/scaling.md index 0eec38133..ed1512fa6 100644 --- a/docs/getting-started/advanced-topics/scaling.md +++ b/docs/getting-started/advanced-topics/scaling.md @@ -200,7 +200,7 @@ Multiple instances mean Socket.IO events travel through Redis, and every one of ENABLE_ORJSON=True ``` -It covers HTTP request and response bodies, upstream provider responses including the per-chunk parsing of streamed completions, and the Socket.IO and Redis payloads. `orjson` already ships as a dependency, so nothing needs installing, and the setting is read once at startup. It is opt-in only because orjson is stricter about what it accepts, and anything it rejects falls back to the standard library automatically, so enabling it cannot turn a working payload into an error. Available from v0.11.0. +It covers HTTP request and response bodies, the JSON columns the database reads and writes (chat contents above all, since a whole conversation is serialized on every save and parsed again on every open), the request bodies sent to model providers, upstream provider responses including the per-chunk parsing of streamed completions and the Socket.IO and Redis payloads. `orjson` already ships as a dependency, so nothing needs installing, and the setting is read once at startup. It is opt-in only because orjson is stricter about what it accepts, and anything it rejects falls back to the standard library automatically, so enabling it cannot turn a working payload into an error. Available from v0.11.0. For the full breakdown of what it covers, the two behaviour differences worth knowing and when it is not worth enabling, see [Multi-Replica → Use the Faster JSON Encoder](/troubleshooting/multi-replica#use-the-faster-json-encoder). diff --git a/docs/getting-started/essentials.mdx b/docs/getting-started/essentials.mdx index 3c9a05b4e..dfb480a73 100644 --- a/docs/getting-started/essentials.mdx +++ b/docs/getting-started/essentials.mdx @@ -104,6 +104,8 @@ These run in the background, so they are easy to overlook. A dedicated task mode The main chat experience does not change. The background chores just stop dragging. ::: +Under the two pickers, **Task Model Parameters > Configure** ([`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params)) sets the generation parameters those background requests are sent with, `max_tokens` and `temperature` among them. Most people never need it. It matters if your task model is a reasoning one and titles or context compaction summaries come back cut off, because the built-in 1000-token limit gets spent on thinking; setting anything here replaces that limit with your own values. + While you are in the Interface settings, you can also disable these chores entirely if you are on a low-spec machine or simply do not want them. Each one has both an **admin toggle** in the same page and an **environment variable**: | Chore | Admin toggle (Settings > Interface) | Env var | diff --git a/docs/getting-started/quick-start/settings.md b/docs/getting-started/quick-start/settings.md index ceaf0708f..601608d90 100644 --- a/docs/getting-started/quick-start/settings.md +++ b/docs/getting-started/quick-start/settings.md @@ -73,6 +73,40 @@ This pattern applies across web search, image generation, direct connections, co --- +## Default Interface Settings (Admin) + +Feature toggles are a ceiling. **Default Interface Settings** are a starting point: an administrator decides the values every account begins with for the options in **Settings > Interface**, and each person can still change any of them for themselves. + +| | | +| :--- | :--- | +| **Location** | **Settings > Admin > System > General**, under **UI > Default Interface Settings** | +| **Access** | Administrators only | +| **Scope** | Every account, until the individual changes that setting | + +Press **Configure** to open the same list of controls a user sees in **Settings > Interface**, set the ones you care about, then press **Save** at the bottom of the admin page. A line above the list counts how many settings you have configured. Every control you touch joins that set, including one you move and then move back, so use **Clear** to empty the whole set and return to the built-in defaults. + +**How a value is decided for a user:** + +1. If the user has set that option themselves, their value is used. +2. Otherwise the instance default is used. +3. If there is no instance default, the built-in default is used. + +Options a user has never touched are marked **Default** next to their control in **Settings > Interface**, and they keep tracking the instance default. Change the default later and everyone who has not overridden that option moves with it. + +:::info Setting an option back to the default releases it +Open WebUI only stores the options a user actually differs on. Moving a control back to whatever the instance default currently is drops it from the user's own settings, so it goes back to being inherited and follows future changes to the default again. +::: + +**What this does not do:** + +- It does not restrict anyone. Everyone keeps full control of every option in **Settings > Interface**; to actually hold people to your values, take **Interface Settings Access** away from them in [permissions](/features/authentication-access/rbac/permissions). +- It does not rewrite accounts that already exist. Nobody's stored choices are touched; people who never set a given option simply start following your default instead of the built-in one. +- It does not cover **Theme** or **Language**. Both live in the browser rather than in the account, so they are not part of this. Use [`DEFAULT_LOCALE`](/reference/env-configuration#default_locale) for the starting language. + +If you configure your instance through environment variables, [`DEFAULT_INTERFACE_SETTINGS`](/reference/env-configuration#default_interface_settings) sets the same thing as a JSON object, for example `{"chatBubble": false, "widescreenMode": true}`. + +--- + ## Quick Reference | | Admin Settings | User Settings | @@ -82,6 +116,8 @@ This pattern applies across web search, image generation, direct connections, co | **Controls** | API connections, feature toggles, security, defaults | Theme, default model, personal preferences | | **Override behavior** | Cannot be overridden by users | Can customize within admin-allowed boundaries | +The one deliberate exception is [Default Interface Settings](#default-interface-settings-admin), which an admin sets as a starting value rather than a limit; each user can change any of it for themselves. + --- ## Common Scenarios @@ -98,6 +134,12 @@ If the admin has enabled **Direct Connections**, you can add personal API keys i **"I set a system prompt but my admin's model settings override it."** Model-level settings configured by admins in the Workspace take precedence over personal settings. See [Chat Parameters](/features/chat-conversations/chat-features/chat-params) for the full precedence hierarchy. +**"An option in Settings > Interface says Default next to it. What does that mean?"** +It means you have never changed that option, so it is following the instance-wide [Default Interface Settings](#default-interface-settings-admin) your admin configured. Change it and it becomes yours; set it back to the current default and it goes back to following. + +**"I am the admin. Can I make everyone start with the same interface options?"** +Yes. **Settings > Admin > System > General > UI > Default Interface Settings**, or the [`DEFAULT_INTERFACE_SETTINGS`](/reference/env-configuration#default_interface_settings) environment variable. It sets where everyone starts; each person can still change any of it afterwards. + :::tip First-Time Admin? Start with **Admin Settings > Connections** to connect your model providers (Ollama, OpenAI, etc.), then explore **Admin Settings > Interface** to enable or disable features for your users. ::: diff --git a/docs/reference/env-configuration.mdx b/docs/reference/env-configuration.mdx index a2d548ce0..cd0307bdb 100644 --- a/docs/reference/env-configuration.mdx +++ b/docs/reference/env-configuration.mdx @@ -34,6 +34,8 @@ To disable this behavior and force Open WebUI to always use your environment var **CRITICAL WARNING:** When `ENABLE_PERSISTENT_CONFIG` is `False`, you may still be able to edit settings in the Admin UI. However, these changes are **NOT saved**. +The OAuth settings are the exception: they are shown read-only in the Admin Panel whenever [`ENABLE_OAUTH_PERSISTENT_CONFIG`](#enable_oauth_persistent_config) is `False`, which is its default, so there is nothing to edit and nothing to lose. + ::: ### Troubleshooting Ignored Environment Variables 🛠️ @@ -259,6 +261,23 @@ is also being used and set to `True`. **Never disable this if OAUTH/SSO is not b ::: +#### `DEFAULT_INTERFACE_SETTINGS` + +- Type: `dict` (JSON object) +- Default: `{}` +- Description: Sets instance-wide defaults for the personal options in **Settings > Interface**, so every account starts from your preferences instead of the built-in ones. Keys are the setting names as they are stored in a user's own settings, for example `{"chatBubble": false, "widescreenMode": true, "chatHoverPreview": false}`. A user's own choice always wins over the default. A setting the user has never touched follows the default and keeps following it, so changing the default later moves everyone who has not overridden it. Configurable via **Settings > Admin > System > General > UI > Default Interface Settings**, see [Default Interface Settings](/getting-started/quick-start/settings#default-interface-settings-admin). +- Persistence: This environment variable is a `ConfigVar` variable. Stored at config key `ui.default_interface_settings`. + +:::info + +`DEFAULT_INTERFACE_SETTINGS` is read from the environment as a JSON string at startup. + +- Use valid JSON (for example: `{"chatBubble": false, "title": {"auto": false}}`) +- If parsing fails, Open WebUI logs the error and falls back to `{}` +- Anything that parses to something other than a JSON object (an array or a number, for example) is also replaced by `{}` + +::: + #### `DEFAULT_USER_ROLE` - Type: `str` @@ -860,7 +879,7 @@ If a reverse proxy, load balancer, ingress, or CDN (Nginx, Caddy, Traefik, Cloud - Type: `bool` - Default: `False` -- Description: Swaps the application-wide JSON encoder and decoder from the standard library's `json` module to [orjson](https://pypi.org/project/orjson/), covering HTTP request and response bodies, upstream provider responses including streamed chunks, and Socket.IO payloads. Off by default because orjson is stricter about what it accepts; rejected payloads fall back to the standard library automatically. Worth enabling on clustered, Redis-backed deployments and not worth it on single-user instances. Read once at startup, so a restart is required. Added in v0.11.0. +- Description: Swaps the application-wide JSON encoder and decoder from the standard library's `json` module to [orjson](https://pypi.org/project/orjson/), covering HTTP request and response bodies, the JSON columns the database reads and writes (chat contents, user settings, the configuration table), the request bodies sent to model providers, upstream provider responses including streamed chunks, built-in tool results, the permission lookup that runs on sign-in, sign-up and every session refresh, Socket.IO payloads and the chunk metadata read back during knowledge base searches on the Valkey and Oracle 23ai vector stores. Off by default because orjson is stricter about what it accepts; rejected payloads fall back to the standard library automatically. Worth enabling on clustered, Redis-backed deployments and not worth it on single-user instances. Read once at startup, so a restart is required. Added in v0.11.0. - Details: [Multi-Replica → Use the Faster JSON Encoder](/troubleshooting/multi-replica#use-the-faster-json-encoder) for the full behaviour and trade-offs, [Scaling](/getting-started/advanced-topics/scaling#switch-the-json-encoder-to-orjson) for where it sits in a scaled rollout, and [Performance & RAM](/troubleshooting/performance#json-encoder) for how it compares to the other tuning knobs. #### `DEFAULT_PROMPT_SUGGESTIONS` @@ -969,6 +988,25 @@ If this variable is unset or invalid, Open WebUI falls back to `AIOHTTP_CLIENT_T - Default: `False` - Description: Controls whether outbound HTTP requests across the application follow `3xx` redirects. When `False` (the default since v0.9.6), redirects are not followed. This closes a class of SSRF where a public, validated URL `302`-redirects to an internal address (RFC 1918, loopback `127.0.0.1`, cloud-metadata `169.254.169.254`) that bypasses the original allowlist check. Affected call sites include the RAG web loader, image loading and base64 conversion, OAuth pre-flight, code-interpreter login, and tool-server execution. Set to `True` only if your deployment legitimately requires redirect following (e.g. shortlink-style URLs) AND you have other SSRF protections in place, typically an egress firewall or `WEB_FETCH_FILTER_LIST` covering your internal ranges. +#### `AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER` + +- Type: `bool` +- Default: `False` +- Description: Chooses which resolver aiohttp uses for every outbound hostname lookup. When `False` (the default), lookups go through the operating system resolver (aiohttp's `ThreadedResolver`, which runs `getaddrinfo` on asyncio's default executor), so Open WebUI resolves names exactly the way anything else on the machine does. When `True`, lookups go through c-ares (the `aiodns` package, aiohttp's `AsyncResolver`), which resolves on the event loop instead of occupying a thread, so a burst of concurrent lookups costs roughly as much as a single one. Read once at startup and applied before the first connection is opened, so a restart is required for a change to take effect. It covers every outbound request, including the Mistral OCR content-extraction loader, which previously pinned itself to c-ares on its own. + +:::warning Only turn this on if you have confirmed c-ares works in your environment + +v0.11.0 shipped the `aiodns` package, which made aiohttp switch every outbound request to c-ares with no way to opt out. That broke name resolution on some deployments: + +- On some Windows hosts, c-ares discovers only `127.0.0.1:53` as a nameserver, so every lookup to an external model provider fails. +- In Docker, the long-lived c-ares channel intermittently stops resolving container names while Docker's embedded DNS keeps answering. That empties the Ollama model list and fails in-flight chats with a misleading "Model not found". + +The operating system resolver is the default again, so nothing needs configuring to get working name resolution. Set this to `True` only for deployments whose resolver setup is known to work with c-ares. + +c-ares also reads `/etc/resolv.conf` and the hosts file but not the rest of `nsswitch.conf`, so names served only by an NSS module (`.local` via avahi/mDNS, NIS or LDAP backends, Windows NBNS) resolve differently or not at all when it is enabled. `host.docker.internal`, Compose `extra_hosts` and Kubernetes `hostAliases` keep working either way, since those go through the hosts file. + +::: + #### `USER_AGENT` - Type: `str` @@ -1269,6 +1307,24 @@ when using Ollama models. when using OpenAI-compatible endpoints. - Persistence: This environment variable is a `ConfigVar` variable. +#### `TASK_MODEL_PARAMS` + +- Type: `dict` (JSON object) +- Default: `{}` +- Description: The generation parameters sent with background task requests: title generation, tag generation, follow-up suggestions, image prompt generation, retrieval and web search query generation, autocomplete and context compaction summaries. It takes the same keys as a model's advanced parameters (`temperature`, `max_tokens`, `top_p`, `seed`, `reasoning_effort`, `stop`, the Ollama-only options and so on), and they are applied to whichever model the task actually runs on, whether that is [`TASK_MODEL`](#task_model), [`TASK_MODEL_EXTERNAL`](#task_model_external), [`CONTEXT_COMPACTION_MODEL`](#context_compaction_model) or the chat's own model. Leave it empty and nothing changes: title generation and compaction summaries stay capped at the `max_tokens` configured on whichever model runs them (default `1000`) and the other tasks send no parameters at all. Set anything at all here and that built-in cap is no longer applied, so include `max_tokens` yourself if you still want a limit. Raising or removing the cap is the fix for a reasoning task model that spends its budget on thinking and returns a title or summary that stops mid-sentence. Emoji generation always uses `max_tokens: 4` and ignores this setting. Can also be set in **Settings > Admin > Experience > Interface**, under **Tasks** > **Task Model Parameters** > **Configure**. +- Persistence: This environment variable is a `ConfigVar` variable. Stored at config key `task.model.params`. + +:::info + +`TASK_MODEL_PARAMS` is read from the environment as a JSON string at startup. + +- Use valid JSON (for example: `{"max_tokens":4000,"temperature":0.3}`) +- If parsing fails, Open WebUI logs the error and falls back to `{}` +- Open WebUI's own control keys are stripped before the request goes out and do nothing here: `stream_response`, `stream_delta_chunk_size`, `function_calling`, `reasoning_tags`, `compact_token_threshold`, `system` and `note_id`. The admin panel offers controls for the first five, so it is possible to set one and see no effect +- Anything under `custom_params` is merged in, which is how you send a provider-specific field that has no control of its own (in the admin panel, **Add Custom Parameter**) + +::: + #### `ENABLE_CONTEXT_COMPACTION` - Type: `bool` @@ -2744,18 +2800,18 @@ If you want to use Milvus, be careful when upgrading Open WebUI (crate backups a - Existing collections (pattern: `open_webui_{collection_name}`) remain in Milvus but **become inaccessible** to Open WebUI - New data is written to the 5 shared multitenancy collections - Application treats knowledge bases as empty until reindexed -- Files and memories are NOT automatically migrated to the new collection schema and will appear missing +- Memories, and files that are not in a knowledge base, are NOT automatically migrated to the new collection schema and will appear missing **Clean migration path from normal Milvus to multitenancy milvus:** - Before enabling multitenancy, export any critical knowledge content from the UI if possible - Set `ENABLE_MILVUS_MULTITENANCY_MODE=true` and restart Open WebUI - Navigate to `Admin Settings > Documents > Click Reindex Knowledge Base` -**This rebuilds ONLY knowledge base vectors into the new multitenancy collections** -**Files, user memories, and web search history are NOT migrated by this operation** +**This rebuilds knowledge base vectors into the new multitenancy collections, together with the per-file vectors of every file inside those knowledge bases** +**User memories, web search history, and files that were never added to a knowledge base are NOT migrated by this operation** **Verify knowledge bases are accessible and functional** -- Re-upload files if file-based retrieval is critical (file metadata remains but vectors are not migrated) +- Re-upload files that live outside any knowledge base if file-based retrieval for them is critical (file metadata remains but their vectors are not migrated) - User chat memories will need to be regenerated through new conversations **Cleaning up legacy collections:** @@ -2775,7 +2831,7 @@ After successful migration (from milvus to multitenancy milvus), legacy collecti **Critical Considerations** **Before enabling multitenancy on an existing installation:** -- Data loss risk: File vectors and user memory vectors are NOT migrated automatically. Only knowledge base content can be reindexed (migrated). +- Data loss risk: user memory vectors, and the vectors of files that are not in a knowledge base, are NOT migrated automatically. Reindexing migrates knowledge bases along with the per-file vectors of the files they contain. - Collection naming dependency: Multitenancy relies on Open WebUI's internal collection naming conventions (user-memory-, file-, web-search-, hash patterns). **If Open WebUI changes these conventions in future updates, multitenancy routing may break, causing data corruption or incorrect data retrieval across isolated resources.** - No automatic rollback: Disabling multitenancy after data is written will not restore access to the shared collections. Data would need manual extraction and re-import. @@ -2783,7 +2839,7 @@ For fresh installations, no migration concerns exist **For existing installations with valuable data:** - Do not migrate to multitenancy mode if you do not want to handle migration and risk data loss -- Understand that files and memories require re-upload/regeneration +- Understand that memories, and files outside knowledge bases, require re-upload/regeneration - Test migration on a backup/staging environment first - Consider if RAM savings justify the migration effort for your use case @@ -3123,7 +3179,7 @@ Currently, there is no button in the UI to only reset the vector DB. If you want - Remove all collections with the `open_webui-knowledge` prefix (or `open_webui` prefix to remove all collections related to Open WebUI) using the native Qdrant client - Go to `Admin Settings` > `Documents` > `Reindex Knowledge Base` to migrate existing knowledge base -`Reindex Knowledge Base` will ONLY migrate the knowledge base +`Reindex Knowledge Base` migrates knowledge bases and the per-file vectors of the files inside them. Files that were never added to a knowledge base, user memories and cached web search results stay in the old collections. ::: @@ -3853,6 +3909,13 @@ The `markdown_header` option has been removed from `RAG_TEXT_SPLITTER`. Markdown - Description: Controls how PDFs are loaded and split into documents when using the **default content extraction engine** (PyPDFLoader). Page mode creates one document per page, while single mode combines all pages into one document, which can improve chunking quality when content spans across page boundaries. This setting has no effect when using external content extraction engines like Tika, Docling, Document Intelligence, MinerU, or Mistral OCR, as those engines have their own document handling logic. - Persistence: This environment variable is a `ConfigVar` variable. +#### `ENABLE_RAG_CSV_SUMMARY` + +- Type: `bool` +- Default: `False` +- Description: Puts a single line describing the shape of the table in front of the parsed contents of every `.csv` file, for example `Table: 501 rows incl. header; 500 data rows; 4 columns: id, name, region, revenue.` The built-in CSV parser emits one document per data row, so without this line nothing in the indexed text says how many rows the file has or which columns exist, and a model asked to count or list them can only go by the rows it retrieved. Column names are taken from the first row, the column count is that of the widest row, and the delimiter is detected from the first 4096 characters of the file, falling back to a comma. The line becomes the first part of the file's extracted content, so it is indexed as an ordinary chunk and is included whenever the whole document is injected. Files that cannot be read, or that have no rows at all, get no summary line and are still parsed as before. Only applies where Open WebUI's own CSV parser is used, so a CSV handled by the `external`, `tika` or `docling` extraction engine is unaffected; every other engine leaves CSVs to the built-in parser. Existing files keep the content they were parsed with, since re-indexing reuses stored text rather than parsing the file again, so re-upload a CSV to give it a summary line. +- Persistence: Set via environment variable; applied at startup (not a `ConfigVar`). + #### `RAG_FILE_MAX_SIZE` - Type: `int` @@ -4447,6 +4510,7 @@ Allow only specific domains: WEB_FETCH_FILTER_LIST="example.com,trusted-site.org - `yacy` - `yandex`: Uses the [Yandex Search API](https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search). - `youcom`: Uses the [You.com](https://you.com/) YDC Index API for web search. + - `openserp`: Uses a self-hosted [OpenSERP](https://github.com/karust/openserp) instance. Requires `OPENSERP_BASE_URL`; no API key. - Persistence: This environment variable is a `ConfigVar` variable. #### `DDGS_BACKEND` @@ -4476,7 +4540,7 @@ Allow only specific domains: WEB_FETCH_FILTER_LIST="example.com,trusted-site.org - Type: `str` - Default: `http://localhost:7000` - Description: Base URL of a self-hosted [OpenSERP](https://github.com/karust/openserp) instance, used when the web search engine is set to `openserp`. Open WebUI calls its `/mega/search` endpoint, which returns results from Google, Bing, Yandex, Baidu, DuckDuckGo and Ecosia together. No API key is involved, the base URL is the only required setting. See the [OpenSERP provider guide](/features/chat-conversations/web-search/providers/openserp). -- Persistence: This environment variable is a `ConfigVar` variable. +- Persistence: This environment variable is a `ConfigVar` variable. It can be configured in the **Settings > Admin > Tools > Web Search > OpenSERP URL** when `openserp` is selected as the search engine. #### `SEARXNG_QUERY_URL` @@ -4975,8 +5039,9 @@ This **timeout only applies when `WEB_LOADER_ENGINE` is set to `safe_web`** or l #### `YOUTUBE_LOADER_PROXY_URL` - Type: `str` -- Description: Sets the proxy URL for YouTube loader. -- Persistence: This environment variable is a `ConfigVar` variable. +- Default: unset (requests come from the server's own address) +- Description: Proxy used for the requests that fetch a YouTube video's transcript, in the form `https://user:password@host:port`. The same URL is used for HTTP and HTTPS. YouTube blocks transcript requests from many datacentre and cloud provider addresses; when it does, attaching a YouTube video fails with a message saying YouTube blocked the request and naming this setting, and routing the requests through a residential or otherwise accepted proxy is what gets them through. +- Persistence: This environment variable is a `ConfigVar` variable. It can be configured in the **Settings > Admin > Tools > Web Search > Youtube Proxy URL**. #### `YOUTUBE_LOADER_LANGUAGE` @@ -5797,6 +5862,18 @@ Set this variable to `True` to persist OAuth settings in the database and manage ::: +:::info Read-only Admin Panel while this is `False` + +Because the environment is authoritative in that case, the **OAuth / OIDC** section of **Settings > Admin > Authentication** is displayed read-only: every value stays visible but no control accepts input, a note above the section names `ENABLE_OAUTH_PERSISTENT_CONFIG` and saving the page leaves the OAuth settings untouched. Previously the fields were editable and every change was silently dropped on the next restart. + +Two consequences while the section is read-only: the client secret stays masked (the reveal button is inert as well); the field values cannot be selected for copying. + +To change these settings, edit your environment variables and restart, or set `ENABLE_OAUTH_PERSISTENT_CONFIG=true` to manage them in the Admin Panel. + +The read-only state follows this variable alone. Setting it to `True` while [`ENABLE_PERSISTENT_CONFIG`](#enable_persistent_config) is `False` therefore leaves the section editable even though nothing at all is written to the database in that combination, so those edits still apply only to the running process and are gone after a restart. + +::: + #### `OAUTH_SUB_CLAIM` - Type: `str` @@ -8019,7 +8096,8 @@ When this variable is left empty (default), `REDIS_SOCKET_CONNECT_TIMEOUT` is au - Type: `int` - Default: unset, meaning no timeout -- Description: Sets the timeout in seconds for the `sio.call()` used in `event_call` events. This controls how long the server waits for a user to respond to interactive prompts, forms, or dropdowns generated by tools and actions using `event_call` (e.g., `execute()` type events). Left unset the server waits indefinitely, so a prompt nobody answers holds that call open. A timeout raises into the calling plugin, so wrap the call in try/except when you set this. +- Description: Sets the timeout in seconds for the `sio.call()` used in `event_call` events. This controls how long the server waits for a user to respond to interactive prompts, forms, or dropdowns generated by tools and actions using `event_call` (e.g., `execute()` type events). Left unset the server waits indefinitely, so a prompt nobody answers holds that call open. When the timeout elapses, the call returns `{"error": "Event call timed out. The browser tab may be inactive or closed."}` to the calling plugin, so check the returned value for an `error` key rather than wrapping the call in try/except. A value that is not a whole number falls back to `300`. +- Details: The browser session is untouched when the timeout fires, so a tab that is still open and whose user simply has not answered yet stays connected and can be prompted again. Sessions that are genuinely gone are reaped separately, once they stop sending heartbeats. See [Events → Interactive Events](/features/extensibility/plugin/development/events#interactive-events) for how to handle the returned error in a plugin. #### `ENABLE_STAR_SESSIONS_MIDDLEWARE` diff --git a/docs/troubleshooting/connection-error.mdx b/docs/troubleshooting/connection-error.mdx index d1882cf0f..e88e170c1 100644 --- a/docs/troubleshooting/connection-error.mdx +++ b/docs/troubleshooting/connection-error.mdx @@ -237,6 +237,34 @@ docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL= ``` After running the above, your WebUI should be available at `http://localhost:8080`. +## 🧭 Intermittent Name Lookup Failures (Often Reported as "Model not found") + +### Common Symptoms + +- Chats fail with **"Model not found"** for a model that is configured and worked a moment ago, then work again later. +- The Ollama model list empties by itself, and a restart brings it back. +- Backend logs show `ClientConnectorDNSError` or `Cannot connect to host ...` for a hostname that resolves fine from a shell inside the same container. +- On some Windows hosts, every request to an external model provider fails from the first start. + +### Cause + +Open WebUI resolves hostnames through the operating system resolver. Between v0.11.0 and this release it resolved them through c-ares instead, which the `aiodns` package activates inside aiohttp for the whole process. c-ares does not behave the same everywhere: + +- On some Windows hosts it discovers only `127.0.0.1:53` as a nameserver, so no external name resolves at all. +- In Docker its long-lived channel intermittently stops resolving container names, even though Docker's embedded DNS is still answering. The symptom is a wiped model list and in-flight chats failing with a misleading "Model not found", since a name that will not resolve is indistinguishable from a provider that has no such model. + +### Solution + +Upgrade. Name lookups go through the operating system resolver again by default, so there is nothing to configure and container names, `host.docker.internal`, Compose `extra_hosts` and Kubernetes `hostAliases` all behave the way the rest of the host does. + +c-ares is still available for deployments whose resolver setup is known to work with it. It resolves on the event loop instead of occupying a thread, which keeps a burst of concurrent lookups roughly as cheap as a single one: + +```bash +AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER=true +``` + +Leave it off unless you have a measured reason to enable it, and be aware that with it on, names served only by an NSS module (`.local` via avahi/mDNS, NIS or LDAP backends, Windows NBNS) resolve differently or not at all. See [`AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER`](/reference/env-configuration#aiohttp_client_async_dns_resolver) for the full trade-off. + ## ⏱️ Model List Loading Issues (Slow UI / Unreachable Endpoints) If your Open WebUI takes a long time to load models, or the model selector spins indefinitely, it may be due to an unreachable or slow API endpoint configured in your connections. diff --git a/docs/troubleshooting/context-window.mdx b/docs/troubleshooting/context-window.mdx index 2fd0cdba2..4aba264fb 100644 --- a/docs/troubleshooting/context-window.mdx +++ b/docs/troubleshooting/context-window.mdx @@ -58,6 +58,7 @@ It is **disabled by default**. An administrator enables and tunes it in **Settin - **Context Compaction Model**: the model that writes the summaries ([`CONTEXT_COMPACTION_MODEL`](/reference/env-configuration#context_compaction_model)). Leave it on **Current Model** to follow the task model as before. - **Token Threshold**: the estimated context size, in tokens, above which older messages are compacted (default `80000`, [`CONTEXT_COMPACTION_TOKEN_THRESHOLD`](/reference/env-configuration#context_compaction_token_threshold)). Set it below your model's real window. This is the global default: an individual model can set its own **Context Compaction Threshold** (`compact_token_threshold`) in its advanced parameters, either lower or higher, bounded by the **Token Cap** ([`CONTEXT_COMPACTION_TOKEN_CAP`](/reference/env-configuration#context_compaction_token_cap)), which defaults to the threshold. So a model can compact later than the global default only if you raise the cap. - **Context Compaction Prompt**: an optional custom summarization prompt ([`CONTEXT_COMPACTION_PROMPT_TEMPLATE`](/reference/env-configuration#context_compaction_prompt_template)); leave it empty for the built-in default. It supports `{{COMPACTED_MESSAGES}}` (the messages being summarized) and `{{RECENT_MESSAGES}}` (the messages kept in context). +- **Task Model Parameters**: the generation parameters the summarization request is sent with ([`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params)), found higher up the same page under **Tasks**. This is how you give the summary a larger `max_tokens` than the built-in 1000, at the cost of applying the same parameters to titles, tags and the other background tasks, which share the setting. This is the summarize-and-replace strategy (option 4 below), built in. If you need a different policy (hard caps, attachment-first trimming, per-model windows), use a filter Function instead. @@ -65,7 +66,8 @@ This is the summarize-and-replace strategy (option 4 below), built in. If you ne - **It runs server-side, per request, and is invisible in the chat.** Your full conversation is still stored and displayed in the UI; compaction only changes what is sent to the model on a given turn. There is no badge or marker indicating it happened. - **It keeps a rolling checkpoint, it does not wipe history.** When the threshold is crossed, the oldest ~60% of the active window is summarized and the most recent ~40% (at least two messages) is kept verbatim, and the split never separates an assistant tool call from its result. The summary is saved onto a message as a checkpoint. Later turns resume from that checkpoint (the summary plus the messages after it), and if the window grows past the threshold again it compacts again, folding the previous summary into the new one and moving the checkpoint forward. -- **A configurable model writes the summary.** By default it uses the same model selection as title and tag generation: your configured Task Model (`TASK_MODEL` / `TASK_MODEL_EXTERNAL`) if set, otherwise the chat's current model. You can give summarization a model of its own with [`CONTEXT_COMPACTION_MODEL`](/reference/env-configuration#context_compaction_model), or **Context Compaction Model** in the same admin panel. That is worth setting when your task model is a small one picked for titles, since the summary has to carry a large part of the conversation. Whatever is chosen, an unavailable model falls back to the task model selection and then to the chat model, so compaction still runs. Summary length is capped by the task model's `max_tokens` (default 1000). +- **A configurable model writes the summary.** By default it uses the same model selection as title and tag generation: your configured Task Model (`TASK_MODEL` / `TASK_MODEL_EXTERNAL`) if set, otherwise the chat's current model. You can give summarization a model of its own with [`CONTEXT_COMPACTION_MODEL`](/reference/env-configuration#context_compaction_model), or **Context Compaction Model** in the same admin panel. That is worth setting when your task model is a small one picked for titles, since the summary has to carry a large part of the conversation. Whatever is chosen, an unavailable model falls back to the task model selection and then to the chat model, so compaction still runs. Summary length is capped by that model's own `max_tokens` (default 1000), unless you configure task model parameters, in which case those replace the cap entirely (see the next point). +- **The summarizer's generation parameters are configurable.** [`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params), or **Task Model Parameters** under **Tasks** in the same admin panel, sets the parameters sent with every background request, compaction summaries included. Setting anything there drops the built-in 1000-token cap, so put `max_tokens` in yourself if you still want a limit. This is the setting to reach for when a reasoning model is doing the summarizing and the checkpoints look like half-finished thoughts. Thinking tokens count against the same budget, so a 1000-token cap can be exhausted before any summary text is produced, and when the response comes back with no content Open WebUI stores the partial reasoning as the checkpoint instead. - **Your system prompt, tools, and skills are preserved.** Compaction only summarizes conversation messages. The model, workspace and folder system prompts, the available tools and their instructions, skills and any RAG, web search or memory context are all reassembled fresh on every request, after compaction runs, so they are never summarized away. The one exception is older **tool-call results** that live in the chat history: a past tool result inside the compacted block is condensed into the summary, though what the model can still call is unaffected. A system message already sitting at the head of the request is held aside before compaction runs and put back at the front afterwards, so it keeps its position rather than being counted among the messages that may be summarized or reordered behind the summary. - **It fails safe.** If the summarizer returns nothing, Open WebUI falls back to a short mechanical summary (the previous summary plus truncated excerpts of the dropped messages). If compaction errors entirely, it is logged and the request proceeds with the full, uncompacted history. - **It splits at a user message, and can decline to split at all.** The cut is placed at a user message so a turn is never severed mid-exchange. If no suitable user message sits far enough back, for example a long conversation that is one enormous exchange rather than many turns, **compaction does not run for that request** and the full over-threshold history is sent. It is silent: there is no error, and it will try again on the next turn. So crossing the threshold does not guarantee compaction happened, and compaction is not a hard ceiling on what reaches the model. If you need a guaranteed bound, use a filter Function as below. diff --git a/docs/troubleshooting/index.mdx b/docs/troubleshooting/index.mdx index 00161ede9..18710069e 100644 --- a/docs/troubleshooting/index.mdx +++ b/docs/troubleshooting/index.mdx @@ -27,16 +27,19 @@ Use this page to find the right guide for your issue. If you're unsure where to | `WebSocket connection failed: 403` or chat hangs | [Connection Errors → WebSocket](./connection-error#websocket-troubleshooting) | | Can't connect to Ollama from Open WebUI | [Connection Errors → Ollama](./connection-error#connection-to-ollama-server) | | Model list takes forever to load / `500` on `/api/models` | [Connection Errors → Model List Loading](./connection-error#%EF%B8%8F-model-list-loading-issues-slow-ui--unreachable-endpoints) | +| Intermittent "Model not found", model list emptying itself, `ClientConnectorDNSError` | [Connection Errors → Intermittent Name Lookup Failures](./connection-error#-intermittent-name-lookup-failures-often-reported-as-model-not-found) | | `[SSL: CERTIFICATE_VERIFY_FAILED]` | [Connection Errors → SSL](./connection-error#-ssl-certificate-issues-with-internal-tools) | | Login loops, 401 Unauthorized, token errors across replicas | [Scaling & HA → Login Loops](./multi-replica#1-login-loops--401-unauthorized-errors) | | `database is locked`, data disappearing across instances | [Scaling & HA → Database](./multi-replica#4-database-corruption--locked-errors) | | Worker crash: `Child process [pid] died` during upload | [RAG → Worker Crashes](./rag#12-worker-dies-during-document-upload) | | Model ignores attached knowledge base | [RAG → Knowledge Base Not Working](./rag#13-knowledge-base-attached-to-model-not-working) | +| `Could not read content from `, or a YouTube video that will not attach | [RAG → Link and YouTube attachments](./rag#14-attaching-a-link-or-a-youtube-video-fails) | | Agent stops mid-task after many tool calls / `Tool-call limit reached (N iterations).` | [`CHAT_RESPONSE_MAX_TOOL_CALL_ITERATIONS`](/reference/env-configuration#chat_response_max_tool_call_iterations) | | `NoneType object has no attribute 'encode'` | [RAG → Embedding Error](./rag#5-400-nonetype-object-has-no-attribute-encode) | | CUDA out of memory during embedding | [RAG → CUDA OOM](./rag#10-cuda-out-of-memory-during-embedding) | | OAuth redirect loops, CSRF state mismatch | [SSO & OAuth](./sso) | | `CSRF Warning! State not equal in request and response` | [SSO → CSRF Errors](./sso#9-session-state-mismatch-csrf-errors) | +| SSO login ends with "The email or password provided is incorrect" and the log shows `Unsupported {'app_id'} in header` | [SSO → Vendor-specific ID token headers](./sso#cyberark-identity-apereo-cas-and-other-providers-with-vendor-specific-id-token-headers) | | TTS loading forever, `Dataset scripts are no longer supported` | [Audio → TTS Issues](./audio#tts-loading-forever--not-working) | | Whisper `int8 compute type` error | [Audio → STT Issues](./audio#whisper-stt-not-working--compute-type-error) | | Microphone not working (non-HTTPS) | [Audio → Microphone](./audio#microphone-access-issues) | @@ -54,7 +57,7 @@ Use this page to find the right guide for your issue. If you're unsure where to | Guide | Covers | | :--- | :--- | -| [Connection Errors](./connection-error) | HTTPS, CORS, WebSocket, reverse proxy, Ollama, SSL, Podman, MCP | +| [Connection Errors](./connection-error) | HTTPS, CORS, WebSocket, reverse proxy, Ollama, DNS, SSL, Podman, MCP | | [Performance & RAM](./performance) | Speed tuning, database optimization, scaling infrastructure, resource efficiency | | [Context Window / Prompt Too Long](./context-window) | Why "prompt is too long" errors happen and how to manage chat history with filters | | [RAG](./rag) | Document ingestion, retrieval quality, embeddings, upload limits, worker crashes | diff --git a/docs/troubleshooting/multi-replica.mdx b/docs/troubleshooting/multi-replica.mdx index 97fabe5be..13f4e7cc6 100644 --- a/docs/troubleshooting/multi-replica.mdx +++ b/docs/troubleshooting/multi-replica.mdx @@ -94,6 +94,8 @@ REDIS_URL=redis://your-redis-host:6379/0 For Ollama specifically, a chat sent to a model the replica has not seen no longer fails outright: the replica clears its model cache, re-reads the model list from the Ollama servers, and only reports the model as unknown if it is still missing. A model pulled or added while a replica was holding a stale list therefore becomes usable on the next request instead of after the cache expires. +If Redis is already configured and the model list still empties itself, the cause is probably not configuration sync at all but name resolution: on v0.11.0 the container could intermittently stop resolving the hostname of the Ollama or provider server, which reads as "Model not found". See [Intermittent Name Lookup Failures](/troubleshooting/connection-error#-intermittent-name-lookup-failures-often-reported-as-model-not-found). + ### 4. Database Corruption / "Locked" Errors **Symptoms:** @@ -322,17 +324,21 @@ Every Socket.IO event in a multi-replica deployment is published through Redis, | Path | Why it matters at scale | |---|---| | Socket.IO payloads, including the ones published over Redis, plus Redis-backed session and collaborative-document state | The reason to turn this on. Every live update crossing replicas is encoded and decoded here | +| Chat contents and the other JSON columns the database stores (user settings, the configuration table, folders, notes and so on) | The whole message tree is serialized on every save and parsed again on every open, so the cost grows with the length of the conversation, not with the number of requests | | Upstream provider responses (OpenAI-compatible and Ollama), including per-chunk parsing of streamed completions | Runs once per arriving token batch, so it scales with streaming volume rather than request count | +| Request bodies sent to model providers: OpenAI-compatible chat completions, embeddings and responses, the Ollama inference endpoints and the Anthropic passthrough | Each body carries the entire conversation or the whole embedding batch, so this is the largest single serialization on a chat request | | Incoming HTTP request bodies and outgoing `JSONResponse` bodies | The broadest surface, but individually the cheapest | +| Chunk metadata written and read by the Valkey vector store, and read by Oracle 23ai | Parsed once per result row, so it scales with how many chunks each knowledge base search returns | +| Results returned by built-in tools, and the permission tree resolved on sign-in, sign-up, OAuth callback and every session refresh | Small payloads, but they sit on paths every user hits repeatedly, and a session refresh happens on every page load | **Why it is opt-in.** orjson is stricter than the standard library, so the default keeps behaviour byte-for-byte identical to earlier releases. In practice the strictness is handled for you: dictionary keys that are not strings, integers beyond 64 bits, and `NaN` or `Infinity` literals are all rejected by orjson and fall back to the standard-library path automatically. Enabling this cannot turn a payload that worked into an error. Two differences do survive the fallback, neither of which affects a normal deployment: - **`NaN` and `Infinity` floats in a response body serialize as `null`** instead of raising. Starlette's own encoder is configured with `allow_nan=False`, so a response carrying those values previously failed outright and now goes out with nulls. If you have a custom tool or pipe that can emit them, this is a behaviour change to be aware of rather than a regression. -- **Encoded output carries raw UTF-8 rather than `\uXXXX` escapes.** Both are valid JSON and every client parses them identically, but the exact bytes differ, which matters only if something downstream checksums or string-compares encoded JSON. +- **Encoded output carries raw UTF-8 rather than `\uXXXX` escapes.** Both are valid JSON and every client parses them identically, but the exact bytes differ, which matters only if something downstream checksums or string-compares encoded JSON. This applies to stored data as well: rows written into the database's JSON columns, and chunk metadata written into the Valkey vector store, hold non-ASCII text raw and are correspondingly smaller. Each encoder reads the other's output, so rows written before you turned the setting on stay readable and turning it back off is equally safe; neither direction needs a migration. -**When not to bother.** On a single-worker, single-user instance the saving is real but invisible next to model latency. The setting earns its keep once Socket.IO traffic is crossing Redis between workers or replicas. +**When not to bother.** On a single-worker, single-user instance the saving is real but invisible next to model latency. The setting earns its keep once Socket.IO traffic is crossing Redis between workers or replicas. The one thing that can be felt on a small instance is very long chats, since the whole conversation is serialized on each save and parsed again on each open. See [`ENABLE_ORJSON`](/reference/env-configuration#enable_orjson) for the variable itself and [Scaling → Switch the JSON Encoder to orjson](/getting-started/advanced-topics/scaling#switch-the-json-encoder-to-orjson) for where it fits in a scaled rollout. diff --git a/docs/troubleshooting/performance.md b/docs/troubleshooting/performance.md index 6c03ef945..2a7ec3571 100644 --- a/docs/troubleshooting/performance.md +++ b/docs/troubleshooting/performance.md @@ -42,6 +42,8 @@ There are two separate settings in **Settings > Admin > Experience > Interface** * **External/Cloud**: `gpt-5-nano`, `gemini-2.5-flash-lite`, `llama-3.1-8b-instant` (OpenAI/Google/Groq/OpenRouter). * **Local**: `qwen3:1b`, `gemma3:1b`, `llama3.2:3b`. +**Tuning the requests themselves:** below the two model pickers, **Task Model Parameters > Configure** ([`TASK_MODEL_PARAMS`](/reference/env-configuration#task_model_params)) sets the generation parameters every background request is sent with, so you can cap output with `max_tokens`, lower `temperature` or set `reasoning_effort` low if you are stuck on a reasoning model. Note that setting anything here removes the built-in 1000-token cap on title generation and context compaction summaries, so add `max_tokens` explicitly if you want those bounded. + ### 2. Caching & Latency Optimization Configure these settings to reduce latency and external API usage. @@ -222,10 +224,11 @@ See [`ENABLE_COMPRESSION_MIDDLEWARE`](/reference/env-configuration#enable_compre #### JSON Encoder -Open WebUI encodes and decodes JSON constantly: every request body, every API response, every chunk of a streamed completion arriving from the provider, and every Socket.IO event, including the ones published over Redis when you run multiple workers or replicas. By default all of that goes through Python's standard-library `json` module. Setting `ENABLE_ORJSON=True` switches the whole application to [orjson](https://pypi.org/project/orjson/), a Rust implementation that is several times faster. It is already installed as a dependency, so this is a one-line change. +Open WebUI encodes and decodes JSON constantly: every request body, every API response, every chat written to and read back from the database, every request body sent on to a provider, every chunk of a streamed completion arriving back and every Socket.IO event, including the ones published over Redis when you run multiple workers or replicas. By default all of that goes through Python's standard-library `json` module. Setting `ENABLE_ORJSON=True` switches the whole application to [orjson](https://pypi.org/project/orjson/), a Rust implementation that is several times faster. It is already installed as a dependency, so this is a one-line change. * **Where the win is**: the Socket.IO encoding path. In clustered deployments, encoding live updates was the single largest cost measured on the workers handling them. Streaming responses benefit too, since every arriving chunk is parsed individually. -* **Where it is not**: a single-user instance. The saving is real but too small to notice against model latency. +* **Where else it shows up**: chat storage. A chat is held in a single JSON column, so the whole message tree is serialized on every save and parsed again on every open, and the cost of that grows with the length of the conversation. The request body sent upstream to the provider, which carries the same conversation, is encoded on the same path. +* **Where it is not**: a single-user instance with ordinary-sized chats. The saving is real but too small to notice against model latency. * **Why it is opt-in**: orjson is stricter than the standard library. Payloads it rejects (non-string dictionary keys, integers beyond 64 bits, `NaN`/`Infinity` literals) fall back to the standard-library path automatically, so nothing breaks, but the default stays on the standard library to keep behaviour byte-for-byte identical to earlier releases. The one behaviour change to be aware of: `NaN` and `Infinity` floats in a JSON response now serialize as `null` instead of raising. - **Env Var**: `ENABLE_ORJSON=True` @@ -252,6 +255,21 @@ Long LLM completions can exceed default HTTP client timeouts. Configure these to - **Env Var**: `AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST=15` (shorter for model listing) - **Env Var**: `AIOHTTP_CLIENT_TIMEOUT_OPENAI_MODEL_LIST=15` +#### DNS Resolver + +Every model call, web search fetch, RAG page load and tool call starts with a hostname lookup. By default those lookups go through the operating system resolver, which runs `getaddrinfo` on asyncio's default executor (a separate pool from `THREAD_POOL_SIZE`). That pool holds `min(32, cpu_count + 4)` threads and is shared with other blocking work, so under heavy concurrency lookups queue behind each other and behind unrelated jobs. + +Setting `AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER=True` switches to c-ares, which resolves on the event loop instead. Concurrent lookups then cost roughly what a single one costs, and a long blocking job can no longer stall name resolution for everyone else on the instance. + +* **Where the win is**: instances doing hundreds of concurrent outbound requests, especially alongside blocking work such as vector-DB batch upserts. +* **Where it is not**: anything below that. At low concurrency the two resolvers are indistinguishable on a real network. +* **Why it is opt-in**: c-ares does not resolve names the same way the rest of the machine does. It reads `/etc/resolv.conf` and the hosts file but not the rest of `nsswitch.conf`, so `.local` via avahi/mDNS, NIS or LDAP backends and Windows NBNS names resolve differently or not at all. On some Windows hosts it finds no usable nameserver, and in Docker its channel has been observed to intermittently stop resolving container names. v0.11.0 enabled it unconditionally and those failures are what made it a switch. + +- **Env Var**: `AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER=True` + * *Recommendation*: leave it off unless you have measured DNS as a bottleneck and confirmed c-ares resolves every name your deployment uses. Requires a restart. + +See [`AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER`](/reference/env-configuration#aiohttp_client_async_dns_resolver) for the variable itself, and [Intermittent Name Lookup Failures](/troubleshooting/connection-error#-intermittent-name-lookup-failures-often-reported-as-model-not-found) if you are debugging lookups that fail on and off. + #### Container Resource Limits For Docker deployments, ensure adequate resource allocation: @@ -527,7 +545,7 @@ For multi-user or growing deployments the durable fix is **PostgreSQL**, not SQL 10. **Caching**: `ENABLE_BASE_MODELS_CACHE=True`, `MODELS_CACHE_TTL=300`, `ENABLE_QUERIES_CACHE=True`. 11. **Redis**: Single instance with `timeout 1800` and high `maxclients` (10000+). See [Redis Tuning](#redis-tuning) below. 12. **Compression**: `ENABLE_COMPRESSION_MIDDLEWARE=False` **if** your load balancer / ingress / CDN compresses responses (enable it there instead). Saves ~3–4% CPU on every worker. See [HTTP Response Compression](#http-response-compression). -13. **JSON Encoder**: `ENABLE_ORJSON=True` (v0.11.0+). Cuts the cost of encoding Socket.IO events and parsing streamed provider chunks, which is the heaviest JSON work in a clustered deployment. See [JSON Encoder](#json-encoder). +13. **JSON Encoder**: `ENABLE_ORJSON=True` (v0.11.0+). Cuts the cost of the heaviest JSON work in a clustered deployment: encoding Socket.IO events, parsing streamed provider chunks and reading and writing whole chats in the database. See [JSON Encoder](#json-encoder). #### Redis Tuning @@ -585,6 +603,7 @@ For detailed information on all available variables, see the [Environment Config | :--- | :--- | | `TASK_MODEL` | [Task Model (Local)](/reference/env-configuration#task_model) | | `TASK_MODEL_EXTERNAL` | [Task Model (External)](/reference/env-configuration#task_model_external) | +| `TASK_MODEL_PARAMS` | [Task Model Parameters](/reference/env-configuration#task_model_params) | | `ENABLE_BASE_MODELS_CACHE` | [Cache Model List](/reference/env-configuration#enable_base_models_cache) | | `MODELS_CACHE_TTL` | [Model Cache TTL](/reference/env-configuration#models_cache_ttl) | | `ENABLE_QUERIES_CACHE` | [Queries Cache](/reference/env-configuration#enable_queries_cache) | @@ -594,6 +613,7 @@ For detailed information on all available variables, see the [Environment Config | `ENABLE_COMPRESSION_MIDDLEWARE` | [HTTP Response Compression](/reference/env-configuration#enable_compression_middleware) | | `ENABLE_ORJSON` | [JSON Encoder](/reference/env-configuration#enable_orjson) | | `THREAD_POOL_SIZE` | [Thread Pool Size](/reference/env-configuration#thread_pool_size) | +| `AIOHTTP_CLIENT_ASYNC_DNS_RESOLVER` | [DNS Resolver](/reference/env-configuration#aiohttp_client_async_dns_resolver) | | `RAG_EMBEDDING_ENGINE` | [Embedding Engine](/reference/env-configuration#rag_embedding_engine) | | `CONTENT_EXTRACTION_ENGINE` | [Content Extraction Engine](/reference/env-configuration#content_extraction_engine) | | `AUDIO_STT_ENGINE` | [STT Engine](/reference/env-configuration#audio_stt_engine) | diff --git a/docs/troubleshooting/rag.mdx b/docs/troubleshooting/rag.mdx index 11280d432..e7cb0c9e2 100644 --- a/docs/troubleshooting/rag.mdx +++ b/docs/troubleshooting/rag.mdx @@ -253,6 +253,7 @@ If your initial response is fast but follow-up questions become increasingly slo | 💀 Worker dies during upload (instant) | Switch away from default ChromaDB (SQLite) in multi-worker setups | | 💀 Worker dies during upload (timeout) | Update Open WebUI, or increase `--timeout-worker-healthcheck` | | 🧠 Model ignores attached KB | Enable Builtin Tools, add system prompt hints, or disable native function calling | +| 🗂 Single attached file returns nothing | Re-index to rebuild the per-file collections | --- @@ -524,4 +525,55 @@ For the full explanation of how knowledge scoping and retrieval modes work, see --- +### 14. Attaching a Link or a YouTube Video Fails + +You attached a webpage or a YouTube video to a chat (**+ > Attach Webpage**, or by typing the URL after `@`), and it came back as an error toast instead of a document. + +**The Problem**: The message names the step that actually failed. A link that could not be fetched or parsed is reported against that link, and a YouTube video whose transcript was refused is reported with the reason. Earlier releases reported both as `[ERROR: Error querying knowledge base]`, which named a stage the attachment had never reached, so the message said nothing about the real cause. + +#### A link that could not be read + +``` +400: [ERROR: Could not read content from https://example.com/page] +``` + +The page was not fetched or not parsed, so nothing reached the vector database. The URL in the message is the one that failed, which matters when you attach several at once. Common causes: + +- The site blocks the request or serves its content only after JavaScript runs. Switch [`WEB_LOADER_ENGINE`](/reference/env-configuration#web_loader_engine) to `playwright`. +- Open WebUI sits behind a proxy the loader is not using. See [`WEB_SEARCH_TRUST_ENV`](/reference/env-configuration#web_search_trust_env), which also governs the plain URL loader. +- The address is refused on purpose. Private and loopback addresses, cloud metadata endpoints and anything matched by [`WEB_FETCH_FILTER_LIST`](/reference/env-configuration#web_fetch_filter_list) are rejected before any request goes out. + +#### A YouTube video whose transcript was refused + +YouTube attachments are transcript based, so a video with no usable transcript cannot be attached. The message says which of these happened: + +| Message | What it means | +|---------|---------------| +| `YouTube blocked the transcript request for