# `Parlora`
[🔗](https://github.com/hfiguera/parlora/blob/v0.1.0/lib/parlora.ex#L1)

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](readme.html) and [first-session guide](first-session.html).

## 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](using-parlora.html) 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.

# `append_context`

```elixir
@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.

# `cancel`

```elixir
@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.

# `close`

```elixir
@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.

# `control`

```elixir
@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.

# `expect_progress`

```elixir
@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.

# `resolve_progress`

```elixir
@spec resolve_progress(pid(), String.t(), :completed | :cancelled) ::
  :ok | {:error, Parlora.Error.t()}
```

Resolves or cancels the active expectation without replaying application work.

# `snapshot`

```elixir
@spec snapshot(pid()) :: Parlora.ContextSnapshot.t() | {:error, Parlora.Error.t()}
```

Returns current conversation context, including transcripts and task inputs.

# `start_session`

```elixir
@spec start_session(keyword()) :: {:ok, pid()} | {:error, term()}
```

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](public-interfaces.html)
for option, history, and capability requirements.

# `status`

```elixir
@spec status(pid()) :: Parlora.Status.t() | {:error, Parlora.Error.t()}
```

Operational observations. See `Parlora.Status` for fields and clarification privacy.

# `subscribe`

```elixir
@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.

# `update_context`

```elixir
@spec update_context(pid(), map()) :: :ok | {:error, Parlora.Error.t()}
```

Replaces application context and requests interpretation of the new state.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
