Files
gnoma/internal/context/truncate.go
T
vikingowl b0b393517e feat: M6 context intelligence — token tracker + truncation compaction
internal/context/:
- Tracker: monitors token usage with OK/Warning/Critical states
  (thresholds from CC: 20K warning buffer, 13K autocompact buffer)
- TruncateStrategy: drops oldest messages, preserves system prompt +
  recent N turns, adds compaction boundary marker
- Window: manages message history with auto-compaction trigger,
  circuit breaker after 3 consecutive failures

Engine integration:
- Context window tracks usage per turn
- Auto-compacts when critical threshold reached
- History syncs with context window after compaction

TUI status bar:
- Token count with percentage (tokens: 1234 (5%))
- Color-coded: green=ok, yellow=warning, red=critical

Session Status extended: TokensMax, TokenPercent, TokenState.
7 context tests.
2026-04-03 18:46:03 +02:00

57 lines
1.5 KiB
Go

package context
import (
"somegit.dev/Owlibou/gnoma/internal/message"
)
// TruncateStrategy drops oldest messages while preserving:
// - System prompt (first message if role=system)
// - Recent messages (last N turns)
// Fast, cheap, no LLM call. Used as default and emergency fallback.
type TruncateStrategy struct {
// KeepRecent is the number of recent messages to always preserve.
// Default: 10 (5 user + 5 assistant turns)
KeepRecent int
}
func NewTruncateStrategy() *TruncateStrategy {
return &TruncateStrategy{KeepRecent: 10}
}
func (s *TruncateStrategy) Compact(messages []message.Message, budget int64) ([]message.Message, error) {
if len(messages) <= s.KeepRecent {
return messages, nil // nothing to compact
}
keepRecent := s.KeepRecent
if keepRecent > len(messages) {
keepRecent = len(messages)
}
// Separate system prompt (if present) from history
var systemMsgs []message.Message
var history []message.Message
for i, m := range messages {
if i == 0 && m.Role == message.RoleSystem {
systemMsgs = append(systemMsgs, m)
} else {
history = append(history, m)
}
}
// Keep only the most recent messages from history
if len(history) > keepRecent {
// Add a compaction boundary marker
marker := message.NewUserText("[Earlier conversation was summarized to save context]")
ack := message.NewAssistantText("Understood, I'll continue from here.")
recent := history[len(history)-keepRecent:]
result := append(systemMsgs, marker, ack)
result = append(result, recent...)
return result, nil
}
return messages, nil
}