Files
AstrBot/astrbot/_internal/skills/parser.py
LIghtJUNction f2c0c2a9de feat: add _internal modules for MCP, Skills, and Tools
This commit adds the _internal package structure for AstrBot's
standardized MCP & Skills support:

astrbot/_internal/mcp/:
- MCPClient for MCP server connections
- MCPTool wrapper for MCP tools
- MCP configuration management

astrbot/_internal/skills/:
- SkillManager for skill lifecycle
- Skill parser and loader
- SkillToToolConverter for tool-based skills
- Prompt builder for skills

astrbot/_internal/tools/:
- ToolSchema, FunctionTool, ToolSet base definitions
- FunctionToolManager for tool registry
- Builtin tools (cron, send_message, kb_query)
- Tool providers (internal, plugin, computer)

astrbot/api/:
- Public API for tools (ToolRegistry, tool decorator)
- Public API for MCP (get_mcp_servers, register_mcp_server)
- Public API for skills (get_skill_manager, skill_to_tool)
2026-03-23 12:48:34 +08:00

82 lines
1.9 KiB
Python

"""SKILL.md parser for extracting frontmatter and content."""
from __future__ import annotations
from pathlib import Path
import yaml
def parse_frontmatter(text: str) -> dict:
"""Extract metadata from YAML frontmatter.
Expects the standard SKILL.md format used by OpenAI Codex CLI and
Anthropic Claude Skills::
---
name: my-skill
description: What this skill does and when to use it.
input_schema: ...
output_schema: ...
---
"""
if not text.startswith("---"):
return {}
lines = text.splitlines()
if not lines or lines[0].strip() != "---":
return {}
end_idx = None
for i in range(1, len(lines)):
if lines[i].strip() == "---":
end_idx = i
break
if end_idx is None:
return {}
frontmatter = "\n".join(lines[1:end_idx])
try:
payload = yaml.safe_load(frontmatter) or {}
except yaml.YAMLError:
return {}
if not isinstance(payload, dict):
return {}
return payload
def parse_skill_markdown(path: Path) -> dict:
"""Parse a SKILL.md file and return frontmatter + content.
Args:
path: Path to the SKILL.md file
Returns:
dict with keys: frontmatter (dict), content (str)
"""
try:
text = path.read_text(encoding="utf-8")
except Exception:
return {"frontmatter": {}, "content": ""}
frontmatter = parse_frontmatter(text)
# Extract content after frontmatter
if text.startswith("---"):
lines = text.splitlines()
end_idx = None
for i in range(1, len(lines)):
if lines[i].strip() == "---":
end_idx = i
break
if end_idx is not None:
content = "\n".join(lines[end_idx + 1 :]).strip()
else:
content = ""
else:
content = text
return {
"frontmatter": frontmatter,
"content": content,
}