You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

plugin.py 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. from collections.abc import Sequence
  2. from core.plugin.entities.bundle import PluginBundleDependency
  3. from core.plugin.entities.plugin import (
  4. GenericProviderID,
  5. MissingPluginDependency,
  6. PluginDeclaration,
  7. PluginEntity,
  8. PluginInstallation,
  9. PluginInstallationSource,
  10. )
  11. from core.plugin.entities.plugin_daemon import (
  12. PluginInstallTask,
  13. PluginInstallTaskStartResponse,
  14. PluginListResponse,
  15. PluginUploadResponse,
  16. )
  17. from core.plugin.impl.base import BasePluginClient
  18. class PluginInstaller(BasePluginClient):
  19. def fetch_plugin_by_identifier(
  20. self,
  21. tenant_id: str,
  22. identifier: str,
  23. ) -> bool:
  24. return self._request_with_plugin_daemon_response(
  25. "GET",
  26. f"plugin/{tenant_id}/management/fetch/identifier",
  27. bool,
  28. params={"plugin_unique_identifier": identifier},
  29. )
  30. def list_plugins(self, tenant_id: str) -> list[PluginEntity]:
  31. result = self._request_with_plugin_daemon_response(
  32. "GET",
  33. f"plugin/{tenant_id}/management/list",
  34. PluginListResponse,
  35. params={"page": 1, "page_size": 256},
  36. )
  37. return result.list
  38. def list_plugins_with_total(self, tenant_id: str, page: int, page_size: int) -> PluginListResponse:
  39. return self._request_with_plugin_daemon_response(
  40. "GET",
  41. f"plugin/{tenant_id}/management/list",
  42. PluginListResponse,
  43. params={"page": page, "page_size": page_size},
  44. )
  45. def upload_pkg(
  46. self,
  47. tenant_id: str,
  48. pkg: bytes,
  49. verify_signature: bool = False,
  50. ) -> PluginUploadResponse:
  51. """
  52. Upload a plugin package and return the plugin unique identifier.
  53. """
  54. body = {
  55. "dify_pkg": ("dify_pkg", pkg, "application/octet-stream"),
  56. }
  57. data = {
  58. "verify_signature": "true" if verify_signature else "false",
  59. }
  60. return self._request_with_plugin_daemon_response(
  61. "POST",
  62. f"plugin/{tenant_id}/management/install/upload/package",
  63. PluginUploadResponse,
  64. files=body,
  65. data=data,
  66. )
  67. def upload_bundle(
  68. self,
  69. tenant_id: str,
  70. bundle: bytes,
  71. verify_signature: bool = False,
  72. ) -> Sequence[PluginBundleDependency]:
  73. """
  74. Upload a plugin bundle and return the dependencies.
  75. """
  76. return self._request_with_plugin_daemon_response(
  77. "POST",
  78. f"plugin/{tenant_id}/management/install/upload/bundle",
  79. list[PluginBundleDependency],
  80. files={"dify_bundle": ("dify_bundle", bundle, "application/octet-stream")},
  81. data={"verify_signature": "true" if verify_signature else "false"},
  82. )
  83. def install_from_identifiers(
  84. self,
  85. tenant_id: str,
  86. identifiers: Sequence[str],
  87. source: PluginInstallationSource,
  88. metas: list[dict],
  89. ) -> PluginInstallTaskStartResponse:
  90. """
  91. Install a plugin from an identifier.
  92. """
  93. # exception will be raised if the request failed
  94. return self._request_with_plugin_daemon_response(
  95. "POST",
  96. f"plugin/{tenant_id}/management/install/identifiers",
  97. PluginInstallTaskStartResponse,
  98. data={
  99. "plugin_unique_identifiers": identifiers,
  100. "source": source,
  101. "metas": metas,
  102. },
  103. headers={"Content-Type": "application/json"},
  104. )
  105. def fetch_plugin_installation_tasks(self, tenant_id: str, page: int, page_size: int) -> Sequence[PluginInstallTask]:
  106. """
  107. Fetch plugin installation tasks.
  108. """
  109. return self._request_with_plugin_daemon_response(
  110. "GET",
  111. f"plugin/{tenant_id}/management/install/tasks",
  112. list[PluginInstallTask],
  113. params={"page": page, "page_size": page_size},
  114. )
  115. def fetch_plugin_installation_task(self, tenant_id: str, task_id: str) -> PluginInstallTask:
  116. """
  117. Fetch a plugin installation task.
  118. """
  119. return self._request_with_plugin_daemon_response(
  120. "GET",
  121. f"plugin/{tenant_id}/management/install/tasks/{task_id}",
  122. PluginInstallTask,
  123. )
  124. def delete_plugin_installation_task(self, tenant_id: str, task_id: str) -> bool:
  125. """
  126. Delete a plugin installation task.
  127. """
  128. return self._request_with_plugin_daemon_response(
  129. "POST",
  130. f"plugin/{tenant_id}/management/install/tasks/{task_id}/delete",
  131. bool,
  132. )
  133. def delete_all_plugin_installation_task_items(self, tenant_id: str) -> bool:
  134. """
  135. Delete all plugin installation task items.
  136. """
  137. return self._request_with_plugin_daemon_response(
  138. "POST",
  139. f"plugin/{tenant_id}/management/install/tasks/delete_all",
  140. bool,
  141. )
  142. def delete_plugin_installation_task_item(self, tenant_id: str, task_id: str, identifier: str) -> bool:
  143. """
  144. Delete a plugin installation task item.
  145. """
  146. return self._request_with_plugin_daemon_response(
  147. "POST",
  148. f"plugin/{tenant_id}/management/install/tasks/{task_id}/delete/{identifier}",
  149. bool,
  150. )
  151. def fetch_plugin_manifest(self, tenant_id: str, plugin_unique_identifier: str) -> PluginDeclaration:
  152. """
  153. Fetch a plugin manifest.
  154. """
  155. return self._request_with_plugin_daemon_response(
  156. "GET",
  157. f"plugin/{tenant_id}/management/fetch/manifest",
  158. PluginDeclaration,
  159. params={"plugin_unique_identifier": plugin_unique_identifier},
  160. )
  161. def fetch_plugin_installation_by_ids(
  162. self, tenant_id: str, plugin_ids: Sequence[str]
  163. ) -> Sequence[PluginInstallation]:
  164. """
  165. Fetch plugin installations by ids.
  166. """
  167. return self._request_with_plugin_daemon_response(
  168. "POST",
  169. f"plugin/{tenant_id}/management/installation/fetch/batch",
  170. list[PluginInstallation],
  171. data={"plugin_ids": plugin_ids},
  172. headers={"Content-Type": "application/json"},
  173. )
  174. def fetch_missing_dependencies(
  175. self, tenant_id: str, plugin_unique_identifiers: list[str]
  176. ) -> list[MissingPluginDependency]:
  177. """
  178. Fetch missing dependencies
  179. """
  180. return self._request_with_plugin_daemon_response(
  181. "POST",
  182. f"plugin/{tenant_id}/management/installation/missing",
  183. list[MissingPluginDependency],
  184. data={"plugin_unique_identifiers": plugin_unique_identifiers},
  185. headers={"Content-Type": "application/json"},
  186. )
  187. def uninstall(self, tenant_id: str, plugin_installation_id: str) -> bool:
  188. """
  189. Uninstall a plugin.
  190. """
  191. return self._request_with_plugin_daemon_response(
  192. "POST",
  193. f"plugin/{tenant_id}/management/uninstall",
  194. bool,
  195. data={
  196. "plugin_installation_id": plugin_installation_id,
  197. },
  198. headers={"Content-Type": "application/json"},
  199. )
  200. def upgrade_plugin(
  201. self,
  202. tenant_id: str,
  203. original_plugin_unique_identifier: str,
  204. new_plugin_unique_identifier: str,
  205. source: PluginInstallationSource,
  206. meta: dict,
  207. ) -> PluginInstallTaskStartResponse:
  208. """
  209. Upgrade a plugin.
  210. """
  211. return self._request_with_plugin_daemon_response(
  212. "POST",
  213. f"plugin/{tenant_id}/management/install/upgrade",
  214. PluginInstallTaskStartResponse,
  215. data={
  216. "original_plugin_unique_identifier": original_plugin_unique_identifier,
  217. "new_plugin_unique_identifier": new_plugin_unique_identifier,
  218. "source": source,
  219. "meta": meta,
  220. },
  221. headers={"Content-Type": "application/json"},
  222. )
  223. def check_tools_existence(self, tenant_id: str, provider_ids: Sequence[GenericProviderID]) -> Sequence[bool]:
  224. """
  225. Check if the tools exist
  226. """
  227. return self._request_with_plugin_daemon_response(
  228. "POST",
  229. f"plugin/{tenant_id}/management/tools/check_existence",
  230. list[bool],
  231. data={
  232. "provider_ids": [
  233. {
  234. "plugin_id": provider_id.plugin_id,
  235. "provider_name": provider_id.provider_name,
  236. }
  237. for provider_id in provider_ids
  238. ]
  239. },
  240. headers={"Content-Type": "application/json"},
  241. )