Class: RubynCode::Context::DecisionCompactor

Inherits:
Object
  • Object
show all
Defined in:
lib/rubyn_code/context/decision_compactor.rb

Overview

Triggers compaction at logical decision boundaries rather than only at capacity limits. This prevents late-session context bloat by compacting after meaningful milestones.

Constant Summary collapse

EARLY_COMPACT_RATIO =

Percentage of context threshold at which to trigger compaction on decision boundaries (lower than the default 95%).

0.6
TRIGGERS =
%i[
  specs_passed
  topic_switch
  multi_file_edit_complete
].freeze
STOPWORDS =
%w[the and for this that with from have been will your what].to_set.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context_manager:, threshold: nil) ⇒ DecisionCompactor

Returns a new instance of DecisionCompactor.



21
22
23
24
25
26
27
# File 'lib/rubyn_code/context/decision_compactor.rb', line 21

def initialize(context_manager:, threshold: nil)
  @context_manager = context_manager
  @threshold = threshold || Config::Defaults::CONTEXT_THRESHOLD_TOKENS
  @pending_trigger = nil
  @last_topic_keywords = Set.new
  @edited_files = Set.new
end

Instance Attribute Details

#pending_triggerObject (readonly)

Returns the value of attribute pending_trigger.



19
20
21
# File 'lib/rubyn_code/context/decision_compactor.rb', line 19

def pending_trigger
  @pending_trigger
end

Instance Method Details

#check!(conversation) ⇒ Object

Check if compaction should run based on decision boundaries. Returns true if compaction was triggered.



59
60
61
62
63
64
65
66
67
# File 'lib/rubyn_code/context/decision_compactor.rb', line 59

def check!(conversation) # rubocop:disable Naming/PredicateMethod -- side-effectful: triggers compaction, not just a query
  return false unless should_compact?(conversation)

  trigger = @pending_trigger
  @pending_trigger = nil
  RubynCode::Debug.token("Decision compaction triggered: #{trigger}")
  @context_manager.check_compaction!(conversation)
  true
end

#detect_topic_switch(user_message) ⇒ Object

Detect topic switch from user message keywords.



48
49
50
51
52
53
54
55
# File 'lib/rubyn_code/context/decision_compactor.rb', line 48

def detect_topic_switch(user_message)
  keywords = extract_keywords(user_message)
  overlap = keywords & @last_topic_keywords

  @pending_trigger = :topic_switch if @last_topic_keywords.any? && overlap.empty? && keywords.any?

  @last_topic_keywords = keywords
end

#reset!Object

Reset all tracked state.



70
71
72
73
74
# File 'lib/rubyn_code/context/decision_compactor.rb', line 70

def reset!
  @pending_trigger = nil
  @last_topic_keywords.clear
  @edited_files.clear
end

#signal_edit_batch_complete!Object

Signal that multi-file editing is complete.



40
41
42
43
44
45
# File 'lib/rubyn_code/context/decision_compactor.rb', line 40

def signal_edit_batch_complete!
  return unless @edited_files.size > 1

  @pending_trigger = :multi_file_edit_complete
  @edited_files.clear
end

#signal_file_edited!(path) ⇒ Object

Signal that a file was edited (for multi-file tracking).



35
36
37
# File 'lib/rubyn_code/context/decision_compactor.rb', line 35

def signal_file_edited!(path)
  @edited_files << path
end

#signal_specs_passed!Object

Signal that specs passed after implementation.



30
31
32
# File 'lib/rubyn_code/context/decision_compactor.rb', line 30

def signal_specs_passed!
  @pending_trigger = :specs_passed
end