Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/dify_plugin/entities/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ class ParameterOption(BaseModel):
default=None,
description="The icon of the option, can be a URL or a base64 encoded string",
)
children: list["ParameterOption"] | None = Field(
default=None,
description="The children options of the option, used for tree select",
)

@field_validator("value", mode="before")
@classmethod
Expand All @@ -75,3 +79,6 @@ class Type(StrEnum):
)
class ParameterTemplate(BaseModel):
enabled: bool = Field(..., description="Whether the parameter is jinja enabled")


ParameterOption.model_rebuild()
1 change: 1 addition & 0 deletions src/dify_plugin/entities/provider_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class CommonParameterType(Enum):
OBJECT = "object"
ARRAY = "array"
DYNAMIC_SELECT = "dynamic-select"
DYNAMIC_TREE_SELECT = "dynamic-tree-select"


@docs(
Expand Down
2 changes: 2 additions & 0 deletions src/dify_plugin/entities/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class ToolParameterType(StrEnum):
OBJECT = CommonParameterType.OBJECT.value
ARRAY = CommonParameterType.ARRAY.value
DYNAMIC_SELECT = CommonParameterType.DYNAMIC_SELECT.value
DYNAMIC_TREE_SELECT = CommonParameterType.DYNAMIC_TREE_SELECT.value

class ToolParameterForm(Enum):
SCHEMA = "schema" # should be set while adding tool
Expand Down Expand Up @@ -115,6 +116,7 @@ class ToolParameterForm(Enum):
)
llm_description: str | None = None
required: bool | None = False
multiple: bool | None = False
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The multiple field is added here, but the default field on line 120 still uses a restricted type hint (int | float | str | None). Since multiple=True implies a list, and other types like BOOLEAN or CHECKBOX require bool or list, the default type hint should be updated to int | float | str | bool | list | None for consistency and correct validation.

default: int | float | str | None = None
min: float | int | None = None
max: float | int | None = None
Expand Down
3 changes: 3 additions & 0 deletions src/dify_plugin/interfaces/tool/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ def _fetch_parameter_options(self, parameter: str) -> list[ParameterOption]:
To be implemented by subclasses.

Also, it's optional to implement, that's why it's not an abstract method.

For `dynamic-tree-select` parameters, you can return options with nested
`children` to build a hierarchical selection tree.
"""
msg = (
"This plugin should implement `_fetch_parameter_options` method "
Expand Down
2 changes: 1 addition & 1 deletion src/dify_plugin/protocol/dynamic_select.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def fetch_parameter_options(self, parameter: str) -> list[ParameterOption]:
Fetch the parameter options.

Classes that implement this protocol should have at least one
parameter with type `dynamic-select`.
parameter with type `dynamic-select` or `dynamic-tree-select`.

At some scenarios, we don't know the available options,
it could not be defined in the plugin directly.
Expand Down
56 changes: 56 additions & 0 deletions tests/interfaces/tool/test_costruct_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,59 @@ def _fetch_parameter_options(self, parameter: str) -> list[ParameterOption]:
assert tool.fetch_parameter_options("test") == [
ParameterOption(value="test", label=I18nObject(en_us="test"))
]


def test_fetch_tree_parameter_options() -> None:
"""
Test that the Tool can fetch tree parameter options with nested children
"""

class ToolImpl(Tool):
def _invoke(
self, tool_parameters: Mapping
) -> Generator[ToolInvokeMessage, None, None]:
del tool_parameters
yield self.create_text_message("Hello, world!")

def _fetch_parameter_options(self, parameter: str) -> list[ParameterOption]:
del parameter
return [
ParameterOption(
value="root",
label=I18nObject(en_us="Root"),
children=[
ParameterOption(
value="child1", label=I18nObject(en_us="Child 1")
),
ParameterOption(
value="child2",
label=I18nObject(en_us="Child 2"),
children=[
ParameterOption(
value="grandchild",
label=I18nObject(en_us="Grandchild"),
)
],
),
],
)
]

session = Session(
session_id="test",
executor=ThreadPoolExecutor(max_workers=1),
reader=StdioRequestReader(),
writer=StdioResponseWriter(),
)

tool = ToolImpl(
runtime=ToolRuntime(credentials={}, user_id="test", session_id="test"),
session=session,
)
options = tool.fetch_parameter_options("test")
assert len(options) == 1
assert options[0].value == "root"
assert options[0].children is not None
assert len(options[0].children) == 2
assert options[0].children[1].children is not None
assert options[0].children[1].children[0].value == "grandchild"