feat: add bulletizeMarkdown post-processor with tests

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Woody 2026-04-28 16:43:21 +08:00
parent 4c56e81872
commit 1fdd2a70a5
2 changed files with 51 additions and 1 deletions

View File

@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest' import { describe, it, expect } from 'vitest'
import { processCitations } from '../../utils/citationParser' import { processCitations, bulletizeMarkdown } from '../../utils/citationParser'
import type { SourceMetadata } from '../../types' import type { SourceMetadata } from '../../types'
const mockSources: SourceMetadata[] = [ const mockSources: SourceMetadata[] = [
@ -145,3 +145,40 @@ describe('processCitations', () => {
expect(result).toContain('/pdf-viewer') expect(result).toContain('/pdf-viewer')
}) })
}) })
describe('bulletizeMarkdown', () => {
it('converts paragraphs to bullet points', () => {
const input = 'First paragraph.\n\nSecond paragraph.\n\nThird paragraph.'
const result = bulletizeMarkdown(input)
expect(result).toBe('- First paragraph.\n- Second paragraph.\n- Third paragraph.')
})
it('preserves content that already has bullet points', () => {
const input = '- Already a bullet\n- Second bullet'
const result = bulletizeMarkdown(input)
expect(result).toBe(input)
})
it('preserves numbered lists', () => {
const input = '1. First item\n2. Second item'
const result = bulletizeMarkdown(input)
expect(result).toBe(input)
})
it('handles single line', () => {
const input = 'Just one line.'
const result = bulletizeMarkdown(input)
expect(result).toBe('- Just one line.')
})
it('handles text with inline newlines (soft wrap)', () => {
const input = 'Line one\nstill same paragraph.'
const result = bulletizeMarkdown(input)
expect(result).toBe('- Line one still same paragraph.')
})
it('returns empty string for empty input', () => {
expect(bulletizeMarkdown('')).toBe('')
expect(bulletizeMarkdown(' \n ')).toBe('')
})
})

View File

@ -1,6 +1,19 @@
import type { SourceMetadata, SubQuestionSources } from '../types' import type { SourceMetadata, SubQuestionSources } from '../types'
import { getPdfViewerUrl } from '../lib/api' import { getPdfViewerUrl } from '../lib/api'
export function bulletizeMarkdown(text: string): string {
if (!text.trim()) return ''
const lines = text.split('\n')
const hasBullets = lines.some(
(line) => /^(\s*[-*+]|\s*\d+[.)]\s)/.test(line.trimStart())
)
if (hasBullets) return text
const paragraphs = text.split(/\n{2,}/).filter((p) => p.trim())
return paragraphs.map((p) => `- ${p.replace(/\n/g, ' ').trim()}`).join('\n')
}
const SUPPORTED_EXTENSIONS = /\.(pdf|docx|txt)$/i const SUPPORTED_EXTENSIONS = /\.(pdf|docx|txt)$/i
function stripExtension(filename: string): string { function stripExtension(filename: string): string {