Forráskód Böngészése

refactor: add parameter scope

Yeuoly 1 éve%!(EXTRA string=óta)
szülő
commit
ddfeff8ef5

+ 178 - 0
internal/types/entities/plugin_entities/config.go

@@ -0,0 +1,178 @@
+package plugin_entities
+
+import (
+	"github.com/go-playground/locales/en"
+	ut "github.com/go-playground/universal-translator"
+	"github.com/go-playground/validator/v10"
+	"github.com/langgenius/dify-plugin-daemon/internal/types/validators"
+)
+
+type ConfigType string
+
+const (
+	CONFIG_TYPE_SECRET_INPUT ConfigType = SECRET_INPUT
+	CONFIG_TYPE_TEXT_INPUT   ConfigType = TEXT_INPUT
+	CONFIG_TYPE_SELECT       ConfigType = SELECT
+	CONFIG_TYPE_BOOLEAN      ConfigType = BOOLEAN
+	CONFIG_TYPE_MODEL_CONFIG ConfigType = MODEL_CONFIG
+	CONFIG_TYPE_APP_SELECTOR ConfigType = APP_SELECTOR
+)
+
+type ModelConfigScope string
+
+const (
+	MODEL_CONFIG_SCOPE_LLM            ModelConfigScope = "llm"
+	MODEL_CONFIG_SCOPE_TEXT_EMBEDDING ModelConfigScope = "text-embedding"
+	MODEL_CONFIG_SCOPE_RERANK         ModelConfigScope = "rerank"
+	MODEL_CONFIG_SCOPE_TTS            ModelConfigScope = "tts"
+	MODEL_CONFIG_SCOPE_SPEECH2TEXT    ModelConfigScope = "speech2text"
+	MODEL_CONFIG_SCOPE_MODERATION     ModelConfigScope = "moderation"
+	MODEL_CONFIG_SCOPE_VISION         ModelConfigScope = "vision"
+)
+
+type AppSelectorScope string
+
+const (
+	APP_SELECTOR_SCOPE_ALL        AppSelectorScope = "all"
+	APP_SELECTOR_SCOPE_CHAT       AppSelectorScope = "chat"
+	APP_SELECTOR_SCOPE_WORKFLOW   AppSelectorScope = "workflow"
+	APP_SELECTOR_SCOPE_COMPLETION AppSelectorScope = "completion"
+)
+
+func isCredentialType(fl validator.FieldLevel) bool {
+	value := fl.Field().String()
+	switch value {
+	case string(CONFIG_TYPE_SECRET_INPUT),
+		string(CONFIG_TYPE_TEXT_INPUT),
+		string(CONFIG_TYPE_SELECT),
+		string(CONFIG_TYPE_BOOLEAN),
+		string(CONFIG_TYPE_APP_SELECTOR):
+		return true
+	}
+	return false
+}
+
+type ConfigOption struct {
+	Value string     `json:"value" validate:"required"`
+	Label I18nObject `json:"label" validate:"required"`
+}
+
+func isModelConfigScope(fl validator.FieldLevel) bool {
+	value := fl.Field().String()
+	switch value {
+	case string(MODEL_CONFIG_SCOPE_LLM),
+		string(MODEL_CONFIG_SCOPE_TEXT_EMBEDDING),
+		string(MODEL_CONFIG_SCOPE_RERANK),
+		string(MODEL_CONFIG_SCOPE_TTS),
+		string(MODEL_CONFIG_SCOPE_SPEECH2TEXT),
+		string(MODEL_CONFIG_SCOPE_MODERATION),
+		string(MODEL_CONFIG_SCOPE_VISION):
+		return true
+	}
+	return false
+}
+
+func isAppSelectorScope(fl validator.FieldLevel) bool {
+	value := fl.Field().String()
+	switch value {
+	case string(APP_SELECTOR_SCOPE_ALL),
+		string(APP_SELECTOR_SCOPE_CHAT),
+		string(APP_SELECTOR_SCOPE_WORKFLOW),
+		string(APP_SELECTOR_SCOPE_COMPLETION):
+		return true
+	}
+	return false
+}
+
+func isScope(fl validator.FieldLevel) bool {
+	// get parent and check if it's a provider config
+	parent := fl.Parent().Interface()
+	if provider_config, ok := parent.(ProviderConfig); ok {
+		// check config type
+		if provider_config.Type == CONFIG_TYPE_APP_SELECTOR {
+			return isAppSelectorScope(fl)
+		} else if provider_config.Type == CONFIG_TYPE_MODEL_CONFIG {
+			return isModelConfigScope(fl)
+		} else {
+			return false
+		}
+	}
+	return false
+}
+
+func init() {
+	en := en.New()
+	uni := ut.New(en, en)
+	translator, _ := uni.GetTranslator("en")
+
+	validators.GlobalEntitiesValidator.RegisterValidation("is_scope", isScope)
+	validators.GlobalEntitiesValidator.RegisterTranslation(
+		"is_scope",
+		translator,
+		func(ut ut.Translator) error {
+			return ut.Add("is_scope", "{0} is not a valid scope", true)
+		},
+		func(ut ut.Translator, fe validator.FieldError) string {
+			t, _ := ut.T("is_scope", fe.Field())
+			return t
+		},
+	)
+
+	validators.GlobalEntitiesValidator.RegisterValidation("is_app_selector_scope", isAppSelectorScope)
+	validators.GlobalEntitiesValidator.RegisterTranslation(
+		"is_app_selector_scope",
+		translator,
+		func(ut ut.Translator) error {
+			return ut.Add("is_app_selector_scope", "{0} is not a valid app selector scope", true)
+		},
+		func(ut ut.Translator, fe validator.FieldError) string {
+			t, _ := ut.T("is_app_selector_scope", fe.Field())
+			return t
+		},
+	)
+
+	validators.GlobalEntitiesValidator.RegisterValidation("is_model_config_scope", isModelConfigScope)
+	validators.GlobalEntitiesValidator.RegisterTranslation(
+		"is_model_config_scope",
+		translator,
+		func(ut ut.Translator) error {
+			return ut.Add("is_model_config_scope", "{0} is not a valid model config scope", true)
+		},
+		func(ut ut.Translator, fe validator.FieldError) string {
+			t, _ := ut.T("is_model_config_scope", fe.Field())
+			return t
+		},
+	)
+}
+
+type ProviderConfig struct {
+	Name        string         `json:"name" validate:"required,gt=0,lt=1024"`
+	Type        ConfigType     `json:"type" validate:"required,credential_type"`
+	Scope       *string        `json:"scope" validate:"omitempty,is_scope"`
+	Required    bool           `json:"required"`
+	Default     any            `json:"default" validate:"omitempty,is_basic_type"`
+	Options     []ConfigOption `json:"options" validate:"omitempty,dive"`
+	Label       I18nObject     `json:"label" validate:"required"`
+	Helper      *I18nObject    `json:"helper" validate:"omitempty"`
+	URL         *string        `json:"url" validate:"omitempty"`
+	Placeholder *I18nObject    `json:"placeholder" validate:"omitempty"`
+}
+
+func init() {
+	en := en.New()
+	uni := ut.New(en, en)
+	translator, _ := uni.GetTranslator("en")
+
+	validators.GlobalEntitiesValidator.RegisterValidation("credential_type", isCredentialType)
+	validators.GlobalEntitiesValidator.RegisterTranslation(
+		"credential_type",
+		translator,
+		func(ut ut.Translator) error {
+			return ut.Add("credential_type", "{0} is not a valid credential type", true)
+		},
+		func(ut ut.Translator, fe validator.FieldError) string {
+			t, _ := ut.T("credential_type", fe.Field())
+			return t
+		},
+	)
+}

