Skip to content

mnesis.compaction.levels

levels

Three-level compaction escalation functions.

This module provides:

  • Summarisation — converts raw messages into a leaf summary node. Three escalation levels: level 1 (structured LLM), level 2 (aggressive LLM), level 3 (deterministic truncation — always succeeds).

  • Condensation — merges one or more existing summary nodes into a single condensed node. Three escalation levels mirror summarisation.

Both operations extract file_xxx identifiers from their inputs and append a [LCM File IDs: ...] footer to the output, preserving the "lossless" guarantee across compaction rounds.

Summarisation input cap: messages passed to the LLM summarizer are capped at MAX_SUMMARISATION_INPUT_FRACTION (75 %) of the compaction model's context window to prevent the compaction call itself from overflowing.

SummaryCandidate dataclass

SummaryCandidate(
    text: str,
    token_count: int,
    span_start_message_id: str,
    span_end_message_id: str,
    compaction_level: int,
    messages_covered: int,
)

A candidate compaction summary before it is committed to the store.

CondensationCandidate dataclass

CondensationCandidate(
    text: str,
    token_count: int,
    parent_node_ids: list[str] = list(),
    compaction_level: int = 1,
)

A candidate condensation of one or more existing summary nodes.

compaction_level class-attribute instance-attribute

compaction_level: int = 1

Condensation escalation level: 1 = normal, 2 = aggressive, 3 = deterministic.

level1_summarise async

level1_summarise(
    messages: list[MessageWithParts],
    model: str,
    budget: ContextBudget,
    estimator: TokenEstimator,
    llm_call: Any,
    compaction_prompt: str | None = None,
    model_context_limit: int = 200000,
    model_max_output_tokens: int = 0,
    compaction_estimator: TokenEstimator | None = None,
) -> SummaryCandidate | None

Attempt Level 1 (selective) summarisation via LLM.

File IDs found in the input messages are automatically appended to the summary via a [LCM File IDs: ...] footer.

Input messages are capped at 75 % of the compaction model's context window to prevent the summarisation call itself from overflowing.

Parameters:

Name Type Description Default
messages list[MessageWithParts]

All non-summary messages in the session.

required
model str

Model string to use for compaction.

required
budget ContextBudget

Token budget for validation.

required
estimator TokenEstimator

Token estimator for result validation.

required
llm_call Any

Async callable (model, messages, max_tokens) -> str.

required
compaction_prompt str | None

Custom system prompt override.

None
model_context_limit int

Context window of the compaction model.

200000
model_max_output_tokens int

Output limit of the compaction model (0 = unknown).

0
compaction_estimator TokenEstimator | None

Estimator in the compaction model's units, used to size the input against its window (defaults to estimator).

None

Returns:

Type Description
SummaryCandidate | None

SummaryCandidate if successful and fits budget, or None to escalate.

level2_summarise async

level2_summarise(
    messages: list[MessageWithParts],
    model: str,
    budget: ContextBudget,
    estimator: TokenEstimator,
    llm_call: Any,
    compaction_prompt: str | None = None,
    model_context_limit: int = 200000,
    model_max_output_tokens: int = 0,
    compaction_estimator: TokenEstimator | None = None,
) -> SummaryCandidate | None

Attempt Level 2 (aggressive) summarisation via LLM.

Uses a more compressed prompt format and drops reasoning details. File IDs found in the input messages are propagated to the summary. Input is capped at 75 % of the compaction model's context window.

Parameters:

Name Type Description Default
messages list[MessageWithParts]

All non-summary messages in the session.

required
model str

Model string to use for compaction.

required
budget ContextBudget

Token budget for validation.

required
estimator TokenEstimator

Token estimator for result validation.

required
llm_call Any

Async callable.

required
compaction_prompt str | None

Custom system prompt override.

None
model_context_limit int

Context window of the compaction model.

200000
model_max_output_tokens int

Output limit of the compaction model (0 = unknown).

0
compaction_estimator TokenEstimator | None

Estimator in the compaction model's units, used to size the input against its window (defaults to estimator).

None

Returns:

Type Description
SummaryCandidate | None

SummaryCandidate if successful and fits budget, or None to escalate.

level3_deterministic

level3_deterministic(
    messages: list[MessageWithParts],
    budget: ContextBudget,
    estimator: TokenEstimator,
) -> SummaryCandidate

Level 3 deterministic fallback (no LLM required).

Keeps the most recent messages that fit within 85% of the usable budget, prefixed with a truncation notice. This always produces a valid result.

File IDs found in all input messages (not just kept ones) are preserved in a [LCM File IDs: ...] footer even when their surrounding context is truncated — this is the lossless guarantee.

