AgentSessionManager.Rendering.Sink behaviour (AgentSessionManager v0.8.0)

Copy Markdown View Source

Behaviour for output destinations that receive rendered text from a renderer.

A sink writes rendered output to a specific destination: terminal, file, JSON log, callback function, etc. Sinks receive iodata and decide how to write it.

Implementing a Sink

defmodule MySink do
  @behaviour AgentSessionManager.Rendering.Sink

  @impl true
  def init(opts), do: {:ok, %{device: opts[:device] || :stdio}}

  @impl true
  def write(iodata, state) do
    IO.write(state.device, iodata)
    {:ok, state}
  end

  @impl true
  def write_event(_event, _iodata, state), do: {:ok, state}

  @impl true
  def flush(state), do: {:ok, state}

  @impl true
  def close(state), do: :ok
end

Rendered vs Raw Output

Sinks receive output through two channels:

  • write/2 — Rendered text from the renderer. Used for human-readable output.
  • write_event/3 — The raw event plus rendered text. Used by sinks that need the structured event data (e.g. JSONL loggers that serialize events, not text).

Summary

Callbacks

Close the sink and release resources.

Flush any buffered output.

Initialize sink state from options.

Write rendered iodata to the output destination.

Write the raw event alongside its rendered form. Called for every event.

Types

opts()

@type opts() :: keyword()

state()

@type state() :: term()

Callbacks

close(state)

@callback close(state()) :: :ok

Close the sink and release resources.

flush(state)

@callback flush(state()) :: {:ok, state()}

Flush any buffered output.

init(opts)

@callback init(opts()) :: {:ok, state()} | {:error, term()}

Initialize sink state from options.

write(iodata, state)

@callback write(iodata(), state()) :: {:ok, state()} | {:error, term(), state()}

Write rendered iodata to the output destination.

write_event(event, iodata, state)

@callback write_event(event :: map(), iodata(), state()) ::
  {:ok, state()} | {:error, term(), state()}

Write the raw event alongside its rendered form. Called for every event.

Sinks that only care about rendered text can delegate to write/2 or no-op. Sinks that need structured data (JSONL, callback) use the event directly.