oluown / app.py
mgbam's picture
Upload 3 files
49687b5 verified
raw
history blame
6.13 kB
import gradio as gr
import os, re, json, textwrap
from typing import Dict, Tuple
SKILLS_ROOT = os.path.join(os.path.dirname(__file__), "skills")
def parse_frontmatter(md_text: str) -> Tuple[dict, str]:
if not md_text.startswith("---"):
return {}, md_text
parts = md_text.split("\n")
if parts[0].strip() != "---":
return {}, md_text
try:
end_idx = parts[1:].index("---") + 1
except ValueError:
return {}, md_text
fm_lines = parts[1:end_idx]
body = "\n".join(parts[end_idx+1:])
meta = {}
for line in fm_lines:
if ":" in line:
k, v = line.split(":", 1)
meta[k.strip()] = v.strip().strip('"').strip("'")
return meta, body
def load_skill(skill_slug: str):
path = os.path.join(SKILLS_ROOT, skill_slug, "SKILL.md")
if not os.path.exists(path):
return {}, f"**SKILL.md not found for skill `{skill_slug}`.**"
with open(path, "r", encoding="utf-8") as f:
text = f.read()
meta, body = parse_frontmatter(text)
return meta, body
def list_skills():
out = []
if not os.path.isdir(SKILLS_ROOT):
return out
for name in sorted(os.listdir(SKILLS_ROOT)):
if os.path.isdir(os.path.join(SKILLS_ROOT, name)) and os.path.exists(os.path.join(SKILLS_ROOT, name, "SKILL.md")):
meta, _ = load_skill(name)
out.append((name, meta.get("name", name), meta.get("description", "")))
return out
def list_linked_files(skill_slug: str):
root = os.path.join(SKILLS_ROOT, skill_slug)
if not os.path.isdir(root):
return []
return [fn for fn in sorted(os.listdir(root)) if fn.lower().endswith(".md") and fn != "SKILL.md"]
def read_linked_file(skill_slug: str, filename: str) -> str:
path = os.path.join(SKILLS_ROOT, skill_slug, filename)
if not os.path.exists(path):
return f"**{filename} not found.**"
with open(path, "r", encoding="utf-8") as f:
return f.read()
def run_pdf_tool(skill_slug: str, uploaded_pdf) -> str:
try:
if uploaded_pdf is None:
return "Please upload a PDF."
import runpy, json as _json, os as _os
tool_path = os.path.join(SKILLS_ROOT, skill_slug, "tools", "extract_form_fields.py")
if not os.path.exists(tool_path):
return "Tool script not found. Expected tools/extract_form_fields.py"
ns = runpy.run_path(tool_path)
if "extract_fields" not in ns:
return "extract_form_fields.py does not define extract_fields(pdf_path)."
fn = ns["extract_fields"]
result = fn(uploaded_pdf.name if hasattr(uploaded_pdf, "name") else uploaded_pdf)
try:
return "```json\n" + _json.dumps(result, indent=2) + "\n```"
except Exception:
return str(result)
except Exception as e:
return f"Error running tool: {e}"
def explain_progressive_disclosure() -> str:
return (
"### Progressive Disclosure\\n\\n"
"1. **Startup**: Only skill *metadata* (name, description) is shown.\\n"
"2. **Trigger**: Loading a skill reads **SKILL.md** into context.\\n"
"3. **Deep Dive**: Linked files (e.g., `reference.md`, `forms.md`) are opened only when needed.\\n"
"4. **Tools**: For the PDF skill, run the Python tool to extract form fields without adding the PDF to context."
)
with gr.Blocks(title="Agent Skills β€” Progressive Disclosure Demo") as demo:
gr.Markdown("# Equipping agents for the real world with Agent Skills\\nPublished Oct 16, 2025")
gr.Markdown("This Space demonstrates **Agent Skills** as folders containing a `SKILL.md`, optional linked files, and tools.")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### Installed Skills")
skills = list_skills()
skill_map = {f"{title} β€” {desc}": slug for (slug, title, desc) in skills} if skills else {}
labels = list(skill_map.keys()) or ["(No skills found)"]
skill_dd = gr.Dropdown(choices=labels, value=labels[0], label="Pick a skill")
meta_out = gr.JSON(label="Skill metadata")
def on_pick(label):
if not skill_map:
return {}, "", [], None, None
slug = skill_map.get(label, None)
if not slug:
return {}, "", [], None, None
meta, body = load_skill(slug)
return meta, body, list_linked_files(slug), slug, None
body_out = gr.Markdown(label="SKILL.md body")
linked_files = gr.Dropdown(choices=[], label="Linked files")
selected_slug_state = gr.State(value=None)
_reset = gr.State(value=None)
skill_dd.change(fn=on_pick, inputs=[skill_dd], outputs=[meta_out, body_out, linked_files, selected_slug_state, _reset])
with gr.Column(scale=2):
gr.Markdown("### Progressive Disclosure")
gr.Markdown(explain_progressive_disclosure())
gr.Markdown("---")
gr.Markdown("### Linked File Viewer")
linked_view = gr.Markdown()
def on_view_linked(filename, slug):
if not slug or not filename:
return "Pick a skill and a linked file."
return read_linked_file(slug, filename)
view_btn = gr.Button("Open linked file")
view_btn.click(fn=on_view_linked, inputs=[linked_files, selected_slug_state], outputs=[linked_view])
gr.Markdown("---")
gr.Markdown("### Run Skill Tool (PDF form field extractor)")
pdf_in = gr.File(label="Upload a PDF", file_count="single", type="filepath")
tool_out = gr.Markdown()
def run_tool_clicked(slug, pdf):
if not slug:
return "Pick a skill first."
return run_pdf_tool(slug, pdf)
run_tool_btn = gr.Button("Extract form fields")
run_tool_btn.click(fn=run_tool_clicked, inputs=[selected_slug_state, pdf_in], outputs=[tool_out])
if __name__ == "__main__":
demo.launch()