def from_markdown(markdown: str) -> AgentScriptSpecification:
"""Convert the markdown to an agent script specification."""
# extract frontmatter as Frontmatter
_, frontmatter_markdown, body_markdown = re.split(r"^--- *\n(.*?)\n--- *\n", markdown, flags=re.DOTALL)
# extract name, description, tools, model from frontmatter
name_match = re.search(r"^name: (.*?)$", frontmatter_markdown, re.MULTILINE)
description_match = re.search(r"^description: (.*?)$", frontmatter_markdown, re.MULTILINE)
tools_match = re.search(r"^tools: (.*?)$", frontmatter_markdown, re.MULTILINE)
model_match = re.search(r"^model: (.*?)$", frontmatter_markdown, re.MULTILINE)
frontmatter_dict = {
"name": name_match.group(1) if name_match else "",
"description": description_match.group(1) if description_match else "",
"tools": tools_match.group(1) if tools_match else "",
"model": model_match.group(1) if model_match else "",
}
# parse body markdown to ast
md = mistune.create_markdown(renderer="ast")
ast = md(body_markdown)
frontmatter_model = Frontmatter(
name=str(frontmatter_dict["name"]),
description=str(frontmatter_dict["description"]),
tools=set(str(frontmatter_dict["tools"]).split(", ")),
model=str(frontmatter_dict["model"]),
)
data: dict[str, object] = {
"role": "",
"expertise": "",
"mission": "",
"key_capabilities": {},
"mcp_integration": None,
"tool_usages": None,
"communication_protocols": None,
"interaction_model": None,
"core_competencies": None,
"guiding_principles": None,
"rules": None,
"approach": None,
"deliverables": None,
}
# Type cast ast to proper type for processing
ast_nodes = list(ast) if isinstance(ast, list) else []
idx = 0
while idx < len(ast_nodes):
node = ast_nodes[idx]
if not isinstance(node, dict) or node.get("type") != "heading":
idx += 1
continue
attrs = node.get("attrs", {})
if not isinstance(attrs, dict):
idx += 1
continue
lvl = attrs.get("level", 0)
heading = _slug(_txt(node))
match lvl, heading:
# ───── H1 sections ─────
case 1, _: # Any H1 is treated as the name
data["name"] = _txt(node).strip()
idx += 1
# ───── H2 sections ─────
case 2, Section.ROLE:
data["role"], idx = _collect_paragraph(ast_nodes, idx + 1)
case 2, Section.EXPERTISE:
data["expertise"], idx = _collect_paragraph(ast_nodes, idx + 1)
case 2, Section.MISSION:
data["mission"], idx = _collect_paragraph(ast_nodes, idx + 1)
case 2, Section.INTERACTION_MODEL:
data["interaction_model"], idx = _parse_interaction_model(ast_nodes, idx + 1)
case 2, Section.DELIVERABLES:
# Skip initial blank lines
j = idx + 1
while j < len(ast_nodes) and ast_nodes[j]["type"] == "blank_line":
j += 1
# Skip the explanatory paragraph (first paragraph only)
if j < len(ast_nodes) and ast_nodes[j]["type"] == "paragraph":
j += 1
data["deliverables"], idx = _collect_list_dict(ast_nodes, j)
# ───── H3 sections ─────
case 3, Section.KEY_CAPABILITIES:
data["key_capabilities"], idx = _collect_list_dict(ast_nodes, idx + 1)
case 3, Section.MCP_INTEGRATION:
data["mcp_integration"], idx = _collect_list_dict(ast_nodes, idx + 1)
case 3, Section.TOOL_USAGE:
data["tool_usages"], idx = _collect_list_dict(ast_nodes, idx + 1)
case 3, Section.COMM_PROTOCOL:
data["communication_protocols"], idx = _collect_paragraph(ast_nodes, idx + 1)
case 3, Section.CORE_COMPETENCIES:
data["core_competencies"], idx = _collect_list_dict(ast_nodes, idx + 1)
case 3, Section.GUIDING_PRINCIPLES:
data["guiding_principles"], idx = _collect_list_dict(ast_nodes, idx + 1)
case 3, Section.APPROACH:
data["approach"], idx = _collect_list_dict(ast_nodes, idx + 1)
case 3, Section.RULES:
idx += 1
rules: dict[str, list[str]] = {}
# Skip blank lines to get to H4 headings
while idx < len(ast_nodes) and ast_nodes[idx].get("type") == "blank_line":
idx += 1
while (
idx < len(ast_nodes)
and isinstance(ast_nodes[idx], dict)
and ast_nodes[idx].get("type") == "heading"
and isinstance(ast_nodes[idx].get("attrs"), dict)
and ast_nodes[idx]["attrs"].get("level") == 4
):
sub = _slug(_txt(ast_nodes[idx]))
key = "DO" if sub == "do" else "DO-NOT"
rules[key], idx = _collect_list_items(ast_nodes, idx + 1)
data["rules"] = rules or None
# fallback
case _:
idx += 1
spec = AgentScriptSpecification(
frontmatter=frontmatter_model,
name=str(data["name"]),
role=str(data["role"]) if data["role"] else "",
expertise=str(data["expertise"]) if data["expertise"] else "",
mission=str(data["mission"]) if data["mission"] else "",
key_capabilities=data["key_capabilities"] if isinstance(data["key_capabilities"], dict) else {},
mcp_integration=data["mcp_integration"] if isinstance(data["mcp_integration"], dict) else None,
tool_usages=data["tool_usages"] if isinstance(data["tool_usages"], dict) else None,
communication_protocols=str(data["communication_protocols"]) if data["communication_protocols"] else None,
interaction_model=data["interaction_model"]
if isinstance(data["interaction_model"], InteractionModel)
else InteractionModel(description="", phases={}),
core_competencies=data["core_competencies"] if isinstance(data["core_competencies"], dict) else None,
guiding_principles=data["guiding_principles"] if isinstance(data["guiding_principles"], dict) else None,
rules=cast(
dict[Literal["DO", "DO-NOT"], list[str]] | None,
data["rules"]
if (isinstance(data["rules"], dict) and all(k in ["DO", "DO-NOT"] for k in data["rules"].keys()))
else None,
),
approach=data["approach"] if isinstance(data["approach"], dict) else None,
deliverables=data["deliverables"] if isinstance(data["deliverables"], dict) else None,
)
return spec