diff --git a/backend/app/services/export_service.py b/backend/app/services/export_service.py index 41da72cb..d38a92c4 100644 --- a/backend/app/services/export_service.py +++ b/backend/app/services/export_service.py @@ -133,6 +133,42 @@ def _get_outcome_label(session: Session) -> str | None: return OUTCOME_LABELS.get(outcome, str(outcome).replace("_", " ").title()) +def _build_summary_fields(session: Session) -> dict[str, str]: + """Build auto-populated summary fields from session data. + + Empty fields are left blank — users fill them in via the editable preview. + """ + tree_name = session.tree_snapshot.get("name", "Troubleshooting Session") + tree_desc = session.tree_snapshot.get("description", "") + issue = f"{tree_name}: {tree_desc}" if tree_desc else tree_name + + if session.completed_at: + status = "Resolved" if getattr(session, "outcome", None) == "resolved" else \ + f"Completed — {_get_outcome_label(session) or 'Unknown'}" + else: + step_count = len(session.decisions) if session.decisions else 0 + status = f"In Progress — paused at step {step_count}" if step_count else "In Progress" + + _raw_notes = getattr(session, 'outcome_notes', None) + resolution = (_raw_notes if isinstance(_raw_notes, str) else '').strip() + + _raw_next = getattr(session, 'next_steps', None) + next_steps = (_raw_next if isinstance(_raw_next, str) else '').strip() + + return { + "issue": issue, + "impact": "", + "status": status, + "resolution": resolution, + "next_steps": next_steps, + } + + +def _escape_markdown_table(value: str) -> str: + """Escape value for use in a markdown table cell.""" + return value.replace("|", "\\|").replace("\n", " ") + + def generate_markdown_export(session: Session, options: SessionExport) -> str: """Generate markdown export.""" lines = [] @@ -157,6 +193,22 @@ def generate_markdown_export(session: Session, options: SessionExport) -> str: lines.append("---") lines.append("") + if options.include_summary: + summary = _build_summary_fields(session) + esc = _escape_markdown_table + lines.append("## Summary") + lines.append("") + lines.append("| Field | Details |") + lines.append("|-------|---------|") + lines.append(f"| Issue | {esc(summary['issue'])} |") + lines.append(f"| Impact | {esc(summary['impact'])} |") + lines.append(f"| Status | {esc(summary['status'])} |") + lines.append(f"| Resolution | {esc(summary['resolution'])} |") + lines.append(f"| Next Steps | {esc(summary['next_steps'])} |") + lines.append("") + lines.append("---") + lines.append("") + # Scratchpad / Evidence section scratchpad = getattr(session, 'scratchpad', '') or '' if scratchpad.strip(): @@ -252,6 +304,17 @@ def generate_text_export(session: Session, options: SessionExport) -> str: lines.append(f"Outcome: {outcome_label}") lines.append("") + if options.include_summary: + summary = _build_summary_fields(session) + lines.append("SUMMARY") + lines.append("-" * 20) + lines.append(f"Issue: {summary['issue']}") + lines.append(f"Impact: {summary['impact']}") + lines.append(f"Status: {summary['status']}") + lines.append(f"Resolution: {summary['resolution']}") + lines.append(f"Next Steps: {summary['next_steps']}") + lines.append("") + # Scratchpad / Evidence section scratchpad = getattr(session, 'scratchpad', '') or '' if scratchpad.strip(): @@ -350,6 +413,17 @@ def generate_html_export(session: Session, options: SessionExport) -> str: html_parts.append(f'

Outcome: {html.escape(outcome_label)}

') html_parts.append('') + if options.include_summary: + summary = _build_summary_fields(session) + html_parts.append('

Summary

') + html_parts.append('') + for label, value in [("Issue", summary["issue"]), ("Impact", summary["impact"]), + ("Status", summary["status"]), ("Resolution", summary["resolution"]), + ("Next Steps", summary["next_steps"])]: + html_parts.append(f'') + html_parts.append(f'') + html_parts.append('
{html.escape(label)}{html.escape(value)}
') + # Scratchpad / Evidence section scratchpad = getattr(session, 'scratchpad', '') or '' if scratchpad.strip(): @@ -427,6 +501,16 @@ def generate_psa_export(session: Session, options: SessionExport) -> str: lines.append(f"Outcome: {outcome_label}") lines.append("") + if options.include_summary: + summary = _build_summary_fields(session) + lines.append("--- SUMMARY ---") + lines.append(f"Issue: {summary['issue']}") + lines.append(f"Impact: {summary['impact']}") + lines.append(f"Status: {summary['status']}") + lines.append(f"Resolution: {summary['resolution']}") + lines.append(f"Next Steps: {summary['next_steps']}") + lines.append("") + # Problem section lines.append("--- PROBLEM ---") lines.append(tree_description if tree_description else "No description provided.")