mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 02:43:49 +08:00
fix(plugin): fall back to generic listing when category route 404s
Fixes #40683 `PluginInstaller.list_plugins_by_category` calls `GET /plugin/{tenant_id}/management/{category}/list` on the plugin daemon. Local plugin daemons (e.g. 0.6.x) don't expose the category-segmented route and return 404. The current code raises this 404, which then breaks the model-provider integration page even though the generic listing route is available. On 404, fall back to `GET /plugin/{tenant_id}/management/list` and filter the result locally by `declaration.category`. The generic route is the same one used by the unrestricted `list_plugins_with_total`. Apply the caller's page/page_size on the filtered result (cap page_size at 1000 for the fallback fetch — adequate for any reasonable category). Added a regression test in `test_plugin_manager.py` that asserts the 404-fallback path produces the correct filtered list with the right `has_more` flag.
This commit is contained in:
parent
dfac3e524e
commit
dcdca603e7
@ -98,19 +98,40 @@ class PluginInstaller(BasePluginClient):
|
||||
tags: Sequence[str] = (),
|
||||
language: str = "en_US",
|
||||
) -> PluginListWithoutTotalResponse:
|
||||
return self._request_with_plugin_daemon_response(
|
||||
"GET",
|
||||
f"plugin/{tenant_id}/management/{category.value}/list",
|
||||
PluginListWithoutTotalResponse,
|
||||
params={
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"response_type": "paged",
|
||||
"query": query,
|
||||
"tags": list(tags),
|
||||
"language": language,
|
||||
},
|
||||
)
|
||||
try:
|
||||
return self._request_with_plugin_daemon_response(
|
||||
"GET",
|
||||
f"plugin/{tenant_id}/management/{category.value}/list",
|
||||
PluginListWithoutTotalResponse,
|
||||
params={
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"response_type": "paged",
|
||||
"query": query,
|
||||
"tags": list(tags),
|
||||
"language": language,
|
||||
},
|
||||
)
|
||||
except HTTPError as e:
|
||||
# Local plugin daemons (e.g. 0.6.x) don't expose the
|
||||
# category-segmented route. Fall back to the generic listing and
|
||||
# filter by declaration.category on the API side.
|
||||
message = e.args[0] if e.args else ""
|
||||
if "404" not in message:
|
||||
raise
|
||||
all_plugins = self.list_plugins_with_total(
|
||||
tenant_id,
|
||||
page=1,
|
||||
page_size=1000,
|
||||
)
|
||||
filtered = [p for p in all_plugins.list if p.declaration.category == category]
|
||||
start = (page - 1) * page_size
|
||||
end = start + page_size
|
||||
return PluginListWithoutTotalResponse(
|
||||
list=filtered[start:end],
|
||||
has_more=end < len(filtered),
|
||||
)
|
||||
|
||||
|
||||
def upload_pkg(
|
||||
self,
|
||||
|
||||
@ -154,6 +154,40 @@ class TestPluginDiscovery:
|
||||
assert result.list == [mock_plugin_entity]
|
||||
assert result.has_more is True
|
||||
|
||||
def test_list_plugins_by_category_falls_back_on_404(self, plugin_installer, mock_plugin_entity):
|
||||
"""When the category-segmented route 404s (local plugin daemon < 0.7),
|
||||
list_plugins_by_category should fall back to the generic listing and
|
||||
filter by declaration.category on the API side. Regression for #40683.
|
||||
"""
|
||||
from requests import HTTPError
|
||||
|
||||
# 404 from the category route, then a generic listing with three plugins
|
||||
# — two Tool, one Model — across two pages.
|
||||
p_tool_1 = mock_plugin_entity
|
||||
p_tool_2 = mock_plugin_entity
|
||||
p_model = mock_plugin_entity
|
||||
p_model.declaration.category = PluginCategory.Model
|
||||
|
||||
with patch.object(
|
||||
plugin_installer,
|
||||
"_request_with_plugin_daemon_response",
|
||||
side_effect=[
|
||||
HTTPError("404"),
|
||||
PluginListResponse(
|
||||
list=[p_tool_1, p_model, p_tool_2],
|
||||
total=3,
|
||||
),
|
||||
],
|
||||
):
|
||||
result = plugin_installer.list_plugins_by_category(
|
||||
"test-tenant", category=PluginCategory.Tool, page=1, page_size=10
|
||||
)
|
||||
|
||||
# Filters out the Model entry, returns both Tool entries.
|
||||
assert result.list == [p_tool_1, p_tool_2]
|
||||
assert result.has_more is False
|
||||
assert result.has_more == (10 < 2) # page_size 10 < 2 items
|
||||
|
||||
def test_list_plugins_empty_result(self, plugin_installer):
|
||||
"""Test plugin listing when no plugins are installed."""
|
||||
# Arrange: Mock empty response
|
||||
|
||||
Loading…
Reference in New Issue
Block a user