Behaviour for message history compression strategies.
Compression strategies transform turn history into LLM messages at render time. This enables various prompt optimization techniques like coalescing multiple turns into a single USER message.
Strategy Pattern
Strategies implement to_messages/3 which receives:
turns- List of completed turns to compressmemory- Accumulated definitions from all turnsopts- Rendering options (mission, tools, data, limits, etc.)
Configuration
Use normalize/1 to handle the various compression option formats:
# Disabled (default)
normalize(nil) # => {nil, []}
normalize(false) # => {nil, []}
# Enabled with defaults
normalize(true) # => {SingleUserCoalesced, [println_limit: 15, tool_call_limit: 20]}
# Custom strategy or options
normalize(MyStrategy) # => {MyStrategy, [println_limit: 15, ...]}
normalize({MyStrategy, opts}) # => {MyStrategy, merged_opts}
Summary
Types
An LLM message with role and content.
Options passed to compression strategies.
Statistics about what compression did.
Callbacks
Human-readable name for this compression strategy.
Render turns into LLM messages with compression statistics.
Functions
Returns the default compression options.
Normalize compression configuration into {strategy, opts} tuple.
Types
@type message() :: %{role: :system | :user | :assistant, content: String.t()}
An LLM message with role and content.
@type opts() :: [ prompt: String.t(), system_prompt: String.t(), tools: map(), data: map(), println_limit: non_neg_integer(), tool_call_limit: non_neg_integer(), turns_left: non_neg_integer() ]
Options passed to compression strategies.
mission- The agent's mission/prompt textsystem_prompt- Static system prompt contenttools- Map of available toolsdata- Input data provided to the agentprintln_limit- Max println calls to include (default: 15)tool_call_limit- Max tool calls to include (default: 20)turns_left- Remaining turns for the agent
@type stats() :: %{ enabled: boolean(), strategy: String.t(), turns_compressed: non_neg_integer(), tool_calls_total: non_neg_integer(), tool_calls_shown: non_neg_integer(), tool_calls_dropped: non_neg_integer(), printlns_total: non_neg_integer(), printlns_shown: non_neg_integer(), printlns_dropped: non_neg_integer(), error_turns_collapsed: non_neg_integer() }
Statistics about what compression did.
Returned alongside messages to report exactly what was dropped or collapsed.
Callbacks
@callback name() :: String.t()
Human-readable name for this compression strategy.
@callback to_messages( turns :: [PtcRunner.Turn.t()], memory :: map(), opts :: opts() ) :: {[message()], stats()}
Render turns into LLM messages with compression statistics.
Returns a tuple of {messages, stats} where stats reports exactly what
the compression did (items dropped, errors collapsed, etc.).
Compression is a pure function - same inputs always produce the same output.
Turn count is derived from length(turns), not message count.
Functions
@spec default_opts() :: keyword()
Returns the default compression options.
Examples
iex> PtcRunner.SubAgent.Compression.default_opts()
[println_limit: 15, tool_call_limit: 20]
Normalize compression configuration into {strategy, opts} tuple.
Handles various configuration formats:
nilorfalse- Compression disabled, returns{nil, []}true- Use default strategy with default optionsModule- Use custom strategy with default options{Module, opts}- Use custom strategy with merged options
Examples
iex> PtcRunner.SubAgent.Compression.normalize(nil)
{nil, []}
iex> PtcRunner.SubAgent.Compression.normalize(false)
{nil, []}
iex> {strategy, opts} = PtcRunner.SubAgent.Compression.normalize(true)
iex> strategy
PtcRunner.SubAgent.Compression.SingleUserCoalesced
iex> opts[:println_limit]
15
iex> opts[:tool_call_limit]
20
iex> {strategy, _opts} = PtcRunner.SubAgent.Compression.normalize(SomeStrategy)
iex> strategy
SomeStrategy
iex> {strategy, opts} = PtcRunner.SubAgent.Compression.normalize({SomeStrategy, println_limit: 5})
iex> strategy
SomeStrategy
iex> opts[:println_limit]
5
iex> opts[:tool_call_limit]
20