You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parameters.py 7.7KB

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