Add per-agent skill workspaces and TraderView management
This commit is contained in:
79
backend/agents/skill_metadata.py
Normal file
79
backend/agents/skill_metadata.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Skill metadata parsing helpers for SKILL.md files."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SkillMetadata:
|
||||
"""Parsed metadata for a skill package."""
|
||||
|
||||
skill_name: str
|
||||
path: Path
|
||||
source: str
|
||||
name: str
|
||||
description: str
|
||||
version: str = ""
|
||||
tools: List[str] = field(default_factory=list)
|
||||
|
||||
|
||||
def parse_skill_metadata(skill_dir: Path, source: str) -> SkillMetadata:
|
||||
"""Parse SKILL.md frontmatter with a forgiving schema."""
|
||||
skill_name = skill_dir.name
|
||||
skill_file = skill_dir / "SKILL.md"
|
||||
if not skill_file.exists():
|
||||
return SkillMetadata(
|
||||
skill_name=skill_name,
|
||||
path=skill_dir,
|
||||
source=source,
|
||||
name=skill_name,
|
||||
description="",
|
||||
)
|
||||
|
||||
raw = skill_file.read_text(encoding="utf-8").strip()
|
||||
frontmatter = {}
|
||||
body = raw
|
||||
if raw.startswith("---"):
|
||||
parts = raw.split("---", 2)
|
||||
if len(parts) >= 3:
|
||||
try:
|
||||
frontmatter = yaml.safe_load(parts[1].strip()) or {}
|
||||
except yaml.YAMLError:
|
||||
frontmatter = {}
|
||||
body = parts[2].strip()
|
||||
if not isinstance(frontmatter, dict):
|
||||
frontmatter = {}
|
||||
|
||||
description = str(frontmatter.get("description") or "").strip()
|
||||
if not description and body:
|
||||
description = body.splitlines()[0].strip().lstrip("#").strip()
|
||||
|
||||
return SkillMetadata(
|
||||
skill_name=skill_name,
|
||||
path=skill_dir,
|
||||
source=source,
|
||||
name=str(frontmatter.get("name") or skill_name).strip() or skill_name,
|
||||
description=description,
|
||||
version=str(frontmatter.get("version") or "").strip(),
|
||||
tools=_string_list(frontmatter.get("tools")),
|
||||
)
|
||||
|
||||
|
||||
def _string_list(value) -> List[str]:
|
||||
if isinstance(value, str):
|
||||
item = value.strip()
|
||||
return [item] if item else []
|
||||
if not isinstance(value, list):
|
||||
return []
|
||||
seen: List[str] = []
|
||||
for item in value:
|
||||
if not isinstance(item, str):
|
||||
continue
|
||||
normalized = item.strip()
|
||||
if normalized and normalized not in seen:
|
||||
seen.append(normalized)
|
||||
return seen
|
||||
Reference in New Issue
Block a user