+ 9 - 11
internal/types/entities/plugin_entities/constant.go

@@ -1,15 +1,13 @@
 package plugin_entities
 
 const (
-	SECRET_INPUT      = "secret-input"
-	TEXT_INPUT        = "text-input"
-	SELECT            = "select"
-	STRING            = "string"
-	NUMBER            = "number"
-	FILE              = "file"
-	BOOLEAN           = "boolean"
-	CHAT_APP_ID       = "chat-app-id"
-	COMPLETION_APP_ID = "completion-app-id"
-	WORKFLOW_APP_ID   = "workflow-app-id"
-	MODEL_CONFIG      = "model-config"
+	SECRET_INPUT = "secret-input"
+	TEXT_INPUT   = "text-input"
+	SELECT       = "select"
+	STRING       = "string"
+	NUMBER       = "number"
+	FILE         = "file"
+	BOOLEAN      = "boolean"
+	APP_SELECTOR = "app-selector"
+	MODEL_CONFIG = "model-config"
 )

+ 0 - 72
internal/types/entities/plugin_entities/credentials.go

@@ -1,72 +0,0 @@
-package plugin_entities
-
-import (
-	"github.com/go-playground/locales/en"
-	ut "github.com/go-playground/universal-translator"
-	"github.com/go-playground/validator/v10"
-	"github.com/langgenius/dify-plugin-daemon/internal/types/validators"
-)
-
-type ConfigType string
-
-const (
-	CONFIG_TYPE_SECRET_INPUT      ConfigType = SECRET_INPUT
-	CONFIG_TYPE_TEXT_INPUT        ConfigType = TEXT_INPUT
-	CONFIG_TYPE_SELECT            ConfigType = SELECT
-	CONFIG_TYPE_BOOLEAN           ConfigType = BOOLEAN
-	CONFIG_TYPE_CHAT_APP_ID       ConfigType = CHAT_APP_ID
-	CONFIG_TYPE_COMPLETION_APP_ID ConfigType = COMPLETION_APP_ID
-	CONFIG_TYPE_WORKFLOW_APP_ID   ConfigType = WORKFLOW_APP_ID
-	CONFIG_TYPE_MODEL_CONFIG      ConfigType = MODEL_CONFIG
-)
-
-func isCredentialType(fl validator.FieldLevel) bool {
-	value := fl.Field().String()
-	switch value {
-	case string(CONFIG_TYPE_SECRET_INPUT),
-		string(CONFIG_TYPE_TEXT_INPUT),
-		string(CONFIG_TYPE_SELECT),
-		string(CONFIG_TYPE_BOOLEAN),
-		string(CONFIG_TYPE_CHAT_APP_ID),
-		string(CONFIG_TYPE_COMPLETION_APP_ID),
-		string(CONFIG_TYPE_WORKFLOW_APP_ID):
-		return true
-	}
-	return false
-}
-
-type ConfigOption struct {
-	Value string     `json:"value" validate:"required"`
-	Label I18nObject `json:"label" validate:"required"`
-}
-
-type ProviderConfig struct {
-	Name        string         `json:"name" validate:"required,gt=0,lt=1024"`
-	Type        ConfigType     `json:"type" validate:"required,credential_type"`
-	Required    bool           `json:"required"`
-	Default     any            `json:"default" validate:"omitempty,is_basic_type"`
-	Options     []ConfigOption `json:"options" validate:"omitempty,dive"`
-	Label       I18nObject     `json:"label" validate:"required"`
-	Helper      *I18nObject    `json:"helper" validate:"omitempty"`
-	URL         *string        `json:"url" validate:"omitempty"`
-	Placeholder *I18nObject    `json:"placeholder" validate:"omitempty"`
-}
-
-func init() {
-	en := en.New()
-	uni := ut.New(en, en)
-	translator, _ := uni.GetTranslator("en")
-
-	validators.GlobalEntitiesValidator.RegisterValidation("credential_type", isCredentialType)
-	validators.GlobalEntitiesValidator.RegisterTranslation(
-		"credential_type",
-		translator,
-		func(ut ut.Translator) error {
-			return ut.Add("credential_type", "{0} is not a valid credential type", true)
-		},
-		func(ut ut.Translator, fe validator.FieldError) string {
-			t, _ := ut.T("credential_type", fe.Field())
-			return t
-		},
-	)
-}

