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

Method structuredSummarize

cli/history_compactor.go:288–357  ·  view source on GitHub ↗

structuredSummarize summarizes the "middle" block of messages using a structured fact-extraction prompt.

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

Source from the content-addressed store, hash-verified

286// structuredSummarize summarizes the "middle" block of messages using
287// a structured fact-extraction prompt.
288func (hc *HistoryCompactor) structuredSummarize(
289 ctx context.Context,
290 history []models.Message,
291 llmClient client.LLMClient,
292 cfg CompactConfig,
293) ([]models.Message, error) {
294 // Find boundaries: [system messages | middle (to summarize) | recent (keep verbatim)]
295 systemEnd := 0
296 for i, msg := range history {
297 if msg.Role == "system" && i == systemEnd {
298 systemEnd = i + 1
299 } else {
300 break
301 }
302 }
303
304 recentStart := len(history) - cfg.MinKeepRecent
305 if recentStart <= systemEnd {
306 // Not enough messages to split — nothing to summarize
307 return history, nil
308 }
309
310 middleMessages := history[systemEnd:recentStart]
311 if len(middleMessages) < 4 {
312 return history, nil
313 }
314
315 // Build input for the summarizer
316 var sb strings.Builder
317 for _, msg := range middleMessages {
318 content := msg.Content
319 if len(content) > 2000 {
320 content = content[:1500] + "\n... [truncated for summarization] ...\n" + content[len(content)-300:]
321 }
322 sb.WriteString(fmt.Sprintf("[%s]: %s\n\n", msg.Role, content))
323 }
324
325 prompt := structuredSummaryPrompt + "\n\nCONVERSATION SEGMENT TO EXTRACT FROM:\n\n" + sb.String()
326
327 summaryHistory := []models.Message{
328 {Role: "user", Content: prompt},
329 }
330
331 // Derive from parent ctx so that a user-initiated cancel (Ctrl+C / ESC)
332 // propagates and aborts the long summarization. We add our OWN generous
333 // timeout (10 min) to protect against ambient turn-level deadlines that
334 // might be shorter than the summary LLM call.
335 summarizeCtx, cancel := context.WithTimeout(ctx, 10*time.Minute)
336 defer cancel()
337
338 response, err := llmClient.SendPrompt(summarizeCtx, prompt, summaryHistory, 0)
339 if err != nil {
340 return nil, fmt.Errorf("structured summarization LLM call failed: %w", err)
341 }
342
343 // Reconstruct: system + summary message + recent messages
344 result := make([]models.Message, 0, systemEnd+1+cfg.MinKeepRecent)
345 result = append(result, history[:systemEnd]...)

Callers 1

CompactMethod · 0.95

Calls 3

ErrorfMethod · 0.80
SendPromptMethod · 0.65
StringMethod · 0.45

Tested by

no test coverage detected