realtime-voice-agents 2.0.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +58 -2
  2. package/dist/{BaseRealtimeProvider-BehPNT1r.d.cts → BaseRealtimeProvider-BL75_HHh.d.cts} +53 -3
  3. package/dist/{BaseRealtimeProvider-DI4pKtOb.cjs → BaseRealtimeProvider-C2mRn1V_.cjs} +10 -0
  4. package/dist/{BaseRealtimeProvider-BQigr5mB.mjs → BaseRealtimeProvider-C9C3s8jx.mjs} +10 -0
  5. package/dist/{BaseRealtimeProvider-ClP8Wx1X.d.mts → BaseRealtimeProvider-CWJ81HIt.d.mts} +53 -3
  6. package/dist/{GeminiLiveProvider-DvkTgzjG.d.cts → GeminiLiveProvider-Cc1dkxW6.d.cts} +1 -1
  7. package/dist/{GeminiLiveProvider-x2nyx5aO.d.mts → GeminiLiveProvider-TvY_cQQZ.d.mts} +1 -1
  8. package/dist/{OpenAICompatibleProvider-Bdtl-UXH.mjs → OpenAICompatibleProvider-D-2OOVBU.mjs} +98 -11
  9. package/dist/{OpenAICompatibleProvider-NS4cKVQj.cjs → OpenAICompatibleProvider-Mp0Mefbh.cjs} +98 -11
  10. package/dist/audio.cjs +9 -6
  11. package/dist/audio.d.cts +51 -1
  12. package/dist/audio.d.mts +51 -1
  13. package/dist/audio.mjs +2 -2
  14. package/dist/gemini.cjs +16 -6
  15. package/dist/gemini.d.cts +8 -3
  16. package/dist/gemini.d.mts +8 -3
  17. package/dist/gemini.mjs +16 -6
  18. package/dist/index.cjs +356 -16
  19. package/dist/index.d.cts +211 -2
  20. package/dist/index.d.mts +211 -2
  21. package/dist/index.mjs +355 -16
  22. package/dist/{BackgroundAudioPlayer-iMcivjis.mjs → noise-CJ789zzj.mjs} +94 -1
  23. package/dist/{BackgroundAudioPlayer-jfRULWKC.cjs → noise-D9jKottW.cjs} +111 -0
  24. package/dist/openai.cjs +22 -8
  25. package/dist/openai.d.cts +31 -3
  26. package/dist/openai.d.mts +31 -3
  27. package/dist/openai.mjs +22 -8
  28. package/dist/{session-config-BVLl7-ha.mjs → session-config-CbifLlkV.mjs} +1 -1
  29. package/dist/{session-config-c8sOw1XL.cjs → session-config-CqJm2Kxz.cjs} +1 -1
  30. package/dist/testing.cjs +29 -2
  31. package/dist/testing.d.cts +31 -1
  32. package/dist/testing.d.mts +31 -1
  33. package/dist/testing.mjs +29 -2
  34. package/dist/xai.cjs +23 -9
  35. package/dist/xai.d.cts +7 -2
  36. package/dist/xai.d.mts +7 -2
  37. package/dist/xai.mjs +23 -9
  38. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as BackgroundAudioPreset, r as BackgroundAudioSpec, t as BackgroundAudioOptions } from "./presets-Bf75YXs5.cjs";
2
2
  import { t as TypedEmitter } from "./events-BUMYdETO.cjs";
3
- import { _ as noopLogger, a as ProviderToolSchema, c as VadConfig, d as ProviderEvents, f as ProviderToolCall, g as consoleLogger, h as Logger, i as ProviderSessionInit, l as ProviderAudioDelta, m as ProviderCapabilities, n as ProviderFactory, o as SendTextOptions, p as ProviderUsage, r as ProviderFactoryContext, s as SendToolResultOptions, t as BaseRealtimeProvider, u as ProviderCloseInfo } from "./BaseRealtimeProvider-BehPNT1r.cjs";
3
+ import { _ as Logger, a as ProviderToolSchema, c as SessionUpdateOptions, d as ProviderCloseInfo, f as ProviderEvents, g as VadTuningProfile, h as ProviderCapabilities, i as ProviderSessionInit, l as VadConfig, m as ProviderUsage, n as ProviderFactory, o as SendTextOptions, p as ProviderToolCall, r as ProviderFactoryContext, s as SendToolResultOptions, t as BaseRealtimeProvider, u as ProviderAudioDelta, v as consoleLogger, y as noopLogger } from "./BaseRealtimeProvider-BL75_HHh.cjs";
4
4
  import { i as WebSocketLike, m as TwilioStartEvent, r as TwilioMediaTransport } from "./transport-B_PJFIVd.cjs";
5
5
  import { a as emptyUsage, i as UsageInfo, n as SessionStore, o as TranscriptEntry, r as CallSnapshot, t as InMemorySessionStore } from "./InMemorySessionStore-B5_rq61L.cjs";
6
6
  import { i as TwilioRestClient, n as connectStreamTwiml } from "./twiml-z9LjoF4_.cjs";
@@ -262,6 +262,112 @@ declare class InterruptionController {
262
262
  private guardActive;
263
263
  }
264
264
  //#endregion
