62 lines
2.0 KiB
Python
62 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
import yaml
|
|
|
|
from app.agents.skills.types import Skill, SkillMetadata, SkillSource
|
|
|
|
|
|
class SkillLoader:
|
|
"""SKILL.md 파일 파싱 및 로딩."""
|
|
|
|
@staticmethod
|
|
def parse_skill_file(content: str, path: str, source: SkillSource) -> Skill:
|
|
"""YAML frontmatter + markdown body를 파싱하여 Skill 객체 반환."""
|
|
frontmatter, instructions = SkillLoader._split_frontmatter(content)
|
|
meta = yaml.safe_load(frontmatter) or {}
|
|
return Skill(
|
|
name=meta.get("name", ""),
|
|
description=meta.get("description", ""),
|
|
path=path,
|
|
source=source,
|
|
instructions=instructions.strip(),
|
|
)
|
|
|
|
@staticmethod
|
|
def load_from_path(path: str | Path, source: SkillSource) -> Skill:
|
|
"""파일 경로에서 Skill을 로드."""
|
|
p = Path(path)
|
|
content = p.read_text(encoding="utf-8")
|
|
return SkillLoader.parse_skill_file(content, str(p), source)
|
|
|
|
@staticmethod
|
|
def extract_metadata(path: str | Path, source: SkillSource) -> SkillMetadata:
|
|
"""frontmatter만 파싱하여 경량 메타데이터 반환."""
|
|
p = Path(path)
|
|
content = p.read_text(encoding="utf-8")
|
|
frontmatter, _ = SkillLoader._split_frontmatter(content)
|
|
meta = yaml.safe_load(frontmatter) or {}
|
|
return SkillMetadata(
|
|
name=meta.get("name", ""),
|
|
description=meta.get("description", ""),
|
|
path=str(p),
|
|
source=source,
|
|
)
|
|
|
|
@staticmethod
|
|
def _split_frontmatter(content: str) -> tuple[str, str]:
|
|
"""--- 마커 사이의 YAML frontmatter와 나머지 body를 분리."""
|
|
stripped = content.strip()
|
|
if not stripped.startswith("---"):
|
|
return "", content
|
|
|
|
# 두 번째 --- 찾기
|
|
end_idx = stripped.find("---", 3)
|
|
if end_idx == -1:
|
|
return "", content
|
|
|
|
frontmatter = stripped[3:end_idx].strip()
|
|
body = stripped[end_idx + 3 :]
|
|
return frontmatter, body
|