Timothy Jaeryang Baek 1 bulan lalu
induk
melakukan
038df1131e

+ 14 - 12
backend/open_webui/utils/middleware.py

@@ -198,7 +198,6 @@ async def chat_completion_tools_handler(
                     allowed_params = (
                         spec.get("parameters", {}).get("properties", {}).keys()
                     )
-                    tool_function = tool["callable"]
                     tool_function_params = {
                         k: v
                         for k, v in tool_function_params.items()
@@ -206,8 +205,6 @@ async def chat_completion_tools_handler(
                     }
 
                     if tool.get("direct", False):
-                        tool_output = await tool_function(**tool_function_params)
-                    else:
                         tool_output = await event_caller(
                             {
                                 "type": "execute:tool",
@@ -215,12 +212,14 @@ async def chat_completion_tools_handler(
                                     "id": str(uuid4()),
                                     "name": tool_function_name,
                                     "params": tool_function_params,
-                                    "tool": tool,
                                     "server": tool.get("server", {}),
                                     "session_id": metadata.get("session_id", None),
                                 },
                             }
                         )
+                    else:
+                        tool_function = tool["callable"]
+                        tool_output = await tool_function(**tool_function_params)
 
                 except Exception as e:
                     tool_output = str(e)
@@ -229,8 +228,9 @@ async def chat_completion_tools_handler(
                     tool_output = json.dumps(tool_output, indent=4)
 
                 if isinstance(tool_output, str):
-                    tool_id = tools[tool_function_name].get("toolkit_id", "")
-                    if tools[tool_function_name].get("citation", False):
+                    tool = tools[tool_function_name]
+                    tool_id = tool.get("toolkit_id", "")
+                    if tool.get("citation", False) or tool.get("direct", False):
 
                         sources.append(
                             {
@@ -1825,7 +1825,7 @@ async def process_chat_response(
                                     .get("properties", {})
                                     .keys()
                                 )
-                                tool_function = tool["callable"]
+
                                 tool_function_params = {
                                     k: v
                                     for k, v in tool_function_params.items()
@@ -1833,10 +1833,6 @@ async def process_chat_response(
                                 }
 
                                 if tool.get("direct", False):
-                                    tool_result = await tool_function(
-                                        **tool_function_params
-                                    )
-                                else:
                                     tool_result = await event_caller(
                                         {
                                             "type": "execute:tool",
@@ -1844,7 +1840,6 @@ async def process_chat_response(
                                                 "id": str(uuid4()),
                                                 "name": tool_name,
                                                 "params": tool_function_params,
-                                                "tool": tool,
                                                 "server": tool.get("server", {}),
                                                 "session_id": metadata.get(
                                                     "session_id", None
@@ -1852,6 +1847,13 @@ async def process_chat_response(
                                             },
                                         }
                                     )
+
+                                else:
+                                    tool_function = tool["callable"]
+                                    tool_result = await tool_function(
+                                        **tool_function_params
+                                    )
+
                             except Exception as e:
                                 tool_result = str(e)
 

+ 57 - 22
src/lib/apis/index.ts

@@ -323,26 +323,25 @@ export const executeToolServer = async (
 	token: string,
 	url: string,
 	name: string,
-	params: object,
+	params: Record<string, any>,
 	serverData: { openapi: any; info: any; specs: any }
 ) => {
 	let error = null;
 
 	try {
-		// Find the matching operationId in the OpenAPI specification
-		const matchingRoute = Object.entries(serverData.openapi.paths).find(([path, methods]) => {
-			return Object.entries(methods).some(
-				([method, operation]: any) => operation.operationId === name
-			);
-		});
+		// Find the matching operationId in the OpenAPI spec
+		const matchingRoute = Object.entries(serverData.openapi.paths).find(([_, methods]) =>
+			Object.entries(methods as any).some(([__, operation]: any) => operation.operationId === name)
+		);
 
 		if (!matchingRoute) {
 			throw new Error(`No matching route found for operationId: ${name}`);
 		}
 
-		const [route, methods] = matchingRoute;
-		const methodEntry = Object.entries(methods).find(
-			([method, operation]: any) => operation.operationId === name
+		const [routePath, methods] = matchingRoute;
+
+		const methodEntry = Object.entries(methods as any).find(
+			([_, operation]: any) => operation.operationId === name
 		);
 
 		if (!methodEntry) {
@@ -351,18 +350,55 @@ export const executeToolServer = async (
 
 		const [httpMethod, operation]: [string, any] = methodEntry;
 
-		// Replace path parameters in the URL
-		let finalUrl = `${url}${route}`;
+		// Split parameters by type
+		const pathParams: Record<string, any> = {};
+		const queryParams: Record<string, any> = {};
+		let bodyParams: any = {};
+
 		if (operation.parameters) {
-			Object.entries(params).forEach(([key, value]) => {
-				finalUrl = finalUrl.replace(`{${key}}`, encodeURIComponent(value as string));
+			operation.parameters.forEach((param: any) => {
+				const paramName = param.name;
+				const paramIn = param.in;
+				if (params.hasOwnProperty(paramName)) {
+					if (paramIn === 'path') {
+						pathParams[paramName] = params[paramName];
+					} else if (paramIn === 'query') {
+						queryParams[paramName] = params[paramName];
+					}
+				}
 			});
 		}
 
-		// Headers and request options
-		const headers = {
-			...(token && { authorization: `Bearer ${token}` }),
-			'Content-Type': 'application/json'
+		let finalUrl = `${url}${routePath}`;
+
+		// Replace path parameters (`{param}`)
+		Object.entries(pathParams).forEach(([key, value]) => {
+			finalUrl = finalUrl.replace(new RegExp(`{${key}}`, 'g'), encodeURIComponent(value));
+		});
+
+		// Append query parameters to URL if any
+		if (Object.keys(queryParams).length > 0) {
+			const queryString = new URLSearchParams(
+				Object.entries(queryParams).map(([k, v]) => [k, String(v)])
+			).toString();
+			finalUrl += `?${queryString}`;
+		}
+
+		// Handle requestBody composite
+		if (operation.requestBody && operation.requestBody.content) {
+			const contentType = Object.keys(operation.requestBody.content)[0]; // typically "application/json"
+			if (params.body !== undefined) {
+				bodyParams = params.body; // Assume the provided params has a "body" property containing the payload
+			} else {
+				// Optional: Fallback or explicit error if body is expected but not provided
+				throw new Error(`Request body expected for operation '${name}' but none found.`);
+			}
+		}
+
+		// Prepare headers and request options
+		const headers: Record<string, string> = {
+			'Content-Type': 'application/json',
+			...(token && { authorization: `Bearer ${token}` })
 		};
 
 		let requestOptions: RequestInit = {
@@ -370,15 +406,14 @@ export const executeToolServer = async (
 			headers
 		};
 
-		// Handle request body for POST, PUT, PATCH
 		if (['post', 'put', 'patch'].includes(httpMethod.toLowerCase()) && operation.requestBody) {
-			requestOptions.body = JSON.stringify(params);
+			requestOptions.body = JSON.stringify(bodyParams);
 		}
 
-		// Execute the request
 		const res = await fetch(finalUrl, requestOptions);
 		if (!res.ok) {
-			throw new Error(`HTTP error! Status: ${res.status}`);
+			const resText = await res.text();
+			throw new Error(`HTTP error! Status: ${res.status}. Message: ${resText}`);
 		}
 
 		return await res.json();

+ 0 - 1
src/lib/components/chat/MessageInput.svelte

@@ -999,7 +999,6 @@
 															return;
 														}
 
-														console.log('keypress', e);
 														// Prevent Enter key from creating a new line
 														const isCtrlPressed = e.ctrlKey || e.metaKey;
 														const enterPressed =

+ 6 - 9
src/routes/+layout.svelte

@@ -25,7 +25,8 @@
 		temporaryChatEnabled,
 		isLastActiveTab,
 		isApp,
-		appInfo
+		appInfo,
+		toolServers
 	} from '$lib/stores';
 	import { goto } from '$app/navigation';
 	import { page } from '$app/stores';
@@ -204,9 +205,9 @@
 	};
 
 	const executeTool = async (data, cb) => {
-		console.log(data);
+		const toolServer = $toolServers?.find((server) => server.url === data.server?.url);
 
-		const toolServer = $settings?.toolServers?.find((server) => server.url === data.server?.url);
+		console.log('executeTool', data, toolServer);
 
 		if (toolServer) {
 			const res = await executeToolServer(
@@ -215,13 +216,9 @@
 				data?.name,
 				data?.params,
 				toolServer
-			).catch((error) => {
-				console.error('executeToolServer', error);
-				return {
-					error: error
-				};
-			});
+			);
 
+			console.log('executeToolServer', res);
 			if (cb) {
 				cb(JSON.parse(JSON.stringify(res)));
 			}