tool_manager.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. import json
  2. import logging
  3. import mimetypes
  4. from collections.abc import Generator
  5. from os import listdir, path
  6. from threading import Lock
  7. from typing import TYPE_CHECKING, Any, Union, cast
  8. from core.plugin.manager.tool import PluginToolManager
  9. from core.tools.__base.tool_runtime import ToolRuntime
  10. from core.tools.plugin_tool.provider import PluginToolProviderController
  11. from core.tools.plugin_tool.tool import PluginTool
  12. if TYPE_CHECKING:
  13. from core.workflow.nodes.tool.entities import ToolEntity
  14. from configs import dify_config
  15. from core.agent.entities import AgentToolEntity
  16. from core.app.entities.app_invoke_entities import InvokeFrom
  17. from core.helper.module_import_helper import load_single_subclass_from_source
  18. from core.helper.position_helper import is_filtered
  19. from core.model_runtime.utils.encoders import jsonable_encoder
  20. from core.tools.__base.tool import Tool
  21. from core.tools.builtin_tool.provider import BuiltinToolProviderController
  22. from core.tools.builtin_tool.providers._positions import BuiltinToolProviderSort
  23. from core.tools.builtin_tool.tool import BuiltinTool
  24. from core.tools.custom_tool.provider import ApiToolProviderController
  25. from core.tools.custom_tool.tool import ApiTool
  26. from core.tools.entities.api_entities import ToolProviderApiEntity, ToolProviderTypeApiLiteral
  27. from core.tools.entities.common_entities import I18nObject
  28. from core.tools.entities.tool_entities import ApiProviderAuthType, ToolInvokeFrom, ToolParameter, ToolProviderType
  29. from core.tools.errors import ToolProviderNotFoundError
  30. from core.tools.tool_label_manager import ToolLabelManager
  31. from core.tools.utils.configuration import ProviderConfigEncrypter, ToolParameterConfigurationManager
  32. from core.tools.utils.tool_parameter_converter import ToolParameterConverter
  33. from core.tools.workflow_as_tool.tool import WorkflowTool
  34. from extensions.ext_database import db
  35. from models.tools import ApiToolProvider, BuiltinToolProvider, WorkflowToolProvider
  36. from services.tools.tools_transform_service import ToolTransformService
  37. logger = logging.getLogger(__name__)
  38. class ToolManager:
  39. _builtin_provider_lock = Lock()
  40. _hardcoded_providers = {}
  41. _builtin_providers_loaded = False
  42. _builtin_tools_labels = {}
  43. @classmethod
  44. def get_builtin_provider(
  45. cls, provider: str, tenant_id: str
  46. ) -> BuiltinToolProviderController | PluginToolProviderController:
  47. """
  48. get the builtin provider
  49. :param provider: the name of the provider
  50. :param tenant_id: the id of the tenant
  51. :return: the provider
  52. """
  53. # split provider to
  54. if len(cls._hardcoded_providers) == 0:
  55. # init the builtin providers
  56. cls.load_hardcoded_providers_cache()
  57. if provider not in cls._hardcoded_providers:
  58. # get plugin provider
  59. plugin_provider = cls.get_plugin_provider(provider, tenant_id)
  60. if plugin_provider:
  61. return plugin_provider
  62. return cls._hardcoded_providers[provider]
  63. @classmethod
  64. def get_plugin_provider(cls, provider: str, tenant_id: str) -> PluginToolProviderController:
  65. """
  66. get the plugin provider
  67. """
  68. manager = PluginToolManager()
  69. provider_entity = manager.fetch_tool_provider(tenant_id, provider)
  70. if not provider_entity:
  71. raise ToolProviderNotFoundError(f"plugin provider {provider} not found")
  72. return PluginToolProviderController(
  73. entity=provider_entity.declaration,
  74. tenant_id=tenant_id,
  75. )
  76. @classmethod
  77. def get_builtin_tool(cls, provider: str, tool_name: str, tenant_id: str) -> BuiltinTool | PluginTool | None:
  78. """
  79. get the builtin tool
  80. :param provider: the name of the provider
  81. :param tool_name: the name of the tool
  82. :param tenant_id: the id of the tenant
  83. :return: the provider, the tool
  84. """
  85. provider_controller = cls.get_builtin_provider(provider, tenant_id)
  86. tool = provider_controller.get_tool(tool_name)
  87. return tool
  88. @classmethod
  89. def get_tool_runtime(
  90. cls,
  91. provider_type: ToolProviderType,
  92. provider_id: str,
  93. tool_name: str,
  94. tenant_id: str,
  95. invoke_from: InvokeFrom = InvokeFrom.DEBUGGER,
  96. tool_invoke_from: ToolInvokeFrom = ToolInvokeFrom.AGENT,
  97. ) -> Union[BuiltinTool, ApiTool, WorkflowTool]:
  98. """
  99. get the tool runtime
  100. :param provider_type: the type of the provider
  101. :param provider_name: the name of the provider
  102. :param tool_name: the name of the tool
  103. :return: the tool
  104. """
  105. if provider_type == ToolProviderType.BUILT_IN:
  106. builtin_tool = cls.get_builtin_tool(provider_id, tool_name, tenant_id)
  107. if not builtin_tool:
  108. raise ValueError(f"tool {tool_name} not found")
  109. # check if the builtin tool need credentials
  110. provider_controller = cls.get_builtin_provider(provider_id, tenant_id)
  111. if not provider_controller.need_credentials:
  112. return cast(
  113. BuiltinTool,
  114. builtin_tool.fork_tool_runtime(
  115. runtime=ToolRuntime(
  116. tenant_id=tenant_id,
  117. credentials={},
  118. invoke_from=invoke_from,
  119. tool_invoke_from=tool_invoke_from,
  120. )
  121. ),
  122. )
  123. # get credentials
  124. builtin_provider: BuiltinToolProvider | None = (
  125. db.session.query(BuiltinToolProvider)
  126. .filter(
  127. BuiltinToolProvider.tenant_id == tenant_id,
  128. BuiltinToolProvider.provider == provider_id,
  129. )
  130. .first()
  131. )
  132. if builtin_provider is None:
  133. raise ToolProviderNotFoundError(f"builtin provider {provider_id} not found")
  134. # decrypt the credentials
  135. credentials = builtin_provider.credentials
  136. tool_configuration = ProviderConfigEncrypter(
  137. tenant_id=tenant_id,
  138. config=provider_controller.get_credentials_schema(),
  139. provider_type=provider_controller.provider_type.value,
  140. provider_identity=provider_controller.entity.identity.name,
  141. )
  142. decrypted_credentials = tool_configuration.decrypt(credentials)
  143. return cast(
  144. BuiltinTool,
  145. builtin_tool.fork_tool_runtime(
  146. runtime=ToolRuntime(
  147. tenant_id=tenant_id,
  148. credentials=decrypted_credentials,
  149. runtime_parameters={},
  150. invoke_from=invoke_from,
  151. tool_invoke_from=tool_invoke_from,
  152. )
  153. ),
  154. )
  155. elif provider_type == ToolProviderType.API:
  156. api_provider, credentials = cls.get_api_provider_controller(tenant_id, provider_id)
  157. # decrypt the credentials
  158. tool_configuration = ProviderConfigEncrypter(
  159. tenant_id=tenant_id,
  160. config=api_provider.get_credentials_schema(),
  161. provider_type=api_provider.provider_type.value,
  162. provider_identity=api_provider.entity.identity.name,
  163. )
  164. decrypted_credentials = tool_configuration.decrypt(credentials)
  165. return cast(
  166. ApiTool,
  167. api_provider.get_tool(tool_name).fork_tool_runtime(
  168. runtime=ToolRuntime(
  169. tenant_id=tenant_id,
  170. credentials=decrypted_credentials,
  171. invoke_from=invoke_from,
  172. tool_invoke_from=tool_invoke_from,
  173. )
  174. ),
  175. )
  176. elif provider_type == ToolProviderType.WORKFLOW:
  177. workflow_provider = (
  178. db.session.query(WorkflowToolProvider)
  179. .filter(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == provider_id)
  180. .first()
  181. )
  182. if workflow_provider is None:
  183. raise ToolProviderNotFoundError(f"workflow provider {provider_id} not found")
  184. controller = ToolTransformService.workflow_provider_to_controller(db_provider=workflow_provider)
  185. return cast(
  186. WorkflowTool,
  187. controller.get_tools(tenant_id=workflow_provider.tenant_id)[0].fork_tool_runtime(
  188. runtime=ToolRuntime(
  189. tenant_id=tenant_id,
  190. credentials={},
  191. invoke_from=invoke_from,
  192. tool_invoke_from=tool_invoke_from,
  193. )
  194. ),
  195. )
  196. elif provider_type == ToolProviderType.APP:
  197. raise NotImplementedError("app provider not implemented")
  198. else:
  199. raise ToolProviderNotFoundError(f"provider type {provider_type.value} not found")
  200. @classmethod
  201. def _init_runtime_parameter(cls, parameter_rule: ToolParameter, parameters: dict) -> Union[str, int, float, bool]:
  202. """
  203. init runtime parameter
  204. """
  205. parameter_value = parameters.get(parameter_rule.name)
  206. if not parameter_value and parameter_value != 0:
  207. # get default value
  208. parameter_value = parameter_rule.default
  209. if not parameter_value and parameter_rule.required:
  210. raise ValueError(f"tool parameter {parameter_rule.name} not found in tool config")
  211. if parameter_rule.type == ToolParameter.ToolParameterType.SELECT:
  212. # check if tool_parameter_config in options
  213. options = [x.value for x in parameter_rule.options]
  214. if parameter_value is not None and parameter_value not in options:
  215. raise ValueError(
  216. f"tool parameter {parameter_rule.name} value {parameter_value} not in options {options}"
  217. )
  218. return ToolParameterConverter.cast_parameter_by_type(parameter_value, parameter_rule.type)
  219. @classmethod
  220. def get_agent_tool_runtime(
  221. cls, tenant_id: str, app_id: str, agent_tool: AgentToolEntity, invoke_from: InvokeFrom = InvokeFrom.DEBUGGER
  222. ) -> Tool:
  223. """
  224. get the agent tool runtime
  225. """
  226. tool_entity = cls.get_tool_runtime(
  227. provider_type=agent_tool.provider_type,
  228. provider_id=agent_tool.provider_id,
  229. tool_name=agent_tool.tool_name,
  230. tenant_id=tenant_id,
  231. invoke_from=invoke_from,
  232. tool_invoke_from=ToolInvokeFrom.AGENT,
  233. )
  234. runtime_parameters = {}
  235. parameters = tool_entity.get_merged_runtime_parameters()
  236. for parameter in parameters:
  237. # check file types
  238. if parameter.type == ToolParameter.ToolParameterType.FILE:
  239. raise ValueError(f"file type parameter {parameter.name} not supported in agent")
  240. if parameter.form == ToolParameter.ToolParameterForm.FORM:
  241. # save tool parameter to tool entity memory
  242. value = cls._init_runtime_parameter(parameter, agent_tool.tool_parameters)
  243. runtime_parameters[parameter.name] = value
  244. # decrypt runtime parameters
  245. encryption_manager = ToolParameterConfigurationManager(
  246. tenant_id=tenant_id,
  247. tool_runtime=tool_entity,
  248. provider_name=agent_tool.provider_id,
  249. provider_type=agent_tool.provider_type,
  250. identity_id=f"AGENT.{app_id}",
  251. )
  252. runtime_parameters = encryption_manager.decrypt_tool_parameters(runtime_parameters)
  253. if not tool_entity.runtime:
  254. raise Exception("tool missing runtime")
  255. tool_entity.runtime.runtime_parameters.update(runtime_parameters)
  256. return tool_entity
  257. @classmethod
  258. def get_workflow_tool_runtime(
  259. cls,
  260. tenant_id: str,
  261. app_id: str,
  262. node_id: str,
  263. workflow_tool: "ToolEntity",
  264. invoke_from: InvokeFrom = InvokeFrom.DEBUGGER,
  265. ) -> Tool:
  266. """
  267. get the workflow tool runtime
  268. """
  269. tool_entity = cls.get_tool_runtime(
  270. provider_type=workflow_tool.provider_type,
  271. provider_id=workflow_tool.provider_id,
  272. tool_name=workflow_tool.tool_name,
  273. tenant_id=tenant_id,
  274. invoke_from=invoke_from,
  275. tool_invoke_from=ToolInvokeFrom.WORKFLOW,
  276. )
  277. runtime_parameters = {}
  278. parameters = tool_entity.get_merged_runtime_parameters()
  279. for parameter in parameters:
  280. # save tool parameter to tool entity memory
  281. if parameter.form == ToolParameter.ToolParameterForm.FORM:
  282. value = cls._init_runtime_parameter(parameter, workflow_tool.tool_configurations)
  283. runtime_parameters[parameter.name] = value
  284. # decrypt runtime parameters
  285. encryption_manager = ToolParameterConfigurationManager(
  286. tenant_id=tenant_id,
  287. tool_runtime=tool_entity,
  288. provider_name=workflow_tool.provider_id,
  289. provider_type=workflow_tool.provider_type,
  290. identity_id=f"WORKFLOW.{app_id}.{node_id}",
  291. )
  292. if runtime_parameters:
  293. runtime_parameters = encryption_manager.decrypt_tool_parameters(runtime_parameters)
  294. if not tool_entity.runtime:
  295. raise Exception("tool missing runtime")
  296. tool_entity.runtime.runtime_parameters.update(runtime_parameters)
  297. return tool_entity
  298. @classmethod
  299. def get_builtin_provider_icon(cls, provider: str, tenant_id: str) -> tuple[str, str]:
  300. """
  301. get the absolute path of the icon of the builtin provider
  302. :param provider: the name of the provider
  303. :param tenant_id: the id of the tenant
  304. :return: the absolute path of the icon, the mime type of the icon
  305. """
  306. # get provider
  307. provider_controller = cls.get_builtin_provider(provider, tenant_id)
  308. absolute_path = path.join(
  309. path.dirname(path.realpath(__file__)),
  310. "builtin_tool",
  311. "providers",
  312. provider,
  313. "_assets",
  314. provider_controller.entity.identity.icon,
  315. )
  316. # check if the icon exists
  317. if not path.exists(absolute_path):
  318. raise ToolProviderNotFoundError(f"builtin provider {provider} icon not found")
  319. # get the mime type
  320. mime_type, _ = mimetypes.guess_type(absolute_path)
  321. mime_type = mime_type or "application/octet-stream"
  322. return absolute_path, mime_type
  323. @classmethod
  324. def list_hardcoded_providers(cls):
  325. # use cache first
  326. if cls._builtin_providers_loaded:
  327. yield from list(cls._hardcoded_providers.values())
  328. return
  329. with cls._builtin_provider_lock:
  330. if cls._builtin_providers_loaded:
  331. yield from list(cls._hardcoded_providers.values())
  332. return
  333. yield from cls._list_hardcoded_providers()
  334. @classmethod
  335. def list_plugin_providers(cls, tenant_id: str) -> list[PluginToolProviderController]:
  336. """
  337. list all the plugin providers
  338. """
  339. manager = PluginToolManager()
  340. provider_entities = manager.fetch_tool_providers(tenant_id)
  341. return [
  342. PluginToolProviderController(
  343. entity=provider.declaration,
  344. tenant_id=tenant_id,
  345. )
  346. for provider in provider_entities
  347. ]
  348. @classmethod
  349. def list_builtin_providers(
  350. cls, tenant_id: str
  351. ) -> Generator[BuiltinToolProviderController | PluginToolProviderController, None, None]:
  352. """
  353. list all the builtin providers
  354. """
  355. yield from cls.list_hardcoded_providers()
  356. # get plugin providers
  357. yield from cls.list_plugin_providers(tenant_id)
  358. @classmethod
  359. def _list_hardcoded_providers(cls) -> Generator[BuiltinToolProviderController, None, None]:
  360. """
  361. list all the builtin providers
  362. """
  363. for provider_path in listdir(path.join(path.dirname(path.realpath(__file__)), "builtin_tool", "providers")):
  364. if provider_path.startswith("__"):
  365. continue
  366. if path.isdir(path.join(path.dirname(path.realpath(__file__)), "builtin_tool", "providers", provider_path)):
  367. if provider_path.startswith("__"):
  368. continue
  369. # init provider
  370. try:
  371. provider_class = load_single_subclass_from_source(
  372. module_name=f"core.tools.builtin_tool.providers.{provider_path}.{provider_path}",
  373. script_path=path.join(
  374. path.dirname(path.realpath(__file__)),
  375. "builtin_tool",
  376. "providers",
  377. provider_path,
  378. f"{provider_path}.py",
  379. ),
  380. parent_type=BuiltinToolProviderController,
  381. )
  382. provider: BuiltinToolProviderController = provider_class()
  383. cls._hardcoded_providers[provider.entity.identity.name] = provider
  384. for tool in provider.get_tools():
  385. cls._builtin_tools_labels[tool.entity.identity.name] = tool.entity.identity.label
  386. yield provider
  387. except Exception as e:
  388. logger.error(f"load builtin provider error: {e}")
  389. continue
  390. # set builtin providers loaded
  391. cls._builtin_providers_loaded = True
  392. @classmethod
  393. def load_hardcoded_providers_cache(cls):
  394. for _ in cls.list_hardcoded_providers():
  395. pass
  396. @classmethod
  397. def clear_hardcoded_providers_cache(cls):
  398. cls._hardcoded_providers = {}
  399. cls._builtin_providers_loaded = False
  400. @classmethod
  401. def get_tool_label(cls, tool_name: str) -> Union[I18nObject, None]:
  402. """
  403. get the tool label
  404. :param tool_name: the name of the tool
  405. :return: the label of the tool
  406. """
  407. if len(cls._builtin_tools_labels) == 0:
  408. # init the builtin providers
  409. cls.load_hardcoded_providers_cache()
  410. if tool_name not in cls._builtin_tools_labels:
  411. return None
  412. return cls._builtin_tools_labels[tool_name]
  413. @classmethod
  414. def list_providers_from_api(
  415. cls, user_id: str, tenant_id: str, typ: ToolProviderTypeApiLiteral
  416. ) -> list[ToolProviderApiEntity]:
  417. result_providers: dict[str, ToolProviderApiEntity] = {}
  418. filters = []
  419. if not typ:
  420. filters.extend(["builtin", "api", "workflow"])
  421. else:
  422. filters.append(typ)
  423. if "builtin" in filters:
  424. # get builtin providers
  425. builtin_providers = cls.list_builtin_providers(tenant_id)
  426. # get db builtin providers
  427. db_builtin_providers: list[BuiltinToolProvider] = (
  428. db.session.query(BuiltinToolProvider).filter(BuiltinToolProvider.tenant_id == tenant_id).all()
  429. )
  430. find_db_builtin_provider = lambda provider: next(
  431. (x for x in db_builtin_providers if x.provider == provider), None
  432. )
  433. # append builtin providers
  434. for provider in builtin_providers:
  435. # handle include, exclude
  436. if is_filtered(
  437. include_set=dify_config.POSITION_TOOL_INCLUDES_SET, # type: ignore
  438. exclude_set=dify_config.POSITION_TOOL_EXCLUDES_SET, # type: ignore
  439. data=provider,
  440. name_func=lambda x: x.identity.name,
  441. ):
  442. continue
  443. user_provider = ToolTransformService.builtin_provider_to_user_provider(
  444. provider_controller=provider,
  445. db_provider=find_db_builtin_provider(provider.entity.identity.name),
  446. decrypt_credentials=False,
  447. )
  448. if isinstance(provider, PluginToolProviderController):
  449. result_providers[f"plugin_provider.{user_provider.name}"] = user_provider
  450. else:
  451. result_providers[f"builtin_provider.{user_provider.name}"] = user_provider
  452. # get db api providers
  453. if "api" in filters:
  454. db_api_providers: list[ApiToolProvider] = (
  455. db.session.query(ApiToolProvider).filter(ApiToolProvider.tenant_id == tenant_id).all()
  456. )
  457. api_provider_controllers = [
  458. {"provider": provider, "controller": ToolTransformService.api_provider_to_controller(provider)}
  459. for provider in db_api_providers
  460. ]
  461. # get labels
  462. labels = ToolLabelManager.get_tools_labels([x["controller"] for x in api_provider_controllers])
  463. for api_provider_controller in api_provider_controllers:
  464. user_provider = ToolTransformService.api_provider_to_user_provider(
  465. provider_controller=api_provider_controller["controller"],
  466. db_provider=api_provider_controller["provider"],
  467. decrypt_credentials=False,
  468. labels=labels.get(api_provider_controller["controller"].provider_id, []),
  469. )
  470. result_providers[f"api_provider.{user_provider.name}"] = user_provider
  471. if "workflow" in filters:
  472. # get workflow providers
  473. workflow_providers: list[WorkflowToolProvider] = (
  474. db.session.query(WorkflowToolProvider).filter(WorkflowToolProvider.tenant_id == tenant_id).all()
  475. )
  476. workflow_provider_controllers = []
  477. for provider in workflow_providers:
  478. try:
  479. workflow_provider_controllers.append(
  480. ToolTransformService.workflow_provider_to_controller(db_provider=provider)
  481. )
  482. except Exception as e:
  483. # app has been deleted
  484. pass
  485. labels = ToolLabelManager.get_tools_labels(workflow_provider_controllers)
  486. for provider_controller in workflow_provider_controllers:
  487. user_provider = ToolTransformService.workflow_provider_to_user_provider(
  488. provider_controller=provider_controller,
  489. labels=labels.get(provider_controller.provider_id, []),
  490. )
  491. result_providers[f"workflow_provider.{user_provider.name}"] = user_provider
  492. return BuiltinToolProviderSort.sort(list(result_providers.values()))
  493. @classmethod
  494. def get_api_provider_controller(
  495. cls, tenant_id: str, provider_id: str
  496. ) -> tuple[ApiToolProviderController, dict[str, Any]]:
  497. """
  498. get the api provider
  499. :param provider_name: the name of the provider
  500. :return: the provider controller, the credentials
  501. """
  502. provider: ApiToolProvider | None = (
  503. db.session.query(ApiToolProvider)
  504. .filter(
  505. ApiToolProvider.id == provider_id,
  506. ApiToolProvider.tenant_id == tenant_id,
  507. )
  508. .first()
  509. )
  510. if provider is None:
  511. raise ToolProviderNotFoundError(f"api provider {provider_id} not found")
  512. controller = ApiToolProviderController.from_db(
  513. provider,
  514. ApiProviderAuthType.API_KEY if provider.credentials["auth_type"] == "api_key" else ApiProviderAuthType.NONE,
  515. )
  516. controller.load_bundled_tools(provider.tools)
  517. return controller, provider.credentials
  518. @classmethod
  519. def user_get_api_provider(cls, provider: str, tenant_id: str) -> dict:
  520. """
  521. get api provider
  522. """
  523. provider_obj: ApiToolProvider | None = (
  524. db.session.query(ApiToolProvider)
  525. .filter(
  526. ApiToolProvider.tenant_id == tenant_id,
  527. ApiToolProvider.name == provider,
  528. )
  529. .first()
  530. )
  531. if provider_obj is None:
  532. raise ValueError(f"you have not added provider {provider}")
  533. try:
  534. credentials = json.loads(provider_obj.credentials_str) or {}
  535. except:
  536. credentials = {}
  537. # package tool provider controller
  538. controller = ApiToolProviderController.from_db(
  539. provider_obj,
  540. ApiProviderAuthType.API_KEY if credentials["auth_type"] == "api_key" else ApiProviderAuthType.NONE,
  541. )
  542. # init tool configuration
  543. tool_configuration = ProviderConfigEncrypter(
  544. tenant_id=tenant_id,
  545. config=controller.get_credentials_schema(),
  546. provider_type=controller.provider_type.value,
  547. provider_identity=controller.entity.identity.name,
  548. )
  549. decrypted_credentials = tool_configuration.decrypt(credentials)
  550. masked_credentials = tool_configuration.mask_tool_credentials(decrypted_credentials)
  551. try:
  552. icon = json.loads(provider_obj.icon)
  553. except:
  554. icon = {"background": "#252525", "content": "\ud83d\ude01"}
  555. # add tool labels
  556. labels = ToolLabelManager.get_tool_labels(controller)
  557. return jsonable_encoder(
  558. {
  559. "schema_type": provider_obj.schema_type,
  560. "schema": provider_obj.schema,
  561. "tools": provider_obj.tools,
  562. "icon": icon,
  563. "description": provider_obj.description,
  564. "credentials": masked_credentials,
  565. "privacy_policy": provider_obj.privacy_policy,
  566. "custom_disclaimer": provider_obj.custom_disclaimer,
  567. "labels": labels,
  568. }
  569. )
  570. @classmethod
  571. def get_tool_icon(cls, tenant_id: str, provider_type: ToolProviderType, provider_id: str) -> Union[str, dict]:
  572. """
  573. get the tool icon
  574. :param tenant_id: the id of the tenant
  575. :param provider_type: the type of the provider
  576. :param provider_id: the id of the provider
  577. :return:
  578. """
  579. provider_type = provider_type
  580. provider_id = provider_id
  581. if provider_type == ToolProviderType.BUILT_IN:
  582. return (
  583. dify_config.CONSOLE_API_URL
  584. + "/console/api/workspaces/current/tool-provider/builtin/"
  585. + provider_id
  586. + "/icon"
  587. )
  588. elif provider_type == ToolProviderType.API:
  589. try:
  590. api_provider: ApiToolProvider | None = (
  591. db.session.query(ApiToolProvider)
  592. .filter(ApiToolProvider.tenant_id == tenant_id, ApiToolProvider.id == provider_id)
  593. .first()
  594. )
  595. if not api_provider:
  596. raise ValueError("api tool not found")
  597. return json.loads(api_provider.icon)
  598. except:
  599. return {"background": "#252525", "content": "\ud83d\ude01"}
  600. elif provider_type == ToolProviderType.WORKFLOW:
  601. workflow_provider: WorkflowToolProvider | None = (
  602. db.session.query(WorkflowToolProvider)
  603. .filter(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == provider_id)
  604. .first()
  605. )
  606. if workflow_provider is None:
  607. raise ToolProviderNotFoundError(f"workflow provider {provider_id} not found")
  608. return json.loads(workflow_provider.icon)
  609. else:
  610. raise ValueError(f"provider type {provider_type} not found")
  611. ToolManager.load_hardcoded_providers_cache()