An Elixir framework for building real-time voice AI agents.
Connect speech-to-speech models to your application's services and agent backends through browser WebRTC, phone calls, or local audio devices. People can keep talking while backend work runs and correct a request during the conversation.
Your application policy interprets requests and corrections. Parlora coordinates tasks, filters outdated task results before delivery to the voice provider, and manages audio queues, playback controls, lifecycle deadlines, and cleanup. Your application owns business rules, authorization, confirmations, and storage.
Choose a channel, speech provider, backend, and Parlora.ContextPolicy for each
session. All audio passes through Parlora. The provider handles speech and
delegates application work; the backend executes that work independently.
Supported integrations and the runnable tutorials are in the
README and first-session guide.
Starting a session
{:ok, session} = Parlora.start_session(
channel: {Parlora.Channels.LocalAudio, []},
provider: {Parlora.Providers.OpenAI, api_key: key},
backend: backend,
context_policy: {MyApp.OrderPolicy, []},
instructions: "Help the caller with their order.",
event_sink: self()
)backend is your configured adapter tuple. Jido, Sagents, and Legion are optional;
an application can implement Parlora.Backend directly. See
Getting started for dependencies and a complete setup path.
Startup is asynchronous. Keep the event sink alive and wait for
{:parlora_event, %Parlora.Event{source: :session, type: :ready}} before inviting
speech. Handle failures and the session :closed event in the same receiver.
Call close/2 when finished; monitor the PID if you need to wait for its exit.
Sessions are in memory. Persist business data in your application and reconcile uncertain operations before retrying. Correcting or cancelling work cannot undo an external effect, and provider acceptance does not prove a result was heard.
Summary
Functions
Submits a structured context update to the voice provider.
Requests cancellation of a backend request without changing playback.
Requests bounded shutdown using :cancel (default) or :finish.
Applies a supported input or output control.
Arms one opt-in progress deadline on a ready session. See Parlora.SessionHealth.
Reusing an ID with the same options never restarts its deadline.
Resolves or cancels the active expectation without replaying application work.
Returns current conversation context, including transcripts and task inputs.
Starts an asynchronously initialized session.
Operational observations. See Parlora.Status for fields and clarification privacy.
Subscribes a process to future {:parlora_event, event} messages.
Replaces application context and requests interpretation of the new state.
Functions
@spec append_context(pid(), Parlora.ContextUpdate.t()) :: :ok | {:error, Parlora.Error.t()}
Submits a structured context update to the voice provider.
Supported update kinds depend on provider capabilities. Admission, provider acknowledgment, generated speech, and playback are separate observations.
@spec cancel(pid(), String.t(), term(), String.t()) :: :ok | {:error, Parlora.Error.t()}
Requests cancellation of a backend request without changing playback.
Cancellation may be advisory. Reuse an explicit command ID when reconciling an uncertain admission; do not assume cancellation reverses external work.
@spec close(pid(), atom()) :: :ok | {:error, Parlora.Error.t()}
Requests bounded shutdown using :cancel (default) or :finish.
:cancel stops local work; :finish allows work to drain until the shutdown
deadline. Observe session :closed for final outcomes. External work may still
require reconciliation. Monitor the session PID to wait for process termination.
@spec control(pid(), term(), String.t()) :: :ok | {:error, Parlora.Error.t()}
Applies a supported input or output control.
Controls include {:input_muted, boolean}, {:suppress_output, boolean}, and
{:clear_output, :next}. Mute, suppression, clearing, and backend cancellation
are independent. Reuse the command ID when reconciling an uncertain admission.
@spec expect_progress(pid(), String.t(), pos_integer(), keyword()) :: :ok | {:error, Parlora.Error.t()}
Arms one opt-in progress deadline on a ready session. See Parlora.SessionHealth.
Reusing an ID with the same options never restarts its deadline.
@spec resolve_progress(pid(), String.t(), :completed | :cancelled) :: :ok | {:error, Parlora.Error.t()}
Resolves or cancels the active expectation without replaying application work.
@spec snapshot(pid()) :: Parlora.ContextSnapshot.t() | {:error, Parlora.Error.t()}
Returns current conversation context, including transcripts and task inputs.
Starts an asynchronously initialized session.
Required options are :channel, :provider, :backend, and :context_policy,
each a {module, keyword_options} tuple. Optional session settings include
:instructions, :history, :context, :event_sink, :audio_format, and
:limits. The default format is mono PCM16LE at 24 kHz; use
Parlora.AudioFormat.pcmu/0 for phone audio.
Provider audio limits are applied automatically, with explicit :limits
overriding them. Returning {:ok, pid} does not establish readiness; observe
the session :ready event. See the adapter reference
for option, history, and capability requirements.
@spec status(pid()) :: Parlora.Status.t() | {:error, Parlora.Error.t()}
Operational observations. See Parlora.Status for fields and clarification privacy.
@spec subscribe(pid(), pid()) :: :ok | {:error, Parlora.Error.t()}
Subscribes a process to future {:parlora_event, event} messages.
Defaults to the caller. Events are live observations, not a durable replay log.
@spec update_context(pid(), map()) :: :ok | {:error, Parlora.Error.t()}
Replaces application context and requests interpretation of the new state.