머니페니 76e3220e77
All checks were successful
Deploy to Production / deploy (push) Successful in 3m10s
feat: 에이전트 기능 추가 (LLM 서비스, 에이전트 API, 테스트)
2026-05-06 20:56:45 +09:00

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