tool_entities.py 10 KB

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