dify/api/models/workflow_features.py
Yansong Zhang 44491e427c feat(api): enable all sandbox/skill controller routes and resolve dependencies (P0)
Resolve the full dependency chain to enable all previously disabled controllers:

Enabled routes:
- sandbox_files: sandbox file browser API
- sandbox_providers: sandbox provider management API
- app_asset: app asset management API
- skills: skill extraction API
- CLI API blueprint: DifyCli callback endpoints (/cli/api/*)

Dependencies extracted (64 files, ~8000 lines):
- models/sandbox.py, models/app_asset.py: DB models
- core/zip_sandbox/: zip-based sandbox execution
- core/session/: CLI API session management
- core/memory/: base memory + node token buffer
- core/helper/creators.py: helper utilities
- core/llm_generator/: context models, output models, utils
- core/workflow/nodes/command/: command node type
- core/workflow/nodes/file_upload/: file upload node type
- core/app/entities/: app_asset_entities, app_bundle_entities, llm_generation_entities
- services/: asset_content, skill, workflow_collaboration, workflow_comment
- controllers/console/app/error.py: AppAsset error classes
- core/tools/utils/system_encryption.py

Import fixes:
- dify_graph.enums -> graphon.enums in skill_service.py
- get_signed_file_url_for_plugin -> get_signed_file_url in cli_api.py

All 5 controllers verified: import OK, Flask starts successfully.
46 existing tests still pass.

Made-with: Cursor
2026-04-09 09:36:16 +08:00

27 lines
833 B
Python

from collections.abc import Mapping
from dataclasses import dataclass
from enum import StrEnum
from typing import Any
class WorkflowFeatures(StrEnum):
SANDBOX = "sandbox"
SPEECH_TO_TEXT = "speech_to_text"
TEXT_TO_SPEECH = "text_to_speech"
RETRIEVER_RESOURCE = "retriever_resource"
SENSITIVE_WORD_AVOIDANCE = "sensitive_word_avoidance"
FILE_UPLOAD = "file_upload"
SUGGESTED_QUESTIONS_AFTER_ANSWER = "suggested_questions_after_answer"
@dataclass(frozen=True)
class WorkflowFeature:
enabled: bool
config: Mapping[str, Any]
@classmethod
def from_dict(cls, data: Mapping[str, Any] | None) -> "WorkflowFeature":
if data is None or not isinstance(data, dict):
return cls(enabled=False, config={})
return cls(enabled=bool(data.get("enabled", False)), config=data)