formatCompactionReport function

List<String> formatCompactionReport(
  1. AutoCompactorPass pass, {
  2. required bool auto,
})

Auto/manual compaction run methods (moved from agent_cli.dart under the repo's 2800-line size gate). Same library, so private state is in scope. Formats the in-chat compaction report block (issue #276): tokens before → after, freed count/percent, WHICH ENGINE did the summarizing (the smol/main role — review major 3: a report that doesn't name the engine can't be judged), how many records were hidden vs summarized, and — when the pass actually wrote summary text — the summary in a fenced block so the user can eyeball — and copy — what the transcript was condensed to. A pass with no summary text (all evictions went to hide, or the model returned blank — issue #578) omits the block: an empty ```-fence says nothing and reads as a bug. Pure; _AgentCliCompactionReportPrinter.print renders it.

Implementation

/// Formats the in-chat compaction report block (issue #276): tokens
/// before → after, freed count/percent, WHICH ENGINE did the summarizing
/// (the `smol`/`main` role — review major 3: a report that doesn't name
/// the engine can't be judged), how many records were hidden vs
/// summarized, and — when the pass actually wrote summary text — the
/// summary in a fenced block so the user can eyeball — and copy — what
/// the transcript was condensed to. A pass with no summary text (all
/// evictions went to hide, or the model returned blank — issue #578)
/// omits the block: an empty ```-fence says nothing and reads as a bug.
/// Pure; [_AgentCliCompactionReportPrinter.print] renders it.
List<String> formatCompactionReport(
  AutoCompactorPass pass, {
  required bool auto,
}) {
  final freedRaw = pass.tokensBefore - pass.tokensAfter;
  // A restamped estimator can report a slightly larger after-count (same
  // clamp as onDone's HEP end frame): "-30 freed" reads as a bug.
  final freed = freedRaw < 0 ? 0 : freedRaw;
  final pct = pass.tokensBefore == 0
      ? 0
      : (freed * 100 / pass.tokensBefore).round();
  final engine = pass.fallback == null ? '' : ' · ${pass.fallback}';
  final passSuffix = pass.pass == 1 ? '' : ' · pass ${pass.pass}';
  final summary = pass.summary?.trim();
  return [
    '${auto ? 'auto-compacted' : 'compacted'}$engine$passSuffix',
    'tokens: ${pass.tokensBefore} → ${pass.tokensAfter} '
        '($freed freed · $pct%)',
    // Issue #673 AC3: the local-trim valve frees tokens WITHOUT hiding
    // session records or folding a summary — a bare "0 hidden · 0
    // summarized" next to a big freed count cannot describe a real
    // compaction. Name the in-memory drop so the line is truthful for
    // BOTH engines.
    if (pass.droppedMessages > 0)
      'records: ${pass.droppedMessages} dropped (in-memory) · '
          '${pass.hiddenRecords} hidden · '
          '${pass.summarizedMessages} summarized'
    else
      'records: ${pass.hiddenRecords} hidden · '
          '${pass.summarizedMessages} summarized',
    if (summary != null && summary.isNotEmpty) ...[
      'summary:',
      '```',
      summary,
      '```',
    ],
  ];
}