feat: native function calling for built-in tools
This commit is contained in:
@@ -44,6 +44,7 @@ from open_webui.routers.retrieval import (
|
||||
process_web_search,
|
||||
SearchForm,
|
||||
)
|
||||
from open_webui.utils.tools import get_builtin_tools
|
||||
from open_webui.routers.images import (
|
||||
image_generations,
|
||||
CreateImageForm,
|
||||
@@ -1305,7 +1306,8 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
except Exception as e:
|
||||
raise Exception(f"{e}")
|
||||
|
||||
features = form_data.pop("features", None)
|
||||
features = form_data.pop("features", None) or {}
|
||||
extra_params["__features__"] = features
|
||||
if features:
|
||||
if "voice" in features and features["voice"]:
|
||||
if request.app.state.config.VOICE_MODE_PROMPT_TEMPLATE != None:
|
||||
@@ -1320,19 +1322,25 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
)
|
||||
|
||||
if "memory" in features and features["memory"]:
|
||||
form_data = await chat_memory_handler(
|
||||
request, form_data, extra_params, user
|
||||
)
|
||||
# Skip forced memory injection when native FC is enabled - model can use memory tools
|
||||
if metadata.get("params", {}).get("function_calling") != "native":
|
||||
form_data = await chat_memory_handler(
|
||||
request, form_data, extra_params, user
|
||||
)
|
||||
|
||||
if "web_search" in features and features["web_search"]:
|
||||
form_data = await chat_web_search_handler(
|
||||
request, form_data, extra_params, user
|
||||
)
|
||||
# Skip forced RAG web search when native FC is enabled - model can use web_search tool
|
||||
if metadata.get("params", {}).get("function_calling") != "native":
|
||||
form_data = await chat_web_search_handler(
|
||||
request, form_data, extra_params, user
|
||||
)
|
||||
|
||||
if "image_generation" in features and features["image_generation"]:
|
||||
form_data = await chat_image_generation_handler(
|
||||
request, form_data, extra_params, user
|
||||
)
|
||||
# Skip forced image generation when native FC is enabled - model can use generate_image tool
|
||||
if metadata.get("params", {}).get("function_calling") != "native":
|
||||
form_data = await chat_image_generation_handler(
|
||||
request, form_data, extra_params, user
|
||||
)
|
||||
|
||||
if "code_interpreter" in features and features["code_interpreter"]:
|
||||
form_data["messages"] = add_or_update_user_message(
|
||||
@@ -1543,6 +1551,20 @@ async def process_chat_payload(request, form_data, user, metadata, model):
|
||||
if mcp_clients:
|
||||
metadata["mcp_clients"] = mcp_clients
|
||||
|
||||
# Always inject builtin tools for native function calling based on enabled features
|
||||
if metadata.get("params", {}).get("function_calling") == "native":
|
||||
builtin_tools = get_builtin_tools(
|
||||
request,
|
||||
{
|
||||
**extra_params,
|
||||
"__event_emitter__": event_emitter,
|
||||
},
|
||||
features,
|
||||
)
|
||||
for name, tool_dict in builtin_tools.items():
|
||||
if name not in tools_dict:
|
||||
tools_dict[name] = tool_dict
|
||||
|
||||
if tools_dict:
|
||||
if metadata.get("params", {}).get("function_calling") == "native":
|
||||
# If the function calling is native, then call the tools function calling handler
|
||||
|
||||
@@ -43,6 +43,10 @@ from open_webui.env import (
|
||||
AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA,
|
||||
AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL,
|
||||
)
|
||||
from open_webui.tools.builtin import (
|
||||
web_search, fetch_url, generate_image, edit_image,
|
||||
memory_query, memory_add
|
||||
)
|
||||
|
||||
import copy
|
||||
|
||||
@@ -320,6 +324,56 @@ async def get_tools(
|
||||
return tools_dict
|
||||
|
||||
|
||||
def get_builtin_tools(request: Request, extra_params: dict, features: dict = None) -> dict[str, dict]:
|
||||
"""
|
||||
Get built-in tools for native function calling.
|
||||
Only returns tools when BOTH the global config is enabled AND the feature is enabled for this chat.
|
||||
"""
|
||||
tools_dict = {}
|
||||
builtin_functions = []
|
||||
features = features or {}
|
||||
|
||||
# Add web search tools if enabled globally AND for this chat
|
||||
if (getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False)
|
||||
and features.get("web_search")):
|
||||
builtin_functions.extend([web_search, fetch_url])
|
||||
|
||||
# Add image generation/edit tools if enabled globally AND for this chat
|
||||
if (getattr(request.app.state.config, "ENABLE_IMAGE_GENERATION", False)
|
||||
and features.get("image_generation")):
|
||||
builtin_functions.append(generate_image)
|
||||
if (getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False)
|
||||
and features.get("image_generation")):
|
||||
builtin_functions.append(edit_image)
|
||||
|
||||
# Add memory tools if enabled for this chat
|
||||
if features.get("memory"):
|
||||
builtin_functions.extend([memory_query, memory_add])
|
||||
|
||||
for func in builtin_functions:
|
||||
callable = get_async_tool_function_and_apply_extra_params(
|
||||
func,
|
||||
{
|
||||
"__request__": request,
|
||||
"__user__": extra_params.get("__user__", {}),
|
||||
"__event_emitter__": extra_params.get("__event_emitter__"),
|
||||
},
|
||||
)
|
||||
|
||||
# Generate spec from function
|
||||
pydantic_model = convert_function_to_pydantic_model(func)
|
||||
spec = convert_pydantic_model_to_openai_function_spec(pydantic_model)
|
||||
|
||||
tools_dict[func.__name__] = {
|
||||
"tool_id": f"builtin:{func.__name__}",
|
||||
"callable": callable,
|
||||
"spec": spec,
|
||||
"type": "builtin",
|
||||
}
|
||||
|
||||
return tools_dict
|
||||
|
||||
|
||||
def parse_description(docstring: str | None) -> str:
|
||||
"""
|
||||
Parse a function's docstring to extract the description.
|
||||
|
||||
Reference in New Issue
Block a user