Puck.LiveView.Handler behaviour (Puck v0.2.23)

Copy Markdown View Source

Behaviour for handling stream lifecycle events inside the stream process.

When using Puck.LiveView, the stream GenServer survives LiveView disconnects (it's supervised under Puck.LiveView). This makes it the right place for persistence logic — if the LiveView disconnects mid-stream, the handler still fires.

Handlers run after PubSub broadcast, so LiveView always gets events even if the handler fails.

Callbacks

All four callbacks are optional — implement only what you need.

  • on_chunk/2 — Called for each chunk. The only callback that threads state, enabling batching or buffering patterns.
  • on_done/3 — Called when the stream completes with a response and context.
  • on_error/2 — Called when the stream fails.
  • on_cancel/2 — Called when the stream is cancelled.

Usage

defmodule MyApp.ChatPersistence do
  @behaviour Puck.LiveView.Handler

  @impl true
  def on_done(response, context, %{conversation_id: id}) do
    MyApp.Conversations.save_message(id, response.content)
    :ok
  end
end

Puck.LiveView.start_stream(client, prompt, context,
  pubsub: MyApp.PubSub,
  handler: {MyApp.ChatPersistence, %{conversation_id: id}}
)

The config map doubles as the initial handler state — no init callback needed. This matches the {module, config} pattern used by Puck.Compaction.

Summary

Callbacks

on_cancel(content, state)

(optional)
@callback on_cancel(content :: term(), state :: term()) :: :ok

on_chunk(chunk, state)

(optional)
@callback on_chunk(chunk :: map(), state :: term()) :: {:cont, new_state :: term()}

on_done(response, context, state)

(optional)
@callback on_done(
  response :: Puck.Response.t(),
  context :: Puck.Context.t(),
  state :: term()
) :: :ok

on_error(reason, state)

(optional)
@callback on_error(reason :: term(), state :: term()) :: :ok