Thanks to visit codestin.com
Credit goes to github.com

Skip to content

0.11.4 - #29960

Draft
tjbck wants to merge 171 commits into
mainfrom
dev
Draft

0.11.4#29960
tjbck wants to merge 171 commits into
mainfrom
dev

Conversation

@tjbck

@tjbck tjbck commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

No description provided.

AnthonyChen05 and others added 30 commits September 1, 2026 22:11
The `/` command menu is portalled into a tippy popup by
getSuggestionRenderer, and tippy's base stylesheet sets
.tippy-box { color: #fff }. The app's `transparent` theme neutralises
tippy's background, padding and margin but never its text colour, so
everything inside the popup inherits white.

DropdownMenu paints bg-white dark:bg-gray-850 dark:text-white, defining
a text colour only for dark mode, and the command rows in SlashCommands
set no colour of their own. In light theme that leaves Temporary, Model
and Settings as white text on a white menu.

Reset the colour on the transparent theme so the popup inherits from
body, which is #000 in light and #eee in dark. The secondary text and
the prompt rows were already unaffected because they set explicit
theme-aware colours.
Added missing translations.
* i18n: update Korean translations

* Update Korean translation

---------

Co-authored-by: bglee <[email protected]>
* add: new translations

* Update translations in zh-TW locale
#29515)

The regex detection helpers wrote their backslash escapes in ordinary string
literals, so Python reported six invalid escape sequences on import. They work
today because Python leaves an unrecognised escape as its two characters, but
that behaviour is deprecated and becomes a syntax error in a future release, at
which point the knowledge filesystem tools stop importing at all.

The literals are now raw, which is the same two characters with no warning.
Pattern detection and normalisation are unchanged: verified identical output
over every string up to length five drawn from the characters these helpers
look at.
…29509)

A direct-connection streaming request registers a per-request socket.io handler before it asks the browser to start the completion, and that handler was only removed once the response had been fully streamed. Every other way the request could end left it behind for the life of the process: the call to the browser raising, a non-success status, an ack with no arguments or an ack that is not an object, cancellation while waiting for that ack and a response body closed or garbage-collected before it finished. A client that repeatedly hits a failing direct connection grows the server's handler table and the closures it holds without bound, and nothing ever cleans it up.

The removal now runs on every exit from the request, through one named helper that pops with a default so it is safe to run twice on the paths where both the generator's finally and the response's background task fire. The guard covers the exchange up to the status read and catches BaseException, because cancellation is not an Exception, and re-raises it unchanged.

Measured across thirteen exit paths: twelve leak a handler on dev and none of those leak here. The thirteenth, a response body that is never iterated at all, behaves the same on both. 200 failing requests leave 200 handlers on dev and none on this branch. Streamed bytes on the success path, exception types and cancellation behaviour are unchanged.
Custom metadata attached to a file upload (e.g. via the API's
metadata field) was stored on the file row but silently dropped
when the file was chunked and embedded for RAG, so it never reached
the LLM through retrieved sources.

process_file() builds chunk metadata in several branches; three of
them already merge the file's meta dict in, but the branch used for
a fresh upload processed through a document loader did not. Bring
it in line with the others so custom metadata flows through
consistently regardless of upload path.

Reported in #29486.
Fill all remaining untranslated strings so both locales reach full
coverage:
- ru-RU: 967 strings translated
- uk-UA: 2110 strings translated

ru-RU also aligns terminology with the existing translations
(webhook -> вебхук, sub-agent -> субагент, reranker -> реранкер,
chunk -> чанк, parsing -> розбір/разбор) and standardizes "web search"
to «Поисковая система» across the whole file.

Co-authored-by: Claude Sonnet 5 <[email protected]>
The settings navigation group labels added in 006f95e (Basics,
Services, Preferences, Data, Experience, AI, Quality) were left
empty in every locale, so ru-RU and uk-UA fell back to the English
key text. Fill them for both locales.

