Skip to content

Compression behaviour and normalize #619

@andreasronge

Description

@andreasronge

Summary

Define the Compression behaviour interface and option normalization for message history compression strategies.

Context

This issue establishes the foundation for pluggable compression strategies. The Compression behaviour defines how turn history is rendered into LLM messages, while normalize/1 handles the various ways users can configure compression (nil, true, false, Module, {Module, opts}).

Spec: message-history-optimization-architecture.md (Roadmap Issue #12)

Requirements

ARC-003: Compression behaviour with callbacks

Compression behaviour defines strategy interface with to_messages/3 and name/0 callbacks.

ARC-004: Compression is pure render function

Compression is a pure render function - same input always produces same output, no side effects.

ARC-006: Turn count from length(turns)

Turn count derived from length(turns), not messages. Message array length varies by compression strategy.

API-001: compression: true enables default strategy

compression: true enables compression with default strategy. Uses SingleUserCoalesced.

API-002: compression: {Strategy, opts} custom strategy

compression: {Strategy, opts} enables with custom strategy and options. e.g., {SingleUserCoalesced, println_limit: 10}.

API-003: compression: false/nil disables

compression: false or nil disables compression (default).

API-004: Default println_limit

Default println_limit is 15. Most recent println calls shown.

API-005: Default tool_call_limit

Default tool_call_limit is 20. Most recent tool calls shown.

API-006: normalize/1 returns tuple

Compression.normalize/1 returns {strategy, opts} tuple. Handles nil, true, false, Module, {Module, opts}.

API-007: Options inherited

Options inherited like other SubAgent options.

CMP-003: Compression at render time

Compression happens at start of each new turn (not storage time). Pure render function.

Implementation

File to create

  • lib/ptc_runner/sub_agent/compression.ex

Behaviour definition

defmodule PtcRunner.SubAgent.Compression do
  @moduledoc """
  Behaviour for message history compression strategies.
  """

  alias PtcRunner.Turn

  @type message :: %{role: :system | :user | :assistant, content: String.t()}
  @type opts :: [
    mission: 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()
  ]

  @doc "Human-readable name for this strategy."
  @callback name() :: String.t()

  @doc "Render turns into LLM messages."
  @callback to_messages(
    turns :: [Turn.t()],
    memory :: map(),
    opts :: opts()
  ) :: [message()]
end

Normalize function

Pattern matching approach (see ToolNormalizer for similar pattern):

@spec normalize(boolean() | module() | {module(), keyword()} | nil) ::
  {module() | nil, keyword()}
def normalize(nil), do: {nil, []}
def normalize(false), do: {nil, []}
def normalize(true), do: {SingleUserCoalesced, default_opts()}
def normalize(module) when is_atom(module), do: {module, default_opts()}
def normalize({module, opts}) when is_atom(module) and is_list(opts),
  do: {module, Keyword.merge(default_opts(), opts)}

defp default_opts, do: [println_limit: 15, tool_call_limit: 20]

Note: SingleUserCoalesced reference will be the module from issue #620, which this issue blocks.

Acceptance Criteria

  • @behaviour defined with @callback to_messages(turns, context, opts) and @callback name()
  • normalize/1 handles: nil -> {nil, []}
  • normalize/1 handles: false -> {nil, []}
  • normalize/1 handles: true -> {SingleUserCoalesced, default_opts}
  • normalize/1 handles: Module -> {Module, default_opts}
  • normalize/1 handles: {Module, opts} -> {Module, merged_opts}
  • Returns {strategy | nil, opts} tuple
  • Default opts include println_limit: 15 and tool_call_limit: 20
  • Type specs for @type message/0 and @type opts/0
  • Docstrings for callbacks and public functions

Test Cases

# normalize/1 tests
test "normalize(nil) returns {nil, []}"
test "normalize(false) returns {nil, []}"
test "normalize(true) returns {SingleUserCoalesced, default_opts}"
test "normalize(CustomStrategy) returns {CustomStrategy, default_opts}"
test "normalize({CustomStrategy, println_limit: 5}) merges with defaults"

Dependencies

Blocked by: #634 (Turn struct) - CLOSED

Blocks: #620 (SingleUserCoalesced compression strategy)

Files

Create:

  • lib/ptc_runner/sub_agent/compression.ex

Complexity

Size: S (1-2h) - Behaviour definition + normalize function with tests.

Automation State

Field Value
Status SUCCESS
PR #647
Branch claude/619-compression-behaviour
Attempts 1

Details: Implementation complete. Created Compression behaviour with to_messages/3 and name/0 callbacks, plus normalize/1 function handling all configuration variants (nil, false, true, Module, {Module, opts}).

Files Created:

  • lib/ptc_runner/sub_agent/compression.ex
  • test/ptc_runner/sub_agent/compression_test.exs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions