mirror of
https://github.com/open-webui/open-webui.git
synced 2026-08-28 05:27:35 +00:00
refac
This commit is contained in:
parent
bd6e0b61c2
commit
8e46450acd
11 changed files with 143 additions and 65 deletions
|
|
@ -8,7 +8,7 @@ import uuid
|
|||
from types import SimpleNamespace
|
||||
from typing import Any
|
||||
|
||||
from open_webui.env import VERSION
|
||||
from open_webui.env import ENABLE_PLUGINS, VERSION
|
||||
from open_webui.models.config import Config
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
from open_webui.retrieval.web.utils import validate_url
|
||||
|
|
@ -1025,6 +1025,9 @@ class WebhookEventSink:
|
|||
|
||||
|
||||
async def dispatch_event_functions(app: Any, event: Event, request: Any | None = None) -> None:
|
||||
if not ENABLE_PLUGINS:
|
||||
return
|
||||
|
||||
from open_webui.models.functions import Functions
|
||||
from open_webui.utils.plugin import get_function_module_from_cache
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from starlette.responses import Response, StreamingResponse
|
|||
|
||||
from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from open_webui.env import BYPASS_MODEL_ACCESS_CONTROL, GLOBAL_LOG_LEVEL
|
||||
from open_webui.env import BYPASS_MODEL_ACCESS_CONTROL, ENABLE_PLUGINS, GLOBAL_LOG_LEVEL
|
||||
from open_webui.models.functions import Functions
|
||||
from open_webui.models.models import Models
|
||||
from open_webui.models.users import UserModel
|
||||
|
|
@ -69,6 +69,9 @@ async def get_function_module_by_id(request: Request, pipe_id: str):
|
|||
|
||||
|
||||
async def get_function_models(request):
|
||||
if not ENABLE_PLUGINS:
|
||||
return []
|
||||
|
||||
pipes = await Functions.get_functions_by_type('pipe', active_only=True)
|
||||
pipe_models = []
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ from open_webui.env import (
|
|||
ENABLE_COMPRESSION_MIDDLEWARE,
|
||||
ENABLE_CUSTOM_MODEL_FALLBACK,
|
||||
ENABLE_EASTER_EGGS,
|
||||
ENABLE_PLUGINS,
|
||||
EXTERNAL_PWA_MANIFEST_URL,
|
||||
# OAuth Back-Channel Logout
|
||||
ENABLE_OAUTH_BACKCHANNEL_LOGOUT,
|
||||
|
|
@ -1927,6 +1928,7 @@ async def get_app_config(request: Request):
|
|||
'enable_public_active_users_count': ENABLE_PUBLIC_ACTIVE_USERS_COUNT,
|
||||
'enable_easter_eggs': ENABLE_EASTER_EGGS,
|
||||
'enable_direct_connections': config.get('direct.enable'),
|
||||
'enable_plugins': ENABLE_PLUGINS,
|
||||
'enable_folders': config.get('folders.enable'),
|
||||
'folder_max_file_count': config.get('folders.max_file_count'),
|
||||
'enable_channels': config.get('channels.enable'),
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import aiohttp
|
|||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from open_webui.config import CACHE_DIR
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT
|
||||
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, ENABLE_PLUGINS
|
||||
from open_webui.events import EVENTS, publish_event
|
||||
from open_webui.internal.db import get_async_session
|
||||
from open_webui.models.functions import (
|
||||
|
|
@ -46,11 +46,17 @@ router = APIRouter()
|
|||
|
||||
@router.get('/', response_model=list[FunctionResponse])
|
||||
async def get_functions(user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)):
|
||||
if not ENABLE_PLUGINS:
|
||||
return []
|
||||
|
||||
return await Functions.get_functions(db=db)
|
||||
|
||||
|
||||
@router.get('/list', response_model=list[FunctionUserResponse])
|
||||
async def get_function_list(user=Depends(get_admin_user), db: AsyncSession = Depends(get_async_session)):
|
||||
if not ENABLE_PLUGINS:
|
||||
return []
|
||||
|
||||
return await Functions.get_function_list(db=db)
|
||||
|
||||
|
||||
|
|
@ -65,6 +71,9 @@ async def get_functions(
|
|||
user=Depends(get_admin_user),
|
||||
db: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
if not ENABLE_PLUGINS:
|
||||
return []
|
||||
|
||||
return await Functions.get_functions(include_valves=include_valves, db=db)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import aiohttp
|
|||
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
||||
from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL, CACHE_DIR
|
||||
from open_webui.constants import ERROR_MESSAGES
|
||||
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT
|
||||
from open_webui.env import AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, ENABLE_PLUGINS
|
||||
from open_webui.events import EVENTS, publish_event
|
||||
from open_webui.internal.db import get_async_session
|
||||
from open_webui.models.access_grants import AccessGrants
|
||||
|
|
@ -72,20 +72,23 @@ async def get_tools(
|
|||
tools = []
|
||||
|
||||
# Local Tools
|
||||
tools_cache = get_tools_cache(request)
|
||||
for tool in await Tools.get_tools(defer_content=True, db=db):
|
||||
tool_module = tools_cache.get(tool.id)
|
||||
has_user_valves = (
|
||||
hasattr(tool_module, 'UserValves') if tool_module else (tool.meta.has_user_valves if tool.meta else False)
|
||||
)
|
||||
tools.append(
|
||||
ToolUserResponse(
|
||||
**{
|
||||
**tool.model_dump(),
|
||||
'has_user_valves': has_user_valves,
|
||||
}
|
||||
if ENABLE_PLUGINS:
|
||||
tools_cache = get_tools_cache(request)
|
||||
for tool in await Tools.get_tools(defer_content=True, db=db):
|
||||
tool_module = tools_cache.get(tool.id)
|
||||
has_user_valves = (
|
||||
hasattr(tool_module, 'UserValves')
|
||||
if tool_module
|
||||
else (tool.meta.has_user_valves if tool.meta else False)
|
||||
)
|
||||
tools.append(
|
||||
ToolUserResponse(
|
||||
**{
|
||||
**tool.model_dump(),
|
||||
'has_user_valves': has_user_valves,
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
# OpenAPI Tool Servers
|
||||
server_access_grants = {}
|
||||
|
|
@ -199,6 +202,9 @@ async def get_tools(
|
|||
|
||||
@router.get('/list', response_model=list[ToolAccessResponse])
|
||||
async def get_tool_list(user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)):
|
||||
if not ENABLE_PLUGINS:
|
||||
return []
|
||||
|
||||
if user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL:
|
||||
tools = await Tools.get_tools(defer_content=True, db=db)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import sys
|
|||
from typing import Any
|
||||
|
||||
from fastapi import Request
|
||||
from open_webui.env import GLOBAL_LOG_LEVEL
|
||||
from open_webui.env import ENABLE_PLUGINS, GLOBAL_LOG_LEVEL
|
||||
from open_webui.models.functions import Functions
|
||||
from open_webui.models.users import UserModel
|
||||
from open_webui.socket.main import get_event_call, get_event_emitter
|
||||
|
|
@ -17,6 +17,9 @@ log = logging.getLogger(__name__)
|
|||
|
||||
|
||||
async def chat_action(request: Request, action_id: str, form_data: dict, user: Any):
|
||||
if not ENABLE_PLUGINS:
|
||||
raise Exception('Plugins are disabled by ENABLE_PLUGINS=false')
|
||||
|
||||
if '.' in action_id:
|
||||
action_id, sub_action_id = action_id.split('.')
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import inspect
|
||||
import logging
|
||||
|
||||
from open_webui.env import ENABLE_PLUGINS
|
||||
from open_webui.models.functions import Functions
|
||||
from open_webui.utils.plugin import (
|
||||
get_function_module_from_cache,
|
||||
|
|
@ -19,6 +20,9 @@ async def get_function_module(request, function_id, load_from_db=True):
|
|||
|
||||
|
||||
async def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list = None):
|
||||
if not ENABLE_PLUGINS:
|
||||
return []
|
||||
|
||||
async def get_priority(function_id):
|
||||
try:
|
||||
function_module = await get_function_module(request, function_id)
|
||||
|
|
@ -64,6 +68,9 @@ async def get_sorted_filter_ids(request, model: dict, enabled_filter_ids: list =
|
|||
# Grant these filters the discernment to pass what serves
|
||||
# and refuse what harms, for every soul in the house.
|
||||
async def process_filter_functions(request, filter_functions, filter_type, form_data, extra_params):
|
||||
if not ENABLE_PLUGINS:
|
||||
return form_data, {}
|
||||
|
||||
skip_files = None
|
||||
|
||||
for function in filter_functions:
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ from open_webui.env import (
|
|||
CHAT_RESPONSE_STREAM_DELTA_CHUNK_SIZE,
|
||||
ENABLE_API_OUTLET_FILTERS,
|
||||
ENABLE_CHAT_RESPONSE_BASE64_IMAGE_URL_CONVERSION,
|
||||
ENABLE_PLUGINS,
|
||||
ENABLE_QUERIES_CACHE,
|
||||
ENABLE_REALTIME_CHAT_SAVE,
|
||||
ENABLE_RESPONSES_API_STATEFUL,
|
||||
|
|
@ -2421,19 +2422,20 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
|||
except Exception as e:
|
||||
raise e
|
||||
|
||||
try:
|
||||
filter_ids = await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
|
||||
filter_functions = await Functions.get_functions_by_ids(filter_ids)
|
||||
if ENABLE_PLUGINS:
|
||||
try:
|
||||
filter_ids = await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
|
||||
filter_functions = await Functions.get_functions_by_ids(filter_ids)
|
||||
|
||||
form_data, flags = await process_filter_functions(
|
||||
request=request,
|
||||
filter_functions=filter_functions,
|
||||
filter_type='inlet',
|
||||
form_data=form_data,
|
||||
extra_params=extra_params,
|
||||
)
|
||||
except Exception as e:
|
||||
raise Exception(f'{e}')
|
||||
form_data, flags = await process_filter_functions(
|
||||
request=request,
|
||||
filter_functions=filter_functions,
|
||||
filter_type='inlet',
|
||||
form_data=form_data,
|
||||
extra_params=extra_params,
|
||||
)
|
||||
except Exception as e:
|
||||
raise Exception(f'{e}')
|
||||
|
||||
features = form_data.pop('features', None) or {}
|
||||
extra_params['__features__'] = features
|
||||
|
|
@ -2618,6 +2620,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
|||
mcp_tools_dict = {}
|
||||
|
||||
if tool_ids:
|
||||
db_tool_ids = []
|
||||
for tool_id in tool_ids:
|
||||
if tool_id.startswith('server:mcp:'):
|
||||
try:
|
||||
|
|
@ -2669,18 +2672,21 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
|||
}
|
||||
)
|
||||
continue
|
||||
elif ENABLE_PLUGINS:
|
||||
db_tool_ids.append(tool_id)
|
||||
|
||||
tools_dict = await get_tools(
|
||||
request,
|
||||
tool_ids,
|
||||
user,
|
||||
{
|
||||
**extra_params,
|
||||
'__model__': models[task_model_id],
|
||||
'__messages__': form_data['messages'],
|
||||
'__files__': metadata.get('files', []),
|
||||
},
|
||||
)
|
||||
if db_tool_ids:
|
||||
tools_dict = await get_tools(
|
||||
request,
|
||||
db_tool_ids,
|
||||
user,
|
||||
{
|
||||
**extra_params,
|
||||
'__model__': models[task_model_id],
|
||||
'__messages__': form_data['messages'],
|
||||
'__files__': metadata.get('files', []),
|
||||
},
|
||||
)
|
||||
|
||||
if mcp_tools_dict:
|
||||
tools_dict = {**tools_dict, **mcp_tools_dict}
|
||||
|
|
@ -2737,7 +2743,7 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
|||
# Inject builtin tools for native function calling based on enabled features and model capability.
|
||||
# Only inject when the request originates from the UI (identified by session_id).
|
||||
# API callers don't expect hidden tools; they can explicitly request tools via tool_ids.
|
||||
if use_builtin_tools:
|
||||
if ENABLE_PLUGINS and use_builtin_tools:
|
||||
# Add file context to user messages
|
||||
chat_id = metadata.get('chat_id')
|
||||
form_data['messages'] = await add_file_context(form_data.get('messages', []), chat_id, user)
|
||||
|
|
@ -3371,16 +3377,19 @@ async def outlet_filter_handler(ctx):
|
|||
'__model__': model,
|
||||
}
|
||||
|
||||
filter_ids = await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
|
||||
filter_functions = await Functions.get_functions_by_ids(filter_ids)
|
||||
if ENABLE_PLUGINS:
|
||||
filter_ids = await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
|
||||
filter_functions = await Functions.get_functions_by_ids(filter_ids)
|
||||
|
||||
outlet_result, _ = await process_filter_functions(
|
||||
request=request,
|
||||
filter_functions=filter_functions,
|
||||
filter_type='outlet',
|
||||
form_data=outlet_data,
|
||||
extra_params=extra_params,
|
||||
)
|
||||
outlet_result, _ = await process_filter_functions(
|
||||
request=request,
|
||||
filter_functions=filter_functions,
|
||||
filter_type='outlet',
|
||||
form_data=outlet_data,
|
||||
extra_params=extra_params,
|
||||
)
|
||||
else:
|
||||
outlet_result = outlet_data
|
||||
|
||||
if outlet_result and outlet_result.get('messages'):
|
||||
if not is_temp_chat and messages_map:
|
||||
|
|
@ -3620,10 +3629,14 @@ async def streaming_chat_response_handler(response, ctx):
|
|||
'__model__': model,
|
||||
}
|
||||
|
||||
filter_functions = [
|
||||
await Functions.get_function_by_id(filter_id)
|
||||
for filter_id in await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
|
||||
]
|
||||
filter_functions = (
|
||||
[
|
||||
await Functions.get_function_by_id(filter_id)
|
||||
for filter_id in await get_sorted_filter_ids(request, model, metadata.get('filter_ids', []))
|
||||
]
|
||||
if ENABLE_PLUGINS
|
||||
else []
|
||||
)
|
||||
|
||||
# Standard streaming response handler
|
||||
# event_caller is optional — only needed for direct (client-side) tools
|
||||
|
|
@ -3907,7 +3920,8 @@ async def streaming_chat_response_handler(response, ctx):
|
|||
model_capabilities = model.get('info', {}).get('meta', {}).get('capabilities') or {}
|
||||
builtin_tools_meta = model.get('info', {}).get('meta', {}).get('builtinTools', {})
|
||||
DETECT_CODE_INTERPRETER = (
|
||||
bool(features.get('code_interpreter'))
|
||||
ENABLE_PLUGINS
|
||||
and bool(features.get('code_interpreter'))
|
||||
and builtin_tools_meta.get('code_interpreter', True)
|
||||
and await Config.get('code_interpreter.enable')
|
||||
and model_capabilities.get('code_interpreter', True)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from open_webui.config import (
|
|||
BYPASS_ADMIN_ACCESS_CONTROL,
|
||||
DEFAULT_ARENA_MODEL,
|
||||
)
|
||||
from open_webui.env import BYPASS_MODEL_ACCESS_CONTROL, GLOBAL_LOG_LEVEL
|
||||
from open_webui.env import BYPASS_MODEL_ACCESS_CONTROL, ENABLE_PLUGINS, GLOBAL_LOG_LEVEL
|
||||
from open_webui.functions import get_function_models
|
||||
from open_webui.models.access_grants import AccessGrants
|
||||
from open_webui.models.config import Config
|
||||
|
|
@ -125,11 +125,23 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
|
|||
]
|
||||
models = models + arena_models
|
||||
|
||||
global_action_ids = {function.id for function in await Functions.get_global_action_functions()}
|
||||
enabled_action_ids = {function.id for function in await Functions.get_functions_by_type('action', active_only=True)}
|
||||
global_action_ids = (
|
||||
{function.id for function in await Functions.get_global_action_functions()} if ENABLE_PLUGINS else set()
|
||||
)
|
||||
enabled_action_ids = (
|
||||
{function.id for function in await Functions.get_functions_by_type('action', active_only=True)}
|
||||
if ENABLE_PLUGINS
|
||||
else set()
|
||||
)
|
||||
|
||||
global_filter_ids = {function.id for function in await Functions.get_global_filter_functions()}
|
||||
enabled_filter_ids = {function.id for function in await Functions.get_functions_by_type('filter', active_only=True)}
|
||||
global_filter_ids = (
|
||||
{function.id for function in await Functions.get_global_filter_functions()} if ENABLE_PLUGINS else set()
|
||||
)
|
||||
enabled_filter_ids = (
|
||||
{function.id for function in await Functions.get_functions_by_type('filter', active_only=True)}
|
||||
if ENABLE_PLUGINS
|
||||
else set()
|
||||
)
|
||||
|
||||
custom_models = await Models.get_all_models()
|
||||
|
||||
|
|
@ -157,8 +169,9 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
|
|||
|
||||
if 'info' in model:
|
||||
if 'meta' in model['info']:
|
||||
action_ids.extend(model['info']['meta'].get('actionIds', []))
|
||||
filter_ids.extend(model['info']['meta'].get('filterIds', []))
|
||||
if ENABLE_PLUGINS:
|
||||
action_ids.extend(model['info']['meta'].get('actionIds', []))
|
||||
filter_ids.extend(model['info']['meta'].get('filterIds', []))
|
||||
|
||||
if 'params' in model['info']:
|
||||
del model['info']['params']
|
||||
|
|
@ -211,10 +224,10 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None)
|
|||
if custom_model.meta:
|
||||
meta = custom_model.meta.model_dump()
|
||||
|
||||
if 'actionIds' in meta:
|
||||
if ENABLE_PLUGINS and 'actionIds' in meta:
|
||||
action_ids.extend(meta['actionIds'])
|
||||
|
||||
if 'filterIds' in meta:
|
||||
if ENABLE_PLUGINS and 'filterIds' in meta:
|
||||
filter_ids.extend(meta['filterIds'])
|
||||
|
||||
model['action_ids'] = action_ids
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ from typing import Any
|
|||
|
||||
from open_webui.env import (
|
||||
ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS,
|
||||
ENABLE_PLUGINS,
|
||||
OFFLINE_MODE,
|
||||
PIP_OPTIONS,
|
||||
PIP_PACKAGE_INDEX_OPTIONS,
|
||||
|
|
@ -203,6 +204,9 @@ def replace_imports(content):
|
|||
# May the intent of the one who wrote it survive every
|
||||
# import and transformation, as a deed survives the generations.
|
||||
async def load_tool_module_by_id(tool_id, content=None):
|
||||
if not ENABLE_PLUGINS:
|
||||
raise RuntimeError('Plugins are disabled by ENABLE_PLUGINS=false')
|
||||
|
||||
if content is None:
|
||||
tool = await Tools.get_tool_by_id(tool_id)
|
||||
if not tool:
|
||||
|
|
@ -251,6 +255,9 @@ async def load_tool_module_by_id(tool_id, content=None):
|
|||
|
||||
|
||||
async def load_function_module_by_id(function_id: str, content: str | None = None):
|
||||
if not ENABLE_PLUGINS:
|
||||
raise RuntimeError('Plugins are disabled by ENABLE_PLUGINS=false')
|
||||
|
||||
if content is None:
|
||||
function = await Functions.get_function_by_id(function_id)
|
||||
if not function:
|
||||
|
|
@ -447,6 +454,10 @@ async def install_tool_and_function_dependencies():
|
|||
and then installing them using pip. Duplicates or similar version specifications are
|
||||
handled by pip as much as possible.
|
||||
"""
|
||||
if not ENABLE_PLUGINS:
|
||||
log.info('ENABLE_PLUGINS is disabled, skipping tool and function dependencies.')
|
||||
return
|
||||
|
||||
function_list = await Functions.get_functions(active_only=True)
|
||||
tool_list = await Tools.get_tools()
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ from open_webui.env import (
|
|||
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER,
|
||||
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA,
|
||||
ENABLE_FORWARD_USER_INFO_HEADERS,
|
||||
ENABLE_PLUGINS,
|
||||
FORWARD_SESSION_INFO_HEADER_CHAT_ID,
|
||||
FORWARD_SESSION_INFO_HEADER_MESSAGE_ID,
|
||||
REDIS_KEY_PREFIX,
|
||||
|
|
@ -253,6 +254,9 @@ async def get_updated_tool_function(function: Callable, extra_params: dict):
|
|||
|
||||
async def get_tools(request: Request, tool_ids: list[str], user: UserModel, extra_params: dict) -> dict[str, dict]:
|
||||
"""Load tools for the given tool_ids, checking access control."""
|
||||
if not ENABLE_PLUGINS:
|
||||
return {}
|
||||
|
||||
if not tool_ids:
|
||||
return {}
|
||||
|
||||
|
|
@ -469,6 +473,9 @@ async def get_builtin_tools(
|
|||
Get built-in tools for native function calling.
|
||||
Only returns tools when BOTH the global config is enabled AND the model capability allows it.
|
||||
"""
|
||||
if not ENABLE_PLUGINS:
|
||||
return {}
|
||||
|
||||
tools_dict = {}
|
||||
builtin_functions = []
|
||||
features = features or {}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue