From 0afe69e1a744226fcdb2265c7b79741d77d71691 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:44:33 +0200 Subject: [PATCH] fix: stop deleting user text that looks like a skill mention (#29051) Any `<$...>` run in a chat message was treated as an inline skill mention and removed before the request reached the model, so text like `<$(=MonthStart($(vMaxMonthEndINC)))"}, [Registration day] >` silently vanished mid-message and the model only saw the part before it. The mention regexes accepted any character except `|` and `>` as the skill id, so they matched far more than real mentions. Skill ids are already validated as `[a-z0-9_-]+` when a skill is created, so both regexes now require that charset. Ordinary text passes through untouched while `<$id>`, `<$id|Label>` and `` still resolve and strip as before. Verified against the reported message (now preserved verbatim) and the three mention forms. Co-authored-by: Claude --- backend/open_webui/utils/middleware.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index cc5f57e0c3..d80066e1dd 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2265,7 +2265,8 @@ def sanitize_tool_pairs(messages: list[dict]) -> list[dict]: return sanitized -SKILL_MENTION_RE = re.compile(r'<(?:\$([^|>]+)(?:\|[^>]*)?|/([^|>]+)\|[^>]*)>') +# Ids are validated as [a-z0-9_-]+ on create; matching that keeps ordinary "<$..." text intact. +SKILL_MENTION_RE = re.compile(r'<(?:\$([a-z0-9_-]+)(?:\|[^>]*)?|/([a-z0-9_-]+)\|[^>]*)>') def _get_text_parts(message: dict) -> list[str]: @@ -2287,7 +2288,7 @@ def extract_skill_ids_from_messages(messages: list[dict]) -> set[str]: return ids -SKILL_MENTION_STRIP_RE = re.compile(r'<(?:\$[^|>]+(?:\|([^>]*))?|/[^|>]+\|([^>]*))>') +SKILL_MENTION_STRIP_RE = re.compile(r'<(?:\$[a-z0-9_-]+(?:\|([^>]*))?|/[a-z0-9_-]+\|([^>]*))>') def strip_skill_mentions(messages: list[dict]) -> None: