浏览代码

refactor: manifest

Yeuoly 10 月之前
父节点
当前提交
62a2a5c906

+ 3 - 1
internal/cluster/plugin_test.go

@@ -59,7 +59,9 @@ func getRandomPluginRuntime() fakePlugin {
 					Type:      plugin_entities.PluginType,
 					Author:    "Yeuoly",
 					CreatedAt: time.Now(),
-					Plugins:   []string{"test"},
+					Plugins: plugin_entities.PluginExtensions{
+						Tools: []string{"test"},
+					},
 				},
 			},
 		},

+ 4 - 2
internal/core/plugin_manager/remote_manager/server_test.go

@@ -157,8 +157,10 @@ func TestAcceptConnection(t *testing.T) {
 				Memory:     1,
 				Permission: nil,
 			},
-			Plugins: []string{
-				"test",
+			Plugins: plugin_entities.PluginExtensions{
+				Tools: []string{
+					"test",
+				},
 			},
 			Meta: plugin_entities.PluginMeta{
 				Version: "0.0.1",

+ 2 - 1
internal/core/plugin_manager/serverless/packager_test_plugin/manifest.yaml

@@ -14,7 +14,8 @@ resource:
       enabled: true
       llm: true
 plugins:
-  - "provider/jina.yaml"
+  models:
+    - "provider/jina.yaml"
 execution:
   install: install.sh
   launch: launch.sh

+ 75 - 77
internal/core/plugin_manager/serverless/packager_test_plugin/provider/jina.yaml

@@ -1,79 +1,77 @@
-type: model
-provider:
-  provider: jina
-  label:
-    en_US: Jina
-  description:
-    en_US: Embedding and Rerank Model Supported
-  icon_small:
-    en_US: icon_s_en.svg
-  icon_large:
-    en_US: icon_l_en.svg
-  background: "#EFFDFD"
-  help:
-    title:
-      en_US: Get your API key from Jina AI
-      zh_Hans: 从 Jina 获取 API Key
-    url:
-      en_US: https://jina.ai/
-  supported_model_types:
-    - text-embedding
-    - rerank
-  configurate_methods:
-    - predefined-model
-    - customizable-model
-  provider_credential_schema:
-    credential_form_schemas:
-      - variable: api_key
-        label:
-          en_US: API Key
-        type: secret-input
-        required: true
-        placeholder:
-          zh_Hans: 在此输入您的 API Key
-          en_US: Enter your API Key
-  model_credential_schema:
-    model:
+provider: jina
+label:
+  en_US: Jina
+description:
+  en_US: Embedding and Rerank Model Supported
+icon_small:
+  en_US: icon_s_en.svg
+icon_large:
+  en_US: icon_l_en.svg
+background: "#EFFDFD"
+help:
+  title:
+    en_US: Get your API key from Jina AI
+    zh_Hans: 从 Jina 获取 API Key
+  url:
+    en_US: https://jina.ai/
+supported_model_types:
+  - text-embedding
+  - rerank
+configurate_methods:
+  - predefined-model
+  - customizable-model
+provider_credential_schema:
+  credential_form_schemas:
+    - variable: api_key
       label:
-        en_US: Model Name
-        zh_Hans: 模型名称
+        en_US: API Key
+      type: secret-input
+      required: true
       placeholder:
-        en_US: Enter your model name
-        zh_Hans: 输入模型名称
-    credential_form_schemas:
-      - variable: api_key
-        label:
-          en_US: API Key
-        type: secret-input
-        required: true
-        placeholder:
-          zh_Hans: 在此输入您的 API Key
-          en_US: Enter your API Key
-      - variable: base_url
-        label:
-          zh_Hans: 服务器 URL
-          en_US: Base URL
-        type: text-input
-        required: true
-        placeholder:
-          zh_Hans: Base URL, e.g. https://api.jina.ai/v1
-          en_US: Base URL, e.g. https://api.jina.ai/v1
-        default: 'https://api.jina.ai/v1'
-      - variable: context_size
-        label:
-          zh_Hans: 上下文大小
-          en_US: Context size
-        placeholder:
-          zh_Hans: 输入上下文大小
-          en_US: Enter context size
-        required: false
-        type: text-input
-        default: '8192'
-  models:
-    - "models/**/*.yaml"
-  extra:
-    python:
-      provider_source: provider/jina.py
-      model_sources:
-        - "models/text_embedding/text_embedding.py"
-        - "models/rerank/rerank.py"
+        zh_Hans: 在此输入您的 API Key
+        en_US: Enter your API Key
+model_credential_schema:
+  model:
+    label:
+      en_US: Model Name
+      zh_Hans: 模型名称
+    placeholder:
+      en_US: Enter your model name
+      zh_Hans: 输入模型名称
+  credential_form_schemas:
+    - variable: api_key
+      label:
+        en_US: API Key
+      type: secret-input
+      required: true
+      placeholder:
+        zh_Hans: 在此输入您的 API Key
+        en_US: Enter your API Key
+    - variable: base_url
+      label:
+        zh_Hans: 服务器 URL
+        en_US: Base URL
+      type: text-input
+      required: true
+      placeholder:
+        zh_Hans: Base URL, e.g. https://api.jina.ai/v1
+        en_US: Base URL, e.g. https://api.jina.ai/v1
+      default: 'https://api.jina.ai/v1'
+    - variable: context_size
+      label:
+        zh_Hans: 上下文大小
+        en_US: Context size
+      placeholder:
+        zh_Hans: 输入上下文大小
+        en_US: Enter context size
+      required: false
+      type: text-input
+      default: '8192'
+models:
+  - "models/**/*.yaml"
+extra:
+  python:
+    provider_source: provider/jina.py
+    model_sources:
+      - "models/text_embedding/text_embedding.py"
+      - "models/rerank/rerank.py"

+ 35 - 23
internal/core/plugin_packager/decoder/decoder.go

@@ -83,37 +83,49 @@ func (p *PluginDecoderHelper) Manifest(decoder PluginDecoder) (plugin_entities.P
 
 	// try to load plugins
 	plugins := dec.Plugins
-	for _, plugin := range plugins {
+	for _, tool := range plugins.Tools {
 		// read yaml
-		plugin_yaml, err := decoder.ReadFile(plugin)
+		plugin_yaml, err := decoder.ReadFile(tool)
 		if err != nil {
-			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to read plugin file: %s", plugin))
+			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to read tool file: %s", tool))
 		}
 
-		plugin_dec, err := parser.UnmarshalYamlBytes[plugin_entities.GenericProviderDeclaration](plugin_yaml)
+		plugin_dec, err := parser.UnmarshalYamlBytes[plugin_entities.ToolProviderDeclaration](plugin_yaml)
 		if err != nil {
-			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to unmarshal plugin file: %s", plugin))
+			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to unmarshal plugin file: %s", tool))
 		}
 
-		switch plugin_dec.Type {
-		case plugin_entities.PROVIDER_TYPE_ENDPOINT:
-			dec.Endpoint, err = parser.MapToStruct[plugin_entities.EndpointProviderDeclaration](plugin_dec.Provider)
-			if err != nil {
-				return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to convert endpoint to struct: %s", plugin))
-			}
-		case plugin_entities.PROVIDER_TYPE_TOOL:
-			dec.Tool, err = parser.MapToStruct[plugin_entities.ToolProviderDeclaration](plugin_dec.Provider)
-			if err != nil {
-				return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to convert tool to struct: %s", plugin))
-			}
-		case plugin_entities.PROVIDER_TYPE_MODEL:
-			dec.Model, err = parser.MapToStruct[plugin_entities.ModelProviderDeclaration](plugin_dec.Provider)
-			if err != nil {
-				return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to convert model to struct: %s", plugin))
-			}
-		default:
-			return plugin_entities.PluginDeclaration{}, fmt.Errorf("unknown provider type: %s", plugin_dec.Type)
+		dec.Tool = &plugin_dec
+	}
+
+	for _, endpoint := range plugins.Endpoints {
+		// read yaml
+		plugin_yaml, err := decoder.ReadFile(endpoint)
+		if err != nil {
+			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to read endpoint file: %s", endpoint))
 		}
+
+		plugin_dec, err := parser.UnmarshalYamlBytes[plugin_entities.EndpointProviderDeclaration](plugin_yaml)
+		if err != nil {
+			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to unmarshal plugin file: %s", endpoint))
+		}
+
+		dec.Endpoint = &plugin_dec
+	}
+
+	for _, model := range plugins.Models {
+		// read yaml
+		plugin_yaml, err := decoder.ReadFile(model)
+		if err != nil {
+			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to read model file: %s", model))
+		}
+
+		plugin_dec, err := parser.UnmarshalYamlBytes[plugin_entities.ModelProviderDeclaration](plugin_yaml)
+		if err != nil {
+			return plugin_entities.PluginDeclaration{}, errors.Join(err, fmt.Errorf("failed to unmarshal plugin file: %s", model))
+		}
+
+		dec.Model = &plugin_dec
 	}
 
 	if err := dec.ManifestValidate(); err != nil {

+ 2 - 1
internal/core/plugin_packager/manifest.yaml

@@ -16,7 +16,8 @@ resource:
       enabled: true
       llm: true
 plugins:
-  - "neko.yaml"
+  endpoints:
+    - "neko.yaml"
 execution:
   install: install.sh
   launch: launch.sh

+ 16 - 18
internal/core/plugin_packager/neko.yaml

@@ -1,18 +1,16 @@
-type: endpoint
-provider:
-  settings:
-    api_key:
-      type: secret-input
-      name: api_key
-      required: true
-      label:
-        en_US: API key
-        zh_Hans: API key
-        pt_BR: API key
-      placeholder:
-        en_US: Please input your API key
-        zh_Hans: 请输入你的 API key
-        pt_BR: Please input your API key
-  endpoints:
-    - endpoints/duck.yaml
-    - endpoints/neko.yaml
+settings:
+  api_key:
+    type: secret-input
+    name: api_key
+    required: true
+    label:
+      en_US: API key
+      zh_Hans: API key
+      pt_BR: API key
+    placeholder:
+      en_US: Please input your API key
+      zh_Hans: 请输入你的 API key
+      pt_BR: Please input your API key
+endpoints:
+  - endpoints/duck.yaml
+  - endpoints/neko.yaml

+ 7 - 1
internal/types/entities/plugin_entities/plugin_declaration.go

@@ -126,6 +126,12 @@ type PluginMeta struct {
 	Runner  PluginRunner     `json:"runner" yaml:"runner" validate:"required"`
 }
 
+type PluginExtensions struct {
+	Tools     []string `json:"tools" yaml:"tools,omitempty" validate:"required,dive,max=128"`
+	Models    []string `json:"models" yaml:"models,omitempty" validate:"required,dive,max=128"`
+	Endpoints []string `json:"endpoints" yaml:"endpoints,omitempty" validate:"required,dive,max=128"`
+}
+
 type PluginDeclarationWithoutAdvancedFields struct {
 	Version   string                    `json:"version" yaml:"version,omitempty" validate:"required,version"`
 	Type      DifyManifestType          `json:"type" yaml:"type,omitempty" validate:"required,eq=plugin"`
@@ -135,7 +141,7 @@ type PluginDeclarationWithoutAdvancedFields struct {
 	Label     I18nObject                `json:"label" yaml:"label" validate:"required"`
 	CreatedAt time.Time                 `json:"created_at" yaml:"created_at,omitempty" validate:"required"`
 	Resource  PluginResourceRequirement `json:"resource" yaml:"resource,omitempty" validate:"required"`
-	Plugins   []string                  `json:"plugins" yaml:"plugins,omitempty" validate:"required,dive,max=128"`
+	Plugins   PluginExtensions          `json:"plugins" yaml:"plugins,omitempty" validate:"required"`
 	Meta      PluginMeta                `json:"meta" yaml:"meta,omitempty" validate:"required"`
 }
 

+ 1 - 1
internal/types/entities/plugin_entities/plugin_declaration_test.go

@@ -38,7 +38,7 @@ func preparePluginDeclaration() PluginDeclaration {
 					},
 				},
 			},
-			Plugins: []string{},
+			Plugins: PluginExtensions{},
 			Meta: PluginMeta{
 				Version: "0.0.1",
 				Arch: []constants.Arch{

+ 0 - 28
internal/types/entities/plugin_entities/provider_declaration.go

@@ -1,28 +0,0 @@
-package plugin_entities
-
-import (
-	"github.com/go-playground/validator/v10"
-	"github.com/langgenius/dify-plugin-daemon/internal/types/validators"
-)
-
-type ProviderType string
-
-const (
-	PROVIDER_TYPE_MODEL    ProviderType = "model"
-	PROVIDER_TYPE_TOOL     ProviderType = "tool"
-	PROVIDER_TYPE_ENDPOINT ProviderType = "endpoint"
-)
-
-func isAvailableProviderType(fl validator.FieldLevel) bool {
-	str := fl.Field().String()
-	return str == string(PROVIDER_TYPE_MODEL) || str == string(PROVIDER_TYPE_TOOL) || str == string(PROVIDER_TYPE_ENDPOINT)
-}
-
-func init() {
-	validators.GlobalEntitiesValidator.RegisterValidation("provider_type", isAvailableProviderType)
-}
-
-type GenericProviderDeclaration struct {
-	Type     ProviderType   `json:"type" yaml:"type" validate:"required,provider_type"`
-	Provider map[string]any `json:"provider" yaml:"provider" validate:"required"`
-}