fix(knowledge-fs): gate availability by deployment edition

This commit is contained in:
Stephen Zhou 2026-08-26 17:51:57 +08:00
parent c195854260
commit d7cd2f482e
No known key found for this signature in database
4 changed files with 63 additions and 4 deletions

View File

@ -180,9 +180,13 @@ class FeatureService:
system_features.enable_learn_app = dify_config.ENABLE_LEARN_APP
system_features.webapp_auth.allow_public_access = dify_config.WEBAPP_PUBLIC_ACCESS_ENABLED
system_features.enable_step_by_step_tour = dify_config.ENABLE_STEP_BY_STEP_TOUR
system_features.knowledge_fs_enabled = dify_config.KNOWLEDGE_FS_ENABLED
system_features.knowledge_fs_upload_enabled = bool(
knowledge_fs_enabled = bool(
dify_config.KNOWLEDGE_FS_ENABLED
and dify_config.DEPLOYMENT_EDITION in {DeploymentEdition.CLOUD, DeploymentEdition.ENTERPRISE}
)
system_features.knowledge_fs_enabled = knowledge_fs_enabled
system_features.knowledge_fs_upload_enabled = bool(
knowledge_fs_enabled
and dify_config.KNOWLEDGE_FS_BASE_URL
and dify_config.KNOWLEDGE_FS_CAPABILITY_V2_ENABLED
and dify_config.KNOWLEDGE_FS_CAPABILITY_V2_SIGNING_KID

View File

@ -31,6 +31,11 @@ def test_get_system_features_reads_knowledge_fs_availability(
signing_ready: bool,
upload_enabled: bool,
) -> None:
monkeypatch.setattr(
feature_service_module.dify_config,
"DEPLOYMENT_EDITION",
DeploymentEdition.CLOUD,
)
monkeypatch.setattr(feature_service_module.dify_config, "KNOWLEDGE_FS_ENABLED", enabled)
monkeypatch.setattr(feature_service_module.dify_config, "KNOWLEDGE_FS_BASE_URL", base_url)
monkeypatch.setattr(
@ -48,10 +53,31 @@ def test_get_system_features_reads_knowledge_fs_availability(
"KNOWLEDGE_FS_CAPABILITY_V2_PRIVATE_KEY_PEM",
object() if signing_ready else None,
)
result = FeatureService.get_system_features()
assert result.knowledge_fs_enabled is enabled
assert result.knowledge_fs_upload_enabled is upload_enabled
assert result.model_dump()["knowledge_fs_enabled"] is enabled
assert result.model_dump()["knowledge_fs_upload_enabled"] is upload_enabled
@pytest.mark.parametrize(
("edition", "expected"),
[(DeploymentEdition.ENTERPRISE, True), (DeploymentEdition.COMMUNITY, False)],
)
def test_get_system_features_controls_knowledge_fs_by_edition(
monkeypatch: pytest.MonkeyPatch,
edition: DeploymentEdition,
expected: bool,
) -> None:
monkeypatch.setattr(
feature_service_module.dify_config,
"DEPLOYMENT_EDITION",
edition,
)
monkeypatch.setattr(feature_service_module.dify_config, "KNOWLEDGE_FS_ENABLED", True)
monkeypatch.setattr(FeatureService, "_fulfill_params_from_enterprise", lambda _: None)
result = FeatureService.get_system_features()
assert result.knowledge_fs_enabled is expected

View File

@ -4,6 +4,15 @@ import { BlockEnum } from '@/app/components/workflow/types'
import { useAvailableNodesMetaData } from '../use-available-nodes-meta-data'
const mockIsAgentV2Enabled = vi.hoisted(() => vi.fn(() => true))
const mockKnowledgeFsEnabled = vi.hoisted(() => vi.fn(() => true))
vi.mock('jotai', () => ({
useAtomValue: () => mockKnowledgeFsEnabled(),
}))
vi.mock('@/features/system-features/state', () => ({
knowledgeFsEnabledAtom: {},
}))
vi.mock('@/context/i18n', () => ({
useDocLink: () => (path?: string) => `https://docs.dify.ai${path || ''}`,
@ -35,6 +44,10 @@ vi.mock('@/app/components/workflow/constants/node', () => ({
metaData: { type: BlockEnum.AgentV2 },
defaultValue: { title: 'Agent' },
},
{
metaData: { type: BlockEnum.KnowledgeRetrievalV2 },
defaultValue: { title: 'Knowledge Retrieval V2' },
},
],
}))
@ -63,6 +76,7 @@ describe('useAvailableNodesMetaData', () => {
beforeEach(() => {
vi.clearAllMocks()
mockIsAgentV2Enabled.mockReturnValue(true)
mockKnowledgeFsEnabled.mockReturnValue(true)
})
it('should return nodes and nodesMap', () => {
@ -146,6 +160,7 @@ describe('useAvailableNodesMetaData', () => {
expect(nodeTypes).toContain(BlockEnum.LLM)
expect(nodeTypes).toContain(BlockEnum.HttpRequest)
expect(nodeTypes).toContain(BlockEnum.KnowledgeRetrievalV2)
expect(nodeTypes).not.toContain(BlockEnum.HumanInput)
})
@ -170,4 +185,14 @@ describe('useAvailableNodesMetaData', () => {
expect(result.current.nodesMap[BlockEnum.Agent]).toBeDefined()
expect(result.current.nodesMap[BlockEnum.AgentV2]).toBeUndefined()
})
it('should hide Knowledge Retrieval V2 when KnowledgeFS is unavailable', () => {
mockKnowledgeFsEnabled.mockReturnValue(false)
const { result } = renderHook(() => useAvailableNodesMetaData())
const nodeTypes = result.current.nodes.map((node) => node.metaData.type)
expect(nodeTypes).not.toContain(BlockEnum.KnowledgeRetrievalV2)
expect(result.current.nodesMap[BlockEnum.KnowledgeRetrievalV2]).toBeUndefined()
})
})

View File

@ -1,5 +1,6 @@
import type { AvailableNodesMetaData } from '@/app/components/workflow/hooks-store/store'
import type { I18nKeysWithPrefix } from '@/types/i18n'
import { useAtomValue } from 'jotai'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import { WORKFLOW_COMMON_NODES } from '@/app/components/workflow/constants/node'
@ -9,17 +10,20 @@ import knowledgeBaseDefault from '@/app/components/workflow/nodes/knowledge-base
import { BlockEnum } from '@/app/components/workflow/types'
import { useDocLink } from '@/context/i18n'
import { isAgentV2Enabled } from '@/features/agent-v2/feature-flag'
import { knowledgeFsEnabledAtom } from '@/features/system-features/state'
export const useAvailableNodesMetaData = () => {
const { t } = useTranslation()
const docLink = useDocLink()
const agentV2Enabled = isAgentV2Enabled()
const knowledgeFsEnabled = useAtomValue(knowledgeFsEnabledAtom)
const mergedNodesMetaData = useMemo(
() => [
...WORKFLOW_COMMON_NODES.filter(
(node) =>
node.metaData.type !== BlockEnum.HumanInput &&
(knowledgeFsEnabled || node.metaData.type !== BlockEnum.KnowledgeRetrievalV2) &&
(agentV2Enabled
? node.metaData.type !== BlockEnum.Agent
: node.metaData.type !== BlockEnum.AgentV2),
@ -34,7 +38,7 @@ export const useAvailableNodesMetaData = () => {
knowledgeBaseDefault,
dataSourceEmptyDefault,
],
[agentV2Enabled],
[agentV2Enabled, knowledgeFsEnabled],
)
const helpLinkUri = useMemo(