feat: optimize integrations initial loading (#40118)

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Jingyiandautofix-ci[bot] authored and GitHub committed 2026-08-07 02:06:25 +00:00
1 parent 6f2e4d72d3
commit 5dfd83e9ab
126 files changed
+6492 -1611

No files matched your search

@@ -12,12 +12,15 @@ from configs import dify_config
from controllers.console.workspace.model_providers import (
ModelProviderCredentialApi,
ModelProviderCredentialSwitchApi,
ModelProviderCreditsApi,
ModelProviderIconApi,
ModelProviderListApi,
ModelProviderPaymentCheckoutUrlApi,
ModelProviderSummaryListApi,
ModelProviderValidateApi,
PreferredProviderTypeUpdateApi,
)
from core.entities.provider_entities import CredentialConfiguration
from graphon.model_runtime.entities.common_entities import I18nObject
from graphon.model_runtime.entities.model_entities import ModelType
from graphon.model_runtime.entities.provider_entities import ConfigurateMethod
@@ -27,9 +30,14 @@ from models.provider import ProviderType
from services.entities.model_provider_entities import (
CustomConfigurationResponse,
CustomConfigurationStatus,
ModelProviderCustomConfigurationSummaryResponse,
ModelProviderPluginSummaryResponse,
ModelProviderSummaryResponse,
ModelProviderSystemConfigurationSummaryResponse,
ProviderResponse,
SystemConfigurationResponse,
)
from services.workspace_service import EffectiveCreditPool
VALID_UUID = "123e4567-e89b-12d3-a456-426614174000"
INVALID_UUID = "123"
@@ -140,6 +148,136 @@ class TestModelProviderListApi:
assert result == {"data": []}
class TestModelProviderSummaryListApi:
def test_get_success(self, app: Flask):
api = ModelProviderSummaryListApi()
method = unwrap(api.get)
provider = ModelProviderSummaryResponse(
tenant_id="tenant1",
provider="langgenius/openai/openai",
plugin_id="langgenius/openai",
label=I18nObject(en_US="OpenAI"),
description=I18nObject(en_US="OpenAI models"),
icon_small=I18nObject(en_US="icon.svg"),
icon_small_dark=None,
supported_model_types=[ModelType.LLM],
configurate_methods=[ConfigurateMethod.PREDEFINED_MODEL],
preferred_provider_type=ProviderType.CUSTOM,
is_configured=True,
custom_configuration=ModelProviderCustomConfigurationSummaryResponse(
status=CustomConfigurationStatus.ACTIVE,
has_custom_models=True,
available_credentials=[
CredentialConfiguration(
credential_id=VALID_UUID,
credential_name="production",
),
CredentialConfiguration(
credential_id="223e4567-e89b-12d3-a456-426614174000",
credential_name="backup",
),
],
current_credential_id=VALID_UUID,
current_credential_name="production",
current_credential_usable=True,
),
system_configuration=ModelProviderSystemConfigurationSummaryResponse(enabled=False),
)
plugin = ModelProviderPluginSummaryResponse(
installation_id="installation-1",
plugin_id="langgenius/openai",
plugin_unique_identifier="langgenius/openai:1.0.0@checksum",
runtime_type="local",
source="marketplace",
version="1.0.0",
)
with (
app.test_request_context("/"),
patch(
"controllers.console.workspace.model_providers.ModelProviderService.get_provider_summary_list",
return_value=([provider], {"langgenius/openai": plugin}),
) as get_provider_summary_list,
):
result = method(api, "tenant1")
get_provider_summary_list.assert_called_once_with(tenant_id="tenant1")
assert result["data"][0]["provider"] == "langgenius/openai/openai"
assert "tenant_id" not in result["data"][0]
assert result["data"][0]["custom_configuration"] == {
"status": "active",
"has_custom_models": True,
"available_credentials": [
{
"credential_id": VALID_UUID,
"credential_name": "production",
},
{
"credential_id": "223e4567-e89b-12d3-a456-426614174000",
"credential_name": "backup",
},
],
"current_credential_id": VALID_UUID,
"current_credential_name": "production",
"current_credential_usable": True,
}
assert result["plugins"]["langgenius/openai"]["installation_id"] == "installation-1"
class TestModelProviderCreditsApi:
def test_get_success(self):
api = ModelProviderCreditsApi()
method = unwrap(api.get)
session = SimpleNamespace()
credit_pool = EffectiveCreditPool(
plan="team",
pool_type="paid",
quota_limit=-1,
quota_used=999,
next_credit_reset_date=1775001600,
)
with patch(
"controllers.console.workspace.model_providers.WorkspaceService.get_effective_credit_pool",
return_value=credit_pool,
) as get_effective_credit_pool:
result = method(api, session, "tenant1")
get_effective_credit_pool.assert_called_once_with("tenant1", session=session)
assert result == {
"pool_type": "paid",
"quota_limit": -1,
"quota_used": 999,
"remaining_credits": -1,
"is_unlimited": True,
"is_exhausted": False,
"exhausted_at": None,
"next_credit_reset_date": 1775001600,
}
def test_get_without_effective_pool(self):
api = ModelProviderCreditsApi()
method = unwrap(api.get)
session = SimpleNamespace()
with patch(
"controllers.console.workspace.model_providers.WorkspaceService.get_effective_credit_pool",
return_value=EffectiveCreditPool(),
):
result = method(api, session, "tenant1")
assert result == {
"pool_type": None,
"quota_limit": None,
"quota_used": None,
"remaining_credits": None,
"is_unlimited": False,
"is_exhausted": True,
"exhausted_at": None,
"next_credit_reset_date": None,
}
class TestModelProviderCredentialApi:
def test_get_success(self, app: Flask):
api = ModelProviderCredentialApi()
@@ -28,6 +28,7 @@ from controllers.console.workspace.plugin import (
PluginFetchMarketplacePkgApi,
PluginFetchPermissionApi,
PluginIconApi,
PluginInstalledIdsApi,
PluginInstallFromGithubApi,
PluginInstallFromMarketplaceApi,
PluginInstallFromPkgApi,
@@ -41,12 +42,16 @@ from controllers.console.workspace.plugin import (
PluginUploadFromBundleApi,
PluginUploadFromGithubApi,
PluginUploadFromPkgApi,
_list_hardcoded_builtin_tool_providers,
)
from core.plugin.entities.parameters import PluginParameterOption
from core.plugin.entities.plugin import PluginDeclaration, PluginEntity, PluginInstallation
from core.plugin.entities.plugin import PluginCategory, PluginDeclaration, PluginEntity, PluginInstallation
from core.plugin.entities.plugin_daemon import PluginInstallTask
from core.plugin.impl.exc import PluginDaemonClientSideError
from core.plugin.plugin_service import PluginService
from core.tools.entities.api_entities import ToolProviderApiEntity
from core.tools.entities.common_entities import I18nObject
from core.tools.entities.tool_entities import ToolProviderType
from models.account import (
Account,
TenantAccountRole,
@@ -445,7 +450,7 @@ class TestPluginCategoryListApi:
mock_list = MagicMock(list=[plugin_item], has_more=True)
with (
app.test_request_context("/?page=2&page_size=10"),
app.test_request_context("/?page=2&page_size=10&query=weather&tags=search&tags=rag&language=zh_Hans"),
patch(
"controllers.console.workspace.plugin.PluginService.list_by_category", return_value=mock_list
) as list_mock,
@@ -456,18 +461,75 @@ class TestPluginCategoryListApi:
):
result = method(api, "t1", "tool")
list_mock.assert_called_once()
assert list_mock.call_args.args[0] == "t1"
assert list_mock.call_args.args[1] == "tool"
assert list_mock.call_args.args[2] == 2
assert list_mock.call_args.args[3] == 10
list_mock.assert_called_once_with(
"t1",
"tool",
2,
10,
query="weather",
tags=["search", "rag"],
language="zh_Hans",
)
assert result["plugins"][0]["id"] == "entity-1"
assert result["plugins"][0]["plugin_unique_identifier"] == "test-author/test-plugin:1.0.0@checksum"
assert result["builtin_tools"][0]["id"] == "builtin"
assert result["builtin_tools"][0]["type"] == "builtin"
assert result["has_more"] is True
assert "total" not in result
builtin_mock.assert_called_once_with("t1")
builtin_mock.assert_called_once_with(
"t1",
query="weather",
tags=["search", "rag"],
language="zh_Hans",
)
def test_builtin_tool_providers_use_the_category_list_filters(self):
search_provider = ToolProviderApiEntity(
id="search-provider",
author="dify",
name="search-provider",
description=I18nObject(en_US="Search provider", zh_Hans="搜索工具"),
icon="icon.svg",
label=I18nObject(en_US="Search", zh_Hans="搜索"),
type=ToolProviderType.BUILT_IN,
labels=["search"],
)
rag_provider = ToolProviderApiEntity(
id="rag-provider",
author="dify",
name="rag-provider",
description=I18nObject(en_US="RAG provider", zh_Hans="知识库工具"),
icon="icon.svg",
label=I18nObject(en_US="RAG", zh_Hans="知识库"),
type=ToolProviderType.BUILT_IN,
labels=["rag"],
)
with (
patch("controllers.console.workspace.plugin.ToolManager.list_default_builtin_providers", return_value=[]),
patch(
"controllers.console.workspace.plugin.ToolManager.list_hardcoded_providers",
return_value=[MagicMock(), MagicMock()],
),
patch("controllers.console.workspace.plugin.is_filtered", return_value=False),
patch(
"controllers.console.workspace.plugin.ToolTransformService.builtin_provider_to_user_provider",
side_effect=[search_provider, rag_provider],
),
patch("controllers.console.workspace.plugin.ToolTransformService.repack_provider"),
patch(
"controllers.console.workspace.plugin.BuiltinToolProviderSort.sort",
side_effect=lambda providers: providers,
),
):
result = _list_hardcoded_builtin_tool_providers(
"t1",
query="搜索",
tags=["search", "weather"],
language="zh_Hans",
)
assert [provider["id"] for provider in result] == ["search-provider"]
def test_non_tool_category_does_not_include_builtin_tools(self, app: Flask):
api = PluginCategoryListApi()
@@ -739,6 +801,39 @@ class TestPluginListInstallationsFromIdsApi:
assert result == ({"code": "plugin_error", "message": "error"}, 400)
class TestPluginInstalledIdsApi:
def test_success(self, app: Flask):
api = PluginInstalledIdsApi()
method = unwrap(api.get)
with (
app.test_request_context("/?category=tool"),
patch(
"controllers.console.workspace.plugin.PluginService.list_installed_plugin_ids",
return_value=["langgenius/openai", "langgenius/anthropic"],
) as list_installed_plugin_ids,
):
result = method(api, "t1")
assert result == {"plugin_ids": ["langgenius/openai", "langgenius/anthropic"]}
list_installed_plugin_ids.assert_called_once_with("t1", PluginCategory.Tool)
def test_daemon_error(self, app: Flask):
api = PluginInstalledIdsApi()
method = unwrap(api.get)
with (
app.test_request_context("/?category=tool"),
patch(
"controllers.console.workspace.plugin.PluginService.list_installed_plugin_ids",
side_effect=PluginDaemonClientSideError("error"),
),
):
result = method(api, "t1")
assert result == ({"code": "plugin_error", "message": "error"}, 400)
class TestPluginUploadFromGithubApi:
def test_success(self, app: Flask, user):
api = PluginUploadFromGithubApi()