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 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. import datetime
  2. from collections.abc import Mapping
  3. from enum import StrEnum, auto
  4. from typing import Any
  5. from packaging.version import InvalidVersion, Version
  6. from pydantic import BaseModel, Field, field_validator, model_validator
  7. from core.agent.plugin_entities import AgentStrategyProviderEntity
  8. from core.datasource.entities.datasource_entities import DatasourceProviderEntity
  9. from core.model_runtime.entities.provider_entities import ProviderEntity
  10. from core.plugin.entities.base import BasePluginEntity
  11. from core.plugin.entities.endpoint import EndpointProviderDeclaration
  12. from core.tools.entities.common_entities import I18nObject
  13. from core.tools.entities.tool_entities import ToolProviderEntity
  14. class PluginInstallationSource(StrEnum):
  15. Github = auto()
  16. Marketplace = auto()
  17. Package = auto()
  18. Remote = auto()
  19. class PluginResourceRequirements(BaseModel):
  20. memory: int
  21. class Permission(BaseModel):
  22. class Tool(BaseModel):
  23. enabled: bool | None = Field(default=False)
  24. class Model(BaseModel):
  25. enabled: bool | None = Field(default=False)
  26. llm: bool | None = Field(default=False)
  27. text_embedding: bool | None = Field(default=False)
  28. rerank: bool | None = Field(default=False)
  29. tts: bool | None = Field(default=False)
  30. speech2text: bool | None = Field(default=False)
  31. moderation: bool | None = Field(default=False)
  32. class Node(BaseModel):
  33. enabled: bool | None = Field(default=False)
  34. class Endpoint(BaseModel):
  35. enabled: bool | None = Field(default=False)
  36. class Storage(BaseModel):
  37. enabled: bool | None = Field(default=False)
  38. size: int = Field(ge=1024, le=1073741824, default=1048576)
  39. tool: Tool | None = Field(default=None)
  40. model: Model | None = Field(default=None)
  41. node: Node | None = Field(default=None)
  42. endpoint: Endpoint | None = Field(default=None)
  43. storage: Storage | None = Field(default=None)
  44. permission: Permission | None = Field(default=None)
  45. class PluginCategory(StrEnum):
  46. Tool = auto()
  47. Model = auto()
  48. Extension = auto()
  49. AgentStrategy = "agent-strategy"
  50. Datasource = "datasource"
  51. class PluginDeclaration(BaseModel):
  52. class Plugins(BaseModel):
  53. tools: list[str] | None = Field(default_factory=list[str])
  54. models: list[str] | None = Field(default_factory=list[str])
  55. endpoints: list[str] | None = Field(default_factory=list[str])
  56. datasources: list[str] | None = Field(default_factory=list[str])
  57. class Meta(BaseModel):
  58. minimum_dify_version: str | None = Field(default=None)
  59. version: str | None = Field(default=None)
  60. @field_validator("minimum_dify_version")
  61. @classmethod
  62. def validate_minimum_dify_version(cls, v: str | None) -> str | None:
  63. if v is None:
  64. return v
  65. try:
  66. Version(v)
  67. return v
  68. except InvalidVersion as e:
  69. raise ValueError(f"Invalid version format: {v}") from e
  70. version: str = Field(...)
  71. author: str | None = Field(..., pattern=r"^[a-zA-Z0-9_-]{1,64}$")
  72. name: str = Field(..., pattern=r"^[a-z0-9_-]{1,128}$")
  73. description: I18nObject
  74. icon: str
  75. icon_dark: str | None = Field(default=None)
  76. label: I18nObject
  77. category: PluginCategory
  78. created_at: datetime.datetime
  79. resource: PluginResourceRequirements
  80. plugins: Plugins
  81. tags: list[str] = Field(default_factory=list)
  82. repo: str | None = Field(default=None)
  83. verified: bool = Field(default=False)
  84. tool: ToolProviderEntity | None = None
  85. model: ProviderEntity | None = None
  86. endpoint: EndpointProviderDeclaration | None = None
  87. agent_strategy: AgentStrategyProviderEntity | None = None
  88. datasource: DatasourceProviderEntity | None = None
  89. meta: Meta
  90. @field_validator("version")
  91. @classmethod
  92. def validate_version(cls, v: str) -> str:
  93. try:
  94. Version(v)
  95. return v
  96. except InvalidVersion as e:
  97. raise ValueError(f"Invalid version format: {v}") from e
  98. @model_validator(mode="before")
  99. @classmethod
  100. def validate_category(cls, values: dict):
  101. # auto detect category
  102. if values.get("tool"):
  103. values["category"] = PluginCategory.Tool
  104. elif values.get("model"):
  105. values["category"] = PluginCategory.Model
  106. elif values.get("datasource"):
  107. values["category"] = PluginCategory.Datasource
  108. elif values.get("agent_strategy"):
  109. values["category"] = PluginCategory.AgentStrategy
  110. else:
  111. values["category"] = PluginCategory.Extension
  112. return values
  113. class PluginInstallation(BasePluginEntity):
  114. tenant_id: str
  115. endpoints_setups: int
  116. endpoints_active: int
  117. runtime_type: str
  118. source: PluginInstallationSource
  119. meta: Mapping[str, Any]
  120. plugin_id: str
  121. plugin_unique_identifier: str
  122. version: str
  123. checksum: str
  124. declaration: PluginDeclaration
  125. class PluginEntity(PluginInstallation):
  126. name: str
  127. installation_id: str
  128. version: str
  129. @model_validator(mode="after")
  130. def set_plugin_id(self):
  131. if self.declaration.tool:
  132. self.declaration.tool.plugin_id = self.plugin_id
  133. return self
  134. class PluginDependency(BaseModel):
  135. class Type(StrEnum):
  136. Github = PluginInstallationSource.Github
  137. Marketplace = PluginInstallationSource.Marketplace
  138. Package = PluginInstallationSource.Package
  139. class Github(BaseModel):
  140. repo: str
  141. version: str
  142. package: str
  143. github_plugin_unique_identifier: str
  144. @property
  145. def plugin_unique_identifier(self) -> str:
  146. return self.github_plugin_unique_identifier
  147. class Marketplace(BaseModel):
  148. marketplace_plugin_unique_identifier: str
  149. version: str | None = None
  150. @property
  151. def plugin_unique_identifier(self) -> str:
  152. return self.marketplace_plugin_unique_identifier
  153. class Package(BaseModel):
  154. plugin_unique_identifier: str
  155. version: str | None = None
  156. type: Type
  157. value: Github | Marketplace | Package
  158. current_identifier: str | None = None
  159. class MissingPluginDependency(BaseModel):
  160. plugin_unique_identifier: str
  161. current_identifier: str | None = None