chore: format
This commit is contained in:
@@ -139,16 +139,23 @@ def has_access(
|
||||
continue
|
||||
principal_type = grant.get("principal_type")
|
||||
principal_id = grant.get("principal_id")
|
||||
if principal_type == "user" and (principal_id == "*" or principal_id == user_id):
|
||||
if principal_type == "user" and (
|
||||
principal_id == "*" or principal_id == user_id
|
||||
):
|
||||
return True
|
||||
if principal_type == "group" and user_group_ids and principal_id in user_group_ids:
|
||||
if (
|
||||
principal_type == "group"
|
||||
and user_group_ids
|
||||
and principal_id in user_group_ids
|
||||
):
|
||||
return True
|
||||
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def migrate_access_control(data: dict, ac_key: str = "access_control", grants_key: str = "access_grants") -> None:
|
||||
def migrate_access_control(
|
||||
data: dict, ac_key: str = "access_control", grants_key: str = "access_grants"
|
||||
) -> None:
|
||||
"""
|
||||
Auto-migrate a config dict in-place from legacy access_control dict to access_grants list.
|
||||
|
||||
@@ -169,17 +176,21 @@ def migrate_access_control(data: dict, ac_key: str = "access_control", grants_ke
|
||||
if not perm_data:
|
||||
continue
|
||||
for group_id in perm_data.get("group_ids", []):
|
||||
grants.append({
|
||||
"principal_type": "group",
|
||||
"principal_id": group_id,
|
||||
"permission": perm,
|
||||
})
|
||||
grants.append(
|
||||
{
|
||||
"principal_type": "group",
|
||||
"principal_id": group_id,
|
||||
"permission": perm,
|
||||
}
|
||||
)
|
||||
for uid in perm_data.get("user_ids", []):
|
||||
grants.append({
|
||||
"principal_type": "user",
|
||||
"principal_id": uid,
|
||||
"permission": perm,
|
||||
})
|
||||
grants.append(
|
||||
{
|
||||
"principal_type": "user",
|
||||
"principal_id": uid,
|
||||
"permission": perm,
|
||||
}
|
||||
)
|
||||
|
||||
data[grants_key] = grants
|
||||
data.pop(ac_key, None)
|
||||
|
||||
@@ -28,7 +28,6 @@ from open_webui.env import AUDIT_LOG_LEVEL, MAX_BODY_LOG_SIZE
|
||||
from open_webui.utils.auth import get_current_user, get_http_authorization_cred
|
||||
from open_webui.models.users import UserModel
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from loguru import Logger
|
||||
|
||||
@@ -222,7 +221,9 @@ class AuditLoggingMiddleware:
|
||||
|
||||
# Skip logging if the request is not authenticated
|
||||
# Check both Authorization header (API keys) and token cookie (browser sessions)
|
||||
if not request.headers.get("authorization") and not request.cookies.get("token"):
|
||||
if not request.headers.get("authorization") and not request.cookies.get(
|
||||
"token"
|
||||
):
|
||||
return True
|
||||
|
||||
# match either /api/<resource>/...(for the endpoint /api/chat case) or /api/v1/<resource>/...
|
||||
|
||||
@@ -46,7 +46,6 @@ from open_webui.env import (
|
||||
from fastapi import BackgroundTasks, Depends, HTTPException, Request, Response, status
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
SESSION_SECRET = WEBUI_SECRET_KEY
|
||||
|
||||
@@ -57,7 +57,6 @@ from open_webui.utils.filter import (
|
||||
|
||||
from open_webui.env import GLOBAL_LOG_LEVEL, BYPASS_MODEL_ACCESS_CONTROL
|
||||
|
||||
|
||||
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -341,7 +340,9 @@ async def chat_completed(request: Request, form_data: dict, user: Any):
|
||||
}
|
||||
|
||||
try:
|
||||
filter_ids = get_sorted_filter_ids(request, model, metadata.get("filter_ids", []))
|
||||
filter_ids = get_sorted_filter_ids(
|
||||
request, model, metadata.get("filter_ids", [])
|
||||
)
|
||||
filter_functions = Functions.get_functions_by_ids(filter_ids)
|
||||
|
||||
result, _ = await process_filter_functions(
|
||||
|
||||
@@ -8,7 +8,6 @@ import aiohttp
|
||||
import websockets
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -86,4 +86,3 @@ async def generate_embeddings(
|
||||
form_data=form_data,
|
||||
user=user,
|
||||
)
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ from open_webui.env import (
|
||||
ENABLE_OTEL_LOGS,
|
||||
)
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from loguru import Record
|
||||
|
||||
|
||||
@@ -133,7 +133,6 @@ from open_webui.env import (
|
||||
from open_webui.utils.headers import include_user_info_headers
|
||||
from open_webui.constants import TASKS
|
||||
|
||||
|
||||
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -2106,10 +2105,15 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
if all_skill_ids:
|
||||
from open_webui.models.skills import Skills as SkillsModel
|
||||
|
||||
accessible_skill_ids = {s.id for s in SkillsModel.get_skills_by_user_id(user.id, "read")}
|
||||
accessible_skill_ids = {
|
||||
s.id for s in SkillsModel.get_skills_by_user_id(user.id, "read")
|
||||
}
|
||||
available_skills = [
|
||||
s for sid in all_skill_ids
|
||||
if sid in accessible_skill_ids and (s := SkillsModel.get_skill_by_id(sid)) and s.is_active
|
||||
s
|
||||
for sid in all_skill_ids
|
||||
if sid in accessible_skill_ids
|
||||
and (s := SkillsModel.get_skill_by_id(sid))
|
||||
and s.is_active
|
||||
]
|
||||
|
||||
if available_skills:
|
||||
@@ -2238,7 +2242,9 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
if ENABLE_FORWARD_USER_INFO_HEADERS and user:
|
||||
headers = include_user_info_headers(headers, user)
|
||||
if metadata and metadata.get("chat_id"):
|
||||
headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = metadata.get("chat_id")
|
||||
headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = metadata.get(
|
||||
"chat_id"
|
||||
)
|
||||
|
||||
mcp_clients[server_id] = MCPClient()
|
||||
await mcp_clients[server_id].connect(
|
||||
@@ -2812,9 +2818,7 @@ async def non_streaming_chat_response_handler(response, ctx):
|
||||
"id": output_id("msg"),
|
||||
"status": "completed",
|
||||
"role": "assistant",
|
||||
"content": [
|
||||
{"type": "output_text", "text": content}
|
||||
],
|
||||
"content": [{"type": "output_text", "text": content}],
|
||||
}
|
||||
]
|
||||
|
||||
@@ -2967,9 +2971,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
match = re.search(start_tag_pattern, content)
|
||||
if match:
|
||||
try:
|
||||
attr_content = (
|
||||
match.group(1) if match.group(1) else ""
|
||||
)
|
||||
attr_content = match.group(1) if match.group(1) else ""
|
||||
except:
|
||||
attr_content = ""
|
||||
|
||||
@@ -2982,7 +2984,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
current_text = get_last_text(output)
|
||||
set_last_text(
|
||||
output,
|
||||
current_text.replace(match.group(0) + after_tag, "")
|
||||
current_text.replace(match.group(0) + after_tag, ""),
|
||||
)
|
||||
|
||||
if before_tag:
|
||||
@@ -3031,7 +3033,9 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
"id": output_id("msg"),
|
||||
"status": "in_progress",
|
||||
"role": "assistant",
|
||||
"content": [{"type": "output_text", "text": ""}],
|
||||
"content": [
|
||||
{"type": "output_text", "text": ""}
|
||||
],
|
||||
"_tag_type": content_type,
|
||||
"start_tag": start_tag,
|
||||
"end_tag": end_tag,
|
||||
@@ -3059,8 +3063,14 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
|
||||
elif (
|
||||
(last_type == "reasoning" and content_type == "reasoning")
|
||||
or (last_type == "open_webui:code_interpreter" and content_type == "code_interpreter")
|
||||
or (last_type == "message" and output[-1].get("_tag_type") == content_type)
|
||||
or (
|
||||
last_type == "open_webui:code_interpreter"
|
||||
and content_type == "code_interpreter"
|
||||
)
|
||||
or (
|
||||
last_type == "message"
|
||||
and output[-1].get("_tag_type") == content_type
|
||||
)
|
||||
):
|
||||
item = output[-1]
|
||||
start_tag = item.get("start_tag", "")
|
||||
@@ -3178,9 +3188,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
# Clean processed content
|
||||
start_tag_clean = rf"{re.escape(start_tag)}"
|
||||
if start_tag.startswith("<") and start_tag.endswith(">"):
|
||||
start_tag_clean = (
|
||||
rf"<{re.escape(start_tag[1:-1])}(\s.*?)?>"
|
||||
)
|
||||
start_tag_clean = rf"<{re.escape(start_tag[1:-1])}(\s.*?)?>"
|
||||
|
||||
content = re.sub(
|
||||
rf"{start_tag_clean}(.|\n)*?{re.escape(end_tag)}",
|
||||
@@ -3231,7 +3239,6 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
else:
|
||||
output = []
|
||||
|
||||
|
||||
usage = None
|
||||
|
||||
reasoning_tags_param = metadata.get("params", {}).get("reasoning_tags")
|
||||
@@ -3514,14 +3521,19 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
for tc in response_tool_calls:
|
||||
call_id = tc.get("id", "")
|
||||
func = tc.get("function", {})
|
||||
pending_fc_items.append({
|
||||
"type": "function_call",
|
||||
"id": call_id or output_id("fc"),
|
||||
"call_id": call_id,
|
||||
"name": func.get("name", ""),
|
||||
"arguments": func.get("arguments", "{}"),
|
||||
"status": "in_progress",
|
||||
})
|
||||
pending_fc_items.append(
|
||||
{
|
||||
"type": "function_call",
|
||||
"id": call_id
|
||||
or output_id("fc"),
|
||||
"call_id": call_id,
|
||||
"name": func.get("name", ""),
|
||||
"arguments": func.get(
|
||||
"arguments", "{}"
|
||||
),
|
||||
"status": "in_progress",
|
||||
}
|
||||
)
|
||||
pending_output = output + pending_fc_items
|
||||
await event_emitter(
|
||||
{
|
||||
@@ -3585,22 +3597,25 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
|
||||
# Append to reasoning content
|
||||
parts = reasoning_item.get("content", [])
|
||||
if parts and parts[-1].get("type") == "output_text":
|
||||
if (
|
||||
parts
|
||||
and parts[-1].get("type") == "output_text"
|
||||
):
|
||||
parts[-1]["text"] += reasoning_content
|
||||
else:
|
||||
reasoning_item["content"] = [
|
||||
{"type": "output_text", "text": reasoning_content}
|
||||
{
|
||||
"type": "output_text",
|
||||
"text": reasoning_content,
|
||||
}
|
||||
]
|
||||
|
||||
data = {
|
||||
"content": serialize_output(output)
|
||||
}
|
||||
data = {"content": serialize_output(output)}
|
||||
|
||||
if value:
|
||||
if (
|
||||
output
|
||||
and output[-1].get("type")
|
||||
== "reasoning"
|
||||
and output[-1].get("type") == "reasoning"
|
||||
and output[-1]
|
||||
.get("attributes", {})
|
||||
.get("type")
|
||||
@@ -3620,7 +3635,12 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
"id": output_id("msg"),
|
||||
"status": "in_progress",
|
||||
"role": "assistant",
|
||||
"content": [{"type": "output_text", "text": ""}],
|
||||
"content": [
|
||||
{
|
||||
"type": "output_text",
|
||||
"text": "",
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3650,13 +3670,22 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
"id": output_id("msg"),
|
||||
"status": "in_progress",
|
||||
"role": "assistant",
|
||||
"content": [{"type": "output_text", "text": ""}],
|
||||
"content": [
|
||||
{
|
||||
"type": "output_text",
|
||||
"text": "",
|
||||
}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
# Append value to last message item's text
|
||||
msg_parts = output[-1].get("content", [])
|
||||
if msg_parts and msg_parts[-1].get("type") == "output_text":
|
||||
if (
|
||||
msg_parts
|
||||
and msg_parts[-1].get("type")
|
||||
== "output_text"
|
||||
):
|
||||
msg_parts[-1]["text"] += value
|
||||
else:
|
||||
output[-1]["content"] = [
|
||||
@@ -3664,32 +3693,26 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
]
|
||||
|
||||
if DETECT_REASONING_TAGS:
|
||||
content, output, _ = (
|
||||
tag_output_handler(
|
||||
"reasoning",
|
||||
reasoning_tags,
|
||||
content,
|
||||
output,
|
||||
)
|
||||
content, output, _ = tag_output_handler(
|
||||
"reasoning",
|
||||
reasoning_tags,
|
||||
content,
|
||||
output,
|
||||
)
|
||||
|
||||
content, output, _ = (
|
||||
tag_output_handler(
|
||||
"solution",
|
||||
DEFAULT_SOLUTION_TAGS,
|
||||
content,
|
||||
output,
|
||||
)
|
||||
content, output, _ = tag_output_handler(
|
||||
"solution",
|
||||
DEFAULT_SOLUTION_TAGS,
|
||||
content,
|
||||
output,
|
||||
)
|
||||
|
||||
if DETECT_CODE_INTERPRETER:
|
||||
content, output, end = (
|
||||
tag_output_handler(
|
||||
"code_interpreter",
|
||||
DEFAULT_CODE_INTERPRETER_TAGS,
|
||||
content,
|
||||
output,
|
||||
)
|
||||
content, output, end = tag_output_handler(
|
||||
"code_interpreter",
|
||||
DEFAULT_CODE_INTERPRETER_TAGS,
|
||||
content,
|
||||
output,
|
||||
)
|
||||
|
||||
if end:
|
||||
@@ -3707,9 +3730,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
)
|
||||
else:
|
||||
data = {
|
||||
"content": serialize_output(
|
||||
output
|
||||
),
|
||||
"content": serialize_output(output),
|
||||
}
|
||||
|
||||
if delta:
|
||||
@@ -3750,7 +3771,9 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
"id": output_id("msg"),
|
||||
"status": "in_progress",
|
||||
"role": "assistant",
|
||||
"content": [{"type": "output_text", "text": ""}],
|
||||
"content": [
|
||||
{"type": "output_text", "text": ""}
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3788,14 +3811,16 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
for tc in response_tool_calls:
|
||||
call_id = tc.get("id", "")
|
||||
func = tc.get("function", {})
|
||||
output.append({
|
||||
"type": "function_call",
|
||||
"id": call_id or output_id("fc"),
|
||||
"call_id": call_id,
|
||||
"name": func.get("name", ""),
|
||||
"arguments": func.get("arguments", "{}"),
|
||||
"status": "in_progress",
|
||||
})
|
||||
output.append(
|
||||
{
|
||||
"type": "function_call",
|
||||
"id": call_id or output_id("fc"),
|
||||
"call_id": call_id,
|
||||
"name": func.get("name", ""),
|
||||
"arguments": func.get("arguments", "{}"),
|
||||
"status": "in_progress",
|
||||
}
|
||||
)
|
||||
|
||||
await event_emitter(
|
||||
{
|
||||
@@ -3954,35 +3979,42 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
call_id = tc.get("id", "")
|
||||
# Mark function_call as completed
|
||||
for item in output:
|
||||
if item.get("type") == "function_call" and item.get("call_id") == call_id:
|
||||
if (
|
||||
item.get("type") == "function_call"
|
||||
and item.get("call_id") == call_id
|
||||
):
|
||||
item["status"] = "completed"
|
||||
# Update arguments with parsed/sanitized version
|
||||
item["arguments"] = tc.get("function", {}).get("arguments", "{}")
|
||||
item["arguments"] = tc.get("function", {}).get(
|
||||
"arguments", "{}"
|
||||
)
|
||||
break
|
||||
|
||||
for result in results:
|
||||
output.append({
|
||||
"type": "function_call_output",
|
||||
"id": output_id("fco"),
|
||||
"call_id": result.get("tool_call_id", ""),
|
||||
"output": [
|
||||
{
|
||||
"type": "input_text",
|
||||
"text": result.get("content", ""),
|
||||
}
|
||||
],
|
||||
"status": "completed",
|
||||
**(
|
||||
{"files": result.get("files")}
|
||||
if result.get("files")
|
||||
else {}
|
||||
),
|
||||
**(
|
||||
{"embeds": result.get("embeds")}
|
||||
if result.get("embeds")
|
||||
else {}
|
||||
),
|
||||
})
|
||||
output.append(
|
||||
{
|
||||
"type": "function_call_output",
|
||||
"id": output_id("fco"),
|
||||
"call_id": result.get("tool_call_id", ""),
|
||||
"output": [
|
||||
{
|
||||
"type": "input_text",
|
||||
"text": result.get("content", ""),
|
||||
}
|
||||
],
|
||||
"status": "completed",
|
||||
**(
|
||||
{"files": result.get("files")}
|
||||
if result.get("files")
|
||||
else {}
|
||||
),
|
||||
**(
|
||||
{"embeds": result.get("embeds")}
|
||||
if result.get("embeds")
|
||||
else {}
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
# Append a new empty message item for the next response
|
||||
output.append(
|
||||
@@ -4079,8 +4111,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
code = sanitize_code(code)
|
||||
|
||||
if CODE_INTERPRETER_BLOCKED_MODULES:
|
||||
blocking_code = textwrap.dedent(
|
||||
f"""
|
||||
blocking_code = textwrap.dedent(f"""
|
||||
import builtins
|
||||
|
||||
BLOCKED_MODULES = {CODE_INTERPRETER_BLOCKED_MODULES}
|
||||
@@ -4096,8 +4127,7 @@ async def streaming_chat_response_handler(response, ctx):
|
||||
return _real_import(name, globals, locals, fromlist, level)
|
||||
|
||||
builtins.__import__ = restricted_import
|
||||
"""
|
||||
)
|
||||
""")
|
||||
code = blocking_code + "\n" + code
|
||||
|
||||
if (
|
||||
|
||||
@@ -151,11 +151,15 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]:
|
||||
def flush_pending():
|
||||
nonlocal pending_content, pending_tool_calls
|
||||
if pending_content or pending_tool_calls:
|
||||
messages.append({
|
||||
"role": "assistant",
|
||||
"content": "\n".join(pending_content) if pending_content else "",
|
||||
**({"tool_calls": pending_tool_calls} if pending_tool_calls else {}),
|
||||
})
|
||||
messages.append(
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "\n".join(pending_content) if pending_content else "",
|
||||
**(
|
||||
{"tool_calls": pending_tool_calls} if pending_tool_calls else {}
|
||||
),
|
||||
}
|
||||
)
|
||||
pending_content = []
|
||||
pending_tool_calls = []
|
||||
|
||||
@@ -178,14 +182,16 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]:
|
||||
# Ensure arguments is always a JSON string
|
||||
if not isinstance(arguments, str):
|
||||
arguments = json.dumps(arguments)
|
||||
pending_tool_calls.append({
|
||||
"id": item.get("call_id", ""),
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": item.get("name", ""),
|
||||
"arguments": arguments,
|
||||
pending_tool_calls.append(
|
||||
{
|
||||
"id": item.get("call_id", ""),
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": item.get("name", ""),
|
||||
"arguments": arguments,
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
elif item_type == "function_call_output":
|
||||
# Flush any pending content/tool_calls before adding tool result
|
||||
@@ -198,11 +204,13 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]:
|
||||
if part.get("type") == "input_text":
|
||||
content += part.get("text", "")
|
||||
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
"tool_call_id": item.get("call_id", ""),
|
||||
"content": content,
|
||||
})
|
||||
messages.append(
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": item.get("call_id", ""),
|
||||
"content": content,
|
||||
}
|
||||
)
|
||||
|
||||
elif item_type == "reasoning":
|
||||
if raw:
|
||||
@@ -218,9 +226,7 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]:
|
||||
if reasoning_text:
|
||||
start_tag = item.get("start_tag", "<think>")
|
||||
end_tag = item.get("end_tag", "</think>")
|
||||
pending_content.append(
|
||||
f"{start_tag}{reasoning_text}{end_tag}"
|
||||
)
|
||||
pending_content.append(f"{start_tag}{reasoning_text}{end_tag}")
|
||||
# else: skip reasoning blocks for normal LLM messages
|
||||
|
||||
elif item_type == "open_webui:code_interpreter":
|
||||
|
||||
@@ -32,7 +32,6 @@ from open_webui.config import (
|
||||
from open_webui.env import BYPASS_MODEL_ACCESS_CONTROL, GLOBAL_LOG_LEVEL
|
||||
from open_webui.models.users import UserModel
|
||||
|
||||
|
||||
logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -289,7 +289,9 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict:
|
||||
"""
|
||||
# Shallow copy metadata separately (may contain non-picklable objects)
|
||||
metadata = openai_payload.get("metadata")
|
||||
openai_payload = copy.deepcopy({k: v for k, v in openai_payload.items() if k != "metadata"})
|
||||
openai_payload = copy.deepcopy(
|
||||
{k: v for k, v in openai_payload.items() if k != "metadata"}
|
||||
)
|
||||
if metadata is not None:
|
||||
openai_payload["metadata"] = dict(metadata)
|
||||
ollama_payload = {}
|
||||
@@ -421,4 +423,3 @@ def convert_embed_payload_openai_to_ollama(openai_payload: dict) -> dict:
|
||||
ollama_payload[optional_key] = openai_payload[optional_key]
|
||||
|
||||
return ollama_payload
|
||||
|
||||
|
||||
@@ -151,7 +151,6 @@ def resolve_valves_schema_options(
|
||||
return schema
|
||||
|
||||
|
||||
|
||||
def extract_frontmatter(content):
|
||||
"""
|
||||
Extract frontmatter as a dictionary from the provided content string.
|
||||
|
||||
@@ -68,7 +68,7 @@ def convert_ollama_usage_to_openai(data: dict) -> dict:
|
||||
input_tokens = int(data.get("prompt_eval_count", 0))
|
||||
output_tokens = int(data.get("eval_count", 0))
|
||||
total_tokens = input_tokens + output_tokens
|
||||
|
||||
|
||||
return {
|
||||
# Standardized fields
|
||||
"input_tokens": input_tokens,
|
||||
|
||||
@@ -2,7 +2,9 @@ import re
|
||||
|
||||
# ANSI escape code pattern - matches all common ANSI sequences
|
||||
# This includes color codes, cursor movement, and other terminal control sequences
|
||||
ANSI_ESCAPE_PATTERN = re.compile(r'\x1b\[[0-9;]*[A-Za-z]|\x1b\([AB]|\x1b[PX^_].*?\x1b\\|\x1b\].*?(?:\x07|\x1b\\)')
|
||||
ANSI_ESCAPE_PATTERN = re.compile(
|
||||
r"\x1b\[[0-9;]*[A-Za-z]|\x1b\([AB]|\x1b[PX^_].*?\x1b\\|\x1b\].*?(?:\x07|\x1b\\)"
|
||||
)
|
||||
|
||||
|
||||
def strip_ansi_codes(text: str) -> str:
|
||||
@@ -18,7 +20,7 @@ def strip_ansi_codes(text: str) -> str:
|
||||
- Reset codes: \x1b[0m, \x1b[39m
|
||||
- Cursor movement: \x1b[1A, \x1b[2J, etc.
|
||||
"""
|
||||
return ANSI_ESCAPE_PATTERN.sub('', text)
|
||||
return ANSI_ESCAPE_PATTERN.sub("", text)
|
||||
|
||||
|
||||
def strip_markdown_code_fences(code: str) -> str:
|
||||
@@ -55,4 +57,3 @@ def sanitize_code(code: str) -> str:
|
||||
code = strip_ansi_codes(code)
|
||||
code = strip_markdown_code_fences(code)
|
||||
return code
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ from open_webui.utils.misc import get_last_user_message, get_messages_content
|
||||
|
||||
from open_webui.config import DEFAULT_RAG_TEMPLATE
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ from fastapi import status
|
||||
|
||||
from open_webui.utils.telemetry.constants import SPAN_REDIS_TYPE, SpanAttributes
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -60,7 +59,7 @@ def response_hook(span: Span, request: PreparedRequest, response: Response):
|
||||
span.set_status(StatusCode.ERROR if response.status_code >= 400 else StatusCode.OK)
|
||||
|
||||
|
||||
def redis_request_hook(span: Span, instance: Union[Redis|RedisCluster], args, kwargs):
|
||||
def redis_request_hook(span: Span, instance: Union[Redis | RedisCluster], args, kwargs):
|
||||
"""
|
||||
Redis Request Hook
|
||||
"""
|
||||
@@ -71,7 +70,7 @@ def redis_request_hook(span: Span, instance: Union[Redis|RedisCluster], args, kw
|
||||
# Instead of checking the type, we check if the instance has a nodes_manager attribute.
|
||||
try:
|
||||
db = ""
|
||||
if hasattr(instance, 'nodes_manager'):
|
||||
if hasattr(instance, "nodes_manager"):
|
||||
default_node = instance.nodes_manager.default_node
|
||||
if not default_node:
|
||||
return
|
||||
|
||||
@@ -352,7 +352,9 @@ async def get_tools(
|
||||
headers = include_user_info_headers(headers, user)
|
||||
metadata = extra_params.get("__metadata__", {})
|
||||
if metadata and metadata.get("chat_id"):
|
||||
headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = metadata.get("chat_id")
|
||||
headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = (
|
||||
metadata.get("chat_id")
|
||||
)
|
||||
|
||||
def make_tool_function(
|
||||
function_name, tool_server_data, headers
|
||||
@@ -416,9 +418,8 @@ def get_builtin_tools(
|
||||
|
||||
# Helper to get model capabilities (defaults to True if not specified)
|
||||
def get_model_capability(name: str, default: bool = True) -> bool:
|
||||
return (
|
||||
(model.get("info", {}).get("meta", {}).get("capabilities") or {})
|
||||
.get(name, default)
|
||||
return (model.get("info", {}).get("meta", {}).get("capabilities") or {}).get(
|
||||
name, default
|
||||
)
|
||||
|
||||
# Helper to check if a builtin tool category is enabled via meta.builtinTools
|
||||
@@ -491,13 +492,17 @@ def get_builtin_tools(
|
||||
builtin_functions.append(execute_code)
|
||||
|
||||
# Notes tools - search, view, create, and update user's notes (if builtin category enabled AND notes enabled globally)
|
||||
if is_builtin_tool_enabled("notes") and getattr(request.app.state.config, "ENABLE_NOTES", False):
|
||||
if is_builtin_tool_enabled("notes") and getattr(
|
||||
request.app.state.config, "ENABLE_NOTES", False
|
||||
):
|
||||
builtin_functions.extend(
|
||||
[search_notes, view_note, write_note, replace_note_content]
|
||||
)
|
||||
|
||||
# Channels tools - search channels and messages (if builtin category enabled AND channels enabled globally)
|
||||
if is_builtin_tool_enabled("channels") and getattr(request.app.state.config, "ENABLE_CHANNELS", False):
|
||||
if is_builtin_tool_enabled("channels") and getattr(
|
||||
request.app.state.config, "ENABLE_CHANNELS", False
|
||||
):
|
||||
builtin_functions.extend(
|
||||
[
|
||||
search_channels,
|
||||
|
||||
@@ -36,4 +36,3 @@ def validate_profile_image_url(url: str) -> str:
|
||||
raise ValueError(
|
||||
"Invalid profile image URL: only data URIs and default avatars are allowed."
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user