Co-authored-by: Claude Sonnet 5 <[email protected]>
Fills the 917 empty strings in the es-ES locale and repairs 94 existing
entries that rendered incorrectly. No keys are added or removed, and the
terminology chosen by the Spanish community is preserved throughout: new
strings reuse the glossary already present in the file.

Filled strings:
- Reuse existing renderings so each English term keeps one Spanish form
  (chunk -> Fragmento, knowledge base -> Base de Conocimiento,
  workspace -> Espacio de Trabajo, skill -> Habilidad).
- Include the settings sidebar group headers added in 006f95e
  (Basics, Services, Preferences, Data, AI, Quality, Experience), which
  were otherwise falling back to English in the settings modal.
- Add real grammatical plural forms for every one/many/other variant.
  Spanish requires the `many` CLDR category, which English does not have.
- Preserve every {{placeholder}}, backtick, URL, HTML tag and CLI flag.

Repaired strings:
- 4 broken interpolations, including "Deleted {{name}}", whose placeholder
  had itself been translated to {{nombre}} and so rendered literally.
- 6 plural groups whose values carried the i18next key suffix as visible
  text (e.g. "{{count}} seleccionados_únicos"), and one where "_one" had
  been translated as the adjective "únicas".
- "Reset" now reads Restablecer rather than Reiniciar ("restart"), which
  misdescribed destructive actions such as Reset Vector Storage/Knowledge.
- "Access" (Acceso) separated from "Permissions" (Permisos); the *Access
  family was previously split between the two.
- "Chats Public Sharing" and "Chats Open Sharing" no longer render
  identically in the group permissions panel.
- "You" corrected to "Tú"; unaccented "Tu" is the possessive "your", and
  this string labels every user message bubble.
- "Channels" corrected from the singular "Canal".
- ~49 misspellings and missing accents (Conexxión, Interprete, Publicamente,
  Busqueda, Incrustración, Añador, Wev, actualiada, mantentrá).

Verified: 0 empty strings, key set identical to dev, 0 placeholder
mismatches, prettier --check passes, and all strings render correctly
through i18next 23.16.8 using the application's own options.

Co-authored-by: Claude Opus 5 <[email protected]>
Ten strings were still untranslated in de-DE, so German users saw raw English keys in the settings sidebar and in the interface settings. The settings group headings (Basics, Services, Preferences, Data, AI, Quality, Experience) all rendered in English above otherwise German tab names, plus the font family label and its description, and the multi-file upload failure toast in a knowledge base.

All ten now have German values, chosen to match the terminology the catalog already uses: AI as KI, Services as Dienste (matching Dienstkonto and the existing service endpoint strings), Interface as Benutzeroberfläche in the font description, and the third-person descriptive voice the neighbouring setting descriptions use. Experience is rendered as Benutzererlebnis rather than Darstellung because that group covers audio as well as interface and images. Both interpolation placeholders in the upload toast are preserved.

Only de-DE is touched. No key was added, removed or reordered, and no already-translated string was changed. The catalog now has no empty values left.
…29503)

Saving any tool or function in the admin UI threw "ModuleNotFoundError:
No module named 'click'" in the browser, even on a fresh tool with no
custom code, because the click name never appears in user code at all.

The in-browser formatter runs black through a Pyodide/micropip worker.
black needs click, mypy_extensions, pathspec, platformdirs and pytokens
at import time, but the vendored pyodide-lock.json records none of
these as black's dependencies, and micropip only walks a locked
package's declared deps when install() is given explicit constraints,
which this worker never does. So only black itself ever got installed.

Requesting the five packages explicitly alongside black fixes it
without touching the worker or the lock file.
A web search is not something that can be cited. The search engine
returns a title, a link and a one line snippet for each hit, and the
model never opens any of those pages. Emitting them as citation sources
produced one <source> tag per result, all named search_web with empty
bodies, and the citation template then instructed the model to cite them
by id. Models either hesitated visibly or attached an id to content from
a different result, which the citations panel then resolved to a title
that looked plausible, so the misattribution read as correct.

Web search results now stay in the tool output the model reads, and stop
being offered as things to cite. Where the model needs to cite a page it
calls fetch_url, whose citation names the URL and already works.