Precedence when the budget is tight: file IDs are reserved first, then prose fills what remains, so messages are dropped before any file ID is. Only if the header plus the ID footer cannot fit in 85% of budget.usable is the footer truncated, keeping the most recently referenced IDs (by last occurrence; the footer itself stays in first-occurrence order). A warning with the dropped count is logged; the raw files stay addressable in the immutable store. Truncating there is the only way to keep the "always fits the budget" guarantee that lets compaction make progress. If budget.usable is smaller than the minimal header, no output can fit, so all IDs are kept (lossless wins).

Parameters:

Name Type Description Default
messages list[MessageWithParts]

All non-summary messages in the session.

required
budget ContextBudget

Token budget — result is guaranteed to fit within usable.

required
estimator TokenEstimator

Token estimator.

required

Returns:

Type Description
SummaryCandidate

SummaryCandidate that fits within budget.usable (barring a budget too

SummaryCandidate

small for even the minimal header), as measured by estimator.

condense_level1 async

condense_level1(
    nodes: list[SummaryNode],
    model: str,
    budget: ContextBudget,
    estimator: TokenEstimator,
    llm_call: Any,
    model_max_output_tokens: int = 0,
    model_context_limit: int = 200000,
    compaction_estimator: TokenEstimator | None = None,
) -> CondensationCandidate | None

Attempt Level 1 condensation: merge summary nodes via structured LLM prompt.

The input is capped against the compaction model's window (see :func:_fit_condensation_nodes): when the nodes do not all fit, the oldest ones that do are condensed and the candidate's parent_node_ids name exactly those; the rest stay live for a later round. File IDs from the condensed nodes are collected and appended to the output via a [LCM File IDs: ...] footer.

Parameters:

Name Type Description Default
nodes list[SummaryNode]

Summary nodes to condense (must be non-empty).

required
model str

LLM model string.

required
budget ContextBudget

Token budget for the condensed result.

required
estimator TokenEstimator

Token estimator.

required
llm_call Any

Async callable (model, messages, max_tokens) -> str.

required
model_max_output_tokens int

Output limit of the compaction model (0 = unknown).

0
model_context_limit int

Context window of the compaction model.

200000
compaction_estimator TokenEstimator | None

Estimator in the compaction model's units, used to size the input against its window (defaults to estimator).

None

Returns:

Type Description
CondensationCandidate | None

CondensationCandidate if successful and fits budget, or None to escalate.

condense_level2 async

condense_level2(
    nodes: list[SummaryNode],
    model: str,
    budget: ContextBudget,
    estimator: TokenEstimator,
    llm_call: Any,
    model_max_output_tokens: int = 0,
    model_context_limit: int = 200000,
    compaction_estimator: TokenEstimator | None = None,
) -> CondensationCandidate | None

Attempt Level 2 condensation: aggressive merge via compressed prompt.

Each node contributes a bounded excerpt. The input is still capped against the compaction model's window (as in :func:condense_level1): when the excerpts do not all fit, the oldest nodes that do are condensed and the candidate's parent_node_ids name exactly those.

Parameters:

Name Type Description Default
nodes list[SummaryNode]

Summary nodes to condense.

required
model str

LLM model string.

required
budget ContextBudget

Token budget.

required
estimator TokenEstimator

Token estimator.

required
llm_call Any

Async callable.

required
model_max_output_tokens int

Output limit of the compaction model (0 = unknown).

0
model_context_limit int

Context window of the compaction model.

200000
compaction_estimator TokenEstimator | None

Estimator in the compaction model's units, used to size the input against its window (defaults to estimator).

None

Returns:

Type Description
CondensationCandidate | None

CondensationCandidate if successful and fits budget, or None to escalate.

condense_level3_deterministic

condense_level3_deterministic(
    nodes: list[SummaryNode],
    estimator: TokenEstimator,
    budget: ContextBudget,
) -> CondensationCandidate

Level 3 deterministic condensation fallback (no LLM required).

Concatenates the parent summaries' prose (without their own file-ID footers) up to :data:_CONDENSE_LEVEL3_MAX_TOKENS tokens, then appends a single [LCM File IDs: ...] footer with the IDs from every parent node.

Bounded like :func:level3_deterministic: the footer and header are sized against 85% of budget.usable with estimator and the assembled text is validated against budget.usable. File IDs take precedence over prose (prose gets what remains), and over the [Condensed from: ...] parent list, which is replaced by a minimal header when it would crowd the prose. Only when the footer cannot fit the budget are the least recently referenced IDs dropped (with a warning); the raw files stay addressable in the immutable store.

Parameters:

Name Type Description Default
nodes list[SummaryNode]

Summary nodes to condense.

required
estimator TokenEstimator

Token estimator.

required
budget ContextBudget

Token budget the result must fit within.

required

Returns:

Type Description
CondensationCandidate

CondensationCandidate that always succeeds and fits budget.usable

CondensationCandidate

(barring a budget too small for even the minimal header).