Skip to main content
Glama
templates.py20.1 kB
"""Report templates with pre-configured section structures. Templates provide starting points for common report types, giving LLM agents a clear structure to populate with content. All templates enforce citation requirements by default. """ from __future__ import annotations import uuid from typing import Any from .models import Section def default() -> list[Section]: """Default template with standard report structure. Provides a clean, professional structure suitable for most analysis reports. All insights should include citations for data provenance. Sections: - Executive Summary: High-level overview and key takeaways - Analysis: Detailed findings and examination - Recommendations: Actionable next steps """ return [ Section( section_id=str(uuid.uuid4()), title="Executive Summary", order=0, insight_ids=[], notes="High-level overview and key takeaways", metadata={"category": "summary"}, ), Section( section_id=str(uuid.uuid4()), title="Analysis", order=1, insight_ids=[], notes="Detailed findings and examination", metadata={"category": "analysis"}, ), Section( section_id=str(uuid.uuid4()), title="Recommendations", order=2, insight_ids=[], notes="Actionable next steps and recommendations", metadata={"category": "recommendations"}, ), ] def deep_dive() -> list[Section]: """Single-topic deep dive template. For in-depth technical analysis of a specific topic or system. All insights should include citations for data provenance. Sections: - Overview: Introduction and background context - Methodology: Data sources and analysis approach - Findings: Detailed examination and key discoveries - Recommendations: Actionable next steps """ return [ Section( section_id=str(uuid.uuid4()), title="Overview", order=0, insight_ids=[], notes="Introduction and background context", metadata={"category": "overview"}, ), Section( section_id=str(uuid.uuid4()), title="Methodology", order=1, insight_ids=[], notes="Data sources and analysis approach", metadata={"category": "methodology"}, ), Section( section_id=str(uuid.uuid4()), title="Findings", order=2, insight_ids=[], notes="Detailed examination and key discoveries", metadata={"category": "findings"}, ), Section( section_id=str(uuid.uuid4()), title="Recommendations", order=3, insight_ids=[], notes="Actionable next steps and recommendations", metadata={"category": "recommendations"}, ), ] def analyst_v1() -> list[Section]: """Analyst report template for blockchain/protocol analysis. Specialized structure for on-chain data analysis. All insights should include citations for data provenance. Sections: - Executive Summary: High-level overview for stakeholders - Methodology: Data sources, time range, and analysis approach - Key Findings: Primary discoveries and insights - Detailed Analysis: In-depth examination of findings - Recommendations: Actionable next steps """ return [ Section( section_id=str(uuid.uuid4()), title="Executive Summary", order=0, insight_ids=[], notes="High-level overview for stakeholders", metadata={"category": "summary"}, ), Section( section_id=str(uuid.uuid4()), title="Methodology", order=1, insight_ids=[], notes="Data sources, time range, and analysis approach", metadata={"category": "methodology"}, ), Section( section_id=str(uuid.uuid4()), title="Key Findings", order=2, insight_ids=[], notes="Primary discoveries and insights", metadata={"category": "findings"}, ), Section( section_id=str(uuid.uuid4()), title="Detailed Analysis", order=3, insight_ids=[], notes="In-depth examination of findings", metadata={"category": "analysis"}, ), Section( section_id=str(uuid.uuid4()), title="Recommendations", order=4, insight_ids=[], notes="Actionable next steps and recommendations", metadata={"category": "recommendations"}, ), ] def empty() -> list[Section]: """Empty template - no pre-configured sections. For maximum flexibility when you want to build structure from scratch. """ return [] # Template registry for lookup TEMPLATES = { "default": default, "deep_dive": deep_dive, "analyst_v1": analyst_v1, "empty": empty, } def get_template(name: str) -> list[Section]: """Get template sections by name. Args: name: Template name (default, deep_dive, analyst_v1, empty) Returns: List of pre-configured sections Raises: ValueError: If template name not found """ if name not in TEMPLATES: available = ", ".join(TEMPLATES.keys()) raise ValueError(f"Unknown template: {name}. Available templates: {available}") return TEMPLATES[name]() # ============================================================================= # Section Content Templates # ============================================================================= # These templates format section content with structured markdown. # Use via evolve_report with template="findings" and template_data={...} # # SINGLE SOURCE OF TRUTH: evolve_report.py delegates to these functions. # Template metadata for discovery via get_report_schema SECTION_CONTENT_TEMPLATES: dict[str, dict[str, Any]] = { "findings": { "description": "Key findings with optional metrics and action items", "aliases": ["findings_list"], "required_fields": ["findings"], "optional_fields": ["heading"], "example": { "heading": "Key Findings", "findings": [ { "title": "Revenue Growth", "description": "Strong YoY performance", "metric": {"name": "YoY Growth", "value": "+45%", "trend": "↑"}, "actions": ["Expand to new markets"], } ], }, }, "metrics": { "description": "Metrics snapshot table with optional callouts", "aliases": ["metrics_snapshot"], "required_fields": ["metrics"], "optional_fields": ["heading", "callouts"], "example": { "heading": "Q4 Metrics", "metrics": [ {"name": "Revenue", "value": "$2.4M", "target": "$2.0M", "delta": "+20%"}, {"name": "Users", "value": "50K", "target": "45K", "delta": "+11%"}, ], "callouts": [{"title": "Record Quarter", "detail": "Highest revenue ever"}], }, }, "bullet_list": { "description": "Simple bullet point list", "aliases": ["bullet", "summary_bullets"], "required_fields": ["items"], "optional_fields": ["heading"], "example": { "heading": "Summary", "items": ["First key point", "Second key point", "Third key point"], }, }, "executive_summary": { "description": "Executive summary with key takeaways and recommendation", "aliases": ["exec_summary"], "required_fields": [], "optional_fields": ["headline", "context", "key_points", "recommendation", "conclusion"], "example": { "headline": "Q4 Performance Review", "context": "This quarter marked significant growth...", "key_points": [ {"title": "Revenue", "detail": "Up 25% YoY"}, "Customer satisfaction at all-time high", ], "recommendation": "Increase investment in growth initiatives", "conclusion": "Strong foundation for continued expansion", }, }, "action_items": { "description": "Action items with owners, due dates, and priority", "aliases": ["next_steps", "actions"], "required_fields": ["actions"], "optional_fields": ["heading"], "example": { "heading": "Next Steps", "actions": [ { "description": "Complete security audit", "owner": "Security Team", "due": "2024-01-15", "priority": "High", }, {"description": "Update documentation", "owner": "TBD"}, ], }, }, "methodology": { "description": "Methodology section with data sources and approach", "aliases": [], "required_fields": [], "optional_fields": ["heading", "data_sources", "time_period", "approach"], "example": { "heading": "Methodology", "data_sources": ["Snowflake analytics warehouse", "On-chain transaction data"], "time_period": "Q4 2024 (Oct 1 - Dec 31)", "approach": "Aggregated daily metrics with 7-day moving averages", }, }, } def render_section_template( template_name: str, template_data: dict[str, Any], section_title: str = "Untitled Section", ) -> str: """Render structured markdown content from a section template. This is the SINGLE SOURCE OF TRUTH for section content templates. evolve_report.py delegates to this function. Args: template_name: Template name (findings, metrics, bullet_list, executive_summary, action_items, methodology) template_data: Data to populate the template section_title: Fallback title if not provided in template_data Returns: Formatted markdown string Raises: ValueError: If template name not found or required fields missing Example: >>> content = render_section_template("findings", { ... "heading": "Key Findings", ... "findings": [ ... {"title": "Revenue Growth", "metric": {"name": "YoY", "value": "+45%", "trend": "↑"}}, ... ], ... }, "Analysis") """ if not isinstance(template_name, str): raise ValueError("template must be a string") normalized_name = template_name.strip().lower() data = template_data or {} # Resolve aliases resolved_name = _resolve_template_alias(normalized_name) if resolved_name is None: available = ", ".join(SECTION_CONTENT_TEMPLATES.keys()) raise ValueError(f"Unknown section template: {template_name}. Available: {available}") # Dispatch to specific renderer if resolved_name == "findings": return _render_findings(data, section_title) elif resolved_name == "metrics": return _render_metrics(data, section_title) elif resolved_name == "bullet_list": return _render_bullet_list(data, section_title) elif resolved_name == "executive_summary": return _render_executive_summary(data, section_title) elif resolved_name == "action_items": return _render_action_items(data, section_title) elif resolved_name == "methodology": return _render_methodology(data, section_title) else: raise ValueError(f"Unknown section template: {template_name}") def _resolve_template_alias(name: str) -> str | None: """Resolve template alias to canonical name.""" # Check direct match if name in SECTION_CONTENT_TEMPLATES: return name # Check aliases for canonical, info in SECTION_CONTENT_TEMPLATES.items(): if name in info.get("aliases", []): return canonical return None def _render_findings(data: dict[str, Any], section_title: str) -> str: """Render findings template.""" findings = data.get("findings", []) if not findings: raise ValueError("findings template requires 'findings' array") heading = data.get("heading") or f"Key Findings - {section_title}" lines = [f"## {heading.strip()}", ""] for idx, finding in enumerate(findings, 1): title = finding.get("title") or f"Finding {idx}" summary = finding.get("description") or finding.get("summary") or "" metric = finding.get("metric") or {} lines.append(f"### {idx}. {title.strip()}") if metric: lines.append("") lines.append("| Metric | Value | Trend |") lines.append("| --- | --- | --- |") lines.append(f"| {metric.get('name', 'Value')} | {metric.get('value', '-')} | {metric.get('trend', '-')} |") if summary: lines.append("") lines.append(summary.strip()) if finding.get("actions"): lines.append("") lines.append("**Next Steps**") for action in finding["actions"]: lines.append(f"- {action}") lines.append("") return "\n".join(lines).strip() def _render_metrics(data: dict[str, Any], section_title: str) -> str: """Render metrics snapshot template.""" metrics = data.get("metrics", []) if not metrics: raise ValueError("metrics template requires 'metrics' array") heading = data.get("heading") or f"{section_title} Metrics" lines = [f"## {heading.strip()}", "", "| Metric | Value | Target | Delta |", "| --- | --- | --- | --- |"] for metric in metrics: lines.append( "| {name} | {value} | {target} | {delta} |".format( name=metric.get("name", "Metric"), value=metric.get("value", "-"), target=metric.get("target", "-"), delta=metric.get("delta", "-"), ) ) if data.get("callouts"): lines.append("") lines.append("### Callouts") for callout in data["callouts"]: title = callout.get("title", "Callout") detail = callout.get("detail") or callout.get("description") or "" lines.append(f"- **{title}** — {detail}") return "\n".join(lines).strip() def _render_bullet_list(data: dict[str, Any], section_title: str) -> str: """Render bullet list template.""" items = data.get("items") or data.get("bullets") if not items: raise ValueError("bullet_list template requires 'items' array") heading = data.get("heading") or section_title or "Summary" lines = [f"## {heading.strip()}", ""] for item in items: lines.append(f"- {item}") return "\n".join(lines).strip() def _render_executive_summary(data: dict[str, Any], section_title: str) -> str: """Render executive summary template.""" headline = data.get("headline") or data.get("title") or section_title key_points = data.get("key_points") or data.get("takeaways") or [] recommendation = data.get("recommendation") or data.get("action") conclusion = data.get("conclusion") or data.get("summary") lines = [f"## {headline.strip()}", ""] if data.get("context"): lines.append(data["context"].strip()) lines.append("") if key_points: lines.append("### Key Takeaways") lines.append("") for idx, point in enumerate(key_points, 1): if isinstance(point, dict): title = point.get("title", f"Point {idx}") detail = point.get("detail", "") lines.append(f"{idx}. **{title}** — {detail}") else: lines.append(f"{idx}. {point}") lines.append("") if recommendation: lines.append("### Recommendation") lines.append("") lines.append(f"> {recommendation.strip()}") lines.append("") if conclusion: lines.append(conclusion.strip()) lines.append("") return "\n".join(lines).strip() def _render_action_items(data: dict[str, Any], section_title: str) -> str: """Render action items template.""" actions = data.get("actions") or data.get("items") or [] if not actions: raise ValueError("action_items template requires 'actions' array") heading = data.get("heading") or "Action Items" lines = [f"## {heading.strip()}", ""] has_table_data = any(isinstance(a, dict) and (a.get("owner") or a.get("due") or a.get("priority")) for a in actions) if has_table_data: lines.append("| # | Action | Owner | Due | Priority |") lines.append("| --- | --- | --- | --- | --- |") for idx, action in enumerate(actions, 1): if isinstance(action, dict): desc = action.get("description") or action.get("action") or action.get("title") or "" owner = action.get("owner") or "TBD" due = action.get("due") or action.get("due_date") or "-" priority = action.get("priority") or "Medium" lines.append(f"| {idx} | {desc} | {owner} | {due} | {priority} |") else: lines.append(f"| {idx} | {action} | TBD | - | Medium |") else: for idx, action in enumerate(actions, 1): if isinstance(action, dict): desc = action.get("description") or action.get("action") or action.get("title") or "" lines.append(f"{idx}. {desc}") else: lines.append(f"{idx}. {action}") lines.append("") return "\n".join(lines).strip() def _render_methodology(data: dict[str, Any], section_title: str) -> str: """Render methodology template.""" heading = data.get("heading") or section_title or "Methodology" lines = [f"## {heading.strip()}", ""] # Data sources sources = data.get("data_sources", []) if sources: lines.append("**Data Sources:**") if isinstance(sources, list): for source in sources: lines.append(f"- {source}") else: lines.append(str(sources)) lines.append("") # Time period time_period = data.get("time_period") if time_period: lines.append(f"**Time Period:** {time_period}") lines.append("") # Approach approach = data.get("approach") if approach: lines.append("**Analysis Approach:**") lines.append(approach.strip()) lines.append("") return "\n".join(lines).strip() def list_section_content_templates() -> dict[str, dict[str, Any]]: """List available section content templates with full metadata. Returns: Dictionary with template info including description, aliases, fields, and example. Example: >>> templates = list_section_content_templates() >>> print(templates["findings"]["description"]) 'Key findings with optional metrics and action items' """ return SECTION_CONTENT_TEMPLATES.copy() def get_section_template_names() -> list[str]: """Get list of all valid template names including aliases. Returns: List of all template names that can be used. """ names = list(SECTION_CONTENT_TEMPLATES.keys()) for info in SECTION_CONTENT_TEMPLATES.values(): names.extend(info.get("aliases", [])) return sorted(set(names)) # Legacy alias for backward compatibility def format_section_content(template_name: str, data: dict[str, Any]) -> str: """Format section content using a predefined template. DEPRECATED: Use render_section_template() instead. This function is kept for backward compatibility. """ return render_section_template(template_name, data, "Untitled Section")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Evan-Kim2028/igloo-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server