config.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. package plugin_entities
  2. import (
  3. "errors"
  4. "strings"
  5. "github.com/go-playground/locales/en"
  6. ut "github.com/go-playground/universal-translator"
  7. "github.com/go-playground/validator/v10"
  8. "github.com/langgenius/dify-plugin-daemon/pkg/validators"
  9. )
  10. type ConfigType string
  11. const (
  12. CONFIG_TYPE_SECRET_INPUT ConfigType = SECRET_INPUT
  13. CONFIG_TYPE_TEXT_INPUT ConfigType = TEXT_INPUT
  14. CONFIG_TYPE_SELECT ConfigType = SELECT
  15. CONFIG_TYPE_BOOLEAN ConfigType = BOOLEAN
  16. CONFIG_TYPE_MODEL_SELECTOR ConfigType = MODEL_SELECTOR
  17. CONFIG_TYPE_APP_SELECTOR ConfigType = APP_SELECTOR
  18. // CONFIG_TYPE_TOOL_SELECTOR ConfigType = TOOL_SELECTOR
  19. )
  20. type ModelConfigScope string
  21. const (
  22. MODEL_CONFIG_SCOPE_ALL ModelConfigScope = "all"
  23. MODEL_CONFIG_SCOPE_LLM ModelConfigScope = "llm"
  24. MODEL_CONFIG_SCOPE_TEXT_EMBEDDING ModelConfigScope = "text-embedding"
  25. MODEL_CONFIG_SCOPE_RERANK ModelConfigScope = "rerank"
  26. MODEL_CONFIG_SCOPE_TTS ModelConfigScope = "tts"
  27. MODEL_CONFIG_SCOPE_SPEECH2TEXT ModelConfigScope = "speech2text"
  28. MODEL_CONFIG_SCOPE_MODERATION ModelConfigScope = "moderation"
  29. MODEL_CONFIG_SCOPE_VISION ModelConfigScope = "vision"
  30. MODEL_CONFIG_SCOPE_DOCUMENT ModelConfigScope = "document"
  31. MODEL_CONFIG_SCOPE_TOOL_CALL ModelConfigScope = "tool-call"
  32. )
  33. type AppSelectorScope string
  34. const (
  35. APP_SELECTOR_SCOPE_ALL AppSelectorScope = "all"
  36. APP_SELECTOR_SCOPE_CHAT AppSelectorScope = "chat"
  37. APP_SELECTOR_SCOPE_WORKFLOW AppSelectorScope = "workflow"
  38. APP_SELECTOR_SCOPE_COMPLETION AppSelectorScope = "completion"
  39. )
  40. type ToolSelectorScope string
  41. const (
  42. TOOL_SELECTOR_SCOPE_ALL ToolSelectorScope = "all"
  43. TOOL_SELECTOR_SCOPE_PLUGIN ToolSelectorScope = "plugin"
  44. TOOL_SELECTOR_SCOPE_API ToolSelectorScope = "api"
  45. TOOL_SELECTOR_SCOPE_WORKFLOW ToolSelectorScope = "workflow"
  46. )
  47. func isCredentialType(fl validator.FieldLevel) bool {
  48. value := fl.Field().String()
  49. switch value {
  50. case string(CONFIG_TYPE_SECRET_INPUT),
  51. string(CONFIG_TYPE_TEXT_INPUT),
  52. string(CONFIG_TYPE_SELECT),
  53. string(CONFIG_TYPE_BOOLEAN),
  54. string(CONFIG_TYPE_APP_SELECTOR),
  55. string(CONFIG_TYPE_MODEL_SELECTOR):
  56. return true
  57. }
  58. return false
  59. }
  60. type ConfigOption struct {
  61. Value string `json:"value" validate:"required,lt=128"`
  62. Label I18nObject `json:"label" validate:"required"`
  63. }
  64. func isModelConfigScope(fl validator.FieldLevel) bool {
  65. value := fl.Field().String()
  66. // split by and symbol
  67. scopes := strings.Split(value, "&")
  68. for _, scope := range scopes {
  69. // trim space
  70. scope = strings.TrimSpace(scope)
  71. switch scope {
  72. case string(MODEL_CONFIG_SCOPE_LLM),
  73. string(MODEL_CONFIG_SCOPE_TEXT_EMBEDDING),
  74. string(MODEL_CONFIG_SCOPE_RERANK),
  75. string(MODEL_CONFIG_SCOPE_TTS),
  76. string(MODEL_CONFIG_SCOPE_SPEECH2TEXT),
  77. string(MODEL_CONFIG_SCOPE_MODERATION),
  78. string(MODEL_CONFIG_SCOPE_VISION),
  79. string(MODEL_CONFIG_SCOPE_DOCUMENT),
  80. string(MODEL_CONFIG_SCOPE_TOOL_CALL):
  81. return true
  82. }
  83. }
  84. return false
  85. }
  86. func isAppSelectorScope(fl validator.FieldLevel) bool {
  87. value := fl.Field().String()
  88. // split by and symbol
  89. scopes := strings.Split(value, "&")
  90. for _, scope := range scopes {
  91. // trim space
  92. scope = strings.TrimSpace(scope)
  93. switch scope {
  94. case string(APP_SELECTOR_SCOPE_ALL),
  95. string(APP_SELECTOR_SCOPE_CHAT),
  96. string(APP_SELECTOR_SCOPE_WORKFLOW),
  97. string(APP_SELECTOR_SCOPE_COMPLETION):
  98. return true
  99. }
  100. }
  101. return false
  102. }
  103. func isToolSelectorScope(fl validator.FieldLevel) bool {
  104. value := fl.Field().String()
  105. // split by and symbol
  106. scopes := strings.Split(value, "&")
  107. for _, scope := range scopes {
  108. // trim space
  109. scope = strings.TrimSpace(scope)
  110. switch scope {
  111. case string(TOOL_SELECTOR_SCOPE_ALL),
  112. string(TOOL_SELECTOR_SCOPE_PLUGIN),
  113. string(TOOL_SELECTOR_SCOPE_API),
  114. string(TOOL_SELECTOR_SCOPE_WORKFLOW):
  115. return true
  116. }
  117. }
  118. return false
  119. }
  120. func isScope(fl validator.FieldLevel) bool {
  121. // get parent and check if it's a provider config
  122. parent := fl.Parent().Interface()
  123. if providerConfig, ok := parent.(ProviderConfig); ok {
  124. // check config type
  125. if providerConfig.Type == CONFIG_TYPE_APP_SELECTOR {
  126. return isAppSelectorScope(fl)
  127. } else if providerConfig.Type == CONFIG_TYPE_MODEL_SELECTOR {
  128. return isModelConfigScope(fl)
  129. } else {
  130. return false
  131. }
  132. //else if providerConfig.Type == CONFIG_TYPE_TOOL_SELECTOR {
  133. //return isToolSelectorScope(fl)
  134. //}
  135. }
  136. if toolParameter, ok := parent.(ToolParameter); ok {
  137. if toolParameter.Type == TOOL_PARAMETER_TYPE_APP_SELECTOR {
  138. return isAppSelectorScope(fl)
  139. } else if toolParameter.Type == TOOL_PARAMETER_TYPE_MODEL_SELECTOR {
  140. return isModelConfigScope(fl)
  141. } else {
  142. return false
  143. }
  144. // else if toolParameter.Type == TOOL_PARAMETER_TYPE_TOOL_SELECTOR {
  145. // return isToolSelectorScope(fl)
  146. // }
  147. }
  148. if agentStrategyParameter, ok := parent.(AgentStrategyParameter); ok {
  149. if agentStrategyParameter.Type == AGENT_STRATEGY_PARAMETER_TYPE_APP_SELECTOR {
  150. return isAppSelectorScope(fl)
  151. } else if agentStrategyParameter.Type == AGENT_STRATEGY_PARAMETER_TYPE_MODEL_SELECTOR {
  152. return isModelConfigScope(fl)
  153. } else {
  154. return false
  155. }
  156. //else if agentStrategyParameter.Type == AGENT_STRATEGY_PARAMETER_TYPE_TOOLS_SELECTOR {
  157. // return isToolSelectorScope(fl)
  158. //}
  159. }
  160. return false
  161. }
  162. func init() {
  163. en := en.New()
  164. uni := ut.New(en, en)
  165. translator, _ := uni.GetTranslator("en")
  166. validators.GlobalEntitiesValidator.RegisterValidation("is_scope", isScope)
  167. validators.GlobalEntitiesValidator.RegisterTranslation(
  168. "is_scope",
  169. translator,
  170. func(ut ut.Translator) error {
  171. return ut.Add("is_scope", "{0} is not a valid scope", true)
  172. },
  173. func(ut ut.Translator, fe validator.FieldError) string {
  174. t, _ := ut.T("is_scope", fe.Field())
  175. return t
  176. },
  177. )
  178. validators.GlobalEntitiesValidator.RegisterValidation("is_app_selector_scope", isAppSelectorScope)
  179. validators.GlobalEntitiesValidator.RegisterTranslation(
  180. "is_app_selector_scope",
  181. translator,
  182. func(ut ut.Translator) error {
  183. return ut.Add("is_app_selector_scope", "{0} is not a valid app selector scope", true)
  184. },
  185. func(ut ut.Translator, fe validator.FieldError) string {
  186. t, _ := ut.T("is_app_selector_scope", fe.Field())
  187. return t
  188. },
  189. )
  190. validators.GlobalEntitiesValidator.RegisterValidation("is_model_config_scope", isModelConfigScope)
  191. validators.GlobalEntitiesValidator.RegisterTranslation(
  192. "is_model_config_scope",
  193. translator,
  194. func(ut ut.Translator) error {
  195. return ut.Add("is_model_config_scope", "{0} is not a valid model config scope", true)
  196. },
  197. func(ut ut.Translator, fe validator.FieldError) string {
  198. t, _ := ut.T("is_model_config_scope", fe.Field())
  199. return t
  200. },
  201. )
  202. validators.GlobalEntitiesValidator.RegisterValidation("is_tool_selector_scope", isToolSelectorScope)
  203. validators.GlobalEntitiesValidator.RegisterTranslation(
  204. "is_tool_selector_scope",
  205. translator,
  206. func(ut ut.Translator) error {
  207. return ut.Add("is_tool_selector_scope", "{0} is not a valid tool selector scope", true)
  208. },
  209. func(ut ut.Translator, fe validator.FieldError) string {
  210. t, _ := ut.T("is_tool_selector_scope", fe.Field())
  211. return t
  212. },
  213. )
  214. }
  215. type ProviderConfig struct {
  216. Name string `json:"name" validate:"omitempty,gt=0,lt=1024"`
  217. Type ConfigType `json:"type" validate:"required,credential_type"`
  218. Scope *string `json:"scope" validate:"omitempty,is_scope"`
  219. Required bool `json:"required"`
  220. Default any `json:"default" validate:"omitempty,is_basic_type"`
  221. Options []ConfigOption `json:"options" validate:"omitempty,lt=128,dive"`
  222. Label I18nObject `json:"label" validate:"required"`
  223. Help *I18nObject `json:"help" validate:"omitempty"`
  224. URL *string `json:"url" validate:"omitempty"`
  225. Placeholder *I18nObject `json:"placeholder" validate:"omitempty"`
  226. }
  227. func init() {
  228. en := en.New()
  229. uni := ut.New(en, en)
  230. translator, _ := uni.GetTranslator("en")
  231. validators.GlobalEntitiesValidator.RegisterValidation("credential_type", isCredentialType)
  232. validators.GlobalEntitiesValidator.RegisterTranslation(
  233. "credential_type",
  234. translator,
  235. func(ut ut.Translator) error {
  236. return ut.Add("credential_type", "{0} is not a valid credential type", true)
  237. },
  238. func(ut ut.Translator, fe validator.FieldError) string {
  239. t, _ := ut.T("credential_type", fe.Field())
  240. return t
  241. },
  242. )
  243. }
  244. // ValidateProviderConfigs validates the provider configs
  245. func ValidateProviderConfigs(settings map[string]any, configs []ProviderConfig) error {
  246. if len(settings) > 64 {
  247. return errors.New("too many setting fields")
  248. }
  249. configsMap := make(map[string]ProviderConfig)
  250. for _, config := range configs {
  251. configsMap[config.Name] = config
  252. }
  253. for config_name, config := range configsMap {
  254. v, ok := settings[config_name]
  255. if (!ok || v == nil) && config.Required {
  256. return errors.New("missing required setting: " + config_name)
  257. }
  258. if !ok || v == nil {
  259. continue
  260. }
  261. // check type
  262. switch config.Type {
  263. case CONFIG_TYPE_TEXT_INPUT:
  264. if _, ok := v.(string); !ok {
  265. return errors.New("setting " + config_name + " is not a string")
  266. }
  267. case CONFIG_TYPE_SECRET_INPUT:
  268. if _, ok := v.(string); !ok {
  269. return errors.New("setting " + config_name + " is not a string")
  270. }
  271. case CONFIG_TYPE_SELECT:
  272. if _, ok := v.(string); !ok {
  273. return errors.New("setting " + config_name + " is not a string")
  274. }
  275. // check if value is in options
  276. found := false
  277. for _, option := range config.Options {
  278. if v == option.Value {
  279. found = true
  280. break
  281. }
  282. }
  283. if !found {
  284. return errors.New("setting " + config_name + " is not a valid option")
  285. }
  286. case CONFIG_TYPE_BOOLEAN:
  287. if _, ok := v.(bool); !ok {
  288. return errors.New("setting " + config_name + " is not a boolean")
  289. }
  290. case CONFIG_TYPE_APP_SELECTOR:
  291. m, ok := v.(map[string]any)
  292. if !ok {
  293. return errors.New("setting " + config_name + " is not a map")
  294. }
  295. // check keys
  296. if _, ok := m["app_id"]; !ok {
  297. return errors.New("setting " + config_name + " is missing app_id")
  298. }
  299. case CONFIG_TYPE_MODEL_SELECTOR:
  300. m, ok := v.(map[string]any)
  301. if !ok {
  302. return errors.New("setting " + config_name + " is not a map")
  303. }
  304. // check keys
  305. if _, ok := m["provider"]; !ok {
  306. return errors.New("setting " + config_name + " is missing provider")
  307. }
  308. if _, ok := m["model"]; !ok {
  309. return errors.New("setting " + config_name + " is missing model")
  310. }
  311. if _, ok := m["model_type"]; !ok {
  312. return errors.New("setting " + config_name + " is missing model_type")
  313. }
  314. // check scope
  315. if config.Scope != nil {
  316. switch *config.Scope {
  317. case string(MODEL_CONFIG_SCOPE_ALL):
  318. // do nothing
  319. case string(MODEL_CONFIG_SCOPE_LLM):
  320. // do nothing
  321. case string(MODEL_CONFIG_SCOPE_TEXT_EMBEDDING):
  322. // do nothing
  323. case string(MODEL_CONFIG_SCOPE_RERANK):
  324. // score_threshold, top_n
  325. if _, ok := m["score_threshold"]; !ok {
  326. return errors.New("setting " + config_name + " is missing score_threshold")
  327. }
  328. if _, ok := m["top_n"]; !ok {
  329. return errors.New("setting " + config_name + " is missing top_n")
  330. }
  331. case string(MODEL_CONFIG_SCOPE_TTS):
  332. // voice
  333. if _, ok := m["voice"]; !ok {
  334. return errors.New("setting " + config_name + " is missing voice")
  335. }
  336. case string(MODEL_CONFIG_SCOPE_SPEECH2TEXT):
  337. // do nothing
  338. case string(MODEL_CONFIG_SCOPE_MODERATION):
  339. // do nothing
  340. case string(MODEL_CONFIG_SCOPE_VISION):
  341. // the same as llm
  342. if _, ok := m["completion_params"]; !ok {
  343. return errors.New("setting " + config_name + " is missing completion_params")
  344. }
  345. default:
  346. return errors.New("setting " + config_name + " is not a valid model config scope")
  347. }
  348. }
  349. // case CONFIG_TYPE_TOOL_SELECTOR:
  350. // m, ok := v.(map[string]any)
  351. // if !ok {
  352. // return errors.New("setting " + config_name + " is not a map")
  353. // }
  354. // // check keys
  355. // if _, ok := m["provider"]; !ok {
  356. // return errors.New("setting " + config_name + " is missing provider")
  357. // }
  358. // if _, ok := m["tool"]; !ok {
  359. // return errors.New("setting " + config_name + " is missing tool")
  360. // }
  361. // if _, ok := m["tool_type"]; !ok {
  362. // return errors.New("setting " + config_name + " is missing tool_type")
  363. // }
  364. }
  365. }
  366. return nil
  367. }