Works withPipecat, LiveKit and ElevenLabs

Fix what your voice agent hears, and the conversation fixes itself.

Tenms cleans up what your voice agent hears. It removes echo and background noise, ignores “mm-hm”, and knows when the caller is done talking. Your LLM and voice stay the same.

We run one of your real calls through Tenms, live.

t = 00.00 s frame 10 msadded delay 5 msp99 46 µs / frame
Agent playbackecho reference
Caller mic, raw listeningagent echo + room noise
After Focus listeningsent to your STT
Turn eventsto your pipeline
1 interruption.backchannel ignored: agent keeps talking
2 interruption.barge_in agent stops
3 turn_prediction start the LLM early
4 turn_end 360 ms after last word
Transcript
Agent Your appointment is confirmed for Thursday at three… Caller mm-hmm Caller Actually, sorry, can we move it to Friday instead? Agent Of course. Friday at three works…
  1. 1interruption.backchannel ignored: agent keeps talking
  2. 2interruption.barge_in agent stops
  3. 3turn_prediction start the LLM early
  4. 4turn_end 360 ms after last word

Press Listen, then switch between Raw mic and After Focus while it plays. Headphones help. Simulated call with synthetic voices; event names are the engine's real output.

Where calls break

Most voice-agent failures happen before the LLM reads a word.

Better prompts and bigger models don't fix a microphone that hears the agent, a VAD that can't tell agreement from interruption, or a timeout that adds dead air to every turn.

  1. 01

    The agent hears itself and stops.

    Agent Your balance is two hundred and

    Agent Sorry, go ahead.

    On speakerphone, the agent's own voice comes back through the caller's microphone. Your VAD calls it speech and the agent cuts itself off.

    focus Focus uses the agent's playback as a reference and removes it from the mic before your STT sees it.

    33 dB echo suppression, live call

  2. 02

    “Mm-hm” stops the agent mid-sentence.

    Agent The plan includes three lines and

    Caller mm-hm

    Agent …

    The caller was agreeing, not interrupting. A VAD can't tell the difference, so the agent goes quiet and the call stalls.

    interruption.kind Turn classifies every interruption as barge_in, backchannel, noise or other_speaker. Only a real barge-in stops the agent.

    0 interruptions within 2 s of a backchannel, live

  3. 03

    Dead air after the caller finishes.

    Caller I'd like to cancel my order.

    ( silence )

    Agent I can help with that.

    The pipeline waits for a fixed silence timeout before it even calls the LLM. Every turn pays that wait.

    turn_prediction Turn emits turn_prediction ahead of turn_end so you can start the LLM early, and cancel if the caller keeps going.

    turn_end p50 360 ms, live

  4. 04

    The call failed and nobody knows why.

    Caller No, I said Austin, not Boston.

    Was it a noisy line, a bad transcript or the model? Without audio metrics every failure lands on the prompt engineer.

    CallSummary Pulse scores SNR, clipping, dropouts, echo and overlap per call and attributes the failure to audio, transcription or LLM.

    One summary per call, no audio stored

Three modules, licensed separately

One engine. Turn on what you need.

Focus, Turn and Pulse share one 10 ms pipeline written in Rust. It allocates nothing per frame and verifies licenses offline, so the audio path never waits on a network call to us.

Focus

Clean caller audio

Echo removal using the agent's own playback, noise suppression and main-speaker lock. Your STT gets the caller and nothing else.

emits processed audio

Turn

Know when to speak and when to stop

Voice activity, predictive end of turn and interruption classification, emitted as events your pipeline already understands.

emits turn_predictionturn_endinterruption

Pulse

See why a call went wrong

Audio-quality metrics, ASR-risk prediction and failure attribution, streamed during the call and summarised at the end.

emits qualityCallSummary
How each module works

Workflows

See where it sits in a real pipeline.

Three short walkthroughs: a Pipecat agent, the ElevenLabs bridge, and Pulse explaining a failed call. Each one shows the events your code receives.

Transport caller audio
Focus tenms
Speech-to-text your provider
Turn tenms
LLM your model
Text-to-speech your voice
Event log
  1. audio16 kHz · 10 ms frames
  2. focusagent echo removed · noise suppressed
  3. stt“can we move it to Friday instead?”
  4. turninterruption.barge_in → stop playback
  5. turnturn_prediction → start the LLM early
  6. turnturn_end · silence_ms 360
  7. tts“Of course. Friday at three works.”

Focus cleans the audio before STT. Turn decides when to stop and when to answer.

Measured, not quoted

Fast enough to sit in front of every word.

Every figure below comes from our own test suite, production Edge or a live call, and each one has a source.

46µs

p99 engine compute per 10 ms frame, all modules on

Offline, 16 kHz. 50 to 65 µs on production Edge.

5ms

audio delay added to the caller's voice

At 16 kHz, confirmed in production summaries.

33dB

echo suppression on a live call

Pipecat over Daily, Nov 2026.

360ms

median end-of-turn decision after the last word

turn_end p50, p95 610 ms, live.

Full numbers, method and known limits

Integration

Ships into the stack you already run.

Run the engine inside your agent process with no network hop, or connect one WebSocket per call to Tenms Edge. ElevenLabs Agents users change one URL.

  • In-process SDKPython wheel or C library. Audio never leaves your process.
  • Tenms EdgeHosted in US West, US East, EU West and Asia Southeast.
All integration guides
from tenms.pipecat import TenmsCall

tenms = TenmsCall()  # one per call; reads TENMS_LICENSE from the env
transport = DailyTransport(room_url, token, "bot", DailyParams(
    audio_in_enabled=True, audio_out_enabled=True,
    audio_in_filter=tenms.focus_filter(),        # Focus: cleaned caller audio
    audio_out_filter=tenms.reference_filter(),   # agent playback -> echo reference
))
user_agg, assistant_agg = LLMContextAggregatorPair(context, user_params=LLMUserAggregatorParams(
    vad_analyzer=tenms.vad_analyzer(),
    user_turn_strategies=tenms.user_turn_strategies(),   # Turn
))
pipeline = Pipeline([transport.input(), stt, tenms.processor(), user_agg, llm, tts,
                     transport.output(), assistant_agg])
task = PipelineTask(pipeline, observers=[tenms.observer()])   # Pulse

Built for production review

No GPU in the bill

The whole engine runs on CPU. Capacity planning is cores, not accelerators.

No audio stored

The control plane keeps per-call quality summaries. No recordings, no transcripts.

Offline licensing

Ed25519-signed licenses, verified against keys pinned in the binary. Edge sessions end within about 90 s of revocation.

Independently reviewed

An external review of the engine, Edge, control plane and SDK. Every critical and high finding is fixed and has a regression test.

Security and data handling

Put Tenms on your worst calls.

Bring a recording your agent got wrong. In 30 minutes we run it through Focus, Turn and Pulse with your engineers and show the events your pipeline would have received.