Skip to main content

Crate rvoip_vapi

Crate rvoip_vapi 

Source
Expand description

Vapi bidirectional WebSocket voice-agent adapter for rvoip.

This crate lets rvoip retain ownership of a SIP or WebRTC caller leg while Vapi owns ASR, dialog, synthesis, and interruption handling on a raw-audio WebSocket call transport.

§rvoip-vapi

Developer-preview Vapi integration for rvoip. rvoip owns the caller-facing SIP or WebRTC leg; Vapi owns the full ASR, model, synthesis, and interruption pipeline through its bidirectional raw-audio WebSocket transport.

The primary API attaches an agent to a caller connection that is already bound to an active rvoip session:

use std::sync::Arc;
use rvoip_core::{ConnectionId, Orchestrator};
use rvoip_vapi::{
    VapiAdapter, VapiApiKey, VapiAssistant, VapiCallOptions, VapiConfig,
};

async fn attach(
    orchestrator: Arc<Orchestrator>,
    caller: ConnectionId,
) -> Result<(), Box<dyn std::error::Error>> {
    let key = VapiApiKey::new(std::env::var("VAPI_API_KEY")?)?;
    let adapter = VapiAdapter::new(VapiConfig::new(key))?;
    let options =
        VapiCallOptions::new(VapiAssistant::saved(std::env::var("VAPI_ASSISTANT_ID")?));

    // Registers this adapter when no Vapi adapter is registered, originates
    // the remote agent, bridges both audio directions, and supervises teardown.
    let mut call = adapter.attach_agent(&orchestrator, caller, options).await?;

    call.say("One moment while I look that up.", false, true).await?;
    let _outcome = call.wait().await;
    Ok(())
}

For a complete high-level server that accepts either SIP or WebRTC with one transport flag, see examples/14-vapi-agent.

VapiAudioFormat::MuLaw8Khz is the default and gives SIP/PCMU a pass-through path. VapiAudioFormat::PcmS16Le16Khz selects raw mono PCM and relies on rvoip’s media graph for conversion to the caller codec.

The low-level path is also available: register VapiAdapter as a ConnectionAdapter, originate Transport::Vapi with a typed VapiCallOptions context, then bridge the resulting connection yourself.

Call events are available through VapiAgentCall::subscribe_events and VapiAdapter::subscribe_vapi_events. Unknown event types are preserved rather than closing the audio session. The first per-call subscriber also receives events buffered during activation. DTMF and transfer remain owned by the rvoip caller leg; Vapi’s WebSocket transport does not define an RTP/DTMF input.

Production configuration requires HTTPS and WSS. API keys, returned socket URLs, assistant definitions, transcripts, audio, and tool payloads are omitted from adapter diagnostics.

The adapter emits content-free counters for setup failures, remote disconnects, bounded-queue overflow, audio-frame flow, unknown or malformed events, dropped RTP DTMF frames, and terminated sessions. Metric labels use only fixed stage, direction, and outcome values.

The live smoke test is ignored by default. Run it explicitly with VAPI_API_KEY and either VAPI_ASSISTANT_ID or VAPI_TRANSIENT_ASSISTANT_JSON:

cargo test -p rvoip-vapi --test live_smoke -- --ignored

Re-exports§

pub use adapter::VapiAdapter;
pub use adapter::VapiTransportHandle;
pub use adapter::ADAPTER_EVENT_CAPACITY;
pub use adapter::VAPI_CALL_REFERENCE_KIND;
pub use agent::VapiAgentCall;
pub use agent::VapiAgentOutcome;
pub use config::VapiApiKey;
pub use config::VapiConfig;
pub use error::Result;
pub use error::VapiError;
pub use events::VapiEvent;
pub use events::VapiEventEnvelope;
pub use types::VapiAssistant;
pub use types::VapiAudioFormat;
pub use types::VapiCallOptions;
pub use types::VapiPeerFailurePolicy;

Modules§

adapter
Staged outbound ConnectionAdapter implementation for Vapi.
agent
High-level caller-to-Vapi attachment and paired lifecycle supervision.
config
Static Vapi adapter configuration.
error
Error types for the Vapi adapter.
events
Typed, forward-compatible Vapi event surface.
types
Public call configuration and control-message types.