better-sandwich-65834
05/13/2026, 2:41 PMdtmf
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:
{"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:
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.tall-airline-16756
05/13/2026, 2:41 PMtall-airline-16756
05/13/2026, 2:42 PMdtmf-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 `#`:
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:
@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