f80ac961ec
* fix(harness): restore legacy skills path fallback (#2694) * fix(format): make format * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
73 lines
2.5 KiB
Python
73 lines
2.5 KiB
Python
import os
|
|
from pathlib import Path
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
from deerflow.config.runtime_paths import project_root, resolve_path
|
|
|
|
|
|
def _legacy_skills_candidates() -> tuple[Path, ...]:
|
|
"""Return source-tree skills locations for monorepo compatibility."""
|
|
backend_dir = Path(__file__).resolve().parents[4]
|
|
repo_root = backend_dir.parent
|
|
return (repo_root / "skills",)
|
|
|
|
|
|
class SkillsConfig(BaseModel):
|
|
"""Configuration for skills system"""
|
|
|
|
use: str = Field(
|
|
default="deerflow.skills.storage.local_skill_storage:LocalSkillStorage",
|
|
description="Class path of the SkillStorage implementation.",
|
|
)
|
|
path: str | None = Field(
|
|
default=None,
|
|
description=("Path to skills directory. If not specified, defaults to `skills` under the caller project root, falling back to the legacy repo-root location for monorepo compatibility."),
|
|
)
|
|
container_path: str = Field(
|
|
default="/mnt/skills",
|
|
description="Path where skills are mounted in the sandbox container",
|
|
)
|
|
|
|
def get_skills_path(self) -> Path:
|
|
"""
|
|
Get the resolved skills directory path.
|
|
|
|
Resolution order:
|
|
1. Explicit ``path`` field
|
|
2. ``DEER_FLOW_SKILLS_PATH`` environment variable
|
|
3. ``skills`` under the caller project root (``project_root()``)
|
|
4. Legacy repo-root candidates for monorepo compatibility (``_legacy_skills_candidates``)
|
|
|
|
When none of (3) or (4) exist on disk, the project-root default is returned so callers
|
|
can still surface a stable "no skills" location without raising.
|
|
"""
|
|
if self.path:
|
|
# Use configured path (can be absolute or relative to project root)
|
|
return resolve_path(self.path)
|
|
if env_path := os.getenv("DEER_FLOW_SKILLS_PATH"):
|
|
return resolve_path(env_path)
|
|
|
|
project_default = project_root() / "skills"
|
|
if project_default.is_dir():
|
|
return project_default
|
|
|
|
for candidate in _legacy_skills_candidates():
|
|
if candidate.is_dir():
|
|
return candidate
|
|
|
|
return project_default
|
|
|
|
def get_skill_container_path(self, skill_name: str, category: str = "public") -> str:
|
|
"""
|
|
Get the full container path for a specific skill.
|
|
|
|
Args:
|
|
skill_name: Name of the skill (directory name)
|
|
category: Category of the skill (public or custom)
|
|
|
|
Returns:
|
|
Full path to the skill in the container
|
|
"""
|
|
return f"{self.container_path}/{category}/{skill_name}"
|