Integrations
Ships into the stack you already run.
Tenms fills slots your framework already has: the input filter, the VAD, the turn detector. Nothing else in your pipeline changes.
- audio16 kHz · 10 ms frames
- focusagent echo removed · noise suppressed
- stt“can we move it to Friday instead?”
- turninterruption.barge_in → stop playback
- turnturn_prediction → start the LLM early
- turnturn_end · silence_ms 360
- tts“Of course. Friday at three works.”
Focus cleans the audio before STT. Turn decides when to stop and when to answer.
- POST/v1/session-tokens
- 200{ token: “tenms1…”, ttl: 300 s }
- wssConversation.startSession({ signedUrl })
- edgelicense verified · agent allowed
- edgecaller audio cleaned in 10 ms frames
- agentagent_response → used to reject echoed words
Your client keeps the ElevenLabs SDK. Only the WebSocket URL changes.
- callstarted · source pipecat
- qualitysnr_db 6.4 · mos 2.9 · asr_risk 0.41
- qualitydropout_ratio 0.04
- failurecause audio · confidence 0.7
- reasonslow SNR, packet dropouts
- dashboardfailed calls by cause and region
Pulse measures the line during the call and attributes the failure when it ends.
Two ways to run it
| In-process SDK | Tenms Edge | |
|---|---|---|
| Where the engine runs | Inside your agent process | Tenms Edge, one WebSocket per call |
| Network hop on the audio path | None | One round trip to the nearest region |
| Audio leaves your infrastructure | No | Streamed to Edge, processed in memory, not stored |
| Packaging | Python wheel, C library (tenms.h) | Any WebSocket client; Python client included |
| License check | Offline, against keys pinned in the binary | Per connection, with live revocation |
| Best for | Pipecat and LiveKit agents you host | ElevenLabs Agents, browsers, other languages |
Focus profiles
One field picks how Focus cleans.
Leave it on stt for anything your agent transcribes. Switch to a listening profile for audio people hear. The listening profiles are never meant for STT input, and the ElevenLabs bridge rejects the two model tiers.
stt- Default on Edge, the ElevenLabs bridge, Pipecat and LiveKitEverywhere
listening- Full suppression for audio people hear; default of tenms.EngineEverywhere
listening_mini- Recordings, review, listen-inEdge, Python SDK, CLI, Rust, C
listening_pro- Best listening quality, 27–30 msEdge replicas with the enhancer loaded, CLI
Unknown values fail with bad_message; a tier the server has not loaded returns profile_unavailable; a full listening_pro replica returns the retryable profile_capacity. Source: API.md. Compare the profiles.
// First message on /v1/stream. Default is "stt" (audio for your STT).
// "listening", "listening_mini", "listening_pro": audio people listen to.
{"type": "start", "sample_rate": 16000, "focus_profile": "listening_mini"}
// The server echoes it back:
{"type": "ready", "focus_profile": "listening_mini", ...} from tenms.edge import EdgeClient
# Supervisor listen-in: the best listening quality Edge offers, 27-30 ms.
async with EdgeClient(EDGE_URL, token, sample_rate=16000,
focus_profile="listening_pro") as edge:
... import tenms
# Agent audio for your STT
engine = tenms.Engine(16000, focus_profile="stt")
# Call recordings for review: our trained model's Focus head, same 5-8 ms
review = tenms.Engine(16000, focus_profile="listening_mini") // The ElevenLabs bridge accepts stt (default) and listening only:
// its audio goes to ElevenLabs' speech recogniser.
wss://${EDGE_HOST}/v1/elevenlabs/stream?agent_id=${agentId}&token=${token}&focus_profile=stt Live-tested over Daily
Pipecat
Tenms drops into the transport filters, the VAD analyzer and the user-turn strategies. Your STT, LLM and TTS stay exactly as they are.
- Focus as the transport's audio_in_filter
- Agent playback captured by reference_filter for echo removal
- Turn replaces the VAD and turn strategies
- Pulse summary through a pipeline observer
- Focus runs the stt profile by default
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()]) # PulseTested against livekit-agents 1.8
LiveKit Agents
A LiveKit plugin that supplies the VAD, turn detector and noise cancellation slots of AgentSession, with one attach call for the summary.
- call.vad() and call.turn_detector() in AgentSession
- Focus through noise_cancellation in the room input options
- TenmsAgent feeds the agent's speech as echo reference
- Focus runs the stt profile by default
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)Live, verified end to end
ElevenLabs Agents
Tenms Edge speaks the unmodified ElevenLabs Agents protocol. Your browser or app keeps the ElevenLabs SDK and points it at Edge instead. Edge cleans the caller's audio and forwards it to your agent.
- Your backend exchanges the license for a 5-minute session token
- The license lists which ElevenLabs agent IDs it may reach
- The agent's own replies are used to reject echoed words
- ?focus_profile= takes stt (default) or listening
curl -X POST "$TENMS_CONTROL_URL/v1/session-tokens" \
-H "Authorization: Bearer $TENMS_LICENSE"
# -> {"token": "tenms1...", "expires_at": ...}// 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_HOST}/v1/elevenlabs/stream?agent_id=${agentId}&token=${token}`,
connectionType: "websocket",
});Live in 4 regions
Edge WebSocket
Any stack, any language. Open one WebSocket per call, stream 16-bit PCM in, and get processed audio and JSON events back on the same socket.
- 8, 16, 24 or 48 kHz
- Optional agent reference stream for echo removal
- Pick a Focus profile per call in start: stt by default
- Send agent_speaking and transcripts to sharpen interruption decisions
- CallSummary returned on end
from tenms.edge import EdgeClient
# focus_profile="stt" is the default: cleaned audio for your speech-to-text
async with EdgeClient(EDGE_URL, 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 dictFull protocol, error codes and configuration.
Read the documentation ›Integrate with our engineers on the call.
Bring your pipeline and a recording your agent got wrong. We wire Tenms in with you and compare the events side by side.