Skip to content

Commit 14ea789

Browse files
Algorithm5838github-actions[bot]
authored andcommitted
fix: respect content edits for assistant messages with output
1 parent 2849ce8 commit 14ea789

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

backend/open_webui/utils/middleware.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
convert_logit_bias_input_to_json,
9595
get_content_from_message,
9696
convert_output_to_messages,
97+
filter_output_by_content,
9798
)
9899
from open_webui.utils.tools import (
99100
get_tools,
@@ -1948,11 +1949,40 @@ def process_messages_with_output(messages: list[dict]) -> list[dict]:
19481949

19491950
for message in messages:
19501951
if message.get("role") == "assistant" and message.get("output"):
1951-
# Use output items for clean OpenAI-format messages
1952-
output_messages = convert_output_to_messages(message["output"])
1952+
# Drop output items for tool call blocks removed from content
1953+
output = filter_output_by_content(
1954+
message["output"], message.get("content", "")
1955+
)
1956+
1957+
# Use content for text (respects edits), output for structured items
1958+
content = re.sub(
1959+
r"<details\b[^>]*>.*?</details>", "",
1960+
message.get("content", ""), flags=re.S,
1961+
).strip()
1962+
non_message_items = [
1963+
i for i in output if i.get("type") != "message"
1964+
]
1965+
output_messages = convert_output_to_messages(non_message_items)
1966+
19531967
if output_messages:
1968+
# Prepend edited text to first assistant message
1969+
for om in output_messages:
1970+
if om.get("role") == "assistant":
1971+
om["content"] = (
1972+
(content + "\n" + om["content"]).strip()
1973+
if om.get("content")
1974+
else content
1975+
)
1976+
content = ""
1977+
break
1978+
if content:
1979+
output_messages.insert(
1980+
0, {"role": "assistant", "content": content}
1981+
)
19541982
processed.extend(output_messages)
1955-
continue
1983+
elif content:
1984+
processed.append({"role": "assistant", "content": content})
1985+
continue
19561986

19571987
# Strip 'output' field before adding (LLM shouldn't see it)
19581988
clean_message = {k: v for k, v in message.items() if k != "output"}

backend/open_webui/utils/misc.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,22 @@ def flush_pending():
261261
return messages
262262

263263

264+
def filter_output_by_content(output: list, content: str) -> list:
265+
"""
266+
Drop function_call and function_call_output items from output for any
267+
tool call block removed from the message content.
268+
"""
269+
present_call_ids = set(
270+
re.findall(r'<details\s[^>]*\btype="tool_calls"[^>]*\bid="([^"]+)"', content)
271+
)
272+
return [
273+
item
274+
for item in output
275+
if item.get("type") not in ("function_call", "function_call_output")
276+
or item.get("call_id", "") in present_call_ids
277+
]
278+
279+
264280
def get_last_user_message(messages: list[dict]) -> Optional[str]:
265281
message = get_last_user_message_item(messages)
266282
if message is None:

0 commit comments

Comments
 (0)