Commit Graph
17468 Commits
Author SHA1 Message Date
Timothy Jaeryang Baek 49abfbdd15 refac 2026-07-23 13:18:04 -04:00
da7097565c perf: deduplicate repeated config fetches in Ollama request handlers (#27226)
The per-request Ollama handlers (chat, generate, embed, embeddings,
and the OpenAI-compat completions/chat-completions/messages/responses
endpoints) fetched 'ollama.api_configs' up to three times and
'ollama.base_urls' separately within a single request — the .get()
default-argument pattern made the second api_configs fetch
unconditional, and get_api_key() triggered a third. Up to four
sequential SELECTs per request collapse to one.

A new get_ollama_connection_config() helper fetches base_urls and
api_configs together in one batched Config.get_many where both are
needed; handlers that only need api_configs fetch it once into a
local. Admin operations (pull/push/copy/delete) and the TTL-cached
model-list path are deliberately left untouched.

Resolution semantics (str(idx) key first, url-key legacy fallback,
same defaults) are unchanged.


Claude-Session: https://claude.ai/code/session_01MHg5zs1VBjvRWQ54qHpfYD

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 12:48:55 -04:00
Timothy Jaeryang BaekandClassic298 85664f650c refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2026-07-23 12:48:23 -04:00
Timothy Jaeryang Baek f9107edeeb refac 2026-07-23 12:48:14 -04:00
8ace4f0a8a perf: stop recomputing static work in per-response ASGI middlewares (#27229)
SecurityHeadersMiddleware called set_security_headers() on every
response — 14 os.environ.get lookups plus a regex validation per
configured header, for values that are static for the process
lifetime. Compute the header list once at construction; when no
security env vars are set, skip wrapping send entirely.

RedirectMiddleware decoded and parse_qs'd the query string of every
GET, though it only acts on /watch?v= and ?shared= URLs. Add a cheap
path/substring precheck first; a false positive just falls through to
the previous full parse, so no redirect behavior changes.

Verified byte-identical responses (status, Location, header values)
against the previous implementations across redirect, passthrough,
and no-env cases.


Claude-Session: https://claude.ai/code/session_01MHg5zs1VBjvRWQ54qHpfYD

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 12:29:01 -04:00
Timothy Jaeryang Baek 1513ddaf58 refac 2026-07-23 12:25:17 -04:00
62491debfa perf: linear content accumulation in the streaming response handler (#27231)
The streaming handler rebuilt the full accumulated response with
`content = f'{content}{value}'` on every content delta — a complete
string copy per chunk, making accumulation O(n^2) over the response
length. Use in-place `content += value` for the (universal) str case,
which CPython extends in place, keeping accumulation O(n); the
f-string fallback is preserved for non-str values so coercion
behavior is unchanged.

In the ENABLE_REALTIME_CHAT_SAVE branch, full_output() — which
concatenates the entire accumulated output — was called twice per
chunk (once for the DB upsert, once for the emitted delta). Compute
it once and reuse.


Claude-Session: https://claude.ai/code/session_01MHg5zs1VBjvRWQ54qHpfYD

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 12:24:29 -04:00
Classic298andGitHub 8becf9443e fix: only admins may switch the global Automatic1111 checkpoint from image generation (#27244)
The Automatic1111 branch of the image generation route called set_image_model whenever the request carried a model field. On this backend set_image_model is not request-scoped: it persists image_generation.model to the global configuration and posts the new sd_model_checkpoint to the shared server, because Automatic1111 holds a single checkpoint instance-wide. A non-admin holding features.image_generation could therefore change the instance-wide image model and the shared backend checkpoint for every user by sending a model on an ordinary generation request, even though the setting is otherwise managed only through the admin-only image configuration route and the frontend never sends this field.

Gate the switch on an admin caller. A non-admin now generates on the currently configured checkpoint and the model field no longer mutates global state; admins retain per-request model switching here and through the image configuration route. Image editing is unaffected, as it selects its model per request without writing global configuration.
2026-07-23 12:23:24 -04:00
9a6d168499 fix: enforce action availability and model access on the chat action route (#27243)
The chat action route loaded a Function by its raw action_id and executed its action callable after only checking that the id and the requested model existed. The model list that the client renders actions from resolves each model's actions to the active action-type Functions that are global or assigned to that model, and the action route did not mirror that resolution, so a disabled, unassigned, or wrong-type Function, or an action on a model the caller cannot access, could be reached by calling the route directly.

Gate the route on the same rules the model resolution applies: the Function must be an active action, and for server-resolved models the caller must have model access and the action must be one the model actually surfaces (matched by function id, the prefix of each model actions entry, so single and sub-actions both resolve). Direct connections carry a client-supplied model the caller already owns, so the model-bound checks are scoped to non-direct calls; the active-action check always applies. Executing admin-authored Function code remains intended behaviour — this only keeps the route consistent with which actions each model exposes.

Co-authored-by: komyunghan <komyunghan@users.noreply.github.com>
2026-07-23 12:23:05 -04:00
9a54bc4bbb perf: halve function-table queries in get_all_models (#27230)
get_all_models ran four function-table queries: global actions, active
actions, global filters, active filters. Global functions are by
definition (type, is_active=True, is_global=True) — a subset of the
active set — so the global id sets can be derived from the active-rows
queries' is_global flag. Four queries become two, and each dropped
query returned full rows including every plugin's source code.

Also folds the mid-function 'models.default_metadata' read into the
Config.get_many already issued at the top of the function (one fewer
round trip; the existing `or {}` default handling is preserved).


Claude-Session: https://claude.ai/code/session_01MHg5zs1VBjvRWQ54qHpfYD

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 12:11:51 -04:00
32242a6788 perf: 40% LESS CPU usage: cut per-instance CPU cost of shared socket.io Redis pub/sub channel (#27282)
* perf: cut per-instance CPU cost of shared socket.io Redis pub/sub channel

Profiling a multi-instance deployment (py-spy --gil) showed ~44% of worker
CPU in the socket.io pub/sub listener. Two causes, two fixes:

- Add hiredis so redis-py parses the RESP protocol in C instead of pure
  Python (redis/_parsers/resp3.py alone accounted for ~28% of GIL samples;
  redis-py auto-selects the hiredis parser when importable).

- Subclass AsyncRedisManager to drop emits whose target room has no local
  participants before upstream _handle_emit re-encodes the full packet.
  Every instance receives every emit published on the shared channel, so
  with N instances all but the hosting one were paying full packet
  re-serialization per message just to deliver it to nobody. Broadcasts
  (room=None) are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9CQ9qnp3sZGYQQwztsCJT

* fix: restrict pub/sub emit early-out to string rooms

Adversarial review against python-socketio 5.16.2 found one divergence
from upstream: for a degenerate empty-sequence room (emit to room=[]) on
an instance whose namespace has no local clients, the filter's
get_participants probe raises IndexError from room[0] where upstream
returns silently at the namespace guard and still publishes to Redis.
Open WebUI only ever emits to scalar string rooms or room=None, so the
case is unreachable today; guard on isinstance(room, str) anyway so any
non-string room shape passes through to upstream behavior unchanged.

Every open-webui emit uses a string room, so the fast path still covers
all real traffic.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9CQ9qnp3sZGYQQwztsCJT

* Update requirements.txt

* Update pyproject.toml

* Update requirements-min.txt

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 12:11:38 -04:00
Timothy Jaeryang Baek aaf2834db7 refac 2026-07-23 12:03:26 -04:00
Timothy Jaeryang Baek d0f7da4f45 refac 2026-07-23 04:45:27 -04:00
Timothy Jaeryang Baek bb12b1a18b refac 2026-07-23 04:16:14 -04:00
Timothy Jaeryang Baek cc9a44569e refac 2026-07-23 04:01:30 -04:00
Timothy Jaeryang Baek 48625e657f refac 2026-07-23 03:54:19 -04:00
073cd65afe Log upstream provider rejections at warn/error level (#27238)
When an upstream provider rejects a request (e.g. a 400 for a
max_tokens value above the model's ceiling), the actionable error
message was only published to event sinks, which are invisible unless
an event function or webhook is configured. Admins had to query the
provider's API directly to diagnose failures (open-webui#27237).

Add a single log line in publish_model_provider_request_failed — the
chokepoint every upstream failure path (OpenAI-compatible chat,
embeddings, responses, token counting, and Ollama) already routes
through — recording status, provider, url, model, error code, and the
upstream message truncated to 1000 chars. 4xx logs at WARNING, 5xx at
ERROR. Client-facing responses are unchanged, so no additional error
detail is exposed in the chat.


Claude-Session: https://claude.ai/code/session_018VecyiPejru1EVF5yfe2sU

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-23 03:42:48 -04:00
Timothy Jaeryang Baek 48cc9d388e refac 2026-07-23 03:39:56 -04:00
Timothy Jaeryang Baek e18e249d5d refac 2026-07-23 03:39:30 -04:00
Timothy Jaeryang Baek af629177f4 refac 2026-07-23 03:31:32 -04:00
Classic298andGitHub 3cf3f8e189 fix: add missing folders field to SharingPermissions so the permission persists (#27296)
`sharing.folders` is present in `DEFAULT_USER_PERMISSIONS` but absent from the `SharingPermissions` response/update schema, so the admin default and group permission API silently drops it on every round-trip and the setting is never saved. Add `folders: bool = False`, matching the config default (`USER_PERMISSIONS_FOLDERS_ALLOW_SHARING`), restoring parity with `DEFAULT_USER_PERMISSIONS`.

Fixes #27120.
2026-07-23 03:24:51 -04:00
Andi ChandlerandGitHub adf07e8df0 **i18n**: Internationalization or localization changes (#27304)
* Change spelling to British English in translation.json

Updated translations to use British English spelling for various terms.

* Update translation.json
2026-07-23 03:24:21 -04:00
joaobackandGitHub 1b28b8a144 i18n: add pt-BR translations for newly added UI items and consistency pass (#27324)
New **pt-BR** translations for items introduced in the latest releases, plus a consistency/quality pass across existing strings (grammar, tone, capitalization, pluralization). Placeholders and hotkeys preserved. No logic changes.
2026-07-23 03:23:47 -04:00
Timothy Jaeryang Baek 9f00b62b3a refac 2026-07-23 03:22:51 -04:00
Timothy Jaeryang Baek 30415c925a refac 2026-07-23 03:11:38 -04:00
Timothy Jaeryang Baek 6ff1df326c refac 2026-07-23 03:05:29 -04:00
Timothy Jaeryang Baek 060d5da473 refac 2026-07-23 03:01:01 -04:00
Timothy Jaeryang Baek 73421c5b42 refac 2026-07-23 02:55:06 -04:00
Timothy Jaeryang Baek cf887b68ea refac 2026-07-23 02:54:56 -04:00
Timothy Jaeryang Baek 5418ac921b refac 2026-07-23 02:33:09 -04:00
Timothy Jaeryang Baek c4efa81d08 refac 2026-07-21 14:18:41 -04:00
Timothy Jaeryang Baek 9ca8cf528a refac 2026-07-21 14:16:51 -04:00
Timothy Jaeryang Baek 409fb39717 refac 2026-07-21 13:53:30 -04:00
Timothy Jaeryang Baek 86efecd9ad refac 2026-07-20 22:45:50 -04:00
Timothy Jaeryang Baek 8631dc83dc refac 2026-07-20 22:27:13 -04:00
Timothy Jaeryang Baek 6940297486 refac 2026-07-20 22:27:09 -04:00
Timothy Jaeryang Baek 49e57f4e7e chore: format 2026-07-20 22:11:42 -04:00
Timothy Jaeryang Baek 4a42543fc3 refac 2026-07-20 22:11:16 -04:00
Timothy Jaeryang Baek e88d2e053c refac 2026-07-20 22:10:11 -04:00
Timothy Jaeryang Baek 704d07e9a2 refac 2026-07-20 22:04:39 -04:00
Timothy Jaeryang Baek bc8d24c951 refac 2026-07-20 22:03:31 -04:00
Timothy Jaeryang Baek 1428a4ddce refac 2026-07-20 21:44:12 -04:00
Timothy Jaeryang Baek 0c7ddbdb4f refac 2026-07-20 19:49:34 -04:00
Timothy Jaeryang Baek 2fcb36267f refac 2026-07-20 01:33:53 -04:00
Timothy Jaeryang Baek af9a315ac3 refac 2026-07-20 01:33:47 -04:00
Timothy Jaeryang Baek 6e5efc1f75 refac 2026-07-20 01:21:15 -04:00
Timothy Jaeryang Baek 4da2ff2655 refac 2026-07-20 00:25:37 -04:00
Timothy Jaeryang Baek d3ea51fd46 refac 2026-07-20 00:23:01 -04:00
Timothy Jaeryang Baek 2dbdba1f91 refac 2026-07-17 23:39:49 -04:00
Timothy Jaeryang Baek 1a32d92d08 refac 2026-07-17 06:50:16 -04:00