mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
152 lines
4.2 KiB
TypeScript
152 lines
4.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { sanitizeTextForSpeech } from './speech-text'
|
|
|
|
describe('sanitizeTextForSpeech', () => {
|
|
it('summarizes fenced code blocks instead of reading them literally', () => {
|
|
expect(sanitizeTextForSpeech('Here is code:\n```ts\nconst x = 1\n```\nDone.')).toBe(
|
|
'Here is code: code block omitted Done.'
|
|
)
|
|
})
|
|
|
|
it('still keeps normal prose and inline code readable', () => {
|
|
expect(sanitizeTextForSpeech('Use `git status` after the change.')).toBe('Use git status after the change.')
|
|
})
|
|
|
|
it('skips markdown table data while preserving surrounding human text', () => {
|
|
const text = `Here is the quick takeaway: the totals remain unchanged.
|
|
|
|
| Item | Value | Notes |
|
|
| --- | ---: | --- |
|
|
| Example A | 10 | first row |
|
|
| Example B | 20 | second row |
|
|
|
|
Full detail stays visible on screen.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe(
|
|
'Here is the quick takeaway: the totals remain unchanged. Full detail stays visible on screen.'
|
|
)
|
|
})
|
|
|
|
it('does not strip prose that merely contains a pipe character', () => {
|
|
const text = 'Use the summary first | keep the table on screen when it matters.'
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Use the summary first | keep the table on screen when it matters.')
|
|
})
|
|
|
|
it('does not duplicate punctuation across paragraph breaks', () => {
|
|
const text = `First sentence.
|
|
|
|
Second sentence.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('First sentence. Second sentence.')
|
|
})
|
|
|
|
it.each([
|
|
['markdown emphasis', '**First sentence.**\n\nSecond sentence.', 'First sentence. Second sentence.'],
|
|
['a closing quote', '“First sentence.”\n\nSecond sentence.', '“First sentence.” Second sentence.'],
|
|
['a closing parenthesis', '(First sentence.)\n\nSecond sentence.', '(First sentence.) Second sentence.']
|
|
])('does not duplicate punctuation after %s', (_label, text, expected) => {
|
|
expect(sanitizeTextForSpeech(text)).toBe(expected)
|
|
})
|
|
|
|
it('skips markdown tables without leading and trailing pipes', () => {
|
|
const text = `Main takeaway: total is unchanged.
|
|
|
|
Item | Value
|
|
--- | ---:
|
|
Example A | 10
|
|
Example B | 20
|
|
|
|
Done.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Main takeaway: total is unchanged. Done.')
|
|
})
|
|
|
|
it('skips markdown tables nested inside blockquotes', () => {
|
|
const text = `Before the table.
|
|
|
|
> | Item | Value |
|
|
> | --- | ---: |
|
|
> | Example A | 10 |
|
|
> | Example B | 20 |
|
|
|
|
After the table.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Before the table. After the table.')
|
|
})
|
|
|
|
it('allows marker padding plus three spaces in blockquoted tables', () => {
|
|
const text = `Before the table.
|
|
|
|
> | Item | Value |
|
|
> | --- | ---: |
|
|
> | Example A | 10 |
|
|
|
|
After the table.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Before the table. After the table.')
|
|
})
|
|
|
|
it('skips explicit single-column markdown tables', () => {
|
|
const text = `Before the table.
|
|
|
|
| Item |
|
|
| --- |
|
|
| Example A |
|
|
|
|
After the table.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Before the table. After the table.')
|
|
})
|
|
|
|
it('preserves rows outside a table blockquote', () => {
|
|
const text = `> | Item | Value |
|
|
> | --- | ---: |
|
|
> | Example A | 10 |
|
|
Outside | prose`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Outside | prose')
|
|
})
|
|
|
|
it('preserves malformed tables with mismatched column counts', () => {
|
|
const text = `Heading | Detail
|
|
--- | --- | ---
|
|
Keep this prose.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toContain('Heading | Detail')
|
|
})
|
|
|
|
it('skips GFM body rows whose cell counts differ from the header', () => {
|
|
const text = `Before the table.
|
|
|
|
| Item | Value |
|
|
| --- | ---: |
|
|
| Example A |
|
|
| Example B | 20 | ignored |
|
|
|
|
After the table.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Before the table. After the table.')
|
|
})
|
|
|
|
it('skips tables containing escaped pipe characters', () => {
|
|
const text = `Before the table.
|
|
|
|
| Item \\| detail | Value |
|
|
| --- | ---: |
|
|
| Example A | 10 |
|
|
|
|
After the table.`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toBe('Before the table. After the table.')
|
|
})
|
|
|
|
it('preserves indented code that resembles a table', () => {
|
|
const text = ` Item | Value
|
|
--- | ---
|
|
Example A | 10`
|
|
|
|
expect(sanitizeTextForSpeech(text)).toContain('Item | Value')
|
|
})
|
|
})
|