import { escapeHtml, sanitizeUrl } from '@/utils/sanitize'; const SECTION_HEADERS = ['SITUATION NOW', 'WHAT THIS MEANS FOR', 'KEY RISKS', 'OUTLOOK', 'WATCH ITEMS']; export interface IntelBriefCitationSource { title?: string; url?: string; } type IntelBriefCitationOptions = | { sources: readonly IntelBriefCitationSource[] } | { count: number; hrefPrefix: string }; /** * Converts structured LLM intel brief text into HTML. * Handles the 5-section format (SITUATION NOW / WHAT THIS MEANS FOR / KEY RISKS / OUTLOOK / WATCH ITEMS). * Falls back gracefully to paragraph rendering for older prose-format responses. * * @param text Raw brief text from LLM * @param citationOpts Optional citation link config for source references like [1], [2] */ export function formatIntelBrief( text: string, citationOpts?: IntelBriefCitationOptions, ): string { const escaped = escapeHtml(text); const lines = escaped.split('\n'); const out: string[] = []; let inSection = false; for (const line of lines) { const trimmed = line.trim(); const isHeader = SECTION_HEADERS.some(h => trimmed.toUpperCase().startsWith(h)); if (isHeader) { if (inSection) out.push(''); out.push(`
${trimmed}
`); inSection = true; } else if (trimmed.startsWith('•') || trimmed.startsWith('-')) { out.push(`
${trimmed.replace(/^[•-]\s*/, '')}
`); } else if (trimmed.startsWith('NEXT ')) { const colonIdx = trimmed.indexOf(':'); if (colonIdx !== -1) { const label = trimmed.slice(0, colonIdx); const body = trimmed.slice(colonIdx + 1).trim(); out.push(`
${label}: ${body}
`); } else { out.push(`
${trimmed}
`); } } else if (trimmed) { out.push(`
${trimmed.replace(/\*\*(.*?)\*\*/g, '$1')}
`); } } if (inSection) out.push('
'); let html = out.join('') || `

${escaped.replace(/\n\n/g, '

').replace(/\n/g, '
')}

`; if (citationOpts && ('sources' in citationOpts || citationOpts.count > 0)) { html = html.replace(/\[(\d{1,2})\]/g, (_match, numStr) => { const n = parseInt(numStr, 10); if ('sources' in citationOpts) { const source = citationOpts.sources[n - 1]; const href = sanitizeUrl(source?.url ?? ''); return href ? `[${n}]` : `[${numStr}]`; } const { count, hrefPrefix } = citationOpts; return n >= 1 && n <= count ? `[${n}]` : `[${numStr}]`; }); } return html; }