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.2KB

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