From fd9641dcd11d1f7133e4d08d45d72934a1b1fe31 Mon Sep 17 00:00:00 2001
From: Timothy Jaeryang Baek <tim@openwebui.com>
Date: Fri, 28 Mar 2025 01:20:45 -0700
Subject: [PATCH] refac

---
 backend/open_webui/utils/middleware.py |  2 -
 src/lib/utils/index.ts                 | 80 +++++++++++++++++++++-----
 2 files changed, 67 insertions(+), 15 deletions(-)

diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py
index 5aecc5c40..32681294d 100644
--- a/backend/open_webui/utils/middleware.py
+++ b/backend/open_webui/utils/middleware.py
@@ -1548,8 +1548,6 @@ async def process_chat_response(
                         try:
                             data = json.loads(data)
 
-                            print(data)
-
                             data, _ = await process_filter_functions(
                                 request=request,
                                 filter_functions=filter_functions,
diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts
index d154a3f3e..927f62ab3 100644
--- a/src/lib/utils/index.ts
+++ b/src/lib/utils/index.ts
@@ -1071,6 +1071,55 @@ export const getLineCount = (text) => {
 	return text ? text.split('\n').length : 0;
 };
 
+// Helper function to recursively resolve OpenAPI schema into JSON schema format
+function resolveSchema(schemaRef, components, resolvedSchemas = new Set()) {
+	if (!schemaRef) return {};
+
+	if (schemaRef['$ref']) {
+		const refPath = schemaRef['$ref'];
+		const schemaName = refPath.split('/').pop();
+
+		if (resolvedSchemas.has(schemaName)) {
+			// Avoid infinite recursion on circular references
+			return {};
+		}
+		resolvedSchemas.add(schemaName);
+		const referencedSchema = components.schemas[schemaName];
+		return resolveSchema(referencedSchema, components, resolvedSchemas);
+	}
+
+	if (schemaRef.type) {
+		const schemaObj = { type: schemaRef.type };
+
+		if (schemaRef.description) {
+			schemaObj.description = schemaRef.description;
+		}
+
+		switch (schemaRef.type) {
+			case 'object':
+				schemaObj.properties = {};
+				schemaObj.required = schemaRef.required || [];
+				for (const [propName, propSchema] of Object.entries(schemaRef.properties || {})) {
+					schemaObj.properties[propName] = resolveSchema(propSchema, components);
+				}
+				break;
+
+			case 'array':
+				schemaObj.items = resolveSchema(schemaRef.items, components);
+				break;
+
+			default:
+				// for primitive types (string, integer, etc.), just use as is
+				break;
+		}
+		return schemaObj;
+	}
+
+	// fallback for schemas without explicit type
+	return {};
+}
+
+// Main conversion function
 export const convertOpenApiToToolPayload = (openApiSpec) => {
 	const toolPayload = [];
 
@@ -1087,7 +1136,7 @@ export const convertOpenApiToToolPayload = (openApiSpec) => {
 				}
 			};
 
-			// Extract path or query parameters
+			// Extract path and query parameters
 			if (operation.parameters) {
 				operation.parameters.forEach((param) => {
 					tool.parameters.properties[param.name] = {
@@ -1101,21 +1150,26 @@ export const convertOpenApiToToolPayload = (openApiSpec) => {
 				});
 			}
 
-			// Extract parameters from requestBody if applicable
+			// Extract and recursively resolve requestBody if available
 			if (operation.requestBody) {
-				const ref = operation.requestBody.content['application/json'].schema['$ref'];
-				if (ref) {
-					const schemaName = ref.split('/').pop();
-					const schemaDef = openApiSpec.components.schemas[schemaName];
+				const content = operation.requestBody.content;
+				if (content && content['application/json']) {
+					const requestSchema = content['application/json'].schema;
+					const resolvedRequestSchema = resolveSchema(requestSchema, openApiSpec.components);
 
-					if (schemaDef && schemaDef.properties) {
-						for (const [prop, details] of Object.entries(schemaDef.properties)) {
-							tool.parameters.properties[prop] = {
-								type: details.type,
-								description: details.description || ''
-							};
+					if (resolvedRequestSchema.properties) {
+						tool.parameters.properties = {
+							...tool.parameters.properties,
+							...resolvedRequestSchema.properties
+						};
+
+						if (resolvedRequestSchema.required) {
+							tool.parameters.required = [
+								...new Set([...tool.parameters.required, ...resolvedRequestSchema.required])
+							];
 						}
-						tool.parameters.required = schemaDef.required || [];
+					} else if (resolvedRequestSchema.type === 'array') {
+						tool.parameters = resolvedRequestSchema; // special case when root schema is an array
 					}
 				}
 			}