| 
									
										
										
										
											2024-02-01 18:11:57 +08:00
										 |  |  | import json | 
					
						
							| 
									
										
										
										
											2024-04-12 17:46:39 +08:00
										 |  |  | from os import getenv | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | from typing import Any | 
					
						
							| 
									
										
										
										
											2024-03-04 14:16:47 +08:00
										 |  |  | from urllib.parse import urlencode | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-01 18:11:57 +08:00
										 |  |  | import httpx | 
					
						
							| 
									
										
										
										
											2024-02-06 13:21:13 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-13 22:42:08 +08:00
										 |  |  | from core.helper import ssrf_proxy | 
					
						
							| 
									
										
										
										
											2024-05-27 22:01:11 +08:00
										 |  |  | from core.tools.entities.tool_bundle import ApiToolBundle | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | from core.tools.entities.tool_entities import ToolInvokeMessage, ToolProviderType | 
					
						
							| 
									
										
										
										
											2024-03-19 18:17:12 +08:00
										 |  |  | from core.tools.errors import ToolInvokeError, ToolParameterValidationError, ToolProviderCredentialValidationError | 
					
						
							| 
									
										
										
										
											2024-02-01 18:11:57 +08:00
										 |  |  | from core.tools.tool.tool import Tool | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-12 17:46:39 +08:00
										 |  |  | API_TOOL_DEFAULT_TIMEOUT = ( | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |     int(getenv("API_TOOL_DEFAULT_CONNECT_TIMEOUT", "10")), | 
					
						
							|  |  |  |     int(getenv("API_TOOL_DEFAULT_READ_TIMEOUT", "60")), | 
					
						
							| 
									
										
										
										
											2024-04-12 17:46:39 +08:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | class ApiTool(Tool): | 
					
						
							| 
									
										
										
										
											2024-05-27 22:01:11 +08:00
										 |  |  |     api_bundle: ApiToolBundle | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     Api tool | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |     def fork_tool_runtime(self, runtime: dict[str, Any]) -> "Tool": | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         fork a new tool with meta data | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         :param meta: the meta data of a tool call processing, tenant_id is required | 
					
						
							|  |  |  |         :return: the new tool | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         return self.__class__( | 
					
						
							| 
									
										
										
										
											2024-06-14 01:05:37 +08:00
										 |  |  |             identity=self.identity.model_copy() if self.identity else None, | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |             parameters=self.parameters.copy() if self.parameters else None, | 
					
						
							| 
									
										
										
										
											2024-06-14 01:05:37 +08:00
										 |  |  |             description=self.description.model_copy() if self.description else None, | 
					
						
							|  |  |  |             api_bundle=self.api_bundle.model_copy() if self.api_bundle else None, | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             runtime=Tool.Runtime(**runtime), | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |     def validate_credentials( | 
					
						
							|  |  |  |         self, credentials: dict[str, Any], parameters: dict[str, Any], format_only: bool = False | 
					
						
							|  |  |  |     ) -> str: | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         validate the credentials for Api tool | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         # assemble validate request and request parameters | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         headers = self.assembling_request(parameters) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if format_only: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             return "" | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         response = self.do_http_request(self.api_bundle.server_url, self.api_bundle.method, headers, parameters) | 
					
						
							|  |  |  |         # validate response | 
					
						
							| 
									
										
										
										
											2024-02-05 18:48:30 +08:00
										 |  |  |         return self.validate_and_parse_response(response) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     def tool_provider_type(self) -> ToolProviderType: | 
					
						
							| 
									
										
										
										
											2024-05-27 22:01:11 +08:00
										 |  |  |         return ToolProviderType.API | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-09 15:21:33 +08:00
										 |  |  |     def assembling_request(self, parameters: dict[str, Any]) -> dict[str, Any]: | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         headers = {} | 
					
						
							|  |  |  |         credentials = self.runtime.credentials or {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         if "auth_type" not in credentials: | 
					
						
							|  |  |  |             raise ToolProviderCredentialValidationError("Missing auth_type") | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         if credentials["auth_type"] == "api_key": | 
					
						
							|  |  |  |             api_key_header = "api_key" | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             if "api_key_header" in credentials: | 
					
						
							|  |  |  |                 api_key_header = credentials["api_key_header"] | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             if "api_key_value" not in credentials: | 
					
						
							|  |  |  |                 raise ToolProviderCredentialValidationError("Missing api_key_value") | 
					
						
							|  |  |  |             elif not isinstance(credentials["api_key_value"], str): | 
					
						
							|  |  |  |                 raise ToolProviderCredentialValidationError("api_key_value must be a string") | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             if "api_key_header_prefix" in credentials: | 
					
						
							|  |  |  |                 api_key_header_prefix = credentials["api_key_header_prefix"] | 
					
						
							|  |  |  |                 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" and credentials["api_key_value"]: | 
					
						
							|  |  |  |                     credentials["api_key_value"] = f'Bearer {credentials["api_key_value"]}' | 
					
						
							|  |  |  |                 elif api_key_header_prefix == "custom": | 
					
						
							| 
									
										
										
										
											2024-02-28 23:19:08 +08:00
										 |  |  |                     pass | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             headers[api_key_header] = credentials["api_key_value"] | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         needed_parameters = [parameter for parameter in self.api_bundle.parameters if parameter.required] | 
					
						
							|  |  |  |         for parameter in needed_parameters: | 
					
						
							|  |  |  |             if parameter.required and parameter.name not in parameters: | 
					
						
							| 
									
										
										
										
											2024-03-19 18:17:12 +08:00
										 |  |  |                 raise ToolParameterValidationError(f"Missing required parameter {parameter.name}") | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |             if parameter.default is not None and parameter.name not in parameters: | 
					
						
							|  |  |  |                 parameters[parameter.name] = parameter.default | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return headers | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  |     def validate_and_parse_response(self, response: httpx.Response) -> str: | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         validate the response | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         if isinstance(response, httpx.Response): | 
					
						
							|  |  |  |             if response.status_code >= 400: | 
					
						
							| 
									
										
										
										
											2024-03-19 18:17:12 +08:00
										 |  |  |                 raise ToolInvokeError(f"Request failed with status code {response.status_code} and {response.text}") | 
					
						
							| 
									
										
										
										
											2024-01-30 22:22:58 +08:00
										 |  |  |             if not response.content: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 return "Empty response from the tool, please check your parameters and try again." | 
					
						
							| 
									
										
										
										
											2024-01-30 22:22:58 +08:00
										 |  |  |             try: | 
					
						
							|  |  |  |                 response = response.json() | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     return json.dumps(response, ensure_ascii=False) | 
					
						
							|  |  |  |                 except Exception as e: | 
					
						
							|  |  |  |                     return json.dumps(response) | 
					
						
							|  |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 return response.text | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             raise ValueError(f"Invalid response type {type(response)}") | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def get_parameter_value(parameter, parameters): | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         if parameter["name"] in parameters: | 
					
						
							|  |  |  |             return parameters[parameter["name"]] | 
					
						
							|  |  |  |         elif parameter.get("required", False): | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  |             raise ToolParameterValidationError(f"Missing required parameter {parameter['name']}") | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             return (parameter.get("schema", {}) or {}).get("default", "") | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |     def do_http_request( | 
					
						
							|  |  |  |         self, url: str, method: str, headers: dict[str, Any], parameters: dict[str, Any] | 
					
						
							|  |  |  |     ) -> httpx.Response: | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         do http request depending on api bundle | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         method = method.lower() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         params = {} | 
					
						
							|  |  |  |         path_params = {} | 
					
						
							|  |  |  |         body = {} | 
					
						
							|  |  |  |         cookies = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # check parameters | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         for parameter in self.api_bundle.openapi.get("parameters", []): | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  |             value = self.get_parameter_value(parameter, parameters) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             if parameter["in"] == "path": | 
					
						
							|  |  |  |                 path_params[parameter["name"]] = value | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             elif parameter["in"] == "query": | 
					
						
							|  |  |  |                 if value != "": | 
					
						
							|  |  |  |                     params[parameter["name"]] = value | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             elif parameter["in"] == "cookie": | 
					
						
							|  |  |  |                 cookies[parameter["name"]] = value | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             elif parameter["in"] == "header": | 
					
						
							|  |  |  |                 headers[parameter["name"]] = value | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # check if there is a request body and handle it | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         if "requestBody" in self.api_bundle.openapi and self.api_bundle.openapi["requestBody"] is not None: | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |             # handle json request body | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             if "content" in self.api_bundle.openapi["requestBody"]: | 
					
						
							|  |  |  |                 for content_type in self.api_bundle.openapi["requestBody"]["content"]: | 
					
						
							|  |  |  |                     headers["Content-Type"] = content_type | 
					
						
							|  |  |  |                     body_schema = self.api_bundle.openapi["requestBody"]["content"][content_type]["schema"] | 
					
						
							|  |  |  |                     required = body_schema.get("required", []) | 
					
						
							|  |  |  |                     properties = body_schema.get("properties", {}) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |                     for name, property in properties.items(): | 
					
						
							|  |  |  |                         if name in parameters: | 
					
						
							|  |  |  |                             # convert type | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                             body[name] = self._convert_body_property_type(property, parameters[name]) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |                         elif name in required: | 
					
						
							| 
									
										
										
										
											2024-03-19 18:17:12 +08:00
										 |  |  |                             raise ToolParameterValidationError( | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |                                 f"Missing required parameter {name} in operation {self.api_bundle.operation_id}" | 
					
						
							|  |  |  |                             ) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                         elif "default" in property: | 
					
						
							|  |  |  |                             body[name] = property["default"] | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |                         else: | 
					
						
							|  |  |  |                             body[name] = None | 
					
						
							|  |  |  |                     break | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         # replace path parameters | 
					
						
							|  |  |  |         for name, value in path_params.items(): | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             url = url.replace(f"{{{name}}}", f"{value}") | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # parse http body data if needed, for GET/HEAD/OPTIONS/TRACE, the body is ignored | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |         if "Content-Type" in headers: | 
					
						
							|  |  |  |             if headers["Content-Type"] == "application/json": | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  |                 body = json.dumps(body) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             elif headers["Content-Type"] == "application/x-www-form-urlencoded": | 
					
						
							| 
									
										
										
										
											2024-03-04 14:16:47 +08:00
										 |  |  |                 body = urlencode(body) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |             else: | 
					
						
							|  |  |  |                 body = body | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-13 22:42:08 +08:00
										 |  |  |         if method in {"get", "head", "post", "put", "delete", "patch"}: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             response = getattr(ssrf_proxy, method)( | 
					
						
							|  |  |  |                 url, | 
					
						
							|  |  |  |                 params=params, | 
					
						
							|  |  |  |                 headers=headers, | 
					
						
							|  |  |  |                 cookies=cookies, | 
					
						
							|  |  |  |                 data=body, | 
					
						
							|  |  |  |                 timeout=API_TOOL_DEFAULT_TIMEOUT, | 
					
						
							|  |  |  |                 follow_redirects=True, | 
					
						
							|  |  |  |             ) | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  |             return response | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             raise ValueError(f"Invalid http method {self.method}") | 
					
						
							| 
									
										
										
										
											2024-06-24 16:14:59 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |     def _convert_body_property_any_of( | 
					
						
							|  |  |  |         self, property: dict[str, Any], value: Any, any_of: list[dict[str, Any]], max_recursive=10 | 
					
						
							|  |  |  |     ) -> Any: | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |         if max_recursive <= 0: | 
					
						
							|  |  |  |             raise Exception("Max recursion depth reached") | 
					
						
							|  |  |  |         for option in any_of or []: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 if "type" in option: | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     # Attempt to convert the value based on the type. | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     if option["type"] == "integer" or option["type"] == "int": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                         return int(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     elif option["type"] == "number": | 
					
						
							|  |  |  |                         if "." in str(value): | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                             return float(value) | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             return int(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     elif option["type"] == "string": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                         return str(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     elif option["type"] == "boolean": | 
					
						
							| 
									
										
										
										
											2024-09-13 22:42:08 +08:00
										 |  |  |                         if str(value).lower() in {"true", "1"}: | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                             return True | 
					
						
							| 
									
										
										
										
											2024-09-13 22:42:08 +08:00
										 |  |  |                         elif str(value).lower() in {"false", "0"}: | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                             return False | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             continue  # Not a boolean, try next option | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     elif option["type"] == "null" and not value: | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                         return None | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         continue  # Unsupported type, try next option | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 elif "anyOf" in option and isinstance(option["anyOf"], list): | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     # Recursive call to handle nested anyOf | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     return self._convert_body_property_any_of(property, value, option["anyOf"], max_recursive - 1) | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |             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: | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             if "type" in property: | 
					
						
							|  |  |  |                 if property["type"] == "integer" or property["type"] == "int": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     return int(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 elif property["type"] == "number": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     # check if it is a float | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                     if "." in str(value): | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                         return float(value) | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         return int(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 elif property["type"] == "string": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     return str(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 elif property["type"] == "boolean": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     return bool(value) | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 elif property["type"] == "null": | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                     if value is None: | 
					
						
							|  |  |  |                         return None | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |                 elif property["type"] == "object" or property["type"] == "array": | 
					
						
							| 
									
										
										
										
											2024-04-16 19:54:17 +08:00
										 |  |  |                     if isinstance(value, str): | 
					
						
							|  |  |  |                         try: | 
					
						
							| 
									
										
										
										
											2024-07-05 17:11:59 +08:00
										 |  |  |                             # an array str like '[1,2]' also can convert to list [1,2] through json.loads | 
					
						
							|  |  |  |                             # json not support single quote, but we can support it | 
					
						
							|  |  |  |                             value = value.replace("'", '"') | 
					
						
							| 
									
										
										
										
											2024-04-16 19:54:17 +08:00
										 |  |  |                             return json.loads(value) | 
					
						
							|  |  |  |                         except ValueError: | 
					
						
							|  |  |  |                             return value | 
					
						
							|  |  |  |                     elif isinstance(value, dict): | 
					
						
							|  |  |  |                         return value | 
					
						
							|  |  |  |                     else: | 
					
						
							|  |  |  |                         return value | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     raise ValueError(f"Invalid type {property['type']} for property {property}") | 
					
						
							| 
									
										
										
										
											2024-09-10 17:00:20 +08:00
										 |  |  |             elif "anyOf" in property and isinstance(property["anyOf"], list): | 
					
						
							|  |  |  |                 return self._convert_body_property_any_of(property, value, property["anyOf"]) | 
					
						
							| 
									
										
										
										
											2024-02-29 14:39:05 +08:00
										 |  |  |         except ValueError as e: | 
					
						
							|  |  |  |             return value | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-09 15:21:33 +08:00
										 |  |  |     def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]: | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  |         """
 | 
					
						
							|  |  |  |         invoke http request | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # assemble request | 
					
						
							| 
									
										
										
										
											2024-01-31 11:58:07 +08:00
										 |  |  |         headers = self.assembling_request(tool_parameters) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # do http request | 
					
						
							| 
									
										
										
										
											2024-01-31 11:58:07 +08:00
										 |  |  |         response = self.do_http_request(self.api_bundle.server_url, self.api_bundle.method, headers, tool_parameters) | 
					
						
							| 
									
										
										
										
											2024-01-23 19:58:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # validate response | 
					
						
							|  |  |  |         response = self.validate_and_parse_response(response) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # assemble invoke message | 
					
						
							|  |  |  |         return self.create_text_message(response) |