Planck.Agent.Compactor behaviour (Planck.Agent v0.1.0)

Copy Markdown View Source

Behaviour and default implementation for context compaction in Planck.Agent.

Behaviour

Use use Planck.Agent.Compactor to implement a custom compaction strategy. The only required callback is compact/2; compact_timeout/0 has a default implementation of 120000 ms.

defmodule MySidecar.Compactors.Builder do
  use Planck.Agent.Compactor

  @impl true
  def compact(_model, messages) do
    summary = Message.new({:custom, :summary}, [{:text, summarise(messages)}])
    kept    = Enum.take(messages, -5)
    {:compact, summary, kept}
  end

  # Optional — override to declare a custom RPC timeout.
  @impl true
  def compact_timeout, do: 60_000
end

Building an on_compact function

build/2 is the single entry point for both the local LLM-based compactor and remote sidecar compactors. When sidecar_node: and compactor: options are absent it runs locally; when both are present it calls the remote module via :rpc.call/5 and falls back to the local compactor if the RPC fails.

# Local (default):
on_compact = Planck.Agent.Compactor.build(model)

# Remote sidecar:
on_compact = Planck.Agent.Compactor.build(model,
  sidecar_node: :planck_sidecar@localhost,
  compactor:    "MySidecar.Compactors.Builder"
  # The string is converted to the atom :"Elixir.MySidecar.Compactors.Builder"
  # before the RPC call. Always use the bare Elixir module name (no "Elixir." prefix).
)

Both return a fn messages -> closure of arity 1, as expected by Planck.Agent.

Compaction strategy (local default)

When triggered, the oldest messages (everything except the last keep_recent messages) are summarised into a single {:custom, :summary} message. On LLM failure the local compactor falls back to the original message list unchanged (:skip). On remote failure the local compactor is used as the fallback.

Summary

Types

Options accepted by build/2.

Callbacks

Compact the message list.

RPC call timeout in milliseconds when this compactor is invoked remotely.

Functions

Build an on_compact function for the given model.

Default RPC timeout used when a compactor module omits compact_timeout/0.

Types

opts()

@type opts() :: [
  ratio: float(),
  keep_recent: pos_integer(),
  sidecar_node: atom() | nil,
  compactor: String.t() | nil
]

Options accepted by build/2.

  • :ratio — fraction of model.context_window that triggers compaction (default 0.8)
  • :keep_recent — number of recent messages to keep verbatim (default 10)
  • :sidecar_node — node name of a connected sidecar (enables remote compaction)
  • :compactor — fully-qualified module name string in the sidecar, e.g. "MySidecar.Compactors.Builder". Required when :sidecar_node is set.

Callbacks

compact(model, messages)

@callback compact(model :: Planck.AI.Model.t(), messages :: [Planck.Agent.Message.t()]) ::
  {:compact, summary :: Planck.Agent.Message.t(),
   kept :: [Planck.Agent.Message.t()]}
  | :skip

Compact the message list.

Return {:compact, summary_msg, kept} to replace older messages with a summary, or :skip to leave the list unchanged.

  • summary_msg — a {:custom, :summary} Message containing the summary text
  • kept — recent messages retained verbatim after the summary

compact_timeout()

@callback compact_timeout() :: pos_integer()

RPC call timeout in milliseconds when this compactor is invoked remotely.

Defaults to 120000 ms. Override to declare a custom expected latency for the compactor — the module knows its own logic better than any caller default.

Functions

build(model, opts \\ [])

@spec build(Planck.AI.Model.t(), opts()) :: ([Planck.Agent.Message.t()] ->
                                         :skip
                                         | {:compact, Planck.Agent.Message.t(),
                                            [Planck.Agent.Message.t()]})

Build an on_compact function for the given model.

Returns a fn messages -> closure of arity 1. When remote options are provided (sidecar_node: and compactor:), the closure calls the remote module via RPC and falls back to the local LLM-based compactor if the call fails.

Examples

# Local:
on_compact = Planck.Agent.Compactor.build(model, ratio: 0.75)

# Remote sidecar with local fallback:
on_compact = Planck.Agent.Compactor.build(model,
  sidecar_node: :planck_sidecar@localhost,
  compactor: "MySidecar.Compactors.Builder"
)

default_compact_timeout()

@spec default_compact_timeout() :: pos_integer()

Default RPC timeout used when a compactor module omits compact_timeout/0.