123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- package plugin_entities
- import (
- "encoding/json"
- "fmt"
- "regexp"
- "time"
- "github.com/go-playground/validator/v10"
- "github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
- "github.com/langgenius/dify-plugin-daemon/pkg/entities/constants"
- "github.com/langgenius/dify-plugin-daemon/pkg/entities/manifest_entities"
- "github.com/langgenius/dify-plugin-daemon/pkg/validators"
- )
- type PluginCategory string
- const (
- PLUGIN_CATEGORY_TOOL PluginCategory = "tool"
- PLUGIN_CATEGORY_MODEL PluginCategory = "model"
- PLUGIN_CATEGORY_EXTENSION PluginCategory = "extension"
- PLUGIN_CATEGORY_AGENT_STRATEGY PluginCategory = "agent-strategy"
- )
- type PluginPermissionRequirement struct {
- Tool *PluginPermissionToolRequirement `json:"tool,omitempty" yaml:"tool,omitempty" validate:"omitempty"`
- Model *PluginPermissionModelRequirement `json:"model,omitempty" yaml:"model,omitempty" validate:"omitempty"`
- Node *PluginPermissionNodeRequirement `json:"node,omitempty" yaml:"node,omitempty" validate:"omitempty"`
- Endpoint *PluginPermissionEndpointRequirement `json:"endpoint,omitempty" yaml:"endpoint,omitempty" validate:"omitempty"`
- App *PluginPermissionAppRequirement `json:"app,omitempty" yaml:"app,omitempty" validate:"omitempty"`
- Storage *PluginPermissionStorageRequirement `json:"storage,omitempty" yaml:"storage,omitempty" validate:"omitempty"`
- }
- func (p *PluginPermissionRequirement) AllowInvokeTool() bool {
- return p != nil && p.Tool != nil && p.Tool.Enabled
- }
- func (p *PluginPermissionRequirement) AllowInvokeModel() bool {
- return p != nil && p.Model != nil && p.Model.Enabled
- }
- func (p *PluginPermissionRequirement) AllowInvokeLLM() bool {
- return p != nil && p.Model != nil && p.Model.Enabled && p.Model.LLM
- }
- func (p *PluginPermissionRequirement) AllowInvokeTextEmbedding() bool {
- return p != nil && p.Model != nil && p.Model.Enabled && p.Model.TextEmbedding
- }
- func (p *PluginPermissionRequirement) AllowInvokeRerank() bool {
- return p != nil && p.Model != nil && p.Model.Enabled && p.Model.Rerank
- }
- func (p *PluginPermissionRequirement) AllowInvokeTTS() bool {
- return p != nil && p.Model != nil && p.Model.Enabled && p.Model.TTS
- }
- func (p *PluginPermissionRequirement) AllowInvokeSpeech2Text() bool {
- return p != nil && p.Model != nil && p.Model.Enabled && p.Model.Speech2text
- }
- func (p *PluginPermissionRequirement) AllowInvokeModeration() bool {
- return p != nil && p.Model != nil && p.Model.Enabled && p.Model.Moderation
- }
- func (p *PluginPermissionRequirement) AllowInvokeNode() bool {
- return p != nil && p.Node != nil && p.Node.Enabled
- }
- func (p *PluginPermissionRequirement) AllowInvokeApp() bool {
- return p != nil && p.App != nil && p.App.Enabled
- }
- func (p *PluginPermissionRequirement) AllowRegisterEndpoint() bool {
- return p != nil && p.Endpoint != nil && p.Endpoint.Enabled
- }
- func (p *PluginPermissionRequirement) AllowInvokeStorage() bool {
- return p != nil && p.Storage != nil && p.Storage.Enabled
- }
- type PluginPermissionToolRequirement struct {
- Enabled bool `json:"enabled" yaml:"enabled"`
- }
- type PluginPermissionModelRequirement struct {
- Enabled bool `json:"enabled" yaml:"enabled"`
- LLM bool `json:"llm" yaml:"llm"`
- TextEmbedding bool `json:"text_embedding" yaml:"text_embedding"`
- Rerank bool `json:"rerank" yaml:"rerank"`
- TTS bool `json:"tts" yaml:"tts"`
- Speech2text bool `json:"speech2text" yaml:"speech2text"`
- Moderation bool `json:"moderation" yaml:"moderation"`
- }
- type PluginPermissionNodeRequirement struct {
- Enabled bool `json:"enabled" yaml:"enabled"`
- }
- type PluginPermissionEndpointRequirement struct {
- Enabled bool `json:"enabled" yaml:"enabled"`
- }
- type PluginPermissionAppRequirement struct {
- Enabled bool `json:"enabled" yaml:"enabled"`
- }
- type PluginPermissionStorageRequirement struct {
- Enabled bool `json:"enabled" yaml:"enabled"`
- Size uint64 `json:"size" yaml:"size" validate:"min=1024,max=1073741824"` // min 1024 bytes, max 1G
- }
- type PluginResourceRequirement struct {
- // Memory in bytes
- Memory int64 `json:"memory" yaml:"memory" validate:"required"`
- // Permission requirements
- Permission *PluginPermissionRequirement `json:"permission,omitempty" yaml:"permission,omitempty" validate:"omitempty"`
- }
- type PluginDeclarationPlatformArch string
- type PluginRunner struct {
- Language constants.Language `json:"language" yaml:"language" validate:"required,is_available_language"`
- Version string `json:"version" yaml:"version" validate:"required,max=128"`
- Entrypoint string `json:"entrypoint" yaml:"entrypoint" validate:"required,max=256"`
- }
- type PluginMeta struct {
- Version string `json:"version" yaml:"version" validate:"required,version"`
- Arch []constants.Arch `json:"arch" yaml:"arch" validate:"required,dive,is_available_arch"`
- Runner PluginRunner `json:"runner" yaml:"runner" validate:"required"`
- }
- type PluginExtensions struct {
- Tools []string `json:"tools" yaml:"tools,omitempty" validate:"omitempty,dive,max=128"`
- Models []string `json:"models" yaml:"models,omitempty" validate:"omitempty,dive,max=128"`
- Endpoints []string `json:"endpoints" yaml:"endpoints,omitempty" validate:"omitempty,dive,max=128"`
- AgentStrategies []string `json:"agent_strategies" yaml:"agent_strategies,omitempty" validate:"omitempty,dive,max=128"`
- }
- type PluginDeclarationWithoutAdvancedFields struct {
- Version manifest_entities.Version `json:"version" yaml:"version,omitempty" validate:"required,version"`
- Type manifest_entities.DifyManifestType `json:"type" yaml:"type,omitempty" validate:"required,eq=plugin"`
- Author string `json:"author" yaml:"author,omitempty" validate:"omitempty,max=64"`
- Name string `json:"name" yaml:"name,omitempty" validate:"required,max=128"`
- Label I18nObject `json:"label" yaml:"label" validate:"required"`
- Description I18nObject `json:"description" yaml:"description" validate:"required"`
- Icon string `json:"icon" yaml:"icon,omitempty" validate:"required,max=128"`
- Resource PluginResourceRequirement `json:"resource" yaml:"resource,omitempty" validate:"required"`
- Plugins PluginExtensions `json:"plugins" yaml:"plugins,omitempty" validate:"required"`
- Meta PluginMeta `json:"meta" yaml:"meta,omitempty" validate:"required"`
- Tags []manifest_entities.PluginTag `json:"tags" yaml:"tags,omitempty" validate:"omitempty,dive,plugin_tag,max=128"`
- CreatedAt time.Time `json:"created_at" yaml:"created_at,omitempty" validate:"required"`
- Privacy *string `json:"privacy,omitempty" yaml:"privacy,omitempty" validate:"omitempty"`
- }
- func (p *PluginDeclarationWithoutAdvancedFields) UnmarshalJSON(data []byte) error {
- type Alias PluginDeclarationWithoutAdvancedFields
- aux := &struct {
- *Alias
- }{
- Alias: (*Alias)(p),
- }
- if err := json.Unmarshal(data, aux); err != nil {
- return err
- }
- if p.Tags == nil {
- p.Tags = []manifest_entities.PluginTag{}
- }
- return nil
- }
- type PluginDeclaration struct {
- PluginDeclarationWithoutAdvancedFields `yaml:",inline"`
- Verified bool `json:"verified" yaml:"verified"`
- Endpoint *EndpointProviderDeclaration `json:"endpoint,omitempty" yaml:"endpoint,omitempty" validate:"omitempty"`
- Model *ModelProviderDeclaration `json:"model,omitempty" yaml:"model,omitempty" validate:"omitempty"`
- Tool *ToolProviderDeclaration `json:"tool,omitempty" yaml:"tool,omitempty" validate:"omitempty"`
- AgentStrategy *AgentStrategyProviderDeclaration `json:"agent_strategy,omitempty" yaml:"agent_strategy,omitempty" validate:"omitempty"`
- }
- func (p *PluginDeclaration) Category() PluginCategory {
- if p.Tool != nil {
- return PLUGIN_CATEGORY_TOOL
- }
- if p.Model != nil {
- return PLUGIN_CATEGORY_MODEL
- }
- if p.AgentStrategy != nil {
- return PLUGIN_CATEGORY_AGENT_STRATEGY
- }
- return PLUGIN_CATEGORY_EXTENSION
- }
- func (p *PluginDeclaration) UnmarshalJSON(data []byte) error {
- // First unmarshal the embedded struct
- if err := json.Unmarshal(data, &p.PluginDeclarationWithoutAdvancedFields); err != nil {
- return err
- }
- // Then unmarshal the remaining fields
- type PluginExtra struct {
- Verified bool `json:"verified"`
- Endpoint *EndpointProviderDeclaration `json:"endpoint,omitempty"`
- Model *ModelProviderDeclaration `json:"model,omitempty"`
- Tool *ToolProviderDeclaration `json:"tool,omitempty"`
- AgentStrategy *AgentStrategyProviderDeclaration `json:"agent_strategy,omitempty"`
- }
- var extra PluginExtra
- if err := json.Unmarshal(data, &extra); err != nil {
- return err
- }
- p.Verified = extra.Verified
- p.Endpoint = extra.Endpoint
- p.Model = extra.Model
- p.Tool = extra.Tool
- p.AgentStrategy = extra.AgentStrategy
- return nil
- }
- func (p *PluginDeclaration) MarshalJSON() ([]byte, error) {
- // TODO: performance issue, need a better way to do this
- c := *p
- c.FillInDefaultValues()
- type alias PluginDeclaration
- return json.Marshal(alias(c))
- }
- var (
- PluginNameRegex = regexp.MustCompile(`^[a-z0-9_-]{1,128}$`)
- AuthorRegex = regexp.MustCompile(`^[a-z0-9_-]{1,64}$`)
- )
- func isPluginName(fl validator.FieldLevel) bool {
- value := fl.Field().String()
- return PluginNameRegex.MatchString(value)
- }
- func (p *PluginDeclaration) Identity() string {
- return parser.MarshalPluginID(p.Author, p.Name, p.Version.String())
- }
- func (p *PluginDeclaration) ManifestValidate() error {
- if p.Endpoint == nil && p.Model == nil && p.Tool == nil && p.AgentStrategy == nil {
- return fmt.Errorf("at least one of endpoint, model, tool, or agent_strategy must be provided")
- }
- if p.Model != nil && p.Tool != nil {
- return fmt.Errorf("model and tool cannot be provided at the same time")
- }
- if p.Model != nil && p.Endpoint != nil {
- return fmt.Errorf("model and endpoint cannot be provided at the same time")
- }
- if p.AgentStrategy != nil {
- if p.Tool != nil || p.Model != nil || p.Endpoint != nil {
- return fmt.Errorf("agent_strategy and tool, model, or endpoint cannot be provided at the same time")
- }
- }
- return nil
- }
- func (p *PluginDeclaration) FillInDefaultValues() {
- if p.Tool != nil {
- if p.Tool.Identity.Description.EnUS == "" {
- p.Tool.Identity.Description = p.Description
- }
- if len(p.Tool.Identity.Tags) == 0 {
- p.Tool.Identity.Tags = p.Tags
- }
- }
- if p.Model != nil {
- if p.Model.Description == nil {
- deepCopiedDescription := p.Description
- p.Model.Description = &deepCopiedDescription
- }
- }
- if p.Tags == nil {
- p.Tags = []manifest_entities.PluginTag{}
- }
- }
- func init() {
- // init validator
- validators.GlobalEntitiesValidator.RegisterValidation("plugin_name", isPluginName)
- }
- func UnmarshalPluginDeclarationFromYaml(data []byte) (*PluginDeclaration, error) {
- obj, err := parser.UnmarshalYamlBytes[PluginDeclaration](data)
- if err != nil {
- return nil, err
- }
- if err := validators.GlobalEntitiesValidator.Struct(obj); err != nil {
- return nil, err
- }
- obj.FillInDefaultValues()
- return &obj, nil
- }
- func UnmarshalPluginDeclarationFromJSON(data []byte) (*PluginDeclaration, error) {
- obj, err := parser.UnmarshalJsonBytes[PluginDeclaration](data)
- if err != nil {
- return nil, err
- }
- if err := validators.GlobalEntitiesValidator.Struct(obj); err != nil {
- return nil, err
- }
- obj.FillInDefaultValues()
- return &obj, nil
- }
|