Class: Legion::Extensions::Agentic::Affect::Interoception::Helpers::BodyBudget
- Inherits:
-
Object
- Object
- Legion::Extensions::Agentic::Affect::Interoception::Helpers::BodyBudget
show all
- Includes:
- Constants
- Defined in:
- lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb
Constant Summary
Constants included
from Constants
Constants::BODY_BUDGET_LABELS, Constants::DEFAULT_BASELINE, Constants::DEVIATION_THRESHOLD, Constants::MARKER_DECAY, Constants::MARKER_FLOOR, Constants::MARKER_INFLUENCE, Constants::MARKER_NEGATIVE_THRESHOLD, Constants::MARKER_POSITIVE_THRESHOLD, Constants::MAX_MARKERS, Constants::MAX_VITAL_HISTORY, Constants::VITAL_ALPHA, Constants::VITAL_CHANNELS, Constants::VITAL_LABELS
Instance Attribute Summary collapse
Instance Method Summary
collapse
Constructor Details
Returns a new instance of BodyBudget.
14
15
16
17
18
19
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 14
def initialize
@vitals = {}
@baselines = {}
@markers = []
@vital_history = {}
end
|
Instance Attribute Details
#baselines ⇒ Object
Returns the value of attribute baselines.
12
13
14
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 12
def baselines
@baselines
end
|
#markers ⇒ Object
Returns the value of attribute markers.
12
13
14
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 12
def markers
@markers
end
|
#vital_history ⇒ Object
Returns the value of attribute vital_history.
12
13
14
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 12
def vital_history
@vital_history
end
|
#vitals ⇒ Object
Returns the value of attribute vitals.
12
13
14
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 12
def vitals
@vitals
end
|
Instance Method Details
#bias_for_action(action:, domain: nil) ⇒ Object
82
83
84
85
86
87
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 82
def bias_for_action(action:, domain: nil)
relevant = markers_for(action: action, domain: domain)
return 0.0 if relevant.empty?
relevant.sum { |m| m.bias_for(action) } / relevant.size
end
|
#body_budget_label ⇒ Object
107
108
109
110
111
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 107
def body_budget_label
health = overall_health
BODY_BUDGET_LABELS.each { |range, lbl| return lbl if range.cover?(health) }
:comfortable
end
|
#channel_count ⇒ Object
113
114
115
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 113
def channel_count
@vitals.size
end
|
#create_marker(action:, domain:, valence:, strength: 1.0) ⇒ Object
69
70
71
72
73
74
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 69
def create_marker(action:, domain:, valence:, strength: 1.0)
marker = SomaticMarker.new(action: action, domain: domain, valence: valence, strength: strength)
@markers << marker
prune_markers if @markers.size > MAX_MARKERS
marker
end
|
#decay_markers ⇒ Object
93
94
95
96
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 93
def decay_markers
@markers.each(&:decay)
@markers.reject!(&:faded?)
end
|
#deviating_channels ⇒ Object
62
63
64
65
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 62
def deviating_channels
@vitals.select { |ch, _| deviation_for(ch).abs >= DEVIATION_THRESHOLD }
.map { |ch, _| { channel: ch, deviation: deviation_for(ch).round(4), label: vital_label(ch) } }
end
|
#deviation_for(channel) ⇒ Object
43
44
45
46
47
48
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 43
def deviation_for(channel)
channel = channel.to_sym
current = @vitals.fetch(channel, DEFAULT_BASELINE)
baseline = @baselines.fetch(channel, DEFAULT_BASELINE)
current - baseline
end
|
#marker_count ⇒ Object
117
118
119
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 117
def marker_count
@markers.size
end
|
#markers_for(action:, domain: nil) ⇒ Object
76
77
78
79
80
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 76
def markers_for(action:, domain: nil)
results = @markers.select { |m| m.action == action }
results = results.select { |m| m.domain == domain } if domain
results
end
|
#overall_health ⇒ Object
100
101
102
103
104
105
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 100
def overall_health
return DEFAULT_BASELINE if @vitals.empty?
healths = @vitals.keys.map { |ch| vital_health(ch) }
healths.sum / healths.size
end
|
#reinforce_markers(action:, domain: nil, amount: 0.1) ⇒ Object
89
90
91
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 89
def reinforce_markers(action:, domain: nil, amount: 0.1)
markers_for(action: action, domain: domain).each { |m| m.reinforce(amount: amount) }
end
|
#report_vital(channel:, value:) ⇒ Object
— Vital Signal Tracking —
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 23
def report_vital(channel:, value:)
channel = channel.to_sym
return nil unless VITAL_CHANNELS.include?(channel)
normalized = value.clamp(0.0, 1.0)
@baselines[channel] ||= DEFAULT_BASELINE
@vitals[channel] = if @vitals.key?(channel)
ema(@vitals[channel], normalized, VITAL_ALPHA)
else
normalized
end
record_vital_history(channel, @vitals[channel])
@baselines[channel] = ema(@baselines[channel], @vitals[channel], VITAL_ALPHA * 0.5)
@vitals[channel]
end
|
#to_h ⇒ Object
121
122
123
124
125
126
127
128
129
130
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 121
def to_h
{
overall_health: overall_health.round(4),
body_budget_label: body_budget_label,
channels: channel_count,
markers: marker_count,
vitals: @vitals.transform_values { |v| v.round(4) },
deviations: deviating_channels
}
end
|
#vital_for(channel) ⇒ Object
39
40
41
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 39
def vital_for(channel)
@vitals.fetch(channel.to_sym, DEFAULT_BASELINE)
end
|
#vital_health(channel) ⇒ Object
56
57
58
59
60
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 56
def vital_health(channel)
val = vital_for(channel)
inverted_channels = %i[cpu_load memory_pressure queue_depth error_rate disk_usage gc_pressure]
inverted_channels.include?(channel.to_sym) ? 1.0 - val : val
end
|
#vital_label(channel) ⇒ Object
50
51
52
53
54
|
# File 'lib/legion/extensions/agentic/affect/interoception/helpers/body_budget.rb', line 50
def vital_label(channel)
health = vital_health(channel)
VITAL_LABELS.each { |range, lbl| return lbl if range.cover?(health) }
:nominal
end
|