Web search results no longer appear in the citations panel. That is the
point of the change: the panel was offering pages that nothing had read.

Scoped to the native tool-calling path. The legacy handler cites every
tool result as one opaque source and does not single out web search, so
it is left alone rather than special-cased.
GET /api/version/updates returned the running version as latest whenever
the GitHub request failed, so an instance that cannot reach GitHub
reported itself up to date however far behind it was. The exception was
logged at debug, below the default level, so nothing recorded that the
check never happened.

The failure path now returns latest: None and logs at warning.

A null latest cannot be passed to compareVersion as it stood.
current.localeCompare(null) coerces to the string "null", and "0.10.2"
sorts before it, so the function returned true. The backend change alone
would have turned a false (latest) into a false update-available plus a
toast, so the guard is part of the fix.

The three callers stop substituting the running version in their catch,
and the two badge surfaces gain a third state. When latest is unknown
the badge is plain text, since there is no release to link to.

Admin Settings > General was wrong in a worse way than reported: it
initialised updateAvailable false with latest set to the running
version, and never checked on mount, so it claimed (latest) having made
no request at all. It now matches About.svelte, which starts unknown and
checks on mount.

Closes #29580
Inter ships arrow substitutions as OpenType contextual alternates, and
Open WebUI sets no font-variant-ligatures, so a sequence like <--- is
stored and sent exactly as typed while being drawn as an arrow. Reported
as text conversion in #29594, where the memory rule had in fact worked
and only the display was misleading.

Reading the DOM back with the bundled Inter file loaded in isolation
confirms every field holds U+3C U+2D U+2D U+2D. Only the glyphs differ.

no-contextual rather than none: none, no-contextual, and
font-feature-settings "calt" 0 all fix it, which places the arrow in
contextual alternates. no-contextual disables that one feature and
leaves standard ligatures intact, so ordinary prose is unaffected.

Set on html, next to the existing document-wide typography, so it
inherits to editable fields and rendered content without a new selector.
Scoping it to inputs would fix the field you type into and leave the
memory list and chat messages still drawing arrows.
The built-in chat and knowledge grep tools awaited their matching helper directly, so the search ran on the event loop and held it for as long as the match took. Both call sites now hand the helper to a worker thread.

