Let me read the agent code to understand the curre...
# ask-ai
b
Let me read the agent code to understand the current DTMF handling before formulating the question. Searched for regex
dtmf
Searched for files matching
/Users/deadsage14235icloud.com/Documents/scnsoft_workflow/rfp-atlascredit-voice-bot/backend/**/*.py
Searched for regex
dtmf|on_dtmf|SipDTMF|sip_dtmf|keypad|digit
Searched for regex
on_data|data_received|SipDTMF|dtmf_received|RoomEvent|DataPacket|room\.on|ctx\.room
Read [](file:///Users/deadsage14235icloud.com/Documents/scnsoft_workflow/rfp-atlascredit-voice-bot/backend/application_verification_flow.py) Now I have full context. Here's the comprehensive question to post to the LiveKit community (Discord/GitHub): --- ## LiveKit Community Question: DTMF Inputs Logged But Agent Never Reacts System overview: We're running a Python outbound voice bot using
livekit-agents
v1.x with the following stack: -
AgentSession[SessionState]
with
openai.realtime.RealtimeModel
(LLM) +
openai.STT
+
silero.VAD
- Outbound SIP call via
ctx.api.sip.create_sip_participant()
(Twilio/Telnyx trunk) - Multi-agent chain:
GreetingsAgent → IdentityVerifyAgent → ApplicationAgent
- Agent registered via
WorkerOptions(entrypoint_fnc=entrypoint, agent_name="atlas_credit_voice_bot")
The problem: DTMF inputs from the phone caller are being received and logged correctly:
Copy code
{"message": "DTMF inputs: 1", ...}
{"message": "DTMF inputs: 1 1", ...}
{"message": "DTMF inputs: 1 1 1", ...}
... (accumulates every ~350ms, up to 16+ presses)
The log source is
"name": "dtmf-inputs"
— so LiveKit is clearly capturing the keypresses. However, the agent never acts on them. The LLM is not informed, the conversation doesn't branch, no tool is triggered. Our
entrypoint
registers only these event handlers:
Copy code
python
@session.on("user_state_changed")
def on_user_state_changed(event): ...

@session.on("agent_state_changed")
def on_agent_state_changed(event): ...

@session.on("metrics_collected")
def _on_metrics_collected(ev): ...
There is no DTMF handler anywhere in our agent code. Questions: 1. Where does the
"dtmf-inputs"
logger originate?
Is it inside the
livekit-agents
SDK itself, or a SIP plugin? We didn't write this logger — it appears to be internal. 2. What is the correct way to subscribe to DTMF events in the Agents v1 framework? Is it
ctx.room.on("sip_dtmf_received", handler)
on the
Room
object, or is there a session-level event like
session.on("dtmf_received")
? 3. Does
AgentSession
/
RealtimeModel
automatically inject DTMF digits into the LLM context, or must we manually feed them?
We want the LLM to be aware that the user pressed
1234#
on the keypad so it can treat it as identity input (e.g., SSN digits). 4. For collecting a sequence of DTMF digits (e.g., wait for
#
terminator or a 4-digit timeout), is there a built-in accumulator in the SDK, or do we need to implement our own buffer with a debounce timer?
5. Is the current behavior (accumulating DTMF in a list, logged every keypress) the intended SDK behavior, or does it indicate a misconfiguration on our end? What we need to achieve: When the caller enters their SSN last 4 digits via keypad (e.g.,
1 2 3 4 #
), the agent should collect the full sequence, then call our existing
verify_ssn_last4(ssn_last4="1234")
function tool — the same tool that handles spoken input. Ideally the same tool works for both speech and DTMF. LiveKit version:
livekit-agents
v1.x (checking exact pin),
livekit
Python SDK matching. --- Post this to the LiveKit Discord
#agents
channel or open a GitHub Discussion on
livekit/agents
. The key gap is that your code has no
dtmf
event subscription — the SDK logs it internally but your entrypoint never wires a handler, so the digits vanish after logging.
✅ 1
t
Thanks for reaching out, Aleh. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’ve reviewed your notes and the question you plan to post. I’ll answer each of your numbered questions and then give a concise recommended next step you can paste into the community post. Acknowledgement • You’re asking about why
dtmf-inputs
logs appear while the agent never reacts, how to subscribe to DTMF in Agents v1, whether DTMF is injected into the LLM, whether there’s an accumulator/timeout built in, and whether the observed behavior is expected. Answers 1) Where the
"dtmf-inputs"
logger originates • That logger comes from the Agents SDK’s SIP/media pipeline (part of the livekit-agents runtime), not from your code. It indicates the SDK captured DTMF at the transport/media layer. 2) How to subscribe to DTMF events in Agents v1 • You must explicitly register a handler. Use the Room-level event (e.g.,
ctx.room.on("dtmf_received", handler)
) or use the prebuilt DTMF task. There is no automatic
session.on("dtmf_received")
hookup you get for free in your entrypoint unless you add it. 3) Does AgentSession/RealtimeModel auto-inject digits into the LLM context? • No. DTMF digits are not automatically injected into the LLM conversation. You must capture digits and either update the conversation context or call your tool yourself. 4) Built-in accumulator / terminator / timeout? • There is a built-in prebuilt task for this:
GetDtmfTask
. It can collect N digits, use a terminator (e.g., `#`/POUND), and apply per-digit timeouts and optional confirmation. If you don’t use
GetDtmfTask
, you need to implement your own buffer+debounce/timeout logic. 5) Is the observed accumulating log behavior intended? • Yes: the SDK’s media pipeline will log arriving DTMF key events as they’re received. That accumulation in logs is normal, but it does not mean the agent logic or LLM was updated—without a handler or
GetDtmfTask
, digits won’t trigger tools or change conversation flow. Recommended next step (code sketch you can post or use) • Use the prebuilt
GetDtmfTask
(recommended) or subscribe to room DTMF events and then call your existing tool. Example outline: 1. Use GetDtmfTask to collect 4 digits or `#`:
Copy code
result = await GetDtmfTask(num_digits=4, dtmf_stop_event="POUND", dtmf_input_timeout=4).run(ctx)
digits = result.user_input  # e.g. "1234"
await verify_ssn_last4(ssn_last4=digits)
1. OR subscribe to room events and accumulate manually:
Copy code
@ctx.room.on("dtmf_received")
def on_dtmf(ev):
    # append digit to buffer, reset/debounce timer, on terminator or timeout call verify_ssn_last4(...)
What I can help with next • I can draft a short, copy‑paste GitHub/Discord post for you with the question + these details and the recommended code, or help adapt the event handler snippet to your entrypoint. Which would you prefer? Sources: GetDtmfTask | LiveKit Documentation, with interactive elements