@langwatch/scenario
    Preparing search index...

    Class GeminiLiveAgentAdapter

    Gemini Live native-audio adapter.

    Connects directly to the Gemini Live API via the @google/genai SDK. Audio flows bidirectionally as raw PCM16; canonical 24kHz internally, resampled to/from 16kHz at the wire boundary.

    The @google/genai package is declared as an optional peer dependency so the SDK ships without a hard Gemini coupling. Users who import this adapter must install @google/genai themselves.

    Hierarchy (View Summary)

    Index

    Constructors

    Properties

    agentSpeakingEvent?: AgentSpeakingEvent

    Set when the adapter has emitted its first agent audio chunk for the current turn — gates timing-based barge-in. Concrete adapters expose this so scenario.interrupt can wait for real speech before firing the interruption. Optional: adapters without server-VAD-style interrupt sequencing can leave it undefined.

    capabilities: AdapterCapabilities = ...

    Declaration of what this adapter can and cannot do. Concrete subclasses MUST publish a non-default value; the base instance defaults to "nothing supported" so capability-gated steps fail safely when an adapter forgets to declare.

    lastAgentTranscript: string | null = null

    Most-recent output transcript received from the server, for observability.

    model: string
    name?: string
    responseMaxDuration: number = 30.0

    Hard cap on a single agent turn's audio. Prevents runaway loops if a transport never signals end-of-stream. 30s = a long sentence.

    responseTailSilence: number = 0.6

    Tail silence: once the first agent chunk arrives, keep draining receiveAudio until no chunk shows up within this many seconds — that's how we detect the agent finished talking.

    responseTimeout: number = 30.0

    Seconds to wait for agent audio after sending user audio.

    role: AgentRole = AgentRole.AGENT
    streamingTranscript?: string

    Incremental transcript text emitted while the agent speaks. Populated by adapters that advertise capabilities.streamingTranscripts. Read by scenario.interrupt when afterWords: N is set.

    systemInstruction: string
    voice: string

    Methods

    • Signal an in-flight receiveAudio() to return the cut-off sentinel immediately, so the interrupted turn doesn't replay stale agent audio into the next turn's drain loop.

      Abort-sentinel pattern (fixes the single-consumer concurrency race):

      The original implementation called dequeue() concurrently with an in-flight receiveAudio(). Since dequeue() has a single resolveNext slot, the second caller (interrupt) overwrote the first caller's (receiveAudio's) resolver. When a message arrived it resolved the interrupt's dequeue, leaving receiveAudio's resolver orphaned — its timer eventually fired with a TimeoutError, causing drainAgentResponse to catch and break prematurely.

      Fix: interrupt() no longer calls dequeue(). Instead it:

      1. Sets _interruptPending = true.
      2. Wakes any in-flight dequeue() by calling the current resolveNext directly with an abort sentinel ({ interrupted: true }).
      3. receiveAudio()'s loop checks _interruptPending (and item.interrupted) and returns the cut-off sentinel immediately on seeing it.

      Best-effort: if nothing is in-flight (resolveNext is null), the flag stays set and receiveAudio() catches it at the top of its next iteration.

      Returns Promise<void>