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

Continuous full-duplex voice, client delegation and correlated context updates.

The current session coordinator requires the selected `AudioFormat` in
`Capabilities.audio_formats`, `full_duplex?: true`, `:client` in
`delegation_modes`, and `:speakable` in `context_update_kinds`. It rejects an
incompatible ready provider with `:unsupported` and closes the session before
starting the audio pipelines. Process startup alone does not imply readiness.

This is a contract for this voice architecture, not a universal STT/LLM/TTS or
turn-based model interface. Another implementation must translate its behavior
into these semantics; implementing the callbacks alone is insufficient.

Quiet/instruction updates, mute, usage and transcript speakers are declared
capabilities, not startup requirements. The application policy must have enough
context to interpret delegations; the coordinator does not infer task arguments
or invent missing transcripts. Unsupported commands return `:unsupported`.
`output_buffer_status/1` and `arm_output_ready/3` are optional. The selected pipeline format is used in
both directions even when a provider can support different formats internally.

Context admission, provider acknowledgment, backend completion and playback
evidence remain separate. A provider must preserve command correlation without
promising that the caller heard an acknowledged context update.

# `append_context`

```elixir
@callback append_context(pid(), Parlora.ContextUpdate.t()) ::
  :ok | {:error, Parlora.Error.t()}
```

# `arm_output_ready`
*optional* 

```elixir
@callback arm_output_ready(pid(), pid(), reference()) :: :ok | {:error, Parlora.Error.t()}
```

Arm a one-shot generated-audio notification for a single output reader.

Send `{:parlora_audio_ready, provider_pid, reference}` to `reader` when audio
is available, including when it was queued before this call. A new arm replaces
the previous one. Successful nonempty reads and close retire the arm. It is a
scheduling hint, not an audio frame or playback evidence. Implementations keep
at most one arm and send at most one notification per arm.

# `audio_limits`
*optional* 

```elixir
@callback audio_limits(Parlora.AudioFormat.t()) :: keyword()
```

Provider receive-storage defaults, independent of the playback cushion. Explicit session limits override them.

# `capabilities`

```elixir
@callback capabilities(pid()) ::
  {:ok, Parlora.Provider.Capabilities.t()} | {:error, Parlora.Error.t()}
```

# `close`

```elixir
@callback close(pid(), String.t(), term()) :: :ok | {:error, Parlora.Error.t()}
```

# `control`

```elixir
@callback control(pid(), String.t(), {:input_muted, boolean()}) ::
  :ok | {:error, Parlora.Error.t()}
```

# `output_buffer_status`
*optional* 

```elixir
@callback output_buffer_status(pid()) ::
  {:ok, %{queued_bytes: non_neg_integer(), capacity_bytes: pos_integer()}}
  | {:error, Parlora.Error.t()}
```

Optional snapshot of generated audio waiting for the output pipeline, in bytes.

# `read_audio`

```elixir
@callback read_audio(pid(), pos_integer()) ::
  {:ok, [Parlora.AudioFrame.t()]} | {:error, Parlora.Error.t()}
```

# `recover_output`
*optional* 

```elixir
@callback recover_output(pid(), pos_integer(), Parlora.ContextSnapshot.t()) ::
  :ok | {:error, Parlora.Error.t()}
```

Replace an overloaded voice transport after the coordinator cleared its playback. Preserve backend execution and logical provider generation.

# `resolve_delegation`
*optional* 

```elixir
@callback resolve_delegation(pid(), String.t(), map()) ::
  :ok | {:error, Parlora.Error.t()}
```

Resolve a provider function call that was associated, rejected, or superseded without a new result.

# `resume_output`
*optional* 

```elixir
@callback resume_output(pid(), non_neg_integer()) :: :ok | {:error, Parlora.Error.t()}
```

Release new output after the coordinator cleared interrupted playback.

# `start_link`

```elixir
@callback start_link(Parlora.AdapterInit.t(), keyword()) ::
  {:ok, pid()} | {:error, Parlora.Error.t()}
```

# `write_audio`

```elixir
@callback write_audio(pid(), Parlora.AudioFrame.t()) :: :ok | {:error, Parlora.Error.t()}
```

---

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