Module: Legion::Extensions::Agentic::Attention::Surprise::Runners::Surprise
- Includes:
- Helpers::Lex
- Included in:
- Client
- Defined in:
- lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb
Instance Method Summary collapse
- #domain_sensitivity(domain:) ⇒ Object
-
#evaluate_surprise(domain:, predicted:, actual:, valence: :neutral) ⇒ Object
Evaluate a single prediction-outcome pair and compute surprise magnitude.
- #recent_surprises(count: 10) ⇒ Object
- #reset_habituation(domain:) ⇒ Object
- #surprise_stats ⇒ Object
-
#update_surprise(tick_result: {}) ⇒ Object
Per-tick update: extract domain predictions from tick_result, compute surprise for each, decay the store’s baseline tracking, and return a summary.
Instance Method Details
#domain_sensitivity(domain:) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb', line 95 def domain_sensitivity(domain:, **) sensitivity = habituation_model.sensitivity_for(domain) baseline = store.baseline_for(domain) domain_events = store.by_domain(domain) log.debug("[surprise] domain_sensitivity: domain=#{domain} sensitivity=#{sensitivity.round(3)}") { success: true, domain: domain, sensitivity: sensitivity.round(4), baseline: baseline.round(4), event_count: domain_events.size } end |
#evaluate_surprise(domain:, predicted:, actual:, valence: :neutral) ⇒ Object
Evaluate a single prediction-outcome pair and compute surprise magnitude. magnitude = |predicted - actual| * sensitivity * valence_weight, clamped to [0,1]
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb', line 15 def evaluate_surprise(domain:, predicted:, actual:, valence: :neutral, **) sensitivity = habituation_model.sensitivity_for(domain) valence_weight = Helpers::Constants::VALENCE_WEIGHTS.fetch(valence, 0.3) raw_diff = (predicted.to_f - actual.to_f).abs magnitude = (raw_diff * sensitivity * valence_weight).clamp(0.0, 1.0) threshold = Helpers::Constants::SURPRISE_THRESHOLD orienting = should_orient?(domain, magnitude, threshold) event = Helpers::SurpriseEvent.new( domain: domain, predicted: predicted, actual: actual, magnitude: magnitude, valence: valence, orienting: orienting ) store.record(event) habituation_model.habituate(domain) if orienting record_cooldown(domain) log.debug("[surprise] orienting response triggered: domain=#{domain} magnitude=#{magnitude.round(3)}") else log.debug("[surprise] surprise recorded: domain=#{domain} magnitude=#{magnitude.round(3)} orienting=false") end { success: true, surprise_event: event.to_h, orienting_triggered: orienting } end |
#recent_surprises(count: 10) ⇒ Object
111 112 113 114 115 |
# File 'lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb', line 111 def recent_surprises(count: 10, **) events = store.recent(count) log.debug("[surprise] recent_surprises: count=#{events.size}") { success: true, events: events.map(&:to_h), count: events.size } end |
#reset_habituation(domain:) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb', line 117 def reset_habituation(domain:, **) old_sensitivity = habituation_model.sensitivity_for(domain) # Sensitize repeatedly to push back toward 1.0 steps = ((1.0 - old_sensitivity) / Helpers::Constants::SENSITIZATION_RATE).ceil steps.times { habituation_model.sensitize(domain) } new_sensitivity = habituation_model.sensitivity_for(domain) log.debug("[surprise] reset_habituation: domain=#{domain} #{old_sensitivity.round(3)} -> #{new_sensitivity.round(3)}") { success: true, domain: domain, old_sensitivity: old_sensitivity.round(4), new_sensitivity: new_sensitivity.round(4) } end |
#surprise_stats ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb', line 78 def surprise_stats(**) stats = store.to_h top = store.most_surprising(1).first avg_mag = stats[:average_magnitude] log.debug("[surprise] stats: total=#{stats[:total_events]} domains=#{stats[:domain_count]}") { success: true, total_events: stats[:total_events], domain_count: stats[:domain_count], average_magnitude: avg_mag, most_surprising_domain: stats[:most_surprising_domain], top_surprise_magnitude: top&.magnitude&.round(4) } end |
#update_surprise(tick_result: {}) ⇒ Object
Per-tick update: extract domain predictions from tick_result, compute surprise for each, decay the store’s baseline tracking, and return a summary.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb', line 48 def update_surprise(tick_result: {}, **) predictions = extract_predictions(tick_result) events = [] predictions.each do |pred| next unless pred[:domain] && !pred[:predicted].nil? && !pred[:actual].nil? result = evaluate_surprise( domain: pred[:domain], predicted: pred[:predicted], actual: pred[:actual], valence: pred.fetch(:valence, :neutral) ) events << result[:surprise_event] if result[:success] end habituation_model.decay_all tick_cooldowns orienting_count = events.count { |e| e[:orienting] } log.debug("[surprise] tick update: evaluated=#{events.size} orienting=#{orienting_count}") { success: true, evaluated: events.size, orienting_count: orienting_count, events: events } end |