+ 11 - 14
internal/types/entities/plugin_entities/tool_configuration.go

@@ -26,16 +26,14 @@ type ToolParameterOption struct {
 type ToolParameterType string
 
 const (
-	TOOL_PARAMETER_TYPE_STRING            ToolParameterType = STRING
-	TOOL_PARAMETER_TYPE_NUMBER            ToolParameterType = NUMBER
-	TOOL_PARAMETER_TYPE_BOOLEAN           ToolParameterType = BOOLEAN
-	TOOL_PARAMETER_TYPE_SELECT            ToolParameterType = SELECT
-	TOOL_PARAMETER_TYPE_SECRET_INPUT      ToolParameterType = SECRET_INPUT
-	TOOL_PARAMETER_TYPE_FILE              ToolParameterType = FILE
-	TOOL_PARAMETER_TYPE_MODEL_CONFIG      ToolParameterType = MODEL_CONFIG
-	TOOL_PARAMETER_TYPE_CHAT_APP_ID       ToolParameterType = CHAT_APP_ID
-	TOOL_PARAMETER_TYPE_COMPLETION_APP_ID ToolParameterType = COMPLETION_APP_ID
-	TOOL_PARAMETER_TYPE_WORKFLOW_APP_ID   ToolParameterType = WORKFLOW_APP_ID
+	TOOL_PARAMETER_TYPE_STRING       ToolParameterType = STRING
+	TOOL_PARAMETER_TYPE_NUMBER       ToolParameterType = NUMBER
+	TOOL_PARAMETER_TYPE_BOOLEAN      ToolParameterType = BOOLEAN
+	TOOL_PARAMETER_TYPE_SELECT       ToolParameterType = SELECT
+	TOOL_PARAMETER_TYPE_SECRET_INPUT ToolParameterType = SECRET_INPUT
+	TOOL_PARAMETER_TYPE_FILE         ToolParameterType = FILE
+	TOOL_PARAMETER_TYPE_APP_SELECTOR ToolParameterType = APP_SELECTOR
+	TOOL_PARAMETER_TYPE_MODEL_CONFIG ToolParameterType = MODEL_CONFIG
 )
 
 func isToolParameterType(fl validator.FieldLevel) bool {
@@ -47,10 +45,8 @@ func isToolParameterType(fl validator.FieldLevel) bool {
 		string(TOOL_PARAMETER_TYPE_SELECT),
 		string(TOOL_PARAMETER_TYPE_SECRET_INPUT),
 		string(TOOL_PARAMETER_TYPE_FILE),
-		string(TOOL_PARAMETER_TYPE_MODEL_CONFIG),
-		string(TOOL_PARAMETER_TYPE_CHAT_APP_ID),
-		string(TOOL_PARAMETER_TYPE_COMPLETION_APP_ID),
-		string(TOOL_PARAMETER_TYPE_WORKFLOW_APP_ID):
+		string(TOOL_PARAMETER_TYPE_APP_SELECTOR),
+		string(TOOL_PARAMETER_TYPE_MODEL_CONFIG):
 		return true
 	}
 	return false
@@ -80,6 +76,7 @@ type ToolParameter struct {
 	Label            I18nObject            `json:"label" validate:"required"`
 	HumanDescription I18nObject            `json:"human_description" validate:"required"`
 	Type             ToolParameterType     `json:"type" validate:"required,tool_parameter_type"`
+	Scope            *string               `json:"scope" validate:"omitempty,is_scope"`
 	Form             ToolParameterForm     `json:"form" validate:"required,tool_parameter_form"`
 	LLMDescription   string                `json:"llm_description" validate:"omitempty"`
 	Required         bool                  `json:"required" validate:"required"`

+ 165 - 0
internal/types/entities/plugin_entities/tool_configuration_test.go

@@ -1,6 +1,7 @@
 package plugin_entities
 
 import (
+	"strings"
 	"testing"
 )
 
@@ -657,3 +658,167 @@ func TestWrongJSONSchemaToolProvider_Validate(t *testing.T) {
 		return
 	}
 }
+
+func TestWrongAppSelectorScopeToolProvider_Validate(t *testing.T) {
+	const data = `
+{
+	"identity": {
+		"author": "author",
+		"name": "name",
+		"description": {
+			"en_US": "description",
+			"zh_Hans": "描述",
+			"pt_BR": "descrição"
+		},
+		"icon": "icon",
+		"label": {
+			"en_US": "label",
+			"zh_Hans": "标签",
+			"pt_BR": "etiqueta"
+		},
+		"tags": []
+	},
+	"credentials_schema": {
+		"api_key": {
+			"name": "app-selector",
+			"type": "app-selector",
+			"scope": "wrong",
+			"required": false,
+			"default": null,
+			"label": {
+				"en_US": "app-selector",
+				"zh_Hans": "app-selector",
+				"pt_BR": "app-selector"
+			},
+			"helper": {
+				"en_US": "app-selector",
+				"zh_Hans": "app-selector",
+				"pt_BR": "app-selector"
+			},
+			"url": "https://example.com",
+			"placeholder": {
+				"en_US": "app-selector",
+				"zh_Hans": "app-selector",
+				"pt_BR": "app-selector"
+			}
+		}
+	},
+	"tools": [
+		{
+			"identity": {
+				"author": "author",
+				"name": "tool",
+				"label": {
+					"en_US": "label",
+					"zh_Hans": "标签",
+					"pt_BR": "etiqueta"
+				}
+			},
+			"description": {
+				"human": {
+					"en_US": "description",
+					"zh_Hans": "描述",
+					"pt_BR": "descrição"
+				},
+				"llm": "description"
+			},
+			"parameters": [
+				{
+					"name": "parameter-app-selector",
+					"label": {
+						"en_US": "label",
+						"zh_Hans": "标签",
+						"pt_BR": "etiqueta"
+					},
+					"human_description": {
+						"en_US": "description",
+						"zh_Hans": "描述",
+						"pt_BR": "descrição"
+					},
+					"type": "app-selector",
+					"form": "llm",
+					"scope": "wrong",
+					"required": true,
+					"default": "default",
+					"options": []
+				}
+			]
+		}
+	]
+}
+	`
+
+	_, err := UnmarshalToolProviderConfiguration([]byte(data))
+	if err == nil {
+		t.Errorf("UnmarshalToolProviderConfiguration() error = %v, wantErr %v", err, true)
+		return
+	}
+
+	str := err.Error()
+	if !strings.Contains(str, "api_key") {
+		t.Errorf("UnmarshalToolProviderConfiguration() error = %v, wantErr %v", err, true)
+		return
+	}
+
+	if !strings.Contains(str, "ToolProviderConfiguration.Tools[0].Parameters[0].Scope") {
+		t.Errorf("UnmarshalToolProviderConfiguration() error = %v, wantErr %v", err, true)
+		return
+	}
+}
+
+func TestAppSelectorScopeToolProvider_Validate(t *testing.T) {
+	const data = `
+{
+	"identity": {
+		"author": "author",
+		"name": "name",
+		"description": {
+			"en_US": "description",
+			"zh_Hans": "描述",
+			"pt_BR": "descrição"
+		},
+		"icon": "icon",
+		"label": {
+			"en_US": "label",
+			"zh_Hans": "标签",
+			"pt_BR": "etiqueta"
+		},
+		"tags": []
+	},
+	"credentials_schema": {
+		"app-selector": {
+			"name": "app-selector",
+			"type": "app-selector",
+			"scope": "all",
+			"required": false,
+			"default": null,
+			"label": {
+				"en_US": "app-selector",
+				"zh_Hans": "app-selector",
+				"pt_BR": "app-selector"
+			},
+			"helper": {
+				"en_US": "app-selector",
+				"zh_Hans": "app-selector",
+				"pt_BR": "app-selector"
+			},
+			"url": "https://example.com",
+			"placeholder": {
+				"en_US": "app-selector",
+				"zh_Hans": "app-selector",
+				"pt_BR": "app-selector"
+			}
+		}
+	},
+	"tools": [
+	
+	]
+}
+	`
+
+	_, err := UnmarshalToolProviderConfiguration([]byte(data))
+	if err != nil {
+		t.Errorf("UnmarshalToolProviderConfiguration() error = %v, wantErr %v", err, true)
+		return
+	}
+}