mirror of
https://github.com/langgenius/dify.git
synced 2026-05-13 08:57:28 +08:00
Port the complete infrastructure for agent sandbox execution and skill system: Sandbox & Virtual Environment (core/sandbox/, core/virtual_environment/): - Sandbox entity with lifecycle management (ready/failed/cancelled states) - SandboxBuilder with fluent API for configuring providers - 5 VM providers: Local, SSH, Docker, E2B, AWS CodeInterpreter - VirtualEnvironment base with command execution, file transfer, transport layers - Channel transport: pipe, queue, socket implementations - Bash session management and DifyCli binary integration - Storage: archive storage, file storage, noop storage, presign storage - Initializers: DifyCli, AppAssets, DraftAppAssets, Skills - Inspector: file browser, archive/runtime source, script utils - Security: encryption utils, debug helpers Skill & App Assets (core/skill/, core/app_assets/, core/app_bundle/): - Skill entity and manager - App asset accessor, builder pipeline (file, skill builders) - App bundle source zip extractor - Storage and converter utilities API Endpoints: - CLI API blueprint (controllers/cli_api/) for sandbox callback - Sandbox provider management (workspace/sandbox_providers) - Sandbox file browser (console/sandbox_files) - App asset management (console/app/app_asset) - Skill management (console/app/skills) - Storage file endpoints (controllers/files/storage_files) Services: - Sandbox service, provider service, file service - App asset service, app bundle service Config: - CliApiConfig, CreatorsPlatformConfig, CollaborationConfig - FILES_API_URL for sandbox file access Note: Controller route registration temporarily commented out (marked TODO) pending resolution of deep dependency chains (socketio, workflow_comment, command node, etc.). Core sandbox modules are fully ported and syntax-validated. 110 files changed, 10,549 insertions. Made-with: Cursor
95 lines
3.2 KiB
Python
95 lines
3.2 KiB
Python
from typing import TYPE_CHECKING
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
|
|
from core.app.entities.app_asset_entities import AppAssetFileTree
|
|
from core.skill.entities.skill_metadata import FileReference
|
|
from core.skill.entities.tool_dependencies import ToolDependencies, ToolDependency
|
|
|
|
if TYPE_CHECKING:
|
|
from core.skill.entities.skill_metadata import SkillMetadata
|
|
|
|
|
|
class SkillDependance(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
tools: ToolDependencies = Field(description="Direct tool dependencies parsed from this skill only")
|
|
|
|
files: set[FileReference] = Field(
|
|
default_factory=set,
|
|
description="Direct file references parsed from this skill only",
|
|
)
|
|
|
|
def __or__(self, other: "SkillDependance") -> "SkillDependance":
|
|
return SkillDependance(tools=self.tools.merge(other.tools), files=self.files | other.files)
|
|
|
|
@staticmethod
|
|
def from_metadata(metadata: "SkillMetadata") -> "SkillDependance":
|
|
"""Convert parsed metadata into direct tool/file dependency model."""
|
|
from core.skill.entities.skill_metadata import ToolReference
|
|
|
|
dep_map: dict[str, ToolDependency] = {}
|
|
ref_map: dict[str, ToolReference] = {}
|
|
|
|
for tool_ref in metadata.tools.values():
|
|
dep_map.setdefault(
|
|
tool_ref.tool_id(),
|
|
ToolDependency(
|
|
type=tool_ref.type,
|
|
provider=tool_ref.provider,
|
|
tool_name=tool_ref.tool_name,
|
|
enabled=tool_ref.enabled,
|
|
),
|
|
)
|
|
ref_map.setdefault(tool_ref.uuid, tool_ref)
|
|
|
|
return SkillDependance(
|
|
tools=ToolDependencies(
|
|
dependencies=[dep_map[key] for key in sorted(dep_map.keys())],
|
|
references=[ref_map[key] for key in sorted(ref_map.keys())],
|
|
),
|
|
files=metadata.files,
|
|
)
|
|
|
|
|
|
class Skill(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
skill_id: str = Field(description="Unique identifier for this skill, same with skill_id")
|
|
|
|
direct_dependance: SkillDependance = Field(description="Direct dependencies parsed from this skill only")
|
|
|
|
dependance: SkillDependance = Field(description="All dependencies including transitive closure")
|
|
|
|
content: str = Field(description="Resolved content with all references replaced")
|
|
|
|
@property
|
|
def tools(self) -> ToolDependencies:
|
|
return self.dependance.tools
|
|
|
|
|
|
class SkillBundle(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
asset_tree: AppAssetFileTree = Field(description="Asset tree for this bundle")
|
|
|
|
assets_id: str = Field(description="Assets ID this bundle belongs to")
|
|
|
|
skills: dict[str, Skill] = Field(default_factory=dict)
|
|
|
|
@property
|
|
def entries(self) -> dict[str, Skill]:
|
|
return self.skills
|
|
|
|
def get(self, skill_id: str) -> Skill | None:
|
|
return self.skills.get(skill_id)
|
|
|
|
def get_tool_dependencies(self) -> ToolDependencies:
|
|
merged = ToolDependencies()
|
|
for skill in self.skills.values():
|
|
merged = merged.merge(skill.dependance.tools)
|
|
return merged
|
|
|
|
def put(self, skill: Skill) -> None:
|
|
self.skills[skill.skill_id] = skill
|