Skip to content

fix: send DTMF to active session room - #2010

Merged
toubatbrian merged 2 commits into
mainfrom
stuffing-craves-channels
Jul 15, 2026
Merged

fix: send DTMF to active session room#2010
toubatbrian merged 2 commits into
mainfrom
stuffing-craves-channels

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add the beta sendDtmfEvents tool and export it through the beta namespace.
  • Publish SIP DTMF through the active AgentSession RoomIO RTC room, falling back to getJobContext().room when RoomIO is absent.
  • Preserve Python's digit/code mapping, ordered 300 ms cadence, and first-publish-failure semantics.

Python parity

Ported from livekit/agents#6360 at Python head 0de254cd8114db4ee6122b9708ae041298640d8d.

The source fix resolves ctx.session.room_io.room first and falls back to the job room when session RoomIO is unavailable. The JS adaptation uses ctx.session._roomIO?.rtcRoom ?? getJobContext().room, milliseconds instead of seconds, and room.localParticipant.publishDtmf(code, digit). Because the target JS base did not yet contain Python's beta DTMF tool, this PR also ports the missing tool and beta exports.

Deterministic coverage

agents/src/beta/tools/send_dtmf.test.ts proves:

  • The active RoomIO RTC room wins and the job room receives zero publishes.
  • The job room is used when RoomIO is absent.
  • Events are published exactly as (1, "1"), (2, "2"), (11, "#") in order.
  • Every publish requests the 300 ms cadence through controlled promises, without elapsed-time sleeps.
  • A publish failure stops later events and returns the exact tool error.

The changeset is intentionally patch: this ports/fixes beta behavior rather than introducing a stable breaking API.

Validation

Passed on exact head 3bfaca6ffadad0f5de5225f460ded3d942a92450:

  • pnpm test agents/src/beta/tools/send_dtmf.test.ts (3/3).
  • pnpm build:agents.
  • pnpm build.
  • pnpm typecheck.
  • pnpm lint.
  • pnpm format:check.
  • git diff --check.
  • Independent spec and code-quality review.

Broader pre-existing failures remain unrelated: agents/src/voice/amd.test.ts timing/verdict cases, provider integration tests requiring available models, and API Extractor limitations/missing plugin configuration.

Cue voice E2E

  • Session: sid_de935ed216a0 in fresh voice mode.
  • Exact source: clean literal local, tracking-remote, and PR head 3bfaca6ffadad0f5de5225f460ded3d942a92450, reconfirmed immediately before build and execution.
  • Predicate: debug_message(.payload.predicate="pr2010_exact_head_active_room_dtmf_verified",.payload.exactHead="3bfaca6ffadad0f5de5225f460ded3d942a92450").
  • Result: resolved with exit code 0 after the final TTS speech handle completed playout.
  • Persisted payload: active room [(1,"1"), (2,"2"), (11,"#")]; job room []; tool result Successfully sent DTMF events: 1, 2, #; playoutComplete=true.
  • Result JSON: ~/.cue-cli/sessions/sid_de935ed216a0/recordings/001_run/result.json, SHA-256 3ca75cf3725af45cf465a40c74c5dc3805185288d7aa2b8635e59b6576f4aa74.
  • Events JSONL: ~/.cue-cli/sessions/sid_de935ed216a0/events.jsonl, SHA-256 5253728e8140ccedd0fe13f7f10c0e0623b5e0cdab16acec4cd7efafdbd743c7.
  • Session WAV: ~/.cue-cli/sessions/sid_de935ed216a0/recording.wav — PCM 16-bit stereo/48 kHz, 15.0815 s, 2,895,692 bytes, SHA-256 be43aad68025b81528e1b83cc1486f878f23e75c3755b1496834e0b38722d014; agent channel -27.0 dB mean, Cue channel silent.
  • Command WAV: ~/.cue-cli/sessions/sid_de935ed216a0/recordings/001_run/recording.wav — PCM 16-bit stereo/48 kHz, 8.389646 s, 1,610,856 bytes, SHA-256 2f866d8748c8db6b1d2004a716cf281f624f0cc6f5bb6687a53142f999657c09; agent channel -24.5 dB mean, Cue channel silent.

Boundary disclosure: Cue used a real LiveKit voice room and real Cartesia TTS playout. Warm-transfer separation used a deterministic controlled RTC-compatible boundary: the actual beta.sendDtmfEvents tool received a transferred-session RoomIO with a controlled active participant, while the real job-room participant publish boundary was intercepted independently. This proves exact room selection and emission without a SIP trunk or human supervisor; it is not a production telephony-provider call.


Original PR description

The send_dtmf_events tool resolved the room from the job context, which is always the original caller room. During a warm transfer the tool runs in a separate session bound to a different room, so DTMF was published to the caller instead of the transferee.

This resolves the room from the run context session (ctx.session.room_io.room), falling back to the job context when the session has no room I/O.

Fixes #6357

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from a team as a code owner July 9, 2026 12:21
@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 3bfaca6

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 36 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-anthropic Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-did Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-soniox Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugins-test Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugin-xai Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@rosetta-livekit-bot
rosetta-livekit-bot Bot requested a review from longcw July 9, 2026 12:22

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

Add deterministic coverage for room selection, event cadence, and publish failures while correcting the release level to patch.

Co-authored-by: Cursor <cursoragent@cursor.com>
@toubatbrian
toubatbrian merged commit 508236a into main Jul 15, 2026
9 checks passed
@toubatbrian
toubatbrian deleted the stuffing-craves-channels branch July 15, 2026 20:52
@github-actions github-actions Bot mentioned this pull request Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants