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.
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.
interruption.backchannel ignored: agent keeps talking interruption.barge_in agent stops turn_prediction start the LLM early turn_end 360 ms after last word interruption.backchannel ignored: agent keeps talkinginterruption.barge_in agent stopsturn_prediction start the LLM earlyturn_end 360 ms after last wordPress 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
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.
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
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
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
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
Use cases
Support lines on speakerphone, scheduling calls full of “mm-hm”, drive-throughs over engine noise, and sales calls where the prospect cuts in.
Long explanations that survive speakerphones and “okay, okay”.
FocusTurnPulse Read the use case ›Confirm times without stopping at every “mm-hm”, and answer without dead air.
TurnFocus Read the use case ›Take orders over engine noise, the agent's own speaker and the people in the car.
FocusTurnPulse Read the use case ›Stop for objections, reply quickly, and know which lost calls were the line.
TurnPulse Read the use case ›Three modules, licensed separately
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.
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.
Know when to speak and when to stop
Voice activity, predictive end of turn and interruption classification, emitted as events your pipeline already understands.
See why a call went wrong
Audio-quality metrics, ASR-risk prediction and failure attribution, streamed during the call and summarised at the end.
Workflows
Three short walkthroughs: a Pipecat agent, the ElevenLabs bridge, and Pulse explaining a failed call. Each one shows the events your code receives.
Focus cleans the audio before STT. Turn decides when to stop and when to answer.
Your client keeps the ElevenLabs SDK. Only the WebSocket URL changes.
Pulse measures the line during the call and attributes the failure when it ends.
Measured, not quoted
Every figure below comes from our own test suite, production Edge or a live call, and each one has a source.
p99 engine compute per 10 ms frame, all modules on
Offline, 16 kHz. 50 to 65 µs on production Edge.
audio delay added to the caller's voice
At 16 kHz, confirmed in production summaries.
echo suppression on a live call
Pipecat over Daily, Nov 2026.
median end-of-turn decision after the last word
turn_end p50, p95 610 ms, live.
Integration
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.
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 from livekit.agents import AgentSession, room_io
from livekit.plugins import tenms
call = tenms.TenmsLiveKit()
session = AgentSession(stt=..., llm=..., tts=..., vad=call.vad(),
turn_handling={"turn_detection": call.turn_detector(),
"interruption": {"mode": "vad", "min_duration": 0.3}})
await session.start(agent=tenms.TenmsAgent(call, instructions="..."), room=ctx.room,
room_options=room_io.RoomOptions(audio_input=room_io.AudioInputOptions(
noise_cancellation=call.noise_cancellation())))
call.attach(session) // Your backend exchanges the license for a 5-minute session token.
// The browser keeps the ElevenLabs SDK; only the URL changes.
Conversation.startSession({
signedUrl: `wss://edge.tenms.cloud/v1/elevenlabs/stream?agent_id=${agentId}&token=${token}`,
connectionType: "websocket",
}); from tenms.edge import EdgeClient
# focus_profile="stt" is the default: cleaned audio for your speech-to-text
async with EdgeClient("wss://edge.tenms.cloud", token, sample_rate=16000, focus_profile="stt") as edge:
await edge.send_reference(agent_chunk) # optional: what the agent is playing
await edge.send_audio(mic_chunk) # int16 bytes or numpy
processed = edge.audio_nowait() # Focus output
summary = await edge.end() # CallSummary dict Built for production review
The whole engine runs on CPU. Capacity planning is cores, not accelerators.
The control plane keeps per-call quality summaries. No recordings, no transcripts.
Ed25519-signed licenses, verified against keys pinned in the binary. Edge sessions end within about 90 s of revocation.
An external review of the engine, Edge, control plane and SDK. Every critical and high finding is fixed and has a regression test.
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.