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.

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.

Two ways to run it

In-process SDKTenms Edge
Where the engine runsInside your agent processTenms Edge, one WebSocket per call
Network hop on the audio pathNoneOne round trip to the nearest region
Audio leaves your infrastructureNoStreamed to Edge, processed in memory, not stored
PackagingPython wheel, C library (tenms.h)Any WebSocket client; Python client included
License checkOffline, against keys pinned in the binaryPer connection, with live revocation
Best forPipecat and LiveKit agents you hostElevenLabs 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", ...}

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()])   # Pulse

Tested 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 dict

Full 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.