Skip to content

feat(plugins): add Gnani plugin#2004

Open
rosetta-livekit-bot[bot] wants to merge 11 commits into
mainfrom
pocketed-retreats-symptoms
Open

feat(plugins): add Gnani plugin#2004
rosetta-livekit-bot[bot] wants to merge 11 commits into
mainfrom
pocketed-retreats-symptoms

Conversation

@rosetta-livekit-bot

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

Copy link
Copy Markdown
Contributor

Summary

Ports livekit/agents#6004 to the Node.js SDK by adding @livekit/agents-plugin-gnani, since agents-js has no existing Gnani plugin.

  • Adds Gnani STT with REST recognition and WebSocket streaming.
  • Adds Gnani TTS with REST, SSE, and WebSocket transports.
  • Adds package metadata, README, API Extractor report, lockfile integration, and a patch changeset.

Python parity and intentional adaptations

The implementation preserves the Python plugin's option names and defaults after idiomatic camelCase adaptation, REST multipart fields, WebSocket headers, voice/model updates, provider/model metadata, and usage metrics.

The public TTS output contract is intentionally narrower than Python: this JS plugin exposes only decoded linear PCM in raw or WAV containers because it has no encoded-audio decoder. Unsupported encoded formats are rejected rather than advertised or treated as PCM.

Protocol correctness

  • STT distinguishes receive deadlines from the Python-equivalent one-second final drain, rejects unexpected pre-terminal closure, and promptly terminates pending or established sockets on caller cancellation.
  • TTS uses a streaming RIFF/WAV parser that supports split headers and ancillary chunks while preserving incremental raw PCM emission.
  • REST, SSE, and WebSocket output never emit empty final frames; exact-aligned audio marks the actual final frame.
  • REST/SSE response handling distinguishes caller cancellation, timeout, provider status, and network/body failures for both TTS and STT.

API, options, and metrics

  • Unknown constructor/update options are rejected where Python rejects them.
  • TTS.updateOptions() accepts only Python-equivalent mutable voice and model fields.
  • Public aliases and resolved option types referenced by exported interfaces are exported; API Extractor reports no forgotten exports.
  • Request payloads and stream metrics snapshot the same model, so an in-flight request remains attributed to its original model after updateOptions() while subsequent requests use the new model.

Validation

  • 106 focused Gnani tests pass.
  • Gnani package build, API check, lint, and formatting pass.
  • Full repository build, lint, and formatting checks passed during verification.

Exact-head Cue voice evidence

Verified remote head 02a10db247665ca503c645d25dcc3f627779e2a2 with Cue session sid_e4df0b706ef6 using a disclosed deterministic, protocol-compatible Gnani boundary because GNANI_API_KEY was unavailable.

Predicate:

user_input_transcribed(.is_final=true) -> agent_state_changed(.new_state="AS_SPEAKING") -> conversation_item_added(.item.message.role="ASSISTANT") -> agent_state_changed(.new_state="AS_LISTENING")[30s]

The predicate resolved in 4080 ms. Persisted events show the final transcription, speaking transition, assistant commit (The exact head Gnani voice path works correctly.), and return to listening. Provider logs captured the TTS request, two binary PCM chunks totaling 32,000 bytes, and terminal complete frame.

Both flushed WAVs are non-silent:

  • Session WAV: 8.500 s, stereo 48 kHz, RMS 3400.75, SHA-256 917762bb22152fcce219506d6c8b1d005cff4826cd98af8d5ca08075437ac8f0.
  • Command WAV: 4.089 s, stereo 48 kHz, RMS 4895.98, SHA-256 1e61c0802415feeb66859dcfb87a611766aad08330a95caf77bcc679e1365a63.
  • Events: SHA-256 56e081171ec85259c6f17023bc5ba8f264a9c5c5a0d412f1c3ac22e805da7fe9.
  • Result: SHA-256 883b25c783a6a808373ef14ebc68cd1c328152eb820cd288b8a1b7fb38af3e01.
  • Provider log: SHA-256 017ef335be31e32725559c57ef674cb712e490e5ed22b02aed79ea13c47419b7.

Earlier successful sessions sid_ec92f760dc6a (at 9934a770) and sid_0f763aa3c02b are historical evidence only; sid_e4df0b706ef6 is the exact-head run.


Ported from livekit/agents#6004

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

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 02a10db

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

This PR includes changesets to release 37 packages
Name Type
@livekit/agents-plugin-gnani Patch
@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-plugin-trugen Patch
@livekit/agents-plugin-xai Patch
@livekit/agents-plugins-test 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

devin-ai-integration[bot]

This comment was marked as resolved.

toubatbrian and others added 10 commits July 15, 2026 11:53
Co-authored-by: Cursor <cursoragent@cursor.com>
Classify websocket frames by protocol metadata, decode only supported PCM containers, emit audio incrementally, and honor configured timeout and drain windows.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reject premature provider closes, cancel pending sockets promptly, and decode streamed WAV containers without corrupting final audio framing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Preserve per-payload WAV decoding and make WebSocket settlement idempotent across real abort ordering and every receive outcome.

Co-authored-by: Cursor <cursoragent@cursor.com>
Settle active receives directly and forcefully tear down established sockets on intentional cancellation while preserving graceful handshake and provider closure paths.

Co-authored-by: Cursor <cursoragent@cursor.com>
Reject unsupported option mutations, expose complete public types, and verify payload and metrics parity.

Co-authored-by: Cursor <cursoragent@cursor.com>
Limit the public audio contract to decodable PCM formats and preserve request-scoped model metadata for in-flight metrics.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep caller aborts quiet while distinguishing timeout and provider failures across REST and SSE requests.

Co-authored-by: Cursor <cursoragent@cursor.com>
Apply caller and timeout provenance while reading REST and SSE provider error bodies without losing status details.

Co-authored-by: Cursor <cursoragent@cursor.com>
Preserve caller, timeout, provider, and network provenance while reading non-2xx REST STT responses.

Co-authored-by: Cursor <cursoragent@cursor.com>

@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 found 1 new potential issue.

View 1 additional finding in Devin Review.

Open in Devin Review

Comment thread plugins/gnani/src/tts.ts
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.

1 participant