265
+ //#region src/vad/NoiseAdaptiveVadController.d.ts
266
+ interface NoiseAdaptiveVadOptions {
267
+ /**
268
+ * 'auto' applies each escalation via the provider's mid-session update
269
+ * (ack-gated) and emits `vad.adjusted`; 'suggest' only emits
270
+ * `vad.suggestion` and leaves applying to the app. Default 'auto'.
271
+ */
272
+ mode?: 'auto' | 'suggest';
273
+ /** Sliding analysis window, in ms of ANALYZED (non-excluded) audio. Default 5000. */
274
+ windowMs?: number;
275
+ /** Noise floor (dBFS re PCM16 full scale) at/above which the line counts as noisy. Default -45. */
276
+ noiseFloorDb?: number;
277
+ /** How long the floor must hold, in ms of analyzed audio, before a step. Default 3000. */
278
+ sustainMs?: number;
279
+ /** Minimum inbound audio between steps (and between apply retries). Default 15000. */
280
+ cooldownMs?: number;
281
+ /** Maximum committed escalation steps per call. Default 1. */
282
+ maxSteps?: number;
283
+ /** Server-VAD threshold increase per step. Default 0.1. */
284
+ thresholdStep?: number;
285
+ /** Server-VAD threshold ceiling (intersected with the provider profile range). Default 0.9. */
286
+ maxThreshold?: number;
287
+ }
288
+ interface VadNoiseMetrics {
289
+ /** Estimated noise floor at decision time, dBFS. */
290
+ noiseFloorDb: number;
291
+ /** The analysis window the floor was computed over. */
292
+ windowMs: number;
293
+ /** Analyzed audio with the floor continuously at/above the trigger. */
294
+ sustainedMs: number;
295
+ /** Non-excluded audio metered so far. */
296
+ analyzedMs: number;
297
+ /** ALL inbound audio observed (deterministic wall-clock proxy) — field data for tuning windowMs. */
298
+ elapsedMs: number;
299
+ }
300
+ interface VadAdjustment {
301
+ /** Effective config before the decision (ACKed truth; `{ type: 'server' }` synthesized when unset). */
302
+ previous: VadConfig;
303
+ /** Recommended (suggest) or applied (auto) config. Escalation only. */
304
+ suggested: VadConfig;
305
+ /** 1-based step number this proposal would commit. */
306
+ step: number;
307
+ maxSteps: number;
308
+ /**
309
+ * POLICY: is this kind of change safe to apply automatically? Server-VAD
310
+ * threshold rungs are; semantic eagerness (an end-of-turn latency control)
311
+ * and sensitivity-only rungs are surfaced as suggestions instead. Runtime
312
+ * gating (mode/capability) is reported separately as `willAutoApply`.
313
+ */
314
+ autoApplicable: boolean;
315
+ metrics: VadNoiseMetrics;
316
+ }
317
+ declare class NoiseAdaptiveVadController {
318
+ private readonly windowMs;
319
+ private readonly noiseFloorDb;
320
+ private readonly sustainMs;
321
+ private readonly cooldownMs;
322
+ private readonly maxSteps;
323
+ private readonly thresholdStep;
324
+ private readonly maxThreshold;
325
+ private readonly profile;
326
+ private readonly estimator;
327
+ /** Current EFFECTIVE config — moved only by commitApplied()/rebase(). */
328
+ private effective;
329
+ private disabled;
330
+ private stepsTaken;
331
+ private suggestionLatched;
332
+ private sustainedMs;
333
+ /** Infinity = no step yet, so the first proposal is never cooldown-blocked. */
334
+ private msSinceLastStep;
335
+ private elapsedMs;
336
+ private analyzedMs;
337
+ /** Memoized next rung; `undefined` = dirty, `null` = ladder exhausted. */
338
+ private cachedNext;
339
+ constructor(options: NoiseAdaptiveVadOptions, effectiveVad: VadConfig | null | undefined, profile: VadTuningProfile | undefined);
340
+ /** No escalation room at all (disabled, or the ladder has no next rung). */
341
+ get exhausted(): boolean;
342
+ /**
343
+ * Feed one inbound Twilio frame (base64 μ-law). `excluded` frames (user
344
+ * speech, agent playback, pregreeting) advance the cooldown clock but are
345
+ * kept out of the floor estimate — they freeze, not reset, the sustain
346
+ * counter. Pure w.r.t. ladder state: the same proposal recurs until
347
+ * commitApplied/markSuggested/defer/rebase.
348
+ */
349
+ onInboundFrame(base64Mulaw: string, excluded: boolean): VadAdjustment | null;
350
+ /** The proposal was applied AND acknowledged: it is the new effective truth. */
351
+ commitApplied(adjustment: VadAdjustment): void;
352
+ /**
353
+ * The suggestion was emitted without being applied: latch so it fires once
354
+ * per effective state. The effective config is deliberately NOT moved — an
355
+ * unapplied suggestion is not reality.
356
+ */
357
+ markSuggested(_adjustment: VadAdjustment): void;
358
+ /** The apply failed/timed out/was superseded: retry after cooldownMs. */
359
+ defer(): void;
360
+ /**
361
+ * App-driven updateVad(): the declared config is the new effective base —
362
+ * a fresh ladder starts from it (never below it). `null` disables the
363
+ * controller; a later non-null rebase re-enables it. A full cooldown
364
+ * applies before the next adaptive step.
365
+ */
366
+ rebase(vad: VadConfig | null): void;
367
+ private nextRung;
368
+ private computeNextRung;
369
+ }
370
+ //#endregion
265
371
  //#region src/providers/base/reconnect.d.ts
266
372
  /** Exponential backoff with optional full jitter, shared by all providers. */
