"""Markdown export functionality for stream ledgers.""" import logging from datetime import datetime from pathlib import Path from app.config import settings from app.memory.database import get_session from app.memory.repository import Repository logger = logging.getLogger(__name__) class MarkdownExporter: """Exports stream session data as markdown ledgers.""" def __init__(self, export_path: str | None = None): """ Initialize exporter. Args: export_path: Directory to export ledgers to (defaults to settings.EXPORT_PATH) """ self.export_path = Path(export_path or settings.EXPORT_PATH) self.export_path.mkdir(parents=True, exist_ok=True) async def export_session(self, session_id: str) -> str: """ Export a session as a markdown ledger. Args: session_id: Session ID to export Returns: Markdown content """ async for db_session in get_session(): repo = Repository(db_session) session = await repo.get_session(session_id) if not session: logger.warning(f"Session {session_id} not found") return "" # Gather data messages = await repo.get_recent_messages(session_id, limit=1000) actions = await repo.get_session_actions(session_id) clips = await repo.get_clip_candidates(session_id) seeds = await repo.get_blog_seeds(session_id) # Build markdown date = session.started_at.strftime("%Y-%m-%d") ledger = f"# Sanctum Ledger — {date}\n\n" ledger += f"**Channel:** {session.channel_name}\n" ledger += f"**Started:** {session.started_at.isoformat()}\n" if session.ended_at: ledger += f"**Ended:** {session.ended_at.isoformat()}\n" ledger += "\n" # Stream Theme ledger += "## Stream Theme\n" if session.theme: ledger += f"{session.theme}\n" else: ledger += "*No theme recorded*\n" ledger += "\n" # Notable Discussion ledger += "## Notable Discussion\n" if messages: for msg in messages[:20]: # Latest 20 messages ledger += f"- **{msg.username}:** {msg.content[:100]}\n" else: ledger += "*No messages recorded*\n" ledger += "\n" # Agent Actions ledger += "## Agent Actions\n" if actions: for action in actions: ledger += f"- **{action.mode}** ({action.action_type}): {action.description}\n" else: ledger += "*No agent actions recorded*\n" ledger += "\n" # Clip Candidates ledger += "## Clip Candidates\n" if clips: for clip in clips: ledger += f"- {clip.reason}\n" else: ledger += "*No clip candidates identified*\n" ledger += "\n" # Blog Seeds ledger += "## Blog Seeds\n" if seeds: for seed in seeds: ledger += f"- **{seed.topic}:** {seed.description}\n" else: ledger += "*No blog seeds proposed*\n" ledger += "\n" logger.info(f"Generated ledger for session {session_id}") return ledger async def save_session_ledger(self, session_id: str) -> Path: """ Export session and save to file. Args: session_id: Session ID Returns: Path to saved file """ ledger = await self.export_session(session_id) date = datetime.utcnow().strftime("%Y-%m-%d") filename = f"ledger_{date}_{session_id[:8]}.md" filepath = self.export_path / filename filepath.write_text(ledger, encoding="utf-8") logger.info(f"Saved ledger to {filepath}") return filepath