Browse Source

feat: native tool calling frontend

Timothy Jaeryang Baek 2 months ago
parent
commit
ec9be0d20d

+ 8 - 0
backend/open_webui/main.py

@@ -861,6 +861,7 @@ async def chat_completion(
         if model_id not in request.app.state.MODELS:
             raise Exception("Model not found")
         model = request.app.state.MODELS[model_id]
+        model_info = Models.get_model_by_id(model_id)
 
         # Check if user has access to the model
         if not BYPASS_MODEL_ACCESS_CONTROL and user.role == "user":
@@ -878,6 +879,13 @@ async def chat_completion(
             "files": form_data.get("files", None),
             "features": form_data.get("features", None),
             "variables": form_data.get("variables", None),
+            "model": model_info,
+            **(
+                {"function_calling": "native"}
+                if form_data.get("params", {}).get("function_calling") == "native"
+                or model_info.params.model_dump().get("function_calling") == "native"
+                else {}
+            ),
         }
         form_data["metadata"] = metadata
 

+ 10 - 7
backend/open_webui/utils/middleware.py

@@ -702,6 +702,7 @@ def apply_params_to_form_data(form_data, model):
 
 
 async def process_chat_payload(request, form_data, metadata, user, model):
+
     form_data = apply_params_to_form_data(form_data, model)
     log.debug(f"form_data: {form_data}")
 
@@ -808,13 +809,15 @@ async def process_chat_payload(request, form_data, metadata, user, model):
     }
     form_data["metadata"] = metadata
 
-    try:
-        form_data, flags = await chat_completion_tools_handler(
-            request, form_data, user, models, extra_params
-        )
-        sources.extend(flags.get("sources", []))
-    except Exception as e:
-        log.exception(e)
+    if not form_data["metadata"].get("function_calling") == "native":
+        # If the function calling is not native, then call the tools function calling handler
+        try:
+            form_data, flags = await chat_completion_tools_handler(
+                request, form_data, user, models, extra_params
+            )
+            sources.extend(flags.get("sources", []))
+        except Exception as e:
+            log.exception(e)
 
     try:
         form_data, flags = await chat_completion_files_handler(request, form_data, user)

+ 30 - 0
src/lib/components/chat/Settings/Advanced/AdvancedParams.svelte

@@ -12,6 +12,7 @@
 	export let params = {
 		// Advanced
 		stream_response: null, // Set stream responses for this model individually
+		function_calling: null,
 		seed: null,
 		stop: null,
 		temperature: null,
@@ -81,6 +82,35 @@
 		</Tooltip>
 	</div>
 
+	<div>
+		<Tooltip
+			content={$i18n.t(
+				'Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model’s built-in tool-calling capabilities, but requires the model to inherently support this feature.'
+			)}
+			placement="top-start"
+			className="inline-tooltip"
+		>
+			<div class=" py-0.5 flex w-full justify-between">
+				<div class=" self-center text-xs font-medium">
+					{$i18n.t('Function Calling')}
+				</div>
+				<button
+					class="p-1 px-3 text-xs flex rounded transition"
+					on:click={() => {
+						params.function_calling = (params?.function_calling ?? null) === null ? 'native' : null;
+					}}
+					type="button"
+				>
+					{#if params.function_calling === 'native'}
+						<span class="ml-2 self-center">{$i18n.t('Native')}</span>
+					{:else}
+						<span class="ml-2 self-center">{$i18n.t('Default')}</span>
+					{/if}
+				</button>
+			</div>
+		</Tooltip>
+	</div>
+
 	<div class=" py-0.5 w-full justify-between">
 		<Tooltip
 			content={$i18n.t(

+ 1 - 0
src/lib/components/chat/Settings/General.svelte

@@ -46,6 +46,7 @@
 	let params = {
 		// Advanced
 		stream_response: null,
+		function_calling: null,
 		seed: null,
 		temperature: null,
 		frequency_penalty: null,