|
@@ -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]:
|
|
|
"""
|