Class: Tryouts::CLI::TokenBudget
- Inherits:
-
Object
- Object
- Tryouts::CLI::TokenBudget
- Defined in:
- lib/tryouts/cli/formatters/token_budget.rb
Overview
Token budget tracking for agent-optimized output
Constant Summary collapse
- DEFAULT_LIMIT =
5000- BUFFER_PERCENT =
5% buffer to avoid going over
0.05
Instance Attribute Summary collapse
-
#limit ⇒ Object
readonly
Returns the value of attribute limit.
-
#remaining ⇒ Object
readonly
Get remaining budget.
-
#used ⇒ Object
readonly
Returns the value of attribute used.
Instance Method Summary collapse
-
#allocate_budget ⇒ Object
Distribution strategy for budget allocation.
-
#consume(text) ⇒ Object
Add text to budget if within limits.
-
#estimate_tokens(text) ⇒ Object
Estimate tokens in text (rough approximation: 1 token ≈ 4 characters).
-
#fit_text(text, preserve_suffix: nil) ⇒ Object
Try to fit text within remaining budget by truncating.
-
#force_consume(text) ⇒ Object
Force consume (for critical information that must be included).
-
#has_budget? ⇒ Boolean
Check if we have budget remaining.
-
#initialize(limit = DEFAULT_LIMIT) ⇒ TokenBudget
constructor
A new instance of TokenBudget.
-
#reset ⇒ Object
Reset budget.
-
#smart_truncate(value, max_tokens: nil) ⇒ Object
Smart truncate for different data types.
- #to_s ⇒ Object
-
#utilization ⇒ Object
Get utilization percentage.
-
#would_exceed?(text) ⇒ Boolean
Check if text would exceed budget.
Constructor Details
#initialize(limit = DEFAULT_LIMIT) ⇒ TokenBudget
Returns a new instance of TokenBudget.
14 15 16 17 18 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 14 def initialize(limit = DEFAULT_LIMIT) @limit = limit @used = 0 @buffer_size = (@limit * BUFFER_PERCENT).to_i end |
Instance Attribute Details
#limit ⇒ Object (readonly)
Returns the value of attribute limit.
12 13 14 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 12 def limit @limit end |
#remaining ⇒ Object (readonly)
Get remaining budget
48 49 50 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 48 def remaining @remaining end |
#used ⇒ Object (readonly)
Returns the value of attribute used.
12 13 14 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 12 def used @used end |
Instance Method Details
#allocate_budget ⇒ Object
Distribution strategy for budget allocation
140 141 142 143 144 145 146 147 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 140 def allocate_budget { summary: (@limit * 0.20).to_i, # 20% for file summaries failures: (@limit * 0.60).to_i, # 60% for failure details context: (@limit * 0.15).to_i, # 15% for additional context buffer: (@limit * 0.05).to_i # 5% buffer } end |
#consume(text) ⇒ Object
Add text to budget if within limits
34 35 36 37 38 39 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 34 def consume(text) return false if would_exceed?(text) @used += estimate_tokens(text) true end |
#estimate_tokens(text) ⇒ Object
Estimate tokens in text (rough approximation: 1 token ≈ 4 characters)
21 22 23 24 25 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 21 def estimate_tokens(text) return 0 if text.nil? || text.empty? (text.length / 4.0).ceil end |
#fit_text(text, preserve_suffix: nil) ⇒ Object
Try to fit text within remaining budget by truncating
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 63 def fit_text(text, preserve_suffix: nil) token_count = estimate_tokens(text) return text if token_count <= remaining return '' unless has_budget? # Calculate how many characters we can fit max_chars = remaining * 4 if preserve_suffix suffix_chars = preserve_suffix.length return preserve_suffix if max_chars <= suffix_chars available_chars = max_chars - suffix_chars - 3 # 3 for "..." return "#{text[0, available_chars]}...#{preserve_suffix}" else return text[0, max_chars - 3] + '...' if max_chars > 3 return '' end end |
#force_consume(text) ⇒ Object
Force consume (for critical information that must be included)
42 43 44 45 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 42 def force_consume(text) @used += estimate_tokens(text) true end |
#has_budget? ⇒ Boolean
Check if we have budget remaining
53 54 55 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 53 def has_budget? remaining > 0 end |
#reset ⇒ Object
Reset budget
150 151 152 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 150 def reset @used = 0 end |
#smart_truncate(value, max_tokens: nil) ⇒ Object
Smart truncate for different data types
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 85 def smart_truncate(value, max_tokens: nil) max_tokens ||= [remaining / 2, 50].min # Use half remaining or 50, whichever is smaller max_chars = [max_tokens.to_i * 4, 0].max case value when String return value if value.length <= max_chars return '...' if max_chars <= 3 "#{value[0, max_chars - 3]}..." when Array if estimate_tokens(value.inspect) <= max_tokens value.inspect else # Show first few elements truncated = [] char_count = 2 # for "[]" value.each do |item| item_str = item.inspect if char_count + item_str.length + 2 <= max_chars - 10 # 10 chars for ", ..." truncated << item char_count += item_str.length + 2 # +2 for ", " else break end end "[#{truncated.map(&:inspect).join(', ')}, ...#{value.size - truncated.size} more]" end when Hash if estimate_tokens(value.inspect) <= max_tokens value.inspect else # Show first few key-value pairs truncated = {} char_count = 2 # for "{}" value.each do |key, val| pair_str = "#{key.inspect}=>#{val.inspect}" if char_count + pair_str.length + 2 <= max_chars - 10 truncated[key] = val char_count += pair_str.length + 2 else break end end "{#{truncated.map { |k, v| "#{k.inspect}=>#{v.inspect}" }.join(', ')}, ...#{value.size - truncated.size} more}" end else smart_truncate(value.to_s, max_tokens: max_tokens) end end |
#to_s ⇒ Object
154 155 156 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 154 def to_s "TokenBudget[#{@used}/#{@limit} tokens (#{utilization}%)]" end |
#utilization ⇒ Object
Get utilization percentage
58 59 60 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 58 def utilization (@used.to_f / @limit * 100).round(1) end |
#would_exceed?(text) ⇒ Boolean
Check if text would exceed budget
28 29 30 31 |
# File 'lib/tryouts/cli/formatters/token_budget.rb', line 28 def would_exceed?(text) token_count = estimate_tokens(text) (@used + token_count) > (@limit - @buffer_size) end |