plugin_declaration.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. package plugin_entities
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "regexp"
  6. "time"
  7. "github.com/go-playground/validator/v10"
  8. "github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
  9. "github.com/langgenius/dify-plugin-daemon/pkg/entities/constants"
  10. "github.com/langgenius/dify-plugin-daemon/pkg/entities/manifest_entities"
  11. "github.com/langgenius/dify-plugin-daemon/pkg/validators"
  12. )
  13. type PluginCategory string
  14. const (
  15. PLUGIN_CATEGORY_TOOL PluginCategory = "tool"
  16. PLUGIN_CATEGORY_MODEL PluginCategory = "model"
  17. PLUGIN_CATEGORY_EXTENSION PluginCategory = "extension"
  18. PLUGIN_CATEGORY_AGENT_STRATEGY PluginCategory = "agent-strategy"
  19. )
  20. type PluginPermissionRequirement struct {
  21. Tool *PluginPermissionToolRequirement `json:"tool,omitempty" yaml:"tool,omitempty" validate:"omitempty"`
  22. Model *PluginPermissionModelRequirement `json:"model,omitempty" yaml:"model,omitempty" validate:"omitempty"`
  23. Node *PluginPermissionNodeRequirement `json:"node,omitempty" yaml:"node,omitempty" validate:"omitempty"`
  24. Endpoint *PluginPermissionEndpointRequirement `json:"endpoint,omitempty" yaml:"endpoint,omitempty" validate:"omitempty"`
  25. App *PluginPermissionAppRequirement `json:"app,omitempty" yaml:"app,omitempty" validate:"omitempty"`
  26. Storage *PluginPermissionStorageRequirement `json:"storage,omitempty" yaml:"storage,omitempty" validate:"omitempty"`
  27. }
  28. func (p *PluginPermissionRequirement) AllowInvokeTool() bool {
  29. return p != nil && p.Tool != nil && p.Tool.Enabled
  30. }
  31. func (p *PluginPermissionRequirement) AllowInvokeModel() bool {
  32. return p != nil && p.Model != nil && p.Model.Enabled
  33. }
  34. func (p *PluginPermissionRequirement) AllowInvokeLLM() bool {
  35. return p != nil && p.Model != nil && p.Model.Enabled && p.Model.LLM
  36. }
  37. func (p *PluginPermissionRequirement) AllowInvokeTextEmbedding() bool {
  38. return p != nil && p.Model != nil && p.Model.Enabled && p.Model.TextEmbedding
  39. }
  40. func (p *PluginPermissionRequirement) AllowInvokeRerank() bool {
  41. return p != nil && p.Model != nil && p.Model.Enabled && p.Model.Rerank
  42. }
  43. func (p *PluginPermissionRequirement) AllowInvokeTTS() bool {
  44. return p != nil && p.Model != nil && p.Model.Enabled && p.Model.TTS
  45. }
  46. func (p *PluginPermissionRequirement) AllowInvokeSpeech2Text() bool {
  47. return p != nil && p.Model != nil && p.Model.Enabled && p.Model.Speech2text
  48. }
  49. func (p *PluginPermissionRequirement) AllowInvokeModeration() bool {
  50. return p != nil && p.Model != nil && p.Model.Enabled && p.Model.Moderation
  51. }
  52. func (p *PluginPermissionRequirement) AllowInvokeNode() bool {
  53. return p != nil && p.Node != nil && p.Node.Enabled
  54. }
  55. func (p *PluginPermissionRequirement) AllowInvokeApp() bool {
  56. return p != nil && p.App != nil && p.App.Enabled
  57. }
  58. func (p *PluginPermissionRequirement) AllowRegisterEndpoint() bool {
  59. return p != nil && p.Endpoint != nil && p.Endpoint.Enabled
  60. }
  61. func (p *PluginPermissionRequirement) AllowInvokeStorage() bool {
  62. return p != nil && p.Storage != nil && p.Storage.Enabled
  63. }
  64. type PluginPermissionToolRequirement struct {
  65. Enabled bool `json:"enabled" yaml:"enabled"`
  66. }
  67. type PluginPermissionModelRequirement struct {
  68. Enabled bool `json:"enabled" yaml:"enabled"`
  69. LLM bool `json:"llm" yaml:"llm"`
  70. TextEmbedding bool `json:"text_embedding" yaml:"text_embedding"`
  71. Rerank bool `json:"rerank" yaml:"rerank"`
  72. TTS bool `json:"tts" yaml:"tts"`
  73. Speech2text bool `json:"speech2text" yaml:"speech2text"`
  74. Moderation bool `json:"moderation" yaml:"moderation"`
  75. }
  76. type PluginPermissionNodeRequirement struct {
  77. Enabled bool `json:"enabled" yaml:"enabled"`
  78. }
  79. type PluginPermissionEndpointRequirement struct {
  80. Enabled bool `json:"enabled" yaml:"enabled"`
  81. }
  82. type PluginPermissionAppRequirement struct {
  83. Enabled bool `json:"enabled" yaml:"enabled"`
  84. }
  85. type PluginPermissionStorageRequirement struct {
  86. Enabled bool `json:"enabled" yaml:"enabled"`
  87. Size uint64 `json:"size" yaml:"size" validate:"min=1024,max=1073741824"` // min 1024 bytes, max 1G
  88. }
  89. type PluginResourceRequirement struct {
  90. // Memory in bytes
  91. Memory int64 `json:"memory" yaml:"memory" validate:"required"`
  92. // Permission requirements
  93. Permission *PluginPermissionRequirement `json:"permission,omitempty" yaml:"permission,omitempty" validate:"omitempty"`
  94. }
  95. type PluginDeclarationPlatformArch string
  96. type PluginRunner struct {
  97. Language constants.Language `json:"language" yaml:"language" validate:"required,is_available_language"`
  98. Version string `json:"version" yaml:"version" validate:"required,max=128"`
  99. Entrypoint string `json:"entrypoint" yaml:"entrypoint" validate:"required,max=256"`
  100. }
  101. type PluginMeta struct {
  102. Version string `json:"version" yaml:"version" validate:"required,version"`
  103. Arch []constants.Arch `json:"arch" yaml:"arch" validate:"required,dive,is_available_arch"`
  104. Runner PluginRunner `json:"runner" yaml:"runner" validate:"required"`
  105. }
  106. type PluginExtensions struct {
  107. Tools []string `json:"tools" yaml:"tools,omitempty" validate:"omitempty,dive,max=128"`
  108. Models []string `json:"models" yaml:"models,omitempty" validate:"omitempty,dive,max=128"`
  109. Endpoints []string `json:"endpoints" yaml:"endpoints,omitempty" validate:"omitempty,dive,max=128"`
  110. AgentStrategies []string `json:"agent_strategies" yaml:"agent_strategies,omitempty" validate:"omitempty,dive,max=128"`
  111. }
  112. type PluginDeclarationWithoutAdvancedFields struct {
  113. Version manifest_entities.Version `json:"version" yaml:"version,omitempty" validate:"required,version"`
  114. Type manifest_entities.DifyManifestType `json:"type" yaml:"type,omitempty" validate:"required,eq=plugin"`
  115. Author string `json:"author" yaml:"author,omitempty" validate:"omitempty,max=64"`
  116. Name string `json:"name" yaml:"name,omitempty" validate:"required,max=128"`
  117. Label I18nObject `json:"label" yaml:"label" validate:"required"`
  118. Description I18nObject `json:"description" yaml:"description" validate:"required"`
  119. Icon string `json:"icon" yaml:"icon,omitempty" validate:"required,max=128"`
  120. Resource PluginResourceRequirement `json:"resource" yaml:"resource,omitempty" validate:"required"`
  121. Plugins PluginExtensions `json:"plugins" yaml:"plugins,omitempty" validate:"required"`
  122. Meta PluginMeta `json:"meta" yaml:"meta,omitempty" validate:"required"`
  123. Tags []manifest_entities.PluginTag `json:"tags" yaml:"tags,omitempty" validate:"omitempty,dive,plugin_tag,max=128"`
  124. CreatedAt time.Time `json:"created_at" yaml:"created_at,omitempty" validate:"required"`
  125. Privacy *string `json:"privacy,omitempty" yaml:"privacy,omitempty" validate:"omitempty"`
  126. }
  127. func (p *PluginDeclarationWithoutAdvancedFields) UnmarshalJSON(data []byte) error {
  128. type Alias PluginDeclarationWithoutAdvancedFields
  129. aux := &struct {
  130. *Alias
  131. }{
  132. Alias: (*Alias)(p),
  133. }
  134. if err := json.Unmarshal(data, aux); err != nil {
  135. return err
  136. }
  137. if p.Tags == nil {
  138. p.Tags = []manifest_entities.PluginTag{}
  139. }
  140. return nil
  141. }
  142. type PluginDeclaration struct {
  143. PluginDeclarationWithoutAdvancedFields `yaml:",inline"`
  144. Verified bool `json:"verified" yaml:"verified"`
  145. Endpoint *EndpointProviderDeclaration `json:"endpoint,omitempty" yaml:"endpoint,omitempty" validate:"omitempty"`
  146. Model *ModelProviderDeclaration `json:"model,omitempty" yaml:"model,omitempty" validate:"omitempty"`
  147. Tool *ToolProviderDeclaration `json:"tool,omitempty" yaml:"tool,omitempty" validate:"omitempty"`
  148. AgentStrategy *AgentStrategyProviderDeclaration `json:"agent_strategy,omitempty" yaml:"agent_strategy,omitempty" validate:"omitempty"`
  149. }
  150. func (p *PluginDeclaration) Category() PluginCategory {
  151. if p.Tool != nil {
  152. return PLUGIN_CATEGORY_TOOL
  153. }
  154. if p.Model != nil {
  155. return PLUGIN_CATEGORY_MODEL
  156. }
  157. if p.AgentStrategy != nil {
  158. return PLUGIN_CATEGORY_AGENT_STRATEGY
  159. }
  160. return PLUGIN_CATEGORY_EXTENSION
  161. }
  162. func (p *PluginDeclaration) UnmarshalJSON(data []byte) error {
  163. // First unmarshal the embedded struct
  164. if err := json.Unmarshal(data, &p.PluginDeclarationWithoutAdvancedFields); err != nil {
  165. return err
  166. }
  167. // Then unmarshal the remaining fields
  168. type PluginExtra struct {
  169. Verified bool `json:"verified"`
  170. Endpoint *EndpointProviderDeclaration `json:"endpoint,omitempty"`
  171. Model *ModelProviderDeclaration `json:"model,omitempty"`
  172. Tool *ToolProviderDeclaration `json:"tool,omitempty"`
  173. AgentStrategy *AgentStrategyProviderDeclaration `json:"agent_strategy,omitempty"`
  174. }
  175. var extra PluginExtra
  176. if err := json.Unmarshal(data, &extra); err != nil {
  177. return err
  178. }
  179. p.Verified = extra.Verified
  180. p.Endpoint = extra.Endpoint
  181. p.Model = extra.Model
  182. p.Tool = extra.Tool
  183. p.AgentStrategy = extra.AgentStrategy
  184. return nil
  185. }
  186. func (p *PluginDeclaration) MarshalJSON() ([]byte, error) {
  187. // TODO: performance issue, need a better way to do this
  188. c := *p
  189. c.FillInDefaultValues()
  190. type alias PluginDeclaration
  191. return json.Marshal(alias(c))
  192. }
  193. var (
  194. PluginNameRegex = regexp.MustCompile(`^[a-z0-9_-]{1,128}$`)
  195. AuthorRegex = regexp.MustCompile(`^[a-z0-9_-]{1,64}$`)
  196. )
  197. func isPluginName(fl validator.FieldLevel) bool {
  198. value := fl.Field().String()
  199. return PluginNameRegex.MatchString(value)
  200. }
  201. func (p *PluginDeclaration) Identity() string {
  202. return parser.MarshalPluginID(p.Author, p.Name, p.Version.String())
  203. }
  204. func (p *PluginDeclaration) ManifestValidate() error {
  205. if p.Endpoint == nil && p.Model == nil && p.Tool == nil && p.AgentStrategy == nil {
  206. return fmt.Errorf("at least one of endpoint, model, tool, or agent_strategy must be provided")
  207. }
  208. if p.Model != nil && p.Tool != nil {
  209. return fmt.Errorf("model and tool cannot be provided at the same time")
  210. }
  211. if p.Model != nil && p.Endpoint != nil {
  212. return fmt.Errorf("model and endpoint cannot be provided at the same time")
  213. }
  214. if p.AgentStrategy != nil {
  215. if p.Tool != nil || p.Model != nil || p.Endpoint != nil {
  216. return fmt.Errorf("agent_strategy and tool, model, or endpoint cannot be provided at the same time")
  217. }
  218. }
  219. return nil
  220. }
  221. func (p *PluginDeclaration) FillInDefaultValues() {
  222. if p.Tool != nil {
  223. if p.Tool.Identity.Description.EnUS == "" {
  224. p.Tool.Identity.Description = p.Description
  225. }
  226. if len(p.Tool.Identity.Tags) == 0 {
  227. p.Tool.Identity.Tags = p.Tags
  228. }
  229. }
  230. if p.Model != nil {
  231. if p.Model.Description == nil {
  232. deepCopiedDescription := p.Description
  233. p.Model.Description = &deepCopiedDescription
  234. }
  235. }
  236. if p.Tags == nil {
  237. p.Tags = []manifest_entities.PluginTag{}
  238. }
  239. }
  240. func init() {
  241. // init validator
  242. validators.GlobalEntitiesValidator.RegisterValidation("plugin_name", isPluginName)
  243. }
  244. func UnmarshalPluginDeclarationFromYaml(data []byte) (*PluginDeclaration, error) {
  245. obj, err := parser.UnmarshalYamlBytes[PluginDeclaration](data)
  246. if err != nil {
  247. return nil, err
  248. }
  249. if err := validators.GlobalEntitiesValidator.Struct(obj); err != nil {
  250. return nil, err
  251. }
  252. obj.FillInDefaultValues()
  253. return &obj, nil
  254. }
  255. func UnmarshalPluginDeclarationFromJSON(data []byte) (*PluginDeclaration, error) {
  256. obj, err := parser.UnmarshalJsonBytes[PluginDeclaration](data)
  257. if err != nil {
  258. return nil, err
  259. }
  260. if err := validators.GlobalEntitiesValidator.Struct(obj); err != nil {
  261. return nil, err
  262. }
  263. obj.FillInDefaultValues()
  264. return &obj, nil
  265. }