Ver código fonte

feat: validate plugin

Yeuoly 1 ano atrás
pai
commit
f0122a585d

+ 13 - 12
go.mod

@@ -2,12 +2,14 @@ module github.com/langgenius/dify-plugin-daemon
 
 go 1.20
 
-require github.com/google/uuid v1.6.0
+require (
+	github.com/google/uuid v1.6.0
+	github.com/redis/go-redis/v9 v9.5.3
+)
 
 require (
 	github.com/cespare/xxhash/v2 v2.2.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
-	github.com/redis/go-redis/v9 v9.5.3 // indirect
 )
 
 require (
@@ -18,27 +20,26 @@ require (
 	github.com/gabriel-vasile/mimetype v1.4.4 // indirect
 	github.com/gammazero/deque v0.2.1
 	github.com/gin-contrib/sse v0.1.0 // indirect
-	github.com/gin-gonic/gin v1.10.0 // indirect
-	github.com/go-playground/locales v0.14.1 // indirect
-	github.com/go-playground/universal-translator v0.18.1 // indirect
-	github.com/go-playground/validator/v10 v10.22.0 // indirect
+	github.com/gin-gonic/gin v1.10.0
+	github.com/go-playground/locales v0.14.1
+	github.com/go-playground/universal-translator v0.18.1
+	github.com/go-playground/validator/v10 v10.22.0
 	github.com/goccy/go-json v0.10.3 // indirect
-	github.com/joho/godotenv v1.5.1 // indirect
+	github.com/joho/godotenv v1.5.1
 	github.com/json-iterator/go v1.1.12 // indirect
-	github.com/kelseyhightower/envconfig v1.4.0 // indirect
+	github.com/kelseyhightower/envconfig v1.4.0
 	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/panjf2000/ants v1.3.0 // indirect
-	github.com/panjf2000/gnet/v2 v2.5.5 // indirect
+	github.com/panjf2000/ants v1.3.0
+	github.com/panjf2000/gnet/v2 v2.5.5
 	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/shopspring/decimal v1.4.0
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
 	golang.org/x/arch v0.8.0 // indirect
@@ -50,5 +51,5 @@ require (
 	golang.org/x/text v0.16.0 // indirect
 	google.golang.org/protobuf v1.34.2 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
-	gopkg.in/yaml.v3 v3.0.1 // indirect
+	gopkg.in/yaml.v3 v3.0.1
 )

+ 10 - 2
go.sum

@@ -1,3 +1,5 @@
+github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
+github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
 github.com/bytedance/sonic v1.11.9 h1:LFHENlIY/SLzDWverzdOvgMztTxcfcF+cqNsz9pK5zg=
 github.com/bytedance/sonic v1.11.9/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
 github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
@@ -9,6 +11,7 @@ github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJ
 github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
 github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
@@ -20,6 +23,7 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
 github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
 github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
 github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
+github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
 github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
@@ -28,6 +32,7 @@ github.com/go-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4
 github.com/go-playground/validator/v10 v10.22.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
 github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
 github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -52,10 +57,12 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/panjf2000/ants v1.3.0 h1:8pQ+8leaLc9lys2viEEr8md0U4RN6uOSUCE9bOYjQ9M=
 github.com/panjf2000/ants v1.3.0/go.mod h1:AaACblRPzq35m1g3enqYcxspbbiOJJYaxU2wMpm1cXY=
+github.com/panjf2000/ants/v2 v2.10.0 h1:zhRg1pQUtkyRiOFo2Sbqwjp0GfBNo9cUY2/Grpx1p+8=
 github.com/panjf2000/gnet/v2 v2.5.5 h1:H+LqGgCHs2mGJq/4n6YELhMjZ027bNgd5Qb8Wj5nbrM=
 github.com/panjf2000/gnet/v2 v2.5.5/go.mod h1:ppopMJ8VrDbJu8kDsqFQTgNmpMS8Le5CmPxISf+Sauk=
 github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
 github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
 github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
@@ -71,6 +78,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
 github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
 github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
@@ -78,8 +86,7 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
-go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
 go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
 go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -103,6 +110,7 @@ golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=

+ 5 - 4
internal/core/plugin_manager/lifetime_manager.go

@@ -7,6 +7,7 @@ import (
 	"github.com/google/uuid"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/app"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/entities"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/cache"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/log"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
@@ -18,10 +19,10 @@ const (
 )
 
 type PluginLifeTime struct {
-	Identity string                       `json:"identity"`
-	Restarts int                          `json:"restarts"`
-	Status   string                       `json:"status"`
-	Config   entities.PluginConfiguration `json:"configuration"`
+	Identity string                            `json:"identity"`
+	Restarts int                               `json:"restarts"`
+	Status   string                            `json:"status"`
+	Config   plugin_entities.PluginDeclaration `json:"configuration"`
 }
 
 type pluginLifeCollection struct {

+ 6 - 10
internal/core/plugin_manager/watcher.go

@@ -9,8 +9,8 @@ import (
 	"github.com/langgenius/dify-plugin-daemon/internal/core/plugin_manager/local_manager"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/app"
 	"github.com/langgenius/dify-plugin-daemon/internal/types/entities"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/log"
-	"github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
 	"github.com/langgenius/dify-plugin-daemon/internal/utils/routine"
 )
 
@@ -73,11 +73,6 @@ func loadNewPlugins(root_path string) <-chan entities.PluginRuntime {
 					continue
 				}
 
-				if err := configuration.Validate(); err != nil {
-					log.Error("plugin %s config validate error: %v", configuration.Name, err)
-					continue
-				}
-
 				status := verifyPluginStatus(configuration)
 				if status.exist {
 					continue
@@ -102,25 +97,26 @@ func loadNewPlugins(root_path string) <-chan entities.PluginRuntime {
 	return ch
 }
 
-func parsePluginConfig(configuration_path string) (*entities.PluginConfiguration, error) {
+func parsePluginConfig(configuration_path string) (*plugin_entities.PluginDeclaration, error) {
 	text, err := os.ReadFile(configuration_path)
 	if err != nil {
 		return nil, err
 	}
 
-	result, err := parser.UnmarshalJson[entities.PluginConfiguration](string(text))
+	// TODO: validate
+	result, err := plugin_entities.UnmarshalPluginDeclarationFromYaml(text)
 	if err != nil {
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 type pluginStatusResult struct {
 	exist bool
 }
 
-func verifyPluginStatus(config *entities.PluginConfiguration) pluginStatusResult {
+func verifyPluginStatus(config *plugin_entities.PluginDeclaration) pluginStatusResult {
 	_, exist := checkPluginExist(config.Identity())
 	if exist {
 		return pluginStatusResult{

+ 5 - 0
internal/core/plugin_packager/packager/file_scanner.go

@@ -0,0 +1,5 @@
+package packager
+
+func (p *Packager) ScanProvider() error {
+	return nil
+}

+ 18 - 0
internal/core/plugin_packager/packager/packager.go

@@ -0,0 +1,18 @@
+package packager
+
+type Packager struct {
+	wp string // working path
+
+	manifest string // manifest file path
+}
+
+func NewPackager(plugin_path string) *Packager {
+	return &Packager{
+		wp:       plugin_path,
+		manifest: "manifest.yaml",
+	}
+}
+
+func (p *Packager) Pack() error {
+	return nil
+}

+ 0 - 60
internal/types/entities/config.go

@@ -1,60 +0,0 @@
-package entities
-
-import (
-	"time"
-
-	"github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
-)
-
-type PluginConfiguration struct {
-	Version   string                      `json:"version"`
-	Author    string                      `json:"author"`
-	Name      string                      `json:"name"`
-	CreatedAt time.Time                   `json:"createdAt"`
-	Module    string                      `json:"module"`
-	Resource  PluginConfigurationResource `json:"resource"`
-	Meta      PluginConfigurationMeta     `json:"meta"`
-	Plugins   []string                    `json:"plugins"`
-}
-
-func (p *PluginConfiguration) Identity() string {
-	return parser.MarshalPluginIdentity(p.Name, p.Version)
-}
-
-type PluginConfigurationResource struct {
-	Memory     int64                         `json:"memory"`
-	Storage    int64                         `json:"storage"`
-	Permission PluginConfigurationPermission `json:"permission"`
-}
-
-type PluginConfigurationMeta struct {
-	Version string   `json:"version"`
-	Arch    []string `json:"arch"`
-	Runner  struct {
-		Language string `json:"language"`
-		Version  string `json:"version"`
-	} `json:"runner"`
-}
-
-type PluginExtension struct {
-	Tool  bool `json:"tool"`
-	Model bool `json:"model"`
-}
-
-type PluginConfigurationPermission struct {
-	Model PluginConfigurationPermissionModel `json:"model"`
-	Tool  PluginConfigurationPermissionTool  `json:"tool"`
-}
-
-type PluginConfigurationPermissionModel struct {
-	Enabled       bool `json:"enabled"`
-	LLM           bool `json:"llm"`
-	TextEmbedding bool `json:"text_embedding"`
-	Rerank        bool `json:"rerank"`
-	TTS           bool `json:"tts"`
-	STT           bool `json:"stt"`
-}
-
-type PluginConfigurationPermissionTool struct {
-	Enabled bool `json:"enabled"`
-}

+ 121 - 0
internal/types/entities/plugin_entities/plugin_declaration.go

@@ -0,0 +1,121 @@
+package plugin_entities
+
+import (
+	"time"
+
+	"github.com/go-playground/validator/v10"
+	"github.com/langgenius/dify-plugin-daemon/internal/utils/parser"
+)
+
+type DifyManifestType string
+
+const (
+	PluginType DifyManifestType = "plugin"
+)
+
+type PluginPermissionRequirement struct {
+	Tool  *PluginPermissionToolRequirement  `json:"tool" yaml:"tool" validate:"omitempty"`
+	Model *PluginPermissionModelRequirement `json:"model" yaml:"model" validate:"omitempty"`
+	Node  *PluginPermissionNodeRequirement  `json:"node" yaml:"node" validate:"omitempty"`
+}
+
+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"`
+}
+
+type PluginPermissionNodeRequirement struct {
+	Enabled bool `json:"enabled" yaml:"enabled"`
+}
+
+type PluginResourceRequirement struct {
+	// Memory in bytes
+	Memory int64 `json:"memory" yaml:"memory" validate:"required"`
+	// Storage in bytes
+	Storage int64 `json:"storage" yaml:"storage" validate:"required"`
+	// Permission requirements
+	Permission *PluginPermissionRequirement `json:"permission" yaml:"permission" validate:"omitempty"`
+}
+
+type PluginDeclarationPlatformArch string
+
+const (
+	PLUGIN_PLATFORM_ARCH_AMD64 PluginDeclarationPlatformArch = "amd64"
+	PLUGIN_PLATFORM_ARCH_ARM64 PluginDeclarationPlatformArch = "arm64"
+)
+
+func isPluginDeclarationPlatformArch(fl validator.FieldLevel) bool {
+	value := fl.Field().String()
+	switch value {
+	case string(PLUGIN_PLATFORM_ARCH_AMD64),
+		string(PLUGIN_PLATFORM_ARCH_ARM64):
+		return true
+	}
+	return false
+}
+
+type PluginDeclarationMeta struct {
+	Version string   `json:"version" yaml:"version" validate:"required"`
+	Arch    []string `json:"arch" yaml:"arch" validate:"required,dive,plugin_declaration_platform_arch"`
+}
+
+type PluginDeclaration struct {
+	Version   string                    `json:"version" yaml:"version" validate:"required"`
+	Type      DifyManifestType          `json:"type" yaml:"type" validate:"required,eq=plugin"`
+	Author    string                    `json:"author" yaml:"author" validate:"required"`
+	Name      string                    `json:"name" yaml:"name" validate:"required" enum:"plugin"`
+	CreatedAt time.Time                 `json:"created_at" yaml:"created_at" validate:"required"`
+	Resource  PluginResourceRequirement `json:"resource" yaml:"resource" validate:"required"`
+	Plugin    []string                  `json:"plugins" yaml:"plugin" validate:"required"`
+}
+
+func (p *PluginDeclaration) Identity() string {
+	return parser.MarshalPluginIdentity(p.Name, p.Version)
+}
+
+var (
+	plugin_declaration_validator = validator.New()
+)
+
+func init() {
+	// init validator
+	plugin_declaration_validator.RegisterValidation("plugin_declaration_platform_arch", isPluginDeclarationPlatformArch)
+}
+
+func (p *PluginDeclaration) Validate() error {
+	return plugin_declaration_validator.Struct(p)
+}
+
+func UnmarshalPluginDeclarationFromYaml(data []byte) (*PluginDeclaration, error) {
+	obj, err := parser.UnmarshalYamlBytes[PluginDeclaration](data)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := obj.Validate(); err != nil {
+		return nil, err
+	}
+
+	return &obj, nil
+}
+
+func UnmarshalPluginDeclarationFromJSON(data []byte) (*PluginDeclaration, error) {
+	obj, err := parser.UnmarshalJsonBytes[PluginDeclaration](data)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := obj.Validate(); err != nil {
+		return nil, err
+	}
+
+	return &obj, nil
+}

+ 7 - 5
internal/types/entities/runtime.go

@@ -2,13 +2,15 @@ package entities
 
 import (
 	"time"
+
+	"github.com/langgenius/dify-plugin-daemon/internal/types/entities/plugin_entities"
 )
 
 type (
 	PluginRuntime struct {
-		State     PluginRuntimeState  `json:"state"`
-		Config    PluginConfiguration `json:"config"`
-		Connector PluginConnector     `json:"-"`
+		State     PluginRuntimeState                `json:"state"`
+		Config    plugin_entities.PluginDeclaration `json:"config"`
+		Connector PluginConnector                   `json:"-"`
 	}
 
 	PluginRuntimeInterface interface {
@@ -21,7 +23,7 @@ type (
 		StartPlugin() error
 		Stopped() bool
 		Stop()
-		Configuration() *PluginConfiguration
+		Configuration() *plugin_entities.PluginDeclaration
 		RuntimeState() *PluginRuntimeState
 	}
 
@@ -40,7 +42,7 @@ func (r *PluginRuntime) Stop() {
 	r.State.Status = PLUGIN_RUNTIME_STATUS_STOPPED
 }
 
-func (r *PluginRuntime) Configuration() *PluginConfiguration {
+func (r *PluginRuntime) Configuration() *plugin_entities.PluginDeclaration {
 	return &r.Config
 }
 

+ 0 - 19
internal/types/entities/validate.go

@@ -1,19 +0,0 @@
-package entities
-
-import "errors"
-
-func (c *PluginConfiguration) Validate() error {
-	if c.Module == "" {
-		return errors.New("exec is required")
-	}
-
-	if c.Name == "" {
-		return errors.New("name is required")
-	}
-
-	if c.Version == "" {
-		return errors.New("version is required")
-	}
-
-	return nil
-}

+ 4 - 0
internal/utils/parser/json.go

@@ -21,3 +21,7 @@ func MarshalJsonBytes[T any](data T) []byte {
 	b, _ := json.Marshal(data)
 	return b
 }
+
+func UnmarshalJson2Map(json []byte) (map[string]any, error) {
+	return UnmarshalJsonBytes[map[string]any](json)
+}

+ 28 - 0
internal/utils/parser/yaml.go

@@ -0,0 +1,28 @@
+package parser
+
+import (
+	"gopkg.in/yaml.v3"
+)
+
+func UnmarshalYaml[T any](text string) (T, error) {
+	return UnmarshalYamlBytes[T]([]byte(text))
+}
+
+func UnmarshalYamlBytes[T any](data []byte) (T, error) {
+	var result T
+	err := yaml.Unmarshal(data, &result)
+	return result, err
+}
+
+func MarshalYaml[T any](data T) string {
+	return string(MarshalYamlBytes(data))
+}
+
+func MarshalYamlBytes[T any](data T) []byte {
+	b, _ := yaml.Marshal(data)
+	return b
+}
+
+func UnmarshalYaml2Map(yaml []byte) (map[string]any, error) {
+	return UnmarshalYamlBytes[map[string]any](yaml)
+}