tool_entities.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. from enum import Enum
  2. from typing import Any, Optional, Union, cast
  3. from pydantic import BaseModel, Field
  4. from core.tools.entities.common_entities import I18nObject
  5. class ToolProviderType(Enum):
  6. """
  7. Enum class for tool provider
  8. """
  9. BUILT_IN = "built-in"
  10. DATASET_RETRIEVAL = "dataset-retrieval"
  11. APP_BASED = "app-based"
  12. API_BASED = "api-based"
  13. @classmethod
  14. def value_of(cls, value: str) -> 'ToolProviderType':
  15. """
  16. Get value of given mode.
  17. :param value: mode value
  18. :return: mode
  19. """
  20. for mode in cls:
  21. if mode.value == value:
  22. return mode
  23. raise ValueError(f'invalid mode value {value}')
  24. class ApiProviderSchemaType(Enum):
  25. """
  26. Enum class for api provider schema type.
  27. """
  28. OPENAPI = "openapi"
  29. SWAGGER = "swagger"
  30. OPENAI_PLUGIN = "openai_plugin"
  31. OPENAI_ACTIONS = "openai_actions"
  32. @classmethod
  33. def value_of(cls, value: str) -> 'ApiProviderSchemaType':
  34. """
  35. Get value of given mode.
  36. :param value: mode value
  37. :return: mode
  38. """
  39. for mode in cls:
  40. if mode.value == value:
  41. return mode
  42. raise ValueError(f'invalid mode value {value}')
  43. class ApiProviderAuthType(Enum):
  44. """
  45. Enum class for api provider auth type.
  46. """
  47. NONE = "none"
  48. API_KEY = "api_key"
  49. @classmethod
  50. def value_of(cls, value: str) -> 'ApiProviderAuthType':
  51. """
  52. Get value of given mode.
  53. :param value: mode value
  54. :return: mode
  55. """
  56. for mode in cls:
  57. if mode.value == value:
  58. return mode
  59. raise ValueError(f'invalid mode value {value}')
  60. class ToolInvokeMessage(BaseModel):
  61. class MessageType(Enum):
  62. TEXT = "text"
  63. IMAGE = "image"
  64. LINK = "link"
  65. BLOB = "blob"
  66. IMAGE_LINK = "image_link"
  67. type: MessageType = MessageType.TEXT
  68. """
  69. plain text, image url or link url
  70. """
  71. message: Union[str, bytes] = None
  72. meta: dict[str, Any] = None
  73. save_as: str = ''
  74. class ToolInvokeMessageBinary(BaseModel):
  75. mimetype: str = Field(..., description="The mimetype of the binary")
  76. url: str = Field(..., description="The url of the binary")
  77. save_as: str = ''
  78. class ToolParameterOption(BaseModel):
  79. value: str = Field(..., description="The value of the option")
  80. label: I18nObject = Field(..., description="The label of the option")
  81. class ToolParameter(BaseModel):
  82. class ToolParameterType(Enum):
  83. STRING = "string"
  84. NUMBER = "number"
  85. BOOLEAN = "boolean"
  86. SELECT = "select"
  87. SECRET_INPUT = "secret-input"
  88. class ToolParameterForm(Enum):
  89. SCHEMA = "schema" # should be set while adding tool
  90. FORM = "form" # should be set before invoking tool
  91. LLM = "llm" # will be set by LLM
  92. name: str = Field(..., description="The name of the parameter")
  93. label: I18nObject = Field(..., description="The label presented to the user")
  94. human_description: I18nObject = Field(..., description="The description presented to the user")
  95. type: ToolParameterType = Field(..., description="The type of the parameter")
  96. form: ToolParameterForm = Field(..., description="The form of the parameter, schema/form/llm")
  97. llm_description: Optional[str] = None
  98. required: Optional[bool] = False
  99. default: Optional[Union[int, str]] = None
  100. min: Optional[Union[float, int]] = None
  101. max: Optional[Union[float, int]] = None
  102. options: Optional[list[ToolParameterOption]] = None
  103. @classmethod
  104. def get_simple_instance(cls,
  105. name: str, llm_description: str, type: ToolParameterType,
  106. required: bool, options: Optional[list[str]] = None) -> 'ToolParameter':
  107. """
  108. get a simple tool parameter
  109. :param name: the name of the parameter
  110. :param llm_description: the description presented to the LLM
  111. :param type: the type of the parameter
  112. :param required: if the parameter is required
  113. :param options: the options of the parameter
  114. """
  115. # convert options to ToolParameterOption
  116. if options:
  117. options = [ToolParameterOption(value=option, label=I18nObject(en_US=option, zh_Hans=option)) for option in options]
  118. return cls(
  119. name=name,
  120. label=I18nObject(en_US='', zh_Hans=''),
  121. human_description=I18nObject(en_US='', zh_Hans=''),
  122. type=type,
  123. form=cls.ToolParameterForm.LLM,
  124. llm_description=llm_description,
  125. required=required,
  126. options=options,
  127. )
  128. class ToolProviderIdentity(BaseModel):
  129. author: str = Field(..., description="The author of the tool")
  130. name: str = Field(..., description="The name of the tool")
  131. description: I18nObject = Field(..., description="The description of the tool")
  132. icon: str = Field(..., description="The icon of the tool")
  133. label: I18nObject = Field(..., description="The label of the tool")
  134. class ToolDescription(BaseModel):
  135. human: I18nObject = Field(..., description="The description presented to the user")
  136. llm: str = Field(..., description="The description presented to the LLM")
  137. class ToolIdentity(BaseModel):
  138. author: str = Field(..., description="The author of the tool")
  139. name: str = Field(..., description="The name of the tool")
  140. label: I18nObject = Field(..., description="The label of the tool")
  141. provider: str = Field(..., description="The provider of the tool")
  142. icon: Optional[str] = None
  143. class ToolCredentialsOption(BaseModel):
  144. value: str = Field(..., description="The value of the option")
  145. label: I18nObject = Field(..., description="The label of the option")
  146. class ToolProviderCredentials(BaseModel):
  147. class CredentialsType(Enum):
  148. SECRET_INPUT = "secret-input"
  149. TEXT_INPUT = "text-input"
  150. SELECT = "select"
  151. BOOLEAN = "boolean"
  152. @classmethod
  153. def value_of(cls, value: str) -> "ToolProviderCredentials.CredentialsType":
  154. """
  155. Get value of given mode.
  156. :param value: mode value
  157. :return: mode
  158. """
  159. for mode in cls:
  160. if mode.value == value:
  161. return mode
  162. raise ValueError(f'invalid mode value {value}')
  163. @staticmethod
  164. def default(value: str) -> str:
  165. return ""
  166. name: str = Field(..., description="The name of the credentials")
  167. type: CredentialsType = Field(..., description="The type of the credentials")
  168. required: bool = False
  169. default: Optional[Union[int, str]] = None
  170. options: Optional[list[ToolCredentialsOption]] = None
  171. label: Optional[I18nObject] = None
  172. help: Optional[I18nObject] = None
  173. url: Optional[str] = None
  174. placeholder: Optional[I18nObject] = None
  175. def to_dict(self) -> dict:
  176. return {
  177. 'name': self.name,
  178. 'type': self.type.value,
  179. 'required': self.required,
  180. 'default': self.default,
  181. 'options': self.options,
  182. 'help': self.help.to_dict() if self.help else None,
  183. 'label': self.label.to_dict(),
  184. 'url': self.url,
  185. 'placeholder': self.placeholder.to_dict() if self.placeholder else None,
  186. }
  187. class ToolRuntimeVariableType(Enum):
  188. TEXT = "text"
  189. IMAGE = "image"
  190. class ToolRuntimeVariable(BaseModel):
  191. type: ToolRuntimeVariableType = Field(..., description="The type of the variable")
  192. name: str = Field(..., description="The name of the variable")
  193. position: int = Field(..., description="The position of the variable")
  194. tool_name: str = Field(..., description="The name of the tool")
  195. class ToolRuntimeTextVariable(ToolRuntimeVariable):
  196. value: str = Field(..., description="The value of the variable")
  197. class ToolRuntimeImageVariable(ToolRuntimeVariable):
  198. value: str = Field(..., description="The path of the image")
  199. class ToolRuntimeVariablePool(BaseModel):
  200. conversation_id: str = Field(..., description="The conversation id")
  201. user_id: str = Field(..., description="The user id")
  202. tenant_id: str = Field(..., description="The tenant id of assistant")
  203. pool: list[ToolRuntimeVariable] = Field(..., description="The pool of variables")
  204. def __init__(self, **data: Any):
  205. pool = data.get('pool', [])
  206. # convert pool into correct type
  207. for index, variable in enumerate(pool):
  208. if variable['type'] == ToolRuntimeVariableType.TEXT.value:
  209. pool[index] = ToolRuntimeTextVariable(**variable)
  210. elif variable['type'] == ToolRuntimeVariableType.IMAGE.value:
  211. pool[index] = ToolRuntimeImageVariable(**variable)
  212. super().__init__(**data)
  213. def dict(self) -> dict:
  214. return {
  215. 'conversation_id': self.conversation_id,
  216. 'user_id': self.user_id,
  217. 'tenant_id': self.tenant_id,
  218. 'pool': [variable.dict() for variable in self.pool],
  219. }
  220. def set_text(self, tool_name: str, name: str, value: str) -> None:
  221. """
  222. set a text variable
  223. """
  224. for variable in self.pool:
  225. if variable.name == name:
  226. if variable.type == ToolRuntimeVariableType.TEXT:
  227. variable = cast(ToolRuntimeTextVariable, variable)
  228. variable.value = value
  229. return
  230. variable = ToolRuntimeTextVariable(
  231. type=ToolRuntimeVariableType.TEXT,
  232. name=name,
  233. position=len(self.pool),
  234. tool_name=tool_name,
  235. value=value,
  236. )
  237. self.pool.append(variable)
  238. def set_file(self, tool_name: str, value: str, name: str = None) -> None:
  239. """
  240. set an image variable
  241. :param tool_name: the name of the tool
  242. :param value: the id of the file
  243. """
  244. # check how many image variables are there
  245. image_variable_count = 0
  246. for variable in self.pool:
  247. if variable.type == ToolRuntimeVariableType.IMAGE:
  248. image_variable_count += 1
  249. if name is None:
  250. name = f"file_{image_variable_count}"
  251. for variable in self.pool:
  252. if variable.name == name:
  253. if variable.type == ToolRuntimeVariableType.IMAGE:
  254. variable = cast(ToolRuntimeImageVariable, variable)
  255. variable.value = value
  256. return
  257. variable = ToolRuntimeImageVariable(
  258. type=ToolRuntimeVariableType.IMAGE,
  259. name=name,
  260. position=len(self.pool),
  261. tool_name=tool_name,
  262. value=value,
  263. )
  264. self.pool.append(variable)
  265. class ModelToolPropertyKey(Enum):
  266. IMAGE_PARAMETER_NAME = "image_parameter_name"
  267. class ModelToolConfiguration(BaseModel):
  268. """
  269. Model tool configuration
  270. """
  271. type: str = Field(..., description="The type of the model tool")
  272. model: str = Field(..., description="The model")
  273. label: I18nObject = Field(..., description="The label of the model tool")
  274. properties: dict[ModelToolPropertyKey, Any] = Field(..., description="The properties of the model tool")
  275. class ModelToolProviderConfiguration(BaseModel):
  276. """
  277. Model tool provider configuration
  278. """
  279. provider: str = Field(..., description="The provider of the model tool")
  280. models: list[ModelToolConfiguration] = Field(..., description="The models of the model tool")
  281. label: I18nObject = Field(..., description="The label of the model tool")
  282. class ToolInvokeMeta(BaseModel):
  283. """
  284. Tool invoke meta
  285. """
  286. time_cost: float = Field(..., description="The time cost of the tool invoke")
  287. error: Optional[str] = None
  288. tool_config: Optional[dict] = None
  289. @classmethod
  290. def empty(cls) -> 'ToolInvokeMeta':
  291. """
  292. Get an empty instance of ToolInvokeMeta
  293. """
  294. return cls(time_cost=0.0, error=None, tool_config={})
  295. @classmethod
  296. def error_instance(cls, error: str) -> 'ToolInvokeMeta':
  297. """
  298. Get an instance of ToolInvokeMeta with error
  299. """
  300. return cls(time_cost=0.0, error=error, tool_config={})
  301. def to_dict(self) -> dict:
  302. return {
  303. 'time_cost': self.time_cost,
  304. 'error': self.error,
  305. 'tool_config': self.tool_config,
  306. }