267
373
  interface ReconnectPolicy {
@@ -348,6 +454,14 @@ interface SessionOptions {
348
454
  hangup: HangupOptions;
349
455
  /** Normalized VAD, mapped to the provider's native config. */
350
456
  vad?: VadConfig | null;
457
+ /**
458
+ * Opt-in noise-adaptive VAD escalation: analyze inbound caller audio and,
459
+ * on sustained background noise, raise turn-detection settings mid-call
460
+ * (auto-applied where the provider supports acknowledged session updates;
461
+ * suggestion events otherwise). Set `{}` to enable with defaults. Enabling
462
+ * this also serializes ALL mid-call session updates for the session.
463
+ */
464
+ noiseAdaptiveVad?: NoiseAdaptiveVadOptions;
351
465
  /**
352
466
  * `afterPlayback` (default): tool results wait until current agent audio
353
467
  * finishes playing. `immediate`: send as soon as the tool completes.
@@ -421,6 +535,19 @@ interface BridgeConfig {
421
535
  /** The (root) agent, or a resolver for multi-tenant routing per call. */
422
536
  agent: Agent | ((start: TwilioStartEvent) => Agent | Promise<Agent>);
423
537
  provider: ProviderFactory;
538
+ /**
539
+ * Backup providers tried in order when `provider` fails to come up at call
540
+ * start (bad key, exhausted quota, outage, connect timeout). Each attempt
541
+ * emits `provider.fallback`; the call fails only when every fallback is
542
+ * exhausted. Connect-time only: once a provider answers, the call stays
543
+ * with it (mid-call reconnects keep using the same provider).
544
+ *
545
+ * ```ts
546
+ * provider: openaiRealtime(),
547
+ * fallbacks: [xaiRealtime(), geminiLive()],
548
+ * ```
549
+ */
550
+ fallbacks?: ProviderFactory[];
424
551
  session?: Partial<SessionOptions> | ((start: TwilioStartEvent) => Partial<SessionOptions> | Promise<Partial<SessionOptions>>);
425
552
  /** Twilio REST credentials — enables clean hangup, transfer, SMS/WhatsApp. */
426
553
  twilio?: TwilioRestOptions;
@@ -470,6 +597,28 @@ interface ApprovalRequestInfo {
470
597
  agentId: string;
471
598
  expiresAtMs: number;
472
599
  }
600
+ /**
601
+ * A noise-adaptive VAD suggestion. `autoApplicable` is policy ("is this kind
602
+ * of change safe to auto-apply?"); `willAutoApply` is runtime — false in
603
+ * suggest mode or when the provider has no mid-session update, even for an
604
+ * auto-applicable change.
605
+ */
606
+ type VadSuggestionInfo = VadAdjustment & {
607
+ willAutoApply: boolean;
608
+ };
609
+ /**
610
+ * While ESTABLISHING the call, a provider failed to come up and the session
611
+ * is trying the next factory in the fallback chain. Fires only before the
612
+ * call is active — once a provider has connected, the call stays with it.
613
+ */
614
+ interface ProviderFallbackInfo {
615
+ /** Name of the provider whose connect failed. */
616
+ from: string;
617
+ /** Name of the provider being tried instead. */
618
+ to: string;
619
+ /** The connect error that triggered the fallback. */
620
+ error: Error;
621
+ }
473
622
  interface SessionEventMap {
474
623
  'call.started': (info: CallStartedInfo) => void;
475
624
  'call.ended': (info: {
@@ -488,6 +637,8 @@ interface SessionEventMap {
488
637
  code?: number;
489
638
  reason?: string;
490
639
  }) => void;
640
+ /** Connect-time fallback: trying the next provider in the configured chain. */
641
+ 'provider.fallback': (info: ProviderFallbackInfo) => void;
491
642
  /** Generation-side: the model started/finished producing a response. */
492
643
  'agent.speech.started': (info: {
493
644
  responseId: string;
@@ -527,6 +678,10 @@ interface SessionEventMap {
527
678
  'interruption.blocked': (info: {
528
679
  cause: string;
529
680
  }) => void;
681
+ /** Sustained background noise detected; an escalation is recommended (fires in both modes). */
682
+ 'vad.suggestion': (info: VadSuggestionInfo) => void;
683
+ /** The escalation was applied AND acknowledged by the provider (auto mode only). */
684
+ 'vad.adjusted': (info: VadAdjustment) => void;
530
685
  'background_audio.started': (info: {
531
686
  preset?: string;
532
687
  }) => void;
@@ -556,6 +711,8 @@ interface CallSessionDeps {
556
711
  transport: TwilioMediaTransport;
557
712
  start: TwilioStartEvent;
558
713
  providerFactory: ProviderFactory;
714
+ /** Backup factories tried in order when `providerFactory` fails to connect. */
715
+ fallbacks?: readonly ProviderFactory[];
559
716
  agent: Agent;
560
717
  options: SessionOptions;
561
718
  store: SessionStore;
@@ -586,6 +743,8 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
586
743
  private readonly runningTools;
587
744
  private readonly timers;
588
745
  private provider;
746
+ /** Primary + fallbacks, in try-order. Only walked while connecting. */
747
+ private readonly providerChain;
589
748
  private activeAgentValue;
590
749
  private generating;
591
750
  private currentResponseId;
@@ -623,6 +782,21 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
623
782
  private handoffInProgress;
624
783
  /** Pre-synthesized greeting playout state. */
625
784
  private pregreeting;
785
+ /** Noise-adaptive VAD (opt-in); built after connect from the provider's ACKed config. */
786
+ private noiseVad;
787
+ /**
788
+ * DESIRED turn-detection override — drives reconnect/handoff rebuilds via
789
+ * buildProviderInit. Distinct from the provider's ACKed effective state:
790
+ * manual updateVad() promotes it immediately (user intent survives network
791
+ * failures); adaptive applies promote it only after the provider's ack.
792
+ */
793
+ private vadOverride;
794
+ /** VAD mutations in flight (manual AND adaptive); proposals drop while > 0. */
795
+ private vadOpsInFlight;
796
+ /** Bumped by every updateVad(); a stale revision means an adaptive apply was superseded. */
797
+ private vadRevision;
798
+ private userSpeechActive;
799
+ private userSpeechStartedAtMs;
626
800
  constructor(deps: CallSessionDeps);
627
801
  get state(): CallState;
628
802
  get activeAgent(): Agent;
@@ -630,6 +804,15 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
630
804
  get transcript(): readonly TranscriptEntry[];
631
805
  /** Connect the provider and activate the call. Called by the bridge. */
632
806
  begin(): Promise<void>;
807
+ /**
808
+ * Walk primary + fallbacks until one connects. A provider that fails to
809
+ * come up is detached BEFORE the chain advances, so a half-open socket's
810
+ * late events can never reach the session once the next provider owns the
811
+ * call. Connect-time only by design: once a provider has answered, the
812
+ * call stays with it. Returns false after failing the call (chain
813
+ * exhausted) or when the call was torn down while connecting.
814
+ */
815
+ private connectInitialProvider;
633
816
  /** The outbound leg was answered (host's Twilio status callback). */
634
817
  notifyAnswered(): void;
635
818
  sendText(text: string, options?: {
@@ -637,6 +820,21 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
637
820
  triggerResponse?: boolean;
638
821
  }): void;
639
822
  updateInstructions(instructions: string): Promise<void>;
823
+ /**
824
+ * Replace the session's turn-detection config mid-call. The value is the
825
+ * new DESIRED state: it survives reconnects and handoffs, and the
826
+ * noise-adaptive ladder (when enabled) rebases onto it — future escalation
827
+ * is relative to this config, never below it. `null` disables turn
828
+ * detection AND suspends noise adaptation (adaptation never re-enables VAD
829
+ * on its own); a later non-null call re-enables both.
830
+ *
831
+ * Returns true when the live session applied it — provider-acknowledged
832
+ * when `noiseAdaptiveVad` is configured (serialized updates), best-effort
833
+ * "sent" otherwise. False when it could not be applied live (no provider,
834
+ * call ended, no sessionUpdate capability, or the ack timed out — the
835
+ * resulting reconnect then applies the stored config).
836
+ */
837
+ updateVad(vad: VadConfig | null): Promise<boolean>;
640
838
  /** Manual barge-in: stop the agent mid-sentence. */
641
839
  interrupt(): void;
642
840
  /**
@@ -672,6 +870,17 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
672
870
  private wireProvider;
673
871
  private handleInboundMedia;
674
872
  private flushInboundBuffer;
873
+ /** Caller speech is excluded from the noise floor, capped so a missing
874
+ * speech-stopped event (Gemini) can't latch the meter off forever. */
875
+ private isUserSpeechExcluded;
876
+ private handleVadProposal;
877
+ /**
878
+ * Adaptive applies promote NOTHING until the provider ACKs: a timed-out
879
+ * update must not leak into vadOverride, or the desync-reconnect would
880
+ * apply a config the controller never committed (dual truth). Contrast
881
+ * with updateVad(), where the user's declared intent persists regardless.
882
+ */
883
+ private applyAdaptiveVadUpdate;
675
884
  private handleMarkEcho;
676
885
  private onPlaybackFinished;
677
886
  private handleBargeIn;
@@ -917,4 +1126,4 @@ declare class PlaybackTracker {
917
1126
  private maybeForget;
918
1127
  }
919
1128
  //#endregion
920
- export { Agent, type AgentDefinition, type ApprovalRequestInfo, type BackgroundAudioOptions, type BackgroundAudioPreset, type BackgroundAudioSpec, BaseRealtimeProvider, type BridgeConfig, type BridgeEventMap, type BuiltinToolsConfig, type CallEndReason, CallSession, type CallSessionFacade, type CallSnapshot, type CallStartedInfo, type CallState, type CaptureGreetingOptions, type CapturedGreeting, DEFAULT_RECONNECT_POLICY, DEFAULT_SESSION_OPTIONS, type DeafnessOptions, type FinishCallToolOptions, type GreetingOptions, type HandoffDirective, type HangupOptions, type IdleOptions, InMemorySessionStore, type InferSchema, type InterruptionBlockCause, InterruptionController, type InterruptionDecision, type InterruptionRateLimit, type InterruptionSettings, type Logger, type MarkEchoResult, PlaybackTracker, type ProviderAudioDelta, type ProviderCapabilities, type ProviderCloseInfo, type ProviderEvents, type ProviderFactory, type ProviderFactoryContext, type ProviderSessionInit, type ProviderToolCall, type ProviderToolSchema, type ProviderUsage, type ReconnectPolicy, type SendTextOptions, type SendToolResultOptions, SessionContext, type SessionEventMap, type SessionOptions, type SessionStore, type Tool, type ToolCallInfo, type ToolContext, type ToolDecoration, type ToolDefinition, type ToolMiddleware, type ToolRunInfo, type ToolStrategy, type TranscriptEntry, type TransferCallToolOptions, TwilioRealtimeBridge, type TwilioRestOptions, type TwilioStartEvent, type UsageInfo, type VadConfig, type WebSocketLike, type ZodSchemaLike, captureGreetingAudio, collectAgentGraph, composeExecution, connectStreamTwiml, consoleLogger, createFinishCallTool, createHandoffTool, createTransferCallTool, decorateTool, emptyUsage, handoffToolName, isHandoffDirective, noopLogger, resolveSessionOptions, tool, zodToJsonSchema };
1129
+ export { Agent, type AgentDefinition, type ApprovalRequestInfo, type BackgroundAudioOptions, type BackgroundAudioPreset, type BackgroundAudioSpec, BaseRealtimeProvider, type BridgeConfig, type BridgeEventMap, type BuiltinToolsConfig, type CallEndReason, CallSession, type CallSessionFacade, type CallSnapshot, type CallStartedInfo, type CallState, type CaptureGreetingOptions, type CapturedGreeting, DEFAULT_RECONNECT_POLICY, DEFAULT_SESSION_OPTIONS, type DeafnessOptions, type FinishCallToolOptions, type GreetingOptions, type HandoffDirective, type HangupOptions, type IdleOptions, InMemorySessionStore, type InferSchema, type InterruptionBlockCause, InterruptionController, type InterruptionDecision, type InterruptionRateLimit, type InterruptionSettings, type Logger, type MarkEchoResult, NoiseAdaptiveVadController, type NoiseAdaptiveVadOptions, PlaybackTracker, type ProviderAudioDelta, type ProviderCapabilities, type ProviderCloseInfo, type ProviderEvents, type ProviderFactory, type ProviderFactoryContext, type ProviderFallbackInfo, type ProviderSessionInit, type ProviderToolCall, type ProviderToolSchema, type ProviderUsage, type ReconnectPolicy, type SendTextOptions, type SendToolResultOptions, SessionContext, type SessionEventMap, type SessionOptions, type SessionStore, type SessionUpdateOptions, type Tool, type ToolCallInfo, type ToolContext, type ToolDecoration, type ToolDefinition, type ToolMiddleware, type ToolRunInfo, type ToolStrategy, type TranscriptEntry, type TransferCallToolOptions, TwilioRealtimeBridge, type TwilioRestOptions, type TwilioStartEvent, type UsageInfo, type VadAdjustment, type VadConfig, type VadNoiseMetrics, type VadSuggestionInfo, type VadTuningProfile, type WebSocketLike, type ZodSchemaLike, captureGreetingAudio, collectAgentGraph, composeExecution, connectStreamTwiml, consoleLogger, createFinishCallTool, createHandoffTool, createTransferCallTool, decorateTool, emptyUsage, handoffToolName, isHandoffDirective, noopLogger, resolveSessionOptions, tool, zodToJsonSchema };
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { n as BackgroundAudioPreset, r as BackgroundAudioSpec, t as BackgroundAudioOptions } from "./presets-Bf75YXs5.mjs";
2
2
  import { t as TypedEmitter } from "./events-BUMYdETO.mjs";
3
- import { _ as noopLogger, a as ProviderToolSchema, c as VadConfig, d as ProviderEvents, f as ProviderToolCall, g as consoleLogger, h as Logger, i as ProviderSessionInit, l as ProviderAudioDelta, m as ProviderCapabilities, n as ProviderFactory, o as SendTextOptions, p as ProviderUsage, r as ProviderFactoryContext, s as SendToolResultOptions, t as BaseRealtimeProvider, u as ProviderCloseInfo } from "./BaseRealtimeProvider-ClP8Wx1X.mjs";
3
+ import { _ as Logger, a as ProviderToolSchema, c as SessionUpdateOptions, d as ProviderCloseInfo, f as ProviderEvents, g as VadTuningProfile, h as ProviderCapabilities, i as ProviderSessionInit, l as VadConfig, m as ProviderUsage, n as ProviderFactory, o as SendTextOptions, p as ProviderToolCall, r as ProviderFactoryContext, s as SendToolResultOptions, t as BaseRealtimeProvider, u as ProviderAudioDelta, v as consoleLogger, y as noopLogger } from "./BaseRealtimeProvider-CWJ81HIt.mjs";
4
4
  import { i as WebSocketLike, m as TwilioStartEvent, r as TwilioMediaTransport } from "./transport-CEaLFV4E.mjs";
5
5
  import { a as emptyUsage, i as UsageInfo, n as SessionStore, o as TranscriptEntry, r as CallSnapshot, t as InMemorySessionStore } from "./InMemorySessionStore-B5_rq61L.mjs";
6
6
  import { i as TwilioRestClient, n as connectStreamTwiml } from "./twiml-z9LjoF4_.mjs";
@@ -262,6 +262,112 @@ declare class InterruptionController {
262
262
  private guardActive;
263
263
  }
264
264
  //#endregion
265
+ //#region src/vad/NoiseAdaptiveVadController.d.ts
266
+ interface NoiseAdaptiveVadOptions {
267
+ /**
268
+ * 'auto' applies each escalation via the provider's mid-session update
269
+ * (ack-gated) and emits `vad.adjusted`; 'suggest' only emits
270
+ * `vad.suggestion` and leaves applying to the app. Default 'auto'.
271
+ */
272
+ mode?: 'auto' | 'suggest';
273
+ /** Sliding analysis window, in ms of ANALYZED (non-excluded) audio. Default 5000. */
274
+ windowMs?: number;
275
+ /** Noise floor (dBFS re PCM16 full scale) at/above which the line counts as noisy. Default -45. */
276
+ noiseFloorDb?: number;
277
+ /** How long the floor must hold, in ms of analyzed audio, before a step. Default 3000. */
278
+ sustainMs?: number;
279
+ /** Minimum inbound audio between steps (and between apply retries). Default 15000. */
280
+ cooldownMs?: number;
281
+ /** Maximum committed escalation steps per call. Default 1. */
282
+ maxSteps?: number;
283
+ /** Server-VAD threshold increase per step. Default 0.1. */
284
+ thresholdStep?: number;
285
+ /** Server-VAD threshold ceiling (intersected with the provider profile range). Default 0.9. */
286
+ maxThreshold?: number;
287
+ }
288
+ interface VadNoiseMetrics {
289
+ /** Estimated noise floor at decision time, dBFS. */
290
+ noiseFloorDb: number;
291
+ /** The analysis window the floor was computed over. */
292
+ windowMs: number;
293
+ /** Analyzed audio with the floor continuously at/above the trigger. */
294
+ sustainedMs: number;
295
+ /** Non-excluded audio metered so far. */
296
+ analyzedMs: number;
297
+ /** ALL inbound audio observed (deterministic wall-clock proxy) — field data for tuning windowMs. */
298
+ elapsedMs: number;
299
+ }
300
+ interface VadAdjustment {
301
+ /** Effective config before the decision (ACKed truth; `{ type: 'server' }` synthesized when unset). */
302
+ previous: VadConfig;
303
+ /** Recommended (suggest) or applied (auto) config. Escalation only. */
304
+ suggested: VadConfig;
305
+ /** 1-based step number this proposal would commit. */
306
+ step: number;
307
+ maxSteps: number;
308
+ /**
309
+ * POLICY: is this kind of change safe to apply automatically? Server-VAD
310
+ * threshold rungs are; semantic eagerness (an end-of-turn latency control)
311
+ * and sensitivity-only rungs are surfaced as suggestions instead. Runtime
312
+ * gating (mode/capability) is reported separately as `willAutoApply`.
313
+ */
314
+ autoApplicable: boolean;
315
+ metrics: VadNoiseMetrics;
316
+ }
317
+ declare class NoiseAdaptiveVadController {
318
+ private readonly windowMs;
319
+ private readonly noiseFloorDb;
320
+ private readonly sustainMs;
321
+ private readonly cooldownMs;
322
+ private readonly maxSteps;
323
+ private readonly thresholdStep;
324
+ private readonly maxThreshold;
325
+ private readonly profile;
326
+ private readonly estimator;
327
+ /** Current EFFECTIVE config — moved only by commitApplied()/rebase(). */
328
+ private effective;
329
+ private disabled;
330
+ private stepsTaken;
331
+ private suggestionLatched;
332
+ private sustainedMs;
333
+ /** Infinity = no step yet, so the first proposal is never cooldown-blocked. */
334
+ private msSinceLastStep;
335
+ private elapsedMs;
336
+ private analyzedMs;
337
+ /** Memoized next rung; `undefined` = dirty, `null` = ladder exhausted. */
338
+ private cachedNext;
339
+ constructor(options: NoiseAdaptiveVadOptions, effectiveVad: VadConfig | null | undefined, profile: VadTuningProfile | undefined);
340
+ /** No escalation room at all (disabled, or the ladder has no next rung). */
341
+ get exhausted(): boolean;
342
+ /**
343
+ * Feed one inbound Twilio frame (base64 μ-law). `excluded` frames (user
344
+ * speech, agent playback, pregreeting) advance the cooldown clock but are
345
+ * kept out of the floor estimate — they freeze, not reset, the sustain
346
+ * counter. Pure w.r.t. ladder state: the same proposal recurs until
347
+ * commitApplied/markSuggested/defer/rebase.
348
+ */
349
+ onInboundFrame(base64Mulaw: string, excluded: boolean): VadAdjustment | null;
350
+ /** The proposal was applied AND acknowledged: it is the new effective truth. */
351
+ commitApplied(adjustment: VadAdjustment): void;
352
+ /**
353
+ * The suggestion was emitted without being applied: latch so it fires once
354
+ * per effective state. The effective config is deliberately NOT moved — an
355
+ * unapplied suggestion is not reality.
356
+ */
357
+ markSuggested(_adjustment: VadAdjustment): void;
358
+ /** The apply failed/timed out/was superseded: retry after cooldownMs. */
359
+ defer(): void;
360
+ /**
361
+ * App-driven updateVad(): the declared config is the new effective base —
362
+ * a fresh ladder starts from it (never below it). `null` disables the
363
+ * controller; a later non-null rebase re-enables it. A full cooldown
364
+ * applies before the next adaptive step.
365
+ */
366
+ rebase(vad: VadConfig | null): void;
367
+ private nextRung;
368
+ private computeNextRung;
369
+ }
370
+ //#endregion
265
371
  //#region src/providers/base/reconnect.d.ts
266
372
  /** Exponential backoff with optional full jitter, shared by all providers. */
267
373
  interface ReconnectPolicy {
@@ -348,6 +454,14 @@ interface SessionOptions {
348
454
  hangup: HangupOptions;
349
455
  /** Normalized VAD, mapped to the provider's native config. */
350
456
  vad?: VadConfig | null;
457
+ /**
458
+ * Opt-in noise-adaptive VAD escalation: analyze inbound caller audio and,
459
+ * on sustained background noise, raise turn-detection settings mid-call
460
+ * (auto-applied where the provider supports acknowledged session updates;
461
+ * suggestion events otherwise). Set `{}` to enable with defaults. Enabling
462
+ * this also serializes ALL mid-call session updates for the session.
463
+ */
464
+ noiseAdaptiveVad?: NoiseAdaptiveVadOptions;
351
465
  /**
352
466
  * `afterPlayback` (default): tool results wait until current agent audio
353
467
  * finishes playing. `immediate`: send as soon as the tool completes.
@@ -421,6 +535,19 @@ interface BridgeConfig {
421
535
  /** The (root) agent, or a resolver for multi-tenant routing per call. */
422
536
  agent: Agent | ((start: TwilioStartEvent) => Agent | Promise<Agent>);
423
537
  provider: ProviderFactory;
538
+ /**
539
+ * Backup providers tried in order when `provider` fails to come up at call
540
+ * start (bad key, exhausted quota, outage, connect timeout). Each attempt
541
+ * emits `provider.fallback`; the call fails only when every fallback is
542
+ * exhausted. Connect-time only: once a provider answers, the call stays
543
+ * with it (mid-call reconnects keep using the same provider).
544
+ *
545
+ * ```ts
546
+ * provider: openaiRealtime(),
547
+ * fallbacks: [xaiRealtime(), geminiLive()],
548
+ * ```
549
+ */
550
+ fallbacks?: ProviderFactory[];
424
551
  session?: Partial<SessionOptions> | ((start: TwilioStartEvent) => Partial<SessionOptions> | Promise<Partial<SessionOptions>>);
425
552
  /** Twilio REST credentials — enables clean hangup, transfer, SMS/WhatsApp. */
426
553
  twilio?: TwilioRestOptions;
@@ -470,6 +597,28 @@ interface ApprovalRequestInfo {
470
597
  agentId: string;
471
598
  expiresAtMs: number;
472
599
  }
600
+ /**
601
+ * A noise-adaptive VAD suggestion. `autoApplicable` is policy ("is this kind
602
+ * of change safe to auto-apply?"); `willAutoApply` is runtime — false in
603
+ * suggest mode or when the provider has no mid-session update, even for an
604
+ * auto-applicable change.
605
+ */
606
+ type VadSuggestionInfo = VadAdjustment & {
607
+ willAutoApply: boolean;
608
+ };
609
+ /**
610
+ * While ESTABLISHING the call, a provider failed to come up and the session
611
+ * is trying the next factory in the fallback chain. Fires only before the
612
+ * call is active — once a provider has connected, the call stays with it.
613
+ */
614
+ interface ProviderFallbackInfo {
615
+ /** Name of the provider whose connect failed. */
616
+ from: string;
617
+ /** Name of the provider being tried instead. */
618
+ to: string;
619
+ /** The connect error that triggered the fallback. */
620
+ error: Error;
621
+ }
473
622
  interface SessionEventMap {
474
623
  'call.started': (info: CallStartedInfo) => void;
475
624
  'call.ended': (info: {
@@ -488,6 +637,8 @@ interface SessionEventMap {
488
637
  code?: number;
489
638
  reason?: string;
490
639
  }) => void;
640
+ /** Connect-time fallback: trying the next provider in the configured chain. */
641
+ 'provider.fallback': (info: ProviderFallbackInfo) => void;
491
642
  /** Generation-side: the model started/finished producing a response. */
492
643
  'agent.speech.started': (info: {
493
644
  responseId: string;
@@ -527,6 +678,10 @@ interface SessionEventMap {
527
678
  'interruption.blocked': (info: {
528
679
  cause: string;
529
680
  }) => void;
681
+ /** Sustained background noise detected; an escalation is recommended (fires in both modes). */
682
+ 'vad.suggestion': (info: VadSuggestionInfo) => void;
683
+ /** The escalation was applied AND acknowledged by the provider (auto mode only). */
684
+ 'vad.adjusted': (info: VadAdjustment) => void;
530
685
  'background_audio.started': (info: {
531
686
  preset?: string;
532
687
  }) => void;
@@ -556,6 +711,8 @@ interface CallSessionDeps {
556
711
  transport: TwilioMediaTransport;
557
712
  start: TwilioStartEvent;
558
713
  providerFactory: ProviderFactory;
714
+ /** Backup factories tried in order when `providerFactory` fails to connect. */
715
+ fallbacks?: readonly ProviderFactory[];
559
716
  agent: Agent;
560
717
  options: SessionOptions;
561
718
  store: SessionStore;
@@ -586,6 +743,8 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
586
743
  private readonly runningTools;
587
744
  private readonly timers;
588
745
  private provider;
746
+ /** Primary + fallbacks, in try-order. Only walked while connecting. */
747
+ private readonly providerChain;
589
748
  private activeAgentValue;
590
749
  private generating;
591
750
  private currentResponseId;
@@ -623,6 +782,21 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
623
782
  private handoffInProgress;
624
783
  /** Pre-synthesized greeting playout state. */
625
784
  private pregreeting;
785
+ /** Noise-adaptive VAD (opt-in); built after connect from the provider's ACKed config. */
786
+ private noiseVad;
787
+ /**
788
+ * DESIRED turn-detection override — drives reconnect/handoff rebuilds via
789
+ * buildProviderInit. Distinct from the provider's ACKed effective state:
790
+ * manual updateVad() promotes it immediately (user intent survives network
791
+ * failures); adaptive applies promote it only after the provider's ack.
792
+ */
793
+ private vadOverride;
794
+ /** VAD mutations in flight (manual AND adaptive); proposals drop while > 0. */
795
+ private vadOpsInFlight;
796
+ /** Bumped by every updateVad(); a stale revision means an adaptive apply was superseded. */
797
+ private vadRevision;
798
+ private userSpeechActive;
799
+ private userSpeechStartedAtMs;
626
800
  constructor(deps: CallSessionDeps);
627
801
  get state(): CallState;
628
802
  get activeAgent(): Agent;
@@ -630,6 +804,15 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
630
804
  get transcript(): readonly TranscriptEntry[];
631
805
  /** Connect the provider and activate the call. Called by the bridge. */
632
806
  begin(): Promise<void>;
807
+ /**
808
+ * Walk primary + fallbacks until one connects. A provider that fails to
809
+ * come up is detached BEFORE the chain advances, so a half-open socket's
810
+ * late events can never reach the session once the next provider owns the
811
+ * call. Connect-time only by design: once a provider has answered, the
812
+ * call stays with it. Returns false after failing the call (chain
813
+ * exhausted) or when the call was torn down while connecting.
814
+ */
815
+ private connectInitialProvider;
633
816
  /** The outbound leg was answered (host's Twilio status callback). */
634
817
  notifyAnswered(): void;
635
818
  sendText(text: string, options?: {
@@ -637,6 +820,21 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
637
820
  triggerResponse?: boolean;
638
821
  }): void;
639
822
  updateInstructions(instructions: string): Promise<void>;
823
+ /**
824
+ * Replace the session's turn-detection config mid-call. The value is the
825
+ * new DESIRED state: it survives reconnects and handoffs, and the
826
+ * noise-adaptive ladder (when enabled) rebases onto it — future escalation
827
+ * is relative to this config, never below it. `null` disables turn
828
+ * detection AND suspends noise adaptation (adaptation never re-enables VAD
829
+ * on its own); a later non-null call re-enables both.
830
+ *
831
+ * Returns true when the live session applied it — provider-acknowledged
832
+ * when `noiseAdaptiveVad` is configured (serialized updates), best-effort
833
+ * "sent" otherwise. False when it could not be applied live (no provider,
834
+ * call ended, no sessionUpdate capability, or the ack timed out — the
835
+ * resulting reconnect then applies the stored config).
836
+ */
837
+ updateVad(vad: VadConfig | null): Promise<boolean>;
640
838
  /** Manual barge-in: stop the agent mid-sentence. */
641
839
  interrupt(): void;
642
840
  /**
@@ -672,6 +870,17 @@ declare class CallSession extends TypedEmitter<SessionEventMap> {
672
870
  private wireProvider;
673
871
  private handleInboundMedia;
674
872
  private flushInboundBuffer;
873
+ /** Caller speech is excluded from the noise floor, capped so a missing
874
+ * speech-stopped event (Gemini) can't latch the meter off forever. */
875
+ private isUserSpeechExcluded;
876
+ private handleVadProposal;
877
+ /**
878
+ * Adaptive applies promote NOTHING until the provider ACKs: a timed-out
879
+ * update must not leak into vadOverride, or the desync-reconnect would
880
+ * apply a config the controller never committed (dual truth). Contrast
881
+ * with updateVad(), where the user's declared intent persists regardless.
882
+ */
883
+ private applyAdaptiveVadUpdate;
675
884
  private handleMarkEcho;
676
885
  private onPlaybackFinished;
677
886
  private handleBargeIn;
@@ -917,4 +1126,4 @@ declare class PlaybackTracker {
917
1126
  private maybeForget;
918
1127
  }
919
1128
  //#endregion
920
- export { Agent, type AgentDefinition, type ApprovalRequestInfo, type BackgroundAudioOptions, type BackgroundAudioPreset, type BackgroundAudioSpec, BaseRealtimeProvider, type BridgeConfig, type BridgeEventMap, type BuiltinToolsConfig, type CallEndReason, CallSession, type CallSessionFacade, type CallSnapshot, type CallStartedInfo, type CallState, type CaptureGreetingOptions, type CapturedGreeting, DEFAULT_RECONNECT_POLICY, DEFAULT_SESSION_OPTIONS, type DeafnessOptions, type FinishCallToolOptions, type GreetingOptions, type HandoffDirective, type HangupOptions, type IdleOptions, InMemorySessionStore, type InferSchema, type InterruptionBlockCause, InterruptionController, type InterruptionDecision, type InterruptionRateLimit, type InterruptionSettings, type Logger, type MarkEchoResult, PlaybackTracker, type ProviderAudioDelta, type ProviderCapabilities, type ProviderCloseInfo, type ProviderEvents, type ProviderFactory, type ProviderFactoryContext, type ProviderSessionInit, type ProviderToolCall, type ProviderToolSchema, type ProviderUsage, type ReconnectPolicy, type SendTextOptions, type SendToolResultOptions, SessionContext, type SessionEventMap, type SessionOptions, type SessionStore, type Tool, type ToolCallInfo, type ToolContext, type ToolDecoration, type ToolDefinition, type ToolMiddleware, type ToolRunInfo, type ToolStrategy, type TranscriptEntry, type TransferCallToolOptions, TwilioRealtimeBridge, type TwilioRestOptions, type TwilioStartEvent, type UsageInfo, type VadConfig, type WebSocketLike, type ZodSchemaLike, captureGreetingAudio, collectAgentGraph, composeExecution, connectStreamTwiml, consoleLogger, createFinishCallTool, createHandoffTool, createTransferCallTool, decorateTool, emptyUsage, handoffToolName, isHandoffDirective, noopLogger, resolveSessionOptions, tool, zodToJsonSchema };
1129
+ export { Agent, type AgentDefinition, type ApprovalRequestInfo, type BackgroundAudioOptions, type BackgroundAudioPreset, type BackgroundAudioSpec, BaseRealtimeProvider, type BridgeConfig, type BridgeEventMap, type BuiltinToolsConfig, type CallEndReason, CallSession, type CallSessionFacade, type CallSnapshot, type CallStartedInfo, type CallState, type CaptureGreetingOptions, type CapturedGreeting, DEFAULT_RECONNECT_POLICY, DEFAULT_SESSION_OPTIONS, type DeafnessOptions, type FinishCallToolOptions, type GreetingOptions, type HandoffDirective, type HangupOptions, type IdleOptions, InMemorySessionStore, type InferSchema, type InterruptionBlockCause, InterruptionController, type InterruptionDecision, type InterruptionRateLimit, type InterruptionSettings, type Logger, type MarkEchoResult, NoiseAdaptiveVadController, type NoiseAdaptiveVadOptions, PlaybackTracker, type ProviderAudioDelta, type ProviderCapabilities, type ProviderCloseInfo, type ProviderEvents, type ProviderFactory, type ProviderFactoryContext, type ProviderFallbackInfo, type ProviderSessionInit, type ProviderToolCall, type ProviderToolSchema, type ProviderUsage, type ReconnectPolicy, type SendTextOptions, type SendToolResultOptions, SessionContext, type SessionEventMap, type SessionOptions, type SessionStore, type SessionUpdateOptions, type Tool, type ToolCallInfo, type ToolContext, type ToolDecoration, type ToolDefinition, type ToolMiddleware, type ToolRunInfo, type ToolStrategy, type TranscriptEntry, type TransferCallToolOptions, TwilioRealtimeBridge, type TwilioRestOptions, type TwilioStartEvent, type UsageInfo, type VadAdjustment, type VadConfig, type VadNoiseMetrics, type VadSuggestionInfo, type VadTuningProfile, type WebSocketLike, type ZodSchemaLike, captureGreetingAudio, collectAgentGraph, composeExecution, connectStreamTwiml, consoleLogger, createFinishCallTool, createHandoffTool, createTransferCallTool, decorateTool, emptyUsage, handoffToolName, isHandoffDirective, noopLogger, resolveSessionOptions, tool, zodToJsonSchema };