Class: Legion::Extensions::Agentic::Affect::SomaticMarker::Helpers::MarkerStore

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb

Constant Summary

Constants included from Constants

Constants::BODY_STATE_DECAY, Constants::DEFAULT_VALENCE, Constants::MARKER_ALPHA, Constants::MARKER_DECAY, Constants::MARKER_STRENGTH_FLOOR, Constants::MAX_BODY_STATES, Constants::MAX_DECISION_HISTORY, Constants::MAX_MARKERS, Constants::MAX_OPTIONS_PER_DECISION, Constants::NEGATIVE_BIAS, Constants::POSITIVE_BIAS, Constants::PUNISHMENT_PENALTY, Constants::REINFORCEMENT_BOOST, Constants::SIGNAL_LABELS, Constants::VALENCE_LABELS

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeMarkerStore

Returns a new instance of MarkerStore.



14
15
16
17
18
19
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 14

def initialize
  @markers          = {}
  @body_state       = BodyState.new
  @decision_history = []
  @next_id          = 1
end

Instance Attribute Details

#body_stateObject (readonly)

Returns the value of attribute body_state.



12
13
14
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 12

def body_state
  @body_state
end

#markersObject (readonly)

Returns the value of attribute markers.



12
13
14
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 12

def markers
  @markers
end

Instance Method Details

#body_influenceObject



97
98
99
100
101
102
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 97

def body_influence
  {
    composite_valence: @body_state.composite_valence,
    stressed:          @body_state.stressed?
  }
end

#decay_allObject



104
105
106
107
108
109
110
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 104

def decay_all
  @markers.each_value(&:decay)
  faded_ids = @markers.select { |_id, m| m.faded? }.keys
  faded_ids.each { |id| @markers.delete(id) }
  @body_state.decay
  { markers_decayed: @markers.size, markers_removed: faded_ids.size }
end

#decide(options:, domain:) ⇒ Object



45
46
47
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
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 45

def decide(options:, domain:)
  capped = options.first(MAX_OPTIONS_PER_DECISION)
  ranked = capped.map do |option|
    eval_result = evaluate_option(action: option, domain: domain)
    {
      action:       option,
      signal:       eval_result[:signal],
      valence:      eval_result[:valence],
      marker_count: eval_result[:marker_count]
    }
  end

  ranked.sort_by! { |r| -r[:valence] }

  body_contribution = body_influence

  record = {
    options:           capped,
    ranked:            ranked,
    domain:            domain,
    body_contribution: body_contribution,
    decided_at:        Time.now.utc
  }

  @decision_history.shift while @decision_history.size >= MAX_DECISION_HISTORY
  @decision_history << record

  record
end

#decision_history(limit: 10) ⇒ Object



112
113
114
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 112

def decision_history(limit: 10)
  @decision_history.last(limit)
end

#evaluate_option(action:, domain:) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 36

def evaluate_option(action:, domain:)
  relevant = markers_for(action: action, domain: domain)
  return { signal: :neutral, valence: DEFAULT_VALENCE, marker_count: 0 } if relevant.empty?

  weighted_valence = compute_weighted_valence(relevant)
  signal           = valence_to_signal(weighted_valence)
  { signal: signal, valence: weighted_valence, marker_count: relevant.size }
end

#markers_for(action:, domain:) ⇒ Object



93
94
95
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 93

def markers_for(action:, domain:)
  @markers.values.select { |m| m.action == action && m.domain == domain }
end

#register_marker(action:, domain:, valence:, source: :experience) ⇒ Object



21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 21

def register_marker(action:, domain:, valence:, source: :experience)
  evict_weakest if @markers.size >= MAX_MARKERS

  id     = generate_id
  marker = SomaticMarker.new(
    id:      id,
    action:  action,
    domain:  domain,
    valence: valence,
    source:  source
  )
  @markers[id] = marker
  marker
end

#reinforce_marker(marker_id:, outcome_valence:) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 75

def reinforce_marker(marker_id:, outcome_valence:)
  marker = @markers[marker_id]
  return nil unless marker

  marker.reinforce(outcome_valence: outcome_valence)
  marker
end

#to_hObject



116
117
118
119
120
121
122
123
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 116

def to_h
  {
    marker_count:   @markers.size,
    decision_count: @decision_history.size,
    body_state:     @body_state.to_h,
    stressed:       @body_state.stressed?
  }
end

#update_body_state(arousal: nil, tension: nil, comfort: nil, gut_signal: nil) ⇒ Object



83
84
85
86
87
88
89
90
91
# File 'lib/legion/extensions/agentic/affect/somatic_marker/helpers/marker_store.rb', line 83

def update_body_state(arousal: nil, tension: nil, comfort: nil, gut_signal: nil)
  @body_state.update(
    arousal:    arousal,
    tension:    tension,
    comfort:    comfort,
    gut_signal: gut_signal
  )
  @body_state
end