MCPcopy Create free account
hub / github.com/diillson/chatcli / Compact

Method Compact

cli/history_compactor.go:207–284  ·  view source on GitHub ↗

Compact runs the 3-level compaction pipeline. Each level is progressively more aggressive. Most of the time, Level 1 (trim) suffices.

(
	ctx context.Context,
	history []models.Message,
	llmClient client.LLMClient,
	cfg CompactConfig,
)

Source from the content-addressed store, hash-verified

205// Compact runs the 3-level compaction pipeline.
206// Each level is progressively more aggressive. Most of the time, Level 1 (trim) suffices.
207func (hc *HistoryCompactor) Compact(
208 ctx context.Context,
209 history []models.Message,
210 llmClient client.LLMClient,
211 cfg CompactConfig,
212) ([]models.Message, error) {
213 budget := hc.CharBudget(cfg)
214 before := totalChars(history)
215 beforeMsgs := len(history)
216
217 hc.logger.Info("History compaction triggered",
218 zap.Int("budget_chars", budget),
219 zap.Int("current_chars", before),
220 zap.Int("messages", beforeMsgs),
221 zap.Int("max_payload_bytes", cfg.MaxPayloadBytes),
222 )
223 hc.emitStatus(CompactStageStart, i18n.T("compact.status.start",
224 beforeMsgs, FormatPayloadSize(before), FormatPayloadSize(budget)))
225
226 // LEVEL 1: Near-lossless trimming — pure Go, no network
227 hc.emitStatus(CompactStageTrim, i18n.T("compact.status.trim"))
228 history = hc.trimmer.TrimHistory(history)
229 current := totalChars(history)
230 if current <= budget {
231 hc.logger.Info("Level 1 (trim) sufficient",
232 zap.Int("before_chars", before),
233 zap.Int("after_chars", current),
234 )
235 hc.emitStatus(CompactStageDone, i18n.T("compact.status.trim_sufficient",
236 FormatPayloadSize(before), FormatPayloadSize(current)))
237 return history, nil
238 }
239
240 // LEVEL 2: Structured summarization of old messages (requires LLM call)
241 hc.emitStatus(CompactStageSummarize, i18n.T("compact.status.summarize"))
242 summarized, err := hc.structuredSummarize(ctx, history, llmClient, cfg)
243 if err != nil {
244 // A cancellation from the user should propagate, not silently fall
245 // through to emergency truncation — the user's own choice to abort
246 // must not mangle their history.
247 if ctx.Err() != nil {
248 hc.emitStatus(CompactStageDone, i18n.T("compact.status.canceled"))
249 return nil, ctx.Err()
250 }
251 hc.logger.Warn("Level 2 (summarization) failed, falling back",
252 zap.Error(err),
253 )
254 hc.emitStatus(CompactStageSummarize,
255 i18n.T("compact.status.summarize_failed", err))
256 } else {
257 history = summarized
258 current = totalChars(history)
259 if current <= budget {
260 hc.logger.Info("Level 2 (structured summarization) sufficient",
261 zap.Int("before_chars", before),
262 zap.Int("after_chars", current),
263 zap.Int("before_msgs", beforeMsgs),
264 zap.Int("after_msgs", len(history)),

Callers 6

RunOnceMethod · 0.80
handleCompactCommandMethod · 0.80
tryCompactJSONFunction · 0.80
CompressMethod · 0.80

Calls 11

CharBudgetMethod · 0.95
emitStatusMethod · 0.95
structuredSummarizeMethod · 0.95
emergencyTruncateMethod · 0.95
TFunction · 0.92
totalCharsFunction · 0.85
FormatPayloadSizeFunction · 0.85
TrimHistoryMethod · 0.80
WarnMethod · 0.80
InfoMethod · 0.65
ErrorMethod · 0.65

Tested by

no test coverage detected