mirror of
https://github.com/langgenius/dify.git
synced 2026-10-24 12:04:30 +08:00
feat(api): isolate credentials from local packages (#39957)
This commit is contained in:
@@ -48,6 +48,7 @@ from core.plugin.entities.plugin_daemon import (
|
||||
PluginInstallTaskStatus,
|
||||
PluginListResponse,
|
||||
PluginListWithoutTotalResponse,
|
||||
PluginModelProviderDeclaration,
|
||||
PluginModelProviderEntity,
|
||||
PluginVerification,
|
||||
)
|
||||
@@ -58,7 +59,6 @@ from core.plugin.impl.model import PluginModelClient
|
||||
from core.plugin.impl.plugin import PluginInstaller
|
||||
from extensions.ext_database import db
|
||||
from extensions.ext_redis import redis_client
|
||||
from graphon.model_runtime.entities.provider_entities import ProviderEntity
|
||||
from models.provider import Provider, ProviderCredential, TenantPreferredModelProvider
|
||||
from models.provider_ids import GenericProviderID, ModelProviderID
|
||||
from services.enterprise.plugin_manager_service import (
|
||||
@@ -69,7 +69,9 @@ from services.errors.plugin import PluginInstallationForbiddenError
|
||||
from services.feature_service import FeatureService, PluginInstallationPermissionModel, PluginInstallationScope
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_provider_entities_adapter: TypeAdapter[list[ProviderEntity]] = TypeAdapter(list[ProviderEntity])
|
||||
_provider_entities_adapter: TypeAdapter[list[PluginModelProviderDeclaration]] = TypeAdapter(
|
||||
list[PluginModelProviderDeclaration]
|
||||
)
|
||||
|
||||
|
||||
class _RedisLock(Protocol):
|
||||
@@ -146,11 +148,44 @@ class PluginService:
|
||||
return provider.provider
|
||||
|
||||
@classmethod
|
||||
def _to_provider_entity(cls, provider: PluginModelProviderEntity) -> ProviderEntity:
|
||||
declaration = provider.declaration.model_copy(deep=True)
|
||||
declaration.provider = f"{provider.plugin_id}/{provider.provider}"
|
||||
declaration.provider_name = cls._get_provider_short_name_alias(provider)
|
||||
return declaration
|
||||
def _to_provider_entity(
|
||||
cls,
|
||||
provider: PluginModelProviderEntity,
|
||||
installation_source: PluginInstallationSource | None,
|
||||
) -> PluginModelProviderDeclaration:
|
||||
return PluginModelProviderDeclaration.model_validate(
|
||||
{
|
||||
**provider.declaration.model_dump(),
|
||||
"provider": f"{provider.plugin_id}/{provider.provider}",
|
||||
"provider_name": cls._get_provider_short_name_alias(provider),
|
||||
"plugin_unique_identifier": provider.plugin_unique_identifier,
|
||||
"installation_source": installation_source,
|
||||
}
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _resolve_model_provider_installation_sources(
|
||||
cls,
|
||||
tenant_id: str,
|
||||
providers: Sequence[PluginModelProviderEntity],
|
||||
) -> Mapping[str, PluginInstallationSource]:
|
||||
unresolved_plugin_ids = list(
|
||||
dict.fromkeys(provider.plugin_id for provider in providers if provider.installation_source is None)
|
||||
)
|
||||
if not unresolved_plugin_ids:
|
||||
return {}
|
||||
|
||||
try:
|
||||
installations = cls.list_installations_from_ids(tenant_id, unresolved_plugin_ids)
|
||||
except Exception:
|
||||
logger.warning(
|
||||
"Failed to resolve model provider installation sources for tenant %s.",
|
||||
tenant_id,
|
||||
exc_info=True,
|
||||
)
|
||||
return {}
|
||||
|
||||
return {installation.plugin_unique_identifier: installation.source for installation in installations}
|
||||
|
||||
@classmethod
|
||||
def _encode_plugin_model_providers_cache_payload(cls, payload: bytes) -> bytes:
|
||||
@@ -206,7 +241,7 @@ class PluginService:
|
||||
@classmethod
|
||||
def _load_cached_plugin_model_providers_for_generation(
|
||||
cls, tenant_id: str, generation: int | None
|
||||
) -> tuple[tuple[ProviderEntity, ...] | None, bool]:
|
||||
) -> tuple[tuple[PluginModelProviderDeclaration, ...] | None, bool]:
|
||||
if generation is None:
|
||||
return None, False
|
||||
|
||||
@@ -253,7 +288,7 @@ class PluginService:
|
||||
|
||||
@classmethod
|
||||
def _store_cached_plugin_model_providers(
|
||||
cls, tenant_id: str, generation: int, providers: Sequence[ProviderEntity]
|
||||
cls, tenant_id: str, generation: int, providers: Sequence[PluginModelProviderDeclaration]
|
||||
) -> None:
|
||||
cache_key = cls._get_plugin_model_providers_cache_key(tenant_id, generation)
|
||||
try:
|
||||
@@ -437,14 +472,22 @@ class PluginService:
|
||||
@classmethod
|
||||
def _fetch_plugin_model_providers_uncached(
|
||||
cls, tenant_id: str, client: PluginModelClient | None
|
||||
) -> tuple[ProviderEntity, ...]:
|
||||
) -> tuple[PluginModelProviderDeclaration, ...]:
|
||||
model_client = client or PluginModelClient()
|
||||
return tuple(cls._to_provider_entity(provider) for provider in model_client.fetch_model_providers(tenant_id))
|
||||
providers = model_client.fetch_model_providers(tenant_id)
|
||||
installation_sources = cls._resolve_model_provider_installation_sources(tenant_id, providers)
|
||||
return tuple(
|
||||
cls._to_provider_entity(
|
||||
provider,
|
||||
provider.installation_source or installation_sources.get(provider.plugin_unique_identifier),
|
||||
)
|
||||
for provider in providers
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _fetch_and_cache_plugin_model_providers(
|
||||
cls, tenant_id: str, client: PluginModelClient | None, *, refresh_generation: int | None
|
||||
) -> tuple[ProviderEntity, ...]:
|
||||
) -> tuple[PluginModelProviderDeclaration, ...]:
|
||||
providers = cls._fetch_plugin_model_providers_uncached(tenant_id, client)
|
||||
generation = cls._load_plugin_model_providers_generation(tenant_id)
|
||||
if generation is not None and generation == refresh_generation:
|
||||
@@ -467,7 +510,7 @@ class PluginService:
|
||||
@classmethod
|
||||
def fetch_plugin_model_providers(
|
||||
cls, *, tenant_id: str, client: PluginModelClient | None = None
|
||||
) -> Sequence[ProviderEntity]:
|
||||
) -> Sequence[PluginModelProviderDeclaration]:
|
||||
"""
|
||||
Fetch plugin model providers through the tenant-scoped plugin cache.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user