LiveKit Support for Transcript Normalization Before LLM Calls

Hi LiveKit Team,

We’re using LiveKit Agents (1.5.16) with Azure OpenAI (gpt-5.4 via openai.LLM.with_azure).

We’re seeing Azure Prompt Shield false positives when callers spell their names letter-by-letter (e.g. “S A H I L”). Azure rejects the request with:

{
“error”: {
“code”: “content_filter”,
“status”: 400,
“message”: “The response was filtered due to the prompt triggering Azure OpenAI’s content management policy…”,
“innererror”: {
“code”: “ResponsibleAIPolicyViolation”,
“content_filter_result”: {
“hate”: { “filtered”: false, “severity”: “safe” },
“self_harm”: { “filtered”: false, “severity”: “safe” },
“sexual”: { “filtered”: false, “severity”: “safe” },
“violence”: { “filtered”: false, “severity”: “safe” },
“jailbreak”: { “detected”: true, “filtered”: true }
}
}
}
}

Have you seen this issue before, and does LiveKit provide any built-in way to preprocess or normalize STT transcripts before they are sent to the LLM (for example, converting spelled-out letters into a single word)?

@darryncampbell @Muhammad_Usman_Bashir

Interesting, I haven’t come across this before.

Anecdotally, I have heard that some customers have had success disabling the policy (as detailed here).

My immediate suggestion would be to pre-process the input using on_user_turn_completed, as documented here: Pipeline nodes and hooks | LiveKit Documentation, to preprocess the name.

Alternatively, you should also be able to use Pipeline nodes and hooks | LiveKit Documentation, but the former is likely more straight-forward.

@sahil.dutta, There’s no built-in transcript normalizer, but on_user_turn_completed is the right hook: it hands you new_message before it goes to the LLM, and editing it there is explicitly the documented way to change what’s sent [ Pipeline nodes and hooks | LiveKit Documentation ].

One gotcha: text_content is read-only (it just joins the string parts of content) [ livekit/agents llm/chat_context.py ], so write the normalized text back via new_message.content:

import re
from livekit.agents import Agent, llm

class MyAgent(Agent):
    async def on_user_turn_completed(
        self, turn_ctx: llm.ChatContext, new_message: llm.ChatMessage
    ) -> None:
        text = new_message.text_content
        if text:
            # collapse runs of spelled-out letters: "S A H I L" -> "SAHIL"
            normalized = re.sub(r"\b(?:[A-Za-z] ){2,}[A-Za-z]\b",
                                lambda m: m.group(0).replace(" ", ""), text)
            new_message.content = [normalized]

That keeps the spelled-name turn from reaching Prompt Shield as "S A H I L" while leaving normal turns untouched. Since your error shows jailbreak=true specifically on the spaced letters, collapsing them is usually enough without disabling the Azure policy. The regex is a starting point; tighten it to your name/digit patterns.