您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

parameters.py 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import enum
  2. from typing import Any, Optional, Union
  3. from pydantic import BaseModel, Field, field_validator
  4. from core.entities.parameter_entities import CommonParameterType
  5. from core.tools.entities.common_entities import I18nObject
  6. from core.workflow.nodes.base.entities import NumberType
  7. class PluginParameterOption(BaseModel):
  8. value: str = Field(..., description="The value of the option")
  9. label: I18nObject = Field(..., description="The label of the option")
  10. icon: Optional[str] = Field(
  11. default=None, description="The icon of the option, can be a url or a base64 encoded image"
  12. )
  13. @field_validator("value", mode="before")
  14. @classmethod
  15. def transform_id_to_str(cls, value) -> str:
  16. if not isinstance(value, str):
  17. return str(value)
  18. else:
  19. return value
  20. class PluginParameterType(enum.StrEnum):
  21. """
  22. all available parameter types
  23. """
  24. STRING = CommonParameterType.STRING.value
  25. NUMBER = CommonParameterType.NUMBER.value
  26. BOOLEAN = CommonParameterType.BOOLEAN.value
  27. SELECT = CommonParameterType.SELECT.value
  28. SECRET_INPUT = CommonParameterType.SECRET_INPUT.value
  29. FILE = CommonParameterType.FILE.value
  30. FILES = CommonParameterType.FILES.value
  31. APP_SELECTOR = CommonParameterType.APP_SELECTOR.value
  32. MODEL_SELECTOR = CommonParameterType.MODEL_SELECTOR.value
  33. TOOLS_SELECTOR = CommonParameterType.TOOLS_SELECTOR.value
  34. ANY = CommonParameterType.ANY.value
  35. DYNAMIC_SELECT = CommonParameterType.DYNAMIC_SELECT.value
  36. # deprecated, should not use.
  37. SYSTEM_FILES = CommonParameterType.SYSTEM_FILES.value
  38. # MCP object and array type parameters
  39. ARRAY = CommonParameterType.ARRAY.value
  40. OBJECT = CommonParameterType.OBJECT.value
  41. class MCPServerParameterType(enum.StrEnum):
  42. """
  43. MCP server got complex parameter types
  44. """
  45. ARRAY = "array"
  46. OBJECT = "object"
  47. class PluginParameterAutoGenerate(BaseModel):
  48. class Type(enum.StrEnum):
  49. PROMPT_INSTRUCTION = "prompt_instruction"
  50. type: Type
  51. class PluginParameterTemplate(BaseModel):
  52. enabled: bool = Field(default=False, description="Whether the parameter is jinja enabled")
  53. class PluginParameter(BaseModel):
  54. name: str = Field(..., description="The name of the parameter")
  55. label: I18nObject = Field(..., description="The label presented to the user")
  56. placeholder: Optional[I18nObject] = Field(default=None, description="The placeholder presented to the user")
  57. scope: str | None = None
  58. auto_generate: Optional[PluginParameterAutoGenerate] = None
  59. template: Optional[PluginParameterTemplate] = None
  60. required: bool = False
  61. default: Optional[Union[float, int, str]] = None
  62. min: Optional[Union[float, int]] = None
  63. max: Optional[Union[float, int]] = None
  64. precision: Optional[int] = None
  65. options: list[PluginParameterOption] = Field(default_factory=list)
  66. @field_validator("options", mode="before")
  67. @classmethod
  68. def transform_options(cls, v):
  69. if not isinstance(v, list):
  70. return []
  71. return v
  72. def as_normal_type(typ: enum.StrEnum):
  73. if typ.value in {
  74. PluginParameterType.SECRET_INPUT,
  75. PluginParameterType.SELECT,
  76. }:
  77. return "string"
  78. return typ.value
  79. def cast_parameter_value(typ: enum.StrEnum, value: Any, /):
  80. try:
  81. match typ.value:
  82. case PluginParameterType.STRING | PluginParameterType.SECRET_INPUT | PluginParameterType.SELECT:
  83. if value is None:
  84. return ""
  85. else:
  86. return value if isinstance(value, str) else str(value)
  87. case PluginParameterType.BOOLEAN:
  88. if value is None:
  89. return False
  90. elif isinstance(value, str):
  91. # Allowed YAML boolean value strings: https://yaml.org/type/bool.html
  92. # and also '0' for False and '1' for True
  93. match value.lower():
  94. case "true" | "yes" | "y" | "1":
  95. return True
  96. case "false" | "no" | "n" | "0":
  97. return False
  98. case _:
  99. return bool(value)
  100. else:
  101. return value if isinstance(value, bool) else bool(value)
  102. case PluginParameterType.NUMBER:
  103. if isinstance(value, int | float):
  104. return value
  105. elif isinstance(value, str) and value:
  106. if "." in value:
  107. return float(value)
  108. else:
  109. return int(value)
  110. case PluginParameterType.SYSTEM_FILES | PluginParameterType.FILES:
  111. if not isinstance(value, list):
  112. return [value]
  113. return value
  114. case PluginParameterType.FILE:
  115. if isinstance(value, list):
  116. if len(value) != 1:
  117. raise ValueError("This parameter only accepts one file but got multiple files while invoking.")
  118. else:
  119. return value[0]
  120. return value
  121. case PluginParameterType.MODEL_SELECTOR | PluginParameterType.APP_SELECTOR:
  122. if not isinstance(value, dict):
  123. raise ValueError("The selector must be a dictionary.")
  124. return value
  125. case PluginParameterType.TOOLS_SELECTOR:
  126. if value and not isinstance(value, list):
  127. raise ValueError("The tools selector must be a list.")
  128. return value
  129. case PluginParameterType.ANY:
  130. if value and not isinstance(value, str | dict | list | NumberType):
  131. raise ValueError("The var selector must be a string, dictionary, list or number.")
  132. return value
  133. case PluginParameterType.ARRAY:
  134. if not isinstance(value, list):
  135. # Try to parse JSON string for arrays
  136. if isinstance(value, str):
  137. try:
  138. import json
  139. parsed_value = json.loads(value)
  140. if isinstance(parsed_value, list):
  141. return parsed_value
  142. except (json.JSONDecodeError, ValueError):
  143. pass
  144. return [value]
  145. return value
  146. case PluginParameterType.OBJECT:
  147. if not isinstance(value, dict):
  148. # Try to parse JSON string for objects
  149. if isinstance(value, str):
  150. try:
  151. import json
  152. parsed_value = json.loads(value)
  153. if isinstance(parsed_value, dict):
  154. return parsed_value
  155. except (json.JSONDecodeError, ValueError):
  156. pass
  157. return {}
  158. return value
  159. case _:
  160. return str(value)
  161. except ValueError:
  162. raise
  163. except Exception:
  164. raise ValueError(f"The tool parameter value {value} is not in correct type of {as_normal_type(typ)}.")
  165. def init_frontend_parameter(rule: PluginParameter, type: enum.StrEnum, value: Any):
  166. """
  167. init frontend parameter by rule
  168. """
  169. parameter_value = value
  170. if not parameter_value and parameter_value != 0:
  171. # get default value
  172. parameter_value = rule.default
  173. if not parameter_value and rule.required:
  174. raise ValueError(f"tool parameter {rule.name} not found in tool config")
  175. if type == PluginParameterType.SELECT:
  176. # check if tool_parameter_config in options
  177. options = [x.value for x in rule.options]
  178. if parameter_value is not None and parameter_value not in options:
  179. raise ValueError(f"tool parameter {rule.name} value {parameter_value} not in options {options}")
  180. return cast_parameter_value(type, parameter_value)