Output and error handling are unchanged: 17 cases (literal, regex, case-insensitive, count-only, no-match, invalid pattern, rejected quantifiers, missing file data, result truncation) compare byte-for-byte against the previous behaviour. The matcher's time budget lives in a contextvar, which asyncio.to_thread copies into the worker, so budget scoping still behaves as before.
…ckends (#29502)

Chunk metadata inserted into the vector DB carries arbitrary client-
supplied fields (e.g. custom metadata from file uploads), so it needs
the same size cap, type coercion and null-byte sanitization every
other backend already applies through process_metadata(). Four
backends never called it: Qdrant, Qdrant multitenancy, Milvus
multitenancy and Oracle23ai, so an oversized or malformed metadata
blob went into those unfiltered.

Wire process_metadata() in at each backend's single insert/upsert
chokepoint, matching the pattern already used by the other eleven
backends.
Two entries lost their interpolation placeholder, so they render
literally instead of being substituted:

- "{{ models }}" had the placeholder name itself translated
- the 50-word summary prompt replaced {{topic}} with a bracketed note

The rest change the meaning or contradict neighbouring strings:

- "Enter Key Behavior" was read as the verb "enter", turning the label
  for how the Enter key behaves into "type in the behaviour key", while
  its own description already explains the setting correctly
- "Regenerate Menu" was read as "refresh the menu" rather than the menu
  of regenerate actions its description describes
- "Enter reasoning effort" was not meaningful Russian
- "Enter Bing Search V7 Subscription Key" mentioned an endpoint that the
  source string does not
- "Web Search in Chat" called the feature a search engine
- "Enter Application DN" said ND; "Enter Bocha Search API Key" said APi
- "Toast Notifications for New Updates" dropped "new" and used the wrong
  form of the preposition
- "Enter Top K Reranker" used a term its own label does not, and
  "Select a reranking model engine" differed from every other reranking
  string
- two of the four iframe sandbox switches did not follow the wording of
  the other two
- "Follow-Up Auto-Generation" capitalised a word mid-phrase

Only values changed; the keys and their order are untouched.
Adopts the loanwords normally used in Spanish-language developer and AI
interfaces for three terms the locale currently calques, and applies each
one consistently across the file.

- prompt:   Indicador -> Prompt   (74 strings)
- pipeline: Tubería   -> Pipeline (14 strings)
- delete:   Borrar    -> Eliminar (62 strings), matching the rendering the
            locale already uses for "remove" and closing the Borrar /
            Eliminar split that applied both words to the same action
- Admin -> Administrador, Email -> Correo electrónico (3 strings)

"Indicador" means indicator or gauge and is not how Spanish-language AI
tools refer to a prompt. "Tubería" is a physical pipe; the file already
hedged once with "Tuberías (Pipelines)". Gender agreement is updated where
it changes, since Pipeline is masculine and Tubería feminine.

Before this change the locale rendered "delete" as Borrar in 34 strings and
Eliminar in 28, with no distinction in meaning between them.

This changes wording contributed by the Spanish community rather than
fixing defects, so it is a terminology decision rather than a correctness
fix, and is kept separate from the translation work for that reason.

Co-authored-by: Claude Opus 5 <[email protected]>
tjbck and others added 20 commits September 12, 2026 15:41
… to Chat Completions (#29849)

* fix: drop thinking blocks when converting Anthropic Messages requests to Chat Completions

Claude Code and other Anthropic SDK clients pointed at /api/v1/messages send the assistant's earlier thinking blocks back with every follow-up request. Since 0.11.0 those blocks were copied into the OpenAI assistant message as content parts of type thinking, a part type Chat Completions does not define. Strict OpenAI-compatible servers such as NVIDIA Dynamo reject the whole request with 400 "data did not match any variant of untagged enum ChatCompletionRequestAssistantMessageContent", so a conversation with a reasoning model died on its second turn. The error reports its position at the very end of the body, which made the request look cut off; it was complete.

Thinking and redacted_thinking blocks are now skipped in the conversion, which is what happened before 0.11.0. An assistant turn that held only thinking blocks is kept as an empty assistant message so the turn order survives. Native Anthropic and LiteLLM connections are unaffected because they receive the request untouched, and thinking blocks in responses are still produced.

Fixes #29799

* fix: keep signed thinking blocks when converting Anthropic Messages requests

Dropping every thinking block also removed the signed ones. Those are the blocks a gateway such as LiteLLM forwards to Anthropic, which needs the signed thinking block of the previous assistant turn when a tool-use turn continues with extended thinking. Only the unsigned blocks are the problem: Open WebUI creates them itself from reasoning_content, and strict Chat Completions backends reject them because thinking is not a content part type they know.

Unsigned thinking blocks are now dropped while signed thinking and redacted_thinking blocks are kept, the same rule LiteLLM applies before forwarding to Anthropic and the rule the native chat path already uses for Anthropic reasoning details. Backends that never emit a signature, such as NVIDIA Dynamo and vLLM, keep receiving requests without thinking parts, so the original failure stays fixed.
…ofile images (#29889)

Setting ENABLE_PROFILE_IMAGE_URL_FORWARDING=false stops the user and model profile image endpoints from redirecting browsers to external avatar URLs, but channel webhook avatars kept redirecting regardless. An operator who turned the setting off precisely to stop clients leaking their IP, User-Agent and Referer to outside origins still leaked all three whenever anyone viewed a channel message posted by a webhook with an external profile image URL.

The webhook profile image endpoint now reads the same setting the user and model endpoints already read, and serves the bundled default image instead of the redirect when forwarding is off. Stored URLs are untouched, so turning the setting back on restores the previous behaviour.

Verified against the real handler with seeded webhook rows: with the setting unset or true the endpoint still returns the 302 with the original Location, with it false it returns the default favicon as image/png with no Location and no header carrying the external host, and the data URI, no image and unknown webhook responses are byte identical in both states.
Link URLs rendered from markdown, citations and web search results now pass a scheme check before they reach an anchor. A new safeLinkUrl helper sits beside isValidHttpUrl and keeps http, https, mailto, tel and relative URLs, returning undefined for anything else so the label renders without a link. Markdown links with an unusual scheme (ftp, sms, and application deep links such as obsidian or vscode) render as plain text from now on.

The citation checks move off a substring test for "http" onto isValidHttpUrl, which is what Citations.svelte already uses for the same question. That also drops two long-standing quirks: an uppercase HTTP:// source never rendered as a link, and a filename merely containing "http" rendered as a dead external one.
…dlers (#29918)

The three community origins were repeated inline in five window message handlers and now come from a single COMMUNITY_ORIGINS constant in constants.ts.

The sync stats modal uses that same list in both directions: it reads messages only from a community origin, replies to the origin the message came from, and names the community origins as the targets of the messages it sends. Its chat id goes into the request as one encoded path segment.
…xt (#29665)

When a tool returns a base64 image, Open WebUI only moves it out of the model's context if the entire result is that image, or if the tool is MCP. An image sitting inside a returned object or a list was serialised into the tool message instead, so a single screenshot could cost hundreds of thousands of tokens, push out the rest of the conversation and leave the model answering from garbage.

Any string in a tool result that is exactly one image data URI is now moved into the result's files wherever it sits in the structure, and replaced with a short marker. The model gets the image as an attachment rather than as text, and it renders for the user instead of being dropped.

Detection is deliberately limited to values that are entirely a data URI. Scanning inside longer strings was tried and abandoned: a payload wrapped over several lines, or one followed by text, gets cut short, and shipping a truncated image is worse than the bloat because the provider rejects the whole request.

This also fixes the OpenAPI branch removing entries from the list it was iterating over, which skipped every second data URI and left it in the model's context.

Fixes #29208
Syncing a knowledge base from a local directory only ever showed a
generic "Error accessing directory" toast when a per-file read
failed, and production builds strip console.error, so nothing else
recorded the cause either. On Windows this hides a real Chromium bug
where files with very long absolute paths throw a NotFoundError from
the File System Access API, leaving no way to tell which file failed
or why.

Both per-file read paths (the directory picker and drag-and-drop) now
wrap read failures with the file's relative path and the underlying
browser error before they reach the toast, so the message actually
names the file and the reason. Reuses the existing translated toast
text instead of adding a new i18n key, so the fix doesn't orphan
existing translations of that string.
…29495)

Pressing stop saved the assistant message as finished while its output items were still marked as running, so the affected block kept showing "Thinking...", "Analyzing..." or "Executing...". That state was written to the database, so it came back after every reload. A tool call cancelled mid-execution was affected as well: it is marked completed as soon as its arguments finish streaming, well before the tool returns, and the client reads that as still executing until the result item arrives.

Cancelling now closes those items before the message is saved, marking them incomplete, which is the status the client already treats as finished without flagging an error. Tool calls waiting for approval are left untouched so their approval prompt survives a reload. The corrected output is sent on the chat:tasks:cancel event that was already being emitted, so an open tab settles immediately instead of only after a reload.

Emitting a chat:completion event instead would have fired response auto-copy, text to speech playback and the chat finished listeners on a response the user had just cancelled.

Verified on a running instance against a mock upstream: cancelling mid-response leaves no item marked as running in the saved message, and the identical run on unpatched code leaves one.

Fixes #29281
Comment thread backend/open_webui/utils/middleware.py Dismissed
Comment thread backend/open_webui/utils/middleware.py Dismissed
Classic298 and others added 7 commits September 12, 2026 18:10
…isting handlers (#29622)

The model listing routes accept the backend index as a path segment and as a query parameter on the index-less sibling route, so the check now runs in the handler and applies to both forms.
@CherrieTheShifter

Copy link
Copy Markdown

Yes This

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.