Skip to content

feat(amd): port AMDResult → AMDPredictionEvent + event emission from python#1393

Closed
toubatbrian wants to merge 1 commit intomainfrom
claude/quirky-galileo-1K2NJ
Closed

feat(amd): port AMDResult → AMDPredictionEvent + event emission from python#1393
toubatbrian wants to merge 1 commit intomainfrom
claude/quirky-galileo-1K2NJ

Conversation

@toubatbrian
Copy link
Copy Markdown
Contributor

Summary

Automated port of livekit/agents#5621 (feat(amd): add remote session event for amd AGT-2828) — a core-runtime change to the Answering Machine Detection module.

This is an automated Claude Code routine created by @toubatbrian. Right now it is in experimentation stage.

What's ported

agents/src/voice/amd.ts

  • Renamed AMDResultAMDPredictionEvent to match Python's new event-shaped name. AMDResult is preserved as a @deprecated type alias re-exporting AMDPredictionEvent so existing JS consumers don't immediately break (Python performed a hard rename; we soften this for the JS port — see Implementation nuances below).
  • AMD now extends EventEmitter (typed via @livekit/typed-emitter with an AMDCallbacks map). It emits 'amd_prediction' once a prediction settles, mirroring Python's _AMDClassifierAMD event chain. Subscribers register with amd.on('amd_prediction', listener).
  • Added a type: 'amd_prediction' discriminator on the payload. This makes AMDPredictionEvent consistent with the rest of the JS event types in voice/events.ts (e.g. UserInputTranscribedEvent, MetricsCollectedEvent) which all use a type literal.
  • Added optional speechDurationMs on the payload. Computed from existing speechStartedAt / new speechEndedAt tracking inside the detector, populated for both heuristic and LLM-driven verdicts. (See Implementation nuances for why this is in ms and optional.)
  • The finish() method now emits amd_prediction immediately before resolving the execute() promise, so listeners and await amd.execute() callers see the same payload.

agents/src/voice/amd.test.ts

  • Updated to assert the new type: 'amd_prediction' discriminator on the resolved value.
  • Added an explicit amd.on('amd_prediction', ...) subscriber that verifies the event fires exactly once and carries the right category, alongside the existing execute() resolution assertion.

agents/src/voice/remote_session.ts

  • Added a TODO(amd_prediction) marker on SessionHost next to the other on* handlers, pointing at the spot where Python's _on_amd_prediction belongs. It is intentionally not wired up yet — see What's deferred.

Implementation nuances (where exact parity wasn't possible)

  1. Wire-format remote-session serialization is deferred. Python's PR adds a new AgentSessionEvent.AmdPrediction message and an AmdCategory enum to livekit/protocol and bumps the Python protocol dependency to >=1.1.8. The JS protocol package (@livekit/protocol@1.45.6) currently shipped in agents-js does not yet contain those types. Rather than vendoring the protobuf or adding a hand-rolled serializer, this PR leaves a TODO at the wire-up site in remote_session.ts. Once @livekit/protocol ships the AMD prediction types, a follow-up PR can:
    • subscribe SessionHost to amd.on('amd_prediction', this.onAmdPrediction) (or, more likely, expose the AMD instance through the session)
    • mirror the Python _AMD_CATEGORY_MAP in TS
    • convert speechDurationMs → seconds-typed Duration and forward via emitEvent({ case: 'amdPrediction', value: ... })
  2. AMDResult kept as a deprecated alias. Python performed a hard rename (no backward-compat alias), but Python is mid-major (1.x) and ships AMD as part of the same release window. agents-js publishes against an installed user base, so we soften the rename with export type AMDResult = AMDPredictionEvent; marked @deprecated. Same shape, no runtime impact, gives consumers one release to migrate.
  3. speechDurationMs is number | undefined (ms), not float (seconds). Python ships speech_duration: float (seconds) on the event. Per CLAUDE.md JS time-unit conventions, the JS port uses milliseconds with no InS suffix. It is also marked optional because there are paths (no-speech timeout before any VAD speaking transition) where the detector legitimately has no measured speech duration; in Python those paths fall back to self.speech_duration which the classifier always tracks, but the JS AMD class doesn't track a continuous speech duration outside an active execute() run.
  4. No delay field yet. Python's AmdPrediction proto includes a delay (LLM detection delay). The JS detector doesn't currently instrument LLM-call timing for AMD, so adding a delay field would require additional bookkeeping. Left out for this patch; will come naturally with the wire-format follow-up.
  5. Skipped Python-only changes. Per the porting policy, the following from #5621 were intentionally not ported: livekit-protocol version bump in pyproject.toml, uv.lock regeneration, # type: ignore[assignment] annotation in llm/_provider_format/openai.py, fal-plugin await correctness fix, spitch-plugin # type: ignore cleanup. None of these have JS equivalents.
  6. Example update skipped. Python touched examples/telephony/amd.py to make SIP optional. The agents-js examples don't ship a corresponding AMD telephony example, so there is nothing to mirror.

Test plan

  • pnpm vitest run src/voice/amd.test.ts — 4/4 pass
  • pnpm vitest run src/voice/amd.test.ts src/voice/agent.test.ts — 22/22 pass
  • pnpm build:agents — clean build
  • pnpm format:write — formatting clean
  • pnpm lint on touched files (amd.ts, amd.test.ts, remote_session.ts) — no new errors (pre-existing repo-wide warnings unrelated)
  • (Manual) verify in agents playground / a real call — the AMD path requires a live SIP setup and isn't covered by the JS unit tests

Notes

  • Changeset added: .changeset/amd-prediction-event.md (@livekit/agents: patch).
  • Wire-format follow-up tracked via the inline TODO(amd_prediction) in voice/remote_session.ts.

cc @toubatbrian @livekit/agent-devs

https://claude.ai/code/session_01EKYkaTHopcXtBQXb8d4yrV


Generated by Claude Code

…sion

Ports livekit/agents#5621 to agents-js. The `AMD` detector now extends an
`EventEmitter` and emits `amd_prediction` with an `AMDPredictionEvent` payload
(`type: 'amd_prediction'`, plus the existing `category` / `reason` /
`transcript` / `rawResponse` / `isMachine` fields and a new optional
`speechDurationMs`). `AMDResult` is preserved as a deprecated type alias for
backward compatibility.

The remote-session wire serialization for AMD predictions is intentionally
deferred until `@livekit/protocol` ships the corresponding `AmdPrediction` /
`AmdCategory` message types; a TODO marker has been left in
`voice/remote_session.ts`.

https://claude.ai/code/session_01EKYkaTHopcXtBQXb8d4yrV
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 5, 2026

🦋 Changeset detected

Latest commit: 0116894

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

This PR includes changesets to release 29 packages
Name Type
@livekit/agents Patch
@livekit/agents-plugin-anam 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-elevenlabs Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hedra 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-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-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

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@chenghao-mou
Copy link
Copy Markdown
Member

This is a duplicate of #1394

@chenghao-mou
Copy link
Copy Markdown
Member

Going to close this as this is a duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants