Class: RubynCode::Context::ContextBudget

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

Overview

Budget-aware context loader that prioritizes which related files to load fully vs. as signatures-only. Prevents context bloat by capping auto-loaded context at a configurable token budget.

Constant Summary collapse

CHARS_PER_TOKEN =
4
DEFAULT_BUDGET =

tokens

4000
PRIORITY_MAP =

Rails convention-based priority for related files. Lower number = higher priority = loaded first.

{
  'spec' => 1, # tests for the file
  'factory' => 2,  # FactoryBot factories
  'service' => 3,  # service objects
  'model' => 4, # related models
  'controller' => 5,  # controllers
  'serializer' => 6,  # serializers
  'concern' => 7, # concerns/mixins
  'helper' => 8, # helpers
  'migration' => 9 # migrations
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(budget: DEFAULT_BUDGET, codebase_index: nil) ⇒ ContextBudget

Returns a new instance of ContextBudget.



28
29
30
31
32
33
34
# File 'lib/rubyn_code/context/context_budget.rb', line 28

def initialize(budget: DEFAULT_BUDGET, codebase_index: nil)
  @budget = budget
  @codebase_index = codebase_index
  @loaded_files = []
  @signature_files = []
  @tokens_used = 0
end

Instance Attribute Details

#loaded_filesObject (readonly)

Returns the value of attribute loaded_files.



26
27
28
# File 'lib/rubyn_code/context/context_budget.rb', line 26

def loaded_files
  @loaded_files
end

#signature_filesObject (readonly)

Returns the value of attribute signature_files.



26
27
28
# File 'lib/rubyn_code/context/context_budget.rb', line 26

def signature_files
  @signature_files
end

#tokens_usedObject (readonly)

Returns the value of attribute tokens_used.



26
27
28
# File 'lib/rubyn_code/context/context_budget.rb', line 26

def tokens_used
  @tokens_used
end

Instance Method Details

#extract_signatures(content) ⇒ Object

Extract method signatures and class structure without method bodies. Much more compact than full source — typically 10-20% of original size.



68
69
70
71
72
73
74
75
76
77
# File 'lib/rubyn_code/context/context_budget.rb', line 68

def extract_signatures(content)
  signatures = []
  indent_stack = []

  content.lines.each do |line|
    process_signature_line(line, signatures, indent_stack)
  end

  signatures.join
end

#load_for(file_path, related_files: []) ⇒ Object

Load context for a primary file, filling budget with related files. Returns array of { file:, content:, mode: :full|:signatures }

When a codebase_index is available and no related_files are supplied, uses impact_analysis to auto-discover related files (specs, associated models, controllers, etc.).



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rubyn_code/context/context_budget.rb', line 42

def load_for(file_path, related_files: [])
  results = []

  # Primary file always loads fully
  primary_content = safe_read(file_path)
  return results unless primary_content

  primary_tokens = estimate_tokens(primary_content)
  @tokens_used = primary_tokens
  @loaded_files << file_path
  results << { file: file_path, content: primary_content, mode: :full }

  # Auto-discover related files from the index when none supplied
  related_files = discover_related_files(file_path) if related_files.empty? && @codebase_index

  # Sort related files by priority and fill remaining budget
  sorted = prioritize(related_files)
  remaining = @budget - @tokens_used
  remaining = load_full_files(sorted, results, remaining)
  load_signature_files(sorted, results, remaining)

  results
end

#statsObject

Returns budget utilization stats.



80
81
82
83
84
85
86
87
88
# File 'lib/rubyn_code/context/context_budget.rb', line 80

def stats
  {
    budget: @budget,
    tokens_used: @tokens_used,
    utilization: @budget.positive? ? (@tokens_used.to_f / @budget).round(3) : 0.0,
    full_files: @loaded_files.size,
    signature_files: @signature_files.size
  }
end