tool_entities.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. 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. SECRET_INPUT = "secret-input"
  87. class ToolParameterForm(Enum):
  88. SCHEMA = "schema" # should be set while adding tool
  89. FORM = "form" # should be set before invoking tool
  90. LLM = "llm" # will be set by LLM
  91. name: str = Field(..., description="The name of the parameter")
  92. label: I18nObject = Field(..., description="The label presented to the user")
  93. human_description: I18nObject = Field(..., description="The description presented to the user")
  94. type: ToolParameterType = Field(..., description="The type of the parameter")
  95. form: ToolParameterForm = Field(..., description="The form of the parameter, schema/form/llm")
  96. llm_description: Optional[str] = None
  97. required: Optional[bool] = False
  98. default: Optional[Union[int, str]] = None
  99. min: Optional[Union[float, int]] = None
  100. max: Optional[Union[float, int]] = None
  101. options: Optional[list[ToolParameterOption]] = None
  102. @classmethod
  103. def get_simple_instance(cls,
  104. name: str, llm_description: str, type: ToolParameterType,
  105. required: bool, options: Optional[list[str]] = None) -> 'ToolParameter':
  106. """
  107. get a simple tool parameter
  108. :param name: the name of the parameter
  109. :param llm_description: the description presented to the LLM
  110. :param type: the type of the parameter
  111. :param required: if the parameter is required
  112. :param options: the options of the parameter
  113. """
  114. # convert options to ToolParameterOption
  115. if options:
  116. options = [ToolParameterOption(value=option, label=I18nObject(en_US=option, zh_Hans=option)) for option in options]
  117. return cls(
  118. name=name,
  119. label=I18nObject(en_US='', zh_Hans=''),
  120. human_description=I18nObject(en_US='', zh_Hans=''),
  121. type=type,
  122. form=cls.ToolParameterForm.LLM,
  123. llm_description=llm_description,
  124. required=required,
  125. options=options,
  126. )
  127. class ToolProviderIdentity(BaseModel):
  128. author: str = Field(..., description="The author of the tool")
  129. name: str = Field(..., description="The name of the tool")
  130. description: I18nObject = Field(..., description="The description of the tool")
  131. icon: str = Field(..., description="The icon of the tool")
  132. label: I18nObject = Field(..., description="The label of the tool")
  133. class ToolDescription(BaseModel):
  134. human: I18nObject = Field(..., description="The description presented to the user")
  135. llm: str = Field(..., description="The description presented to the LLM")
  136. class ToolIdentity(BaseModel):
  137. author: str = Field(..., description="The author of the tool")
  138. name: str = Field(..., description="The name of the tool")
  139. label: I18nObject = Field(..., description="The label of the tool")
  140. class ToolCredentialsOption(BaseModel):
  141. value: str = Field(..., description="The value of the option")
  142. label: I18nObject = Field(..., description="The label of the option")
  143. class ToolProviderCredentials(BaseModel):
  144. class CredentialsType(Enum):
  145. SECRET_INPUT = "secret-input"
  146. TEXT_INPUT = "text-input"
  147. SELECT = "select"
  148. BOOLEAN = "boolean"
  149. @classmethod
  150. def value_of(cls, value: str) -> "ToolProviderCredentials.CredentialsType":
  151. """
  152. Get value of given mode.
  153. :param value: mode value
  154. :return: mode
  155. """
  156. for mode in cls:
  157. if mode.value == value:
  158. return mode
  159. raise ValueError(f'invalid mode value {value}')
  160. @staticmethod
  161. def default(value: str) -> str:
  162. return ""
  163. name: str = Field(..., description="The name of the credentials")
  164. type: CredentialsType = Field(..., description="The type of the credentials")
  165. required: bool = False
  166. default: Optional[Union[int, str]] = None
  167. options: Optional[list[ToolCredentialsOption]] = None
  168. label: Optional[I18nObject] = None
  169. help: Optional[I18nObject] = None
  170. url: Optional[str] = None
  171. placeholder: Optional[I18nObject] = None
  172. def to_dict(self) -> dict:
  173. return {
  174. 'name': self.name,
  175. 'type': self.type.value,
  176. 'required': self.required,
  177. 'default': self.default,
  178. 'options': self.options,
  179. 'help': self.help.to_dict() if self.help else None,
  180. 'label': self.label.to_dict(),
  181. 'url': self.url,
  182. 'placeholder': self.placeholder.to_dict() if self.placeholder else None,
  183. }
  184. class ToolRuntimeVariableType(Enum):
  185. TEXT = "text"
  186. IMAGE = "image"
  187. class ToolRuntimeVariable(BaseModel):
  188. type: ToolRuntimeVariableType = Field(..., description="The type of the variable")
  189. name: str = Field(..., description="The name of the variable")
  190. position: int = Field(..., description="The position of the variable")
  191. tool_name: str = Field(..., description="The name of the tool")
  192. class ToolRuntimeTextVariable(ToolRuntimeVariable):
  193. value: str = Field(..., description="The value of the variable")
  194. class ToolRuntimeImageVariable(ToolRuntimeVariable):
  195. value: str = Field(..., description="The path of the image")
  196. class ToolRuntimeVariablePool(BaseModel):
  197. conversation_id: str = Field(..., description="The conversation id")
  198. user_id: str = Field(..., description="The user id")
  199. tenant_id: str = Field(..., description="The tenant id of assistant")
  200. pool: list[ToolRuntimeVariable] = Field(..., description="The pool of variables")
  201. def __init__(self, **data: Any):
  202. pool = data.get('pool', [])
  203. # convert pool into correct type
  204. for index, variable in enumerate(pool):
  205. if variable['type'] == ToolRuntimeVariableType.TEXT.value:
  206. pool[index] = ToolRuntimeTextVariable(**variable)
  207. elif variable['type'] == ToolRuntimeVariableType.IMAGE.value:
  208. pool[index] = ToolRuntimeImageVariable(**variable)
  209. super().__init__(**data)
  210. def dict(self) -> dict:
  211. return {
  212. 'conversation_id': self.conversation_id,
  213. 'user_id': self.user_id,
  214. 'tenant_id': self.tenant_id,
  215. 'pool': [variable.dict() for variable in self.pool],
  216. }
  217. def set_text(self, tool_name: str, name: str, value: str) -> None:
  218. """
  219. set a text variable
  220. """
  221. for variable in self.pool:
  222. if variable.name == name:
  223. if variable.type == ToolRuntimeVariableType.TEXT:
  224. variable = cast(ToolRuntimeTextVariable, variable)
  225. variable.value = value
  226. return
  227. variable = ToolRuntimeTextVariable(
  228. type=ToolRuntimeVariableType.TEXT,
  229. name=name,
  230. position=len(self.pool),
  231. tool_name=tool_name,
  232. value=value,
  233. )
  234. self.pool.append(variable)
  235. def set_file(self, tool_name: str, value: str, name: str = None) -> None:
  236. """
  237. set an image variable
  238. :param tool_name: the name of the tool
  239. :param value: the id of the file
  240. """
  241. # check how many image variables are there
  242. image_variable_count = 0
  243. for variable in self.pool:
  244. if variable.type == ToolRuntimeVariableType.IMAGE:
  245. image_variable_count += 1
  246. if name is None:
  247. name = f"file_{image_variable_count}"
  248. for variable in self.pool:
  249. if variable.name == name:
  250. if variable.type == ToolRuntimeVariableType.IMAGE:
  251. variable = cast(ToolRuntimeImageVariable, variable)
  252. variable.value = value
  253. return
  254. variable = ToolRuntimeImageVariable(
  255. type=ToolRuntimeVariableType.IMAGE,
  256. name=name,
  257. position=len(self.pool),
  258. tool_name=tool_name,
  259. value=value,
  260. )
  261. self.pool.append(variable)
  262. class ModelToolPropertyKey(Enum):
  263. IMAGE_PARAMETER_NAME = "image_parameter_name"
  264. class ModelToolConfiguration(BaseModel):
  265. """
  266. Model tool configuration
  267. """
  268. type: str = Field(..., description="The type of the model tool")
  269. model: str = Field(..., description="The model")
  270. label: I18nObject = Field(..., description="The label of the model tool")
  271. properties: dict[ModelToolPropertyKey, Any] = Field(..., description="The properties of the model tool")
  272. class ModelToolProviderConfiguration(BaseModel):
  273. """
  274. Model tool provider configuration
  275. """
  276. provider: str = Field(..., description="The provider of the model tool")
  277. models: list[ModelToolConfiguration] = Field(..., description="The models of the model tool")
  278. label: I18nObject = Field(..., description="The label of the model tool")