Yeuoly преди 1 година
родител
ревизия
a769edbc89
променени са 2 файла, в които са добавени 64 реда и са изтрити 22 реда
  1. 63 21
      api/core/tools/tool/api_tool.py
  2. 1 1
      web/app/components/tools/edit-custom-collection-modal/test-api.tsx

+ 63 - 21
api/core/tools/tool/api_tool.py

@@ -67,9 +67,9 @@ class ApiTool(Tool):
             
             if 'api_key_header_prefix' in credentials:
                 api_key_header_prefix = credentials['api_key_header_prefix']
-                if api_key_header_prefix == 'basic':
+                if api_key_header_prefix == 'basic' and credentials['api_key_value']:
                     credentials['api_key_value'] = f'Basic {credentials["api_key_value"]}'
-                elif api_key_header_prefix == 'bearer':
+                elif api_key_header_prefix == 'bearer' and credentials['api_key_value']:
                     credentials['api_key_value'] = f'Bearer {credentials["api_key_value"]}'
                 elif api_key_header_prefix == 'custom':
                     pass
@@ -184,21 +184,7 @@ class ApiTool(Tool):
                     for name, property in properties.items():
                         if name in parameters:
                             # convert type
-                            try:
-                                value = parameters[name]
-                                if property['type'] == 'integer':
-                                    value = int(value)
-                                elif property['type'] == 'number':
-                                    # check if it is a float
-                                    if '.' in value:
-                                        value = float(value)
-                                    else:
-                                        value = int(value)
-                                elif property['type'] == 'boolean':
-                                    value = bool(value)
-                                body[name] = value
-                            except ValueError as e:
-                                body[name] = parameters[name]
+                            body[name] = self._convert_body_property_type(property, parameters[name])
                         elif name in required:
                             raise ToolProviderCredentialValidationError(
                                 f"Missing required parameter {name} in operation {self.api_bundle.operation_id}"
@@ -228,10 +214,6 @@ class ApiTool(Tool):
         elif method == 'put':
             response = ssrf_proxy.put(url, params=params, headers=headers, cookies=cookies, data=body, timeout=10, follow_redirects=True)
         elif method == 'delete':
-            """
-            request body data is unsupported for DELETE method in standard http protocol
-            however, OpenAPI 3.0 supports request body data for DELETE method, so we support it here by using requests
-            """
             response = ssrf_proxy.delete(url, params=params, headers=headers, cookies=cookies, data=body, timeout=10, allow_redirects=True)
         elif method == 'patch':
             response = ssrf_proxy.patch(url, params=params, headers=headers, cookies=cookies, data=body, timeout=10, follow_redirects=True)
@@ -243,6 +225,66 @@ class ApiTool(Tool):
             raise ValueError(f'Invalid http method {method}')
         
         return response
+    
+    def _convert_body_property_any_of(self, property: dict[str, Any], value: Any, any_of: list[dict[str, Any]], max_recursive=10) -> Any:
+        if max_recursive <= 0:
+            raise Exception("Max recursion depth reached")
+        for option in any_of or []:
+            try:
+                if 'type' in option:
+                    # Attempt to convert the value based on the type.
+                    if option['type'] == 'integer' or option['type'] == 'int':
+                        return int(value)
+                    elif option['type'] == 'number':
+                        if '.' in str(value):
+                            return float(value)
+                        else:
+                            return int(value)
+                    elif option['type'] == 'string':
+                        return str(value)
+                    elif option['type'] == 'boolean':
+                        if str(value).lower() in ['true', '1']:
+                            return True
+                        elif str(value).lower() in ['false', '0']:
+                            return False
+                        else:
+                            continue  # Not a boolean, try next option
+                    elif option['type'] == 'null' and not value:
+                        return None
+                    else:
+                        continue  # Unsupported type, try next option
+                elif 'anyOf' in option and isinstance(option['anyOf'], list):
+                    # Recursive call to handle nested anyOf
+                    return self._convert_body_property_any_of(property, value, option['anyOf'], max_recursive - 1)
+            except ValueError:
+                continue  # Conversion failed, try next option
+        # If no option succeeded, you might want to return the value as is or raise an error
+        return value  # or raise ValueError(f"Cannot convert value '{value}' to any specified type in anyOf")
+
+    def _convert_body_property_type(self, property: dict[str, Any], value: Any) -> Any:
+        try:
+            if 'type' in property:
+                if property['type'] == 'integer' or property['type'] == 'int':
+                    return int(value)
+                elif property['type'] == 'number':
+                    # check if it is a float
+                    if '.' in value:
+                        return float(value)
+                    else:
+                        return int(value)
+                elif property['type'] == 'string':
+                    return str(value)
+                elif property['type'] == 'boolean':
+                    return bool(value)
+                elif property['type'] == 'null':
+                    if value is None:
+                        return None
+                else:
+                    raise ValueError(f"Invalid type {property['type']} for property {property}")
+            elif 'anyOf' in property and isinstance(property['anyOf'], list):
+                return self._convert_body_property_any_of(property, value, property['anyOf'])
+        except ValueError as e:
+            return value
 
     def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]:
         """

+ 1 - 1
web/app/components/tools/edit-custom-collection-modal/test-api.tsx

@@ -43,7 +43,7 @@ const TestApi: FC<Props> = ({
     }
     const data = {
       tool_name: toolName,
-      credentials: tempCredential,
+      credentials,
       schema_type: customCollection.schema_type,
       schema: customCollection.schema,
       parameters: parametersValue,