From 5c403fb82919665e8ac36c43bae0cdd66531a1e7 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 24 Feb 2026 22:58:23 +0100 Subject: [PATCH] fix: resolve valve priority for actions and filters via class instantiation (#21841) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix: resolve valve priority for actions and filters via class instantiation The priority sorting for action buttons and filter execution order read valve data directly from the database JSON column using Functions.get_function_valves_by_id(). This returns only explicitly saved values — when a developer defines priority as a class default in their Valves definition (e.g. priority: int = 5) without ever opening the Valves UI to persist it, the database column remains empty. Every function then resolves to priority 0, and the preceding set() deduplication produces non-deterministic iteration order that the stable sort preserves — resulting in random button placement on every page load. The fix instantiates the Valves class with database values as keyword overrides: Valves(**(db_valves or {})). This merges any persisted overrides onto the code-defined defaults, matching the pattern already established in the action execution handler, filter processing pipeline, and tool module initialization. A secondary sort key (the function ID) ensures fully deterministic ordering even when multiple functions share the same priority value. Affected locations: - get_action_priority in utils/models.py (action button ordering) - get_priority in utils/filter.py (filter execution ordering) --- backend/open_webui/utils/filter.py | 14 +++++++++----- backend/open_webui/utils/models.py | 13 ++++++++++--- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/backend/open_webui/utils/filter.py b/backend/open_webui/utils/filter.py index 37349d290..9c71f0d65 100644 --- a/backend/open_webui/utils/filter.py +++ b/backend/open_webui/utils/filter.py @@ -22,10 +22,14 @@ def get_function_module(request, function_id, load_from_db=True): def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list = None): def get_priority(function_id): - function = Functions.get_function_by_id(function_id) - if function is not None: - valves = Functions.get_function_valves_by_id(function_id) - return valves.get("priority", 0) if valves else 0 + try: + function_module = get_function_module(request, function_id) + if function_module and hasattr(function_module, "Valves"): + valves_db = Functions.get_function_valves_by_id(function_id) + valves = function_module.Valves(**(valves_db if valves_db else {})) + return getattr(valves, "priority", 0) + except Exception: + pass return 0 filter_ids = [function.id for function in Functions.get_global_filter_functions()] @@ -50,7 +54,7 @@ def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list = None) ] filter_ids = [fid for fid in filter_ids if fid in active_filter_ids] - filter_ids.sort(key=get_priority) + filter_ids.sort(key=lambda fid: (get_priority(fid), fid)) return filter_ids diff --git a/backend/open_webui/utils/models.py b/backend/open_webui/utils/models.py index d890dc0a2..6c82b4aa9 100644 --- a/backend/open_webui/utils/models.py +++ b/backend/open_webui/utils/models.py @@ -332,8 +332,15 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None) meta[key] = copy.deepcopy(value) def get_action_priority(action_id): - valves = Functions.get_function_valves_by_id(action_id) - return valves.get("priority", 0) if valves else 0 + try: + function_module = request.app.state.FUNCTIONS.get(action_id) + if function_module and hasattr(function_module, "Valves"): + valves_db = Functions.get_function_valves_by_id(action_id) + valves = function_module.Valves(**(valves_db if valves_db else {})) + return getattr(valves, "priority", 0) + except Exception: + pass + return 0 for model in models: action_ids = [ @@ -341,7 +348,7 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None) for action_id in list(set(model.pop("action_ids", []) + global_action_ids)) if action_id in enabled_action_ids ] - action_ids.sort(key=get_action_priority) + action_ids.sort(key=lambda aid: (get_action_priority(aid), aid)) filter_ids = [ filter_id