{"version":3,"sources":["../../src/tts/provider_format.test.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2026 LiveKit, Inc.\n//\n// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Tests for the LiveKit expression marker (expr) dialect.\n *\n * The LLM emits a single marker tag — `<expr type=\"...\" label=\"...\"/>` (self-closing for\n * expression/break/sound, wrapping for prosody/spell) — and the framework lowers it to\n * each provider's native markup before synthesis while stripping it from transcripts. The\n * syntax is shared, but the kinds and label vocabularies are per provider: each provider's\n * instruction block advertises only what that provider supports.\n */\nimport { describe, expect, it } from 'vitest';\nimport { ChatContext, ChatMessage } from '../llm/chat_context.js';\nimport { type TimedString, createTimedString } from '../voice/io.js';\nimport { matchMood } from './mood.js';\nimport {\n  TranscriptMarkupStripper,\n  convertMarkup,\n  dropBracketCues,\n  expressionAttribute,\n  llmInstructions,\n  maxInputLen,\n  normalizeMarkup,\n  sentenceTokenizer,\n  splitAllMarkup,\n  steeringInstructions,\n  stripAllMarkup,\n  stripExprMarkup,\n  supportedNonverbals,\n} from './provider_format.js';\n\n// Inworld-flavored turn: free-form expression + sound + break\nconst JOKE =\n  '<expr type=\"expression\" label=\"say playfully\"/> Why did the burger go to the gym? ' +\n  '<expr type=\"break\" label=\"500ms\"/> Because it wanted better buns! ' +\n  '<expr type=\"sound\" label=\"laugh\"/>';\n\ndescribe('convertMarkup: expr -> xAI', () => {\n  it('lowers sounds, breaks and wrapping prosody', () => {\n    const text =\n      'So I walked in and <expr type=\"break\" label=\"500ms\"/> there it was! ' +\n      '<expr type=\"sound\" label=\"laugh\"/> ' +\n      '<expr type=\"prosody\" label=\"whisper\">It was a secret the whole time.</expr>';\n    expect(convertMarkup('xai', text)).toBe(\n      'So I walked in and [pause] there it was! [laugh] ' +\n        '<whisper>It was a secret the whole time.</whisper>',\n    );\n  });\n\n  it('maps break durations to the two native pause levels', () => {\n    expect(convertMarkup('xai', '<expr type=\"break\" label=\"50ms\"/>')).toBe('[pause]');\n    expect(convertMarkup('xai', '<expr type=\"break\" label=\"2s\"/>')).toBe('[long-pause]');\n  });\n\n  it('aliases an Inworld-style sound label to the native cue', () => {\n    expect(convertMarkup('xai', '<expr type=\"sound\" label=\"breathe\"/>')).toBe('[breath]');\n  });\n\n  it('normalizes multi-word prosody labels to hyphenated tag names', () => {\n    const text = '<expr type=\"prosody\" label=\"higher pitch\">no way</expr>';\n    expect(convertMarkup('xai', text)).toBe('<higher-pitch>no way</higher-pitch>');\n  });\n\n  it('unwraps an unknown prosody label', () => {\n    const text = '<expr type=\"prosody\" label=\"like a pirate\">ahoy there</expr>';\n    expect(convertMarkup('xai', text)).toBe('ahoy there');\n  });\n\n  it('drops a hallucinated expression marker from the audio path', () => {\n    // xAI has no free-form delivery descriptions; the marker still surfaces in\n    // transcript tags\n    const text = '<expr type=\"expression\" label=\"say playfully\"/> Hello!';\n    expect(convertMarkup('xai', text)).toBe(' Hello!');\n  });\n});\n\ndescribe('convertMarkup: expr -> Inworld', () => {\n  it('lowers expression/sound to brackets and keeps break as native SSML', () => {\n    expect(convertMarkup('inworld', JOKE)).toBe(\n      '[say playfully] Why did the burger go to the gym? ' +\n        '<break time=\"500ms\"/> Because it wanted better buns! [laugh]',\n    );\n  });\n\n  it('salvages a stray prosody marker as a delivery hint', () => {\n    const text = '<expr type=\"prosody\" label=\"whisper\">keep it secret</expr>';\n    expect(convertMarkup('inworld', text)).toBe('[whisper]keep it secret');\n  });\n});\n\ndescribe('convertMarkup: expr -> Cartesia', () => {\n  it('lowers expression to <emotion>, keeps break, drops sound', () => {\n    const text =\n      '<expr type=\"expression\" label=\"excited\"/> We won! ' +\n      '<expr type=\"break\" label=\"1s\"/> <expr type=\"sound\" label=\"laugh\"/> Unbelievable.';\n    // without leaving the space the dropped marker sat between behind as a doubled\n    // separator\n    expect(convertMarkup('cartesia', text)).toBe(\n      '<emotion value=\"excited\"/> We won! <break time=\"1s\"/> Unbelievable.',\n    );\n  });\n\n  it('lowers spell to the native tag', () => {\n    const text = 'Your code is <expr type=\"spell\">A7X9</expr>.';\n    expect(convertMarkup('cartesia', text)).toBe('Your code is <spell>A7X9</spell>.');\n  });\n\n  it('unwraps spell for providers that lack it', () => {\n    const text = 'Your code is <expr type=\"spell\">A7X9</expr>.';\n    expect(convertMarkup('xai', text)).toBe('Your code is A7X9.');\n    expect(convertMarkup('inworld', text)).toBe('Your code is A7X9.');\n  });\n\n  it('lowers prosody labels to native speed/volume point controls', () => {\n    expect(convertMarkup('cartesia', '<expr type=\"prosody\" label=\"slow\"/> One moment.')).toBe(\n      '<speed ratio=\"0.85\"/> One moment.',\n    );\n    expect(convertMarkup('cartesia', '<expr type=\"prosody\" label=\"loud\"/> We won!')).toBe(\n      '<volume ratio=\"1.3\"/> We won!',\n    );\n    // wrapping form applies the control before the span\n    expect(convertMarkup('cartesia', '<expr type=\"prosody\" label=\"soft\">bad news</expr>')).toBe(\n      '<volume ratio=\"0.9\"/>bad news',\n    );\n  });\n\n  it('unwraps an unknown prosody label', () => {\n    const text = '<expr type=\"prosody\" label=\"whisper\">keep it secret</expr>';\n    expect(convertMarkup('cartesia', text)).toBe('keep it secret');\n  });\n\n  it('does not let a self-closing prosody marker swallow a later span', () => {\n    // Cartesia's prosody markers are self-closing point controls. Read as an opening tag,\n    // one would run to the next </expr> and eat the spell marker with it — the code would\n    // reach the TTS as a bare word and be pronounced instead of spelled out.\n    const text =\n      '<expr type=\"prosody\" label=\"slow\"/> One moment. ' +\n      'Your code is <expr type=\"spell\">A7X9</expr>.';\n    expect(convertMarkup('cartesia', text)).toBe(\n      '<speed ratio=\"0.85\"/> One moment. Your code is <spell>A7X9</spell>.',\n    );\n  });\n\n  it('keeps each self-closing marker distinct across a sentence', () => {\n    const text =\n      '<expr type=\"prosody\" label=\"loud\"/> Big news! <expr type=\"prosody\" label=\"soft\"/> Or not.';\n    expect(convertMarkup('cartesia', text)).toBe(\n      '<volume ratio=\"1.3\"/> Big news! <volume ratio=\"0.9\"/> Or not.',\n    );\n  });\n});\n\ndescribe('convertMarkup: expr -> Fish Audio', () => {\n  it('lowers expression to an intensified bracket cue and sounds to their aliases', () => {\n    const text =\n      '<expr type=\"expression\" label=\"regretful\"/> That\\'s on us. ' +\n      '<expr type=\"sound\" label=\"sigh\"/>';\n    expect(convertMarkup('fishaudio', text)).toBe(\"[very regretful] That's on us. [sighing]\");\n  });\n\n  it('lowers a tone wrapper to Fish’s prefix marker form', () => {\n    const text = '<expr type=\"prosody\" label=\"whispering\">don\\'t tell anyone</expr>';\n    expect(convertMarkup('fishaudio', text)).toBe(\"[whispering] don't tell anyone\");\n  });\n\n  it('lowers emphasis to the per-word stress marker', () => {\n    const text = 'Are you <expr type=\"prosody\" label=\"emphasis\">sure</expr>?';\n    expect(convertMarkup('fishaudio', text)).toBe('Are you [emphasis] sure?');\n  });\n\n  it('maps break durations to the two native pause levels', () => {\n    expect(convertMarkup('fishaudio', '<expr type=\"break\" label=\"500ms\"/>')).toBe('[break]');\n    expect(convertMarkup('fishaudio', '<expr type=\"break\" label=\"2s\"/>')).toBe('[long-break]');\n  });\n});\n\nit('drops a stray expr tag rather than letting it reach the TTS', () => {\n  // an unpaired prosody open/close (e.g. split across stream chunks) is dropped, keeping\n  // the words\n  expect(convertMarkup('xai', '<expr type=\"prosody\" label=\"loud\">hello there')).toBe('hello there');\n  expect(convertMarkup('xai', 'hello there</expr>')).toBe('hello there');\n});\n\ndescribe('transcript stripping (provider-agnostic)', () => {\n  it('strips expr and reports its tags', () => {\n    const [clean, tags] = splitAllMarkup(JOKE);\n    expect(clean.trim()).toBe('Why did the burger go to the gym? Because it wanted better buns!');\n    expect(tags).toEqual([\n      { type: 'expression', value: 'say playfully' },\n      { type: 'break', value: '500ms' },\n      { type: 'sound', value: 'laugh' },\n    ]);\n  });\n\n  it('keeps the inner text of a wrapping marker', () => {\n    const text =\n      'She said <expr type=\"prosody\" label=\"whisper\">keep it secret</expr> — ' +\n      'code <expr type=\"spell\">A7X9</expr>.';\n    const [clean, tags] = splitAllMarkup(text);\n    expect(clean).toBe('She said keep it secret — code A7X9.');\n    expect(tags).toEqual([\n      { type: 'prosody', value: 'whisper' },\n      { type: 'spell', value: '' },\n    ]);\n  });\n\n  it('strips mixed expr and provider-native tags', () => {\n    const text = '<expr type=\"expression\" label=\"say playfully\"/> Hello! <sound value=\"laugh\"/>';\n    const [clean, tags] = splitAllMarkup(text);\n    expect(clean.trim()).toBe('Hello!');\n    expect(tags).toContainEqual({ type: 'expression', value: 'say playfully' });\n    expect(tags).toContainEqual({ type: 'sound', value: 'laugh' });\n  });\n\n  it('keeps square-bracket spans', () => {\n    // bracket spans are a TTS-only native form (convertMarkup emits them on the audio\n    // path), so the transcript strip must leave markdown links and prose brackets intact\n    const text =\n      'Press [Enter], then read [the docs](https://docs.livekit.io). <sound value=\"sigh\"/>';\n    const [clean, tags] = splitAllMarkup(text);\n    expect(clean).toBe('Press [Enter], then read [the docs](https://docs.livekit.io). ');\n    expect(tags).toEqual([{ type: 'sound', value: 'sigh' }]);\n  });\n\n  it('does not match the native <expression> tag with the expr regexes', () => {\n    // \"<expr\" is a prefix of \"<expression\" — the word boundary in the expr regexes must\n    // keep the native Inworld tag on the generic strip path with its own type\n    const text = '<expression value=\"speak calmly\"/> Hi <expr type=\"break\" label=\"1s\"/> there.';\n    const [clean, tags] = splitAllMarkup(text);\n    expect(clean).toBe(' Hi there.');\n    expect(tags).toContainEqual({ type: 'expression', value: 'speak calmly' });\n    expect(tags).toContainEqual({ type: 'break', value: '1s' });\n    // conversion must also leave the native tag for the provider pipeline, not eat it\n    expect(convertMarkup('inworld', text)).toBe('[speak calmly] Hi <break time=\"1s\"/> there.');\n  });\n\n  it('holds a tag split across streamed chunks', () => {\n    const stripper = new TranscriptMarkupStripper();\n    let out = '';\n    // split mid-tag so the partial \"<expr ...\" must be held back, never half-emitted\n    for (const chunk of [\n      '<expr type=\"expr',\n      'ession\" label=\"say playfully\"/> Hello',\n      ' <expr type=\"prosody\" label=\"whisper\">wor',\n      'ld</expr>!',\n    ]) {\n      out += stripper.push(chunk);\n    }\n    out += stripper.flush();\n    // no leading space: the marker opened the segment, so the space it left behind is\n    // trimmed (Python leaves it, and its own tests .strip() around it)\n    expect(out).toBe('Hello world!');\n    expect(stripper.tags[0]).toEqual({ type: 'expression', value: 'say playfully' });\n    expect(stripper.tags).toContainEqual({ type: 'prosody', value: 'whisper' });\n  });\n\n  it('leaves a single space where a removed tag sat between two', () => {\n    // a marker between two spaces must not leave both behind, or punctuation ends up\n    // followed by a double space in the transcript\n    expect(stripAllMarkup('Right. <expr type=\"sound\" label=\"laugh\"/> Anyway.')).toBe(\n      'Right. Anyway.',\n    );\n    expect(stripAllMarkup('Right. <sound value=\"laugh\"/> Anyway.')).toBe('Right. Anyway.');\n    // a wrapping marker keeps its inner text, so its spacing is untouched\n    expect(stripAllMarkup('a <expr type=\"prosody\" label=\"loud\">b</expr> c')).toBe('a b c');\n    // only the doubled separator goes: a marker with text on one side keeps the space\n    expect(stripAllMarkup('Right.<expr type=\"sound\" label=\"laugh\"/> Anyway.')).toBe(\n      'Right. Anyway.',\n    );\n    expect(stripAllMarkup('Right. <expr type=\"sound\" label=\"laugh\"/>Anyway.')).toBe(\n      'Right. Anyway.',\n    );\n    // newlines are structure, not a separator a strip may collapse\n    expect(stripAllMarkup('a\\n<expr type=\"sound\" label=\"laugh\"/>\\nb')).toBe('a\\n\\nb');\n  });\n\n  it('keeps the trailing space before a marker at the end of a chunk', () => {\n    // the space before a trailing marker is the separator for words still streaming in,\n    // so it survives the strip (the seam is deduped by TranscriptMarkupStripper)\n    expect(stripAllMarkup('Right. <expr type=\"sound\" label=\"laugh\"/>')).toBe('Right. ');\n  });\n\n  it('dedups the space across chunk seams', () => {\n    // the space before the marker goes out with the previous chunk, so the in-text dedup\n    // can't see it — the stripper has to close that seam itself\n    for (const chunks of [\n      ['Right. ', '<expr type=\"sound\" label=\"laugh\"/>', ' Anyway.'],\n      ['Right. ', '<expr type=\"sound\" label=\"laugh\"/> Anyway.'],\n      ['Right. ', '<sound value=\"laugh\"/>', ' Anyway.'],\n    ]) {\n      const stripper = new TranscriptMarkupStripper();\n      const out = chunks.map((c) => stripper.push(c)).join('') + stripper.flush();\n      expect(out, chunks.join('|')).toBe('Right. Anyway.');\n    }\n  });\n\n  it('leaves untagged whitespace alone', () => {\n    // without a stripped tag at the seam there is nothing to dedup: whitespace the LLM\n    // itself emitted is passed through untouched\n    let stripper = new TranscriptMarkupStripper();\n    let out = ['Right. ', ' Anyway.'].map((c) => stripper.push(c)).join('') + stripper.flush();\n    expect(out).toBe('Right.  Anyway.');\n\n    // a tag stripped earlier in the chunk doesn't license collapsing the seam either:\n    // the whitespace here trails \"hello\", not the removed tag\n    stripper = new TranscriptMarkupStripper();\n    out =\n      ['<sound value=\"x\"/>hello  ', '   world'].map((c) => stripper.push(c)).join('') +\n      stripper.flush();\n    expect(out).toBe('hello     world');\n  });\n\n  it('builds the lk.expression attribute from the leading expression', () => {\n    const [, tags] = splitAllMarkup(JOKE);\n    const attr = expressionAttribute(tags);\n    expect(attr).toBeDefined();\n    expect(Object.values(attr!)[0]).toContain('\"say playfully\"');\n  });\n\n  it('has no lk.expression attribute without an expression tag', () => {\n    const [, tags] = splitAllMarkup('Hi <expr type=\"break\" label=\"1s\"/> there.');\n    expect(expressionAttribute(tags)).toBeUndefined();\n  });\n});\n\ndescribe('normalizeMarkup', () => {\n  it.each(['xai', 'inworld', 'cartesia', 'fishaudio'])(\n    'closes an unclosed self-closing expr marker for %s',\n    (provider) => {\n      const text = '<expr type=\"sound\" label=\"laugh\"> Hello';\n      expect(normalizeMarkup(provider, text)).toBe('<expr type=\"sound\" label=\"laugh\"/> Hello');\n    },\n  );\n\n  it('leaves wrapping and already-closed tags alone', () => {\n    const text =\n      '<expr type=\"prosody\" label=\"whisper\">hi</expr> <expr type=\"break\" label=\"1s\"/> ' +\n      '<expr type=\"spell\">A7X9</expr>';\n    expect(normalizeMarkup('xai', text)).toBe(text);\n  });\n});\n\ndescribe('llmInstructions', () => {\n  it.each(['xai', 'inworld', 'cartesia', 'fishaudio'])('uses expr syntax for %s', (provider) => {\n    const instructions = llmInstructions(provider);\n    expect(instructions).toBeDefined();\n    expect(instructions).toContain('<expr');\n    expect(instructions).toContain('<expr type=\"break\" label=\"');\n  });\n\n  it('advertises Cartesia’s kinds only', () => {\n    const instructions = llmInstructions('cartesia')!;\n    // discrete emotion vocabulary, not free-form descriptions\n    expect(instructions).toContain('<expr type=\"expression\" label=\"EMOTION\"/>');\n    expect(instructions).toContain('NOT free-form');\n    expect(instructions).toContain('<expr type=\"spell\">');\n    // coarse self-closing prosody point controls\n    expect(instructions).toContain('<expr type=\"prosody\" label=\"slow\"/>');\n    // no non-verbal sounds\n    expect(instructions).not.toContain('type=\"sound\"');\n  });\n\n  it('advertises Inworld’s kinds only', () => {\n    const instructions = llmInstructions('inworld')!;\n    // free-form delivery descriptions + Inworld's own sound list\n    expect(instructions).toContain('<expr type=\"expression\" label=\"DESCRIPTION\"/>');\n    expect(instructions).toContain('free-form');\n    expect(instructions).toContain('clear throat');\n    // no wrapping prosody, no spell\n    expect(instructions).not.toContain('type=\"prosody\"');\n    expect(instructions).not.toContain('type=\"spell\"');\n  });\n\n  it('advertises xAI’s kinds only', () => {\n    const instructions = llmInstructions('xai')!;\n    // xAI's own sound cues + wrapping prosody vocabulary\n    expect(instructions).toContain('tongue-click');\n    expect(instructions).toContain('<expr type=\"prosody\" label=\"STYLE\">');\n    expect(instructions).toContain('sing-song');\n    // no free-form delivery descriptions, no spell\n    expect(instructions).not.toContain('type=\"expression\"');\n    expect(instructions).not.toContain('type=\"spell\"');\n  });\n\n  it('is undefined for a provider with no markup dialect', () => {\n    expect(llmInstructions('')).toBeUndefined();\n    expect(llmInstructions('openai')).toBeUndefined();\n    expect(llmInstructions('rime')).toBeUndefined();\n  });\n\n  it('omits a sound category that steering disables, and its examples', () => {\n    const instructions = llmInstructions('inworld', { nonverbalSounds: { laughing: false } })!;\n    expect(instructions).not.toContain('label=\"laugh\"');\n    expect(instructions).toContain('clear throat');\n  });\n\n  it('omits the whole sounds section when every sound is disabled', () => {\n    const instructions = llmInstructions('inworld', { nonverbalSounds: false })!;\n    expect(instructions).not.toContain('type=\"sound\"');\n  });\n\n  it('renders identically when steering explicitly enables everything', () => {\n    expect(llmInstructions('xai', { nonverbalSounds: true })).toBe(llmInstructions('xai'));\n    expect(llmInstructions('xai', {})).toBe(llmInstructions('xai'));\n  });\n});\n\n// assistant text mixing expr markers with content that must survive an expr-only strip:\n// provider-native tags, bracket spans, markdown links, and stray angle brackets\nconst MIXED =\n  '<expr type=\"expression\" label=\"happy\"/> Press [Enter] to see <b>bold</b>, ' +\n  'read [the docs](https://docs.livekit.io), then 1 < 2. <break time=\"1s\"/> ' +\n  '<expr type=\"prosody\" label=\"whisper\">keep it secret</expr>';\nconst MIXED_CLEAN =\n  ' Press [Enter] to see <b>bold</b>, ' +\n  'read [the docs](https://docs.livekit.io), then 1 < 2. <break time=\"1s\"/> ' +\n  'keep it secret';\n\ndescribe('stripExprMarkup', () => {\n  it('only touches expr', () => {\n    expect(stripExprMarkup(MIXED)).toBe(MIXED_CLEAN);\n  });\n\n  it('is a no-op without expr', () => {\n    const text = 'plain text with [brackets] and <sound value=\"laugh\"/>';\n    expect(stripExprMarkup(text)).toBe(text);\n  });\n\n  it('strips expr only from assistant textContent', () => {\n    const msg = ChatMessage.create({ role: 'assistant', content: [MIXED] });\n    expect(msg.textContent).toBe(MIXED_CLEAN);\n    expect(msg.rawTextContent).toBe(MIXED);\n  });\n\n  it.each(['user', 'system', 'developer'] as const)('leaves %s messages raw', (role) => {\n    // only assistant messages carry expressive markup; other roles are never stripped\n    const msg = ChatMessage.create({ role, content: [JOKE] });\n    expect(msg.textContent).toBe(JOKE);\n    expect(msg.rawTextContent).toBe(JOKE);\n  });\n\n  it('returns undefined without text content', () => {\n    const msg = ChatMessage.create({ role: 'assistant', content: [] });\n    expect(msg.textContent).toBeUndefined();\n    expect(msg.rawTextContent).toBeUndefined();\n  });\n\n  it('toJSON stripMarkup is expr-only and assistant-only', () => {\n    const chatCtx = ChatContext.empty();\n    chatCtx.addMessage({ role: 'user', content: [MIXED] });\n    chatCtx.addMessage({ role: 'assistant', content: [MIXED] });\n\n    let items = chatCtx.toJSON({ stripMarkup: true }).items as Array<{ content: string[] }>;\n    expect(items[0]!.content).toEqual([MIXED]); // user content untouched\n    expect(items[1]!.content).toEqual([MIXED_CLEAN]); // assistant loses only expr tags\n\n    // default keeps the raw content for persistence\n    items = chatCtx.toJSON().items as Array<{ content: string[] }>;\n    expect(items[1]!.content).toEqual([MIXED]);\n  });\n});\n\ndescribe('universal transcript stripping', () => {\n  // The transcript sinks strip downstream without knowing the provider, so they remove\n  // the union of every provider's XML tags — but never square brackets, which reach the\n  // transcript as markdown/prose.\n\n  it('strips every provider’s tags at once and leaves brackets', () => {\n    const [clean, tags] = splitAllMarkup(\n      '<emotion value=\"happy\"/>Hi <expression value=\"warm\"/>there ' +\n        '<sound value=\"giggle\"/>[pause] friend',\n    );\n    expect(clean).toBe('Hi there [pause] friend');\n    expect(tags).toContainEqual({ type: 'emotion', value: 'happy' });\n    expect(tags).toContainEqual({ type: 'expression', value: 'warm' });\n    expect(tags).toContainEqual({ type: 'sound', value: 'giggle' });\n  });\n\n  it('takes the attribute, not the wrapped words, as a delivery label', () => {\n    // the model writes `<expression value=\"warm\">…</expression>` often enough that\n    // normalizeMarkup repairs it — but that runs on the audio path only, so the sinks see\n    // the raw shape. Recording the inner text here published the agent's own sentence as\n    // lk.expression, and matchMood then fell back to `calm`.\n    const [clean, tags] = splitAllMarkup('<expression value=\"warm\">Hello there</expression>');\n    expect(clean).toBe('Hello there');\n    expect(tags).toEqual([{ type: 'expression', value: 'warm' }]);\n    expect(expressionAttribute(tags)).toEqual({\n      'lk.expression': '{\"expression\":\"warm\",\"mood\":\"happy\"}',\n    });\n  });\n\n  it('still reads a content tag from its inner text', () => {\n    // the inverse must keep working: spell/emphasis and xAI's wrapping emotion tags carry\n    // no attribute, so their content is the value\n    expect(splitAllMarkup('<spell>A7X9</spell>')[1]).toEqual([{ type: 'spell', value: 'A7X9' }]);\n    expect(splitAllMarkup('<emphasis>wow</emphasis>')[1]).toEqual([\n      { type: 'emphasis', value: 'wow' },\n    ]);\n    expect(splitAllMarkup('<happy>Great to hear!</happy>')[1]).toEqual([\n      { type: 'happy', value: 'Great to hear!' },\n    ]);\n  });\n\n  it('produces the documented lk.expression payload shape', () => {\n    let [, tags] = splitAllMarkup('<emotion value=\"sad\"/>oh no');\n    expect(expressionAttribute(tags)).toEqual({\n      'lk.expression': '{\"expression\":\"sad\",\"mood\":\"sad\"}',\n    });\n\n    // no expression/emotion tag -> no attribute\n    [, tags] = splitAllMarkup('<break time=\"1s\"/>hi');\n    expect(expressionAttribute(tags)).toBeUndefined();\n  });\n\n  it('holds partial tags while streaming', () => {\n    const s = new TranscriptMarkupStripper();\n    let out = s.push('Hi <emo');\n    out += s.push('tion value=\"happy\"/> the');\n    out += s.push('re');\n    out += s.flush();\n    expect(out).not.toContain('<emotion');\n    expect(out.replace(/ /g, '')).toBe('Hithere');\n    expect(s.expressionAttribute()).toEqual({\n      'lk.expression': '{\"expression\":\"happy\",\"mood\":\"happy\"}',\n    });\n  });\n\n  it('does not stall on an unclosed markdown link', () => {\n    const s = new TranscriptMarkupStripper();\n    // an unclosed \"[\" must not stall the chunk (brackets aren't markup), and the link must\n    // arrive intact rather than collapsed to its (url) tail\n    const first = s.push('Read [the docs](https:');\n    expect(first).toBe('Read [the docs](https:');\n    const rest = s.push('//docs.livekit.io) now.') + s.flush();\n    expect(first + rest).toBe('Read [the docs](https://docs.livekit.io) now.');\n  });\n\n  it('does not stall on a bare \"<\"', () => {\n    const s = new TranscriptMarkupStripper();\n    const first = s.push('The value 3 < 5 ');\n    expect(first).toContain('3 < 5');\n    const rest = s.push('is true.') + s.flush();\n    expect((first + rest).replace(/ /g, '')).toBe('Thevalue3<5istrue.');\n  });\n\n  it('strips nested emotion + prosody cleanly', () => {\n    // combining emotion + prosody means nesting; the transcript must come out clean (no\n    // leaked inner markup) — this is what the fixed-point strip guarantees\n    const raw =\n      '<excited><loud><higher-pitch>no way</higher-pitch></loud></excited> ' +\n      '<sound value=\"laugh\"/> okay';\n    const [clean] = splitAllMarkup(raw);\n    expect(clean).not.toContain('<');\n    expect(clean).not.toContain('>');\n    expect(clean).toContain('no way');\n    expect(clean).toContain('okay');\n  });\n});\n\ndescribe('speech steering', () => {\n  it('renders nothing for the explicit all-on forms', () => {\n    // equivalent configurations must produce identical instructions: the explicit all-on\n    // forms add no sound guidance the default doesn't have\n    for (const provider of ['fishaudio', 'inworld', 'xai']) {\n      for (const steering of [{ nonverbalSounds: true } as const, { nonverbalSounds: {} }]) {\n        expect(steeringInstructions(provider, steering), provider).toBe('');\n        expect(llmInstructions(provider, steering), provider).toBe(llmInstructions(provider));\n      }\n    }\n    // all-off leaves nothing to guide; the vocabulary removal happens in llmInstructions\n    expect(steeringInstructions('fishaudio', { nonverbalSounds: false })).toBe('');\n  });\n\n  it('guides only about the sounds that survive an opt-out', () => {\n    const partial = steeringInstructions('fishaudio', { nonverbalSounds: { laughing: false } });\n    expect(partial).toContain('clear-throat');\n    expect(partial.toLowerCase()).not.toContain('laugh');\n  });\n\n  it('renders pace and disfluency guidelines', () => {\n    expect(steeringInstructions('inworld', { disfluencies: false })).toContain('No fillers');\n    expect(steeringInstructions('inworld', { pace: 'slow' })).toContain('slow overall speaking');\n    // \"normal\" is the default, so it adds nothing\n    expect(steeringInstructions('inworld', { pace: 'normal' })).toBe('');\n  });\n\n  it('never mentions an opted-out concept, not even prohibitively', () => {\n    const composed = llmInstructions('fishaudio', {\n      nonverbalSounds: false,\n      disfluencies: false,\n    })!;\n    expect(composed.toLowerCase()).not.toContain('laugh');\n    expect(composed.toLowerCase()).not.toContain('filler');\n    expect(composed).not.toContain('Um, uh');\n  });\n\n  it('few-shots fillers only while disfluencies are enabled', () => {\n    expect(llmInstructions('fishaudio', { disfluencies: true })).toContain('Um, uh');\n    expect(llmInstructions('fishaudio')).toContain('Um, uh'); // default is on\n    const off = llmInstructions('fishaudio', { disfluencies: false })!;\n    expect(off).not.toContain('Um, uh');\n    expect(off).not.toContain(', um,');\n  });\n\n  it('exposes the queryable non-verbal capability matrix', () => {\n    expect(supportedNonverbals('fishaudio')).toEqual({\n      laughing: ['laughing', 'chuckling'],\n      breathing: ['gasping'],\n      sighing: ['sighing'],\n      crying: ['sobbing'],\n      vocalizing: ['groaning'],\n      reflexSounds: ['clear throat', 'yawning'],\n    });\n    expect(supportedNonverbals('cartesia')).toEqual({});\n  });\n\n  it('treats a category object as a sparse opt-out', () => {\n    // omitted categories stay enabled, so { laughing: false } removes laughter and\n    // nothing else\n    const steering = { nonverbalSounds: { laughing: false } };\n    const inworld = llmInstructions('inworld', steering)!;\n    expect(inworld).not.toContain('label=\"laugh\"');\n    for (const kept of ['sigh', 'breathe', 'clear throat', 'cough', 'yawn']) {\n      expect(inworld, kept).toContain(kept);\n    }\n    // xai's laugh-family prosody is governed by the same field\n    const xai = llmInstructions('xai', steering)!;\n    expect(xai).not.toContain('laugh-speak');\n    expect(xai).toContain('whisper');\n  });\n\n  it('carries the register rule in every provider’s block', () => {\n    // register inference is provider-neutral: every markup-capable provider's block\n    // carries the rule via the shared preamble\n    for (const provider of ['fishaudio', 'inworld', 'xai', 'cartesia']) {\n      expect(llmInstructions(provider), provider).toContain('REGISTER of the moment');\n    }\n  });\n});\n\ndescribe('expressive chunking', () => {\n  // a typical expressive reply: three short sentences with markers, ~270 chars — well\n  // under every provider's request cap\n  const REPLY =\n    '<expr type=\"expression\" label=\"really amiable and welcoming\"/> Hey, good to hear from you! ' +\n    '<expr type=\"expression\" label=\"gently inquisitive\"/> How did the interview go? ' +\n    '<expr type=\"expression\" label=\"really bright, upbeat energy\"/> I have been thinking about it all week.';\n\n  /** Feed the reply in LLM-sized chunks; report what the TTS would have received and when. */\n  async function synthesisRequests(provider: string, expressive: boolean) {\n    const stream = sentenceTokenizer(provider, { expressive }).stream();\n    const tokens: string[] = [];\n    const reader = (async () => {\n      for await (const ev of stream) tokens.push(ev.token);\n    })();\n\n    for (const chunk of REPLY.match(/.{1,12}/gs) ?? []) stream.pushText(chunk);\n    await new Promise((r) => setImmediate(r));\n    // everything emitted at this point went out while the LLM was still generating\n    const duringStream = [...tokens];\n\n    stream.endInput();\n    await reader;\n    return { duringStream, total: tokens.length, first: tokens[0] ?? '' };\n  }\n\n  it.each(['inworld', 'xai', 'cartesia'])(\n    'leaves time-to-first-audio unchanged for %s',\n    async (provider) => {\n      const plain = await synthesisRequests(provider, false);\n      const expressive = await synthesisRequests(provider, true);\n\n      // regression: the batch target used to be the provider's request cap (400–1000\n      // chars). A typical reply never reaches it, so nothing was sent until generation\n      // finished and the whole turn was synthesized in one request — first audio waited\n      // for the full completion.\n      expect(expressive.duringStream.length).toBeGreaterThan(0);\n      expect(expressive.first).toBe(plain.first);\n\n      // ...while still batching the body of the turn into fewer requests than per-sentence\n      expect(expressive.total).toBeLessThan(plain.total);\n    },\n  );\n\n  it('keeps fishaudio per-sentence', async () => {\n    // its markers are sentence-scoped, so batching would cost first-audio and buy no\n    // steering — it is deliberately absent from the chunk-limit table\n    const plain = await synthesisRequests('fishaudio', false);\n    const expressive = await synthesisRequests('fishaudio', true);\n    expect(expressive.total).toBe(plain.total);\n  });\n\n  it('never exceeds the provider request cap', async () => {\n    const long = Array.from({ length: 40 }, (_, i) => `This is sentence number ${i}.`).join(' ');\n    const stream = sentenceTokenizer('cartesia', { expressive: true }).stream();\n    const tokens: string[] = [];\n    const reader = (async () => {\n      for await (const ev of stream) tokens.push(ev.token);\n    })();\n    stream.pushText(long);\n    stream.endInput();\n    await reader;\n\n    expect(tokens.length).toBeGreaterThan(1);\n    for (const t of tokens) expect(t.length).toBeLessThanOrEqual(maxInputLen('cartesia')!);\n  });\n});\n\ndescribe('mood matching', () => {\n  it('normalizes free-form delivery labels', () => {\n    expect(matchMood('soft, with genuine care')).toBe('empathetic');\n    expect(matchMood('gently curious, welcoming')).toBe('curious');\n    // word starts only: \"like a pirate\" must not match `angry` via the \"irate\" stem\n    expect(matchMood('like a pirate')).toBe('calm');\n    expect(matchMood('like a pirate', null)).toBeNull();\n  });\n\n  it('resolves every advertised Fish emotion to a real mood', () => {\n    // lk.expression consumers get a meaningful enum for the whole vocabulary\n    const instructions = llmInstructions('fishaudio')!;\n    for (const emotion of ['regretful', 'hopeful', 'delighted', 'determined', 'frustrated']) {\n      expect(instructions).toContain(emotion);\n      expect(matchMood(emotion, null), emotion).not.toBeNull();\n    }\n  });\n});\n\ndescribe('dropBracketCues', () => {\n  const timed = (text: string) => createTimedString({ text, startTime: 0, endTime: 1 });\n\n  it('drops a native cue and one of the spaces it sat between', () => {\n    const held: TimedString[] = [];\n    const out = dropBracketCues(['Right.', ' ', '[laughing]', ' ', 'Anyway.'].map(timed), held, {\n      final: true,\n    });\n    expect(out.map((t) => t.text).join('')).toBe('Right. Anyway.');\n  });\n\n  it('holds an unclosed span across messages until it closes', () => {\n    const held: TimedString[] = [];\n    let out = dropBracketCues(['Hello ', '[lau'].map(timed), held);\n    expect(out.map((t) => t.text).join('')).toBe('Hello ');\n    expect(held.length).toBeGreaterThan(0);\n\n    // the cue and the space after it are gone; \"Hello \" already went out above, so the\n    // seam still reads as a single separator\n    out = dropBracketCues(['ghing] there'].map(timed), held);\n    expect(out.map((t) => t.text).join('')).toBe('there');\n  });\n\n  it('releases an unresolved span at end of stream', () => {\n    const held: TimedString[] = [];\n    dropBracketCues([timed('Hello [lau')], held);\n    const out = dropBracketCues([], held, { final: true });\n    expect(out.map((t) => t.text).join('')).toBe('[lau');\n  });\n});\n"],"mappings":"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","names":[]}